@hanzo/design 0.4.1 → 0.4.3

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,7 +3,8 @@ import React from 'react'
3
3
  const V = {
4
4
  primary:{background:'var(--primary)',color:'var(--primary-foreground)',border:'1px solid transparent'},
5
5
  secondary:{background:'var(--secondary)',color:'var(--secondary-foreground)',border:'1px solid transparent'},
6
- outline:{background:'transparent',color:'var(--text-primary)',border:'1px solid var(--border)'},
6
+ // --border-control, not --border: an outline button's edge IS the button.
7
+ outline:{background:'transparent',color:'var(--text-primary)',border:'1px solid var(--border-control)'},
7
8
  ghost:{background:'transparent',color:'var(--text-secondary)',border:'1px solid transparent'},
8
9
  link:{background:'transparent',color:'var(--text-primary)',border:'1px solid transparent',textDecoration:'underline',textUnderlineOffset:4,padding:0,height:'auto'},
9
10
  destructive:{background:'var(--destructive)',color:'var(--destructive-foreground)',border:'1px solid transparent'},
@@ -14,17 +15,34 @@ const SZ = {
14
15
  lg:{height:44,padding:'0 24px',fontSize:'var(--text-sm)'},
15
16
  icon:{height:36,width:36,padding:0},
16
17
  }
17
- const HOVER = { primary:'primary', secondary:'primary', outline:'accent', ghost:'accent', destructive:'destructive', link:'link' }
18
+ // Hover, per variant. A FILLED button does not brighten on hover — its fill is
19
+ // already the top of the ink ramp — so it steps DOWN that ramp and
20
+ // gains a bloom instead, which is the reference's own move
21
+ // (.primary-btn:hover → --accent-hover + a white glow). This used to be
22
+ // `opacity: 0.9`, which faded the button toward the page: the one thing a
23
+ // hovered control must never do is look more disabled than it did at rest.
24
+ // An UNFILLED button has room to gain, so it takes a surface and an edge.
25
+ const HOVER = {
26
+ primary: { background:'var(--primary-hover)', boxShadow:'var(--bloom)' },
27
+ secondary: { background:'var(--secondary-hover)', boxShadow:'var(--edge-highlight)' },
28
+ // An unfilled button's hover is the SURFACE arriving, not the edge moving:
29
+ // --border-control (.15) to --border-strong (.16) is a one-percent step and
30
+ // reads as nothing, so the fill has to carry it. --glass-strong, not --glass;
31
+ // at .05 the fill was invisible too and the variant had no hover at all.
32
+ outline: { background:'var(--glass-strong)', borderColor:'var(--border-strong)', color:'var(--text-primary)' },
33
+ ghost: { background:'var(--glass-strong)', color:'var(--text-primary)' },
34
+ destructive:{ background:'var(--destructive-hover)', boxShadow:'var(--bloom)' },
35
+ link: { textDecoration:'underline' },
36
+ }
37
+ // The filled variants catch the light along their top edge, the same way every
38
+ // raised surface in this system does.
39
+ const LIT = new Set(['primary', 'destructive'])
18
40
 
19
41
  export function Button({ variant = 'primary', size = 'default', pill = false, disabled, style, children, ...rest }) {
20
42
  const [hover, setHover] = React.useState(false)
21
43
  const v = V[variant] || V.primary
22
44
  const s = SZ[size] || SZ.default
23
- const h = HOVER[variant]
24
- const hoverStyle = !hover || disabled ? null
25
- : h === 'primary' || h === 'destructive' ? { opacity: 0.9 }
26
- : h === 'accent' ? { background: 'var(--accent)', color: 'var(--text-primary)' }
27
- : { textDecoration: 'underline' }
45
+ const hoverStyle = !hover || disabled ? null : HOVER[variant]
28
46
  return (
29
47
  <button
30
48
  disabled={disabled}
@@ -33,10 +51,18 @@ export function Button({ variant = 'primary', size = 'default', pill = false, di
33
51
  style={{
34
52
  display:'inline-flex',alignItems:'center',justifyContent:'center',gap:8,whiteSpace:'nowrap',
35
53
  fontFamily:'var(--font-sans)',fontWeight:'var(--weight-medium)',lineHeight:1,
36
- borderRadius: pill ? 'var(--radius-full)' : 'var(--radius-sm)',
54
+ // --radius-md (8px), not --radius-sm (6px): on a 36px control that one
55
+ // step is the difference between boxy and considered. --radius-sm keeps
56
+ // its job on genuinely small parts (badges, chips, menu rows).
57
+ borderRadius: pill ? 'var(--radius-full)' : 'var(--radius-md)',
58
+ letterSpacing:'var(--tracking-tight)',
37
59
  cursor: disabled ? 'not-allowed' : 'pointer',
38
60
  opacity: disabled ? 0.5 : 1,
39
- transition:'background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out), opacity var(--duration-fast) var(--ease-out)',
61
+ boxShadow: LIT.has(variant) ? 'var(--edge-highlight)' : 'none',
62
+ // `transform` is in the list because tokens/base.css scales this button
63
+ // to .98 while it is held down, and a transform with no transition
64
+ // snaps rather than presses.
65
+ transition:'background-color var(--duration-fast) var(--ease-out), color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out), opacity var(--duration-fast) var(--ease-out), transform var(--duration-press) var(--ease-out)',
40
66
  ...v, ...s, ...hoverStyle, ...style,
41
67
  }}
42
68
  {...rest}
@@ -7,8 +7,9 @@ const FILL = {
7
7
  plain:'transparent',
8
8
  }
9
9
 
10
- export function Card({ variant = 'default', sheen = false, interactive = false, style, children, ...rest }) {
10
+ export function Card({ variant = 'default', sheen = false, interactive = false, selected = false, style, children, ...rest }) {
11
11
  const [hover, setHover] = React.useState(false)
12
+ const edge = selected ? 'var(--border-selected)' : hover ? 'var(--border-strong)' : 'var(--border)'
12
13
  return (
13
14
  <div
14
15
  onMouseEnter={interactive ? () => setHover(true) : undefined}
@@ -16,13 +17,24 @@ export function Card({ variant = 'default', sheen = false, interactive = false,
16
17
  style={{
17
18
  position:'relative',overflow:'hidden',
18
19
  borderRadius:'var(--radius-lg)',
19
- border:'1px solid ' + (hover ? 'var(--border-strong)' : 'var(--border)'),
20
+ border:'1px solid ' + edge,
20
21
  background:FILL[variant] || FILL.default,
21
- transition:'border-color var(--duration-fast) var(--ease-out)',
22
+ // The card catches the light along its top edge at rest, and picks up a
23
+ // real drop only when it lifts. A shadow on a resting card is noise; a
24
+ // card with NO inset highlight is a coloured rectangle rather than a
25
+ // surface, which is why the highlight is unconditional and the drop is
26
+ // not. See tokens/elevation.css for why this is the part that matters
27
+ // on a near-black ground.
28
+ boxShadow: hover ? 'var(--edge-highlight), var(--shadow-lg)' : 'var(--edge-highlight)',
29
+ transform: hover ? 'translateY(-1px)' : 'none',
30
+ transition:'border-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-base) var(--ease-out), transform var(--duration-base) var(--ease-out)',
22
31
  ...style,
23
32
  }}
24
33
  {...rest}
25
34
  >
35
+ {/* The top hairline: brightest at the centre, dissolved before either
36
+ corner, so the edge never terminates in a hard stop. */}
37
+ <div aria-hidden style={{position:'absolute',top:0,left:0,right:0,height:1,pointerEvents:'none',background:'var(--sheen-edge)'}} />
26
38
  {sheen && <div aria-hidden style={{position:'absolute',inset:0,pointerEvents:'none',background:'var(--sheen-card)',opacity:0.7}} />}
27
39
  {children}
28
40
  </div>
@@ -33,10 +45,13 @@ export function CardHeader({ style, children, ...rest }) {
33
45
  return <div style={{position:'relative',padding:'24px 24px 0',display:'flex',flexDirection:'column',gap:6,...style}} {...rest}>{children}</div>
34
46
  }
35
47
  export function CardTitle({ style, children, ...rest }) {
36
- return <h3 style={{fontSize:'var(--text-base)',fontWeight:'var(--weight-semibold)',color:'var(--text-primary)',...style}} {...rest}>{children}</h3>
48
+ // --text-lg over --text-base: at 14px a title sat one point above its own
49
+ // 13px description, which is not a hierarchy, it is a rounding error. The
50
+ // step up plus the tighter tracking is what makes a card scannable.
51
+ return <h3 style={{fontSize:'var(--text-lg)',fontWeight:'var(--weight-semibold)',letterSpacing:'var(--tracking-tight)',color:'var(--text-primary)',...style}} {...rest}>{children}</h3>
37
52
  }
38
53
  export function CardDescription({ style, children, ...rest }) {
39
- return <p style={{fontSize:'var(--text-sm)',lineHeight:'var(--leading-relaxed)',color:'var(--text-helper)',...style}} {...rest}>{children}</p>
54
+ return <p style={{fontSize:'var(--text-sm)',lineHeight:'var(--leading-relaxed)',color:'var(--text-tertiary)',...style}} {...rest}>{children}</p>
40
55
  }
41
56
  export function CardContent({ style, children, ...rest }) {
42
57
  return <div style={{position:'relative',padding:24,...style}} {...rest}>{children}</div>
@@ -2,17 +2,27 @@ import React from 'react'
2
2
 
3
3
  export function Input({ invalid = false, style, ...rest }) {
4
4
  const [focus, setFocus] = React.useState(false)
5
+ const [hover, setHover] = React.useState(false)
5
6
  return (
6
7
  <input
7
8
  onFocus={(e)=>{setFocus(true);rest.onFocus&&rest.onFocus(e)}}
8
9
  onBlur={(e)=>{setFocus(false);rest.onBlur&&rest.onBlur(e)}}
10
+ onMouseEnter={()=>setHover(true)}
11
+ onMouseLeave={()=>setHover(false)}
9
12
  style={{
10
13
  width:'100%',height:36,padding:'0 12px',
11
14
  fontFamily:'var(--font-sans)',fontSize:'var(--text-control)',color:'var(--foreground)',
12
- background:'var(--surface-2)',
15
+ // A hovered field lifts its SURFACE. Moving its edge from .15 to .16
16
+ // is a state you cannot see, and a state you cannot see is dead code.
17
+ background: hover && !focus ? 'var(--surface-3)' : 'var(--surface-2)',
13
18
  border:'1px solid ' + (invalid ? 'var(--state-error)' : focus ? 'var(--border-focus)' : 'var(--border-control)'),
14
- borderRadius:'var(--radius-sm)',
15
- transition:'border-color var(--duration-fast) var(--ease-out)',
19
+ borderRadius:'var(--radius-md)',
20
+ outline:'none',
21
+ // Focus is the edge brightening plus a soft halo just outside it — the
22
+ // reference's .composer-box:focus-within, and the same recipe
23
+ // tokens/base.css gives a bare <input>. Not a second hard ring.
24
+ boxShadow: focus ? 'var(--ring-focus)' : 'none',
25
+ transition:'border-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out)',
16
26
  ...style,
17
27
  }}
18
28
  {...rest}
@@ -15,24 +15,35 @@ export function Tabs({ defaultValue, value, onValueChange, style, children, ...r
15
15
 
16
16
  export function TabsList({ style, children, ...rest }) {
17
17
  return (
18
- <div role="tablist" style={{display:'inline-flex',alignItems:'center',gap:4,padding:4,borderRadius:'var(--radius-sm)',background:'var(--muted)',border:'1px solid var(--border)',...style}} {...rest}>{children}</div>
18
+ // alignSelf: a segmented control is as wide as its segments. Without it the
19
+ // list is a flex ITEM of the Tabs column and stretches to the full row,
20
+ // which turns a compact control into a full-width bar.
21
+ <div role="tablist" style={{display:'inline-flex',alignSelf:'flex-start',maxWidth:'100%',overflowX:'auto',alignItems:'center',gap:2,padding:3,borderRadius:'var(--radius-lg)',background:'var(--surface-2)',border:'1px solid var(--border)',...style}} {...rest}>{children}</div>
19
22
  )
20
23
  }
21
24
 
22
25
  export function TabsTrigger({ value, style, children, ...rest }) {
23
26
  const { value: active, setValue } = React.useContext(Ctx)
27
+ const [hover, setHover] = React.useState(false)
24
28
  const on = active === value
25
29
  return (
26
30
  <button
27
31
  role="tab" aria-selected={on} onClick={() => setValue(value)}
32
+ onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
28
33
  style={{
29
- display:'inline-flex',alignItems:'center',gap:8,height:30,padding:'0 12px',
34
+ display:'inline-flex',alignItems:'center',gap:8,height:30,padding:'0 14px',
30
35
  fontFamily:'var(--font-sans)',fontSize:'var(--text-sm)',fontWeight:'var(--weight-medium)',
31
- color: on ? 'var(--text-primary)' : 'var(--text-helper)',
32
- background: on ? 'var(--secondary)' : 'transparent',
33
- border:'1px solid ' + (on ? 'var(--border)' : 'transparent'),
34
- borderRadius:'calc(var(--radius-sm) - 2px)',cursor:'pointer',whiteSpace:'nowrap',
35
- transition:'color var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out)',
36
+ letterSpacing:'var(--tracking-tight)',
37
+ color: on ? 'var(--text-primary)' : hover ? 'var(--text-secondary)' : 'var(--text-helper)',
38
+ // The selected tab is a surface that has RISEN out of the track: it
39
+ // lifts a rung, catches the light on its top edge and casts a small
40
+ // drop. A selected tab that only changes colour reads as a link that
41
+ // happens to be a different grey.
42
+ background: on ? 'var(--surface-3)' : 'transparent',
43
+ border:'1px solid ' + (on ? 'var(--border-strong)' : 'transparent'),
44
+ boxShadow: on ? 'var(--edge-highlight), var(--shadow-sm)' : 'none',
45
+ borderRadius:'calc(var(--radius-lg) - 3px)',cursor:'pointer',whiteSpace:'nowrap',
46
+ transition:'color var(--duration-fast) var(--ease-out), background-color var(--duration-fast) var(--ease-out), border-color var(--duration-fast) var(--ease-out), box-shadow var(--duration-fast) var(--ease-out), transform var(--duration-press) var(--ease-out)',
36
47
  ...style,
37
48
  }}
38
49
  {...rest}
@@ -11,7 +11,7 @@ export function Dialog({ open, onOpenChange, children }) {
11
11
  return (
12
12
  <div
13
13
  onClick={() => onOpenChange && onOpenChange(false)}
14
- style={{position:'fixed',inset:0,zIndex:'var(--z-modal)',display:'flex',alignItems:'center',justifyContent:'center',padding:24,background:'var(--surface-scrim)',backdropFilter:'blur(4px)',animation:'hanzo-fade-up var(--duration-fast) var(--ease-out)'}}
14
+ style={{position:'fixed',inset:0,zIndex:'var(--z-modal)',display:'flex',alignItems:'center',justifyContent:'center',padding:24,background:'var(--surface-scrim)',backdropFilter:'blur(8px) saturate(140%)',animation:'hanzo-fade-up var(--duration-fast) var(--ease-out)'}}
15
15
  >
16
16
  {children}
17
17
  </div>
@@ -22,7 +22,7 @@ export function DialogContent({ width = 480, style, children, ...rest }) {
22
22
  return (
23
23
  <div
24
24
  role="dialog" aria-modal="true" onClick={(e) => e.stopPropagation()}
25
- style={{width:'100%',maxWidth:width,maxHeight:'85vh',overflowY:'auto',padding:24,display:'flex',flexDirection:'column',gap:16,background:'var(--popover)',color:'var(--popover-foreground)',border:'1px solid var(--border)',borderRadius:'var(--radius-xl)',boxShadow:'var(--shadow-floating)',...style}}
25
+ style={{width:'100%',maxWidth:width,maxHeight:'85vh',overflowY:'auto',padding:24,display:'flex',flexDirection:'column',gap:16,background:'var(--popover)',color:'var(--popover-foreground)',border:'1px solid var(--border-strong)',borderRadius:'var(--radius-xl)',boxShadow:'var(--edge-highlight), var(--shadow-floating)',animation:'hanzo-zoom-in var(--duration-base) var(--ease-emphasis)',...style}}
26
26
  {...rest}
27
27
  >{children}</div>
28
28
  )
@@ -19,7 +19,7 @@ export function DropdownMenu({ align = 'right', hover = false, trigger, style, c
19
19
  <span onClick={() => setOpen((v) => !v)} style={{display:'inline-flex'}}>{trigger}</span>
20
20
  {open && (
21
21
  <div style={{position:'absolute',top:'100%',[align]:0,paddingTop:12,zIndex:'var(--z-dropdown)',minWidth:208}}>
22
- <div style={{display:'flex',flexDirection:'column',padding:8,background:'var(--surface-overlay)',border:'1px solid var(--border)',borderRadius:'var(--radius-xl)',boxShadow:'var(--shadow-floating)',backdropFilter:'blur(16px)',animation:'hanzo-fade-down var(--duration-fast) var(--ease-out)'}}>
22
+ <div style={{display:'flex',flexDirection:'column',padding:6,background:'var(--surface-overlay)',border:'1px solid var(--border-strong)',borderRadius:'var(--radius-lg)',boxShadow:'var(--edge-highlight), var(--shadow-floating)',backdropFilter:'blur(20px) saturate(180%)',animation:'hanzo-zoom-in var(--duration-fast) var(--ease-emphasis)'}}>
23
23
  {children}
24
24
  </div>
25
25
  </div>
@@ -33,16 +33,20 @@ export function DropdownMenuItem({ desc, style, children, ...rest }) {
33
33
  return (
34
34
  <a
35
35
  onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
36
- style={{display:'block',padding: desc ? '10px 12px' : '8px 12px',borderRadius:'var(--radius-sm)',background: hover ? 'var(--glass)' : 'transparent',cursor:'pointer',textDecoration:'none',transition:'background-color var(--duration-fast) var(--ease-out)',...style}}
36
+ style={{display:'block',padding: desc ? '10px 12px' : '8px 12px',borderRadius:'var(--radius-sm)',background: hover ? 'var(--glass-strong)' : 'transparent',cursor:'pointer',textDecoration:'none',transition:'background-color var(--duration-fast) var(--ease-out)',...style}}
37
37
  {...rest}
38
38
  >
39
- <span style={{display:'block',fontSize:'var(--text-sm)',fontWeight:'var(--weight-medium)',color:'var(--neutral-100)'}}>{children}</span>
40
- {desc && <span style={{display:'block',marginTop:2,fontSize:'var(--text-xs)',color:'var(--neutral-500)'}}>{desc}</span>}
39
+ {/* --text-primary / --text-tertiary, not --neutral-100 / --neutral-500.
40
+ The neutral ladder is a PALETTE: it does not invert, so a menu item
41
+ painted from it rendered #f5f5f5 text on the light theme's #ffffff
42
+ popover — the item did not change colour, it stopped being legible. */}
43
+ <span style={{display:'block',fontSize:'var(--text-sm)',fontWeight:'var(--weight-medium)',color:'var(--text-primary)'}}>{children}</span>
44
+ {desc && <span style={{display:'block',marginTop:2,fontSize:'var(--text-xs)',lineHeight:'var(--leading-normal)',color:'var(--text-tertiary)'}}>{desc}</span>}
41
45
  </a>
42
46
  )
43
47
  }
44
48
  export function DropdownMenuLabel({ style, children, ...rest }) {
45
- return <span style={{padding:'6px 12px',fontSize:'var(--text-xs)',fontWeight:'var(--weight-medium)',textTransform:'uppercase',letterSpacing:'var(--tracking-wide)',color:'var(--neutral-500)',...style}} {...rest}>{children}</span>
49
+ return <span style={{padding:'6px 12px',fontSize:'var(--text-xs)',fontWeight:'var(--weight-semibold)',textTransform:'uppercase',letterSpacing:'var(--tracking-widest)',color:'var(--text-tertiary)',...style}} {...rest}>{children}</span>
46
50
  }
47
51
  export function DropdownMenuSeparator({ style }) {
48
52
  return <span style={{height:1,margin:'6px 4px',background:'var(--border)',...style}} />
@@ -36,22 +36,26 @@ export declare const colors: {
36
36
  readonly popover: "#0f0f0f";
37
37
  readonly 'popover-foreground': "#fafafa";
38
38
  readonly primary: "#fafafa";
39
- readonly 'primary-hover': "#d4d4d4";
39
+ readonly 'primary-hover': "#e5e5e5";
40
40
  readonly 'primary-foreground': "#0a0a0a";
41
41
  readonly secondary: "#262626";
42
+ readonly 'secondary-hover': "#333333";
42
43
  readonly 'secondary-foreground': "#fafafa";
43
44
  readonly muted: "#171717";
44
45
  readonly 'muted-foreground': "#a3a3a3";
45
46
  readonly accent: "#262626";
46
47
  readonly 'accent-foreground': "#fafafa";
47
- readonly destructive: "#666666";
48
+ readonly destructive: "var(--state-error)";
49
+ readonly 'destructive-hover': "#dc2626";
48
50
  readonly 'destructive-foreground': "#fafafa";
49
51
  readonly border: "var(--white-10)";
50
52
  readonly 'border-strong': "var(--white-16)";
51
- readonly 'border-control': "var(--neutral-500)";
52
- readonly 'border-focus': "var(--neutral-400)";
53
+ readonly 'border-control': "var(--white-15)";
54
+ readonly 'border-focus': "var(--white-22)";
55
+ readonly 'border-selected': "var(--white-30)";
53
56
  readonly input: "var(--border-control)";
54
- readonly ring: "var(--neutral-500)";
57
+ readonly ring: "var(--white-40)";
58
+ readonly 'ring-halo': "var(--white-10)";
55
59
  readonly brand: "#e4e4e7";
56
60
  readonly 'brand-foreground': "#09090b";
57
61
  readonly 'brand-muted': "#a3a3a3";
@@ -61,10 +65,10 @@ export declare const colors: {
61
65
  readonly glass: "var(--white-05)";
62
66
  readonly 'glass-strong': "var(--white-08)";
63
67
  readonly 'surface-page': "var(--background)";
64
- readonly 'surface-card': "rgb(23 23 23 / .5)";
65
- readonly 'surface-card-emphasis': "rgb(23 23 23 / .8)";
66
- readonly 'surface-card-quiet': "rgb(23 23 23 / .4)";
67
- readonly 'surface-overlay': "rgb(10 10 10 / .95)";
68
+ readonly 'surface-card': "rgb(38 38 38 / .5)";
69
+ readonly 'surface-card-emphasis': "rgb(38 38 38 / .75)";
70
+ readonly 'surface-card-quiet': "rgb(38 38 38 / .35)";
71
+ readonly 'surface-overlay': "rgb(23 23 23 / .92)";
68
72
  readonly 'surface-header': "rgb(0 0 0 / .7)";
69
73
  readonly 'surface-scrim': "rgb(0 0 0 / .8)";
70
74
  readonly 'surface-0': "var(--background)";
@@ -222,9 +226,11 @@ export declare const radius: {
222
226
  /** elevation tokens (from tokens/elevation.css). Values are raw CSS. */
223
227
  export declare const elevation: {
224
228
  readonly 'shadow-none': "none";
225
- readonly 'shadow-floating': "0 25px 50px -12px rgb(0 0 0 / .25)";
229
+ readonly 'shadow-floating': "0 24px 60px -16px rgb(0 0 0 / .75)";
226
230
  readonly 'shadow-inset-hairline': "inset 0 0 0 1px var(--white-10)";
227
- readonly 'ring-focus': "0 0 0 2px var(--ring)";
231
+ readonly 'edge-highlight': "inset 0 1px 0 0 rgb(255 255 255 / .10)";
232
+ readonly bloom: "0 0 24px -2px rgb(255 255 255 / .28)";
233
+ readonly 'ring-focus': "0 0 0 3px var(--ring-halo)";
228
234
  readonly 'shadow-sm': "0 1px 2px 0 rgb(0 0 0 / .40)";
229
235
  readonly shadow: "0 1px 3px 0 rgb(0 0 0 / .45), 0 1px 2px -1px rgb(0 0 0 / .45)";
230
236
  readonly 'shadow-md': "0 4px 6px -1px rgb(0 0 0 / .50), 0 2px 4px -2px rgb(0 0 0 / .50)";
@@ -234,6 +240,7 @@ export declare const elevation: {
234
240
  readonly 'glow-hero': "radial-gradient(circle,rgb(255 255 255 / .12) 0%,transparent 68%)";
235
241
  readonly 'glow-hero-blur': "120px";
236
242
  readonly 'sheen-card': "radial-gradient(120% 120% at 80% 0%,rgb(255 255 255 / .08) 0%,transparent 55%)";
243
+ readonly 'sheen-edge': "linear-gradient(90deg,transparent,rgb(255 255 255 / .14) 50%,transparent)";
237
244
  readonly 'gradient-chrome': "linear-gradient(to right,#ffffff,var(--white-80),var(--white-60))";
238
245
  readonly 'gradient-chrome-2': "linear-gradient(to right,#ffffff,var(--neutral-500))";
239
246
  readonly 'gradient-protect': "linear-gradient(to bottom,var(--white-10),transparent)";
@@ -245,8 +252,10 @@ export declare const motion: {
245
252
  readonly 'duration-slow': "400ms";
246
253
  readonly 'duration-slower': "500ms";
247
254
  readonly 'duration-glow': "9s";
255
+ readonly 'duration-press': "90ms";
248
256
  readonly 'ease-out': "cubic-bezier(0,0,0.2,1)";
249
257
  readonly 'ease-in-out': "cubic-bezier(0.4,0,0.2,1)";
258
+ readonly 'ease-emphasis': "cubic-bezier(0.16,1,0.3,1)";
250
259
  readonly stagger: "60ms";
251
260
  readonly 'entry-rise': "16px";
252
261
  readonly 'entry-rise-lg': "24px";
@@ -313,22 +322,26 @@ export declare const cssVars: {
313
322
  readonly '--popover': "#0f0f0f";
314
323
  readonly '--popover-foreground': "#fafafa";
315
324
  readonly '--primary': "#fafafa";
316
- readonly '--primary-hover': "#d4d4d4";
325
+ readonly '--primary-hover': "#e5e5e5";
317
326
  readonly '--primary-foreground': "#0a0a0a";
318
327
  readonly '--secondary': "#262626";
328
+ readonly '--secondary-hover': "#333333";
319
329
  readonly '--secondary-foreground': "#fafafa";
320
330
  readonly '--muted': "#171717";
321
331
  readonly '--muted-foreground': "#a3a3a3";
322
332
  readonly '--accent': "#262626";
323
333
  readonly '--accent-foreground': "#fafafa";
324
- readonly '--destructive': "#666666";
334
+ readonly '--destructive': "var(--state-error)";
335
+ readonly '--destructive-hover': "#dc2626";
325
336
  readonly '--destructive-foreground': "#fafafa";
326
337
  readonly '--border': "var(--white-10)";
327
338
  readonly '--border-strong': "var(--white-16)";
328
- readonly '--border-control': "var(--neutral-500)";
329
- readonly '--border-focus': "var(--neutral-400)";
339
+ readonly '--border-control': "var(--white-15)";
340
+ readonly '--border-focus': "var(--white-22)";
341
+ readonly '--border-selected': "var(--white-30)";
330
342
  readonly '--input': "var(--border-control)";
331
- readonly '--ring': "var(--neutral-500)";
343
+ readonly '--ring': "var(--white-40)";
344
+ readonly '--ring-halo': "var(--white-10)";
332
345
  readonly '--brand': "#e4e4e7";
333
346
  readonly '--brand-foreground': "#09090b";
334
347
  readonly '--brand-muted': "#a3a3a3";
@@ -338,10 +351,10 @@ export declare const cssVars: {
338
351
  readonly '--glass': "var(--white-05)";
339
352
  readonly '--glass-strong': "var(--white-08)";
340
353
  readonly '--surface-page': "var(--background)";
341
- readonly '--surface-card': "rgb(23 23 23 / .5)";
342
- readonly '--surface-card-emphasis': "rgb(23 23 23 / .8)";
343
- readonly '--surface-card-quiet': "rgb(23 23 23 / .4)";
344
- readonly '--surface-overlay': "rgb(10 10 10 / .95)";
354
+ readonly '--surface-card': "rgb(38 38 38 / .5)";
355
+ readonly '--surface-card-emphasis': "rgb(38 38 38 / .75)";
356
+ readonly '--surface-card-quiet': "rgb(38 38 38 / .35)";
357
+ readonly '--surface-overlay': "rgb(23 23 23 / .92)";
345
358
  readonly '--surface-header': "rgb(0 0 0 / .7)";
346
359
  readonly '--surface-scrim': "rgb(0 0 0 / .8)";
347
360
  readonly '--surface-0': "var(--background)";
@@ -484,9 +497,11 @@ export declare const cssVars: {
484
497
  readonly '--radius-composer': "28px";
485
498
  readonly '--radius-full': "9999px";
486
499
  readonly '--shadow-none': "none";
487
- readonly '--shadow-floating': "0 25px 50px -12px rgb(0 0 0 / .25)";
500
+ readonly '--shadow-floating': "0 24px 60px -16px rgb(0 0 0 / .75)";
488
501
  readonly '--shadow-inset-hairline': "inset 0 0 0 1px var(--white-10)";
489
- readonly '--ring-focus': "0 0 0 2px var(--ring)";
502
+ readonly '--edge-highlight': "inset 0 1px 0 0 rgb(255 255 255 / .10)";
503
+ readonly '--bloom': "0 0 24px -2px rgb(255 255 255 / .28)";
504
+ readonly '--ring-focus': "0 0 0 3px var(--ring-halo)";
490
505
  readonly '--shadow-sm': "0 1px 2px 0 rgb(0 0 0 / .40)";
491
506
  readonly '--shadow': "0 1px 3px 0 rgb(0 0 0 / .45), 0 1px 2px -1px rgb(0 0 0 / .45)";
492
507
  readonly '--shadow-md': "0 4px 6px -1px rgb(0 0 0 / .50), 0 2px 4px -2px rgb(0 0 0 / .50)";
@@ -496,6 +511,7 @@ export declare const cssVars: {
496
511
  readonly '--glow-hero': "radial-gradient(circle,rgb(255 255 255 / .12) 0%,transparent 68%)";
497
512
  readonly '--glow-hero-blur': "120px";
498
513
  readonly '--sheen-card': "radial-gradient(120% 120% at 80% 0%,rgb(255 255 255 / .08) 0%,transparent 55%)";
514
+ readonly '--sheen-edge': "linear-gradient(90deg,transparent,rgb(255 255 255 / .14) 50%,transparent)";
499
515
  readonly '--gradient-chrome': "linear-gradient(to right,#ffffff,var(--white-80),var(--white-60))";
500
516
  readonly '--gradient-chrome-2': "linear-gradient(to right,#ffffff,var(--neutral-500))";
501
517
  readonly '--gradient-protect': "linear-gradient(to bottom,var(--white-10),transparent)";
@@ -504,8 +520,10 @@ export declare const cssVars: {
504
520
  readonly '--duration-slow': "400ms";
505
521
  readonly '--duration-slower': "500ms";
506
522
  readonly '--duration-glow': "9s";
523
+ readonly '--duration-press': "90ms";
507
524
  readonly '--ease-out': "cubic-bezier(0,0,0.2,1)";
508
525
  readonly '--ease-in-out': "cubic-bezier(0.4,0,0.2,1)";
526
+ readonly '--ease-emphasis': "cubic-bezier(0.16,1,0.3,1)";
509
527
  readonly '--stagger': "60ms";
510
528
  readonly '--entry-rise': "16px";
511
529
  readonly '--entry-rise-lg': "24px";
@@ -1 +1 @@
1
- {"version":3,"file":"tokens.gen.d.ts","sourceRoot":"","sources":["../src/tokens.gen.ts"],"names":[],"mappings":"AAIA,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFT,CAAA;AAEV,0EAA0E;AAC1E,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+Db,CAAA;AAEV,oEAAoE;AACpE,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CV,CAAA;AAEV,8DAA8D;AAC9D,eAAO,MAAM,IAAI;;;;;;;;;;;;CAYP,CAAA;AAEV,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;CAST,CAAA;AAEV,wEAAwE;AACxE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;CAiBZ,CAAA;AAEV,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;;;CAWT,CAAA;AAEV,6DAA6D;AAC7D,eAAO,MAAM,MAAM;;;;;;;;;;;;CAYT,CAAA;AAEV,gEAAgE;AAChE,eAAO,MAAM,KAAK;;;;;;CAMR,CAAA;AAEV,8DAA8D;AAC9D,eAAO,MAAM,IAAI,IAEP,CAAA;AAEV,sFAAsF;AACtF,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyPV,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,OAAO,CAAA"}
1
+ {"version":3,"file":"tokens.gen.d.ts","sourceRoot":"","sources":["../src/tokens.gen.ts"],"names":[],"mappings":"AAIA,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyFT,CAAA;AAEV,0EAA0E;AAC1E,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+Db,CAAA;AAEV,oEAAoE;AACpE,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA0CV,CAAA;AAEV,8DAA8D;AAC9D,eAAO,MAAM,IAAI;;;;;;;;;;;;CAYP,CAAA;AAEV,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;CAST,CAAA;AAEV,wEAAwE;AACxE,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;CAoBZ,CAAA;AAEV,kEAAkE;AAClE,eAAO,MAAM,MAAM;;;;;;;;;;;;;CAaT,CAAA;AAEV,6DAA6D;AAC7D,eAAO,MAAM,MAAM;;;;;;;;;;;;CAYT,CAAA;AAEV,gEAAgE;AAChE,eAAO,MAAM,KAAK;;;;;;CAMR,CAAA;AAEV,8DAA8D;AAC9D,eAAO,MAAM,IAAI,IAEP,CAAA;AAEV,sFAAsF;AACtF,eAAO,MAAM,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkQV,CAAA;AAEV,MAAM,MAAM,UAAU,GAAG,MAAM,OAAO,OAAO,CAAA"}
@@ -39,22 +39,26 @@ export const colors = {
39
39
  'popover': '#0f0f0f',
40
40
  'popover-foreground': '#fafafa',
41
41
  'primary': '#fafafa',
42
- 'primary-hover': '#d4d4d4',
42
+ 'primary-hover': '#e5e5e5',
43
43
  'primary-foreground': '#0a0a0a',
44
44
  'secondary': '#262626',
45
+ 'secondary-hover': '#333333',
45
46
  'secondary-foreground': '#fafafa',
46
47
  'muted': '#171717',
47
48
  'muted-foreground': '#a3a3a3',
48
49
  'accent': '#262626',
49
50
  'accent-foreground': '#fafafa',
50
- 'destructive': '#666666',
51
+ 'destructive': 'var(--state-error)',
52
+ 'destructive-hover': '#dc2626',
51
53
  'destructive-foreground': '#fafafa',
52
54
  'border': 'var(--white-10)',
53
55
  'border-strong': 'var(--white-16)',
54
- 'border-control': 'var(--neutral-500)',
55
- 'border-focus': 'var(--neutral-400)',
56
+ 'border-control': 'var(--white-15)',
57
+ 'border-focus': 'var(--white-22)',
58
+ 'border-selected': 'var(--white-30)',
56
59
  'input': 'var(--border-control)',
57
- 'ring': 'var(--neutral-500)',
60
+ 'ring': 'var(--white-40)',
61
+ 'ring-halo': 'var(--white-10)',
58
62
  'brand': '#e4e4e7',
59
63
  'brand-foreground': '#09090b',
60
64
  'brand-muted': '#a3a3a3',
@@ -64,10 +68,10 @@ export const colors = {
64
68
  'glass': 'var(--white-05)',
65
69
  'glass-strong': 'var(--white-08)',
66
70
  'surface-page': 'var(--background)',
67
- 'surface-card': 'rgb(23 23 23 / .5)',
68
- 'surface-card-emphasis': 'rgb(23 23 23 / .8)',
69
- 'surface-card-quiet': 'rgb(23 23 23 / .4)',
70
- 'surface-overlay': 'rgb(10 10 10 / .95)',
71
+ 'surface-card': 'rgb(38 38 38 / .5)',
72
+ 'surface-card-emphasis': 'rgb(38 38 38 / .75)',
73
+ 'surface-card-quiet': 'rgb(38 38 38 / .35)',
74
+ 'surface-overlay': 'rgb(23 23 23 / .92)',
71
75
  'surface-header': 'rgb(0 0 0 / .7)',
72
76
  'surface-scrim': 'rgb(0 0 0 / .8)',
73
77
  'surface-0': 'var(--background)',
@@ -225,9 +229,11 @@ export const radius = {
225
229
  /** elevation tokens (from tokens/elevation.css). Values are raw CSS. */
226
230
  export const elevation = {
227
231
  'shadow-none': 'none',
228
- 'shadow-floating': '0 25px 50px -12px rgb(0 0 0 / .25)',
232
+ 'shadow-floating': '0 24px 60px -16px rgb(0 0 0 / .75)',
229
233
  'shadow-inset-hairline': 'inset 0 0 0 1px var(--white-10)',
230
- 'ring-focus': '0 0 0 2px var(--ring)',
234
+ 'edge-highlight': 'inset 0 1px 0 0 rgb(255 255 255 / .10)',
235
+ 'bloom': '0 0 24px -2px rgb(255 255 255 / .28)',
236
+ 'ring-focus': '0 0 0 3px var(--ring-halo)',
231
237
  'shadow-sm': '0 1px 2px 0 rgb(0 0 0 / .40)',
232
238
  'shadow': '0 1px 3px 0 rgb(0 0 0 / .45), 0 1px 2px -1px rgb(0 0 0 / .45)',
233
239
  'shadow-md': '0 4px 6px -1px rgb(0 0 0 / .50), 0 2px 4px -2px rgb(0 0 0 / .50)',
@@ -237,6 +243,7 @@ export const elevation = {
237
243
  'glow-hero': 'radial-gradient(circle,rgb(255 255 255 / .12) 0%,transparent 68%)',
238
244
  'glow-hero-blur': '120px',
239
245
  'sheen-card': 'radial-gradient(120% 120% at 80% 0%,rgb(255 255 255 / .08) 0%,transparent 55%)',
246
+ 'sheen-edge': 'linear-gradient(90deg,transparent,rgb(255 255 255 / .14) 50%,transparent)',
240
247
  'gradient-chrome': 'linear-gradient(to right,#ffffff,var(--white-80),var(--white-60))',
241
248
  'gradient-chrome-2': 'linear-gradient(to right,#ffffff,var(--neutral-500))',
242
249
  'gradient-protect': 'linear-gradient(to bottom,var(--white-10),transparent)',
@@ -248,8 +255,10 @@ export const motion = {
248
255
  'duration-slow': '400ms',
249
256
  'duration-slower': '500ms',
250
257
  'duration-glow': '9s',
258
+ 'duration-press': '90ms',
251
259
  'ease-out': 'cubic-bezier(0,0,0.2,1)',
252
260
  'ease-in-out': 'cubic-bezier(0.4,0,0.2,1)',
261
+ 'ease-emphasis': 'cubic-bezier(0.16,1,0.3,1)',
253
262
  'stagger': '60ms',
254
263
  'entry-rise': '16px',
255
264
  'entry-rise-lg': '24px',
@@ -316,22 +325,26 @@ export const cssVars = {
316
325
  '--popover': '#0f0f0f',
317
326
  '--popover-foreground': '#fafafa',
318
327
  '--primary': '#fafafa',
319
- '--primary-hover': '#d4d4d4',
328
+ '--primary-hover': '#e5e5e5',
320
329
  '--primary-foreground': '#0a0a0a',
321
330
  '--secondary': '#262626',
331
+ '--secondary-hover': '#333333',
322
332
  '--secondary-foreground': '#fafafa',
323
333
  '--muted': '#171717',
324
334
  '--muted-foreground': '#a3a3a3',
325
335
  '--accent': '#262626',
326
336
  '--accent-foreground': '#fafafa',
327
- '--destructive': '#666666',
337
+ '--destructive': 'var(--state-error)',
338
+ '--destructive-hover': '#dc2626',
328
339
  '--destructive-foreground': '#fafafa',
329
340
  '--border': 'var(--white-10)',
330
341
  '--border-strong': 'var(--white-16)',
331
- '--border-control': 'var(--neutral-500)',
332
- '--border-focus': 'var(--neutral-400)',
342
+ '--border-control': 'var(--white-15)',
343
+ '--border-focus': 'var(--white-22)',
344
+ '--border-selected': 'var(--white-30)',
333
345
  '--input': 'var(--border-control)',
334
- '--ring': 'var(--neutral-500)',
346
+ '--ring': 'var(--white-40)',
347
+ '--ring-halo': 'var(--white-10)',
335
348
  '--brand': '#e4e4e7',
336
349
  '--brand-foreground': '#09090b',
337
350
  '--brand-muted': '#a3a3a3',
@@ -341,10 +354,10 @@ export const cssVars = {
341
354
  '--glass': 'var(--white-05)',
342
355
  '--glass-strong': 'var(--white-08)',
343
356
  '--surface-page': 'var(--background)',
344
- '--surface-card': 'rgb(23 23 23 / .5)',
345
- '--surface-card-emphasis': 'rgb(23 23 23 / .8)',
346
- '--surface-card-quiet': 'rgb(23 23 23 / .4)',
347
- '--surface-overlay': 'rgb(10 10 10 / .95)',
357
+ '--surface-card': 'rgb(38 38 38 / .5)',
358
+ '--surface-card-emphasis': 'rgb(38 38 38 / .75)',
359
+ '--surface-card-quiet': 'rgb(38 38 38 / .35)',
360
+ '--surface-overlay': 'rgb(23 23 23 / .92)',
348
361
  '--surface-header': 'rgb(0 0 0 / .7)',
349
362
  '--surface-scrim': 'rgb(0 0 0 / .8)',
350
363
  '--surface-0': 'var(--background)',
@@ -487,9 +500,11 @@ export const cssVars = {
487
500
  '--radius-composer': '28px',
488
501
  '--radius-full': '9999px',
489
502
  '--shadow-none': 'none',
490
- '--shadow-floating': '0 25px 50px -12px rgb(0 0 0 / .25)',
503
+ '--shadow-floating': '0 24px 60px -16px rgb(0 0 0 / .75)',
491
504
  '--shadow-inset-hairline': 'inset 0 0 0 1px var(--white-10)',
492
- '--ring-focus': '0 0 0 2px var(--ring)',
505
+ '--edge-highlight': 'inset 0 1px 0 0 rgb(255 255 255 / .10)',
506
+ '--bloom': '0 0 24px -2px rgb(255 255 255 / .28)',
507
+ '--ring-focus': '0 0 0 3px var(--ring-halo)',
493
508
  '--shadow-sm': '0 1px 2px 0 rgb(0 0 0 / .40)',
494
509
  '--shadow': '0 1px 3px 0 rgb(0 0 0 / .45), 0 1px 2px -1px rgb(0 0 0 / .45)',
495
510
  '--shadow-md': '0 4px 6px -1px rgb(0 0 0 / .50), 0 2px 4px -2px rgb(0 0 0 / .50)',
@@ -499,6 +514,7 @@ export const cssVars = {
499
514
  '--glow-hero': 'radial-gradient(circle,rgb(255 255 255 / .12) 0%,transparent 68%)',
500
515
  '--glow-hero-blur': '120px',
501
516
  '--sheen-card': 'radial-gradient(120% 120% at 80% 0%,rgb(255 255 255 / .08) 0%,transparent 55%)',
517
+ '--sheen-edge': 'linear-gradient(90deg,transparent,rgb(255 255 255 / .14) 50%,transparent)',
502
518
  '--gradient-chrome': 'linear-gradient(to right,#ffffff,var(--white-80),var(--white-60))',
503
519
  '--gradient-chrome-2': 'linear-gradient(to right,#ffffff,var(--neutral-500))',
504
520
  '--gradient-protect': 'linear-gradient(to bottom,var(--white-10),transparent)',
@@ -507,8 +523,10 @@ export const cssVars = {
507
523
  '--duration-slow': '400ms',
508
524
  '--duration-slower': '500ms',
509
525
  '--duration-glow': '9s',
526
+ '--duration-press': '90ms',
510
527
  '--ease-out': 'cubic-bezier(0,0,0.2,1)',
511
528
  '--ease-in-out': 'cubic-bezier(0.4,0,0.2,1)',
529
+ '--ease-emphasis': 'cubic-bezier(0.16,1,0.3,1)',
512
530
  '--stagger': '60ms',
513
531
  '--entry-rise': '16px',
514
532
  '--entry-rise-lg': '24px',
@@ -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>