@hanzo/ui 8.27.44 → 8.27.46
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/dist/backends/gui/animated-testimonials.cjs +2 -2
- package/dist/backends/gui/animated-testimonials.js +2 -2
- package/dist/backends/gui/animated-testimonials.js.map +1 -1
- package/dist/backends/gui/animated-tooltip.cjs +2 -2
- package/dist/backends/gui/animated-tooltip.js +2 -2
- package/dist/backends/gui/animated-tooltip.js.map +1 -1
- package/dist/backends/gui/carousel.cjs +2 -2
- package/dist/backends/gui/carousel.d.ts.map +1 -1
- package/dist/backends/gui/carousel.js +2 -2
- package/dist/backends/gui/carousel.js.map +1 -1
- package/dist/backends/gui/index.cjs +4 -5
- package/dist/backends/gui/index.d.ts +1 -1
- package/dist/backends/gui/index.d.ts.map +1 -1
- package/dist/backends/gui/index.js +1 -1
- package/dist/backends/gui/index.js.map +1 -1
- package/dist/backends/gui/input-otp.cjs +2 -1
- package/dist/backends/gui/input-otp.d.ts.map +1 -1
- package/dist/backends/gui/input-otp.js +2 -1
- package/dist/backends/gui/input-otp.js.map +1 -1
- package/dist/backends/gui/navigation-menu.cjs +24 -6
- package/dist/backends/gui/navigation-menu.d.ts +0 -6
- package/dist/backends/gui/navigation-menu.d.ts.map +1 -1
- package/dist/backends/gui/navigation-menu.js +23 -5
- package/dist/backends/gui/navigation-menu.js.map +1 -1
- package/dist/backends/gui/popover.cjs +7 -2
- package/dist/backends/gui/popover.d.ts +8 -1
- package/dist/backends/gui/popover.d.ts.map +1 -1
- package/dist/backends/gui/popover.js +7 -2
- package/dist/backends/gui/popover.js.map +1 -1
- package/dist/backends/gui/prose.cjs +4 -18
- package/dist/backends/gui/prose.d.ts +8 -5
- package/dist/backends/gui/prose.d.ts.map +1 -1
- package/dist/backends/gui/prose.js +4 -18
- package/dist/backends/gui/prose.js.map +1 -1
- package/dist/backends/gui/skeleton.cjs +1 -1
- package/dist/backends/gui/skeleton.d.ts.map +1 -1
- package/dist/backends/gui/skeleton.js +1 -1
- package/dist/backends/gui/skeleton.js.map +1 -1
- package/dist/backends/gui/timeline.cjs +2 -2
- package/dist/backends/gui/timeline.d.ts +1 -1
- package/dist/backends/gui/timeline.js +2 -2
- package/dist/backends/gui/timeline.js.map +1 -1
- package/dist/backends/gui/video.cjs +1 -1
- package/dist/backends/gui/video.js +1 -1
- package/dist/backends/gui/video.js.map +1 -1
- package/dist/chat/Chat.cjs +7 -2
- package/dist/chat/Chat.d.ts +14 -1
- package/dist/chat/Chat.d.ts.map +1 -1
- package/dist/chat/Chat.js +7 -2
- package/dist/chat/Chat.js.map +1 -1
- package/dist/chat/Composer.cjs +6 -1
- package/dist/chat/Composer.d.ts.map +1 -1
- package/dist/chat/Composer.js +6 -1
- package/dist/chat/Composer.js.map +1 -1
- package/dist/chat/SessionRail.cjs +1 -4
- package/dist/chat/SessionRail.js +1 -4
- package/dist/chat/SessionRail.js.map +1 -1
- package/dist/core/cn.cjs +1 -1
- package/dist/core/cn.d.ts +1 -1
- package/dist/core/cn.js +1 -1
- package/dist/gallery.html +495 -598
- package/dist/glass.cjs +2 -24
- package/dist/glass.css +14 -196
- package/dist/glass.d.ts +2 -26
- package/dist/glass.d.ts.map +1 -1
- package/dist/glass.js +1 -22
- package/dist/glass.js.map +1 -1
- package/dist/grid.cjs +60 -10
- package/dist/grid.d.ts +20 -24
- package/dist/grid.d.ts.map +1 -1
- package/dist/grid.js +60 -10
- package/dist/grid.js.map +1 -1
- package/dist/index.cjs +6 -2
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -1
- package/dist/index.js.map +1 -1
- package/dist/index.node.cjs +6 -2
- package/dist/index.node.js +4 -1
- package/dist/masthead/index.cjs +3 -12
- package/dist/masthead/index.d.ts +3 -6
- package/dist/masthead/index.d.ts.map +1 -1
- package/dist/masthead/index.js +3 -6
- package/dist/masthead/index.js.map +1 -1
- package/dist/motion.cjs +20 -0
- package/dist/motion.d.ts +17 -0
- package/dist/motion.d.ts.map +1 -0
- package/dist/motion.js +16 -0
- package/dist/motion.js.map +1 -0
- package/dist/product/DataTable.cjs +24 -4
- package/dist/product/DataTable.d.ts +0 -16
- package/dist/product/DataTable.d.ts.map +1 -1
- package/dist/product/DataTable.js +24 -4
- package/dist/product/DataTable.js.map +1 -1
- package/dist/product/FadeIn.cjs +1 -1
- package/dist/product/FadeIn.js +1 -1
- package/dist/product/FadeIn.js.map +1 -1
- package/dist/product/Metric.cjs +19 -2
- package/dist/product/Metric.d.ts +0 -16
- package/dist/product/Metric.d.ts.map +1 -1
- package/dist/product/Metric.js +19 -2
- package/dist/product/Metric.js.map +1 -1
- package/dist/product/Reorder.cjs +1 -1
- package/dist/product/Reorder.js +1 -1
- package/dist/product/Reorder.js.map +1 -1
- package/dist/product/Skeleton.cjs +5 -5
- package/dist/product/Skeleton.d.ts +4 -4
- package/dist/product/Skeleton.d.ts.map +1 -1
- package/dist/product/Skeleton.js +5 -5
- package/dist/product/Skeleton.js.map +1 -1
- package/dist/product/SlideOver.cjs +2 -10
- package/dist/product/SlideOver.d.ts.map +1 -1
- package/dist/product/SlideOver.js +2 -10
- package/dist/product/SlideOver.js.map +1 -1
- package/dist/product/figures.cjs +16 -0
- package/dist/product/figures.d.ts +16 -0
- package/dist/product/figures.d.ts.map +1 -0
- package/dist/product/figures.js +14 -0
- package/dist/product/figures.js.map +1 -0
- package/dist/product/social/SocialResource.cjs +2 -1
- package/dist/product/social/SocialResource.d.ts.map +1 -1
- package/dist/product/social/SocialResource.js +2 -1
- package/dist/product/social/SocialResource.js.map +1 -1
- package/dist/product/social/SocialSummaryBar.cjs +2 -1
- package/dist/product/social/SocialSummaryBar.d.ts.map +1 -1
- package/dist/product/social/SocialSummaryBar.js +2 -1
- package/dist/product/social/SocialSummaryBar.js.map +1 -1
- package/dist/style.cjs +1 -4
- package/dist/style.d.ts +0 -2
- package/dist/style.d.ts.map +1 -1
- package/dist/style.js +0 -2
- package/dist/style.js.map +1 -1
- package/dist/styles/motion.css +61 -283
- package/dist/styles.css +492 -595
- package/dist/sx.cjs +1 -1
- package/dist/sx.js +1 -1
- package/dist/theme.css +383 -292
- package/package.json +3 -4
- package/dist/masthead/Masthead.cjs +0 -168
- package/dist/masthead/Masthead.d.ts +0 -54
- package/dist/masthead/Masthead.d.ts.map +0 -1
- package/dist/masthead/Masthead.js +0 -162
- package/dist/masthead/Masthead.js.map +0 -1
- package/dist/masthead.css +0 -502
- package/dist/primitives/navigationMenuTriggerStyle.cjs +0 -8
- package/dist/primitives/navigationMenuTriggerStyle.d.ts +0 -2
- package/dist/primitives/navigationMenuTriggerStyle.d.ts.map +0 -1
- package/dist/primitives/navigationMenuTriggerStyle.js +0 -5
- package/dist/primitives/navigationMenuTriggerStyle.js.map +0 -1
package/dist/styles.css
CHANGED
|
@@ -1332,13 +1332,8 @@
|
|
|
1332
1332
|
src/glass.css and are inlined here by scripts/compose-theme.mjs — one home,
|
|
1333
1333
|
two entry points (`@hanzo/ui/theme.css` and `@hanzo/ui/glass.css`), so a host
|
|
1334
1334
|
that wants only the chrome material does not have to take the token layer
|
|
1335
|
-
with it.
|
|
1336
|
-
|
|
1337
|
-
They used to be four `.elevation-*` rules reading `var(--hz-elevation-N, …)`.
|
|
1338
|
-
Nothing in this repo, in @hanzo/design or in any consumer ever DEFINED an
|
|
1339
|
-
`--hz-elevation-*` variable, so every one of those resolved to its fallback:
|
|
1340
|
-
an indirection through a name that does not exist, with a hardcoded shadow
|
|
1341
|
-
behind it, next to a design system that publishes real ones. */
|
|
1335
|
+
with it. The ladder reads @hanzo/design's own shadows, never a private
|
|
1336
|
+
variable nothing defines. */
|
|
1342
1337
|
|
|
1343
1338
|
/* ── Prose ───────────────────────────────────────────────────────────────────
|
|
1344
1339
|
What `<ApplyTypography>` turns on: running text — a heading, a byline, a
|
|
@@ -1352,12 +1347,13 @@
|
|
|
1352
1347
|
@hanzo/design ramp, which is where every other surface already reads them —
|
|
1353
1348
|
so prose and a Button now round to the same scale instead of two.
|
|
1354
1349
|
|
|
1355
|
-
Scoped under
|
|
1356
|
-
component keeps its own type.
|
|
1357
|
-
.
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
display:
|
|
1350
|
+
Scoped under `[data-slot='prose']` and applied with `>` only one level down,
|
|
1351
|
+
so a nested component keeps its own type. The content arrives as bare tags
|
|
1352
|
+
(a CMS field, an .mdx file), which is the one case a prop cannot reach: the
|
|
1353
|
+
rules have to select by tag from the container. */
|
|
1354
|
+
[data-slot='prose'] {
|
|
1355
|
+
display: flex;
|
|
1356
|
+
flex-direction: column;
|
|
1361
1357
|
gap: var(--space-3, 0.75rem);
|
|
1362
1358
|
color: var(--foreground);
|
|
1363
1359
|
font-family: var(--font-sans), sans-serif;
|
|
@@ -1365,8 +1361,8 @@
|
|
|
1365
1361
|
line-height: var(--leading-base, var(--leading-normal));
|
|
1366
1362
|
}
|
|
1367
1363
|
|
|
1368
|
-
|
|
1369
|
-
|
|
1364
|
+
[data-slot='prose'] > h1, [data-slot='prose'] > h2, [data-slot='prose'] > h3,
|
|
1365
|
+
[data-slot='prose'] > h4, [data-slot='prose'] > h5, [data-slot='prose'] > h6 {
|
|
1370
1366
|
font-family: var(--font-display, var(--font-sans)), sans-serif;
|
|
1371
1367
|
font-weight: 606;
|
|
1372
1368
|
line-height: var(--leading-tight);
|
|
@@ -1374,37 +1370,37 @@
|
|
|
1374
1370
|
margin: 0;
|
|
1375
1371
|
}
|
|
1376
1372
|
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1373
|
+
[data-slot='prose'] > h1 { font-size: var(--text-4xl) }
|
|
1374
|
+
[data-slot='prose'] > h2 { font-size: var(--text-3xl) }
|
|
1375
|
+
[data-slot='prose'] > h3 { font-size: var(--text-2xl) }
|
|
1376
|
+
[data-slot='prose'] > h4 { font-size: var(--text-xl) }
|
|
1377
|
+
[data-slot='prose'] > h5 { font-size: var(--text-lg) }
|
|
1382
1378
|
/* h6 is the byline rung: heading TAG, body weight and colour, because that is
|
|
1383
1379
|
what a byline is — subordinate text that happens to sit in the heading
|
|
1384
1380
|
stack. */
|
|
1385
|
-
|
|
1381
|
+
[data-slot='prose'] > h6 {
|
|
1386
1382
|
font-size: var(--text-base);
|
|
1387
1383
|
font-weight: 497;
|
|
1388
1384
|
color: var(--muted-foreground);
|
|
1389
1385
|
}
|
|
1390
1386
|
|
|
1391
|
-
|
|
1387
|
+
[data-slot='prose'] > p { margin: 0 }
|
|
1392
1388
|
/* The marker is RESTORED here. `base.css` takes it off every list in the
|
|
1393
1389
|
document, because a nav and a card grid are both lists and neither wants one.
|
|
1394
1390
|
Authored prose is the one place it belongs. Setting only the indent leaves an
|
|
1395
1391
|
indented list with nothing at the start of the line. */
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1392
|
+
[data-slot='prose'] > ul, [data-slot='prose'] ul ul { list-style: disc }
|
|
1393
|
+
[data-slot='prose'] > ol, [data-slot='prose'] ol ol { list-style: decimal }
|
|
1394
|
+
[data-slot='prose'] ul, [data-slot='prose'] ol { margin: 0; padding-inline-start: 1.5em }
|
|
1395
|
+
[data-slot='prose'] li { margin-block: 0.25em }
|
|
1396
|
+
[data-slot='prose'] li::marker { color: var(--muted-foreground) }
|
|
1401
1397
|
|
|
1402
1398
|
/* A code block is a SURFACE, not just a change of typeface. Without the panel
|
|
1403
1399
|
it sits directly on the page ground and reads as body text that happens to be
|
|
1404
1400
|
monospaced — which is exactly what a reader scanning for the command must not
|
|
1405
1401
|
have to work out. `pre` already scrolls inside itself (base.css); this gives
|
|
1406
1402
|
it the ground to scroll on. */
|
|
1407
|
-
|
|
1403
|
+
[data-slot='prose'] > pre {
|
|
1408
1404
|
margin: 0;
|
|
1409
1405
|
padding: var(--space-4, 1rem);
|
|
1410
1406
|
border: 1px solid var(--border);
|
|
@@ -1415,97 +1411,61 @@
|
|
|
1415
1411
|
}
|
|
1416
1412
|
/* Inside a block the panel IS the surface, so the inline treatment would draw a
|
|
1417
1413
|
second one around every line. */
|
|
1418
|
-
|
|
1419
|
-
|
|
1414
|
+
[data-slot='prose'] > pre code { background: none; padding: 0; border: 0; font-size: inherit }
|
|
1415
|
+
[data-slot='prose'] :not(pre) > code {
|
|
1420
1416
|
padding: 0.15em 0.35em;
|
|
1421
1417
|
border-radius: calc(var(--radius, 0.5rem) / 2);
|
|
1422
1418
|
background: var(--muted);
|
|
1423
1419
|
}
|
|
1424
|
-
|
|
1420
|
+
[data-slot='prose'] > blockquote {
|
|
1425
1421
|
margin: 0;
|
|
1426
1422
|
padding-inline-start: 1em;
|
|
1427
1423
|
border-inline-start: 2px solid var(--border);
|
|
1428
1424
|
color: var(--muted-foreground);
|
|
1429
1425
|
}
|
|
1430
|
-
|
|
1426
|
+
[data-slot='prose'] code {
|
|
1431
1427
|
font-family: var(--font-mono), ui-monospace, monospace;
|
|
1432
1428
|
font-size: 0.9em;
|
|
1433
1429
|
}
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1430
|
+
[data-slot='prose'] a { color: inherit; text-decoration: underline }
|
|
1431
|
+
[data-slot='prose'] strong { font-weight: 606 }
|
|
1432
|
+
[data-slot='prose'] :where(img, video) { max-width: 100%; height: auto }
|
|
1437
1433
|
|
|
1438
1434
|
/* The named rungs. `responsive` is the default and is the only one that moves
|
|
1439
1435
|
with the viewport — a t-shirt size is a DECISION, so it stays put. */
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1436
|
+
[data-slot='prose'][data-size='sm'] { font-size: var(--text-sm); gap: var(--space-3, 0.75rem) }
|
|
1437
|
+
[data-slot='prose'][data-size='sm'] > h1 { font-size: var(--text-3xl) }
|
|
1438
|
+
[data-slot='prose'][data-size='sm'] > h2 { font-size: var(--text-2xl) }
|
|
1439
|
+
[data-slot='prose'][data-size='sm'] > h3 { font-size: var(--text-xl) }
|
|
1440
|
+
[data-slot='prose'][data-size='sm'] > p { font-size: var(--text-sm) }
|
|
1441
|
+
|
|
1442
|
+
[data-slot='prose'][data-size='lg'] { font-size: var(--text-lg); gap: var(--space-5, 1.25rem) }
|
|
1443
|
+
[data-slot='prose'][data-size='lg'] > h1 { font-size: var(--text-5xl) }
|
|
1444
|
+
[data-slot='prose'][data-size='lg'] > h2 { font-size: var(--text-4xl) }
|
|
1445
|
+
[data-slot='prose'][data-size='lg'] > h3 { font-size: var(--text-3xl) }
|
|
1446
|
+
[data-slot='prose'][data-size='lg'] > p { font-size: var(--text-lg) }
|
|
1447
|
+
|
|
1448
|
+
[data-slot='prose'][data-size='xl'] { font-size: var(--text-lg); gap: var(--space-6, 1.5rem) }
|
|
1449
|
+
[data-slot='prose'][data-size='xl'] > h1 { font-size: var(--text-6xl) }
|
|
1450
|
+
[data-slot='prose'][data-size='xl'] > h2 { font-size: var(--text-5xl) }
|
|
1451
|
+
[data-slot='prose'][data-size='xl'] > h3 { font-size: var(--text-4xl) }
|
|
1452
|
+
[data-slot='prose'][data-size='xl'] > p { font-size: var(--text-lg) }
|
|
1457
1453
|
|
|
1458
1454
|
/* Responsive: start at the small rung and climb. Written as min-width so the
|
|
1459
1455
|
phone case is the unprefixed one and needs no query at all. */
|
|
1460
1456
|
@media (min-width: 640px) {
|
|
1461
|
-
|
|
1457
|
+
[data-slot='prose'][data-size='responsive'] { gap: var(--space-4, 1rem) }
|
|
1462
1458
|
}
|
|
1463
1459
|
@media (min-width: 1024px) {
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1460
|
+
[data-slot='prose'][data-size='responsive'] { font-size: var(--text-lg); gap: var(--space-5, 1.25rem) }
|
|
1461
|
+
[data-slot='prose'][data-size='responsive'] > h1 { font-size: var(--text-5xl) }
|
|
1462
|
+
[data-slot='prose'][data-size='responsive'] > h2 { font-size: var(--text-4xl) }
|
|
1463
|
+
[data-slot='prose'][data-size='responsive'] > h3 { font-size: var(--text-3xl) }
|
|
1468
1464
|
}
|
|
1469
1465
|
@media (min-width: 1280px) {
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
}
|
|
1474
|
-
|
|
1475
|
-
/* The two things a style PROP cannot say, because neither is a property of an
|
|
1476
|
-
element: a keyframe, and a scrollbar. */
|
|
1477
|
-
|
|
1478
|
-
/* Skeleton's pulse. Opacity only — animating a colour or a size would repaint
|
|
1479
|
-
or reflow every frame for a placeholder nobody is looking at. */
|
|
1480
|
-
@keyframes hz-pulse {
|
|
1481
|
-
50% { opacity: 0.5 }
|
|
1482
|
-
}
|
|
1483
|
-
.hz-pulse { animation: hz-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite }
|
|
1484
|
-
|
|
1485
|
-
/* A carousel scrolls but must not show a bar: the arrows and the snap already
|
|
1486
|
-
say it scrolls, and a bar that appears mid-drag shifts the slides under the
|
|
1487
|
-
pointer. Firefox reads the property, WebKit the pseudo-element, and the
|
|
1488
|
-
property rides on the component so only this half needs a sheet. */
|
|
1489
|
-
.hz-scroller::-webkit-scrollbar { display: none }
|
|
1490
|
-
|
|
1491
|
-
/* The drawn caret in a one-time-code box. The real one is hidden, because it
|
|
1492
|
-
would sit at the left edge of an invisible full-width field rather than in
|
|
1493
|
-
the box the next keystroke lands in. */
|
|
1494
|
-
@keyframes hz-caret {
|
|
1495
|
-
0%, 49% { opacity: 1 }
|
|
1496
|
-
50%, 100% { opacity: 0 }
|
|
1497
|
-
}
|
|
1498
|
-
.hz-caret {
|
|
1499
|
-
background: var(--foreground);
|
|
1500
|
-
animation: hz-caret 1s steps(1) infinite;
|
|
1501
|
-
}
|
|
1502
|
-
|
|
1503
|
-
/* Motion is a preference, and all of the above is decoration. A caret that does
|
|
1504
|
-
not blink is still a caret; one that does can trigger a migraine. */
|
|
1505
|
-
@media (prefers-reduced-motion: reduce) {
|
|
1506
|
-
.hz-pulse { animation: none }
|
|
1507
|
-
.hz-caret { animation: none }
|
|
1508
|
-
.hz-scroller { scroll-behavior: auto }
|
|
1466
|
+
[data-slot='prose'][data-size='responsive'] { gap: var(--space-6, 1.5rem) }
|
|
1467
|
+
[data-slot='prose'][data-size='responsive'] > h1 { font-size: var(--text-6xl) }
|
|
1468
|
+
[data-slot='prose'][data-size='responsive'] > h2 { font-size: var(--text-5xl) }
|
|
1509
1469
|
}
|
|
1510
1470
|
|
|
1511
1471
|
/* Glass — the material floating chrome is made of, and the ladder it stands on.
|
|
@@ -1625,6 +1585,20 @@
|
|
|
1625
1585
|
}
|
|
1626
1586
|
}
|
|
1627
1587
|
|
|
1588
|
+
/* ── Solid — the one way out of the material ─────────────────────────────────
|
|
1589
|
+
A panel over something that moves (a menu over a streaming transcript) reads
|
|
1590
|
+
the motion through 72% frost. `<PopoverContent solid>` marks itself, and every
|
|
1591
|
+
popover opened from inside it, with `data-material="solid"`: the ground is
|
|
1592
|
+
design's opaque `--popover` and nothing behind is blurred into it. The rung's
|
|
1593
|
+
shadow, lit edge and prism lip stay, so it is the same surface at the same
|
|
1594
|
+
height with a solid fill. Declared after the material so the later rule wins
|
|
1595
|
+
between two !important declarations of equal weight. */
|
|
1596
|
+
[data-material="solid"] {
|
|
1597
|
+
background-color: var(--popover, #0f0f0f) !important;
|
|
1598
|
+
-webkit-backdrop-filter: none;
|
|
1599
|
+
backdrop-filter: none;
|
|
1600
|
+
}
|
|
1601
|
+
|
|
1628
1602
|
/* ── Depth — three rungs, and the lit edge is the load-bearing half ──────────
|
|
1629
1603
|
A cast shadow is how a light page shows lift. On a near-black canvas it is
|
|
1630
1604
|
nearly free of information: black on near-black moves no pixels, so a raised
|
|
@@ -1754,73 +1728,6 @@
|
|
|
1754
1728
|
border-bottom-right-radius: 0 !important;
|
|
1755
1729
|
}
|
|
1756
1730
|
|
|
1757
|
-
/* ── The crease — the valley where one sheet lies over another ───────────────
|
|
1758
|
-
The ladder lifts a sheet with a drop that falls STRAIGHT DOWN: design's rule
|
|
1759
|
-
is one light, above, and `check-tokens.mjs` fails the build on a sideways
|
|
1760
|
-
offset. That is right, and it means the ladder has nothing to say about a
|
|
1761
|
-
VERTICAL seam — and an app shell is nothing but vertical seams. A rail beside
|
|
1762
|
-
a sidebar beside a pane, each a step apart on the ladder, still reads as three
|
|
1763
|
-
abutting rectangles with lines ruled between them, because the only mark at
|
|
1764
|
-
the seam is the hairline.
|
|
1765
|
-
|
|
1766
|
-
What a real sheet lays on the one beneath it, side by side under a light from
|
|
1767
|
-
above, is not a cast shadow — it is the valley going dark. Ambient occlusion
|
|
1768
|
-
has no direction of its own, which is both why it is honest here and why it is
|
|
1769
|
-
NOT spelled as a --shadow-*: those are directional by definition and this is
|
|
1770
|
-
not one.
|
|
1771
|
-
|
|
1772
|
-
A PSEUDO-ELEMENT, at z-index -1 inside an isolated stacking context, so it
|
|
1773
|
-
paints above the sheet's own fill and below every child. That ordering is the
|
|
1774
|
-
whole reason it is not a `background-image` (which `.fold` already claims on
|
|
1775
|
-
this same element, !important, so the two would silently fight) and not an
|
|
1776
|
-
inset `box-shadow` (which `.elevation-*` claims, likewise).
|
|
1777
|
-
|
|
1778
|
-
No side named -> both edges, which is what a pane with a neighbour on each
|
|
1779
|
-
hand needs. Name one and the other stops being drawn. */
|
|
1780
|
-
:root {
|
|
1781
|
-
--crease-ink: rgb(0 0 0 / .28);
|
|
1782
|
-
--crease-depth: 20px;
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
.light, :root.t_light, .t_light {
|
|
1786
|
-
/* On white the valley is a smudge, not a shadow — the same redistribution the
|
|
1787
|
-
drops make, and for the same reason. */
|
|
1788
|
-
--crease-ink: rgb(0 0 0 / .05);
|
|
1789
|
-
}
|
|
1790
|
-
|
|
1791
|
-
.hz-crease {
|
|
1792
|
-
position: relative;
|
|
1793
|
-
/* Without this the -1 escapes and paints behind an ancestor's fill, which is
|
|
1794
|
-
indistinguishable from the crease not being there at all. */
|
|
1795
|
-
isolation: isolate;
|
|
1796
|
-
}
|
|
1797
|
-
|
|
1798
|
-
.hz-crease::before,
|
|
1799
|
-
.hz-crease::after {
|
|
1800
|
-
content: "";
|
|
1801
|
-
position: absolute;
|
|
1802
|
-
top: 0;
|
|
1803
|
-
bottom: 0;
|
|
1804
|
-
width: var(--crease-depth);
|
|
1805
|
-
z-index: -1;
|
|
1806
|
-
pointer-events: none;
|
|
1807
|
-
}
|
|
1808
|
-
|
|
1809
|
-
.hz-crease::before {
|
|
1810
|
-
left: 0;
|
|
1811
|
-
background-image: linear-gradient(to right, var(--crease-ink), transparent);
|
|
1812
|
-
}
|
|
1813
|
-
|
|
1814
|
-
.hz-crease::after {
|
|
1815
|
-
right: 0;
|
|
1816
|
-
background-image: linear-gradient(to left, var(--crease-ink), transparent);
|
|
1817
|
-
}
|
|
1818
|
-
|
|
1819
|
-
.hz-crease[data-crease="left"]::after,
|
|
1820
|
-
.hz-crease[data-crease="right"]::before {
|
|
1821
|
-
content: none;
|
|
1822
|
-
}
|
|
1823
|
-
|
|
1824
1731
|
/* ── The scrim ──────────────────────────────────────────────────────────────
|
|
1825
1732
|
The dim that makes a floating panel read as floating rather than as more
|
|
1826
1733
|
page. gui's overlay dims TWICE — a translucent ground under a further
|
|
@@ -1868,135 +1775,6 @@
|
|
|
1868
1775
|
border-top: 1px solid var(--borderColor, var(--border));
|
|
1869
1776
|
}
|
|
1870
1777
|
|
|
1871
|
-
/* ── The composer prism — the ONE ring on any Hanzo surface ──────────────────
|
|
1872
|
-
The composer is where you talk to Hanzo, so it is the thing that should look
|
|
1873
|
-
alive, and it earns that with MOTION and LIGHT rather than hue. Every other
|
|
1874
|
-
pixel of chrome stays monochrome; there is no second exemption, and the two
|
|
1875
|
-
attempts to grant one (a violet ring, then a full-wheel rainbow) each made
|
|
1876
|
-
the surface wearing it the only colour in the product.
|
|
1877
|
-
|
|
1878
|
-
THIS LIVES HERE BECAUSE IT WAS DECLARED TWICE AND DRIFTED. hanzo.chat's
|
|
1879
|
-
client/src/style.css and hanzo.app's assets/globals.css each carried a copy,
|
|
1880
|
-
each calling itself "the ONE prism on any Hanzo surface". chat fixed the ring
|
|
1881
|
-
to be a rim; hanzo.app's copy kept drawing a filled DISC and never got the
|
|
1882
|
-
fix — invisible until a glass panel sat in it, at which point the whole
|
|
1883
|
-
spectrum washed up through the composer's interior. chat also quieted the
|
|
1884
|
-
halo (0.5 with a pulse -> 0.22, no pulse); hanzo.app kept the loud one. Two
|
|
1885
|
-
copies of one look is how that happens, and neither app could see the other
|
|
1886
|
-
was wrong.
|
|
1887
|
-
|
|
1888
|
-
Structure: `.hz-composer` is a 1.5px-padded host; its direct child is the
|
|
1889
|
-
panel. ::before is the ring, ::after the halo. Both are MASKED to exclude the
|
|
1890
|
-
panel's footprint, so the ring is a rim BY CONSTRUCTION and the panel is free
|
|
1891
|
-
to be any material — opaque, glass, anything. The stops are declared once and
|
|
1892
|
-
read by both, because duplicated they drift on the first palette change and
|
|
1893
|
-
nobody notices which half moved. */
|
|
1894
|
-
|
|
1895
|
-
/* `@property` is what lets a conic angle animate. Where it is unsupported the
|
|
1896
|
-
ring is simply static, which is a fine floor. */
|
|
1897
|
-
@property --hz-angle {
|
|
1898
|
-
syntax: "<angle>";
|
|
1899
|
-
initial-value: 0deg;
|
|
1900
|
-
inherits: false;
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
:root {
|
|
1904
|
-
/* One sweep, closing on the stop it opened with — a conic gradient whose
|
|
1905
|
-
first and last stop differ shows a hard seam.
|
|
1906
|
-
|
|
1907
|
-
LUMINANCE, NOT HUE. Four saturated stops at 0.40-0.48 alpha, swept around
|
|
1908
|
-
a rounded RECTANGLE, do not distribute evenly: the long top and bottom
|
|
1909
|
-
edges each take a wide angular slice and the short sides almost none, so
|
|
1910
|
-
one edge wore a bright blue while the opposite wore a burnt orange — a
|
|
1911
|
-
ring that highlights half the box and reads as sitting off-centre. White
|
|
1912
|
-
at two close alphas removes the bright arc entirely, drops the peak from
|
|
1913
|
-
0.48 to 0.18, and keeps the slow drift as a sheen. hanzo.chat and
|
|
1914
|
-
hanzo.app both declare exactly these stops; this is the package catching
|
|
1915
|
-
up to its consumers — the copies must not drift again, and this file is
|
|
1916
|
-
the home. */
|
|
1917
|
-
--hz-spectrum: rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.18),
|
|
1918
|
-
rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.18),
|
|
1919
|
-
rgba(255, 255, 255, 0.1);
|
|
1920
|
-
}
|
|
1921
|
-
|
|
1922
|
-
@keyframes hzComposerSpin {
|
|
1923
|
-
to {
|
|
1924
|
-
--hz-angle: 360deg;
|
|
1925
|
-
}
|
|
1926
|
-
}
|
|
1927
|
-
|
|
1928
|
-
.hz-composer {
|
|
1929
|
-
position: relative;
|
|
1930
|
-
isolation: isolate;
|
|
1931
|
-
padding: 1.5px;
|
|
1932
|
-
}
|
|
1933
|
-
|
|
1934
|
-
/* The ring DRAWS A RING. `padding` is its thickness; the two-layer mask keeps
|
|
1935
|
-
paint outside it — `content-box` is the hole, the full box the plate, and
|
|
1936
|
-
`exclude` leaves the lip. */
|
|
1937
|
-
.hz-composer::before {
|
|
1938
|
-
content: "";
|
|
1939
|
-
position: absolute;
|
|
1940
|
-
inset: 0;
|
|
1941
|
-
padding: 1.5px;
|
|
1942
|
-
border-radius: inherit;
|
|
1943
|
-
background: conic-gradient(from var(--hz-angle), var(--hz-spectrum));
|
|
1944
|
-
animation: hzComposerSpin 10s linear infinite;
|
|
1945
|
-
-webkit-mask:
|
|
1946
|
-
linear-gradient(#000 0 0) content-box,
|
|
1947
|
-
linear-gradient(#000 0 0);
|
|
1948
|
-
mask:
|
|
1949
|
-
linear-gradient(#000 0 0) content-box,
|
|
1950
|
-
linear-gradient(#000 0 0);
|
|
1951
|
-
mask-composite: exclude;
|
|
1952
|
-
/* After the standard shorthand: WebKit aliases `mask` onto `-webkit-mask`, so
|
|
1953
|
-
declaring this first lets the shorthand reset it to `source-over` — the
|
|
1954
|
-
filled disc again, on exactly the browsers too old to have `mask-composite`
|
|
1955
|
-
at all. */
|
|
1956
|
-
-webkit-mask-composite: xor;
|
|
1957
|
-
z-index: 0;
|
|
1958
|
-
pointer-events: none;
|
|
1959
|
-
}
|
|
1960
|
-
|
|
1961
|
-
/* The halo lights the air AROUND the box and nothing behind it. */
|
|
1962
|
-
.hz-composer::after {
|
|
1963
|
-
content: "";
|
|
1964
|
-
position: absolute;
|
|
1965
|
-
inset: -6px;
|
|
1966
|
-
padding: 6px;
|
|
1967
|
-
/* Concentric with the box, NOT `inherit`: the halo lives 6px outside, so an
|
|
1968
|
-
inherited corner on this larger box curves too tight and reads as a second,
|
|
1969
|
-
mismatched rounding just outside the panel. */
|
|
1970
|
-
border-radius: calc(1.5rem + 6px);
|
|
1971
|
-
background: conic-gradient(from var(--hz-angle), var(--hz-spectrum));
|
|
1972
|
-
filter: blur(16px);
|
|
1973
|
-
opacity: 0.22;
|
|
1974
|
-
animation: hzComposerSpin 10s linear infinite;
|
|
1975
|
-
-webkit-mask:
|
|
1976
|
-
linear-gradient(#000 0 0) content-box,
|
|
1977
|
-
linear-gradient(#000 0 0);
|
|
1978
|
-
mask:
|
|
1979
|
-
linear-gradient(#000 0 0) content-box,
|
|
1980
|
-
linear-gradient(#000 0 0);
|
|
1981
|
-
mask-composite: exclude;
|
|
1982
|
-
-webkit-mask-composite: xor;
|
|
1983
|
-
z-index: -1;
|
|
1984
|
-
pointer-events: none;
|
|
1985
|
-
}
|
|
1986
|
-
|
|
1987
|
-
/* The panel sits above ring and halo. */
|
|
1988
|
-
.hz-composer > * {
|
|
1989
|
-
position: relative;
|
|
1990
|
-
z-index: 1;
|
|
1991
|
-
}
|
|
1992
|
-
|
|
1993
|
-
@media (prefers-reduced-motion: reduce) {
|
|
1994
|
-
.hz-composer::before,
|
|
1995
|
-
.hz-composer::after {
|
|
1996
|
-
animation: none;
|
|
1997
|
-
}
|
|
1998
|
-
}
|
|
1999
|
-
|
|
2000
1778
|
/* FOCUS RINGS THE CONTROL A PERSON SEES, WHICH IS THE WHOLE COMPOSER.
|
|
2001
1779
|
|
|
2002
1780
|
`Composer` is a bordered box holding a field above a toolbar row, so it reads
|
|
@@ -2028,6 +1806,319 @@
|
|
|
2028
1806
|
--outlineColor: transparent;
|
|
2029
1807
|
}
|
|
2030
1808
|
|
|
1809
|
+
/* @hanzo/ui motion — the calm, restrained animation vocabulary the Hanzo
|
|
1810
|
+
surfaces share. One place defines the easing; components carry the name.
|
|
1811
|
+
|
|
1812
|
+
Import once at the app root: import '@hanzo/ui/styles/motion.css'
|
|
1813
|
+
|
|
1814
|
+
── KEYED ON `data-motion`, NEVER ON A CLASS ─────────────────────────────────
|
|
1815
|
+
A component says what it does with one attribute — `data-motion="rise"` — and
|
|
1816
|
+
this sheet says how. The paint (a caret's ink, a skeleton's gradient) is the
|
|
1817
|
+
component's own gui props; what is left here is what no prop can say: a
|
|
1818
|
+
keyframe, a transition a preference can switch off, and the preference
|
|
1819
|
+
itself. Every animation is off under `prefers-reduced-motion: reduce`.
|
|
1820
|
+
|
|
1821
|
+
rise enter: fade up 10px over 400ms FadeIn, Timeline, tooltips
|
|
1822
|
+
fade opacity eases 240ms SlideOver's scrim
|
|
1823
|
+
slide transform eases 260ms SlideOver's panel
|
|
1824
|
+
drag a row eases into place while one is held Reorder
|
|
1825
|
+
pulse opacity dims and returns, 2s Pulse, StatusDot, Skeleton
|
|
1826
|
+
blink on/off, 1s Caret
|
|
1827
|
+
shimmer a highlight sweeps a placeholder product Skeleton
|
|
1828
|
+
unfold a sheet turns open about its hinge unfold() */
|
|
1829
|
+
|
|
1830
|
+
@keyframes rise {
|
|
1831
|
+
from {
|
|
1832
|
+
opacity: 0;
|
|
1833
|
+
transform: translateY(10px);
|
|
1834
|
+
}
|
|
1835
|
+
to {
|
|
1836
|
+
opacity: 1;
|
|
1837
|
+
transform: translateY(0);
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
|
|
1841
|
+
[data-motion='rise'] {
|
|
1842
|
+
animation: rise 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
1843
|
+
will-change: transform, opacity;
|
|
1844
|
+
}
|
|
1845
|
+
|
|
1846
|
+
[data-motion='fade'] {
|
|
1847
|
+
transition: opacity 240ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
1848
|
+
will-change: opacity;
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
[data-motion='slide'] {
|
|
1852
|
+
transition: transform 260ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
1853
|
+
will-change: transform;
|
|
1854
|
+
}
|
|
1855
|
+
|
|
1856
|
+
[data-motion='drag'] {
|
|
1857
|
+
touch-action: none;
|
|
1858
|
+
transition: transform 180ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
1859
|
+
}
|
|
1860
|
+
|
|
1861
|
+
@keyframes dim {
|
|
1862
|
+
50% {
|
|
1863
|
+
opacity: 0.5;
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
|
|
1867
|
+
[data-motion='pulse'] {
|
|
1868
|
+
animation: dim 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
1869
|
+
}
|
|
1870
|
+
|
|
1871
|
+
@keyframes blink {
|
|
1872
|
+
0%,
|
|
1873
|
+
49% {
|
|
1874
|
+
opacity: 1;
|
|
1875
|
+
}
|
|
1876
|
+
50%,
|
|
1877
|
+
100% {
|
|
1878
|
+
opacity: 0;
|
|
1879
|
+
}
|
|
1880
|
+
}
|
|
1881
|
+
|
|
1882
|
+
[data-motion='blink'] {
|
|
1883
|
+
animation: blink 1s steps(1) infinite;
|
|
1884
|
+
}
|
|
1885
|
+
|
|
1886
|
+
@keyframes shimmer {
|
|
1887
|
+
0% {
|
|
1888
|
+
background-position: -160px 0;
|
|
1889
|
+
}
|
|
1890
|
+
100% {
|
|
1891
|
+
background-position: 160px 0;
|
|
1892
|
+
}
|
|
1893
|
+
}
|
|
1894
|
+
|
|
1895
|
+
[data-motion='shimmer'] {
|
|
1896
|
+
animation: shimmer 1.2s ease-in-out infinite;
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
/* Unfold — how a sheet arrives. A panel that appears by fading is a rectangle
|
|
1900
|
+
switching on; a sheet of paper TURNS OPEN about the edge it is hinged on. The
|
|
1901
|
+
hinge is the only knob and the angle follows it, so a turn cannot open the
|
|
1902
|
+
wrong way. `perspective()` inside the transform puts the vanishing point at
|
|
1903
|
+
the sheet's own centre. Seven degrees over 220ms. */
|
|
1904
|
+
@keyframes unfold {
|
|
1905
|
+
from {
|
|
1906
|
+
opacity: 0;
|
|
1907
|
+
transform: perspective(1600px) rotateY(var(--turn, -7deg));
|
|
1908
|
+
}
|
|
1909
|
+
to {
|
|
1910
|
+
opacity: 1;
|
|
1911
|
+
transform: perspective(1600px) rotateY(0deg);
|
|
1912
|
+
}
|
|
1913
|
+
}
|
|
1914
|
+
|
|
1915
|
+
[data-motion='unfold'] {
|
|
1916
|
+
animation: unfold 220ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
|
|
1917
|
+
transform-origin: left center;
|
|
1918
|
+
will-change: transform, opacity;
|
|
1919
|
+
}
|
|
1920
|
+
|
|
1921
|
+
[data-motion='unfold'][data-hinge='right'] {
|
|
1922
|
+
transform-origin: right center;
|
|
1923
|
+
--turn: 7deg;
|
|
1924
|
+
}
|
|
1925
|
+
|
|
1926
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1927
|
+
[data-motion] {
|
|
1928
|
+
animation: none;
|
|
1929
|
+
transition: none;
|
|
1930
|
+
}
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
/* ── Layout guarantee ──────────────────────────────────────────────────────────
|
|
1934
|
+
Structural, so attached to a data attribute: it is the thing the primitive
|
|
1935
|
+
PROMISES, and a class can be lost by forgetting to pass it on. */
|
|
1936
|
+
|
|
1937
|
+
/* Media fills the ratio box instead of setting its own size. Without this an
|
|
1938
|
+
<img> renders at its intrinsic pixel size and either overflows the frame or
|
|
1939
|
+
sits letterboxed inside it, and the ratio the caller asked for is decoration.
|
|
1940
|
+
`display:block` kills the inline-baseline gap under the image. */
|
|
1941
|
+
[data-ratio] > img,
|
|
1942
|
+
[data-ratio] > video {
|
|
1943
|
+
width: 100%;
|
|
1944
|
+
height: 100%;
|
|
1945
|
+
object-fit: cover;
|
|
1946
|
+
display: block;
|
|
1947
|
+
}
|
|
1948
|
+
|
|
1949
|
+
|
|
1950
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
1951
|
+
Scrollbars, on the surfaces this package scrolls.
|
|
1952
|
+
|
|
1953
|
+
Left to the platform this is not neutral: Linux/GTK Chrome draws a wide track
|
|
1954
|
+
with STEPPER ARROWS at both ends, so a dark product grows two grey buttons per
|
|
1955
|
+
scroll region. Windows draws a wide light track. macOS overlays a thin one,
|
|
1956
|
+
which is the behaviour the other two should have had.
|
|
1957
|
+
|
|
1958
|
+
THE TWO HALVES MUST NOT BE DECLARED TOGETHER, and that is the whole subtlety.
|
|
1959
|
+
Chromium supports both the standard properties and the `::-webkit-scrollbar`
|
|
1960
|
+
pseudo-elements — but the moment `scrollbar-width` or `scrollbar-color` is
|
|
1961
|
+
anything other than `auto`, it takes the standard path and DISCARDS the entire
|
|
1962
|
+
webkit block. Shipping both is how 8.1.19 removed nothing: measured headed on
|
|
1963
|
+
Linux, as-shipped gave a 10px gutter with arrows, while the authored webkit
|
|
1964
|
+
rule alone gives 8px with none. Isolated: webkit-only 8px no arrows;
|
|
1965
|
+
standard-only 10px arrows; both together 10px arrows.
|
|
1966
|
+
|
|
1967
|
+
Neither half is redundant, so neither can simply be deleted — Firefox
|
|
1968
|
+
implements ONLY the standard properties, Safari ONLY the webkit ones. They are
|
|
1969
|
+
separated by engine instead: the webkit block applies wherever the selector is
|
|
1970
|
+
understood, and the standard properties apply only where it is not.
|
|
1971
|
+
|
|
1972
|
+
And it is invisible headless. Chromium's headless shell paints OVERLAY
|
|
1973
|
+
scrollbars, so nothing is drawn, `offsetWidth - clientWidth` is 0 on a blank
|
|
1974
|
+
page, and `getComputedStyle(el, '::-webkit-scrollbar-button').display` happily
|
|
1975
|
+
reports `none` for a rule that never ran. This must be checked headed.
|
|
1976
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
1977
|
+
|
|
1978
|
+
/* Firefox and anything else with no webkit pseudo-elements. */
|
|
1979
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
1980
|
+
:where(
|
|
1981
|
+
[data-slot='fill'],
|
|
1982
|
+
[data-slot='thread'],
|
|
1983
|
+
[data-slot='sources-strip'],
|
|
1984
|
+
[data-slot='sidebar-scroll'],
|
|
1985
|
+
[data-slot='scroll-area-viewport'],
|
|
1986
|
+
[data-slot='textarea'],
|
|
1987
|
+
[data-slot='composer-field']
|
|
1988
|
+
) {
|
|
1989
|
+
scrollbar-width: thin;
|
|
1990
|
+
scrollbar-color: rgb(255 255 255 / 0.18) transparent;
|
|
1991
|
+
}
|
|
1992
|
+
.t_light :where(
|
|
1993
|
+
[data-slot='fill'],
|
|
1994
|
+
[data-slot='thread'],
|
|
1995
|
+
[data-slot='sources-strip'],
|
|
1996
|
+
[data-slot='sidebar-scroll'],
|
|
1997
|
+
[data-slot='scroll-area-viewport'],
|
|
1998
|
+
[data-slot='textarea'],
|
|
1999
|
+
[data-slot='composer-field']
|
|
2000
|
+
) { scrollbar-color: rgb(0 0 0 / 0.20) transparent; }
|
|
2001
|
+
}
|
|
2002
|
+
|
|
2003
|
+
/* Chromium and Safari.
|
|
2004
|
+
The first rule is the load-bearing one and it is a RESET, not a style.
|
|
2005
|
+
@hanzo/design sets `scrollbar-color` and `scrollbar-width` on `:where(html)`
|
|
2006
|
+
(theme.css), and both INHERIT — so every element in the document already
|
|
2007
|
+
carries a non-`auto` value, Chromium takes the standard path, and the whole
|
|
2008
|
+
webkit block below is discarded before it is read. Nothing declared here can
|
|
2009
|
+
win until the inherited value is put back to `auto` on the element itself.
|
|
2010
|
+
That is why the arrows survived 8.1.19: the competing declaration was one
|
|
2011
|
+
level up and inherited, not a rule anyone would find in this file. */
|
|
2012
|
+
@supports selector(::-webkit-scrollbar) {
|
|
2013
|
+
:where(
|
|
2014
|
+
[data-slot='fill'],
|
|
2015
|
+
[data-slot='thread'],
|
|
2016
|
+
[data-slot='sources-strip'],
|
|
2017
|
+
[data-slot='sidebar-scroll'],
|
|
2018
|
+
[data-slot='scroll-area-viewport'],
|
|
2019
|
+
[data-slot='textarea'],
|
|
2020
|
+
[data-slot='composer-field']
|
|
2021
|
+
) {
|
|
2022
|
+
scrollbar-width: auto;
|
|
2023
|
+
scrollbar-color: auto;
|
|
2024
|
+
}
|
|
2025
|
+
|
|
2026
|
+
:where(
|
|
2027
|
+
[data-slot='fill'],
|
|
2028
|
+
[data-slot='thread'],
|
|
2029
|
+
[data-slot='sources-strip'],
|
|
2030
|
+
[data-slot='sidebar-scroll'],
|
|
2031
|
+
[data-slot='scroll-area-viewport'],
|
|
2032
|
+
[data-slot='textarea'],
|
|
2033
|
+
[data-slot='composer-field']
|
|
2034
|
+
)::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
2035
|
+
|
|
2036
|
+
/* The steppers. This is the rule that removes the arrows, and the reason the
|
|
2037
|
+
two halves had to be separated at all. */
|
|
2038
|
+
:where(
|
|
2039
|
+
[data-slot='fill'],
|
|
2040
|
+
[data-slot='thread'],
|
|
2041
|
+
[data-slot='sources-strip'],
|
|
2042
|
+
[data-slot='sidebar-scroll'],
|
|
2043
|
+
[data-slot='scroll-area-viewport'],
|
|
2044
|
+
[data-slot='textarea'],
|
|
2045
|
+
[data-slot='composer-field']
|
|
2046
|
+
)::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
|
|
2047
|
+
|
|
2048
|
+
:where(
|
|
2049
|
+
[data-slot='fill'],
|
|
2050
|
+
[data-slot='thread'],
|
|
2051
|
+
[data-slot='sources-strip'],
|
|
2052
|
+
[data-slot='sidebar-scroll'],
|
|
2053
|
+
[data-slot='scroll-area-viewport'],
|
|
2054
|
+
[data-slot='textarea'],
|
|
2055
|
+
[data-slot='composer-field']
|
|
2056
|
+
)::-webkit-scrollbar-track { background: transparent; }
|
|
2057
|
+
|
|
2058
|
+
:where(
|
|
2059
|
+
[data-slot='fill'],
|
|
2060
|
+
[data-slot='thread'],
|
|
2061
|
+
[data-slot='sources-strip'],
|
|
2062
|
+
[data-slot='sidebar-scroll'],
|
|
2063
|
+
[data-slot='scroll-area-viewport'],
|
|
2064
|
+
[data-slot='textarea'],
|
|
2065
|
+
[data-slot='composer-field']
|
|
2066
|
+
)::-webkit-scrollbar-thumb {
|
|
2067
|
+
background: rgb(255 255 255 / 0.18);
|
|
2068
|
+
border-radius: 999px;
|
|
2069
|
+
/* A transparent border with background-clip keeps the thumb off the very
|
|
2070
|
+
edge without a track colour doing it, so it reads as an overlay rather
|
|
2071
|
+
than a channel. */
|
|
2072
|
+
border: 2px solid transparent;
|
|
2073
|
+
background-clip: content-box;
|
|
2074
|
+
}
|
|
2075
|
+
:where(
|
|
2076
|
+
[data-slot='fill'],
|
|
2077
|
+
[data-slot='thread'],
|
|
2078
|
+
[data-slot='sources-strip'],
|
|
2079
|
+
[data-slot='sidebar-scroll'],
|
|
2080
|
+
[data-slot='scroll-area-viewport'],
|
|
2081
|
+
[data-slot='textarea'],
|
|
2082
|
+
[data-slot='composer-field']
|
|
2083
|
+
)::-webkit-scrollbar-thumb:hover {
|
|
2084
|
+
background: rgb(255 255 255 / 0.30);
|
|
2085
|
+
background-clip: content-box;
|
|
2086
|
+
}
|
|
2087
|
+
:where(
|
|
2088
|
+
[data-slot='fill'],
|
|
2089
|
+
[data-slot='thread'],
|
|
2090
|
+
[data-slot='sources-strip'],
|
|
2091
|
+
[data-slot='sidebar-scroll'],
|
|
2092
|
+
[data-slot='scroll-area-viewport'],
|
|
2093
|
+
[data-slot='textarea'],
|
|
2094
|
+
[data-slot='composer-field']
|
|
2095
|
+
)::-webkit-scrollbar-corner { background: transparent; }
|
|
2096
|
+
|
|
2097
|
+
.t_light :where(
|
|
2098
|
+
[data-slot='fill'],
|
|
2099
|
+
[data-slot='thread'],
|
|
2100
|
+
[data-slot='sources-strip'],
|
|
2101
|
+
[data-slot='sidebar-scroll'],
|
|
2102
|
+
[data-slot='scroll-area-viewport'],
|
|
2103
|
+
[data-slot='textarea'],
|
|
2104
|
+
[data-slot='composer-field']
|
|
2105
|
+
)::-webkit-scrollbar-thumb {
|
|
2106
|
+
background: rgb(0 0 0 / 0.20);
|
|
2107
|
+
background-clip: content-box;
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
|
|
2111
|
+
/* A carousel scrolls but shows no bar: the arrows and the snap already say it
|
|
2112
|
+
scrolls, and a bar appearing mid-drag shifts the slides under the pointer.
|
|
2113
|
+
Firefox reads `scrollbar-width`, which the component sets; WebKit reads only
|
|
2114
|
+
the pseudo-element, which no prop can reach. */
|
|
2115
|
+
[data-slot='carousel-content']::-webkit-scrollbar { display: none; }
|
|
2116
|
+
|
|
2117
|
+
/* The textarea's resize grip is the other platform artefact in the same family:
|
|
2118
|
+
a diagonal hatch drawn by the UA that matches nothing. A composer that grows
|
|
2119
|
+
with its content does not need one. */
|
|
2120
|
+
:where([data-slot='textarea'], [data-slot='composer-field']) { resize: none; }
|
|
2121
|
+
|
|
2031
2122
|
[stylesheet-group="0"]{}
|
|
2032
2123
|
body{margin:0;}
|
|
2033
2124
|
button::-moz-focus-inner,input::-moz-focus-inner{border:0;padding:0;}
|
|
@@ -2246,10 +2337,10 @@ input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-web
|
|
|
2246
2337
|
is what gives it presence — so only the elements that set paragraphs are
|
|
2247
2338
|
capped. A max-width can never make something wider, so this is safe inside a
|
|
2248
2339
|
card or a column that is already narrower. */
|
|
2249
|
-
|
|
2250
|
-
|
|
2251
|
-
|
|
2252
|
-
|
|
2340
|
+
[data-slot='prose'] > p,
|
|
2341
|
+
[data-slot='prose'] > ul,
|
|
2342
|
+
[data-slot='prose'] > ol,
|
|
2343
|
+
[data-slot='prose'] > blockquote {
|
|
2253
2344
|
max-width: var(--measure);
|
|
2254
2345
|
}
|
|
2255
2346
|
|
|
@@ -2326,14 +2417,14 @@ input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-web
|
|
|
2326
2417
|
}
|
|
2327
2418
|
|
|
2328
2419
|
/* ── Prose meets a control ────────────────────────────────────────────────
|
|
2329
|
-
|
|
2420
|
+
`[data-slot='prose'] a` is underlined on purpose: in running text an underline is what
|
|
2330
2421
|
marks a link. A link wearing a button is not running text — it already reads
|
|
2331
2422
|
as a control from its fill and its border — so the underline is noise inside
|
|
2332
2423
|
it. Measured on every call to action across the lux slides, each of which
|
|
2333
2424
|
sits inside prose. */
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2425
|
+
[data-slot='prose'] [data-slot="button"] a,
|
|
2426
|
+
[data-slot='prose'] a[data-slot="button"],
|
|
2427
|
+
[data-slot='prose'] button a {
|
|
2337
2428
|
text-decoration: none;
|
|
2338
2429
|
}
|
|
2339
2430
|
|
|
@@ -2342,22 +2433,22 @@ input::-webkit-search-cancel-button,input::-webkit-search-decoration,input::-web
|
|
|
2342
2433
|
a 52px display line and a 17px sub-head: 8px under the display line read as
|
|
2343
2434
|
the byline touching it. `em` here is the heading's own size, so the ratio
|
|
2344
2435
|
holds at every rung. A caller setting its own margin still wins. */
|
|
2345
|
-
|
|
2346
|
-
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2436
|
+
[data-slot='prose'] > h1 { margin-block-end: .5em }
|
|
2437
|
+
[data-slot='prose'] > h2 { margin-block-end: .55em }
|
|
2438
|
+
[data-slot='prose'] > h3 { margin-block-end: .6em }
|
|
2439
|
+
[data-slot='prose'] > h4,
|
|
2440
|
+
[data-slot='prose'] > h5,
|
|
2441
|
+
[data-slot='prose'] > h6 { margin-block-end: .75em }
|
|
2351
2442
|
|
|
2352
2443
|
/* Space ABOVE a heading is larger than the space below it — that asymmetry is
|
|
2353
2444
|
what groups a heading with the text it introduces rather than the text it
|
|
2354
2445
|
follows. Not applied to the first child, which has nothing to separate from. */
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2446
|
+
[data-slot='prose'] > h1:not(:first-child) { margin-block-start: 1.1em }
|
|
2447
|
+
[data-slot='prose'] > h2:not(:first-child) { margin-block-start: 1.2em }
|
|
2448
|
+
[data-slot='prose'] > h3:not(:first-child),
|
|
2449
|
+
[data-slot='prose'] > h4:not(:first-child),
|
|
2450
|
+
[data-slot='prose'] > h5:not(:first-child),
|
|
2451
|
+
[data-slot='prose'] > h6:not(:first-child) { margin-block-start: 1.4em }
|
|
2361
2452
|
|
|
2362
2453
|
/* ── The line-height a converted box inherits ─────────────────────────────
|
|
2363
2454
|
gui's Stack stamps its own leading, which is right for a native view and
|
|
@@ -2396,34 +2487,28 @@ a svg,
|
|
|
2396
2487
|
flex-shrink: 0;
|
|
2397
2488
|
}
|
|
2398
2489
|
|
|
2399
|
-
/* @hanzo/ui motion
|
|
2400
|
-
|
|
2401
|
-
`className` forwards to the underlying DOM node on web, so the browser
|
|
2402
|
-
transitions the Gui-driven inline width/transform/opacity. Every animation is
|
|
2403
|
-
guarded by `prefers-reduced-motion: reduce`.
|
|
2490
|
+
/* @hanzo/ui motion — the calm, restrained animation vocabulary the Hanzo
|
|
2491
|
+
surfaces share. One place defines the easing; components carry the name.
|
|
2404
2492
|
|
|
2405
2493
|
Import once at the app root: import '@hanzo/ui/styles/motion.css'
|
|
2406
2494
|
|
|
2407
|
-
──
|
|
2408
|
-
|
|
2409
|
-
|
|
2410
|
-
|
|
2411
|
-
|
|
2412
|
-
|
|
2413
|
-
|
|
2414
|
-
|
|
2415
|
-
|
|
2416
|
-
|
|
2417
|
-
|
|
2418
|
-
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
/* Fade-up entrance — <FadeIn> applies the class + a per-item stagger delay.
|
|
2425
|
-
~0.4s ease-out, small upward travel (matches the hanzo.ai marketing feel). */
|
|
2426
|
-
@keyframes hz-fade-up {
|
|
2495
|
+
── KEYED ON `data-motion`, NEVER ON A CLASS ─────────────────────────────────
|
|
2496
|
+
A component says what it does with one attribute — `data-motion="rise"` — and
|
|
2497
|
+
this sheet says how. The paint (a caret's ink, a skeleton's gradient) is the
|
|
2498
|
+
component's own gui props; what is left here is what no prop can say: a
|
|
2499
|
+
keyframe, a transition a preference can switch off, and the preference
|
|
2500
|
+
itself. Every animation is off under `prefers-reduced-motion: reduce`.
|
|
2501
|
+
|
|
2502
|
+
rise enter: fade up 10px over 400ms FadeIn, Timeline, tooltips
|
|
2503
|
+
fade opacity eases 240ms SlideOver's scrim
|
|
2504
|
+
slide transform eases 260ms SlideOver's panel
|
|
2505
|
+
drag a row eases into place while one is held Reorder
|
|
2506
|
+
pulse opacity dims and returns, 2s Pulse, StatusDot, Skeleton
|
|
2507
|
+
blink on/off, 1s Caret
|
|
2508
|
+
shimmer a highlight sweeps a placeholder product Skeleton
|
|
2509
|
+
unfold a sheet turns open about its hinge unfold() */
|
|
2510
|
+
|
|
2511
|
+
@keyframes rise {
|
|
2427
2512
|
from {
|
|
2428
2513
|
opacity: 0;
|
|
2429
2514
|
transform: translateY(10px);
|
|
@@ -2434,122 +2519,37 @@ a svg,
|
|
|
2434
2519
|
}
|
|
2435
2520
|
}
|
|
2436
2521
|
|
|
2437
|
-
|
|
2438
|
-
animation:
|
|
2522
|
+
[data-motion='rise'] {
|
|
2523
|
+
animation: rise 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
2439
2524
|
will-change: transform, opacity;
|
|
2440
2525
|
}
|
|
2441
2526
|
|
|
2442
|
-
|
|
2443
|
-
.
|
|
2444
|
-
|
|
2445
|
-
}
|
|
2446
|
-
}
|
|
2447
|
-
|
|
2448
|
-
/* Shell chrome motion — sidebar collapse (width) and the Linear-style two-level
|
|
2449
|
-
nav slide (transform); backdrop cross-fade behind a SlideOver / dialog. */
|
|
2450
|
-
.hz-collapse {
|
|
2451
|
-
transition: width 220ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
2452
|
-
will-change: width;
|
|
2527
|
+
[data-motion='fade'] {
|
|
2528
|
+
transition: opacity 240ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
2529
|
+
will-change: opacity;
|
|
2453
2530
|
}
|
|
2454
2531
|
|
|
2455
|
-
|
|
2532
|
+
[data-motion='slide'] {
|
|
2456
2533
|
transition: transform 260ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
2457
2534
|
will-change: transform;
|
|
2458
2535
|
}
|
|
2459
2536
|
|
|
2460
|
-
|
|
2461
|
-
transition: opacity 240ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
2462
|
-
will-change: opacity;
|
|
2463
|
-
}
|
|
2464
|
-
|
|
2465
|
-
/* Drag-to-reorder — a pinned row while it is being dragged (pointer DnD). The
|
|
2466
|
-
lifted row gets a subtle lift; siblings ease into place via `.hz-slide`. */
|
|
2467
|
-
.hz-drag {
|
|
2537
|
+
[data-motion='drag'] {
|
|
2468
2538
|
touch-action: none;
|
|
2469
2539
|
transition: transform 180ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
2470
2540
|
}
|
|
2471
|
-
.hz-drag[data-dragging='true'] {
|
|
2472
|
-
transition: none;
|
|
2473
|
-
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
|
|
2474
|
-
opacity: 0.96;
|
|
2475
|
-
cursor: grabbing;
|
|
2476
|
-
}
|
|
2477
|
-
|
|
2478
|
-
@media (prefers-reduced-motion: reduce) {
|
|
2479
|
-
.hz-collapse,
|
|
2480
|
-
.hz-slide,
|
|
2481
|
-
.hz-fade,
|
|
2482
|
-
.hz-drag {
|
|
2483
|
-
transition: none;
|
|
2484
|
-
}
|
|
2485
|
-
}
|
|
2486
2541
|
|
|
2487
|
-
|
|
2488
|
-
live sparkline are driven in JS (rAF, gated by prefers-reduced-motion in the
|
|
2489
|
-
hooks); these are the pure-CSS bits: a loading shimmer, a live-feed pulse, and
|
|
2490
|
-
a brief highlight when a freshly-arrived row lands. */
|
|
2491
|
-
|
|
2492
|
-
/* Skeleton shimmer — an honest "loading", never fabricated content. */
|
|
2493
|
-
@keyframes hz-shimmer {
|
|
2494
|
-
0% {
|
|
2495
|
-
background-position: -160px 0;
|
|
2496
|
-
}
|
|
2497
|
-
100% {
|
|
2498
|
-
background-position: 160px 0;
|
|
2499
|
-
}
|
|
2500
|
-
}
|
|
2501
|
-
|
|
2502
|
-
.hz-skeleton {
|
|
2503
|
-
background-color: var(--color3, rgba(128, 128, 128, 0.14));
|
|
2504
|
-
background-image: linear-gradient(
|
|
2505
|
-
90deg,
|
|
2506
|
-
transparent 0%,
|
|
2507
|
-
var(--color4, rgba(128, 128, 128, 0.22)) 50%,
|
|
2508
|
-
transparent 100%
|
|
2509
|
-
);
|
|
2510
|
-
background-size: 160px 100%;
|
|
2511
|
-
background-repeat: no-repeat;
|
|
2512
|
-
animation: hz-shimmer 1.2s ease-in-out infinite;
|
|
2513
|
-
}
|
|
2514
|
-
|
|
2515
|
-
/* Live-feed pulse — the "Live" dot on a streaming panel.
|
|
2516
|
-
|
|
2517
|
-
NAMED APART FROM THE SKELETON'S. Both sheets shipped a `@keyframes hz-pulse`
|
|
2518
|
-
and `styles.css` concatenates them, so the later one — this one — won for
|
|
2519
|
-
every consumer and `.hz-pulse` animated a placeholder by RESIZING it. That is
|
|
2520
|
-
the thing theme.css's own comment forbids: "animating a colour or a size
|
|
2521
|
-
would repaint or reflow every frame for a placeholder nobody is looking at".
|
|
2522
|
-
Nothing referenced this keyframe by name, which is why it went unnoticed. */
|
|
2523
|
-
@keyframes hz-live {
|
|
2524
|
-
0%,
|
|
2525
|
-
100% {
|
|
2526
|
-
opacity: 1;
|
|
2527
|
-
transform: scale(1);
|
|
2528
|
-
}
|
|
2529
|
-
50% {
|
|
2530
|
-
opacity: 0.45;
|
|
2531
|
-
transform: scale(0.82);
|
|
2532
|
-
}
|
|
2533
|
-
}
|
|
2534
|
-
|
|
2535
|
-
/* THE TWO CLASSES THE COMPONENTS STAMP, in the sheet a host imports.
|
|
2536
|
-
`skeleton.js` emits `hz-pulse` and `input-otp.js` emits `hz-caret`, and their
|
|
2537
|
-
rules lived only in theme.css — the sheet that inlines the whole design system
|
|
2538
|
-
and which a host with its own tokens cannot take. So every host either mounted
|
|
2539
|
-
110KB it did not want or wrote these two rules by hand; hanzo.ai carried them
|
|
2540
|
-
for exactly that reason. A library that stamps a class owns its rule, and this
|
|
2541
|
-
is the sheet it owns it in. */
|
|
2542
|
-
@keyframes hz-dim {
|
|
2542
|
+
@keyframes dim {
|
|
2543
2543
|
50% {
|
|
2544
2544
|
opacity: 0.5;
|
|
2545
2545
|
}
|
|
2546
2546
|
}
|
|
2547
2547
|
|
|
2548
|
-
|
|
2549
|
-
animation:
|
|
2548
|
+
[data-motion='pulse'] {
|
|
2549
|
+
animation: dim 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
2550
2550
|
}
|
|
2551
2551
|
|
|
2552
|
-
@keyframes
|
|
2552
|
+
@keyframes blink {
|
|
2553
2553
|
0%,
|
|
2554
2554
|
49% {
|
|
2555
2555
|
opacity: 1;
|
|
@@ -2560,138 +2560,32 @@ a svg,
|
|
|
2560
2560
|
}
|
|
2561
2561
|
}
|
|
2562
2562
|
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
animation: hz-blink 1s steps(1) infinite;
|
|
2566
|
-
}
|
|
2567
|
-
|
|
2568
|
-
/* Entrance for a freshly-arrived activity row (staggerless — one row at a time). */
|
|
2569
|
-
@keyframes hz-row-in {
|
|
2570
|
-
from {
|
|
2571
|
-
opacity: 0;
|
|
2572
|
-
transform: translateY(-6px);
|
|
2573
|
-
}
|
|
2574
|
-
to {
|
|
2575
|
-
opacity: 1;
|
|
2576
|
-
transform: translateY(0);
|
|
2577
|
-
}
|
|
2563
|
+
[data-motion='blink'] {
|
|
2564
|
+
animation: blink 1s steps(1) infinite;
|
|
2578
2565
|
}
|
|
2579
2566
|
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
@media (prefers-reduced-motion: reduce) {
|
|
2585
|
-
.hz-skeleton {
|
|
2586
|
-
animation: none;
|
|
2587
|
-
}
|
|
2588
|
-
.hz-row-in {
|
|
2589
|
-
animation: none;
|
|
2590
|
-
}
|
|
2591
|
-
.hz-pulse {
|
|
2592
|
-
animation: none;
|
|
2567
|
+
@keyframes shimmer {
|
|
2568
|
+
0% {
|
|
2569
|
+
background-position: -160px 0;
|
|
2593
2570
|
}
|
|
2594
|
-
|
|
2595
|
-
|
|
2571
|
+
100% {
|
|
2572
|
+
background-position: 160px 0;
|
|
2596
2573
|
}
|
|
2597
2574
|
}
|
|
2598
2575
|
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
SelectMenu paint their popovers with `hz-paper hz-menu-in`; DataTable rows use
|
|
2602
|
-
`hz-row`. They travel WITH the components (this is the package's one
|
|
2603
|
-
stylesheet) so any host that imports `@hanzo/ui/styles/motion.css` renders them
|
|
2604
|
-
correctly. The elevation/ring variables fall back to sane values, so a host
|
|
2605
|
-
that defines its own `--hz-*` theme tokens (the console does) still wins. */
|
|
2606
|
-
|
|
2607
|
-
.hz-tnum {
|
|
2608
|
-
font-variant-numeric: tabular-nums;
|
|
2609
|
-
font-feature-settings: 'tnum' 1;
|
|
2610
|
-
}
|
|
2611
|
-
|
|
2612
|
-
/* Data/numeric face — Zen Mono + tabular figures for metric values, prices, IDs
|
|
2613
|
-
and counts, so numbers read as precise, column-aligned data. */
|
|
2614
|
-
.hz-mono {
|
|
2615
|
-
font-family: var(--font-mono, 'Zen Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);
|
|
2616
|
-
font-variant-numeric: tabular-nums;
|
|
2617
|
-
font-feature-settings: 'tnum' 1;
|
|
2618
|
-
letter-spacing: -0.01em;
|
|
2619
|
-
}
|
|
2620
|
-
|
|
2621
|
-
/* Paper — a ringed sheet: the ladder's lit edge and drop, plus a hairline all
|
|
2622
|
-
the way round. The three values are reached by their real names. They used to
|
|
2623
|
-
be `--hz-ring` / `--hz-paper-highlight` / `--hz-elevation-3`, none of which is
|
|
2624
|
-
defined in this repo, in @hanzo/design or in any consumer — so all three
|
|
2625
|
-
resolved to hardcoded fallbacks, and the comment above promising that "a host
|
|
2626
|
-
that defines its own --hz-* tokens still wins" described a hook nobody could
|
|
2627
|
-
reach.
|
|
2628
|
-
|
|
2629
|
-
The drop is rung 2's, by the ladder's own name. It read `--shadow-lg` — a
|
|
2630
|
-
t-shirt size @hanzo/brand also declares, for a white canvas, winning on load
|
|
2631
|
-
order — so paper lost its drop on dark exactly the way the rungs did. The
|
|
2632
|
-
fallback stays because this sheet ships on its own: a host that imports
|
|
2633
|
-
motion.css without glass.css has no ladder to read. */
|
|
2634
|
-
.hz-paper {
|
|
2635
|
-
box-shadow: var(--shadow-inset-hairline, inset 0 0 0 1px rgb(255 255 255 / .10)),
|
|
2636
|
-
var(--edge-highlight, inset 0 1px 0 0 rgb(255 255 255 / .10)),
|
|
2637
|
-
var(--glass-shadow-2, 0 10px 15px -3px rgb(0 0 0 / .55), 0 4px 6px -4px rgb(0 0 0 / .55));
|
|
2576
|
+
[data-motion='shimmer'] {
|
|
2577
|
+
animation: shimmer 1.2s ease-in-out infinite;
|
|
2638
2578
|
}
|
|
2639
2579
|
|
|
2640
|
-
|
|
2580
|
+
/* Unfold — how a sheet arrives. A panel that appears by fading is a rectangle
|
|
2581
|
+
switching on; a sheet of paper TURNS OPEN about the edge it is hinged on. The
|
|
2582
|
+
hinge is the only knob and the angle follows it, so a turn cannot open the
|
|
2583
|
+
wrong way. `perspective()` inside the transform puts the vanishing point at
|
|
2584
|
+
the sheet's own centre. Seven degrees over 220ms. */
|
|
2585
|
+
@keyframes unfold {
|
|
2641
2586
|
from {
|
|
2642
2587
|
opacity: 0;
|
|
2643
|
-
|
|
2644
|
-
to {
|
|
2645
|
-
opacity: 1;
|
|
2646
|
-
}
|
|
2647
|
-
}
|
|
2648
|
-
|
|
2649
|
-
.hz-menu-in {
|
|
2650
|
-
animation: hz-menu-in 140ms ease-out both;
|
|
2651
|
-
will-change: opacity;
|
|
2652
|
-
}
|
|
2653
|
-
|
|
2654
|
-
.hz-row {
|
|
2655
|
-
transition: background-color 140ms ease-out;
|
|
2656
|
-
}
|
|
2657
|
-
|
|
2658
|
-
/* AND WHAT IT TRANSITIONS TO. Stating the transition without the destination
|
|
2659
|
-
left every host to invent the affordance — a row that announces it responds
|
|
2660
|
-
and then does not. The colour is @hanzo/design's `--surface-card-quiet`,
|
|
2661
|
-
which carries a value in both themes, so this needs nothing of the host it
|
|
2662
|
-
has not already mounted. */
|
|
2663
|
-
.hz-row:hover {
|
|
2664
|
-
background-color: var(--surface-card-quiet);
|
|
2665
|
-
}
|
|
2666
|
-
|
|
2667
|
-
@media (prefers-reduced-motion: reduce) {
|
|
2668
|
-
.hz-menu-in {
|
|
2669
|
-
animation: none;
|
|
2670
|
-
}
|
|
2671
|
-
}
|
|
2672
|
-
|
|
2673
|
-
/* ── Unfold — how a sheet arrives ─────────────────────────────────────────────
|
|
2674
|
-
A panel that appears by fading is a rectangle switching on. A sheet of paper
|
|
2675
|
-
arrives by TURNING OPEN about the edge it is hinged on, so its near edge swings
|
|
2676
|
-
toward the reader and its far edge stays put — which is the one motion that
|
|
2677
|
-
says "this was already here, folded" rather than "this was drawn just now".
|
|
2678
|
-
|
|
2679
|
-
The hinge is the ONLY thing that varies, so it is the only knob: a drawer
|
|
2680
|
-
coming off the left wall turns about its left edge, a pane folding in from the
|
|
2681
|
-
right about its right. The angle follows the hinge — a sheet swings toward you
|
|
2682
|
-
from whichever side it is held — so naming the hinge sets both, and there is no
|
|
2683
|
-
way to ask for a turn that opens the wrong way.
|
|
2684
|
-
|
|
2685
|
-
`perspective()` inside the transform rather than on a parent: the vanishing
|
|
2686
|
-
point is then the sheet's own centre, so the turn reads at any size and the
|
|
2687
|
-
caller does not have to own a 3D context it did not ask for.
|
|
2688
|
-
|
|
2689
|
-
Seven degrees over 220ms. Enough to see the plane; short of the swinging-door
|
|
2690
|
-
effect that makes a workspace feel like a slideshow. */
|
|
2691
|
-
@keyframes hz-unfold {
|
|
2692
|
-
from {
|
|
2693
|
-
opacity: 0;
|
|
2694
|
-
transform: perspective(1600px) rotateY(var(--hz-turn, -7deg));
|
|
2588
|
+
transform: perspective(1600px) rotateY(var(--turn, -7deg));
|
|
2695
2589
|
}
|
|
2696
2590
|
to {
|
|
2697
2591
|
opacity: 1;
|
|
@@ -2699,37 +2593,27 @@ a svg,
|
|
|
2699
2593
|
}
|
|
2700
2594
|
}
|
|
2701
2595
|
|
|
2702
|
-
|
|
2703
|
-
animation:
|
|
2596
|
+
[data-motion='unfold'] {
|
|
2597
|
+
animation: unfold 220ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
|
|
2704
2598
|
transform-origin: left center;
|
|
2705
2599
|
will-change: transform, opacity;
|
|
2706
2600
|
}
|
|
2707
2601
|
|
|
2708
|
-
|
|
2602
|
+
[data-motion='unfold'][data-hinge='right'] {
|
|
2709
2603
|
transform-origin: right center;
|
|
2710
|
-
--
|
|
2604
|
+
--turn: 7deg;
|
|
2711
2605
|
}
|
|
2712
2606
|
|
|
2713
2607
|
@media (prefers-reduced-motion: reduce) {
|
|
2714
|
-
|
|
2608
|
+
[data-motion] {
|
|
2715
2609
|
animation: none;
|
|
2610
|
+
transition: none;
|
|
2716
2611
|
}
|
|
2717
2612
|
}
|
|
2718
2613
|
|
|
2719
|
-
/* ── Layout
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
thing the primitive PROMISES, and a class can be overwritten by forgetting to
|
|
2723
|
-
pass it on. */
|
|
2724
|
-
|
|
2725
|
-
/* A grid item's initial `min-width` is `auto`, which floors the track at the
|
|
2726
|
-
item's min-content width. One long unbroken string — a hash, a URL, a wide
|
|
2727
|
-
<pre> — then pushes its own column wider and squeezes every sibling, which is
|
|
2728
|
-
the ragged row Grid exists to prevent. The track sizing in grid.tsx is only
|
|
2729
|
-
honoured once this floor is gone. */
|
|
2730
|
-
[data-slot='grid'] > * {
|
|
2731
|
-
min-width: 0;
|
|
2732
|
-
}
|
|
2614
|
+
/* ── Layout guarantee ──────────────────────────────────────────────────────────
|
|
2615
|
+
Structural, so attached to a data attribute: it is the thing the primitive
|
|
2616
|
+
PROMISES, and a class can be lost by forgetting to pass it on. */
|
|
2733
2617
|
|
|
2734
2618
|
/* Media fills the ratio box instead of setting its own size. Without this an
|
|
2735
2619
|
<img> renders at its intrinsic pixel size and either overflows the frame or
|
|
@@ -2905,32 +2789,17 @@ a svg,
|
|
|
2905
2789
|
}
|
|
2906
2790
|
}
|
|
2907
2791
|
|
|
2792
|
+
/* A carousel scrolls but shows no bar: the arrows and the snap already say it
|
|
2793
|
+
scrolls, and a bar appearing mid-drag shifts the slides under the pointer.
|
|
2794
|
+
Firefox reads `scrollbar-width`, which the component sets; WebKit reads only
|
|
2795
|
+
the pseudo-element, which no prop can reach. */
|
|
2796
|
+
[data-slot='carousel-content']::-webkit-scrollbar { display: none; }
|
|
2797
|
+
|
|
2908
2798
|
/* The textarea's resize grip is the other platform artefact in the same family:
|
|
2909
2799
|
a diagonal hatch drawn by the UA that matches nothing. A composer that grows
|
|
2910
2800
|
with its content does not need one. */
|
|
2911
2801
|
:where([data-slot='textarea'], [data-slot='composer-field']) { resize: none; }
|
|
2912
2802
|
|
|
2913
|
-
/* A top-level nav item.
|
|
2914
|
-
*
|
|
2915
|
-
* `navigationMenuTriggerStyle()` returns this name, so a trigger with no rule
|
|
2916
|
-
* behind it is bare text separated only by the list's gap.
|
|
2917
|
-
*
|
|
2918
|
-
* Padding rather than a wider gap: the padding is also the hit area, and a nav
|
|
2919
|
-
* item wants a target bigger than its glyphs. */
|
|
2920
|
-
.hz-nav-menu-trigger {
|
|
2921
|
-
padding-inline: 0.75rem;
|
|
2922
|
-
padding-block: 0.5rem;
|
|
2923
|
-
border-radius: var(--radius, 0.5rem);
|
|
2924
|
-
color: var(--muted-foreground);
|
|
2925
|
-
transition: color 150ms, background-color 150ms;
|
|
2926
|
-
}
|
|
2927
|
-
|
|
2928
|
-
.hz-nav-menu-trigger:hover,
|
|
2929
|
-
.hz-nav-menu-trigger[data-state='open'] {
|
|
2930
|
-
color: var(--foreground);
|
|
2931
|
-
background: var(--muted);
|
|
2932
|
-
}
|
|
2933
|
-
|
|
2934
2803
|
._ovs-contain {overscroll-behavior:contain;}
|
|
2935
2804
|
.t_unmounted .is_View, .t_unmounted .is_Text { transition: none !important; }
|
|
2936
2805
|
.is_View { display: flex; align-items: stretch; flex-direction: column; flex-basis: auto; box-sizing: border-box; min-height: 0; min-width: 0; flex-shrink: 0; }
|
|
@@ -3141,12 +3010,16 @@ a svg,
|
|
|
3141
3010
|
:root ._WebkitBoxOrient-vertical{-webkit-box-orient:vertical;}
|
|
3142
3011
|
:root ._WebkitLineClamp-2{-webkit-line-clamp:2;}
|
|
3143
3012
|
:root ._WebkitLineClamp-3{-webkit-line-clamp:3;}
|
|
3013
|
+
:root ._aspectRatio-1{aspect-ratio:1;}
|
|
3144
3014
|
:root ._aspectRatio-1--6{aspect-ratio:1.6;}
|
|
3145
3015
|
:root ._aspectRatio-1--77777777771627090080{aspect-ratio:1.7777777777777777;}
|
|
3146
3016
|
:root ._b-0px{bottom:0px;}
|
|
3147
3017
|
:root ._b-c-space-4{bottom:var(--c-space-4);}
|
|
3148
3018
|
:root:root:root:root ._background-0focus-hover:focus{background:var(--hover) !important;}
|
|
3149
3019
|
@media (hover) {:root:root ._background-0hover-hover:hover{background:var(--hover) !important;}}
|
|
3020
|
+
:root ._backgroundImage-linear-grad1137497498{background-image:linear-gradient(90deg, transparent 0%, var(--color4, rgba(128, 128, 128, 0.22)) 50%, transparent 100%);}
|
|
3021
|
+
:root ._backgroundRepeat-no-repeat{background-repeat:no-repeat;}
|
|
3022
|
+
:root ._backgroundSize-160px1001029{background-size:160px 100%;}
|
|
3150
3023
|
:root ._bblr-0px{border-bottom-left-radius:0px;}
|
|
3151
3024
|
:root ._bblr-100000px{border-bottom-left-radius:100000px;}
|
|
3152
3025
|
:root ._bblr-1000px{border-bottom-left-radius:1000px;}
|
|
@@ -3164,6 +3037,7 @@ a svg,
|
|
|
3164
3037
|
:root ._bblr-c-radius-5{border-bottom-left-radius:var(--c-radius-5);}
|
|
3165
3038
|
:root ._bblr-c-radius-6{border-bottom-left-radius:var(--c-radius-6);}
|
|
3166
3039
|
:root ._bblr-c-radius-tr3728{border-bottom-left-radius:var(--c-radius-true);}
|
|
3040
|
+
:root ._bblr-radius-full604151108{border-bottom-left-radius:var(--radius-full, 9999px);}
|
|
3167
3041
|
:root ._bblr-radius-lg0--71290927033{border-bottom-left-radius:var(--radius-lg, 0.75rem);}
|
|
3168
3042
|
:root ._bbrr-0px{border-bottom-right-radius:0px;}
|
|
3169
3043
|
:root ._bbrr-100000px{border-bottom-right-radius:100000px;}
|
|
@@ -3182,12 +3056,14 @@ a svg,
|
|
|
3182
3056
|
:root ._bbrr-c-radius-5{border-bottom-right-radius:var(--c-radius-5);}
|
|
3183
3057
|
:root ._bbrr-c-radius-6{border-bottom-right-radius:var(--c-radius-6);}
|
|
3184
3058
|
:root ._bbrr-c-radius-tr3728{border-bottom-right-radius:var(--c-radius-true);}
|
|
3059
|
+
:root ._bbrr-radius-full604151108{border-bottom-right-radius:var(--radius-full, 9999px);}
|
|
3185
3060
|
:root ._bbrr-radius-lg0--71290927033{border-bottom-right-radius:var(--radius-lg, 0.75rem);}
|
|
3186
3061
|
:root ._bbs-solid._bbs-solid{border-bottom-style:solid;}
|
|
3187
3062
|
:root:root:root ._bg-0active-background:active{background-color:var(--background) !important;}
|
|
3188
3063
|
:root:root:root ._bg-0active-backgroundF3405682:active{background-color:var(--backgroundFocus) !important;}
|
|
3189
3064
|
:root:root:root ._bg-0active-backgroundP3496915:active{background-color:var(--backgroundPress) !important;}
|
|
3190
3065
|
:root:root:root ._bg-0active-hover:active{background-color:var(--hover) !important;}
|
|
3066
|
+
:root:root:root ._bg-0active-primary:active{background-color:var(--primary) !important;}
|
|
3191
3067
|
:root:root:root ._bg-0active-raised:active{background-color:var(--raised) !important;}
|
|
3192
3068
|
:root:root:root:root ._bg-0focus-backgroundH3423444:focus{background-color:var(--backgroundHover) !important;}
|
|
3193
3069
|
:root:root:root:root ._bg-0focus-edge:focus{background-color:var(--edge) !important;}
|
|
@@ -3200,6 +3076,7 @@ a svg,
|
|
|
3200
3076
|
@media (hover) {:root:root ._bg-0hover-edge:hover{background-color:var(--edge) !important;}}
|
|
3201
3077
|
@media (hover) {:root:root ._bg-0hover-hover:hover{background-color:var(--hover) !important;}}
|
|
3202
3078
|
@media (hover) {:root:root ._bg-0hover-panel:hover{background-color:var(--panel) !important;}}
|
|
3079
|
+
@media (hover) {:root:root ._bg-0hover-primary:hover{background-color:var(--primary) !important;}}
|
|
3203
3080
|
@media (hover) {:root:root ._bg-0hover-raised:hover{background-color:var(--raised) !important;}}
|
|
3204
3081
|
@media (hover) {:root:root ._bg-0hover-rim:hover{background-color:var(--rim) !important;}}
|
|
3205
3082
|
@media (hover) {:root:root ._bg-0hover-transparent:hover{background-color:transparent !important;}}
|
|
@@ -3210,6 +3087,7 @@ a svg,
|
|
|
3210
3087
|
:root ._bg-borderColor{background-color:var(--borderColor);}
|
|
3211
3088
|
:root ._bg-color12{background-color:var(--color12);}
|
|
3212
3089
|
:root ._bg-color3{background-color:var(--color3);}
|
|
3090
|
+
:root ._bg-color3rgba11269896602{background-color:var(--color3, rgba(128, 128, 128, 0.14));}
|
|
3213
3091
|
:root ._bg-color5{background-color:var(--color5);}
|
|
3214
3092
|
:root ._bg-edge{background-color:var(--edge);}
|
|
3215
3093
|
:root ._bg-faint{background-color:var(--faint);}
|
|
@@ -3218,6 +3096,7 @@ a svg,
|
|
|
3218
3096
|
:root ._bg-hover{background-color:var(--hover);}
|
|
3219
3097
|
:root ._bg-ink{background-color:var(--ink);}
|
|
3220
3098
|
:root ._bg-panel{background-color:var(--panel);}
|
|
3099
|
+
:root ._bg-primary{background-color:var(--primary);}
|
|
3221
3100
|
:root ._bg-quiet{background-color:var(--quiet);}
|
|
3222
3101
|
:root ._bg-raised{background-color:var(--raised);}
|
|
3223
3102
|
:root ._bg-red9{background-color:var(--red9);}
|
|
@@ -3349,6 +3228,7 @@ a svg,
|
|
|
3349
3228
|
:root ._btlr-c-radius-5{border-top-left-radius:var(--c-radius-5);}
|
|
3350
3229
|
:root ._btlr-c-radius-6{border-top-left-radius:var(--c-radius-6);}
|
|
3351
3230
|
:root ._btlr-c-radius-tr3728{border-top-left-radius:var(--c-radius-true);}
|
|
3231
|
+
:root ._btlr-radius-full604151108{border-top-left-radius:var(--radius-full, 9999px);}
|
|
3352
3232
|
:root ._btlr-radius-lg0--71290927033{border-top-left-radius:var(--radius-lg, 0.75rem);}
|
|
3353
3233
|
:root ._btrr-0px{border-top-right-radius:0px;}
|
|
3354
3234
|
:root ._btrr-100000px{border-top-right-radius:100000px;}
|
|
@@ -3367,6 +3247,7 @@ a svg,
|
|
|
3367
3247
|
:root ._btrr-c-radius-5{border-top-right-radius:var(--c-radius-5);}
|
|
3368
3248
|
:root ._btrr-c-radius-6{border-top-right-radius:var(--c-radius-6);}
|
|
3369
3249
|
:root ._btrr-c-radius-tr3728{border-top-right-radius:var(--c-radius-true);}
|
|
3250
|
+
:root ._btrr-radius-full604151108{border-top-right-radius:var(--radius-full, 9999px);}
|
|
3370
3251
|
:root ._btrr-radius-lg0--71290927033{border-top-right-radius:var(--radius-lg, 0.75rem);}
|
|
3371
3252
|
:root ._bts-solid._bts-solid{border-top-style:solid;}
|
|
3372
3253
|
:root ._btw-0px._btw-0px{border-top-width:0px;}
|
|
@@ -3405,6 +3286,7 @@ a svg,
|
|
|
3405
3286
|
@media (min-width: 768px){:root:root:root:root:root:root:root:root:root:root:root:root:root:root:root:root:root:root ._dsp-_md_none{display:none;}}
|
|
3406
3287
|
:root ._dsp-block{display:block;}
|
|
3407
3288
|
:root ._dsp-flex{display:flex;}
|
|
3289
|
+
:root ._dsp-grid{display:grid;}
|
|
3408
3290
|
:root ._dsp-inline-flex{display:inline-flex;}
|
|
3409
3291
|
:root ._dsp-none{display:none;}
|
|
3410
3292
|
:root ._fb-0px{flex-basis:0px;}
|
|
@@ -3439,6 +3321,7 @@ a svg,
|
|
|
3439
3321
|
:root ._fwr-nowrap{flex-wrap:nowrap;}
|
|
3440
3322
|
:root ._fwr-wrap{flex-wrap:wrap;}
|
|
3441
3323
|
:root ._gap-0px{gap:0px;}
|
|
3324
|
+
:root ._gap-12px{gap:12px;}
|
|
3442
3325
|
:root ._gap-16px{gap:16px;}
|
|
3443
3326
|
:root ._gap-1px{gap:1px;}
|
|
3444
3327
|
:root ._gap-24px{gap:24px;}
|
|
@@ -3458,6 +3341,19 @@ a svg,
|
|
|
3458
3341
|
:root ._gap-c-space-6{gap:var(--c-space-6);}
|
|
3459
3342
|
:root ._gap-calc6pxvar-1380234971{gap:calc(6px * var(--radius-scale, 1));}
|
|
3460
3343
|
:root ._gap-calc8pxvar-1380234971{gap:calc(8px * var(--radius-scale, 1));}
|
|
3344
|
+
:root ._gap-space-312px1396{gap:var(--space-3, 12px);}
|
|
3345
|
+
:root ._gridColumn-1-132241{grid-column:1 / -1;}
|
|
3346
|
+
:root ._gridColumn-span232{grid-column:span 2;}
|
|
3347
|
+
:root ._gridRow-2432241{grid-row:2 / 4;}
|
|
3348
|
+
:root ._gridRow-span232{grid-row:span 2;}
|
|
3349
|
+
:root ._gridTemplateColumns-2fr1fr32{grid-template-columns:2fr 1fr;}
|
|
3350
|
+
:root ._gridTemplateColumns-repeat31fr1234957{grid-template-columns:repeat(3, 1fr);}
|
|
3351
|
+
:root ._gridTemplateColumns-repeat3minm577740846{grid-template-columns:repeat(3, minmax(0, 1fr));}
|
|
3352
|
+
:root ._gridTemplateColumns-repeatauto-1305671373{grid-template-columns:repeat(auto-fill, minmax(min(280px, 100%), 1fr));}
|
|
3353
|
+
:root ._gridTemplateColumns-repeatauto-827335640{grid-template-columns:repeat(auto-fill, minmax(max(min(160px, 100%), calc((100% - 3 * var(--space-3, 12px)) / 4)), 1fr));}
|
|
3354
|
+
:root ._gridTemplateColumns-repeatauto-924020196{grid-template-columns:repeat(auto-fill, minmax(min(900px, 100%), 1fr));}
|
|
3355
|
+
:root ._gridTemplateColumns-repeatauto-998993489{grid-template-columns:repeat(auto-fill, minmax(min(240px, 100%), 1fr));}
|
|
3356
|
+
:root ._gridTemplateRows-repeat2minm577740846{grid-template-rows:repeat(2, minmax(0, 1fr));}
|
|
3461
3357
|
:root ._grow-0{flex-grow:0;}
|
|
3462
3358
|
:root ._grow-1{flex-grow:1;}
|
|
3463
3359
|
:root ._grow-50{flex-grow:50;}
|
|
@@ -3607,6 +3503,7 @@ a svg,
|
|
|
3607
3503
|
:root ._o-0--6{opacity:0.6;}
|
|
3608
3504
|
:root ._o-0--7{opacity:0.7;}
|
|
3609
3505
|
:root ._o-0--8{opacity:0.8;}
|
|
3506
|
+
:root:root:root ._o-0active-0--85:active{opacity:0.85 !important;}
|
|
3610
3507
|
@media (hover) {:root:root ._o-0hover-0--8:hover{opacity:0.8 !important;}}
|
|
3611
3508
|
@media (hover) {:root:root ._o-0hover-0--9:hover{opacity:0.9 !important;}}
|
|
3612
3509
|
@media (hover) {:root:root ._o-0hover-0--92:hover{opacity:0.92 !important;}}
|