@putdotio/design 1.3.0 → 1.5.0

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.
package/DESIGN.md CHANGED
@@ -24,17 +24,17 @@ typography:
24
24
  ui:
25
25
  family: "\"GT America\", sans-serif"
26
26
  weight: 400
27
- size: "0.875rem"
27
+ size: "1rem"
28
28
  lineHeight: 1.45
29
29
  display:
30
30
  family: "\"GT America\", sans-serif"
31
31
  weight: 900
32
- size: "6rem"
32
+ size: "96px"
33
33
  lineHeight: 1.1
34
34
  mono:
35
- family: "\"Berkeley Mono\", \"GT America Mono\", monospace"
35
+ family: "\"Berkeley Mono\", monospace"
36
36
  weight: 400
37
- size: "0.8125rem"
37
+ size: "0.875rem"
38
38
  lineHeight: 1.45
39
39
  rounded:
40
40
  sm: "4px"
@@ -74,23 +74,31 @@ Dark app surfaces are the default product mode, but the token contract includes
74
74
 
75
75
  ## Typography
76
76
 
77
- Use GT America for product UI and display. Use GT America Mono for compact product numerics where it matches the app. Use Berkeley Mono for code, logs, identifiers, hashes, and raw technical strings.
77
+ Use GT America for product UI and display. Berkeley Mono is the single mono face: numerics, timestamps, file sizes, ETAs, counts, code, logs, identifiers, hashes, magnet URIs, and filenames. Its tabular figures keep metadata columns aligned, so pair it with `font-variant-numeric: tabular-nums` wherever numbers sit in a column.
78
+
79
+ The mono role is web and mobile only. TV surfaces have no mono face — 10-foot numerics render in GT America with tabular figures.
78
80
 
79
81
  Body UI text should stay readable and dense. Use medium weight for labels and controls, bold weight only where the hierarchy earns it, and black weight for deliberate display moments.
80
82
 
83
+ The root font-size is responsive like the product: 14px, stepping to 15px at the `--bp-lg` breakpoint. Body, labels, and inputs sit at `--fs-base` (1rem, equal to the root); captions and button labels sit at `--fs-sm` (0.875rem). The display tiers (`--fs-2xl`, `--fs-3xl`, `--fs-display`) are fixed pixel sizes and do not scale with the root.
84
+
81
85
  ## Layout & Spacing
82
86
 
83
87
  put.io layouts are file-browser layouts first: lists, rows, columns, sidebars, toolbars, and sheets. Prefer whitespace and subtle dividers before card-heavy composition.
84
88
 
85
89
  The spacing scale is intentionally steep: `4, 8, 16, 32, 64, 128, 256, 512`. Use it consistently rather than tuning one-off gaps.
86
90
 
91
+ Stacking uses the token scale — `--z-dropdown` (1000), `--z-sticky` (1100), `--z-modal` (1300), `--z-notification` (1400), `--z-tooltip` (1500) — gapped for platform chrome; never invent z-index numbers. Breakpoints (`--bp-sm`/`--bp-md`/`--bp-lg` = 640/768/1280px) mirror the product's responsive tiers; CSS media queries cannot read custom properties, so write the literal pixels in `@media` and keep them in sync with the tokens.
92
+
87
93
  ## Elevation & Depth
88
94
 
89
95
  Elevation should clarify interaction, not decorate. Use borders and soft shadows for popovers, modals, menus, TV focus, and draggable/drop targets. Avoid decorative glow except where it is part of a focused TV state.
90
96
 
91
97
  ## Shapes
92
98
 
93
- The default radius is `6px`. Use `4px` for tight controls, `8px` or `10px` for larger panels, and pill radius for segmented controls, badges, and TV action pills.
99
+ The default radius is `6px`. Use `4px` for tight controls, `8px` or `10px` for larger panels, and pill radius for segmented controls and badges.
100
+
101
+ TV is the exception: every 10-foot surface — list rows, buttons, sheets, cards, code tiles, keys — uses the single `--radius-tv` (`12px`). TV has one radius, not a scale; the only other radii on a TV surface are intentional pills and circles.
94
102
 
95
103
  ## Components
96
104
 
