@hanzo/ui 8.27.44 → 8.27.45
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/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/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 +481 -598
- package/dist/glass.cjs +2 -24
- package/dist/glass.css +0 -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 +478 -595
- package/dist/sx.cjs +1 -1
- package/dist/sx.js +1 -1
- package/dist/theme.css +369 -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/theme.css
CHANGED
|
@@ -1330,13 +1330,8 @@
|
|
|
1330
1330
|
src/glass.css and are inlined here by scripts/compose-theme.mjs — one home,
|
|
1331
1331
|
two entry points (`@hanzo/ui/theme.css` and `@hanzo/ui/glass.css`), so a host
|
|
1332
1332
|
that wants only the chrome material does not have to take the token layer
|
|
1333
|
-
with it.
|
|
1334
|
-
|
|
1335
|
-
They used to be four `.elevation-*` rules reading `var(--hz-elevation-N, …)`.
|
|
1336
|
-
Nothing in this repo, in @hanzo/design or in any consumer ever DEFINED an
|
|
1337
|
-
`--hz-elevation-*` variable, so every one of those resolved to its fallback:
|
|
1338
|
-
an indirection through a name that does not exist, with a hardcoded shadow
|
|
1339
|
-
behind it, next to a design system that publishes real ones. */
|
|
1333
|
+
with it. The ladder reads @hanzo/design's own shadows, never a private
|
|
1334
|
+
variable nothing defines. */
|
|
1340
1335
|
|
|
1341
1336
|
/* ── Prose ───────────────────────────────────────────────────────────────────
|
|
1342
1337
|
What `<ApplyTypography>` turns on: running text — a heading, a byline, a
|
|
@@ -1350,12 +1345,13 @@
|
|
|
1350
1345
|
@hanzo/design ramp, which is where every other surface already reads them —
|
|
1351
1346
|
so prose and a Button now round to the same scale instead of two.
|
|
1352
1347
|
|
|
1353
|
-
Scoped under
|
|
1354
|
-
component keeps its own type.
|
|
1355
|
-
.
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
display:
|
|
1348
|
+
Scoped under `[data-slot='prose']` and applied with `>` only one level down,
|
|
1349
|
+
so a nested component keeps its own type. The content arrives as bare tags
|
|
1350
|
+
(a CMS field, an .mdx file), which is the one case a prop cannot reach: the
|
|
1351
|
+
rules have to select by tag from the container. */
|
|
1352
|
+
[data-slot='prose'] {
|
|
1353
|
+
display: flex;
|
|
1354
|
+
flex-direction: column;
|
|
1359
1355
|
gap: var(--space-3, 0.75rem);
|
|
1360
1356
|
color: var(--foreground);
|
|
1361
1357
|
font-family: var(--font-sans), sans-serif;
|
|
@@ -1363,8 +1359,8 @@
|
|
|
1363
1359
|
line-height: var(--leading-base, var(--leading-normal));
|
|
1364
1360
|
}
|
|
1365
1361
|
|
|
1366
|
-
|
|
1367
|
-
|
|
1362
|
+
[data-slot='prose'] > h1, [data-slot='prose'] > h2, [data-slot='prose'] > h3,
|
|
1363
|
+
[data-slot='prose'] > h4, [data-slot='prose'] > h5, [data-slot='prose'] > h6 {
|
|
1368
1364
|
font-family: var(--font-display, var(--font-sans)), sans-serif;
|
|
1369
1365
|
font-weight: 606;
|
|
1370
1366
|
line-height: var(--leading-tight);
|
|
@@ -1372,37 +1368,37 @@
|
|
|
1372
1368
|
margin: 0;
|
|
1373
1369
|
}
|
|
1374
1370
|
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1371
|
+
[data-slot='prose'] > h1 { font-size: var(--text-4xl) }
|
|
1372
|
+
[data-slot='prose'] > h2 { font-size: var(--text-3xl) }
|
|
1373
|
+
[data-slot='prose'] > h3 { font-size: var(--text-2xl) }
|
|
1374
|
+
[data-slot='prose'] > h4 { font-size: var(--text-xl) }
|
|
1375
|
+
[data-slot='prose'] > h5 { font-size: var(--text-lg) }
|
|
1380
1376
|
/* h6 is the byline rung: heading TAG, body weight and colour, because that is
|
|
1381
1377
|
what a byline is — subordinate text that happens to sit in the heading
|
|
1382
1378
|
stack. */
|
|
1383
|
-
|
|
1379
|
+
[data-slot='prose'] > h6 {
|
|
1384
1380
|
font-size: var(--text-base);
|
|
1385
1381
|
font-weight: 497;
|
|
1386
1382
|
color: var(--muted-foreground);
|
|
1387
1383
|
}
|
|
1388
1384
|
|
|
1389
|
-
|
|
1385
|
+
[data-slot='prose'] > p { margin: 0 }
|
|
1390
1386
|
/* The marker is RESTORED here. `base.css` takes it off every list in the
|
|
1391
1387
|
document, because a nav and a card grid are both lists and neither wants one.
|
|
1392
1388
|
Authored prose is the one place it belongs. Setting only the indent leaves an
|
|
1393
1389
|
indented list with nothing at the start of the line. */
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1390
|
+
[data-slot='prose'] > ul, [data-slot='prose'] ul ul { list-style: disc }
|
|
1391
|
+
[data-slot='prose'] > ol, [data-slot='prose'] ol ol { list-style: decimal }
|
|
1392
|
+
[data-slot='prose'] ul, [data-slot='prose'] ol { margin: 0; padding-inline-start: 1.5em }
|
|
1393
|
+
[data-slot='prose'] li { margin-block: 0.25em }
|
|
1394
|
+
[data-slot='prose'] li::marker { color: var(--muted-foreground) }
|
|
1399
1395
|
|
|
1400
1396
|
/* A code block is a SURFACE, not just a change of typeface. Without the panel
|
|
1401
1397
|
it sits directly on the page ground and reads as body text that happens to be
|
|
1402
1398
|
monospaced — which is exactly what a reader scanning for the command must not
|
|
1403
1399
|
have to work out. `pre` already scrolls inside itself (base.css); this gives
|
|
1404
1400
|
it the ground to scroll on. */
|
|
1405
|
-
|
|
1401
|
+
[data-slot='prose'] > pre {
|
|
1406
1402
|
margin: 0;
|
|
1407
1403
|
padding: var(--space-4, 1rem);
|
|
1408
1404
|
border: 1px solid var(--border);
|
|
@@ -1413,97 +1409,61 @@
|
|
|
1413
1409
|
}
|
|
1414
1410
|
/* Inside a block the panel IS the surface, so the inline treatment would draw a
|
|
1415
1411
|
second one around every line. */
|
|
1416
|
-
|
|
1417
|
-
|
|
1412
|
+
[data-slot='prose'] > pre code { background: none; padding: 0; border: 0; font-size: inherit }
|
|
1413
|
+
[data-slot='prose'] :not(pre) > code {
|
|
1418
1414
|
padding: 0.15em 0.35em;
|
|
1419
1415
|
border-radius: calc(var(--radius, 0.5rem) / 2);
|
|
1420
1416
|
background: var(--muted);
|
|
1421
1417
|
}
|
|
1422
|
-
|
|
1418
|
+
[data-slot='prose'] > blockquote {
|
|
1423
1419
|
margin: 0;
|
|
1424
1420
|
padding-inline-start: 1em;
|
|
1425
1421
|
border-inline-start: 2px solid var(--border);
|
|
1426
1422
|
color: var(--muted-foreground);
|
|
1427
1423
|
}
|
|
1428
|
-
|
|
1424
|
+
[data-slot='prose'] code {
|
|
1429
1425
|
font-family: var(--font-mono), ui-monospace, monospace;
|
|
1430
1426
|
font-size: 0.9em;
|
|
1431
1427
|
}
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1428
|
+
[data-slot='prose'] a { color: inherit; text-decoration: underline }
|
|
1429
|
+
[data-slot='prose'] strong { font-weight: 606 }
|
|
1430
|
+
[data-slot='prose'] :where(img, video) { max-width: 100%; height: auto }
|
|
1435
1431
|
|
|
1436
1432
|
/* The named rungs. `responsive` is the default and is the only one that moves
|
|
1437
1433
|
with the viewport — a t-shirt size is a DECISION, so it stays put. */
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1434
|
+
[data-slot='prose'][data-size='sm'] { font-size: var(--text-sm); gap: var(--space-3, 0.75rem) }
|
|
1435
|
+
[data-slot='prose'][data-size='sm'] > h1 { font-size: var(--text-3xl) }
|
|
1436
|
+
[data-slot='prose'][data-size='sm'] > h2 { font-size: var(--text-2xl) }
|
|
1437
|
+
[data-slot='prose'][data-size='sm'] > h3 { font-size: var(--text-xl) }
|
|
1438
|
+
[data-slot='prose'][data-size='sm'] > p { font-size: var(--text-sm) }
|
|
1439
|
+
|
|
1440
|
+
[data-slot='prose'][data-size='lg'] { font-size: var(--text-lg); gap: var(--space-5, 1.25rem) }
|
|
1441
|
+
[data-slot='prose'][data-size='lg'] > h1 { font-size: var(--text-5xl) }
|
|
1442
|
+
[data-slot='prose'][data-size='lg'] > h2 { font-size: var(--text-4xl) }
|
|
1443
|
+
[data-slot='prose'][data-size='lg'] > h3 { font-size: var(--text-3xl) }
|
|
1444
|
+
[data-slot='prose'][data-size='lg'] > p { font-size: var(--text-lg) }
|
|
1445
|
+
|
|
1446
|
+
[data-slot='prose'][data-size='xl'] { font-size: var(--text-lg); gap: var(--space-6, 1.5rem) }
|
|
1447
|
+
[data-slot='prose'][data-size='xl'] > h1 { font-size: var(--text-6xl) }
|
|
1448
|
+
[data-slot='prose'][data-size='xl'] > h2 { font-size: var(--text-5xl) }
|
|
1449
|
+
[data-slot='prose'][data-size='xl'] > h3 { font-size: var(--text-4xl) }
|
|
1450
|
+
[data-slot='prose'][data-size='xl'] > p { font-size: var(--text-lg) }
|
|
1455
1451
|
|
|
1456
1452
|
/* Responsive: start at the small rung and climb. Written as min-width so the
|
|
1457
1453
|
phone case is the unprefixed one and needs no query at all. */
|
|
1458
1454
|
@media (min-width: 640px) {
|
|
1459
|
-
|
|
1455
|
+
[data-slot='prose'][data-size='responsive'] { gap: var(--space-4, 1rem) }
|
|
1460
1456
|
}
|
|
1461
1457
|
@media (min-width: 1024px) {
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1458
|
+
[data-slot='prose'][data-size='responsive'] { font-size: var(--text-lg); gap: var(--space-5, 1.25rem) }
|
|
1459
|
+
[data-slot='prose'][data-size='responsive'] > h1 { font-size: var(--text-5xl) }
|
|
1460
|
+
[data-slot='prose'][data-size='responsive'] > h2 { font-size: var(--text-4xl) }
|
|
1461
|
+
[data-slot='prose'][data-size='responsive'] > h3 { font-size: var(--text-3xl) }
|
|
1466
1462
|
}
|
|
1467
1463
|
@media (min-width: 1280px) {
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
}
|
|
1472
|
-
|
|
1473
|
-
/* The two things a style PROP cannot say, because neither is a property of an
|
|
1474
|
-
element: a keyframe, and a scrollbar. */
|
|
1475
|
-
|
|
1476
|
-
/* Skeleton's pulse. Opacity only — animating a colour or a size would repaint
|
|
1477
|
-
or reflow every frame for a placeholder nobody is looking at. */
|
|
1478
|
-
@keyframes hz-pulse {
|
|
1479
|
-
50% { opacity: 0.5 }
|
|
1480
|
-
}
|
|
1481
|
-
.hz-pulse { animation: hz-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite }
|
|
1482
|
-
|
|
1483
|
-
/* A carousel scrolls but must not show a bar: the arrows and the snap already
|
|
1484
|
-
say it scrolls, and a bar that appears mid-drag shifts the slides under the
|
|
1485
|
-
pointer. Firefox reads the property, WebKit the pseudo-element, and the
|
|
1486
|
-
property rides on the component so only this half needs a sheet. */
|
|
1487
|
-
.hz-scroller::-webkit-scrollbar { display: none }
|
|
1488
|
-
|
|
1489
|
-
/* The drawn caret in a one-time-code box. The real one is hidden, because it
|
|
1490
|
-
would sit at the left edge of an invisible full-width field rather than in
|
|
1491
|
-
the box the next keystroke lands in. */
|
|
1492
|
-
@keyframes hz-caret {
|
|
1493
|
-
0%, 49% { opacity: 1 }
|
|
1494
|
-
50%, 100% { opacity: 0 }
|
|
1495
|
-
}
|
|
1496
|
-
.hz-caret {
|
|
1497
|
-
background: var(--foreground);
|
|
1498
|
-
animation: hz-caret 1s steps(1) infinite;
|
|
1499
|
-
}
|
|
1500
|
-
|
|
1501
|
-
/* Motion is a preference, and all of the above is decoration. A caret that does
|
|
1502
|
-
not blink is still a caret; one that does can trigger a migraine. */
|
|
1503
|
-
@media (prefers-reduced-motion: reduce) {
|
|
1504
|
-
.hz-pulse { animation: none }
|
|
1505
|
-
.hz-caret { animation: none }
|
|
1506
|
-
.hz-scroller { scroll-behavior: auto }
|
|
1464
|
+
[data-slot='prose'][data-size='responsive'] { gap: var(--space-6, 1.5rem) }
|
|
1465
|
+
[data-slot='prose'][data-size='responsive'] > h1 { font-size: var(--text-6xl) }
|
|
1466
|
+
[data-slot='prose'][data-size='responsive'] > h2 { font-size: var(--text-5xl) }
|
|
1507
1467
|
}
|
|
1508
1468
|
|
|
1509
1469
|
/* Glass — the material floating chrome is made of, and the ladder it stands on.
|
|
@@ -1752,73 +1712,6 @@
|
|
|
1752
1712
|
border-bottom-right-radius: 0 !important;
|
|
1753
1713
|
}
|
|
1754
1714
|
|
|
1755
|
-
/* ── The crease — the valley where one sheet lies over another ───────────────
|
|
1756
|
-
The ladder lifts a sheet with a drop that falls STRAIGHT DOWN: design's rule
|
|
1757
|
-
is one light, above, and `check-tokens.mjs` fails the build on a sideways
|
|
1758
|
-
offset. That is right, and it means the ladder has nothing to say about a
|
|
1759
|
-
VERTICAL seam — and an app shell is nothing but vertical seams. A rail beside
|
|
1760
|
-
a sidebar beside a pane, each a step apart on the ladder, still reads as three
|
|
1761
|
-
abutting rectangles with lines ruled between them, because the only mark at
|
|
1762
|
-
the seam is the hairline.
|
|
1763
|
-
|
|
1764
|
-
What a real sheet lays on the one beneath it, side by side under a light from
|
|
1765
|
-
above, is not a cast shadow — it is the valley going dark. Ambient occlusion
|
|
1766
|
-
has no direction of its own, which is both why it is honest here and why it is
|
|
1767
|
-
NOT spelled as a --shadow-*: those are directional by definition and this is
|
|
1768
|
-
not one.
|
|
1769
|
-
|
|
1770
|
-
A PSEUDO-ELEMENT, at z-index -1 inside an isolated stacking context, so it
|
|
1771
|
-
paints above the sheet's own fill and below every child. That ordering is the
|
|
1772
|
-
whole reason it is not a `background-image` (which `.fold` already claims on
|
|
1773
|
-
this same element, !important, so the two would silently fight) and not an
|
|
1774
|
-
inset `box-shadow` (which `.elevation-*` claims, likewise).
|
|
1775
|
-
|
|
1776
|
-
No side named -> both edges, which is what a pane with a neighbour on each
|
|
1777
|
-
hand needs. Name one and the other stops being drawn. */
|
|
1778
|
-
:root {
|
|
1779
|
-
--crease-ink: rgb(0 0 0 / .28);
|
|
1780
|
-
--crease-depth: 20px;
|
|
1781
|
-
}
|
|
1782
|
-
|
|
1783
|
-
.light, :root.t_light, .t_light {
|
|
1784
|
-
/* On white the valley is a smudge, not a shadow — the same redistribution the
|
|
1785
|
-
drops make, and for the same reason. */
|
|
1786
|
-
--crease-ink: rgb(0 0 0 / .05);
|
|
1787
|
-
}
|
|
1788
|
-
|
|
1789
|
-
.hz-crease {
|
|
1790
|
-
position: relative;
|
|
1791
|
-
/* Without this the -1 escapes and paints behind an ancestor's fill, which is
|
|
1792
|
-
indistinguishable from the crease not being there at all. */
|
|
1793
|
-
isolation: isolate;
|
|
1794
|
-
}
|
|
1795
|
-
|
|
1796
|
-
.hz-crease::before,
|
|
1797
|
-
.hz-crease::after {
|
|
1798
|
-
content: "";
|
|
1799
|
-
position: absolute;
|
|
1800
|
-
top: 0;
|
|
1801
|
-
bottom: 0;
|
|
1802
|
-
width: var(--crease-depth);
|
|
1803
|
-
z-index: -1;
|
|
1804
|
-
pointer-events: none;
|
|
1805
|
-
}
|
|
1806
|
-
|
|
1807
|
-
.hz-crease::before {
|
|
1808
|
-
left: 0;
|
|
1809
|
-
background-image: linear-gradient(to right, var(--crease-ink), transparent);
|
|
1810
|
-
}
|
|
1811
|
-
|
|
1812
|
-
.hz-crease::after {
|
|
1813
|
-
right: 0;
|
|
1814
|
-
background-image: linear-gradient(to left, var(--crease-ink), transparent);
|
|
1815
|
-
}
|
|
1816
|
-
|
|
1817
|
-
.hz-crease[data-crease="left"]::after,
|
|
1818
|
-
.hz-crease[data-crease="right"]::before {
|
|
1819
|
-
content: none;
|
|
1820
|
-
}
|
|
1821
|
-
|
|
1822
1715
|
/* ── The scrim ──────────────────────────────────────────────────────────────
|
|
1823
1716
|
The dim that makes a floating panel read as floating rather than as more
|
|
1824
1717
|
page. gui's overlay dims TWICE — a translucent ground under a further
|
|
@@ -1866,135 +1759,6 @@
|
|
|
1866
1759
|
border-top: 1px solid var(--borderColor, var(--border));
|
|
1867
1760
|
}
|
|
1868
1761
|
|
|
1869
|
-
/* ── The composer prism — the ONE ring on any Hanzo surface ──────────────────
|
|
1870
|
-
The composer is where you talk to Hanzo, so it is the thing that should look
|
|
1871
|
-
alive, and it earns that with MOTION and LIGHT rather than hue. Every other
|
|
1872
|
-
pixel of chrome stays monochrome; there is no second exemption, and the two
|
|
1873
|
-
attempts to grant one (a violet ring, then a full-wheel rainbow) each made
|
|
1874
|
-
the surface wearing it the only colour in the product.
|
|
1875
|
-
|
|
1876
|
-
THIS LIVES HERE BECAUSE IT WAS DECLARED TWICE AND DRIFTED. hanzo.chat's
|
|
1877
|
-
client/src/style.css and hanzo.app's assets/globals.css each carried a copy,
|
|
1878
|
-
each calling itself "the ONE prism on any Hanzo surface". chat fixed the ring
|
|
1879
|
-
to be a rim; hanzo.app's copy kept drawing a filled DISC and never got the
|
|
1880
|
-
fix — invisible until a glass panel sat in it, at which point the whole
|
|
1881
|
-
spectrum washed up through the composer's interior. chat also quieted the
|
|
1882
|
-
halo (0.5 with a pulse -> 0.22, no pulse); hanzo.app kept the loud one. Two
|
|
1883
|
-
copies of one look is how that happens, and neither app could see the other
|
|
1884
|
-
was wrong.
|
|
1885
|
-
|
|
1886
|
-
Structure: `.hz-composer` is a 1.5px-padded host; its direct child is the
|
|
1887
|
-
panel. ::before is the ring, ::after the halo. Both are MASKED to exclude the
|
|
1888
|
-
panel's footprint, so the ring is a rim BY CONSTRUCTION and the panel is free
|
|
1889
|
-
to be any material — opaque, glass, anything. The stops are declared once and
|
|
1890
|
-
read by both, because duplicated they drift on the first palette change and
|
|
1891
|
-
nobody notices which half moved. */
|
|
1892
|
-
|
|
1893
|
-
/* `@property` is what lets a conic angle animate. Where it is unsupported the
|
|
1894
|
-
ring is simply static, which is a fine floor. */
|
|
1895
|
-
@property --hz-angle {
|
|
1896
|
-
syntax: "<angle>";
|
|
1897
|
-
initial-value: 0deg;
|
|
1898
|
-
inherits: false;
|
|
1899
|
-
}
|
|
1900
|
-
|
|
1901
|
-
:root {
|
|
1902
|
-
/* One sweep, closing on the stop it opened with — a conic gradient whose
|
|
1903
|
-
first and last stop differ shows a hard seam.
|
|
1904
|
-
|
|
1905
|
-
LUMINANCE, NOT HUE. Four saturated stops at 0.40-0.48 alpha, swept around
|
|
1906
|
-
a rounded RECTANGLE, do not distribute evenly: the long top and bottom
|
|
1907
|
-
edges each take a wide angular slice and the short sides almost none, so
|
|
1908
|
-
one edge wore a bright blue while the opposite wore a burnt orange — a
|
|
1909
|
-
ring that highlights half the box and reads as sitting off-centre. White
|
|
1910
|
-
at two close alphas removes the bright arc entirely, drops the peak from
|
|
1911
|
-
0.48 to 0.18, and keeps the slow drift as a sheen. hanzo.chat and
|
|
1912
|
-
hanzo.app both declare exactly these stops; this is the package catching
|
|
1913
|
-
up to its consumers — the copies must not drift again, and this file is
|
|
1914
|
-
the home. */
|
|
1915
|
-
--hz-spectrum: rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.18),
|
|
1916
|
-
rgba(255, 255, 255, 0.1), rgba(255, 255, 255, 0.18),
|
|
1917
|
-
rgba(255, 255, 255, 0.1);
|
|
1918
|
-
}
|
|
1919
|
-
|
|
1920
|
-
@keyframes hzComposerSpin {
|
|
1921
|
-
to {
|
|
1922
|
-
--hz-angle: 360deg;
|
|
1923
|
-
}
|
|
1924
|
-
}
|
|
1925
|
-
|
|
1926
|
-
.hz-composer {
|
|
1927
|
-
position: relative;
|
|
1928
|
-
isolation: isolate;
|
|
1929
|
-
padding: 1.5px;
|
|
1930
|
-
}
|
|
1931
|
-
|
|
1932
|
-
/* The ring DRAWS A RING. `padding` is its thickness; the two-layer mask keeps
|
|
1933
|
-
paint outside it — `content-box` is the hole, the full box the plate, and
|
|
1934
|
-
`exclude` leaves the lip. */
|
|
1935
|
-
.hz-composer::before {
|
|
1936
|
-
content: "";
|
|
1937
|
-
position: absolute;
|
|
1938
|
-
inset: 0;
|
|
1939
|
-
padding: 1.5px;
|
|
1940
|
-
border-radius: inherit;
|
|
1941
|
-
background: conic-gradient(from var(--hz-angle), var(--hz-spectrum));
|
|
1942
|
-
animation: hzComposerSpin 10s linear infinite;
|
|
1943
|
-
-webkit-mask:
|
|
1944
|
-
linear-gradient(#000 0 0) content-box,
|
|
1945
|
-
linear-gradient(#000 0 0);
|
|
1946
|
-
mask:
|
|
1947
|
-
linear-gradient(#000 0 0) content-box,
|
|
1948
|
-
linear-gradient(#000 0 0);
|
|
1949
|
-
mask-composite: exclude;
|
|
1950
|
-
/* After the standard shorthand: WebKit aliases `mask` onto `-webkit-mask`, so
|
|
1951
|
-
declaring this first lets the shorthand reset it to `source-over` — the
|
|
1952
|
-
filled disc again, on exactly the browsers too old to have `mask-composite`
|
|
1953
|
-
at all. */
|
|
1954
|
-
-webkit-mask-composite: xor;
|
|
1955
|
-
z-index: 0;
|
|
1956
|
-
pointer-events: none;
|
|
1957
|
-
}
|
|
1958
|
-
|
|
1959
|
-
/* The halo lights the air AROUND the box and nothing behind it. */
|
|
1960
|
-
.hz-composer::after {
|
|
1961
|
-
content: "";
|
|
1962
|
-
position: absolute;
|
|
1963
|
-
inset: -6px;
|
|
1964
|
-
padding: 6px;
|
|
1965
|
-
/* Concentric with the box, NOT `inherit`: the halo lives 6px outside, so an
|
|
1966
|
-
inherited corner on this larger box curves too tight and reads as a second,
|
|
1967
|
-
mismatched rounding just outside the panel. */
|
|
1968
|
-
border-radius: calc(1.5rem + 6px);
|
|
1969
|
-
background: conic-gradient(from var(--hz-angle), var(--hz-spectrum));
|
|
1970
|
-
filter: blur(16px);
|
|
1971
|
-
opacity: 0.22;
|
|
1972
|
-
animation: hzComposerSpin 10s linear infinite;
|
|
1973
|
-
-webkit-mask:
|
|
1974
|
-
linear-gradient(#000 0 0) content-box,
|
|
1975
|
-
linear-gradient(#000 0 0);
|
|
1976
|
-
mask:
|
|
1977
|
-
linear-gradient(#000 0 0) content-box,
|
|
1978
|
-
linear-gradient(#000 0 0);
|
|
1979
|
-
mask-composite: exclude;
|
|
1980
|
-
-webkit-mask-composite: xor;
|
|
1981
|
-
z-index: -1;
|
|
1982
|
-
pointer-events: none;
|
|
1983
|
-
}
|
|
1984
|
-
|
|
1985
|
-
/* The panel sits above ring and halo. */
|
|
1986
|
-
.hz-composer > * {
|
|
1987
|
-
position: relative;
|
|
1988
|
-
z-index: 1;
|
|
1989
|
-
}
|
|
1990
|
-
|
|
1991
|
-
@media (prefers-reduced-motion: reduce) {
|
|
1992
|
-
.hz-composer::before,
|
|
1993
|
-
.hz-composer::after {
|
|
1994
|
-
animation: none;
|
|
1995
|
-
}
|
|
1996
|
-
}
|
|
1997
|
-
|
|
1998
1762
|
/* FOCUS RINGS THE CONTROL A PERSON SEES, WHICH IS THE WHOLE COMPOSER.
|
|
1999
1763
|
|
|
2000
1764
|
`Composer` is a bordered box holding a field above a toolbar row, so it reads
|
|
@@ -2025,3 +1789,316 @@
|
|
|
2025
1789
|
[data-slot='composer-field'] {
|
|
2026
1790
|
--outlineColor: transparent;
|
|
2027
1791
|
}
|
|
1792
|
+
|
|
1793
|
+
/* @hanzo/ui motion — the calm, restrained animation vocabulary the Hanzo
|
|
1794
|
+
surfaces share. One place defines the easing; components carry the name.
|
|
1795
|
+
|
|
1796
|
+
Import once at the app root: import '@hanzo/ui/styles/motion.css'
|
|
1797
|
+
|
|
1798
|
+
── KEYED ON `data-motion`, NEVER ON A CLASS ─────────────────────────────────
|
|
1799
|
+
A component says what it does with one attribute — `data-motion="rise"` — and
|
|
1800
|
+
this sheet says how. The paint (a caret's ink, a skeleton's gradient) is the
|
|
1801
|
+
component's own gui props; what is left here is what no prop can say: a
|
|
1802
|
+
keyframe, a transition a preference can switch off, and the preference
|
|
1803
|
+
itself. Every animation is off under `prefers-reduced-motion: reduce`.
|
|
1804
|
+
|
|
1805
|
+
rise enter: fade up 10px over 400ms FadeIn, Timeline, tooltips
|
|
1806
|
+
fade opacity eases 240ms SlideOver's scrim
|
|
1807
|
+
slide transform eases 260ms SlideOver's panel
|
|
1808
|
+
drag a row eases into place while one is held Reorder
|
|
1809
|
+
pulse opacity dims and returns, 2s Pulse, StatusDot, Skeleton
|
|
1810
|
+
blink on/off, 1s Caret
|
|
1811
|
+
shimmer a highlight sweeps a placeholder product Skeleton
|
|
1812
|
+
unfold a sheet turns open about its hinge unfold() */
|
|
1813
|
+
|
|
1814
|
+
@keyframes rise {
|
|
1815
|
+
from {
|
|
1816
|
+
opacity: 0;
|
|
1817
|
+
transform: translateY(10px);
|
|
1818
|
+
}
|
|
1819
|
+
to {
|
|
1820
|
+
opacity: 1;
|
|
1821
|
+
transform: translateY(0);
|
|
1822
|
+
}
|
|
1823
|
+
}
|
|
1824
|
+
|
|
1825
|
+
[data-motion='rise'] {
|
|
1826
|
+
animation: rise 0.4s cubic-bezier(0.16, 1, 0.3, 1) both;
|
|
1827
|
+
will-change: transform, opacity;
|
|
1828
|
+
}
|
|
1829
|
+
|
|
1830
|
+
[data-motion='fade'] {
|
|
1831
|
+
transition: opacity 240ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
1832
|
+
will-change: opacity;
|
|
1833
|
+
}
|
|
1834
|
+
|
|
1835
|
+
[data-motion='slide'] {
|
|
1836
|
+
transition: transform 260ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
1837
|
+
will-change: transform;
|
|
1838
|
+
}
|
|
1839
|
+
|
|
1840
|
+
[data-motion='drag'] {
|
|
1841
|
+
touch-action: none;
|
|
1842
|
+
transition: transform 180ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
1843
|
+
}
|
|
1844
|
+
|
|
1845
|
+
@keyframes dim {
|
|
1846
|
+
50% {
|
|
1847
|
+
opacity: 0.5;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
|
|
1851
|
+
[data-motion='pulse'] {
|
|
1852
|
+
animation: dim 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
|
|
1853
|
+
}
|
|
1854
|
+
|
|
1855
|
+
@keyframes blink {
|
|
1856
|
+
0%,
|
|
1857
|
+
49% {
|
|
1858
|
+
opacity: 1;
|
|
1859
|
+
}
|
|
1860
|
+
50%,
|
|
1861
|
+
100% {
|
|
1862
|
+
opacity: 0;
|
|
1863
|
+
}
|
|
1864
|
+
}
|
|
1865
|
+
|
|
1866
|
+
[data-motion='blink'] {
|
|
1867
|
+
animation: blink 1s steps(1) infinite;
|
|
1868
|
+
}
|
|
1869
|
+
|
|
1870
|
+
@keyframes shimmer {
|
|
1871
|
+
0% {
|
|
1872
|
+
background-position: -160px 0;
|
|
1873
|
+
}
|
|
1874
|
+
100% {
|
|
1875
|
+
background-position: 160px 0;
|
|
1876
|
+
}
|
|
1877
|
+
}
|
|
1878
|
+
|
|
1879
|
+
[data-motion='shimmer'] {
|
|
1880
|
+
animation: shimmer 1.2s ease-in-out infinite;
|
|
1881
|
+
}
|
|
1882
|
+
|
|
1883
|
+
/* Unfold — how a sheet arrives. A panel that appears by fading is a rectangle
|
|
1884
|
+
switching on; a sheet of paper TURNS OPEN about the edge it is hinged on. The
|
|
1885
|
+
hinge is the only knob and the angle follows it, so a turn cannot open the
|
|
1886
|
+
wrong way. `perspective()` inside the transform puts the vanishing point at
|
|
1887
|
+
the sheet's own centre. Seven degrees over 220ms. */
|
|
1888
|
+
@keyframes unfold {
|
|
1889
|
+
from {
|
|
1890
|
+
opacity: 0;
|
|
1891
|
+
transform: perspective(1600px) rotateY(var(--turn, -7deg));
|
|
1892
|
+
}
|
|
1893
|
+
to {
|
|
1894
|
+
opacity: 1;
|
|
1895
|
+
transform: perspective(1600px) rotateY(0deg);
|
|
1896
|
+
}
|
|
1897
|
+
}
|
|
1898
|
+
|
|
1899
|
+
[data-motion='unfold'] {
|
|
1900
|
+
animation: unfold 220ms cubic-bezier(0.2, 0.7, 0.3, 1) both;
|
|
1901
|
+
transform-origin: left center;
|
|
1902
|
+
will-change: transform, opacity;
|
|
1903
|
+
}
|
|
1904
|
+
|
|
1905
|
+
[data-motion='unfold'][data-hinge='right'] {
|
|
1906
|
+
transform-origin: right center;
|
|
1907
|
+
--turn: 7deg;
|
|
1908
|
+
}
|
|
1909
|
+
|
|
1910
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1911
|
+
[data-motion] {
|
|
1912
|
+
animation: none;
|
|
1913
|
+
transition: none;
|
|
1914
|
+
}
|
|
1915
|
+
}
|
|
1916
|
+
|
|
1917
|
+
/* ── Layout guarantee ──────────────────────────────────────────────────────────
|
|
1918
|
+
Structural, so attached to a data attribute: it is the thing the primitive
|
|
1919
|
+
PROMISES, and a class can be lost by forgetting to pass it on. */
|
|
1920
|
+
|
|
1921
|
+
/* Media fills the ratio box instead of setting its own size. Without this an
|
|
1922
|
+
<img> renders at its intrinsic pixel size and either overflows the frame or
|
|
1923
|
+
sits letterboxed inside it, and the ratio the caller asked for is decoration.
|
|
1924
|
+
`display:block` kills the inline-baseline gap under the image. */
|
|
1925
|
+
[data-ratio] > img,
|
|
1926
|
+
[data-ratio] > video {
|
|
1927
|
+
width: 100%;
|
|
1928
|
+
height: 100%;
|
|
1929
|
+
object-fit: cover;
|
|
1930
|
+
display: block;
|
|
1931
|
+
}
|
|
1932
|
+
|
|
1933
|
+
|
|
1934
|
+
/* ─────────────────────────────────────────────────────────────────────────────
|
|
1935
|
+
Scrollbars, on the surfaces this package scrolls.
|
|
1936
|
+
|
|
1937
|
+
Left to the platform this is not neutral: Linux/GTK Chrome draws a wide track
|
|
1938
|
+
with STEPPER ARROWS at both ends, so a dark product grows two grey buttons per
|
|
1939
|
+
scroll region. Windows draws a wide light track. macOS overlays a thin one,
|
|
1940
|
+
which is the behaviour the other two should have had.
|
|
1941
|
+
|
|
1942
|
+
THE TWO HALVES MUST NOT BE DECLARED TOGETHER, and that is the whole subtlety.
|
|
1943
|
+
Chromium supports both the standard properties and the `::-webkit-scrollbar`
|
|
1944
|
+
pseudo-elements — but the moment `scrollbar-width` or `scrollbar-color` is
|
|
1945
|
+
anything other than `auto`, it takes the standard path and DISCARDS the entire
|
|
1946
|
+
webkit block. Shipping both is how 8.1.19 removed nothing: measured headed on
|
|
1947
|
+
Linux, as-shipped gave a 10px gutter with arrows, while the authored webkit
|
|
1948
|
+
rule alone gives 8px with none. Isolated: webkit-only 8px no arrows;
|
|
1949
|
+
standard-only 10px arrows; both together 10px arrows.
|
|
1950
|
+
|
|
1951
|
+
Neither half is redundant, so neither can simply be deleted — Firefox
|
|
1952
|
+
implements ONLY the standard properties, Safari ONLY the webkit ones. They are
|
|
1953
|
+
separated by engine instead: the webkit block applies wherever the selector is
|
|
1954
|
+
understood, and the standard properties apply only where it is not.
|
|
1955
|
+
|
|
1956
|
+
And it is invisible headless. Chromium's headless shell paints OVERLAY
|
|
1957
|
+
scrollbars, so nothing is drawn, `offsetWidth - clientWidth` is 0 on a blank
|
|
1958
|
+
page, and `getComputedStyle(el, '::-webkit-scrollbar-button').display` happily
|
|
1959
|
+
reports `none` for a rule that never ran. This must be checked headed.
|
|
1960
|
+
───────────────────────────────────────────────────────────────────────────── */
|
|
1961
|
+
|
|
1962
|
+
/* Firefox and anything else with no webkit pseudo-elements. */
|
|
1963
|
+
@supports not selector(::-webkit-scrollbar) {
|
|
1964
|
+
:where(
|
|
1965
|
+
[data-slot='fill'],
|
|
1966
|
+
[data-slot='thread'],
|
|
1967
|
+
[data-slot='sources-strip'],
|
|
1968
|
+
[data-slot='sidebar-scroll'],
|
|
1969
|
+
[data-slot='scroll-area-viewport'],
|
|
1970
|
+
[data-slot='textarea'],
|
|
1971
|
+
[data-slot='composer-field']
|
|
1972
|
+
) {
|
|
1973
|
+
scrollbar-width: thin;
|
|
1974
|
+
scrollbar-color: rgb(255 255 255 / 0.18) transparent;
|
|
1975
|
+
}
|
|
1976
|
+
.t_light :where(
|
|
1977
|
+
[data-slot='fill'],
|
|
1978
|
+
[data-slot='thread'],
|
|
1979
|
+
[data-slot='sources-strip'],
|
|
1980
|
+
[data-slot='sidebar-scroll'],
|
|
1981
|
+
[data-slot='scroll-area-viewport'],
|
|
1982
|
+
[data-slot='textarea'],
|
|
1983
|
+
[data-slot='composer-field']
|
|
1984
|
+
) { scrollbar-color: rgb(0 0 0 / 0.20) transparent; }
|
|
1985
|
+
}
|
|
1986
|
+
|
|
1987
|
+
/* Chromium and Safari.
|
|
1988
|
+
The first rule is the load-bearing one and it is a RESET, not a style.
|
|
1989
|
+
@hanzo/design sets `scrollbar-color` and `scrollbar-width` on `:where(html)`
|
|
1990
|
+
(theme.css), and both INHERIT — so every element in the document already
|
|
1991
|
+
carries a non-`auto` value, Chromium takes the standard path, and the whole
|
|
1992
|
+
webkit block below is discarded before it is read. Nothing declared here can
|
|
1993
|
+
win until the inherited value is put back to `auto` on the element itself.
|
|
1994
|
+
That is why the arrows survived 8.1.19: the competing declaration was one
|
|
1995
|
+
level up and inherited, not a rule anyone would find in this file. */
|
|
1996
|
+
@supports selector(::-webkit-scrollbar) {
|
|
1997
|
+
:where(
|
|
1998
|
+
[data-slot='fill'],
|
|
1999
|
+
[data-slot='thread'],
|
|
2000
|
+
[data-slot='sources-strip'],
|
|
2001
|
+
[data-slot='sidebar-scroll'],
|
|
2002
|
+
[data-slot='scroll-area-viewport'],
|
|
2003
|
+
[data-slot='textarea'],
|
|
2004
|
+
[data-slot='composer-field']
|
|
2005
|
+
) {
|
|
2006
|
+
scrollbar-width: auto;
|
|
2007
|
+
scrollbar-color: auto;
|
|
2008
|
+
}
|
|
2009
|
+
|
|
2010
|
+
:where(
|
|
2011
|
+
[data-slot='fill'],
|
|
2012
|
+
[data-slot='thread'],
|
|
2013
|
+
[data-slot='sources-strip'],
|
|
2014
|
+
[data-slot='sidebar-scroll'],
|
|
2015
|
+
[data-slot='scroll-area-viewport'],
|
|
2016
|
+
[data-slot='textarea'],
|
|
2017
|
+
[data-slot='composer-field']
|
|
2018
|
+
)::-webkit-scrollbar { width: 8px; height: 8px; }
|
|
2019
|
+
|
|
2020
|
+
/* The steppers. This is the rule that removes the arrows, and the reason the
|
|
2021
|
+
two halves had to be separated at all. */
|
|
2022
|
+
:where(
|
|
2023
|
+
[data-slot='fill'],
|
|
2024
|
+
[data-slot='thread'],
|
|
2025
|
+
[data-slot='sources-strip'],
|
|
2026
|
+
[data-slot='sidebar-scroll'],
|
|
2027
|
+
[data-slot='scroll-area-viewport'],
|
|
2028
|
+
[data-slot='textarea'],
|
|
2029
|
+
[data-slot='composer-field']
|
|
2030
|
+
)::-webkit-scrollbar-button { display: none; width: 0; height: 0; }
|
|
2031
|
+
|
|
2032
|
+
:where(
|
|
2033
|
+
[data-slot='fill'],
|
|
2034
|
+
[data-slot='thread'],
|
|
2035
|
+
[data-slot='sources-strip'],
|
|
2036
|
+
[data-slot='sidebar-scroll'],
|
|
2037
|
+
[data-slot='scroll-area-viewport'],
|
|
2038
|
+
[data-slot='textarea'],
|
|
2039
|
+
[data-slot='composer-field']
|
|
2040
|
+
)::-webkit-scrollbar-track { background: transparent; }
|
|
2041
|
+
|
|
2042
|
+
:where(
|
|
2043
|
+
[data-slot='fill'],
|
|
2044
|
+
[data-slot='thread'],
|
|
2045
|
+
[data-slot='sources-strip'],
|
|
2046
|
+
[data-slot='sidebar-scroll'],
|
|
2047
|
+
[data-slot='scroll-area-viewport'],
|
|
2048
|
+
[data-slot='textarea'],
|
|
2049
|
+
[data-slot='composer-field']
|
|
2050
|
+
)::-webkit-scrollbar-thumb {
|
|
2051
|
+
background: rgb(255 255 255 / 0.18);
|
|
2052
|
+
border-radius: 999px;
|
|
2053
|
+
/* A transparent border with background-clip keeps the thumb off the very
|
|
2054
|
+
edge without a track colour doing it, so it reads as an overlay rather
|
|
2055
|
+
than a channel. */
|
|
2056
|
+
border: 2px solid transparent;
|
|
2057
|
+
background-clip: content-box;
|
|
2058
|
+
}
|
|
2059
|
+
:where(
|
|
2060
|
+
[data-slot='fill'],
|
|
2061
|
+
[data-slot='thread'],
|
|
2062
|
+
[data-slot='sources-strip'],
|
|
2063
|
+
[data-slot='sidebar-scroll'],
|
|
2064
|
+
[data-slot='scroll-area-viewport'],
|
|
2065
|
+
[data-slot='textarea'],
|
|
2066
|
+
[data-slot='composer-field']
|
|
2067
|
+
)::-webkit-scrollbar-thumb:hover {
|
|
2068
|
+
background: rgb(255 255 255 / 0.30);
|
|
2069
|
+
background-clip: content-box;
|
|
2070
|
+
}
|
|
2071
|
+
:where(
|
|
2072
|
+
[data-slot='fill'],
|
|
2073
|
+
[data-slot='thread'],
|
|
2074
|
+
[data-slot='sources-strip'],
|
|
2075
|
+
[data-slot='sidebar-scroll'],
|
|
2076
|
+
[data-slot='scroll-area-viewport'],
|
|
2077
|
+
[data-slot='textarea'],
|
|
2078
|
+
[data-slot='composer-field']
|
|
2079
|
+
)::-webkit-scrollbar-corner { background: transparent; }
|
|
2080
|
+
|
|
2081
|
+
.t_light :where(
|
|
2082
|
+
[data-slot='fill'],
|
|
2083
|
+
[data-slot='thread'],
|
|
2084
|
+
[data-slot='sources-strip'],
|
|
2085
|
+
[data-slot='sidebar-scroll'],
|
|
2086
|
+
[data-slot='scroll-area-viewport'],
|
|
2087
|
+
[data-slot='textarea'],
|
|
2088
|
+
[data-slot='composer-field']
|
|
2089
|
+
)::-webkit-scrollbar-thumb {
|
|
2090
|
+
background: rgb(0 0 0 / 0.20);
|
|
2091
|
+
background-clip: content-box;
|
|
2092
|
+
}
|
|
2093
|
+
}
|
|
2094
|
+
|
|
2095
|
+
/* A carousel scrolls but shows no bar: the arrows and the snap already say it
|
|
2096
|
+
scrolls, and a bar appearing mid-drag shifts the slides under the pointer.
|
|
2097
|
+
Firefox reads `scrollbar-width`, which the component sets; WebKit reads only
|
|
2098
|
+
the pseudo-element, which no prop can reach. */
|
|
2099
|
+
[data-slot='carousel-content']::-webkit-scrollbar { display: none; }
|
|
2100
|
+
|
|
2101
|
+
/* The textarea's resize grip is the other platform artefact in the same family:
|
|
2102
|
+
a diagonal hatch drawn by the UA that matches nothing. A composer that grows
|
|
2103
|
+
with its content does not need one. */
|
|
2104
|
+
:where([data-slot='textarea'], [data-slot='composer-field']) { resize: none; }
|