@@ -100,6 +108,10 @@ Form fields use the shared `--field-*` aliases: `--field-bg` for the fill, `--fi
100
108
 
101
109
  TV components are list-first and focus-first. A TV app is still a file browser, not a poster wall. Roku, native Apple, Android, and web TV repos should consume the generic tokens and generate their own platform bindings.
102
110
 
111
+ TV surfaces are solid token colors — no translucent materials and no blur. Focus is expressed as a fill, never a lift: rows go transparent to `--component-bg-active`, and buttons step both their fill and their border. Navigation is a Home hub that pushes full screens onto a stack; there is no tab bar. Menus are centred modals, not popovers anchored to a trigger.
112
+
113
+ The 10-foot scale lives in the `tv` token group — type steps, spacing ramp, overscan ratios, radius, and z-indices — carried as data for platform adapters rather than emitted into web CSS. Overscan ratios declare their viewport axis: multiply `tv.overscan.x` by viewport width and `tv.overscan.y` by viewport height, then compose screen padding locally with the spacing tokens. Two rules do not cross over: TV has no mono face, and TV stacks `--tv-z-overlay` above `--tv-z-toast`, the reverse of the web `--z-*` order. Emit the two scales separately.
114
+
103
115
  ## Do's and Don'ts
104
116
 
105
117
  Do show raw filenames such as `The.Wire.S03E04.Back.Burners.1080p.BluRay.x264-DEMAND.mkv`.
@@ -108,6 +120,6 @@ Do use Phosphor-style inline SVG for forward-looking icon guidance and no emoji
108
120
 
109
121
  Do keep `DESIGN.md`, `tokens/`, `dist/`, and `system/tokens.css` in agreement.
110
122
 
111
- Don't publish private research, local file paths, internal project links, screenshots, team photos, account data, discount strategy, or auth-gated workspace URLs in the public design repo.
123
+ Don't publish private material in this public repo — the enumerated list lives in the repo's `docs/DISTRIBUTION.md` (Public Safety).
112
124
 
113
- Don't generate Swift, Kotlin, Android XML, or Roku outputs from this repo until a consuming platform repo asks for an adapter.
125
+ Don't generate platform-native outputs (Swift, Kotlin, Android XML, Roku) from this repo — platform repos own their adapters. Policy in the repo's `docs/DISTRIBUTION.md`.
@@ -15,9 +15,19 @@
15
15
  --button-success-bg-hover: hsl(151, 58%, 37%);
16
16
  --button-danger-bg: hsl(358, 75%, 59%);
17
17
  --button-danger-bg-hover: hsl(357, 66%, 53%);
18
+ --button-info-bg: hsl(0, 0%, 56.1%);
18
19
  --button-info-bg-hover: hsl(0, 0%, 52.3%);
20
+ --button-info-fg: hsl(0, 0%, 0%);
21
+ --button-default-bg: hsl(0, 0%, 95.1%);
22
+ --button-default-bg-hover: hsl(0, 0%, 93.0%);
23
+ --button-default-fg: hsl(0, 0%, 9.0%);
19
24
  --input-bg: hsl(0, 0%, 100%);
20
25
  --input-border: hsl(0, 0%, 85.8%);
26
+ --input-border-hover: hsl(0, 0%, 78.0%);
27
+ --input-border-focus: hsl(0, 0%, 78.0%);
28
+ --input-ring: 0 0 0 1px hsl(0, 0%, 78.0%);
29
+ --input-text: hsl(0, 0%, 9.0%);
30
+ --input-placeholder: hsl(0, 0%, 43.5%);
21
31
  --field-bg: hsl(0, 0%, 100%);
22
32
  --field-bg-disabled: hsl(0, 0%, 97.3%);
23
33
  --field-border: hsl(0, 0%, 85.8%);
@@ -47,8 +57,41 @@
47
57
  --input: hsl(0, 0%, 85.8%);
48
58
  --file-row-bg: hsla(0, 0%, 0%, 0);
49
59
  --file-row-bg-hover: hsl(0, 0%, 97.3%);
60
+ --file-row-bg-active: hsl(0, 0%, 97.3%);
61
+ --file-row-border: hsl(0, 0%, 90.9%);
50
62
  --notification-info-bg: hsl(0, 0%, 97.3%);
51
63
  --notification-danger-bg: hsl(2, 100%, 96%);
64
+ --notification-bg: hsl(0, 0%, 95.1%);
65
+ --notification-border: hsl(0, 0%, 88.7%);
66
+ --notification-fg: hsl(0, 0%, 9.0%);
67
+ --notification-icon: hsl(0, 0%, 43.5%);
68
+ --notification-success-bg: hsl(140, 41%, 97%);
69
+ --notification-success-border: hsl(140, 39%, 68%);
70
+ --notification-success-fg: hsl(146, 35%, 17%);
71
+ --notification-danger-border: hsl(2, 81%, 80%);
72
+ --notification-danger-fg: hsl(358, 62%, 24%);
73
+ --menu-bg: hsl(0, 0%, 95.1%);
74
+ --menu-border: hsl(0, 0%, 88.7%);
75
+ --menu-shadow: 0 16px 40px hsla(0, 0%, 0%, 0.12);
76
+ --menu-item-bg-hover: hsl(0, 0%, 93.0%);
77
+ --menu-item-text: hsl(0, 0%, 9.0%);
78
+ --menu-item-icon: hsl(0, 0%, 43.5%);
79
+ --menu-item-shortcut: hsl(0, 0%, 43.5%);
80
+ --menu-item-danger-text: hsl(355, 64%, 49%);
81
+ --menu-item-danger-bg-hover: hsl(2, 100%, 96%);
82
+ --menu-separator: hsl(0, 0%, 88.7%);
83
+ --menu-label: hsl(0, 0%, 43.5%);
84
+ --palette-bg: hsl(0, 0%, 95.1%);
85
+ --palette-border: hsl(0, 0%, 88.7%);
86
+ --palette-shadow: 0 16px 40px hsla(0, 0%, 0%, 0.12);
87
+ --palette-scrim: hsla(0, 0%, 0%, 0.439);
88
+ --palette-item-bg-active: hsl(0, 0%, 93.0%);
89
+ --palette-group-label: hsl(0, 0%, 43.5%);
90
+ --palette-item-meta: hsl(0, 0%, 43.5%);
91
+ --sheet-bg: hsl(0, 0%, 95.1%);
92
+ --sheet-border: hsl(0, 0%, 88.7%);
93
+ --sheet-shadow: 0 16px 40px hsla(0, 0%, 0%, 0.12);
94
+ --sheet-scrim: hsla(0, 0%, 0%, 0.439);
52
95
  --bg: hsl(0, 0%, 99.0%);
53
96
  --bg-secondary: hsl(0, 0%, 97.3%);
54
97
  --component-bg: hsl(0, 0%, 95.1%);
@@ -124,6 +167,7 @@
124
167
  --button-success-fg: hsl(0, 0%, 100%);
125
168
  --button-danger-fg: hsl(0, 0%, 100%);
126
169
  --input-radius: 6px;
170
+ --field-radius: 6px;
127
171
  --panel-radius: 10px;
128
172
  --primary: hsl(44.7, 97.9%, 63.1%);
129
173
  --primary-foreground: hsl(38, 65%, 10%);
@@ -131,6 +175,12 @@
131
175
  --destructive-foreground: hsl(0, 0%, 100%);
132
176
  --ring: hsla(47, 100%, 65%, 0.35);
133
177
  --file-row-icon: hsl(44.7, 97.9%, 63.1%);
178
+ --menu-radius: 8px;
179
+ --menu-item-height: 32px;
180
+ --palette-width: 560px;
181
+ --palette-input-height: 48px;
182
+ --palette-item-height: 36px;
183
+ --sheet-width: 380px;
134
184
  --yellow-solid: hsl(44.7, 97.9%, 63.1%);
135
185
  --shadow-color: hsl(0, 0%, 78.0%);
136
186
  --shadow: hsl(0, 0%, 78.0%);
@@ -141,18 +191,17 @@
141
191
  --shadow-focus: 0 0 0 3px hsla(47, 100%, 65%, 0.35);
142
192
  --font-sans: "GT America", sans-serif;
143
193
  --font-display: "GT America", sans-serif;
144
- --font-ui-mono: "GT America Mono", monospace;
145
- --font-mono: "Berkeley Mono", "GT America Mono", monospace;
194
+ --font-mono: "Berkeley Mono", monospace;
146
195
  --fs-xs: 0.75rem;
147
- --fs-sm: 0.8125rem;
148
- --fs-base: 0.875rem;
149
- --fs-md: 1rem;
150
- --fs-lg: 1.125rem;
151
- --fs-xl: 1.5rem;
152
- --fs-2xl: 2rem;
153
- --fs-3xl: 3rem;
154
- --fs-4xl: 4rem;
155
- --fs-display: 6rem;
196
+ --fs-sm: 0.875rem;
197
+ --fs-base: 1rem;
198
+ --fs-md: 1.125rem;
199
+ --fs-lg: 1.5rem;
200
+ --fs-xl: 2rem;
201
+ --fs-2xl: 48px;
202
+ --fs-3xl: 64px;
203
+ --fs-4xl: 64px;
204
+ --fs-display: 96px;
156
205
  --lh-tight: 1.1;
157
206
  --lh-snug: 1.25;
158
207
  --lh-normal: 1.45;
@@ -179,12 +228,21 @@
179
228
  --radius-md: 8px;
180
229
  --radius-lg: 10px;
181
230
  --radius-pill: 999px;
231
+ --radius-tv: 12px;
182
232
  --border-width: 1px;
183
233
  --ease-out: cubic-bezier(0.22, 1, 0.36, 1);
184
234
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
185
235
  --dur-fast: 120ms;
186
236
  --dur-base: 200ms;
187
237
  --dur-slow: 320ms;
238
+ --z-dropdown: 1000;
239
+ --z-sticky: 1100;
240
+ --z-modal: 1300;
241
+ --z-notification: 1400;
242
+ --z-tooltip: 1500;
243
+ --bp-sm: 640px;
244
+ --bp-md: 768px;
245
+ --bp-lg: 1280px;
188
246
  }
189
247
 
190
248
  /* -- Dark (.dark) --------------------------------------------------- */
@@ -196,9 +254,19 @@
196
254
  --button-success-bg-hover: hsl(151, 68%, 35%);
197
255
  --button-danger-bg: hsl(358, 75%, 59%);
198
256
  --button-danger-bg-hover: hsl(357, 67%, 53%);
257
+ --button-info-bg: hsl(0, 0%, 43.9%);
199
258
  --button-info-bg-hover: hsl(0, 0%, 49.4%);
259
+ --button-info-fg: hsl(0, 0%, 100%);
260
+ --button-default-bg: hsl(0, 0%, 13.6%);
261
+ --button-default-bg-hover: hsl(0, 0%, 15.8%);
262
+ --button-default-fg: hsl(0, 0%, 93.0%);
200
263
  --input-bg: hsl(0, 0%, 8.5%);
201
264
  --input-border: hsl(0, 0%, 24.3%);
265
+ --input-border-hover: hsl(0, 0%, 31.2%);
266
+ --input-border-focus: hsl(0, 0%, 31.2%);
267
+ --input-ring: 0 0 0 1px hsl(0, 0%, 31.2%);
268
+ --input-text: hsl(0, 0%, 93.0%);
269
+ --input-placeholder: hsl(0, 0%, 62.8%);
202
270
  --field-bg: hsl(0, 0%, 8.5%);
203
271
  --field-bg-disabled: hsl(0, 0%, 11.0%);
204
272
  --field-border: hsl(0, 0%, 24.3%);
@@ -228,8 +296,41 @@
228
296
  --input: hsl(0, 0%, 24.3%);
229
297
  --file-row-bg: hsla(0, 0%, 0%, 0);
230
298
  --file-row-bg-hover: hsl(0, 0%, 11.0%);
299
+ --file-row-bg-active: hsl(0, 0%, 11.0%);
300
+ --file-row-border: hsl(0, 0%, 17.9%);
231
301
  --notification-info-bg: hsl(0, 0%, 13.6%);
232
302
  --notification-danger-bg: hsl(0, 55%, 15%);
303
+ --notification-bg: hsl(0, 0%, 13.6%);
304
+ --notification-border: hsl(0, 0%, 20.5%);
305
+ --notification-fg: hsl(0, 0%, 93.0%);
306
+ --notification-icon: hsl(0, 0%, 62.8%);
307
+ --notification-success-bg: hsl(149, 21%, 9%);
308
+ --notification-success-border: hsl(146, 41%, 29%);
309
+ --notification-success-fg: hsl(142, 71%, 82%);
310
+ --notification-danger-border: hsl(0, 46%, 38%);
311
+ --notification-danger-fg: hsl(5, 100%, 91%);
312
+ --menu-bg: hsl(0, 0%, 13.6%);
313
+ --menu-border: hsl(0, 0%, 20.5%);
314
+ --menu-shadow: 0 16px 40px hsla(0, 0%, 0%, 0.6);
315
+ --menu-item-bg-hover: hsl(0, 0%, 15.8%);
316
+ --menu-item-text: hsl(0, 0%, 93.0%);
317
+ --menu-item-icon: hsl(0, 0%, 62.8%);
318
+ --menu-item-shortcut: hsl(0, 0%, 62.8%);
319
+ --menu-item-danger-text: hsl(2, 100%, 77%);
320
+ --menu-item-danger-bg-hover: hsl(0, 55%, 15%);
321
+ --menu-separator: hsl(0, 0%, 20.5%);
322
+ --menu-label: hsl(0, 0%, 62.8%);
323
+ --palette-bg: hsl(0, 0%, 13.6%);
324
+ --palette-border: hsl(0, 0%, 20.5%);
325
+ --palette-shadow: 0 16px 40px hsla(0, 0%, 0%, 0.6);
326
+ --palette-scrim: hsla(0, 0%, 0%, 0.565);
327
+ --palette-item-bg-active: hsl(0, 0%, 15.8%);
328
+ --palette-group-label: hsl(0, 0%, 62.8%);
329
+ --palette-item-meta: hsl(0, 0%, 62.8%);
330
+ --sheet-bg: hsl(0, 0%, 13.6%);
331
+ --sheet-border: hsl(0, 0%, 20.5%);
332
+ --sheet-shadow: 0 16px 40px hsla(0, 0%, 0%, 0.6);
333
+ --sheet-scrim: hsla(0, 0%, 0%, 0.565);
233
334
  --bg: hsl(0, 0%, 8.5%);
234
335
  --bg-secondary: hsl(0, 0%, 11.0%);
235
336
  --component-bg: hsl(0, 0%, 13.6%);
@@ -310,7 +411,7 @@ html {
310
411
  background: var(--html-bg);
311
412
  color: var(--text);
312
413
  font-family: var(--font-sans);
313
- font-size: 15px; /* 14–15 responsive base, per app convention */
414
+ font-size: 14px; /* app.put.io root: fontSize ["14px","14px","15px"] — 15px at ≥ --bp-lg (media query below) */
314
415
  line-height: var(--lh-normal);
315
416
  -webkit-font-smoothing: antialiased;
316
417
  -moz-osx-font-smoothing: grayscale;
@@ -322,6 +423,13 @@ body {
322
423
  margin: 0;
323
424
  }
324
425
 
426
+ /* Root steps up on desktop, matching app.put.io's responsive base.
427
+ 14px/15px literals must stay in sync with --bp-lg (media queries
428
+ can't read custom properties). */
429
+ @media (min-width: 1280px) {
430
+ html { font-size: 15px; }
431
+ }
432
+
325
433
  /* -- Semantic type ------------------------------------------------- */
326
434
 
327
435
  .h-display, h1.display {
@@ -336,14 +444,14 @@ body {
336
444
 
337
445
  /* Numeric / tabular UI text — transfer speeds, storage sizes, timestamps */
338
446
  .num, .tabular {
339
- font-family: var(--font-ui-mono);
447
+ font-family: var(--font-mono);
340
448
  font-variant-numeric: tabular-nums;
341
449
  font-feature-settings: "tnum";
342
450
  }
343
451
 
344
452
  h1, .h1 {
345
453
  font-family: var(--font-sans);
346
- font-size: var(--fs-3xl);
454
+ font-size: var(--fs-xl);
347
455
  font-weight: var(--fw-bold);
348
456
  line-height: var(--lh-tight);
349
457
  letter-spacing: var(--tracking-tight);
@@ -352,7 +460,7 @@ h1, .h1 {
352
460
 
353
461
  h2, .h2 {
354
462
  font-family: var(--font-sans);
355
- font-size: var(--fs-2xl);
463
+ font-size: var(--fs-lg);
356
464
  font-weight: var(--fw-bold);
357
465
  line-height: var(--lh-tight);
358
466
  margin: 0 0 var(--space-3);
@@ -360,7 +468,7 @@ h2, .h2 {
360
468
 
361
469
  h3, .h3 {
362
470
  font-family: var(--font-sans);
363
- font-size: var(--fs-xl);
471
+ font-size: var(--fs-md);
364
472
  font-weight: var(--fw-medium);
365
473
  line-height: var(--lh-snug);
366
474
  margin: 0 0 var(--space-2);
@@ -368,7 +476,7 @@ h3, .h3 {
368
476
 
369
477
  h4, .h4 {
370
478
  font-family: var(--font-sans);
371
- font-size: var(--fs-lg);
479
+ font-size: var(--fs-base);
372
480
  font-weight: var(--fw-medium);
373
481
  line-height: var(--lh-snug);
374
482
  margin: 0 0 var(--space-2);
@@ -389,26 +497,26 @@ p, .body {
389
497
  }
390
498
 
391
499
  .lead {
392
- font-size: var(--fs-lg);
500
+ font-size: var(--fs-md);
393
501
  font-weight: var(--fw-regular);
394
502
  line-height: var(--lh-normal);
395
503
  color: var(--text-secondary);
396
504
  }
397
505
 
398
506
  small, .caption {
399
- font-size: var(--fs-xs);
507
+ font-size: var(--fs-sm); /* production caption = fontSize 0 */
400
508
  color: var(--text-secondary);
401
509
  }
402
510
 
403
511
  .label {
404
- font-size: var(--fs-sm);
512
+ font-size: var(--fs-base); /* production label = fontSize 1, medium */
405
513
  font-weight: var(--fw-medium);
406
514
  color: var(--text);
407
515
  }
408
516
 
409
517
  .button-text {
410
518
  font-weight: var(--fw-medium);
411
- font-size: var(--fs-base);
519
+ font-size: var(--fs-sm); /* production button = fontSize 0 */
412
520
  letter-spacing: 0;
413
521
  }
414
522
 
@@ -427,16 +535,6 @@ a {
427
535
  }
428
536
  a:hover { text-decoration-color: currentColor; }
429
537
 
430
- /* -- Component-role aliases --------------------------------------- */
431
- /* Button default + info variants — live aliases; the DTCG layer doesn't define these two. */
432
- :root {
433
- --button-default-bg: var(--component-bg);
434
- --button-default-bg-hover: var(--component-bg-hover);
435
- --button-default-fg: var(--text);
436
- --button-info-bg: var(--solid);
437
- --button-info-fg: var(--solid-foreground);
438
- }
439
-
440
538
  /* -- Utility classes ---------------------------------------------- */
441
539
  .fg-1 { color: var(--text); }
442
540
  .fg-2 { color: var(--text-secondary); }
@@ -448,3 +546,16 @@ a:hover { text-decoration-color: currentColor; }
448
546
  .bg-2 { background: var(--bg-secondary); }
449
547
  .bg-component { background: var(--component-bg); }
450
548
  .bg-yellow { background: var(--yellow-solid); color: var(--primary-foreground); }
549
+
550
+ /* -- Reduced motion ------------------------------------------------ */
551
+ /* Honor the OS "reduce motion" setting: collapse transitions/animations
552
+ to near-instant and stop looping/auto-scrolling effects. Components
553
+ should not rely on motion to convey state. */
554
+ @media (prefers-reduced-motion: reduce) {
555
+ *, *::before, *::after {
556
+ animation-duration: 0.01ms !important;
557
+ animation-iteration-count: 1 !important;
558
+ transition-duration: 0.01ms !important;
559
+ scroll-behavior: auto !important;
560
+ }
561
+ }