fancy-ui-react 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -19
- package/dist/components/animated-beam/AnimatedBeam.d.ts +47 -11
- package/dist/components/animated-beam/AnimatedBeam.js +293 -118
- package/dist/components/animated-tooltip/AnimatedTooltip.d.ts +10 -1
- package/dist/components/animated-tooltip/AnimatedTooltip.js +170 -101
- package/dist/components/bento-grid/BentoFrame.d.ts +16 -0
- package/dist/components/bento-grid/BentoFrame.js +28 -0
- package/dist/components/bento-grid/BentoGrid.d.ts +5 -1
- package/dist/components/bento-grid/BentoGrid.js +71 -2
- package/dist/components/bento-grid/BentoGridCard.js +34 -26
- package/dist/components/bento-grid/BentoGridItem.js +10 -10
- package/dist/components/border-beam/BorderBeam.d.ts +55 -10
- package/dist/components/border-beam/BorderBeam.js +93 -16
- package/dist/components/compare/Compare.d.ts +32 -8
- package/dist/components/compare/Compare.js +213 -95
- package/dist/components/container-scroll/ContainerScroll.d.ts +26 -4
- package/dist/components/container-scroll/ContainerScroll.js +88 -49
- package/dist/components/dock/Dock.d.ts +10 -7
- package/dist/components/dock/Dock.js +76 -31
- package/dist/components/dock/DockIcon.d.ts +14 -3
- package/dist/components/dock/DockIcon.js +23 -19
- package/dist/components/dock/DockSeparator.d.ts +4 -1
- package/dist/components/dock/DockSeparator.js +5 -2
- package/dist/components/dock/types.d.ts +13 -6
- package/dist/components/dropdown-menu/menu-shared.d.ts +11 -8
- package/dist/components/editorial-engine/engine.js +1 -14
- package/dist/components/fireworks-hdr/webgl2-renderer.js +0 -19
- package/dist/components/fireworks-hdr/webgpu-renderer.js +3 -22
- package/dist/components/flip-card/FlipCard.d.ts +42 -1
- package/dist/components/flip-card/FlipCard.js +178 -25
- package/dist/components/flip-card/index.d.ts +1 -1
- package/dist/components/fluid-cursor/FluidCursor.js +5 -4
- package/dist/components/fluid-cursor/dev.d.ts +1 -0
- package/dist/components/fluid-cursor/dev.js +8 -0
- package/dist/components/fluid-cursor/fluid-shared.d.ts +0 -2
- package/dist/components/fluid-cursor/fluid-shared.js +0 -2
- package/dist/components/fluid-cursor/webgpu-engine.js +10 -24
- package/dist/components/glow-border/GlowBorder.d.ts +41 -1
- package/dist/components/glow-border/GlowBorder.js +96 -16
- package/dist/components/glow-border/index.d.ts +2 -2
- package/dist/components/gradient-button/GradientButton.d.ts +10 -5
- package/dist/components/gradient-button/GradientButton.js +25 -18
- package/dist/components/image-trail-cursor/ImageTrailCursor.js +1 -0
- package/dist/components/image-trail-cursor/trail-variants.d.ts +37 -1
- package/dist/components/image-trail-cursor/trail-variants.js +331 -8
- package/dist/components/interactive-hover-button/InteractiveHoverButton.js +30 -35
- package/dist/components/marquee/Marquee.d.ts +7 -3
- package/dist/components/marquee/Marquee.js +134 -2
- package/dist/components/marquee/ReviewCard.d.ts +2 -1
- package/dist/components/marquee/ReviewCard.js +20 -9
- package/dist/components/meteors/Meteors.d.ts +32 -10
- package/dist/components/meteors/Meteors.js +53 -20
- package/dist/components/mosaic-glow/mosaic-glow-core.d.ts +98 -10
- package/dist/components/neon-border/NeonBorder.d.ts +24 -5
- package/dist/components/neon-border/NeonBorder.js +37 -7
- package/dist/components/pagination/Pagination.js +220 -82
- package/dist/components/rainbow-button/RainbowButton.js +13 -5
- package/dist/components/ripple-button/RippleButton.d.ts +20 -1
- package/dist/components/ripple-button/RippleButton.js +44 -21
- package/dist/components/shimmer-button/ShimmerButton.d.ts +5 -5
- package/dist/components/shimmer-button/ShimmerButton.js +17 -19
- package/dist/components/smooth-cursor/SmoothCursor.d.ts +13 -9
- package/dist/components/smooth-cursor/SmoothCursor.js +114 -163
- package/dist/components/smooth-cursor/smooth-cursor-core.d.ts +85 -0
- package/dist/components/smooth-cursor/smooth-cursor-core.js +327 -0
- package/dist/components/stepper/Step.js +32 -19
- package/dist/components/stepper/Stepper.js +18 -2
- package/dist/components/stepper/types.d.ts +13 -0
- package/dist/components/timeline/Timeline.d.ts +8 -1
- package/dist/components/timeline/Timeline.js +165 -76
- package/dist/index.js +2 -1
- package/dist/internals/markdown.d.ts +5 -0
- package/dist/internals/motion/haptics.d.ts +0 -4
- package/dist/internals/motion/presence-core.d.ts +59 -0
- package/dist/internals/motion/presence-core.js +162 -0
- package/dist/internals/motion/presence.d.ts +2 -4
- package/dist/internals/motion/presence.js +1 -156
- package/dist/internals/motion/raf.d.ts +1 -1
- package/dist/internals/motion/stagger.d.ts +3 -4
- package/dist/internals/motion/tokens.js +4 -0
- package/dist/internals/motion/transitions.d.ts +17 -17
- package/dist/internals/motion/types.d.ts +6 -7
- package/dist/internals/relative-time.d.ts +1 -1
- package/dist/styles.css +3470 -203
- package/package.json +18 -2
- package/dist/components/fireworks-hdr/webgpu-types.d.ts +0 -159
package/dist/styles.css
CHANGED
|
@@ -429,6 +429,422 @@
|
|
|
429
429
|
transform: rotate(360deg);
|
|
430
430
|
}
|
|
431
431
|
}
|
|
432
|
+
/*
|
|
433
|
+
* `.animated-beam` is a port-added anchor: the source has no root class and
|
|
434
|
+
* relied on compiler scoping, while plain CSS is global. Every rule below is
|
|
435
|
+
* anchored on it; class names, custom properties and keyframe names are
|
|
436
|
+
* identical to the source.
|
|
437
|
+
*/
|
|
438
|
+
|
|
439
|
+
/* Theme-aware glass. Public vars first, house defaults as fallbacks. */
|
|
440
|
+
.animated-beam .fibre-sheath {
|
|
441
|
+
stroke: var(--beam-fibre-rim, rgba(0, 0, 0, 0.07));
|
|
442
|
+
}
|
|
443
|
+
.animated-beam .fibre-core {
|
|
444
|
+
stroke: var(--beam-fibre, rgba(0, 0, 0, 0.18));
|
|
445
|
+
}
|
|
446
|
+
.animated-beam .fibre-glint {
|
|
447
|
+
stroke: var(--beam-fibre-glint, rgba(255, 255, 255, 0.75));
|
|
448
|
+
}
|
|
449
|
+
.dark .animated-beam .fibre-sheath {
|
|
450
|
+
stroke: var(--beam-fibre-rim, rgba(255, 255, 255, 0.06));
|
|
451
|
+
}
|
|
452
|
+
.dark .animated-beam .fibre-core {
|
|
453
|
+
stroke: var(--beam-fibre, rgba(255, 255, 255, 0.14));
|
|
454
|
+
}
|
|
455
|
+
.dark .animated-beam .fibre-glint {
|
|
456
|
+
stroke: var(--beam-fibre-glint, rgba(255, 255, 255, 0.16));
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
/* On a light surface a white core disappears; keep more colour there. */
|
|
460
|
+
.animated-beam .packet-core {
|
|
461
|
+
stroke: color-mix(in oklab, var(--_core) 72%, white);
|
|
462
|
+
}
|
|
463
|
+
.dark .animated-beam .packet-core {
|
|
464
|
+
stroke: color-mix(in oklab, var(--_core) 45%, white);
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
.animated-beam .packet-layer {
|
|
468
|
+
stroke-dasharray: var(--_len) 3000;
|
|
469
|
+
stroke-dashoffset: var(--_o0);
|
|
470
|
+
animation: beam-packet var(--_dur, 5s) linear var(--_delay, 0s) infinite backwards;
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
/* Glide out, settle into the node at ARRIVAL (78%), then drain the tail. */
|
|
474
|
+
@keyframes beam-packet {
|
|
475
|
+
0% {
|
|
476
|
+
stroke-dashoffset: var(--_o0);
|
|
477
|
+
animation-timing-function: cubic-bezier(0.45, 0, 0.2, 1);
|
|
478
|
+
}
|
|
479
|
+
78% {
|
|
480
|
+
stroke-dashoffset: var(--_o1);
|
|
481
|
+
animation-timing-function: cubic-bezier(0.5, 0, 1, 1);
|
|
482
|
+
}
|
|
483
|
+
100% {
|
|
484
|
+
stroke-dashoffset: var(--_o2);
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
.animated-beam .bloom-disc,
|
|
489
|
+
.animated-beam .bloom-ring {
|
|
490
|
+
transform-box: fill-box;
|
|
491
|
+
transform-origin: center;
|
|
492
|
+
opacity: 0;
|
|
493
|
+
animation: beam-bloom var(--_dur, 5s) linear var(--_delay, 0s) infinite backwards;
|
|
494
|
+
}
|
|
495
|
+
.animated-beam .bloom-ring {
|
|
496
|
+
animation-name: beam-ring;
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
/* The head lands at 78%: the halo swells behind the node, then lets go. */
|
|
500
|
+
@keyframes beam-bloom {
|
|
501
|
+
0%,
|
|
502
|
+
74% {
|
|
503
|
+
opacity: 0;
|
|
504
|
+
transform: scale(0.6);
|
|
505
|
+
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
|
506
|
+
}
|
|
507
|
+
84% {
|
|
508
|
+
opacity: 0.85;
|
|
509
|
+
transform: scale(1);
|
|
510
|
+
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
|
|
511
|
+
}
|
|
512
|
+
100% {
|
|
513
|
+
opacity: 0;
|
|
514
|
+
transform: scale(1.15);
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
/* A single ripple leaves the node on arrival. */
|
|
519
|
+
@keyframes beam-ring {
|
|
520
|
+
0%,
|
|
521
|
+
77% {
|
|
522
|
+
opacity: 0;
|
|
523
|
+
transform: scale(0.96);
|
|
524
|
+
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
|
525
|
+
}
|
|
526
|
+
81% {
|
|
527
|
+
opacity: 0.7;
|
|
528
|
+
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
|
529
|
+
}
|
|
530
|
+
100% {
|
|
531
|
+
opacity: 0;
|
|
532
|
+
transform: scale(1.5);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/* Before hydration can ask the browser, keep reduced-motion users still. */
|
|
537
|
+
@media (prefers-reduced-motion: reduce) {
|
|
538
|
+
.animated-beam .packet {
|
|
539
|
+
display: none;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
/*
|
|
543
|
+
* Every rule below is anchored on `.at-root`, the class the source's own root
|
|
544
|
+
* element carries: the source's compiler scoped these selectors, plain CSS does
|
|
545
|
+
* not, so the anchor keeps the `at-*` hooks from leaking into a consumer page.
|
|
546
|
+
* Class names, custom properties, `@property` and keyframe names are identical
|
|
547
|
+
* to the source's; they are the visual contract.
|
|
548
|
+
*/
|
|
549
|
+
|
|
550
|
+
@property --at-angle {
|
|
551
|
+
syntax: "<angle>";
|
|
552
|
+
inherits: false;
|
|
553
|
+
initial-value: 0deg;
|
|
554
|
+
}
|
|
555
|
+
|
|
556
|
+
.at-root {
|
|
557
|
+
/* Public, class-themeable knobs with private fallbacks. */
|
|
558
|
+
--_at-a: var(--at-accent, oklch(0.62 0.13 295));
|
|
559
|
+
--_at-b: var(--at-accent-2, oklch(0.7 0.1 220));
|
|
560
|
+
--_at-core: color-mix(in oklab, var(--_at-a) 45%, white);
|
|
561
|
+
--_at-sep: var(--at-separator, var(--background, #ffffff));
|
|
562
|
+
--_at-ease-out: cubic-bezier(0.16, 1, 0.3, 1);
|
|
563
|
+
--_at-ease-rise: cubic-bezier(0.34, 1.32, 0.64, 1);
|
|
564
|
+
--_at-ease-inout: cubic-bezier(0.4, 0, 0.2, 1);
|
|
565
|
+
--_at-card-bg: rgba(255, 255, 255, 0.85);
|
|
566
|
+
--_at-card-line: rgba(0, 0, 0, 0.08);
|
|
567
|
+
--_at-card-hi: rgba(255, 255, 255, 0.9);
|
|
568
|
+
--_at-card-shadow: 0 10px 28px -12px rgba(0, 0, 0, 0.28), 0 2px 6px -2px rgba(0, 0, 0, 0.1);
|
|
569
|
+
--_at-name: #111113;
|
|
570
|
+
--_at-role: rgba(0, 0, 0, 0.55);
|
|
571
|
+
}
|
|
572
|
+
|
|
573
|
+
.dark .at-root {
|
|
574
|
+
--_at-a: var(--at-accent, oklch(0.78 0.1 295));
|
|
575
|
+
--_at-b: var(--at-accent-2, oklch(0.83 0.08 210));
|
|
576
|
+
--_at-card-bg: rgba(20, 20, 22, 0.85);
|
|
577
|
+
--_at-card-line: rgba(255, 255, 255, 0.1);
|
|
578
|
+
--_at-card-hi: rgba(255, 255, 255, 0.06);
|
|
579
|
+
--_at-card-shadow: 0 14px 32px -12px rgba(0, 0, 0, 0.8), 0 2px 6px -2px rgba(0, 0, 0, 0.5);
|
|
580
|
+
--_at-name: #f4f4f5;
|
|
581
|
+
--_at-role: rgba(255, 255, 255, 0.55);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/* ---------- stack ---------- */
|
|
585
|
+
|
|
586
|
+
.at-root .at-item {
|
|
587
|
+
outline: none;
|
|
588
|
+
transform: translateX(var(--_at-shift, 0px));
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
.at-root .at-item:not(:last-child) {
|
|
592
|
+
margin-inline-end: calc(var(--_at-size) * -0.285);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
.at-root .at-item.at-active {
|
|
596
|
+
z-index: 30;
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
.at-root .at-avatar {
|
|
600
|
+
position: relative;
|
|
601
|
+
width: var(--_at-size);
|
|
602
|
+
height: var(--_at-size);
|
|
603
|
+
border-radius: 9999px;
|
|
604
|
+
isolation: isolate;
|
|
605
|
+
transform-origin: 50% 60%;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/* The hairline that separates stacked avatars, in the page colour. */
|
|
609
|
+
.at-root .at-disc {
|
|
610
|
+
position: absolute;
|
|
611
|
+
inset: 0;
|
|
612
|
+
z-index: 1;
|
|
613
|
+
border-radius: 9999px;
|
|
614
|
+
background: var(--_at-sep);
|
|
615
|
+
box-shadow: 0 0 0 2px var(--_at-sep);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
.at-root .at-avatar.at-lifted {
|
|
619
|
+
transform: translateY(-4px) scale(1.08);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
.at-root .at-img {
|
|
623
|
+
position: absolute;
|
|
624
|
+
inset: 3px;
|
|
625
|
+
width: calc(100% - 6px);
|
|
626
|
+
height: calc(100% - 6px);
|
|
627
|
+
z-index: 3;
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/* The lit ring is the focus indicator; forced-colors mode strips it, so
|
|
631
|
+
fall back to a system-coloured outline there. */
|
|
632
|
+
@media (forced-colors: active) {
|
|
633
|
+
.at-root .at-item:focus-visible .at-avatar {
|
|
634
|
+
outline: 2px solid Highlight;
|
|
635
|
+
outline-offset: 2px;
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
/* ---------- presence ring ---------- */
|
|
640
|
+
|
|
641
|
+
.at-root .at-ring,
|
|
642
|
+
.at-root .at-glow {
|
|
643
|
+
position: absolute;
|
|
644
|
+
border-radius: 9999px;
|
|
645
|
+
background: conic-gradient(
|
|
646
|
+
from var(--at-angle),
|
|
647
|
+
var(--_at-a) 0deg,
|
|
648
|
+
var(--_at-b) 150deg,
|
|
649
|
+
var(--_at-core) 205deg,
|
|
650
|
+
var(--_at-a) 260deg,
|
|
651
|
+
var(--_at-a) 360deg
|
|
652
|
+
);
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.at-root .at-ring {
|
|
656
|
+
inset: 0;
|
|
657
|
+
z-index: 2;
|
|
658
|
+
padding: 2px;
|
|
659
|
+
-webkit-mask:
|
|
660
|
+
linear-gradient(#000 0 0) content-box,
|
|
661
|
+
linear-gradient(#000 0 0);
|
|
662
|
+
-webkit-mask-composite: xor;
|
|
663
|
+
mask:
|
|
664
|
+
linear-gradient(#000 0 0) content-box exclude,
|
|
665
|
+
linear-gradient(#000 0 0);
|
|
666
|
+
opacity: 0.35;
|
|
667
|
+
transition: opacity 300ms var(--_at-ease-inout);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
.at-root .at-glow {
|
|
671
|
+
inset: -3px;
|
|
672
|
+
z-index: 0;
|
|
673
|
+
filter: blur(7px);
|
|
674
|
+
opacity: 0;
|
|
675
|
+
transition: opacity 300ms var(--_at-ease-inout);
|
|
676
|
+
}
|
|
677
|
+
|
|
678
|
+
.at-root .at-active .at-ring {
|
|
679
|
+
opacity: 1;
|
|
680
|
+
}
|
|
681
|
+
|
|
682
|
+
.at-root .at-active .at-glow {
|
|
683
|
+
opacity: 0.55;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
/* ---------- glass card ---------- */
|
|
687
|
+
|
|
688
|
+
.at-root .at-tip {
|
|
689
|
+
bottom: calc(100% + 12px);
|
|
690
|
+
transform-origin: 50% 100%;
|
|
691
|
+
}
|
|
692
|
+
|
|
693
|
+
.at-root .at-card {
|
|
694
|
+
position: relative;
|
|
695
|
+
display: flex;
|
|
696
|
+
flex-direction: column;
|
|
697
|
+
align-items: center;
|
|
698
|
+
gap: 5px;
|
|
699
|
+
padding: 8px 14px 9px;
|
|
700
|
+
border-radius: 10px;
|
|
701
|
+
white-space: nowrap;
|
|
702
|
+
background: var(--_at-card-bg);
|
|
703
|
+
border: 1px solid var(--_at-card-line);
|
|
704
|
+
box-shadow:
|
|
705
|
+
inset 0 1px 0 var(--_at-card-hi),
|
|
706
|
+
var(--_at-card-shadow);
|
|
707
|
+
-webkit-backdrop-filter: blur(12px) saturate(1.4);
|
|
708
|
+
backdrop-filter: blur(12px) saturate(1.4);
|
|
709
|
+
transform-origin: 50% 100%;
|
|
710
|
+
animation: at-fade 160ms var(--_at-ease-out) both;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
.at-root .at-pointer {
|
|
714
|
+
position: absolute;
|
|
715
|
+
left: 50%;
|
|
716
|
+
bottom: -5px;
|
|
717
|
+
width: 9px;
|
|
718
|
+
height: 9px;
|
|
719
|
+
margin-left: -4.5px;
|
|
720
|
+
background: var(--_at-card-bg);
|
|
721
|
+
border-right: 1px solid var(--_at-card-line);
|
|
722
|
+
border-bottom: 1px solid var(--_at-card-line);
|
|
723
|
+
border-bottom-right-radius: 2px;
|
|
724
|
+
transform: rotate(45deg);
|
|
725
|
+
clip-path: polygon(100% 0, 100% 100%, 0 100%);
|
|
726
|
+
-webkit-backdrop-filter: blur(12px);
|
|
727
|
+
backdrop-filter: blur(12px);
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
.at-root .at-name {
|
|
731
|
+
font-size: 0.8125rem;
|
|
732
|
+
line-height: 1.1rem;
|
|
733
|
+
font-weight: 600;
|
|
734
|
+
letter-spacing: -0.005em;
|
|
735
|
+
color: var(--_at-name);
|
|
736
|
+
}
|
|
737
|
+
|
|
738
|
+
.at-root .at-role {
|
|
739
|
+
font-size: 0.6875rem;
|
|
740
|
+
line-height: 0.9rem;
|
|
741
|
+
color: var(--_at-role);
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
/* One thin line of light under the name: a faint resting hairline plus a
|
|
745
|
+
glint that sweeps across it once when the card opens. */
|
|
746
|
+
.at-root .at-rule {
|
|
747
|
+
position: relative;
|
|
748
|
+
display: block;
|
|
749
|
+
width: 100%;
|
|
750
|
+
min-width: 64px;
|
|
751
|
+
height: 7px;
|
|
752
|
+
margin: -3px 0;
|
|
753
|
+
overflow: clip;
|
|
754
|
+
background: linear-gradient(
|
|
755
|
+
90deg,
|
|
756
|
+
transparent,
|
|
757
|
+
color-mix(in oklab, var(--_at-a) 50%, transparent) 30%,
|
|
758
|
+
color-mix(in oklab, var(--_at-b) 50%, transparent) 70%,
|
|
759
|
+
transparent
|
|
760
|
+
)
|
|
761
|
+
center / 100% 1px no-repeat;
|
|
762
|
+
}
|
|
763
|
+
|
|
764
|
+
.at-root .at-glint {
|
|
765
|
+
display: none;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
769
|
+
.at-root .at-item {
|
|
770
|
+
transition: transform 380ms var(--_at-ease-out);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
.at-root .at-avatar {
|
|
774
|
+
transition: transform 420ms var(--_at-ease-out);
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
.at-root .at-ring,
|
|
778
|
+
.at-root .at-glow {
|
|
779
|
+
transition:
|
|
780
|
+
opacity 300ms var(--_at-ease-inout),
|
|
781
|
+
--at-angle 900ms var(--_at-ease-out);
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
.at-root .at-active .at-ring,
|
|
785
|
+
.at-root .at-active .at-glow {
|
|
786
|
+
--at-angle: 140deg;
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
.at-root .at-tip {
|
|
790
|
+
transition: transform 240ms var(--_at-ease-out);
|
|
791
|
+
}
|
|
792
|
+
|
|
793
|
+
.at-root .at-card {
|
|
794
|
+
animation: at-rise 260ms var(--_at-ease-rise) both;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
.at-root .at-glint {
|
|
798
|
+
display: block;
|
|
799
|
+
position: absolute;
|
|
800
|
+
top: 3px;
|
|
801
|
+
left: 0;
|
|
802
|
+
width: 60%;
|
|
803
|
+
height: 1px;
|
|
804
|
+
border-radius: 1px;
|
|
805
|
+
background: linear-gradient(
|
|
806
|
+
90deg,
|
|
807
|
+
transparent,
|
|
808
|
+
var(--_at-a) 25%,
|
|
809
|
+
var(--_at-core) 50%,
|
|
810
|
+
var(--_at-b) 75%,
|
|
811
|
+
transparent
|
|
812
|
+
);
|
|
813
|
+
/* Soft halo so a 1px line still reads as light. */
|
|
814
|
+
filter: drop-shadow(0 0 2px var(--_at-a)) drop-shadow(0 0 4px var(--_at-b));
|
|
815
|
+
transform: translateX(-110%);
|
|
816
|
+
animation: at-sweep 760ms var(--_at-ease-inout) 90ms both;
|
|
817
|
+
}
|
|
818
|
+
}
|
|
819
|
+
|
|
820
|
+
@keyframes at-rise {
|
|
821
|
+
from {
|
|
822
|
+
opacity: 0;
|
|
823
|
+
transform: translateY(6px) scale(0.94);
|
|
824
|
+
}
|
|
825
|
+
to {
|
|
826
|
+
opacity: 1;
|
|
827
|
+
transform: none;
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
@keyframes at-fade {
|
|
832
|
+
from {
|
|
833
|
+
opacity: 0;
|
|
834
|
+
}
|
|
835
|
+
to {
|
|
836
|
+
opacity: 1;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
@keyframes at-sweep {
|
|
841
|
+
from {
|
|
842
|
+
transform: translateX(-110%);
|
|
843
|
+
}
|
|
844
|
+
to {
|
|
845
|
+
transform: translateX(180%);
|
|
846
|
+
}
|
|
847
|
+
}
|
|
432
848
|
/*
|
|
433
849
|
* Every colour is read at the point of use through two hooks: this card's own
|
|
434
850
|
* `--ft-approval-*`, then the `--ft-status-*` vocabulary the whole AI family
|
|
@@ -852,6 +1268,240 @@
|
|
|
852
1268
|
border-color: var(--ft-field-accent);
|
|
853
1269
|
box-shadow: 0 0 0 3px color-mix(in oklab, var(--ft-field-accent) 25%, transparent);
|
|
854
1270
|
}
|
|
1271
|
+
/*
|
|
1272
|
+
* Ported from BentoGrid.svelte's <style> block. The rules were already
|
|
1273
|
+
* anchored on the grid's own root class (.fancy-bento) there; Svelte's
|
|
1274
|
+
* `:global(*)` child selector becomes a plain `*`.
|
|
1275
|
+
*
|
|
1276
|
+
* The hidden state exists only for viewers who allow motion and whose
|
|
1277
|
+
* browser runs scripts — everyone else gets the resting, visible grid
|
|
1278
|
+
* without waiting on JS. Transforms and opacity only.
|
|
1279
|
+
*/
|
|
1280
|
+
@media (prefers-reduced-motion: no-preference) and (scripting: enabled) {
|
|
1281
|
+
.fancy-bento.bento-reveal[data-state="armed"] > * {
|
|
1282
|
+
opacity: 0;
|
|
1283
|
+
transform: translate3d(0, 18px, 0) scale(0.985);
|
|
1284
|
+
}
|
|
1285
|
+
.fancy-bento.bento-reveal[data-state="shown"] > * {
|
|
1286
|
+
transition:
|
|
1287
|
+
opacity 600ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
1288
|
+
transform 800ms cubic-bezier(0.16, 1, 0.3, 1),
|
|
1289
|
+
border-color 300ms cubic-bezier(0.4, 0, 0.2, 1); /* DURATIONS.entrance, EASINGS.out */
|
|
1290
|
+
transition-delay: var(--bento-delay, 0ms), var(--bento-delay, 0ms), 0ms;
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
/*
|
|
1294
|
+
* Ported from BentoFrame.svelte's <style> block. Every rule is anchored on
|
|
1295
|
+
* the tile's own root class (.bento-tile). The source's compiler-scoped
|
|
1296
|
+
* `.bento-panel`, `.bento-glow` and `.bento-edge` selectors are written here
|
|
1297
|
+
* as descendants of `.bento-tile` (port-added anchor); `:global(...)` parts
|
|
1298
|
+
* become plain selectors, since this file is global CSS to begin with.
|
|
1299
|
+
*/
|
|
1300
|
+
|
|
1301
|
+
/*
|
|
1302
|
+
* Colour plumbing. `--_accent` reads the public `--bento-accent` (written by
|
|
1303
|
+
* BentoGrid's `accent` prop, or set by a consumer on any ancestor via class)
|
|
1304
|
+
* with a soft periwinkle fallback. `--_core` is the white-hot centre of the
|
|
1305
|
+
* glow, mixed from the accent.
|
|
1306
|
+
*/
|
|
1307
|
+
.bento-tile {
|
|
1308
|
+
--_accent: var(--bento-accent, #8e9cff);
|
|
1309
|
+
--_core: color-mix(in oklab, var(--_accent) 45%, white);
|
|
1310
|
+
--_frame-bg: var(--bento-frame-bg, #f6f6f7);
|
|
1311
|
+
--_frame-line: var(--bento-frame-line, rgba(0, 0, 0, 0.08));
|
|
1312
|
+
--_panel-bg: var(--bento-panel-bg, #fdfdfd);
|
|
1313
|
+
--_panel-line: var(--bento-panel-line, rgba(0, 0, 0, 0.07));
|
|
1314
|
+
--_panel-top: rgba(255, 255, 255, 0.95);
|
|
1315
|
+
--_panel-top-edge: rgba(255, 255, 255, 1);
|
|
1316
|
+
--_glow-peak: 0.3;
|
|
1317
|
+
|
|
1318
|
+
background: var(--_frame-bg);
|
|
1319
|
+
border: 1px solid var(--_frame-line);
|
|
1320
|
+
box-shadow:
|
|
1321
|
+
0 1px 2px rgba(15, 15, 20, 0.04),
|
|
1322
|
+
0 12px 32px -18px rgba(15, 15, 20, 0.14);
|
|
1323
|
+
transition: border-color 300ms cubic-bezier(0.4, 0, 0.2, 1); /* EASINGS.inout */
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
.dark .bento-tile {
|
|
1327
|
+
--_frame-bg: var(--bento-frame-bg, #0f0f10);
|
|
1328
|
+
--_frame-line: var(--bento-frame-line, rgba(255, 255, 255, 0.08));
|
|
1329
|
+
--_panel-bg: var(--bento-panel-bg, #141416);
|
|
1330
|
+
--_panel-line: var(--bento-panel-line, rgba(255, 255, 255, 0.06));
|
|
1331
|
+
--_panel-top: rgba(255, 255, 255, 0.06);
|
|
1332
|
+
--_panel-top-edge: rgba(255, 255, 255, 0.08);
|
|
1333
|
+
--_glow-peak: 0.35;
|
|
1334
|
+
box-shadow:
|
|
1335
|
+
0 1px 2px rgba(0, 0, 0, 0.4),
|
|
1336
|
+
0 18px 40px -22px rgba(0, 0, 0, 0.7);
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
/* Inner panel: its own hairline plus a soft top light. */
|
|
1340
|
+
.bento-tile .bento-panel {
|
|
1341
|
+
background: linear-gradient(180deg, var(--_panel-top), transparent 40%), var(--_panel-bg);
|
|
1342
|
+
border: 1px solid var(--_panel-line);
|
|
1343
|
+
box-shadow: inset 0 1px 0 var(--_panel-top-edge);
|
|
1344
|
+
}
|
|
1345
|
+
|
|
1346
|
+
/* The glow: a blurred accent radial parked below the panel's bottom edge,
|
|
1347
|
+
white-hot at its centre. Hover raises it 40% → 0 and fades it in. */
|
|
1348
|
+
.bento-tile .bento-glow {
|
|
1349
|
+
position: absolute;
|
|
1350
|
+
z-index: -1;
|
|
1351
|
+
left: -10%;
|
|
1352
|
+
right: -10%;
|
|
1353
|
+
bottom: -22%;
|
|
1354
|
+
height: 78%;
|
|
1355
|
+
pointer-events: none;
|
|
1356
|
+
background: radial-gradient(
|
|
1357
|
+
65% 85% at 50% 100%,
|
|
1358
|
+
var(--_core) 0%,
|
|
1359
|
+
var(--_accent) 30%,
|
|
1360
|
+
color-mix(in oklab, var(--_accent) 40%, transparent) 55%,
|
|
1361
|
+
transparent 80%
|
|
1362
|
+
);
|
|
1363
|
+
filter: blur(24px);
|
|
1364
|
+
opacity: 0;
|
|
1365
|
+
transform: translate3d(0, 40%, 0);
|
|
1366
|
+
transition:
|
|
1367
|
+
opacity 500ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
1368
|
+
transform 700ms cubic-bezier(0.16, 1, 0.3, 1); /* EASINGS.out */
|
|
1369
|
+
}
|
|
1370
|
+
|
|
1371
|
+
/* The bottom edge catches the light as the glow arrives. */
|
|
1372
|
+
.bento-tile .bento-edge {
|
|
1373
|
+
position: absolute;
|
|
1374
|
+
left: 14%;
|
|
1375
|
+
right: 14%;
|
|
1376
|
+
bottom: 0;
|
|
1377
|
+
height: 1px;
|
|
1378
|
+
pointer-events: none;
|
|
1379
|
+
background: linear-gradient(
|
|
1380
|
+
90deg,
|
|
1381
|
+
transparent,
|
|
1382
|
+
var(--_accent) 25%,
|
|
1383
|
+
var(--_core) 50%,
|
|
1384
|
+
var(--_accent) 75%,
|
|
1385
|
+
transparent
|
|
1386
|
+
);
|
|
1387
|
+
opacity: 0;
|
|
1388
|
+
transition: opacity 500ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
1389
|
+
}
|
|
1390
|
+
|
|
1391
|
+
.bento-tile:hover,
|
|
1392
|
+
.bento-tile:focus-within {
|
|
1393
|
+
--_frame-line: var(--bento-frame-line-hover, rgba(0, 0, 0, 0.12));
|
|
1394
|
+
}
|
|
1395
|
+
.dark .bento-tile:hover,
|
|
1396
|
+
.dark .bento-tile:focus-within {
|
|
1397
|
+
--_frame-line: var(--bento-frame-line-hover, rgba(255, 255, 255, 0.13));
|
|
1398
|
+
}
|
|
1399
|
+
|
|
1400
|
+
.bento-tile:hover .bento-glow,
|
|
1401
|
+
.bento-tile:focus-within .bento-glow {
|
|
1402
|
+
opacity: var(--_glow-peak);
|
|
1403
|
+
transform: translate3d(0, 0, 0);
|
|
1404
|
+
}
|
|
1405
|
+
.bento-tile:hover .bento-edge,
|
|
1406
|
+
.bento-tile:focus-within .bento-edge {
|
|
1407
|
+
opacity: 0.85;
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1410
|
+
/*
|
|
1411
|
+
* Shared content parts, styled here so Item and Card stay identical.
|
|
1412
|
+
* They live in the tiles' own markup.
|
|
1413
|
+
*/
|
|
1414
|
+
|
|
1415
|
+
/* Content lift. */
|
|
1416
|
+
.bento-tile .bento-lift {
|
|
1417
|
+
transition: transform 500ms cubic-bezier(0.16, 1, 0.3, 1);
|
|
1418
|
+
}
|
|
1419
|
+
|
|
1420
|
+
/* The icon sits in a small inset tile: darker well, inset hairline. */
|
|
1421
|
+
.bento-tile .bento-icon {
|
|
1422
|
+
display: grid;
|
|
1423
|
+
place-items: center;
|
|
1424
|
+
flex: none;
|
|
1425
|
+
border-radius: 10px;
|
|
1426
|
+
color: #71717a;
|
|
1427
|
+
background: #f0f0f2;
|
|
1428
|
+
border: 1px solid rgba(0, 0, 0, 0.07);
|
|
1429
|
+
box-shadow:
|
|
1430
|
+
inset 0 1px 2px rgba(0, 0, 0, 0.06),
|
|
1431
|
+
0 1px 0 rgba(255, 255, 255, 0.9);
|
|
1432
|
+
transition:
|
|
1433
|
+
color 300ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
1434
|
+
border-color 300ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
1435
|
+
background-color 300ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
1436
|
+
box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
1437
|
+
}
|
|
1438
|
+
.dark .bento-tile .bento-icon {
|
|
1439
|
+
color: #8a8a93;
|
|
1440
|
+
background: #0b0b0c;
|
|
1441
|
+
border-color: rgba(255, 255, 255, 0.07);
|
|
1442
|
+
box-shadow:
|
|
1443
|
+
inset 0 1px 3px rgba(0, 0, 0, 0.6),
|
|
1444
|
+
0 1px 0 rgba(255, 255, 255, 0.04);
|
|
1445
|
+
}
|
|
1446
|
+
.bento-tile:is(:hover, :focus-within) .bento-icon {
|
|
1447
|
+
color: #18181b;
|
|
1448
|
+
background: #fff;
|
|
1449
|
+
border-color: color-mix(in oklab, var(--_accent) 45%, rgba(0, 0, 0, 0.08));
|
|
1450
|
+
box-shadow:
|
|
1451
|
+
inset 0 1px 2px rgba(0, 0, 0, 0.04),
|
|
1452
|
+
0 0 0 3px color-mix(in oklab, var(--_accent) 14%, transparent);
|
|
1453
|
+
}
|
|
1454
|
+
.dark .bento-tile:is(:hover, :focus-within) .bento-icon {
|
|
1455
|
+
color: #fafafa;
|
|
1456
|
+
background: #19191c;
|
|
1457
|
+
border-color: color-mix(in oklab, var(--_accent) 40%, rgba(255, 255, 255, 0.1));
|
|
1458
|
+
box-shadow:
|
|
1459
|
+
inset 0 1px 0 rgba(255, 255, 255, 0.06),
|
|
1460
|
+
0 0 14px -4px color-mix(in oklab, var(--_accent) 55%, transparent);
|
|
1461
|
+
}
|
|
1462
|
+
|
|
1463
|
+
/* The CTA slides in from the left and fades up. */
|
|
1464
|
+
.bento-tile .bento-cta {
|
|
1465
|
+
opacity: 0;
|
|
1466
|
+
transform: translate3d(-8px, 0, 0);
|
|
1467
|
+
transition:
|
|
1468
|
+
opacity 400ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
1469
|
+
transform 500ms cubic-bezier(0.16, 1, 0.3, 1),
|
|
1470
|
+
color 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
1471
|
+
}
|
|
1472
|
+
.bento-tile:is(:hover, :focus-within) .bento-cta {
|
|
1473
|
+
opacity: 1;
|
|
1474
|
+
transform: translate3d(0, 0, 0);
|
|
1475
|
+
}
|
|
1476
|
+
/* No hover on touch screens: keep the CTA visible. */
|
|
1477
|
+
@media (hover: none) {
|
|
1478
|
+
.bento-tile .bento-cta {
|
|
1479
|
+
opacity: 1;
|
|
1480
|
+
transform: none;
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
|
|
1484
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
1485
|
+
.bento-tile:is(:hover, :focus-within) .bento-lift {
|
|
1486
|
+
transform: translate3d(0, -6px, 0);
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1489
|
+
|
|
1490
|
+
/* Reduced motion: the glow still arrives, but only as a fade — it sits in
|
|
1491
|
+
its final place from the start. */
|
|
1492
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1493
|
+
.bento-tile .bento-glow {
|
|
1494
|
+
transform: none;
|
|
1495
|
+
transition: opacity 300ms linear;
|
|
1496
|
+
}
|
|
1497
|
+
.bento-tile .bento-cta {
|
|
1498
|
+
transform: none;
|
|
1499
|
+
transition: opacity 300ms linear;
|
|
1500
|
+
}
|
|
1501
|
+
.bento-tile .bento-lift {
|
|
1502
|
+
transition: none;
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
855
1505
|
/*
|
|
856
1506
|
* `.fancy-bg-stars` is a PORT-ADDED anchor (PORTING.md, styling rule 2). The
|
|
857
1507
|
* Svelte source has no root class: its compiler scoped `.stars-parallax` /
|
|
@@ -914,58 +1564,300 @@
|
|
|
914
1564
|
.blur-reveal-wrapper.is-visible > :nth-child(3) {
|
|
915
1565
|
transition-delay: calc(var(--blur-reveal-delay, 0.2s) * 2);
|
|
916
1566
|
}
|
|
917
|
-
.blur-reveal-wrapper.is-visible > :nth-child(4) {
|
|
918
|
-
transition-delay: calc(var(--blur-reveal-delay, 0.2s) * 3);
|
|
1567
|
+
.blur-reveal-wrapper.is-visible > :nth-child(4) {
|
|
1568
|
+
transition-delay: calc(var(--blur-reveal-delay, 0.2s) * 3);
|
|
1569
|
+
}
|
|
1570
|
+
.blur-reveal-wrapper.is-visible > :nth-child(5) {
|
|
1571
|
+
transition-delay: calc(var(--blur-reveal-delay, 0.2s) * 4);
|
|
1572
|
+
}
|
|
1573
|
+
.blur-reveal-wrapper.is-visible > :nth-child(6) {
|
|
1574
|
+
transition-delay: calc(var(--blur-reveal-delay, 0.2s) * 5);
|
|
1575
|
+
}
|
|
1576
|
+
.blur-reveal-wrapper.is-visible > :nth-child(7) {
|
|
1577
|
+
transition-delay: calc(var(--blur-reveal-delay, 0.2s) * 6);
|
|
1578
|
+
}
|
|
1579
|
+
.blur-reveal-wrapper.is-visible > :nth-child(8) {
|
|
1580
|
+
transition-delay: calc(var(--blur-reveal-delay, 0.2s) * 7);
|
|
1581
|
+
}
|
|
1582
|
+
.blur-reveal-wrapper.is-visible > :nth-child(9) {
|
|
1583
|
+
transition-delay: calc(var(--blur-reveal-delay, 0.2s) * 8);
|
|
1584
|
+
}
|
|
1585
|
+
.blur-reveal-wrapper.is-visible > :nth-child(10) {
|
|
1586
|
+
transition-delay: calc(var(--blur-reveal-delay, 0.2s) * 9);
|
|
1587
|
+
}
|
|
1588
|
+
|
|
1589
|
+
/* Hard mode: no blur/translate softening, opacity snaps in via a stepped timing function */
|
|
1590
|
+
.blur-reveal-wrapper.mode-hard > * {
|
|
1591
|
+
opacity: 0;
|
|
1592
|
+
filter: none;
|
|
1593
|
+
transform: none;
|
|
1594
|
+
transition: opacity var(--blur-reveal-duration, 1s) steps(2, jump-none);
|
|
1595
|
+
}
|
|
1596
|
+
|
|
1597
|
+
.blur-reveal-wrapper.mode-hard.is-visible > * {
|
|
1598
|
+
opacity: 1;
|
|
1599
|
+
}
|
|
1600
|
+
|
|
1601
|
+
/* Respect reduced motion */
|
|
1602
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1603
|
+
.blur-reveal-wrapper > * {
|
|
1604
|
+
transition-duration: 0.1s !important;
|
|
1605
|
+
transition-delay: 0s !important;
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
/*
|
|
1609
|
+
* Port note: the Svelte source's rules are compiler-scoped. Here every rule is
|
|
1610
|
+
* anchored on the component's own root class `.border-beam` so the `bb-*`
|
|
1611
|
+
* hooks never match outside the component; the dark-theme block reads
|
|
1612
|
+
* `.dark .border-beam` (the Svelte `:global(.dark)` selector).
|
|
1613
|
+
*/
|
|
1614
|
+
|
|
1615
|
+
.border-beam {
|
|
1616
|
+
/* private plumbing: every value reads a public var with a fallback */
|
|
1617
|
+
--_from: var(--border-beam-color-from, #8ec5ff);
|
|
1618
|
+
--_to: var(--border-beam-color-to, #c084fc);
|
|
1619
|
+
--_bw: calc(var(--border-beam-border-width, 1.5) * 1px);
|
|
1620
|
+
--_size: calc(var(--border-beam-size, 200) * 1px);
|
|
1621
|
+
--_dur: var(--border-beam-duration, 9s);
|
|
1622
|
+
--_tail: var(--border-beam-tail, 0.25);
|
|
1623
|
+
--_glow: var(--border-beam-glow, 0.6);
|
|
1624
|
+
--_offset: var(--border-beam-offset, 0s);
|
|
1625
|
+
--_start: calc(var(--border-beam-anchor, 90) * 1%);
|
|
1626
|
+
--_park: var(--border-beam-park, 90%);
|
|
1627
|
+
--_dir: var(--border-beam-dir, 1);
|
|
1628
|
+
--_radius: var(--border-beam-radius, 12px);
|
|
1629
|
+
/* perimeter of the box, read through container units */
|
|
1630
|
+
--_perimeter: calc(2 * (100cqw + 100cqh));
|
|
1631
|
+
|
|
1632
|
+
/* light theme: inks a touch deeper, head warm rather than white, quieter bloom */
|
|
1633
|
+
--_ink-from: color-mix(in oklab, var(--_from) 76%, #0b0b0c);
|
|
1634
|
+
--_ink-to: color-mix(in oklab, var(--_to) 76%, #0b0b0c);
|
|
1635
|
+
--_hot: color-mix(in oklab, var(--_from) 80%, white);
|
|
1636
|
+
--_core: color-mix(in oklab, var(--_ink-from) 70%, white);
|
|
1637
|
+
--_rail: color-mix(in oklab, var(--_ink-from) 6%, transparent);
|
|
1638
|
+
--_bloom-max: 0.7;
|
|
1639
|
+
--_halo-max: 0.7;
|
|
1640
|
+
--_spill-max: 0.16;
|
|
1641
|
+
|
|
1642
|
+
container-type: size;
|
|
1643
|
+
isolation: isolate;
|
|
1644
|
+
}
|
|
1645
|
+
|
|
1646
|
+
.dark .border-beam {
|
|
1647
|
+
--_ink-from: var(--_from);
|
|
1648
|
+
--_ink-to: var(--_to);
|
|
1649
|
+
--_hot: color-mix(in oklab, var(--_from) 40%, white);
|
|
1650
|
+
--_core: white;
|
|
1651
|
+
--_rail: color-mix(in oklab, var(--_from) 7%, transparent);
|
|
1652
|
+
--_bloom-max: 1;
|
|
1653
|
+
--_halo-max: 0.85;
|
|
1654
|
+
--_spill-max: 0.24;
|
|
1655
|
+
}
|
|
1656
|
+
|
|
1657
|
+
.border-beam > *,
|
|
1658
|
+
.border-beam .bb-ring > *,
|
|
1659
|
+
.border-beam .bb-bloom > *,
|
|
1660
|
+
.border-beam .bb-halo > *,
|
|
1661
|
+
.border-beam .bb-spill-clip > * {
|
|
1662
|
+
position: absolute;
|
|
1663
|
+
pointer-events: none;
|
|
1664
|
+
}
|
|
1665
|
+
|
|
1666
|
+
.border-beam .bb-spill-clip,
|
|
1667
|
+
.border-beam .bb-bloom,
|
|
1668
|
+
.border-beam .bb-halo,
|
|
1669
|
+
.border-beam .bb-ring,
|
|
1670
|
+
.border-beam .bb-rail {
|
|
1671
|
+
inset: 0;
|
|
1672
|
+
border-radius: inherit;
|
|
1673
|
+
}
|
|
1674
|
+
|
|
1675
|
+
/* ---------- riders: everything that travels the border ---------- */
|
|
1676
|
+
|
|
1677
|
+
.border-beam .bb-ride {
|
|
1678
|
+
top: 0;
|
|
1679
|
+
left: 0;
|
|
1680
|
+
/* fallback path first, then the box itself with its real radius */
|
|
1681
|
+
offset-path: rect(0 auto auto 0 round var(--_radius));
|
|
1682
|
+
offset-path: border-box;
|
|
1683
|
+
offset-rotate: auto;
|
|
1684
|
+
offset-anchor: 50% 50%;
|
|
1685
|
+
/* rest pose (reduced motion): parked at the anchor, tail laid out behind */
|
|
1686
|
+
offset-distance: calc(var(--_park) - var(--_dir) * var(--_lag, 0) * 100%);
|
|
1687
|
+
--_lag: 0;
|
|
1688
|
+
}
|
|
1689
|
+
|
|
1690
|
+
.border-beam[data-direction="reverse"] .bb-ride {
|
|
1691
|
+
offset-rotate: reverse;
|
|
1692
|
+
}
|
|
1693
|
+
|
|
1694
|
+
.border-beam .bb-piece {
|
|
1695
|
+
--_lag: calc(var(--_tail) * var(--bb-t));
|
|
1696
|
+
/* pieces overlap twice over so the tail reads as one stroke */
|
|
1697
|
+
width: calc(var(--_perimeter) * var(--_tail) / var(--bb-count) * 2.2);
|
|
1698
|
+
}
|
|
1699
|
+
|
|
1700
|
+
/* ---------- the sharp comet on the hairline ---------- */
|
|
1701
|
+
|
|
1702
|
+
.border-beam .bb-ring {
|
|
1703
|
+
padding: var(--_bw);
|
|
1704
|
+
-webkit-mask:
|
|
1705
|
+
linear-gradient(#000 0 0) content-box,
|
|
1706
|
+
linear-gradient(#000 0 0);
|
|
1707
|
+
-webkit-mask-composite: xor;
|
|
1708
|
+
mask:
|
|
1709
|
+
linear-gradient(#000 0 0) content-box,
|
|
1710
|
+
linear-gradient(#000 0 0);
|
|
1711
|
+
mask-composite: exclude;
|
|
1712
|
+
}
|
|
1713
|
+
|
|
1714
|
+
.border-beam .bb-rail {
|
|
1715
|
+
position: absolute;
|
|
1716
|
+
background: var(--_rail);
|
|
1717
|
+
}
|
|
1718
|
+
|
|
1719
|
+
.border-beam .bb-reach {
|
|
1720
|
+
width: var(--_size);
|
|
1721
|
+
height: var(--_size);
|
|
1722
|
+
border-radius: 50%;
|
|
1723
|
+
background: radial-gradient(
|
|
1724
|
+
closest-side,
|
|
1725
|
+
color-mix(in oklab, var(--_hot) 70%, transparent),
|
|
1726
|
+
color-mix(in oklab, var(--_ink-from) 40%, transparent) 45%,
|
|
1727
|
+
transparent
|
|
1728
|
+
);
|
|
1729
|
+
opacity: 0.7;
|
|
1730
|
+
}
|
|
1731
|
+
|
|
1732
|
+
.border-beam .bb-tail-piece {
|
|
1733
|
+
height: calc(var(--_bw) * 2 + 4px);
|
|
1734
|
+
opacity: var(--bb-alpha);
|
|
1735
|
+
background: linear-gradient(
|
|
1736
|
+
90deg,
|
|
1737
|
+
transparent,
|
|
1738
|
+
color-mix(in oklab, var(--_ink-from) calc((1 - var(--bb-t)) * 100%), var(--_ink-to)) 30%,
|
|
1739
|
+
color-mix(in oklab, var(--_ink-from) calc((1 - var(--bb-t)) * 100%), var(--_ink-to)) 70%,
|
|
1740
|
+
transparent
|
|
1741
|
+
);
|
|
1742
|
+
}
|
|
1743
|
+
|
|
1744
|
+
.border-beam .bb-head {
|
|
1745
|
+
width: 44px;
|
|
1746
|
+
height: calc(var(--_bw) * 2 + 4px);
|
|
1747
|
+
offset-anchor: 100% 50%;
|
|
1748
|
+
background: linear-gradient(
|
|
1749
|
+
90deg,
|
|
1750
|
+
transparent,
|
|
1751
|
+
var(--_ink-from) 45%,
|
|
1752
|
+
var(--_hot) 85%,
|
|
1753
|
+
var(--_core)
|
|
1754
|
+
);
|
|
919
1755
|
}
|
|
920
|
-
|
|
921
|
-
|
|
1756
|
+
|
|
1757
|
+
/* ---------- bloom: the comet again, thicker and blurred ---------- */
|
|
1758
|
+
|
|
1759
|
+
.border-beam .bb-bloom {
|
|
1760
|
+
filter: blur(11px);
|
|
1761
|
+
opacity: calc(var(--_glow) * var(--_bloom-max));
|
|
922
1762
|
}
|
|
923
|
-
|
|
924
|
-
|
|
1763
|
+
|
|
1764
|
+
.border-beam .bb-bloom-piece {
|
|
1765
|
+
height: calc(var(--_bw) + 16px * var(--bb-thick));
|
|
1766
|
+
opacity: var(--bb-alpha);
|
|
1767
|
+
border-radius: 999px;
|
|
1768
|
+
background: color-mix(in oklab, var(--_ink-from) calc((1 - var(--bb-t)) * 100%), var(--_ink-to));
|
|
925
1769
|
}
|
|
926
|
-
|
|
927
|
-
|
|
1770
|
+
|
|
1771
|
+
.border-beam .bb-bloom-head {
|
|
1772
|
+
width: 56px;
|
|
1773
|
+
height: 22px;
|
|
1774
|
+
offset-anchor: 85% 50%;
|
|
1775
|
+
border-radius: 50%;
|
|
1776
|
+
background: radial-gradient(closest-side, var(--_hot), var(--_ink-from) 60%, transparent);
|
|
928
1777
|
}
|
|
929
|
-
|
|
930
|
-
|
|
1778
|
+
|
|
1779
|
+
/* ---------- halo: a thin, lightly blurred glow right on the line ---------- */
|
|
1780
|
+
|
|
1781
|
+
.border-beam .bb-halo {
|
|
1782
|
+
filter: blur(2.5px);
|
|
1783
|
+
opacity: calc(var(--_glow) * var(--_halo-max));
|
|
931
1784
|
}
|
|
932
|
-
|
|
933
|
-
|
|
1785
|
+
|
|
1786
|
+
.border-beam .bb-halo-piece {
|
|
1787
|
+
height: calc(var(--_bw) + 5px * var(--bb-thick));
|
|
1788
|
+
opacity: var(--bb-alpha);
|
|
1789
|
+
border-radius: 999px;
|
|
1790
|
+
background: color-mix(in oklab, var(--_ink-from) calc((1 - var(--bb-t)) * 100%), var(--_ink-to));
|
|
934
1791
|
}
|
|
935
|
-
|
|
936
|
-
|
|
1792
|
+
|
|
1793
|
+
/* ---------- inner spill: a wide, faint pool clipped to the inside ---------- */
|
|
1794
|
+
|
|
1795
|
+
.border-beam .bb-spill-clip {
|
|
1796
|
+
overflow: hidden;
|
|
937
1797
|
}
|
|
938
1798
|
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
1799
|
+
.border-beam .bb-spill {
|
|
1800
|
+
width: calc(var(--_size) * 1.3);
|
|
1801
|
+
height: calc(var(--_size) * 1.3);
|
|
1802
|
+
border-radius: 50%;
|
|
1803
|
+
background: radial-gradient(
|
|
1804
|
+
closest-side,
|
|
1805
|
+
color-mix(in oklab, var(--_ink-from) 70%, transparent),
|
|
1806
|
+
color-mix(in oklab, var(--_ink-to) 25%, transparent) 50%,
|
|
1807
|
+
transparent
|
|
1808
|
+
);
|
|
1809
|
+
opacity: calc(var(--_glow) * var(--_spill-max));
|
|
945
1810
|
}
|
|
946
1811
|
|
|
947
|
-
|
|
948
|
-
|
|
1812
|
+
/* ---------- the spark: a tiny white-hot point on the edge ---------- */
|
|
1813
|
+
|
|
1814
|
+
.border-beam .bb-spark {
|
|
1815
|
+
width: calc(var(--_bw) * 2 + 8px);
|
|
1816
|
+
height: calc(var(--_bw) * 2 + 8px);
|
|
1817
|
+
border-radius: 50%;
|
|
1818
|
+
background: radial-gradient(
|
|
1819
|
+
closest-side,
|
|
1820
|
+
var(--_core),
|
|
1821
|
+
var(--_hot) 30%,
|
|
1822
|
+
color-mix(in oklab, var(--_hot) 35%, transparent) 62%,
|
|
1823
|
+
transparent
|
|
1824
|
+
);
|
|
949
1825
|
}
|
|
950
1826
|
|
|
951
|
-
/*
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
1827
|
+
/* ---------- motion ---------- */
|
|
1828
|
+
|
|
1829
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
1830
|
+
.border-beam {
|
|
1831
|
+
/* arrival: the comet fades in over the entrance duration, up to the root's own
|
|
1832
|
+
opacity (no `to` keyframe, no forwards fill), so an opacity class still applies */
|
|
1833
|
+
animation: bb-ignite var(--ft-duration-entrance, 600ms)
|
|
1834
|
+
var(--ft-ease-out, cubic-bezier(0.16, 1, 0.3, 1)) backwards;
|
|
1835
|
+
}
|
|
1836
|
+
|
|
1837
|
+
.border-beam .bb-ride {
|
|
1838
|
+
animation: bb-travel var(--_dur) linear infinite;
|
|
1839
|
+
/* a piece `lag` turns behind the head is started one lap early, minus its lag,
|
|
1840
|
+
so it is already running on the first frame */
|
|
1841
|
+
animation-delay: calc(var(--_offset) - (1 - var(--_lag)) * var(--_dur));
|
|
1842
|
+
}
|
|
1843
|
+
|
|
1844
|
+
.border-beam[data-direction="reverse"] .bb-ride {
|
|
1845
|
+
animation-direction: reverse;
|
|
956
1846
|
}
|
|
957
|
-
}
|
|
958
|
-
.border-beam::after {
|
|
959
|
-
content: "";
|
|
960
|
-
animation: border-beam-animation var(--border-beam-duration) infinite linear;
|
|
961
1847
|
}
|
|
962
1848
|
|
|
963
|
-
@keyframes
|
|
964
|
-
|
|
965
|
-
offset-distance:
|
|
1849
|
+
@keyframes bb-travel {
|
|
1850
|
+
from {
|
|
1851
|
+
offset-distance: var(--_start);
|
|
966
1852
|
}
|
|
967
|
-
|
|
968
|
-
offset-distance: 100
|
|
1853
|
+
to {
|
|
1854
|
+
offset-distance: calc(var(--_start) + 100%);
|
|
1855
|
+
}
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
@keyframes bb-ignite {
|
|
1859
|
+
from {
|
|
1860
|
+
opacity: 0;
|
|
969
1861
|
}
|
|
970
1862
|
}
|
|
971
1863
|
/*
|
|
@@ -1586,6 +2478,224 @@
|
|
|
1586
2478
|
* the left. `transform: scale(…)` alone composes after `translate` and
|
|
1587
2479
|
* scales the panel about its own centre without touching the centring.
|
|
1588
2480
|
*/
|
|
2481
|
+
/*
|
|
2482
|
+
* Compare: the seam as a blade of light.
|
|
2483
|
+
*
|
|
2484
|
+
* Mirrors the <style> block of the reference component. Every rule is
|
|
2485
|
+
* anchored on the root `.compare` class (the reference's own root class),
|
|
2486
|
+
* because plain CSS is global where the reference's rules were compiler-scoped.
|
|
2487
|
+
* Keyframe names, class names and custom properties are kept identical.
|
|
2488
|
+
*/
|
|
2489
|
+
|
|
2490
|
+
@property --cmp-angle {
|
|
2491
|
+
syntax: "<angle>";
|
|
2492
|
+
inherits: false;
|
|
2493
|
+
initial-value: 0deg;
|
|
2494
|
+
}
|
|
2495
|
+
|
|
2496
|
+
.compare:focus-visible {
|
|
2497
|
+
outline: 2px solid var(--cmp-c2);
|
|
2498
|
+
outline-offset: 3px;
|
|
2499
|
+
}
|
|
2500
|
+
|
|
2501
|
+
/* the whole beam screens onto the pictures: light adds, never darkens */
|
|
2502
|
+
.compare .compare-beam {
|
|
2503
|
+
mix-blend-mode: screen;
|
|
2504
|
+
}
|
|
2505
|
+
|
|
2506
|
+
.compare .compare-beam > span {
|
|
2507
|
+
position: absolute;
|
|
2508
|
+
pointer-events: none;
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
/* The light the beam spills on both sides: chromatic, brighter when active. */
|
|
2512
|
+
.compare .compare-beam__glow {
|
|
2513
|
+
top: 0;
|
|
2514
|
+
bottom: 0;
|
|
2515
|
+
left: -70px;
|
|
2516
|
+
width: 140px;
|
|
2517
|
+
background: linear-gradient(
|
|
2518
|
+
to right,
|
|
2519
|
+
transparent,
|
|
2520
|
+
color-mix(in srgb, var(--cmp-c1) 55%, transparent) 38%,
|
|
2521
|
+
var(--cmp-c2) 50%,
|
|
2522
|
+
color-mix(in srgb, var(--cmp-c3) 55%, transparent) 62%,
|
|
2523
|
+
transparent
|
|
2524
|
+
);
|
|
2525
|
+
-webkit-mask: linear-gradient(to bottom, transparent, #000 18%, #000 82%, transparent);
|
|
2526
|
+
mask: linear-gradient(to bottom, transparent, #000 18%, #000 82%, transparent);
|
|
2527
|
+
filter: blur(18px);
|
|
2528
|
+
opacity: calc(0.35 + var(--cmp-energy) * 0.55);
|
|
2529
|
+
}
|
|
2530
|
+
|
|
2531
|
+
/* The trail: stretched out behind the seam by its speed (the sign picks the side). */
|
|
2532
|
+
.compare .compare-beam__trail {
|
|
2533
|
+
top: 12%;
|
|
2534
|
+
bottom: 12%;
|
|
2535
|
+
left: 0;
|
|
2536
|
+
width: 100px;
|
|
2537
|
+
transform-origin: left center;
|
|
2538
|
+
transform: scaleX(calc(var(--cmp-trail) / -100));
|
|
2539
|
+
background: linear-gradient(
|
|
2540
|
+
to right,
|
|
2541
|
+
#fff,
|
|
2542
|
+
var(--cmp-c2) 18%,
|
|
2543
|
+
color-mix(in srgb, var(--cmp-c3) 50%, transparent) 55%,
|
|
2544
|
+
transparent
|
|
2545
|
+
);
|
|
2546
|
+
-webkit-mask: linear-gradient(to bottom, transparent, #000 30%, #000 70%, transparent);
|
|
2547
|
+
mask: linear-gradient(to bottom, transparent, #000 30%, #000 70%, transparent);
|
|
2548
|
+
filter: blur(6px);
|
|
2549
|
+
opacity: 0.75;
|
|
2550
|
+
}
|
|
2551
|
+
|
|
2552
|
+
/* A chromatic fringe either side of the core. */
|
|
2553
|
+
.compare .compare-beam__fringe {
|
|
2554
|
+
top: 0;
|
|
2555
|
+
bottom: 0;
|
|
2556
|
+
left: -4px;
|
|
2557
|
+
width: 9px;
|
|
2558
|
+
background: linear-gradient(
|
|
2559
|
+
to right,
|
|
2560
|
+
var(--cmp-c1),
|
|
2561
|
+
transparent 45%,
|
|
2562
|
+
transparent 55%,
|
|
2563
|
+
var(--cmp-c3)
|
|
2564
|
+
);
|
|
2565
|
+
-webkit-mask: linear-gradient(to bottom, transparent, #000 8%, #000 92%, transparent);
|
|
2566
|
+
mask: linear-gradient(to bottom, transparent, #000 8%, #000 92%, transparent);
|
|
2567
|
+
filter: blur(1.5px);
|
|
2568
|
+
opacity: calc(0.55 + var(--cmp-energy) * 0.45);
|
|
2569
|
+
}
|
|
2570
|
+
|
|
2571
|
+
/* The white-hot core. */
|
|
2572
|
+
.compare .compare-beam__core {
|
|
2573
|
+
top: 0;
|
|
2574
|
+
bottom: 0;
|
|
2575
|
+
left: -0.75px;
|
|
2576
|
+
width: 1.5px;
|
|
2577
|
+
background: linear-gradient(
|
|
2578
|
+
to bottom,
|
|
2579
|
+
transparent,
|
|
2580
|
+
color-mix(in srgb, var(--cmp-c2) 40%, #fff) 6%,
|
|
2581
|
+
#fff 30%,
|
|
2582
|
+
#fff 70%,
|
|
2583
|
+
color-mix(in srgb, var(--cmp-c2) 40%, #fff) 94%,
|
|
2584
|
+
transparent
|
|
2585
|
+
);
|
|
2586
|
+
box-shadow: 0 0 6px 0.5px color-mix(in srgb, var(--cmp-c2) 80%, transparent);
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
/* Pulses of light running down the seam. */
|
|
2590
|
+
.compare .compare-beam__pulse {
|
|
2591
|
+
top: 0;
|
|
2592
|
+
left: -1.5px;
|
|
2593
|
+
width: 3px;
|
|
2594
|
+
height: 26%;
|
|
2595
|
+
border-radius: 999px;
|
|
2596
|
+
background: linear-gradient(to bottom, transparent, #fff 50%, transparent);
|
|
2597
|
+
filter: drop-shadow(0 0 4px var(--cmp-c2)) drop-shadow(0 0 10px var(--cmp-c1));
|
|
2598
|
+
opacity: 0;
|
|
2599
|
+
}
|
|
2600
|
+
|
|
2601
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
2602
|
+
.compare .compare-beam__pulse {
|
|
2603
|
+
animation: cmp-pulse 3.2s cubic-bezier(0.45, 0, 0.55, 1) infinite;
|
|
2604
|
+
}
|
|
2605
|
+
.compare .compare-beam__pulse--late {
|
|
2606
|
+
animation-delay: -1.6s;
|
|
2607
|
+
animation-duration: 3.2s;
|
|
2608
|
+
}
|
|
2609
|
+
.compare[data-active] .compare-beam__pulse {
|
|
2610
|
+
animation-duration: 1.6s;
|
|
2611
|
+
}
|
|
2612
|
+
.compare[data-active] .compare-beam__pulse--late {
|
|
2613
|
+
animation-delay: -0.8s;
|
|
2614
|
+
}
|
|
2615
|
+
.compare .compare-handle__ring {
|
|
2616
|
+
animation: cmp-spin 4s linear infinite;
|
|
2617
|
+
}
|
|
2618
|
+
.compare[data-active] .compare-handle__ring {
|
|
2619
|
+
animation-duration: 1.4s;
|
|
2620
|
+
}
|
|
2621
|
+
}
|
|
2622
|
+
|
|
2623
|
+
@keyframes cmp-pulse {
|
|
2624
|
+
0% {
|
|
2625
|
+
transform: translateY(-100%);
|
|
2626
|
+
opacity: 0;
|
|
2627
|
+
}
|
|
2628
|
+
15% {
|
|
2629
|
+
opacity: 1;
|
|
2630
|
+
}
|
|
2631
|
+
85% {
|
|
2632
|
+
opacity: 1;
|
|
2633
|
+
}
|
|
2634
|
+
100% {
|
|
2635
|
+
transform: translateY(385%);
|
|
2636
|
+
opacity: 0;
|
|
2637
|
+
}
|
|
2638
|
+
}
|
|
2639
|
+
|
|
2640
|
+
/* The handle: a glass bead on the beam with a ring of light round it. */
|
|
2641
|
+
.compare .compare-handle {
|
|
2642
|
+
position: absolute;
|
|
2643
|
+
top: 50%;
|
|
2644
|
+
left: 0;
|
|
2645
|
+
z-index: 30;
|
|
2646
|
+
display: flex;
|
|
2647
|
+
align-items: center;
|
|
2648
|
+
justify-content: center;
|
|
2649
|
+
width: 34px;
|
|
2650
|
+
height: 34px;
|
|
2651
|
+
border-radius: 999px;
|
|
2652
|
+
transform: translate(-50%, -50%) scale(calc(1 + var(--cmp-energy) * 0.08));
|
|
2653
|
+
color: #fff;
|
|
2654
|
+
background: rgb(255 255 255 / 0.12);
|
|
2655
|
+
backdrop-filter: blur(10px) saturate(1.4);
|
|
2656
|
+
-webkit-backdrop-filter: blur(10px) saturate(1.4);
|
|
2657
|
+
box-shadow:
|
|
2658
|
+
inset 0 1px 0 rgb(255 255 255 / 0.35),
|
|
2659
|
+
inset 0 0 0 1px rgb(255 255 255 / 0.18),
|
|
2660
|
+
0 4px 16px rgb(0 0 0 / 0.35),
|
|
2661
|
+
0 0 calc(8px + var(--cmp-energy) * 18px) color-mix(in srgb, var(--cmp-c2) 70%, transparent);
|
|
2662
|
+
cursor: inherit;
|
|
2663
|
+
}
|
|
2664
|
+
|
|
2665
|
+
.compare .compare-handle svg {
|
|
2666
|
+
filter: drop-shadow(0 1px 2px rgb(0 0 0 / 0.45));
|
|
2667
|
+
}
|
|
2668
|
+
|
|
2669
|
+
.compare .compare-handle__ring {
|
|
2670
|
+
position: absolute;
|
|
2671
|
+
inset: -1.5px;
|
|
2672
|
+
border-radius: inherit;
|
|
2673
|
+
padding: 1.5px;
|
|
2674
|
+
background: conic-gradient(
|
|
2675
|
+
from var(--cmp-angle),
|
|
2676
|
+
transparent 0%,
|
|
2677
|
+
var(--cmp-c1) 18%,
|
|
2678
|
+
#fff 30%,
|
|
2679
|
+
var(--cmp-c3) 42%,
|
|
2680
|
+
transparent 58%,
|
|
2681
|
+
transparent 100%
|
|
2682
|
+
);
|
|
2683
|
+
-webkit-mask:
|
|
2684
|
+
linear-gradient(#000 0 0) content-box,
|
|
2685
|
+
linear-gradient(#000 0 0);
|
|
2686
|
+
-webkit-mask-composite: xor;
|
|
2687
|
+
mask:
|
|
2688
|
+
linear-gradient(#000 0 0) content-box,
|
|
2689
|
+
linear-gradient(#000 0 0);
|
|
2690
|
+
mask-composite: exclude;
|
|
2691
|
+
opacity: calc(0.45 + var(--cmp-energy) * 0.55);
|
|
2692
|
+
}
|
|
2693
|
+
|
|
2694
|
+
@keyframes cmp-spin {
|
|
2695
|
+
to {
|
|
2696
|
+
--cmp-angle: 360deg;
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
1589
2699
|
/*
|
|
1590
2700
|
* `.fancy-star-field` is a PORT-ADDED anchor (PORTING.md, styling rule 2).
|
|
1591
2701
|
* The Svelte source has no root class of its own: its compiler scoped `.star`,
|
|
@@ -1889,6 +2999,207 @@
|
|
|
1889
2999
|
transition: background-color 120ms ease;
|
|
1890
3000
|
}
|
|
1891
3001
|
}
|
|
3002
|
+
/*
|
|
3003
|
+
* ContainerScroll — a scroll-driven aperture.
|
|
3004
|
+
* Every rule is anchored on `.cs-root` (the Svelte source's own root class):
|
|
3005
|
+
* the Svelte compiler scoped these selectors, plain CSS is global.
|
|
3006
|
+
*/
|
|
3007
|
+
|
|
3008
|
+
.cs-root {
|
|
3009
|
+
--_accent: var(--cs-accent, #8fb2ff);
|
|
3010
|
+
--_accent-2: var(--cs-accent-2, #c3b1ff);
|
|
3011
|
+
--_core: color-mix(in oklab, var(--_accent) 45%, white);
|
|
3012
|
+
--_radius: 22px;
|
|
3013
|
+
--_glow: 75%;
|
|
3014
|
+
--_frame: #f4f4f5;
|
|
3015
|
+
--_frame-line: rgba(0, 0, 0, 0.08);
|
|
3016
|
+
--_surface: #fafafa;
|
|
3017
|
+
--_surface-line: rgba(0, 0, 0, 0.07);
|
|
3018
|
+
--_shadow:
|
|
3019
|
+
0 1px 2px rgba(0, 0, 0, 0.04), 0 12px 28px -12px rgba(0, 0, 0, 0.12),
|
|
3020
|
+
0 40px 80px -40px rgba(0, 0, 0, 0.22);
|
|
3021
|
+
/* 1 → closed slit (48% top + 48% bottom), 0 → fully open */
|
|
3022
|
+
--_shut: calc(1 - var(--cs-open, 0));
|
|
3023
|
+
}
|
|
3024
|
+
|
|
3025
|
+
.dark .cs-root {
|
|
3026
|
+
--_glow: 60%;
|
|
3027
|
+
--_frame: #0f0f10;
|
|
3028
|
+
--_frame-line: rgba(255, 255, 255, 0.08);
|
|
3029
|
+
--_surface: #0b0b0c;
|
|
3030
|
+
--_surface-line: rgba(255, 255, 255, 0.07);
|
|
3031
|
+
--_shadow:
|
|
3032
|
+
0 1px 0 rgba(255, 255, 255, 0.03) inset, 0 20px 50px -24px rgba(0, 0, 0, 0.9),
|
|
3033
|
+
0 60px 120px -60px rgba(0, 0, 0, 0.8);
|
|
3034
|
+
}
|
|
3035
|
+
|
|
3036
|
+
/* Title: hands the stage over by going out of focus */
|
|
3037
|
+
.cs-root .cs-title {
|
|
3038
|
+
/* starts only once the aperture is a quarter open */
|
|
3039
|
+
--_fade: clamp(0, (var(--cs-progress, 0) - 0.25) / 0.75, 1);
|
|
3040
|
+
opacity: calc(1 - var(--_fade) * 0.85);
|
|
3041
|
+
filter: blur(calc(var(--_fade) * 6px));
|
|
3042
|
+
transform: scale(calc(1 - var(--_fade) * 0.02));
|
|
3043
|
+
transform-origin: 50% 100%;
|
|
3044
|
+
}
|
|
3045
|
+
|
|
3046
|
+
.cs-root .cs-stage {
|
|
3047
|
+
transform: translateY(calc(var(--_shut) * 24px));
|
|
3048
|
+
}
|
|
3049
|
+
|
|
3050
|
+
.cs-root .cs-shadow {
|
|
3051
|
+
border-radius: var(--_radius);
|
|
3052
|
+
box-shadow: var(--_shadow);
|
|
3053
|
+
/* follows the opening so it never outlines the still-hidden card */
|
|
3054
|
+
transform: scaleY(calc(1 - var(--_shut) * 0.96));
|
|
3055
|
+
opacity: calc(var(--cs-open, 0) * var(--cs-open, 0));
|
|
3056
|
+
}
|
|
3057
|
+
|
|
3058
|
+
.cs-root .cs-card {
|
|
3059
|
+
border-radius: var(--_radius);
|
|
3060
|
+
background: var(--_frame);
|
|
3061
|
+
border: 1px solid var(--_frame-line);
|
|
3062
|
+
clip-path: inset(calc(var(--_shut) * 48%) 0 calc(var(--_shut) * 48%) 0 round var(--_radius));
|
|
3063
|
+
}
|
|
3064
|
+
|
|
3065
|
+
.cs-root .cs-surface {
|
|
3066
|
+
border-radius: calc(var(--_radius) - 7px);
|
|
3067
|
+
background: var(--_surface);
|
|
3068
|
+
box-shadow: 0 0 0 1px var(--_surface-line);
|
|
3069
|
+
}
|
|
3070
|
+
|
|
3071
|
+
.cs-root .cs-content {
|
|
3072
|
+
transform: scale(calc(1 + var(--_shut) * 0.08));
|
|
3073
|
+
transform-origin: 50% 50%;
|
|
3074
|
+
}
|
|
3075
|
+
|
|
3076
|
+
/* ---- Light ---------------------------------------------------------- */
|
|
3077
|
+
|
|
3078
|
+
.cs-root .cs-seam {
|
|
3079
|
+
left: 4%;
|
|
3080
|
+
right: 4%;
|
|
3081
|
+
top: 50%;
|
|
3082
|
+
height: 0;
|
|
3083
|
+
opacity: calc(1 - var(--cs-progress, 0) * 3);
|
|
3084
|
+
}
|
|
3085
|
+
|
|
3086
|
+
.cs-root .cs-seam-line,
|
|
3087
|
+
.cs-root .cs-seam-glow,
|
|
3088
|
+
.cs-root .cs-seam-haze {
|
|
3089
|
+
position: absolute;
|
|
3090
|
+
left: 0;
|
|
3091
|
+
right: 0;
|
|
3092
|
+
top: 0;
|
|
3093
|
+
border-radius: 999px;
|
|
3094
|
+
}
|
|
3095
|
+
|
|
3096
|
+
.cs-root .cs-seam-line {
|
|
3097
|
+
height: 1px;
|
|
3098
|
+
transform: translateY(-50%);
|
|
3099
|
+
background: linear-gradient(
|
|
3100
|
+
90deg,
|
|
3101
|
+
transparent,
|
|
3102
|
+
color-mix(in oklab, var(--_accent-2) 70%, transparent) 14%,
|
|
3103
|
+
var(--_accent) 34%,
|
|
3104
|
+
var(--_core) 50%,
|
|
3105
|
+
var(--_accent) 66%,
|
|
3106
|
+
color-mix(in oklab, var(--_accent-2) 70%, transparent) 86%,
|
|
3107
|
+
transparent
|
|
3108
|
+
);
|
|
3109
|
+
box-shadow: 0 0 6px 0 color-mix(in oklab, var(--_accent) 60%, transparent);
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3112
|
+
.cs-root .cs-seam-glow {
|
|
3113
|
+
height: 28px;
|
|
3114
|
+
transform: translateY(-50%);
|
|
3115
|
+
background: radial-gradient(
|
|
3116
|
+
50% 50% at 50% 50%,
|
|
3117
|
+
color-mix(in oklab, var(--_accent) var(--_glow), transparent),
|
|
3118
|
+
color-mix(in oklab, var(--_accent-2) 25%, transparent) 60%,
|
|
3119
|
+
transparent 100%
|
|
3120
|
+
);
|
|
3121
|
+
filter: blur(10px);
|
|
3122
|
+
}
|
|
3123
|
+
|
|
3124
|
+
/* a wide, faint horizon of light spilling past the slit */
|
|
3125
|
+
.cs-root .cs-seam-haze {
|
|
3126
|
+
left: -6%;
|
|
3127
|
+
right: -6%;
|
|
3128
|
+
height: 90px;
|
|
3129
|
+
transform: translateY(-50%);
|
|
3130
|
+
background: radial-gradient(
|
|
3131
|
+
50% 50% at 50% 50%,
|
|
3132
|
+
color-mix(in oklab, var(--_accent) calc(var(--_glow) * 0.45), transparent),
|
|
3133
|
+
transparent 70%
|
|
3134
|
+
);
|
|
3135
|
+
filter: blur(18px);
|
|
3136
|
+
}
|
|
3137
|
+
|
|
3138
|
+
.cs-root .cs-veil {
|
|
3139
|
+
background: var(--_surface);
|
|
3140
|
+
opacity: calc(var(--_shut) * var(--_shut) * 0.75);
|
|
3141
|
+
}
|
|
3142
|
+
|
|
3143
|
+
.cs-root .cs-lip {
|
|
3144
|
+
left: 3%;
|
|
3145
|
+
right: 3%;
|
|
3146
|
+
height: 1px;
|
|
3147
|
+
background: linear-gradient(
|
|
3148
|
+
90deg,
|
|
3149
|
+
transparent,
|
|
3150
|
+
color-mix(in oklab, var(--_accent-2) 55%, transparent) 20%,
|
|
3151
|
+
color-mix(in oklab, var(--_accent) 80%, white) 50%,
|
|
3152
|
+
color-mix(in oklab, var(--_accent-2) 55%, transparent) 80%,
|
|
3153
|
+
transparent
|
|
3154
|
+
);
|
|
3155
|
+
box-shadow: 0 0 10px 0 color-mix(in oklab, var(--_accent) 45%, transparent);
|
|
3156
|
+
opacity: var(--_shut);
|
|
3157
|
+
}
|
|
3158
|
+
|
|
3159
|
+
.cs-root .cs-lip-top {
|
|
3160
|
+
top: calc(var(--_shut) * 48%);
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
.cs-root .cs-lip-bottom {
|
|
3164
|
+
bottom: calc(var(--_shut) * 48%);
|
|
3165
|
+
}
|
|
3166
|
+
|
|
3167
|
+
/* Light theme: a white core vanishes on a pale page, so deepen the seam */
|
|
3168
|
+
html:not(.dark) .cs-root {
|
|
3169
|
+
--_core: color-mix(in oklab, var(--_accent) 75%, white);
|
|
3170
|
+
}
|
|
3171
|
+
|
|
3172
|
+
/* Reduced motion: a still frame — card open, title sharp, no light */
|
|
3173
|
+
.cs-root[data-reduced-motion] {
|
|
3174
|
+
--_shut: 0;
|
|
3175
|
+
}
|
|
3176
|
+
.cs-root[data-reduced-motion] .cs-title {
|
|
3177
|
+
opacity: 1;
|
|
3178
|
+
filter: none;
|
|
3179
|
+
transform: none;
|
|
3180
|
+
}
|
|
3181
|
+
.cs-root[data-reduced-motion] .cs-seam,
|
|
3182
|
+
.cs-root[data-reduced-motion] .cs-lip {
|
|
3183
|
+
display: none;
|
|
3184
|
+
}
|
|
3185
|
+
|
|
3186
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3187
|
+
.cs-root {
|
|
3188
|
+
--_shut: 0;
|
|
3189
|
+
}
|
|
3190
|
+
.cs-root .cs-title {
|
|
3191
|
+
opacity: 1;
|
|
3192
|
+
filter: none;
|
|
3193
|
+
transform: none;
|
|
3194
|
+
}
|
|
3195
|
+
.cs-root .cs-seam,
|
|
3196
|
+
.cs-root .cs-lip {
|
|
3197
|
+
display: none;
|
|
3198
|
+
}
|
|
3199
|
+
.cs-root .cs-shadow {
|
|
3200
|
+
opacity: 1;
|
|
3201
|
+
}
|
|
3202
|
+
}
|
|
1892
3203
|
/* Keyframe names are part of the visual contract — keep them identical to
|
|
1893
3204
|
the source. */
|
|
1894
3205
|
@keyframes text-flip-in {
|
|
@@ -2468,6 +3779,243 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
2468
3779
|
transition-duration: 0.1s !important;
|
|
2469
3780
|
}
|
|
2470
3781
|
}
|
|
3782
|
+
/*
|
|
3783
|
+
* Dock shelf. Mirrors the Svelte <style> block of Dock.svelte rule for rule.
|
|
3784
|
+
* The Svelte compiler scoped every selector; here each one is anchored on the
|
|
3785
|
+
* source's own root class `.dock-shelf`, so no generic name leaks into the page.
|
|
3786
|
+
*/
|
|
3787
|
+
|
|
3788
|
+
/* Theme hooks. Every private var reads a public one first, so a consumer
|
|
3789
|
+
can recolour the light from a class without touching this file. */
|
|
3790
|
+
.dock-shelf {
|
|
3791
|
+
--_dock-accent: var(--dock-accent, var(--primary, #71717a));
|
|
3792
|
+
--_dock-spot-size: var(--dock-spotlight-size, 140px);
|
|
3793
|
+
--_dock-frame: var(--dock-frame-color, rgba(0, 0, 0, 0.05));
|
|
3794
|
+
--_dock-core: color-mix(in oklab, var(--_dock-accent) 45%, white);
|
|
3795
|
+
--_dock-ease: var(--ft-ease-out, cubic-bezier(0.16, 1, 0.3, 1));
|
|
3796
|
+
outline: none;
|
|
3797
|
+
}
|
|
3798
|
+
.dark .dock-shelf {
|
|
3799
|
+
--_dock-frame: var(--dock-frame-color, rgba(255, 255, 255, 0.045));
|
|
3800
|
+
}
|
|
3801
|
+
|
|
3802
|
+
.dock-shelf:focus-visible {
|
|
3803
|
+
outline: 2px solid color-mix(in oklab, var(--_dock-accent) 55%, transparent);
|
|
3804
|
+
outline-offset: 3px;
|
|
3805
|
+
}
|
|
3806
|
+
|
|
3807
|
+
/* Decorative stack: clipped to the shelf, painted under the icons. The
|
|
3808
|
+
icons are not clipped — they are siblings, above this layer. */
|
|
3809
|
+
.dock-shelf .dock-deco {
|
|
3810
|
+
position: absolute;
|
|
3811
|
+
inset: -1px;
|
|
3812
|
+
z-index: 0;
|
|
3813
|
+
overflow: hidden;
|
|
3814
|
+
border-radius: inherit;
|
|
3815
|
+
pointer-events: none;
|
|
3816
|
+
}
|
|
3817
|
+
|
|
3818
|
+
/* The nested inner frame: a second hairline just inside the shelf edge,
|
|
3819
|
+
with a faint top-lit fill. */
|
|
3820
|
+
.dock-shelf .dock-frame {
|
|
3821
|
+
position: absolute;
|
|
3822
|
+
inset: 4px;
|
|
3823
|
+
border: 1px solid var(--_dock-frame);
|
|
3824
|
+
border-radius: calc(1rem - 4px);
|
|
3825
|
+
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.5), transparent 60%);
|
|
3826
|
+
}
|
|
3827
|
+
.dark .dock-shelf .dock-frame {
|
|
3828
|
+
background: linear-gradient(to bottom, rgba(255, 255, 255, 0.025), transparent 60%);
|
|
3829
|
+
}
|
|
3830
|
+
|
|
3831
|
+
/* The spotlight: a blurred pool of accent light with a white-hot core,
|
|
3832
|
+
moved by transform only. Light theme lays a thin tint of the accent
|
|
3833
|
+
into the glass; dark theme screens light onto it. */
|
|
3834
|
+
.dock-shelf .dock-spot {
|
|
3835
|
+
position: absolute;
|
|
3836
|
+
left: 0;
|
|
3837
|
+
top: 0;
|
|
3838
|
+
width: var(--_dock-spot-size);
|
|
3839
|
+
height: var(--_dock-spot-size);
|
|
3840
|
+
border-radius: 50%;
|
|
3841
|
+
background: radial-gradient(
|
|
3842
|
+
closest-side,
|
|
3843
|
+
color-mix(in oklab, var(--_dock-accent) 20%, transparent) 0%,
|
|
3844
|
+
color-mix(in oklab, var(--_dock-accent) 8%, transparent) 45%,
|
|
3845
|
+
transparent 100%
|
|
3846
|
+
);
|
|
3847
|
+
filter: blur(10px);
|
|
3848
|
+
opacity: 0;
|
|
3849
|
+
transform: translate(calc(var(--dock-x) - 50%), calc(var(--dock-y) - 50%));
|
|
3850
|
+
will-change: transform, opacity;
|
|
3851
|
+
}
|
|
3852
|
+
.dark .dock-shelf .dock-spot {
|
|
3853
|
+
background: radial-gradient(
|
|
3854
|
+
closest-side,
|
|
3855
|
+
color-mix(in oklab, var(--_dock-core) 50%, transparent) 0%,
|
|
3856
|
+
color-mix(in oklab, var(--_dock-accent) 20%, transparent) 45%,
|
|
3857
|
+
transparent 100%
|
|
3858
|
+
);
|
|
3859
|
+
mix-blend-mode: screen;
|
|
3860
|
+
}
|
|
3861
|
+
|
|
3862
|
+
/* The lit rim: a 1px ring (padding + mask) holding one blurred blob that
|
|
3863
|
+
rides the same transform, so the shelf edge brightens only near the
|
|
3864
|
+
pointer. */
|
|
3865
|
+
.dock-shelf .dock-rim {
|
|
3866
|
+
position: absolute;
|
|
3867
|
+
inset: 0;
|
|
3868
|
+
padding: 1px;
|
|
3869
|
+
border-radius: inherit;
|
|
3870
|
+
-webkit-mask:
|
|
3871
|
+
linear-gradient(#000 0 0) content-box,
|
|
3872
|
+
linear-gradient(#000 0 0);
|
|
3873
|
+
-webkit-mask-composite: xor;
|
|
3874
|
+
mask:
|
|
3875
|
+
linear-gradient(#000 0 0) content-box exclude,
|
|
3876
|
+
linear-gradient(#000 0 0);
|
|
3877
|
+
opacity: 0;
|
|
3878
|
+
}
|
|
3879
|
+
.dock-shelf .dock-rim-light {
|
|
3880
|
+
position: absolute;
|
|
3881
|
+
left: 0;
|
|
3882
|
+
top: 0;
|
|
3883
|
+
width: 220px;
|
|
3884
|
+
height: 96px;
|
|
3885
|
+
border-radius: 50%;
|
|
3886
|
+
background: radial-gradient(
|
|
3887
|
+
closest-side,
|
|
3888
|
+
color-mix(in oklab, var(--_dock-accent) 70%, transparent),
|
|
3889
|
+
transparent
|
|
3890
|
+
);
|
|
3891
|
+
transform: translate(calc(var(--dock-x) - 50%), calc(var(--dock-y) - 50%));
|
|
3892
|
+
}
|
|
3893
|
+
.dark .dock-shelf .dock-rim-light {
|
|
3894
|
+
background: radial-gradient(closest-side, var(--_dock-core), transparent);
|
|
3895
|
+
}
|
|
3896
|
+
|
|
3897
|
+
.dock-shelf[data-hover] .dock-spot {
|
|
3898
|
+
opacity: 1;
|
|
3899
|
+
}
|
|
3900
|
+
.dock-shelf[data-hover] .dock-rim {
|
|
3901
|
+
opacity: 0.9;
|
|
3902
|
+
}
|
|
3903
|
+
|
|
3904
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
3905
|
+
.dock-shelf .dock-spot {
|
|
3906
|
+
transition:
|
|
3907
|
+
transform 140ms var(--_dock-ease),
|
|
3908
|
+
opacity 300ms var(--_dock-ease);
|
|
3909
|
+
}
|
|
3910
|
+
.dock-shelf .dock-rim-light {
|
|
3911
|
+
transition: transform 140ms var(--_dock-ease);
|
|
3912
|
+
}
|
|
3913
|
+
.dock-shelf .dock-rim {
|
|
3914
|
+
transition: opacity 300ms var(--_dock-ease);
|
|
3915
|
+
}
|
|
3916
|
+
}
|
|
3917
|
+
|
|
3918
|
+
/* Reduced motion: the light holds still, dim and centred, whether or not a
|
|
3919
|
+
pointer is over the dock — the same composition as a resting frame. */
|
|
3920
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3921
|
+
.dock-shelf .dock-spot,
|
|
3922
|
+
.dock-shelf[data-hover] .dock-spot {
|
|
3923
|
+
left: 50%;
|
|
3924
|
+
top: 50%;
|
|
3925
|
+
transform: translate(-50%, -50%);
|
|
3926
|
+
opacity: 0.55;
|
|
3927
|
+
}
|
|
3928
|
+
.dock-shelf .dock-rim,
|
|
3929
|
+
.dock-shelf[data-hover] .dock-rim {
|
|
3930
|
+
opacity: 0;
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
|
|
3934
|
+
/* Nothing can hover: no light to follow. */
|
|
3935
|
+
@media (any-hover: none) {
|
|
3936
|
+
.dock-shelf .dock-spot,
|
|
3937
|
+
.dock-shelf .dock-rim {
|
|
3938
|
+
display: none;
|
|
3939
|
+
}
|
|
3940
|
+
}
|
|
3941
|
+
/*
|
|
3942
|
+
* Dock icon. Mirrors the Svelte <style> block of DockIcon.svelte rule for
|
|
3943
|
+
* rule, anchored on the source's own root class `.dock-icon`.
|
|
3944
|
+
*/
|
|
3945
|
+
.dock-icon {
|
|
3946
|
+
--_dock-accent: var(--dock-accent, var(--primary, #71717a));
|
|
3947
|
+
--_dock-ease: var(--ft-ease-out, cubic-bezier(0.16, 1, 0.3, 1));
|
|
3948
|
+
}
|
|
3949
|
+
|
|
3950
|
+
/* Indicator dot: below the icon on a horizontal dock, beside it on a
|
|
3951
|
+
vertical one. Hidden until the icon is the one under the pointer. */
|
|
3952
|
+
.dock-icon::before {
|
|
3953
|
+
content: "";
|
|
3954
|
+
position: absolute;
|
|
3955
|
+
left: 50%;
|
|
3956
|
+
top: calc(100% + 4px);
|
|
3957
|
+
width: 4px;
|
|
3958
|
+
height: 4px;
|
|
3959
|
+
margin-left: -2px;
|
|
3960
|
+
border-radius: 9999px;
|
|
3961
|
+
background: var(--_dock-accent);
|
|
3962
|
+
opacity: 0;
|
|
3963
|
+
pointer-events: none;
|
|
3964
|
+
}
|
|
3965
|
+
.dark .dock-icon::before {
|
|
3966
|
+
background: color-mix(in oklab, var(--_dock-accent) 45%, white);
|
|
3967
|
+
box-shadow: 0 0 6px 1px color-mix(in oklab, var(--_dock-accent) 55%, transparent);
|
|
3968
|
+
}
|
|
3969
|
+
.dock-icon[data-orientation="vertical"]::before {
|
|
3970
|
+
left: auto;
|
|
3971
|
+
right: calc(100% + 4px);
|
|
3972
|
+
top: 50%;
|
|
3973
|
+
margin-left: 0;
|
|
3974
|
+
margin-top: -2px;
|
|
3975
|
+
}
|
|
3976
|
+
.dock-icon[data-dock-active]::before {
|
|
3977
|
+
opacity: 1;
|
|
3978
|
+
}
|
|
3979
|
+
|
|
3980
|
+
/* Floor reflection: a soft ellipse under the icon — a contact shadow on
|
|
3981
|
+
the light shelf, a faint glow on the dark one. Sized in percent, so it
|
|
3982
|
+
grows with the magnified icon for free. */
|
|
3983
|
+
.dock-icon[data-reflection]::after {
|
|
3984
|
+
content: "";
|
|
3985
|
+
position: absolute;
|
|
3986
|
+
left: 14%;
|
|
3987
|
+
right: 14%;
|
|
3988
|
+
top: calc(100% - 4px);
|
|
3989
|
+
height: 22%;
|
|
3990
|
+
border-radius: 50%;
|
|
3991
|
+
background: radial-gradient(closest-side, rgba(0, 0, 0, 0.22), transparent);
|
|
3992
|
+
filter: blur(3px);
|
|
3993
|
+
opacity: 0.7;
|
|
3994
|
+
z-index: -1;
|
|
3995
|
+
pointer-events: none;
|
|
3996
|
+
}
|
|
3997
|
+
.dark .dock-icon[data-reflection]::after {
|
|
3998
|
+
background: radial-gradient(
|
|
3999
|
+
closest-side,
|
|
4000
|
+
color-mix(in oklab, var(--_dock-accent) 26%, transparent),
|
|
4001
|
+
transparent
|
|
4002
|
+
);
|
|
4003
|
+
}
|
|
4004
|
+
.dock-icon[data-reflection][data-dock-active]::after {
|
|
4005
|
+
opacity: 1;
|
|
4006
|
+
}
|
|
4007
|
+
|
|
4008
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
4009
|
+
.dock-icon {
|
|
4010
|
+
transition:
|
|
4011
|
+
width 180ms var(--_dock-ease),
|
|
4012
|
+
height 180ms var(--_dock-ease);
|
|
4013
|
+
}
|
|
4014
|
+
.dock-icon::before,
|
|
4015
|
+
.dock-icon[data-reflection]::after {
|
|
4016
|
+
transition: opacity 180ms var(--_dock-ease);
|
|
4017
|
+
}
|
|
4018
|
+
}
|
|
2471
4019
|
/*
|
|
2472
4020
|
* The `<style>` block of the source Drawer, moved to a colocated stylesheet
|
|
2473
4021
|
* (PORTING.md §Styling rule 2). The compiler scoped that block; plain CSS is
|
|
@@ -2763,6 +4311,156 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
2763
4311
|
opacity: 0.5;
|
|
2764
4312
|
cursor: not-allowed;
|
|
2765
4313
|
}
|
|
4314
|
+
/*
|
|
4315
|
+
* FlipCard — ported verbatim from the Svelte <style> block. Every rule is
|
|
4316
|
+
* anchored on the root class `.ft-flip-card`, which the Svelte source already
|
|
4317
|
+
* names, so nothing leaks once the compiler-scoped rules become global.
|
|
4318
|
+
*/
|
|
4319
|
+
|
|
4320
|
+
/* The one number everything turns on: the card's rotation. Registered so
|
|
4321
|
+
it can transition, and inherited so the faces can light themselves
|
|
4322
|
+
from it. */
|
|
4323
|
+
@property --fc-angle {
|
|
4324
|
+
syntax: "<angle>";
|
|
4325
|
+
inherits: true;
|
|
4326
|
+
initial-value: 0deg;
|
|
4327
|
+
}
|
|
4328
|
+
|
|
4329
|
+
.ft-flip-card {
|
|
4330
|
+
--fc-angle: var(--fc-target);
|
|
4331
|
+
outline: none;
|
|
4332
|
+
-webkit-tap-highlight-color: transparent;
|
|
4333
|
+
}
|
|
4334
|
+
|
|
4335
|
+
.ft-flip-card:focus-visible .ft-flip-card__inner {
|
|
4336
|
+
box-shadow: 0 0 0 3px color-mix(in oklab, var(--color-ring, #888) 60%, transparent);
|
|
4337
|
+
}
|
|
4338
|
+
|
|
4339
|
+
.ft-flip-card[data-trigger="click"] {
|
|
4340
|
+
cursor: pointer;
|
|
4341
|
+
}
|
|
4342
|
+
|
|
4343
|
+
.ft-flip-card__lift,
|
|
4344
|
+
.ft-flip-card__inner {
|
|
4345
|
+
position: relative;
|
|
4346
|
+
}
|
|
4347
|
+
|
|
4348
|
+
.ft-flip-card[data-axis="y"] .ft-flip-card__inner {
|
|
4349
|
+
transform: rotateY(var(--fc-angle));
|
|
4350
|
+
}
|
|
4351
|
+
|
|
4352
|
+
.ft-flip-card[data-axis="x"] .ft-flip-card__inner {
|
|
4353
|
+
transform: rotateX(var(--fc-angle));
|
|
4354
|
+
}
|
|
4355
|
+
|
|
4356
|
+
.ft-flip-card[data-axis="y"] .ft-flip-card__back {
|
|
4357
|
+
transform: rotateY(180deg);
|
|
4358
|
+
}
|
|
4359
|
+
|
|
4360
|
+
.ft-flip-card[data-axis="x"] .ft-flip-card__back {
|
|
4361
|
+
transform: rotateX(180deg);
|
|
4362
|
+
}
|
|
4363
|
+
|
|
4364
|
+
/* The shadow on the "table" under the card. */
|
|
4365
|
+
.ft-flip-card__shadow {
|
|
4366
|
+
position: absolute;
|
|
4367
|
+
inset: 8% 6% -4%;
|
|
4368
|
+
border-radius: 1.25rem;
|
|
4369
|
+
background: rgb(0 0 0 / 0.9);
|
|
4370
|
+
opacity: 0.35;
|
|
4371
|
+
transform: translateY(10px) scale(0.92);
|
|
4372
|
+
filter: blur(14px);
|
|
4373
|
+
pointer-events: none;
|
|
4374
|
+
}
|
|
4375
|
+
|
|
4376
|
+
/* ---- light: off unless the browser can compute it ---------------------- */
|
|
4377
|
+
|
|
4378
|
+
.ft-flip-card__light {
|
|
4379
|
+
display: none;
|
|
4380
|
+
}
|
|
4381
|
+
|
|
4382
|
+
@supports (opacity: calc(sin(30deg))) {
|
|
4383
|
+
.ft-flip-card__face {
|
|
4384
|
+
/* the face's own turn: the back starts half a turn round */
|
|
4385
|
+
--fc-face: var(--fc-angle);
|
|
4386
|
+
/* |sin| — 0 facing you, 1 edge-on */
|
|
4387
|
+
--fc-edge: max(sin(var(--fc-face)), -1 * sin(var(--fc-face)));
|
|
4388
|
+
}
|
|
4389
|
+
|
|
4390
|
+
.ft-flip-card__back {
|
|
4391
|
+
--fc-face: calc(var(--fc-angle) + 180deg);
|
|
4392
|
+
}
|
|
4393
|
+
|
|
4394
|
+
.ft-flip-card__light {
|
|
4395
|
+
display: block;
|
|
4396
|
+
position: absolute;
|
|
4397
|
+
inset: 0;
|
|
4398
|
+
pointer-events: none;
|
|
4399
|
+
border-radius: inherit;
|
|
4400
|
+
/* a sheen that sweeps across as the face turns, over a shade that
|
|
4401
|
+
deepens as the face goes edge-on */
|
|
4402
|
+
background:
|
|
4403
|
+
linear-gradient(
|
|
4404
|
+
var(--fc-sheen-angle, 105deg),
|
|
4405
|
+
transparent 38%,
|
|
4406
|
+
rgb(255 255 255 / 0.55) 50%,
|
|
4407
|
+
transparent 62%
|
|
4408
|
+
),
|
|
4409
|
+
rgb(0 0 0 / calc(var(--fc-edge) * 0.55));
|
|
4410
|
+
background-size:
|
|
4411
|
+
300% 300%,
|
|
4412
|
+
100% 100%;
|
|
4413
|
+
background-repeat: no-repeat;
|
|
4414
|
+
background-position:
|
|
4415
|
+
calc(50% - sin(var(--fc-face)) * 45%) calc(50% - sin(var(--fc-face)) * 45%),
|
|
4416
|
+
0 0;
|
|
4417
|
+
}
|
|
4418
|
+
|
|
4419
|
+
/* the sheen is brightest part-way round, never facing you or edge-on */
|
|
4420
|
+
.ft-flip-card__light {
|
|
4421
|
+
opacity: calc(min(1, var(--fc-edge) * 2.4));
|
|
4422
|
+
}
|
|
4423
|
+
|
|
4424
|
+
.ft-flip-card[data-axis="x"] .ft-flip-card__light {
|
|
4425
|
+
--fc-sheen-angle: 15deg;
|
|
4426
|
+
}
|
|
4427
|
+
}
|
|
4428
|
+
|
|
4429
|
+
/* ---- motion ---------------------------------------------------------------- */
|
|
4430
|
+
|
|
4431
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
4432
|
+
.ft-flip-card {
|
|
4433
|
+
/* a slight overshoot, so the card lands rather than stops */
|
|
4434
|
+
transition: --fc-angle var(--fc-duration) cubic-bezier(0.34, 1.25, 0.64, 1);
|
|
4435
|
+
}
|
|
4436
|
+
}
|
|
4437
|
+
|
|
4438
|
+
/* Reduced motion: no turning at all — the faces cross-fade in place. */
|
|
4439
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4440
|
+
/* as specific as the axis rules above, and later, so it wins */
|
|
4441
|
+
.ft-flip-card[data-axis] .ft-flip-card__inner,
|
|
4442
|
+
.ft-flip-card[data-axis] .ft-flip-card__back {
|
|
4443
|
+
transform: none;
|
|
4444
|
+
}
|
|
4445
|
+
|
|
4446
|
+
.ft-flip-card__face {
|
|
4447
|
+
transition: opacity 0.2s ease;
|
|
4448
|
+
}
|
|
4449
|
+
|
|
4450
|
+
.ft-flip-card__front,
|
|
4451
|
+
.ft-flip-card[data-flipped] .ft-flip-card__back {
|
|
4452
|
+
opacity: 1;
|
|
4453
|
+
}
|
|
4454
|
+
|
|
4455
|
+
.ft-flip-card__back,
|
|
4456
|
+
.ft-flip-card[data-flipped] .ft-flip-card__front {
|
|
4457
|
+
opacity: 0;
|
|
4458
|
+
}
|
|
4459
|
+
|
|
4460
|
+
.ft-flip-card__light {
|
|
4461
|
+
display: none;
|
|
4462
|
+
}
|
|
4463
|
+
}
|
|
2766
4464
|
/* Keyframe names are part of the visual contract (referenced by inline
|
|
2767
4465
|
style attributes) — keep them identical to the source. */
|
|
2768
4466
|
@keyframes flipFadeInWord {
|
|
@@ -3064,56 +4762,222 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
3064
4762
|
var(--bg-x) var(--bg-y) / 300% no-repeat;
|
|
3065
4763
|
background-blend-mode: hue, hue, hue, overlay;
|
|
3066
4764
|
}
|
|
3067
|
-
@
|
|
3068
|
-
|
|
3069
|
-
|
|
4765
|
+
@property --gb-a1 {
|
|
4766
|
+
syntax: "<angle>";
|
|
4767
|
+
inherits: true;
|
|
4768
|
+
initial-value: 0deg;
|
|
4769
|
+
}
|
|
4770
|
+
|
|
4771
|
+
@property --gb-a2 {
|
|
4772
|
+
syntax: "<angle>";
|
|
4773
|
+
inherits: true;
|
|
4774
|
+
initial-value: 120deg;
|
|
4775
|
+
}
|
|
4776
|
+
|
|
4777
|
+
@property --gb-a3 {
|
|
4778
|
+
syntax: "<angle>";
|
|
4779
|
+
inherits: true;
|
|
4780
|
+
initial-value: 0deg;
|
|
4781
|
+
}
|
|
4782
|
+
|
|
4783
|
+
/* Light pages get the deeper palette; `.dark` switches to the bright one. */
|
|
4784
|
+
.glow-border {
|
|
4785
|
+
--gb-metal: var(--gb-metal-light);
|
|
4786
|
+
--gb-glint: var(--gb-glint-light);
|
|
4787
|
+
/* on a light page a coloured halo reads as fog: keep it faint */
|
|
4788
|
+
--gb-halo-opacity: 0.35;
|
|
4789
|
+
}
|
|
4790
|
+
|
|
4791
|
+
.dark .glow-border {
|
|
4792
|
+
--gb-metal: var(--gb-metal-dark);
|
|
4793
|
+
--gb-glint: var(--gb-glint-dark);
|
|
4794
|
+
--gb-halo-opacity: 0.7;
|
|
4795
|
+
}
|
|
4796
|
+
|
|
4797
|
+
.glow-border > span,
|
|
4798
|
+
.glow-border__halo > span {
|
|
4799
|
+
position: absolute;
|
|
4800
|
+
border-radius: inherit;
|
|
4801
|
+
pointer-events: none;
|
|
4802
|
+
}
|
|
4803
|
+
|
|
4804
|
+
/* keep only the padding ring: the element minus its content box */
|
|
4805
|
+
.glow-border__metal,
|
|
4806
|
+
.glow-border__glint,
|
|
4807
|
+
.glow-border__halo > span {
|
|
4808
|
+
-webkit-mask:
|
|
4809
|
+
linear-gradient(#000 0 0) content-box,
|
|
4810
|
+
linear-gradient(#000 0 0);
|
|
4811
|
+
-webkit-mask-composite: xor;
|
|
4812
|
+
mask:
|
|
4813
|
+
linear-gradient(#000 0 0) content-box,
|
|
4814
|
+
linear-gradient(#000 0 0);
|
|
4815
|
+
mask-composite: exclude;
|
|
4816
|
+
}
|
|
4817
|
+
|
|
4818
|
+
/* Liquid metal: two fields, centred apart and turning against each other. */
|
|
4819
|
+
.glow-border__metal {
|
|
4820
|
+
inset: 0;
|
|
4821
|
+
padding: var(--glow-border-width);
|
|
4822
|
+
background: var(--gb-metal);
|
|
4823
|
+
background-blend-mode: soft-light;
|
|
4824
|
+
}
|
|
4825
|
+
|
|
4826
|
+
/* The glint riding the ring. */
|
|
4827
|
+
.glow-border__glint {
|
|
4828
|
+
inset: 0;
|
|
4829
|
+
padding: var(--glow-border-width);
|
|
4830
|
+
background: var(--gb-glint);
|
|
4831
|
+
mix-blend-mode: screen;
|
|
4832
|
+
opacity: var(--glow-strength);
|
|
4833
|
+
}
|
|
4834
|
+
|
|
4835
|
+
/* The light it spills on both sides of the edge, blurred after masking. */
|
|
4836
|
+
.glow-border__halo {
|
|
4837
|
+
inset: 0;
|
|
4838
|
+
filter: blur(6px);
|
|
4839
|
+
opacity: calc(var(--glow-strength) * var(--gb-halo-opacity));
|
|
4840
|
+
}
|
|
4841
|
+
|
|
4842
|
+
.glow-border__halo > span {
|
|
4843
|
+
inset: -5px;
|
|
4844
|
+
padding: calc(var(--glow-border-width) + 9px);
|
|
4845
|
+
border-radius: calc(var(--glow-border-radius) + 5px);
|
|
4846
|
+
background: var(--gb-glint);
|
|
4847
|
+
}
|
|
4848
|
+
|
|
4849
|
+
.glow-border.animate-glow {
|
|
4850
|
+
animation:
|
|
4851
|
+
gb-flow-1 var(--glow-duration) linear infinite,
|
|
4852
|
+
gb-flow-2 calc(var(--glow-duration) * 1.7) linear infinite reverse,
|
|
4853
|
+
gb-glint calc(var(--glow-duration) * 0.4) linear infinite;
|
|
4854
|
+
}
|
|
4855
|
+
|
|
4856
|
+
@keyframes gb-flow-1 {
|
|
4857
|
+
to {
|
|
4858
|
+
--gb-a1: 360deg;
|
|
3070
4859
|
}
|
|
3071
|
-
|
|
3072
|
-
|
|
4860
|
+
}
|
|
4861
|
+
|
|
4862
|
+
@keyframes gb-flow-2 {
|
|
4863
|
+
from {
|
|
4864
|
+
--gb-a2: 120deg;
|
|
3073
4865
|
}
|
|
3074
|
-
|
|
3075
|
-
|
|
4866
|
+
to {
|
|
4867
|
+
--gb-a2: 480deg;
|
|
3076
4868
|
}
|
|
3077
4869
|
}
|
|
3078
4870
|
|
|
3079
|
-
|
|
3080
|
-
|
|
4871
|
+
@keyframes gb-glint {
|
|
4872
|
+
to {
|
|
4873
|
+
--gb-a3: 360deg;
|
|
4874
|
+
}
|
|
3081
4875
|
}
|
|
3082
4876
|
|
|
3083
4877
|
@media (prefers-reduced-motion: reduce) {
|
|
3084
|
-
.animate-glow {
|
|
4878
|
+
.glow-border.animate-glow {
|
|
3085
4879
|
animation: none;
|
|
4880
|
+
--gb-a3: 210deg;
|
|
3086
4881
|
}
|
|
3087
4882
|
}
|
|
4883
|
+
@property --gb-angle {
|
|
4884
|
+
syntax: "<angle>";
|
|
4885
|
+
inherits: true;
|
|
4886
|
+
initial-value: 0deg;
|
|
4887
|
+
}
|
|
4888
|
+
|
|
3088
4889
|
.gradient-button {
|
|
3089
|
-
padding: var(--gb-border-width);
|
|
3090
4890
|
border-radius: var(--gb-border-radius);
|
|
3091
4891
|
isolation: isolate;
|
|
4892
|
+
background: color-mix(in srgb, var(--gb-bg-color), #fff 8%);
|
|
4893
|
+
animation: gb-spin var(--gb-duration) linear infinite;
|
|
4894
|
+
transition: transform 0.2s ease;
|
|
4895
|
+
}
|
|
4896
|
+
|
|
4897
|
+
.gradient-button:active {
|
|
4898
|
+
transform: scale(0.98);
|
|
4899
|
+
}
|
|
4900
|
+
|
|
4901
|
+
.gradient-button:disabled {
|
|
4902
|
+
cursor: not-allowed;
|
|
4903
|
+
opacity: 0.5;
|
|
4904
|
+
animation-play-state: paused;
|
|
4905
|
+
}
|
|
4906
|
+
|
|
4907
|
+
/* Anchored on the root class: the Svelte compiler scoped these rules, plain CSS
|
|
4908
|
+
would leak them into every consumer element sharing the class name. */
|
|
4909
|
+
.gradient-button .gradient-content {
|
|
4910
|
+
position: relative;
|
|
4911
|
+
margin: var(--gb-border-width);
|
|
4912
|
+
border-radius: calc(var(--gb-border-radius) - var(--gb-border-width));
|
|
4913
|
+
background:
|
|
4914
|
+
linear-gradient(to bottom, rgb(255 255 255 / 0.06), transparent 45%), var(--gb-bg-color);
|
|
4915
|
+
}
|
|
4916
|
+
|
|
4917
|
+
.gradient-button .gradient-border,
|
|
4918
|
+
.gradient-button .gradient-glow,
|
|
4919
|
+
.gradient-button .gradient-glow > span {
|
|
4920
|
+
position: absolute;
|
|
4921
|
+
pointer-events: none;
|
|
4922
|
+
border-radius: inherit;
|
|
4923
|
+
}
|
|
4924
|
+
|
|
4925
|
+
/* keep only the padding ring: the element minus its content box */
|
|
4926
|
+
.gradient-button .gradient-border,
|
|
4927
|
+
.gradient-button .gradient-glow > span {
|
|
4928
|
+
background: var(--gb-beam);
|
|
4929
|
+
-webkit-mask:
|
|
4930
|
+
linear-gradient(#000 0 0) content-box,
|
|
4931
|
+
linear-gradient(#000 0 0);
|
|
4932
|
+
-webkit-mask-composite: xor;
|
|
4933
|
+
mask:
|
|
4934
|
+
linear-gradient(#000 0 0) content-box,
|
|
4935
|
+
linear-gradient(#000 0 0);
|
|
4936
|
+
mask-composite: exclude;
|
|
4937
|
+
}
|
|
4938
|
+
|
|
4939
|
+
.gradient-button .gradient-border {
|
|
4940
|
+
inset: 0;
|
|
4941
|
+
z-index: 2;
|
|
4942
|
+
padding: var(--gb-border-width);
|
|
4943
|
+
}
|
|
4944
|
+
|
|
4945
|
+
/* A wider band inside the border, blurred by its parent AFTER masking so
|
|
4946
|
+
it falls off softly into the face. Screen: it lights, never darkens. */
|
|
4947
|
+
.gradient-button .gradient-glow {
|
|
4948
|
+
inset: 0;
|
|
4949
|
+
z-index: 1;
|
|
4950
|
+
filter: blur(calc(var(--gb-blur) * 3));
|
|
4951
|
+
mix-blend-mode: screen;
|
|
4952
|
+
opacity: 0.45;
|
|
4953
|
+
transition: opacity 0.3s ease;
|
|
4954
|
+
}
|
|
4955
|
+
|
|
4956
|
+
.gradient-button .gradient-glow > span {
|
|
4957
|
+
inset: 0;
|
|
4958
|
+
padding: calc(var(--gb-blur) * 1.75);
|
|
3092
4959
|
}
|
|
3093
4960
|
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
content: "";
|
|
3098
|
-
position: absolute;
|
|
3099
|
-
inset: -200%;
|
|
3100
|
-
z-index: -1;
|
|
3101
|
-
background: conic-gradient(var(--gb-colors));
|
|
3102
|
-
animation: rotate-gradient var(--gb-duration) linear infinite;
|
|
3103
|
-
filter: blur(var(--gb-blur));
|
|
4961
|
+
.gradient-button:hover .gradient-glow,
|
|
4962
|
+
.gradient-button:focus-visible .gradient-glow {
|
|
4963
|
+
opacity: 0.8;
|
|
3104
4964
|
}
|
|
3105
4965
|
|
|
3106
|
-
.gradient-button
|
|
3107
|
-
|
|
3108
|
-
|
|
4966
|
+
.gradient-button:focus-visible {
|
|
4967
|
+
outline: 2px solid rgb(255 255 255 / 0.5);
|
|
4968
|
+
outline-offset: 2px;
|
|
3109
4969
|
}
|
|
3110
4970
|
|
|
3111
|
-
@keyframes
|
|
3112
|
-
|
|
3113
|
-
|
|
4971
|
+
@keyframes gb-spin {
|
|
4972
|
+
to {
|
|
4973
|
+
--gb-angle: 360deg;
|
|
3114
4974
|
}
|
|
3115
|
-
|
|
3116
|
-
|
|
4975
|
+
}
|
|
4976
|
+
|
|
4977
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4978
|
+
.gradient-button {
|
|
4979
|
+
animation: none;
|
|
4980
|
+
--gb-angle: 135deg;
|
|
3117
4981
|
}
|
|
3118
4982
|
}
|
|
3119
4983
|
/* Keyframes referenced by the inline `animation` shorthand on each
|
|
@@ -3389,6 +5253,149 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
3389
5253
|
.interactive-grid-pattern .interactive-grid-square:not(:hover) {
|
|
3390
5254
|
transition-duration: 1000ms;
|
|
3391
5255
|
}
|
|
5256
|
+
.ihb {
|
|
5257
|
+
/* Private copies: read the public variables (set from `className`, which a
|
|
5258
|
+
rule here would otherwise outrank), else the theme. */
|
|
5259
|
+
--_ihb-fill: var(--ihb-fill, var(--primary, var(--color-primary, currentColor)));
|
|
5260
|
+
--_ihb-fill-foreground: var(
|
|
5261
|
+
--ihb-fill-foreground,
|
|
5262
|
+
var(--primary-foreground, var(--color-primary-foreground, #fff))
|
|
5263
|
+
);
|
|
5264
|
+
/* where the dot sits, vertically centred */
|
|
5265
|
+
--ihb-dot-x: 1.75rem;
|
|
5266
|
+
--ihb-ease: cubic-bezier(0.22, 1, 0.36, 1);
|
|
5267
|
+
}
|
|
5268
|
+
|
|
5269
|
+
.ihb-fill {
|
|
5270
|
+
position: absolute;
|
|
5271
|
+
inset: 0;
|
|
5272
|
+
z-index: -1;
|
|
5273
|
+
background: var(--_ihb-fill);
|
|
5274
|
+
clip-path: circle(4px at var(--ihb-dot-x) 50%);
|
|
5275
|
+
}
|
|
5276
|
+
|
|
5277
|
+
.ihb-rest,
|
|
5278
|
+
.ihb-hover {
|
|
5279
|
+
display: flex;
|
|
5280
|
+
align-items: center;
|
|
5281
|
+
justify-content: center;
|
|
5282
|
+
gap: 0.5rem;
|
|
5283
|
+
}
|
|
5284
|
+
|
|
5285
|
+
.ihb-dot-space {
|
|
5286
|
+
width: 8px;
|
|
5287
|
+
flex: none;
|
|
5288
|
+
}
|
|
5289
|
+
|
|
5290
|
+
.ihb-hover {
|
|
5291
|
+
position: absolute;
|
|
5292
|
+
inset: 0;
|
|
5293
|
+
color: var(--_ihb-fill-foreground);
|
|
5294
|
+
opacity: 0;
|
|
5295
|
+
transform: translateY(70%);
|
|
5296
|
+
}
|
|
5297
|
+
|
|
5298
|
+
.ihb-arrow {
|
|
5299
|
+
flex: none;
|
|
5300
|
+
opacity: 0;
|
|
5301
|
+
transform: translateX(-6px);
|
|
5302
|
+
}
|
|
5303
|
+
|
|
5304
|
+
/* ---- hover / keyboard focus ---------------------------------------------- */
|
|
5305
|
+
|
|
5306
|
+
.ihb:hover .ihb-fill,
|
|
5307
|
+
.ihb:focus-visible .ihb-fill {
|
|
5308
|
+
clip-path: circle(150% at var(--ihb-dot-x) 50%);
|
|
5309
|
+
}
|
|
5310
|
+
|
|
5311
|
+
.ihb:hover .ihb-rest,
|
|
5312
|
+
.ihb:focus-visible .ihb-rest {
|
|
5313
|
+
opacity: 0;
|
|
5314
|
+
transform: translateY(-70%);
|
|
5315
|
+
filter: blur(4px);
|
|
5316
|
+
}
|
|
5317
|
+
|
|
5318
|
+
.ihb:hover .ihb-hover,
|
|
5319
|
+
.ihb:focus-visible .ihb-hover {
|
|
5320
|
+
opacity: 1;
|
|
5321
|
+
transform: none;
|
|
5322
|
+
}
|
|
5323
|
+
|
|
5324
|
+
.ihb:hover .ihb-arrow,
|
|
5325
|
+
.ihb:focus-visible .ihb-arrow {
|
|
5326
|
+
opacity: 1;
|
|
5327
|
+
transform: none;
|
|
5328
|
+
}
|
|
5329
|
+
|
|
5330
|
+
.ihb:focus-visible {
|
|
5331
|
+
outline: 2px solid var(--_ihb-fill);
|
|
5332
|
+
outline-offset: 2px;
|
|
5333
|
+
}
|
|
5334
|
+
|
|
5335
|
+
.ihb:disabled {
|
|
5336
|
+
cursor: not-allowed;
|
|
5337
|
+
opacity: 0.5;
|
|
5338
|
+
}
|
|
5339
|
+
|
|
5340
|
+
.ihb:disabled .ihb-fill {
|
|
5341
|
+
clip-path: circle(4px at var(--ihb-dot-x) 50%);
|
|
5342
|
+
}
|
|
5343
|
+
|
|
5344
|
+
.ihb:disabled .ihb-rest {
|
|
5345
|
+
opacity: 1;
|
|
5346
|
+
transform: none;
|
|
5347
|
+
filter: none;
|
|
5348
|
+
}
|
|
5349
|
+
|
|
5350
|
+
.ihb:disabled .ihb-hover {
|
|
5351
|
+
opacity: 0;
|
|
5352
|
+
}
|
|
5353
|
+
|
|
5354
|
+
/* ---- motion: only when the visitor has not asked for less ----------------- */
|
|
5355
|
+
|
|
5356
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
5357
|
+
.ihb {
|
|
5358
|
+
transition: transform 0.2s var(--ihb-ease);
|
|
5359
|
+
}
|
|
5360
|
+
|
|
5361
|
+
.ihb:active {
|
|
5362
|
+
transform: scale(0.97);
|
|
5363
|
+
}
|
|
5364
|
+
|
|
5365
|
+
.ihb-fill {
|
|
5366
|
+
transition: clip-path 0.6s var(--ihb-ease);
|
|
5367
|
+
}
|
|
5368
|
+
|
|
5369
|
+
.ihb-rest {
|
|
5370
|
+
transition:
|
|
5371
|
+
opacity 0.3s var(--ihb-ease),
|
|
5372
|
+
transform 0.5s var(--ihb-ease),
|
|
5373
|
+
filter 0.5s var(--ihb-ease);
|
|
5374
|
+
}
|
|
5375
|
+
|
|
5376
|
+
.ihb-hover {
|
|
5377
|
+
transition:
|
|
5378
|
+
opacity 0.3s var(--ihb-ease),
|
|
5379
|
+
transform 0.5s var(--ihb-ease);
|
|
5380
|
+
}
|
|
5381
|
+
|
|
5382
|
+
.ihb-arrow {
|
|
5383
|
+
transition:
|
|
5384
|
+
opacity 0.3s var(--ihb-ease),
|
|
5385
|
+
transform 0.5s var(--ihb-ease);
|
|
5386
|
+
}
|
|
5387
|
+
|
|
5388
|
+
/* On the way in, stagger: label a beat after the fill, arrow after it. */
|
|
5389
|
+
.ihb:hover .ihb-hover,
|
|
5390
|
+
.ihb:focus-visible .ihb-hover {
|
|
5391
|
+
transition-delay: 60ms;
|
|
5392
|
+
}
|
|
5393
|
+
|
|
5394
|
+
.ihb:hover .ihb-arrow,
|
|
5395
|
+
.ihb:focus-visible .ihb-arrow {
|
|
5396
|
+
transition-delay: 160ms;
|
|
5397
|
+
}
|
|
5398
|
+
}
|
|
3392
5399
|
@keyframes letterPullUp {
|
|
3393
5400
|
0% {
|
|
3394
5401
|
opacity: 0;
|
|
@@ -4167,15 +6174,61 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
4167
6174
|
transform: none;
|
|
4168
6175
|
}
|
|
4169
6176
|
}
|
|
4170
|
-
/* Anchored on the root class (
|
|
6177
|
+
/* Anchored on the source's root class `.marquee` (the Svelte compiler scoped
|
|
4171
6178
|
these rules; as plain CSS they would leak into any consumer element named
|
|
4172
6179
|
.animate-marquee). See PORTING.md, styling rule 2. */
|
|
4173
|
-
.
|
|
4174
|
-
animation: marquee var(--duration) linear infinite;
|
|
6180
|
+
.marquee > .animate-marquee {
|
|
6181
|
+
animation: marquee calc(var(--duration) / var(--marquee-speed, 1)) linear infinite;
|
|
6182
|
+
will-change: transform;
|
|
6183
|
+
}
|
|
6184
|
+
|
|
6185
|
+
.marquee > .animate-marquee-vertical {
|
|
6186
|
+
animation: marquee-vertical calc(var(--duration) / var(--marquee-speed, 1)) linear infinite;
|
|
6187
|
+
will-change: transform;
|
|
6188
|
+
}
|
|
6189
|
+
|
|
6190
|
+
/* Script-owned animations have taken over: silence the CSS keyframe so the
|
|
6191
|
+
track is not moved twice. */
|
|
6192
|
+
.marquee.marquee-upgraded > .animate-marquee,
|
|
6193
|
+
.marquee.marquee-upgraded > .animate-marquee-vertical {
|
|
6194
|
+
animation: none;
|
|
6195
|
+
}
|
|
6196
|
+
|
|
6197
|
+
/* Edge fades: an eased (not linear) alpha ramp, so items dissolve into the
|
|
6198
|
+
edge instead of hitting a visible line. Width via --marquee-fade. */
|
|
6199
|
+
.marquee.marquee-fade {
|
|
6200
|
+
--_fade: var(--marquee-fade, 12%);
|
|
6201
|
+
--_mask: linear-gradient(
|
|
6202
|
+
to right,
|
|
6203
|
+
transparent,
|
|
6204
|
+
rgb(0 0 0 / 0.1) calc(var(--_fade) * 0.25),
|
|
6205
|
+
rgb(0 0 0 / 0.4) calc(var(--_fade) * 0.5),
|
|
6206
|
+
rgb(0 0 0 / 0.8) calc(var(--_fade) * 0.75),
|
|
6207
|
+
#000 var(--_fade),
|
|
6208
|
+
#000 calc(100% - var(--_fade)),
|
|
6209
|
+
rgb(0 0 0 / 0.8) calc(100% - var(--_fade) * 0.75),
|
|
6210
|
+
rgb(0 0 0 / 0.4) calc(100% - var(--_fade) * 0.5),
|
|
6211
|
+
rgb(0 0 0 / 0.1) calc(100% - var(--_fade) * 0.25),
|
|
6212
|
+
transparent
|
|
6213
|
+
);
|
|
6214
|
+
-webkit-mask-image: var(--_mask);
|
|
6215
|
+
mask-image: var(--_mask);
|
|
4175
6216
|
}
|
|
4176
6217
|
|
|
4177
|
-
.
|
|
4178
|
-
|
|
6218
|
+
.marquee.marquee-fade.marquee-vertical {
|
|
6219
|
+
--_mask: linear-gradient(
|
|
6220
|
+
to bottom,
|
|
6221
|
+
transparent,
|
|
6222
|
+
rgb(0 0 0 / 0.1) calc(var(--_fade) * 0.25),
|
|
6223
|
+
rgb(0 0 0 / 0.4) calc(var(--_fade) * 0.5),
|
|
6224
|
+
rgb(0 0 0 / 0.8) calc(var(--_fade) * 0.75),
|
|
6225
|
+
#000 var(--_fade),
|
|
6226
|
+
#000 calc(100% - var(--_fade)),
|
|
6227
|
+
rgb(0 0 0 / 0.8) calc(100% - var(--_fade) * 0.75),
|
|
6228
|
+
rgb(0 0 0 / 0.4) calc(100% - var(--_fade) * 0.5),
|
|
6229
|
+
rgb(0 0 0 / 0.1) calc(100% - var(--_fade) * 0.25),
|
|
6230
|
+
transparent
|
|
6231
|
+
);
|
|
4179
6232
|
}
|
|
4180
6233
|
|
|
4181
6234
|
@keyframes marquee {
|
|
@@ -4195,22 +6248,200 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
4195
6248
|
transform: translateY(calc(-100% - var(--gap)));
|
|
4196
6249
|
}
|
|
4197
6250
|
}
|
|
6251
|
+
|
|
6252
|
+
/* Reduced motion: a still row with the same composition — edge fades stay. */
|
|
6253
|
+
@media (prefers-reduced-motion: reduce) {
|
|
6254
|
+
.marquee > .animate-marquee,
|
|
6255
|
+
.marquee > .animate-marquee-vertical {
|
|
6256
|
+
animation: none;
|
|
6257
|
+
will-change: auto;
|
|
6258
|
+
}
|
|
6259
|
+
}
|
|
6260
|
+
/* Anchored on the source's root class `.review-card`. The Svelte compiler
|
|
6261
|
+
scoped these rules; here every selector starts from that class. */
|
|
6262
|
+
.review-card {
|
|
6263
|
+
--_shell: var(--review-card-shell, #f4f4f5);
|
|
6264
|
+
--_panel: var(--review-card-panel, #fafafa);
|
|
6265
|
+
--_panel-hover: var(--review-card-panel-hover, #ffffff);
|
|
6266
|
+
--_line: var(--review-card-line, rgba(0, 0, 0, 0.08));
|
|
6267
|
+
--_ink: var(--review-card-ink, #18181b);
|
|
6268
|
+
--_muted: var(--review-card-muted, #71717a);
|
|
6269
|
+
--_body: var(--review-card-body, #52525b);
|
|
6270
|
+
--_lift: rgba(255, 255, 255, 1);
|
|
6271
|
+
background: var(--_shell);
|
|
6272
|
+
border-color: var(--_line);
|
|
6273
|
+
transition:
|
|
6274
|
+
border-color 300ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
6275
|
+
background-color 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
6276
|
+
}
|
|
6277
|
+
|
|
6278
|
+
.dark .review-card {
|
|
6279
|
+
--_shell: var(--review-card-shell, #0e0e10);
|
|
6280
|
+
--_panel: var(--review-card-panel, #141416);
|
|
6281
|
+
--_panel-hover: var(--review-card-panel-hover, #17171a);
|
|
6282
|
+
--_line: var(--review-card-line, rgba(255, 255, 255, 0.08));
|
|
6283
|
+
--_ink: var(--review-card-ink, #f4f4f5);
|
|
6284
|
+
--_muted: var(--review-card-muted, #71717a);
|
|
6285
|
+
--_body: var(--review-card-body, #a1a1aa);
|
|
6286
|
+
--_lift: rgba(255, 255, 255, 0.1);
|
|
6287
|
+
}
|
|
6288
|
+
|
|
6289
|
+
.review-card .review-card-inner {
|
|
6290
|
+
background: var(--_panel);
|
|
6291
|
+
border-color: color-mix(in oklab, var(--_line) 75%, transparent);
|
|
6292
|
+
box-shadow: inset 0 1px 0 transparent;
|
|
6293
|
+
transition:
|
|
6294
|
+
box-shadow 300ms cubic-bezier(0.4, 0, 0.2, 1),
|
|
6295
|
+
background-color 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
6296
|
+
}
|
|
6297
|
+
|
|
6298
|
+
/* Hover: a quiet top-edge highlight, as if the card caught light from above. */
|
|
6299
|
+
.review-card:hover .review-card-inner {
|
|
6300
|
+
background: var(--_panel-hover);
|
|
6301
|
+
box-shadow:
|
|
6302
|
+
inset 0 1px 0 var(--_lift),
|
|
6303
|
+
0 1px 2px rgba(0, 0, 0, 0.04),
|
|
6304
|
+
0 6px 16px -8px rgba(0, 0, 0, 0.1);
|
|
6305
|
+
}
|
|
6306
|
+
|
|
6307
|
+
.review-card .review-card-sheen {
|
|
6308
|
+
position: absolute;
|
|
6309
|
+
inset: 0 0 auto 0;
|
|
6310
|
+
height: 60%;
|
|
6311
|
+
pointer-events: none;
|
|
6312
|
+
background: radial-gradient(
|
|
6313
|
+
120% 90% at 50% 0%,
|
|
6314
|
+
color-mix(in oklab, var(--_lift) 60%, transparent),
|
|
6315
|
+
transparent 70%
|
|
6316
|
+
);
|
|
6317
|
+
opacity: 0;
|
|
6318
|
+
transition: opacity 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
6319
|
+
}
|
|
6320
|
+
|
|
6321
|
+
.review-card:hover .review-card-sheen {
|
|
6322
|
+
opacity: 1;
|
|
6323
|
+
}
|
|
6324
|
+
|
|
6325
|
+
.review-card .review-card-avatar {
|
|
6326
|
+
background: var(--_shell);
|
|
6327
|
+
box-shadow:
|
|
6328
|
+
0 0 0 2px var(--_panel),
|
|
6329
|
+
0 0 0 3px var(--_line);
|
|
6330
|
+
}
|
|
6331
|
+
|
|
6332
|
+
@media (prefers-reduced-motion: reduce) {
|
|
6333
|
+
.review-card,
|
|
6334
|
+
.review-card .review-card-inner,
|
|
6335
|
+
.review-card .review-card-sheen {
|
|
6336
|
+
transition: none;
|
|
6337
|
+
}
|
|
6338
|
+
}
|
|
6339
|
+
|
|
6340
|
+
.review-card .review-card-name {
|
|
6341
|
+
color: var(--_ink);
|
|
6342
|
+
}
|
|
6343
|
+
|
|
6344
|
+
.review-card .review-card-handle {
|
|
6345
|
+
color: var(--_muted);
|
|
6346
|
+
}
|
|
6347
|
+
|
|
6348
|
+
.review-card .review-card-body {
|
|
6349
|
+
color: var(--_body);
|
|
6350
|
+
}
|
|
6351
|
+
/* Light pages get a slate meteor; dark ones a pale blue-white. A `color`
|
|
6352
|
+
prop (inline) overrides both. */
|
|
6353
|
+
.meteor {
|
|
6354
|
+
--_meteor-color: var(--meteor-color, #475569);
|
|
6355
|
+
background: var(--_meteor-color);
|
|
6356
|
+
transform: rotate(var(--meteor-angle, 215deg)) scale(var(--meteor-scale, 1));
|
|
6357
|
+
/* the head's glow */
|
|
6358
|
+
box-shadow:
|
|
6359
|
+
0 0 2px 1px color-mix(in srgb, var(--_meteor-color) 70%, transparent),
|
|
6360
|
+
0 0 8px 2px color-mix(in srgb, var(--_meteor-color) 35%, transparent);
|
|
6361
|
+
animation: meteor-fall 5s cubic-bezier(0.3, 0, 0.9, 1) infinite;
|
|
6362
|
+
}
|
|
6363
|
+
|
|
6364
|
+
.dark .meteor {
|
|
6365
|
+
--_meteor-color: var(--meteor-color, #dbeafe);
|
|
6366
|
+
}
|
|
6367
|
+
|
|
6368
|
+
/* The tail: thickest at the head, fading out behind it. */
|
|
6369
|
+
.meteor::before {
|
|
6370
|
+
content: "";
|
|
6371
|
+
position: absolute;
|
|
6372
|
+
top: 50%;
|
|
6373
|
+
left: 1px;
|
|
6374
|
+
width: var(--meteor-tail, 60px);
|
|
6375
|
+
height: 1px;
|
|
6376
|
+
transform: translateY(-50%);
|
|
6377
|
+
border-radius: 999px;
|
|
6378
|
+
background: linear-gradient(
|
|
6379
|
+
to right,
|
|
6380
|
+
var(--_meteor-color),
|
|
6381
|
+
color-mix(in srgb, var(--_meteor-color) 35%, transparent) 30%,
|
|
6382
|
+
transparent
|
|
6383
|
+
);
|
|
6384
|
+
}
|
|
6385
|
+
|
|
4198
6386
|
@keyframes meteor-fall {
|
|
4199
6387
|
0% {
|
|
4200
|
-
transform: rotate(215deg) translateX(0);
|
|
4201
|
-
opacity:
|
|
6388
|
+
transform: rotate(var(--meteor-angle, 215deg)) scale(var(--meteor-scale, 1)) translateX(0);
|
|
6389
|
+
opacity: 0;
|
|
6390
|
+
}
|
|
6391
|
+
8% {
|
|
6392
|
+
opacity: var(--meteor-brightness, 1);
|
|
4202
6393
|
}
|
|
4203
6394
|
70% {
|
|
6395
|
+
opacity: var(--meteor-brightness, 1);
|
|
6396
|
+
}
|
|
6397
|
+
100% {
|
|
6398
|
+
transform: rotate(var(--meteor-angle, 215deg)) scale(var(--meteor-scale, 1))
|
|
6399
|
+
translateX(calc(-1 * var(--meteor-travel, 800px)));
|
|
6400
|
+
opacity: 0;
|
|
6401
|
+
}
|
|
6402
|
+
}
|
|
6403
|
+
|
|
6404
|
+
/* A flare: the meteor swells and brightens just before it burns out. */
|
|
6405
|
+
.meteor.meteor--flare {
|
|
6406
|
+
animation-name: meteor-fall-flare;
|
|
6407
|
+
}
|
|
6408
|
+
|
|
6409
|
+
@keyframes meteor-fall-flare {
|
|
6410
|
+
0% {
|
|
6411
|
+
transform: rotate(var(--meteor-angle, 215deg)) scale(var(--meteor-scale, 1)) translateX(0);
|
|
6412
|
+
opacity: 0;
|
|
6413
|
+
}
|
|
6414
|
+
8% {
|
|
6415
|
+
opacity: var(--meteor-brightness, 1);
|
|
6416
|
+
}
|
|
6417
|
+
62% {
|
|
6418
|
+
opacity: var(--meteor-brightness, 1);
|
|
6419
|
+
box-shadow:
|
|
6420
|
+
0 0 2px 1px color-mix(in srgb, var(--_meteor-color) 70%, transparent),
|
|
6421
|
+
0 0 8px 2px color-mix(in srgb, var(--_meteor-color) 35%, transparent);
|
|
6422
|
+
}
|
|
6423
|
+
74% {
|
|
4204
6424
|
opacity: 1;
|
|
6425
|
+
box-shadow:
|
|
6426
|
+
0 0 4px 2px var(--_meteor-color),
|
|
6427
|
+
0 0 18px 6px color-mix(in srgb, var(--_meteor-color) 55%, transparent);
|
|
4205
6428
|
}
|
|
4206
6429
|
100% {
|
|
4207
|
-
transform: rotate(215deg)
|
|
6430
|
+
transform: rotate(var(--meteor-angle, 215deg)) scale(var(--meteor-scale, 1))
|
|
6431
|
+
translateX(calc(-1 * var(--meteor-travel, 800px)));
|
|
4208
6432
|
opacity: 0;
|
|
4209
6433
|
}
|
|
4210
6434
|
}
|
|
4211
6435
|
|
|
4212
|
-
|
|
4213
|
-
|
|
6436
|
+
/* Reduced motion: a still sky — each meteor frozen part-way along its path. */
|
|
6437
|
+
@media (prefers-reduced-motion: reduce) {
|
|
6438
|
+
.meteor,
|
|
6439
|
+
.meteor.meteor--flare {
|
|
6440
|
+
animation: none;
|
|
6441
|
+
opacity: calc(var(--meteor-brightness, 1) * 0.7);
|
|
6442
|
+
transform: rotate(var(--meteor-angle, 215deg)) scale(var(--meteor-scale, 1))
|
|
6443
|
+
translateX(calc(-0.35 * var(--meteor-travel, 800px)));
|
|
6444
|
+
}
|
|
4214
6445
|
}
|
|
4215
6446
|
/*
|
|
4216
6447
|
* `NavbarLink` declares this same fallback again, locally on itself —
|
|
@@ -4359,71 +6590,150 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
4359
6590
|
color-mix(in oklch, oklch(0.8001 0.1345 225.49) 6%, transparent)
|
|
4360
6591
|
);
|
|
4361
6592
|
}
|
|
4362
|
-
|
|
4363
|
-
|
|
4364
|
-
|
|
4365
|
-
|
|
4366
|
-
|
|
4367
|
-
|
|
4368
|
-
|
|
4369
|
-
inset: 0;
|
|
6593
|
+
/* Svelte scoped these rules; here every rule is anchored on the root class
|
|
6594
|
+
`.neon-border-container` so nothing leaks into the consumer's page. */
|
|
6595
|
+
|
|
6596
|
+
@property --neon-angle {
|
|
6597
|
+
syntax: "<angle>";
|
|
6598
|
+
inherits: true;
|
|
6599
|
+
initial-value: 135deg;
|
|
4370
6600
|
}
|
|
4371
6601
|
|
|
4372
|
-
.neon-
|
|
4373
|
-
|
|
6602
|
+
.neon-border-container {
|
|
6603
|
+
--neon-tube-width: 1.5px;
|
|
6604
|
+
padding: var(--neon-tube-width);
|
|
6605
|
+
isolation: isolate;
|
|
6606
|
+
}
|
|
6607
|
+
|
|
6608
|
+
.neon-border-container .neon-tube,
|
|
6609
|
+
.neon-border-container .neon-light,
|
|
6610
|
+
.neon-border-container .neon-glow,
|
|
6611
|
+
.neon-border-container .neon-glow > span,
|
|
6612
|
+
.neon-border-container .neon-core {
|
|
4374
6613
|
position: absolute;
|
|
4375
|
-
|
|
4376
|
-
|
|
4377
|
-
|
|
4378
|
-
|
|
4379
|
-
|
|
6614
|
+
pointer-events: none;
|
|
6615
|
+
border-radius: inherit;
|
|
6616
|
+
}
|
|
6617
|
+
|
|
6618
|
+
/* keep only the padding ring: the element minus its content box */
|
|
6619
|
+
.neon-border-container .neon-tube,
|
|
6620
|
+
.neon-border-container .neon-glow > span,
|
|
6621
|
+
.neon-border-container .neon-core {
|
|
6622
|
+
-webkit-mask:
|
|
6623
|
+
linear-gradient(#000 0 0) content-box,
|
|
6624
|
+
linear-gradient(#000 0 0);
|
|
6625
|
+
-webkit-mask-composite: xor;
|
|
6626
|
+
mask:
|
|
6627
|
+
linear-gradient(#000 0 0) content-box,
|
|
6628
|
+
linear-gradient(#000 0 0);
|
|
6629
|
+
mask-composite: exclude;
|
|
6630
|
+
}
|
|
6631
|
+
|
|
6632
|
+
/* The unlit tube: always there, faint, shading from one colour to the other. */
|
|
6633
|
+
.neon-border-container .neon-tube {
|
|
6634
|
+
inset: 0;
|
|
6635
|
+
padding: var(--neon-tube-width);
|
|
4380
6636
|
background: linear-gradient(
|
|
4381
6637
|
135deg,
|
|
4382
|
-
var(--neon-color1),
|
|
4383
|
-
var(--neon-
|
|
4384
|
-
transparent,
|
|
4385
|
-
transparent
|
|
6638
|
+
color-mix(in srgb, var(--neon-color1) 30%, transparent),
|
|
6639
|
+
color-mix(in srgb, var(--neon-color2) 30%, transparent)
|
|
4386
6640
|
);
|
|
4387
6641
|
}
|
|
4388
6642
|
|
|
4389
|
-
.neon-
|
|
4390
|
-
position: absolute;
|
|
4391
|
-
overflow: hidden;
|
|
4392
|
-
width: 100%;
|
|
4393
|
-
height: 100%;
|
|
4394
|
-
filter: blur(1px) drop-shadow(0 0 12px var(--neon-color2));
|
|
4395
|
-
z-index: -1;
|
|
6643
|
+
.neon-border-container .neon-light {
|
|
4396
6644
|
inset: 0;
|
|
4397
6645
|
}
|
|
4398
6646
|
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
4403
|
-
|
|
4404
|
-
|
|
4405
|
-
|
|
4406
|
-
|
|
4407
|
-
|
|
4408
|
-
|
|
4409
|
-
|
|
4410
|
-
|
|
4411
|
-
|
|
4412
|
-
|
|
4413
|
-
|
|
6647
|
+
/* The glow: the beams on a wide ring straddling the edge, blurred after
|
|
6648
|
+
masking so it spills softly both inside and outside. */
|
|
6649
|
+
.neon-border-container .neon-glow {
|
|
6650
|
+
inset: 0;
|
|
6651
|
+
filter: blur(7px);
|
|
6652
|
+
/* on a light page a coloured halo reads as a stain: keep it faint */
|
|
6653
|
+
opacity: var(--neon-glow-max);
|
|
6654
|
+
}
|
|
6655
|
+
|
|
6656
|
+
.neon-border-container {
|
|
6657
|
+
--neon-glow-max: 0.4;
|
|
6658
|
+
--neon-glow-min: 0.25;
|
|
6659
|
+
}
|
|
6660
|
+
|
|
6661
|
+
.dark .neon-border-container {
|
|
6662
|
+
--neon-glow-max: 0.9;
|
|
6663
|
+
--neon-glow-min: 0.6;
|
|
6664
|
+
}
|
|
6665
|
+
|
|
6666
|
+
.neon-border-container .neon-glow > span {
|
|
6667
|
+
inset: -7px;
|
|
6668
|
+
padding: calc(var(--neon-tube-width) + 12px);
|
|
6669
|
+
border-radius: calc(0.5rem + 7px);
|
|
6670
|
+
background: var(--neon-beams);
|
|
6671
|
+
}
|
|
6672
|
+
|
|
6673
|
+
/* The white-hot core of the lit tube. */
|
|
6674
|
+
.neon-border-container .neon-core {
|
|
6675
|
+
inset: 0;
|
|
6676
|
+
padding: var(--neon-tube-width);
|
|
6677
|
+
background: var(--neon-core);
|
|
6678
|
+
}
|
|
6679
|
+
|
|
6680
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
6681
|
+
/* The beams chase round the tube. */
|
|
6682
|
+
.neon-border-container.neon-animated {
|
|
6683
|
+
animation: neon-travel var(--neon-duration) linear infinite;
|
|
6684
|
+
}
|
|
6685
|
+
|
|
6686
|
+
/* The tube strikes once on first paint… */
|
|
6687
|
+
.neon-border-container .neon-light {
|
|
6688
|
+
animation: neon-ignite 0.9s steps(1, end) both;
|
|
6689
|
+
}
|
|
6690
|
+
|
|
6691
|
+
/* …then hums: a slow breathing of the glow. */
|
|
6692
|
+
.neon-border-container .neon-glow {
|
|
6693
|
+
animation: neon-hum 2.8s ease-in-out 0.9s infinite alternate;
|
|
6694
|
+
}
|
|
6695
|
+
}
|
|
6696
|
+
|
|
6697
|
+
@keyframes neon-travel {
|
|
6698
|
+
from {
|
|
6699
|
+
--neon-angle: 135deg;
|
|
6700
|
+
}
|
|
6701
|
+
to {
|
|
6702
|
+
--neon-angle: 495deg;
|
|
6703
|
+
}
|
|
4414
6704
|
}
|
|
4415
6705
|
|
|
4416
|
-
@keyframes neon-
|
|
6706
|
+
@keyframes neon-ignite {
|
|
4417
6707
|
0% {
|
|
4418
|
-
|
|
6708
|
+
opacity: 0;
|
|
6709
|
+
}
|
|
6710
|
+
10% {
|
|
6711
|
+
opacity: 0.8;
|
|
6712
|
+
}
|
|
6713
|
+
18% {
|
|
6714
|
+
opacity: 0.1;
|
|
6715
|
+
}
|
|
6716
|
+
30% {
|
|
6717
|
+
opacity: 1;
|
|
6718
|
+
}
|
|
6719
|
+
40% {
|
|
6720
|
+
opacity: 0.35;
|
|
6721
|
+
}
|
|
6722
|
+
52% {
|
|
6723
|
+
opacity: 1;
|
|
4419
6724
|
}
|
|
4420
6725
|
100% {
|
|
4421
|
-
|
|
6726
|
+
opacity: 1;
|
|
4422
6727
|
}
|
|
4423
6728
|
}
|
|
4424
6729
|
|
|
4425
|
-
|
|
4426
|
-
|
|
6730
|
+
@keyframes neon-hum {
|
|
6731
|
+
from {
|
|
6732
|
+
opacity: var(--neon-glow-max);
|
|
6733
|
+
}
|
|
6734
|
+
to {
|
|
6735
|
+
opacity: var(--neon-glow-min);
|
|
6736
|
+
}
|
|
4427
6737
|
}
|
|
4428
6738
|
.ft-number-input-field:focus-visible {
|
|
4429
6739
|
--ft-number-input-accent: var(
|
|
@@ -4510,31 +6820,50 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
4510
6820
|
}
|
|
4511
6821
|
|
|
4512
6822
|
/*
|
|
4513
|
-
* The
|
|
4514
|
-
*
|
|
4515
|
-
*
|
|
4516
|
-
* `
|
|
4517
|
-
* above, and a focus ring must never animate. `data-armed` keeps the pop
|
|
4518
|
-
* off the first paint (see the component). `--ft-ease-out` because the pill
|
|
4519
|
-
* arrives at its new place — it is not toggling in position.
|
|
4520
|
-
*
|
|
4521
|
-
* 150ms = tokens.DURATIONS.fast, cubic-bezier(0.16, 1, 0.3, 1) = tokens.EASINGS.out
|
|
6823
|
+
* The nav is the page buttons' `offsetParent` (no `<ul>`/`<li>` in between
|
|
6824
|
+
* is positioned), so `offsetLeft`/`offsetTop` and the pill's own
|
|
6825
|
+
* `left: 0; top: 0` share one origin. `isolation` lets the pill sit at
|
|
6826
|
+
* `z-index: -1` — above the nav's background, under the buttons.
|
|
4522
6827
|
*/
|
|
4523
|
-
|
|
4524
|
-
|
|
4525
|
-
|
|
4526
|
-
var(--ft-ease-out, cubic-bezier(0.16, 1, 0.3, 1));
|
|
4527
|
-
}
|
|
6828
|
+
.ft-pagination {
|
|
6829
|
+
position: relative;
|
|
6830
|
+
isolation: isolate;
|
|
4528
6831
|
}
|
|
4529
6832
|
|
|
4530
|
-
|
|
4531
|
-
|
|
4532
|
-
|
|
4533
|
-
|
|
4534
|
-
|
|
4535
|
-
|
|
4536
|
-
|
|
4537
|
-
|
|
6833
|
+
.ft-pagination-indicator {
|
|
6834
|
+
position: absolute;
|
|
6835
|
+
left: 0;
|
|
6836
|
+
top: 0;
|
|
6837
|
+
z-index: -1;
|
|
6838
|
+
pointer-events: none;
|
|
6839
|
+
border-radius: var(--radius-md, 0.375rem);
|
|
6840
|
+
background: var(--ft-pagination-indicator-color, var(--color-accent));
|
|
6841
|
+
opacity: 0;
|
|
6842
|
+
}
|
|
6843
|
+
|
|
6844
|
+
.ft-pagination[data-indicator] .ft-pagination-indicator {
|
|
6845
|
+
opacity: 1;
|
|
6846
|
+
}
|
|
6847
|
+
|
|
6848
|
+
/* The pill has taken over: the current button's own fill steps aside. */
|
|
6849
|
+
.ft-pagination[data-indicator] button[aria-current="page"] {
|
|
6850
|
+
background: transparent;
|
|
6851
|
+
}
|
|
6852
|
+
|
|
6853
|
+
/*
|
|
6854
|
+
* 300ms = tokens.DURATIONS.base, cubic-bezier(0.16, 1, 0.3, 1) =
|
|
6855
|
+
* tokens.EASINGS.out — the same curve and length as the numbers' own
|
|
6856
|
+
* glide, so the pill lands with its number. Gated: under reduced
|
|
6857
|
+
* motion the pill still follows the page, it just arrives.
|
|
6858
|
+
*/
|
|
6859
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
6860
|
+
.ft-pagination[data-armed="true"] .ft-pagination-indicator {
|
|
6861
|
+
transition: transform
|
|
6862
|
+
var(
|
|
6863
|
+
--ft-pagination-slide-duration,
|
|
6864
|
+
var(--ft-pagination-pop-duration, var(--ft-duration-base, 300ms))
|
|
6865
|
+
)
|
|
6866
|
+
var(--ft-ease-out, cubic-bezier(0.16, 1, 0.3, 1));
|
|
4538
6867
|
}
|
|
4539
6868
|
}
|
|
4540
6869
|
/*
|
|
@@ -4917,6 +7246,110 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
4917
7246
|
.rainbow-button::before {
|
|
4918
7247
|
animation: rainbow var(--rainbow-speed, 2s) infinite linear;
|
|
4919
7248
|
}
|
|
7249
|
+
|
|
7250
|
+
/*
|
|
7251
|
+
* Hover beam: a rainbow light that rides the border. One conic gradient,
|
|
7252
|
+
* turned through a registered angle, drawn twice — masked to the border ring
|
|
7253
|
+
* (the beam itself) and blurred around the button (its halo).
|
|
7254
|
+
*/
|
|
7255
|
+
@property --beam-angle {
|
|
7256
|
+
syntax: "<angle>";
|
|
7257
|
+
inherits: true;
|
|
7258
|
+
initial-value: 0deg;
|
|
7259
|
+
}
|
|
7260
|
+
|
|
7261
|
+
.rainbow-button {
|
|
7262
|
+
--beam-width: 1.5px;
|
|
7263
|
+
--glow-reach: 6px;
|
|
7264
|
+
--glow-blur: 10px;
|
|
7265
|
+
--beam: conic-gradient(
|
|
7266
|
+
from var(--beam-angle),
|
|
7267
|
+
transparent 0%,
|
|
7268
|
+
var(--rainbow-4) 5%,
|
|
7269
|
+
var(--rainbow-3) 10%,
|
|
7270
|
+
var(--rainbow-2) 15%,
|
|
7271
|
+
var(--rainbow-1) 20%,
|
|
7272
|
+
hsl(35 100% 60%) 24%,
|
|
7273
|
+
transparent 31%,
|
|
7274
|
+
transparent 50%,
|
|
7275
|
+
var(--rainbow-5) 55%,
|
|
7276
|
+
var(--rainbow-4) 60%,
|
|
7277
|
+
var(--rainbow-3) 64%,
|
|
7278
|
+
transparent 71%
|
|
7279
|
+
);
|
|
7280
|
+
}
|
|
7281
|
+
|
|
7282
|
+
.rainbow-button .rainbow-button__beam,
|
|
7283
|
+
.rainbow-button .rainbow-button__glow {
|
|
7284
|
+
position: absolute;
|
|
7285
|
+
border-radius: inherit;
|
|
7286
|
+
pointer-events: none;
|
|
7287
|
+
opacity: 0;
|
|
7288
|
+
transition: opacity 0.35s ease;
|
|
7289
|
+
}
|
|
7290
|
+
|
|
7291
|
+
/* keep only the padding ring: the element minus its content box */
|
|
7292
|
+
.rainbow-button .rainbow-button__beam,
|
|
7293
|
+
.rainbow-button .rainbow-button__glow > span {
|
|
7294
|
+
background: var(--beam);
|
|
7295
|
+
-webkit-mask:
|
|
7296
|
+
linear-gradient(#000 0 0) content-box,
|
|
7297
|
+
linear-gradient(#000 0 0);
|
|
7298
|
+
-webkit-mask-composite: xor;
|
|
7299
|
+
mask:
|
|
7300
|
+
linear-gradient(#000 0 0) content-box,
|
|
7301
|
+
linear-gradient(#000 0 0);
|
|
7302
|
+
mask-composite: exclude;
|
|
7303
|
+
}
|
|
7304
|
+
|
|
7305
|
+
/* the beam itself, on the border */
|
|
7306
|
+
.rainbow-button .rainbow-button__beam {
|
|
7307
|
+
inset: calc(-1 * var(--beam-width));
|
|
7308
|
+
padding: var(--beam-width);
|
|
7309
|
+
z-index: 1;
|
|
7310
|
+
}
|
|
7311
|
+
|
|
7312
|
+
/* its halo: a wider ring, blurred AFTER masking so both edges go soft */
|
|
7313
|
+
.rainbow-button .rainbow-button__glow {
|
|
7314
|
+
inset: 0;
|
|
7315
|
+
filter: blur(var(--glow-blur));
|
|
7316
|
+
}
|
|
7317
|
+
|
|
7318
|
+
.rainbow-button .rainbow-button__glow > span {
|
|
7319
|
+
position: absolute;
|
|
7320
|
+
inset: calc(-1 * var(--glow-reach));
|
|
7321
|
+
padding: var(--glow-reach);
|
|
7322
|
+
border-radius: calc(0.75rem + var(--glow-reach));
|
|
7323
|
+
}
|
|
7324
|
+
|
|
7325
|
+
.rainbow-button:hover .rainbow-button__beam,
|
|
7326
|
+
.rainbow-button:focus-visible .rainbow-button__beam {
|
|
7327
|
+
opacity: 1;
|
|
7328
|
+
}
|
|
7329
|
+
|
|
7330
|
+
.rainbow-button:hover .rainbow-button__glow,
|
|
7331
|
+
.rainbow-button:focus-visible .rainbow-button__glow {
|
|
7332
|
+
opacity: 0.6;
|
|
7333
|
+
}
|
|
7334
|
+
|
|
7335
|
+
.rainbow-button:hover,
|
|
7336
|
+
.rainbow-button:focus-visible {
|
|
7337
|
+
animation: beam-spin calc(var(--rainbow-speed, 2s) * 1.5) linear infinite;
|
|
7338
|
+
}
|
|
7339
|
+
|
|
7340
|
+
@keyframes beam-spin {
|
|
7341
|
+
to {
|
|
7342
|
+
--beam-angle: 360deg;
|
|
7343
|
+
}
|
|
7344
|
+
}
|
|
7345
|
+
|
|
7346
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7347
|
+
.rainbow-button:hover,
|
|
7348
|
+
.rainbow-button:focus-visible {
|
|
7349
|
+
animation: none;
|
|
7350
|
+
--beam-angle: 200deg;
|
|
7351
|
+
}
|
|
7352
|
+
}
|
|
4920
7353
|
/*
|
|
4921
7354
|
* `.fancy-reasoning-panel` is a PORT-ADDED anchor (PORTING.md, styling rule 2).
|
|
4922
7355
|
* The source's <style> block was compiler-scoped and had no root class; plain
|
|
@@ -5175,22 +7608,146 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
5175
7608
|
.animate-ripple-circle {
|
|
5176
7609
|
animation: ripple-effect 2s ease-in-out infinite;
|
|
5177
7610
|
}
|
|
5178
|
-
|
|
7611
|
+
/* Every rule is anchored on the root class `ripple-button` (the Svelte source
|
|
7612
|
+
names it on the root; its compiler scoped the inner selectors). As plain CSS,
|
|
7613
|
+
a bare `.ripple-hover` / `.ripple-animation` would leak into any consumer
|
|
7614
|
+
element of that name. See PORTING.md, styling rule 2. */
|
|
7615
|
+
|
|
7616
|
+
/* Hover: a fingertip over water. */
|
|
7617
|
+
.ripple-button .ripple-hover {
|
|
7618
|
+
position: absolute;
|
|
7619
|
+
inset: 0;
|
|
7620
|
+
pointer-events: none;
|
|
7621
|
+
opacity: 0;
|
|
7622
|
+
transition: opacity 0.3s ease;
|
|
7623
|
+
background: radial-gradient(
|
|
7624
|
+
80px circle at var(--ripple-x, 50%) var(--ripple-y, 50%),
|
|
7625
|
+
color-mix(in srgb, var(--ripple-color) 20%, transparent),
|
|
7626
|
+
transparent 70%
|
|
7627
|
+
);
|
|
7628
|
+
}
|
|
7629
|
+
|
|
7630
|
+
.ripple-button .ripple-hover::after {
|
|
7631
|
+
content: "";
|
|
7632
|
+
position: absolute;
|
|
7633
|
+
left: var(--ripple-x, 50%);
|
|
7634
|
+
top: var(--ripple-y, 50%);
|
|
7635
|
+
width: 72px;
|
|
7636
|
+
height: 72px;
|
|
7637
|
+
margin: -36px 0 0 -36px;
|
|
7638
|
+
border-radius: 50%;
|
|
7639
|
+
border: 1px solid color-mix(in srgb, var(--ripple-color) 55%, transparent);
|
|
7640
|
+
opacity: 0;
|
|
7641
|
+
transform: scale(0.2);
|
|
7642
|
+
}
|
|
7643
|
+
|
|
7644
|
+
.ripple-button:hover .ripple-hover {
|
|
7645
|
+
opacity: 1;
|
|
7646
|
+
}
|
|
7647
|
+
|
|
7648
|
+
.ripple-button:hover .ripple-hover::after {
|
|
7649
|
+
animation: ripple-idle 1.8s cubic-bezier(0.22, 0.61, 0.36, 1) infinite;
|
|
7650
|
+
}
|
|
7651
|
+
|
|
7652
|
+
.ripple-button:hover {
|
|
7653
|
+
border-color: color-mix(in srgb, var(--ripple-color) 35%, transparent);
|
|
7654
|
+
}
|
|
7655
|
+
|
|
7656
|
+
@keyframes ripple-idle {
|
|
5179
7657
|
0% {
|
|
5180
|
-
transform: scale(0);
|
|
5181
|
-
opacity: 0.
|
|
7658
|
+
transform: scale(0.2);
|
|
7659
|
+
opacity: 0.9;
|
|
5182
7660
|
}
|
|
5183
7661
|
100% {
|
|
5184
|
-
transform: scale(
|
|
7662
|
+
transform: scale(1);
|
|
5185
7663
|
opacity: 0;
|
|
5186
7664
|
}
|
|
5187
7665
|
}
|
|
5188
7666
|
|
|
5189
|
-
/*
|
|
5190
|
-
|
|
5191
|
-
|
|
7667
|
+
/* The border takes the ripple's tint while a ripple runs. */
|
|
7668
|
+
.ripple-button[data-rippling] {
|
|
7669
|
+
border-color: color-mix(in srgb, var(--ripple-color) 55%, transparent);
|
|
7670
|
+
}
|
|
7671
|
+
|
|
7672
|
+
/* A soft glow that blooms and fades… */
|
|
5192
7673
|
.ripple-button .ripple-animation {
|
|
5193
|
-
|
|
7674
|
+
background: radial-gradient(
|
|
7675
|
+
circle,
|
|
7676
|
+
color-mix(in srgb, var(--ripple-color) 40%, transparent) 0%,
|
|
7677
|
+
color-mix(in srgb, var(--ripple-color) 16%, transparent) 45%,
|
|
7678
|
+
transparent 70%
|
|
7679
|
+
);
|
|
7680
|
+
animation: ripple-bloom var(--ripple-duration, 900ms) cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
|
7681
|
+
}
|
|
7682
|
+
|
|
7683
|
+
/* …and two fine rings, the second a beat behind, like a wave on water. */
|
|
7684
|
+
.ripple-button .ripple-animation::before,
|
|
7685
|
+
.ripple-button .ripple-animation::after {
|
|
7686
|
+
content: "";
|
|
7687
|
+
position: absolute;
|
|
7688
|
+
inset: 0;
|
|
7689
|
+
border-radius: 50%;
|
|
7690
|
+
border: 2px solid color-mix(in srgb, var(--ripple-color) 90%, transparent);
|
|
7691
|
+
transform: scale(0);
|
|
7692
|
+
opacity: 0;
|
|
7693
|
+
animation: ripple-ring var(--ripple-duration, 900ms) cubic-bezier(0.22, 0.61, 0.36, 1) forwards;
|
|
7694
|
+
}
|
|
7695
|
+
|
|
7696
|
+
.ripple-button .ripple-animation::after {
|
|
7697
|
+
border-width: 1.5px;
|
|
7698
|
+
animation-delay: calc(var(--ripple-duration, 900ms) * 0.12);
|
|
7699
|
+
}
|
|
7700
|
+
|
|
7701
|
+
@keyframes ripple-bloom {
|
|
7702
|
+
0% {
|
|
7703
|
+
transform: scale(0);
|
|
7704
|
+
opacity: 1;
|
|
7705
|
+
}
|
|
7706
|
+
100% {
|
|
7707
|
+
transform: scale(1);
|
|
7708
|
+
opacity: 0;
|
|
7709
|
+
}
|
|
7710
|
+
}
|
|
7711
|
+
|
|
7712
|
+
@keyframes ripple-ring {
|
|
7713
|
+
0% {
|
|
7714
|
+
transform: scale(0);
|
|
7715
|
+
opacity: 1;
|
|
7716
|
+
}
|
|
7717
|
+
60% {
|
|
7718
|
+
opacity: 0.8;
|
|
7719
|
+
}
|
|
7720
|
+
100% {
|
|
7721
|
+
transform: scale(1);
|
|
7722
|
+
opacity: 0;
|
|
7723
|
+
}
|
|
7724
|
+
}
|
|
7725
|
+
|
|
7726
|
+
/* Reduced motion: no expansion, just a brief glow where you pressed. */
|
|
7727
|
+
@media (prefers-reduced-motion: reduce) {
|
|
7728
|
+
.ripple-button:hover .ripple-hover::after {
|
|
7729
|
+
animation: none;
|
|
7730
|
+
}
|
|
7731
|
+
|
|
7732
|
+
.ripple-button .ripple-animation {
|
|
7733
|
+
animation-name: ripple-fade;
|
|
7734
|
+
}
|
|
7735
|
+
|
|
7736
|
+
.ripple-button .ripple-animation::before,
|
|
7737
|
+
.ripple-button .ripple-animation::after {
|
|
7738
|
+
display: none;
|
|
7739
|
+
}
|
|
7740
|
+
|
|
7741
|
+
@keyframes ripple-fade {
|
|
7742
|
+
0% {
|
|
7743
|
+
transform: scale(1);
|
|
7744
|
+
opacity: 1;
|
|
7745
|
+
}
|
|
7746
|
+
100% {
|
|
7747
|
+
transform: scale(1);
|
|
7748
|
+
opacity: 0;
|
|
7749
|
+
}
|
|
7750
|
+
}
|
|
5194
7751
|
}
|
|
5195
7752
|
/*
|
|
5196
7753
|
* Centring lives here rather than on a `-translate-x-1/2` utility: the
|
|
@@ -5370,37 +7927,123 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
5370
7927
|
border-color: var(--ft-field-accent);
|
|
5371
7928
|
box-shadow: 0 0 0 3px color-mix(in oklab, var(--ft-field-accent) 25%, transparent);
|
|
5372
7929
|
}
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
7930
|
+
/* Plain CSS is global: every selector carries the component prefix (.shimmer-button or .shimmer-button__*), so nothing leaks onto consumer elements. */
|
|
7931
|
+
.shimmer-button__rim,
|
|
7932
|
+
.shimmer-button__face,
|
|
7933
|
+
.shimmer-button__sheen,
|
|
7934
|
+
.shimmer-button__spot {
|
|
7935
|
+
position: absolute;
|
|
7936
|
+
pointer-events: none;
|
|
7937
|
+
border-radius: inherit;
|
|
7938
|
+
}
|
|
7939
|
+
|
|
7940
|
+
.shimmer-button__rim {
|
|
7941
|
+
inset: 0;
|
|
7942
|
+
z-index: -2;
|
|
7943
|
+
background: linear-gradient(
|
|
7944
|
+
to bottom,
|
|
7945
|
+
color-mix(in srgb, var(--shimmer-color) 28%, transparent),
|
|
7946
|
+
color-mix(in srgb, var(--shimmer-color) 6%, transparent) 55%,
|
|
7947
|
+
color-mix(in srgb, var(--shimmer-color) 14%, transparent)
|
|
7948
|
+
);
|
|
7949
|
+
}
|
|
7950
|
+
|
|
7951
|
+
.shimmer-button__face {
|
|
7952
|
+
inset: var(--cut);
|
|
7953
|
+
z-index: -1;
|
|
7954
|
+
border-radius: calc(var(--radius) - var(--cut));
|
|
7955
|
+
background:
|
|
7956
|
+
linear-gradient(
|
|
7957
|
+
to bottom,
|
|
7958
|
+
color-mix(in srgb, var(--shimmer-color) 10%, transparent),
|
|
7959
|
+
transparent 50%
|
|
7960
|
+
),
|
|
7961
|
+
var(--bg);
|
|
7962
|
+
box-shadow: inset 0 -10px 16px -12px color-mix(in srgb, var(--shimmer-color) 30%, transparent);
|
|
7963
|
+
}
|
|
7964
|
+
|
|
7965
|
+
/* Screen blend: the band lightens the face and lifts the label to full white. */
|
|
7966
|
+
.shimmer-button__sheen {
|
|
7967
|
+
inset: 0;
|
|
7968
|
+
z-index: 20;
|
|
7969
|
+
mix-blend-mode: screen;
|
|
7970
|
+
/* a wide soft halo with a thin brighter core */
|
|
7971
|
+
background:
|
|
7972
|
+
linear-gradient(
|
|
7973
|
+
108deg,
|
|
7974
|
+
transparent 44%,
|
|
7975
|
+
color-mix(in srgb, var(--shimmer-color) 38%, transparent) 50%,
|
|
7976
|
+
transparent 56%
|
|
7977
|
+
),
|
|
7978
|
+
linear-gradient(
|
|
7979
|
+
108deg,
|
|
7980
|
+
transparent 30%,
|
|
7981
|
+
color-mix(in srgb, var(--shimmer-color) 12%, transparent) 42%,
|
|
7982
|
+
color-mix(in srgb, var(--shimmer-color) 18%, transparent) 50%,
|
|
7983
|
+
color-mix(in srgb, var(--shimmer-color) 12%, transparent) 58%,
|
|
7984
|
+
transparent 70%
|
|
7985
|
+
);
|
|
7986
|
+
background-size: 250% 100%;
|
|
7987
|
+
background-repeat: no-repeat;
|
|
7988
|
+
background-position: 100% 0;
|
|
7989
|
+
animation: shimmer-sweep var(--speed) cubic-bezier(0.4, 0, 0.2, 1) infinite;
|
|
7990
|
+
transition: opacity 0.3s ease;
|
|
7991
|
+
}
|
|
7992
|
+
|
|
7993
|
+
.shimmer-button__spot {
|
|
7994
|
+
inset: 0;
|
|
7995
|
+
z-index: 20;
|
|
7996
|
+
mix-blend-mode: screen;
|
|
7997
|
+
opacity: 0;
|
|
7998
|
+
background: radial-gradient(
|
|
7999
|
+
90px circle at var(--mx, 50%) var(--my, 50%),
|
|
8000
|
+
color-mix(in srgb, var(--shimmer-color) 34%, transparent),
|
|
8001
|
+
transparent 70%
|
|
8002
|
+
);
|
|
8003
|
+
transition: opacity 0.3s ease;
|
|
8004
|
+
}
|
|
8005
|
+
|
|
8006
|
+
.shimmer-button:hover .shimmer-button__spot {
|
|
8007
|
+
opacity: 1;
|
|
8008
|
+
}
|
|
8009
|
+
|
|
8010
|
+
/* The pointer takes over from the sweep while hovering. */
|
|
8011
|
+
.shimmer-button:hover .shimmer-button__sheen {
|
|
8012
|
+
opacity: 0;
|
|
8013
|
+
}
|
|
8014
|
+
|
|
8015
|
+
.shimmer-button:focus-visible {
|
|
8016
|
+
outline: 2px solid color-mix(in srgb, var(--shimmer-color) 70%, transparent);
|
|
8017
|
+
outline-offset: 2px;
|
|
8018
|
+
}
|
|
8019
|
+
|
|
8020
|
+
.shimmer-button:disabled {
|
|
8021
|
+
cursor: not-allowed;
|
|
8022
|
+
opacity: 0.5;
|
|
8023
|
+
}
|
|
8024
|
+
|
|
8025
|
+
.shimmer-button:disabled .shimmer-button__sheen,
|
|
8026
|
+
.shimmer-button:disabled .shimmer-button__spot {
|
|
8027
|
+
display: none;
|
|
5377
8028
|
}
|
|
5378
8029
|
|
|
5379
|
-
|
|
8030
|
+
/* Sweep across in the first 55% of the cycle, then rest off-button. */
|
|
8031
|
+
@keyframes shimmer-sweep {
|
|
5380
8032
|
0% {
|
|
5381
|
-
|
|
5382
|
-
}
|
|
5383
|
-
15%,
|
|
5384
|
-
35% {
|
|
5385
|
-
transform: translateZ(0) rotate(90deg);
|
|
5386
|
-
}
|
|
5387
|
-
65%,
|
|
5388
|
-
85% {
|
|
5389
|
-
transform: translateZ(0) rotate(270deg);
|
|
8033
|
+
background-position: 100% 0;
|
|
5390
8034
|
}
|
|
8035
|
+
55%,
|
|
5391
8036
|
100% {
|
|
5392
|
-
|
|
8037
|
+
background-position: 0% 0;
|
|
5393
8038
|
}
|
|
5394
8039
|
}
|
|
5395
8040
|
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
.shimmer-button .spin-around {
|
|
5403
|
-
animation: spin-around calc(var(--speed) * 2) infinite linear;
|
|
8041
|
+
@media (prefers-reduced-motion: reduce) {
|
|
8042
|
+
.shimmer-button__sheen {
|
|
8043
|
+
animation: none;
|
|
8044
|
+
background-position: 38% 0;
|
|
8045
|
+
opacity: 0.6;
|
|
8046
|
+
}
|
|
5404
8047
|
}
|
|
5405
8048
|
/*
|
|
5406
8049
|
* `SidebarItem` declares this same fallback again, locally on itself —
|
|
@@ -5744,11 +8387,111 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
5744
8387
|
box-shadow: 0 0 0 4px color-mix(in oklab, var(--ft-slider-accent) 25%, transparent);
|
|
5745
8388
|
}
|
|
5746
8389
|
|
|
5747
|
-
.ft-slider:disabled::-webkit-slider-thumb {
|
|
5748
|
-
box-shadow: none;
|
|
8390
|
+
.ft-slider:disabled::-webkit-slider-thumb {
|
|
8391
|
+
box-shadow: none;
|
|
8392
|
+
}
|
|
8393
|
+
.ft-slider:disabled::-moz-range-thumb {
|
|
8394
|
+
box-shadow: none;
|
|
8395
|
+
}
|
|
8396
|
+
/*
|
|
8397
|
+
* SmoothCursor — the Svelte source's scoped <style> block. Plain CSS is global,
|
|
8398
|
+
* so every rule is anchored on the component's own root class `.smooth-cursor`
|
|
8399
|
+
* (the Svelte root already carries it). Class names and custom properties are
|
|
8400
|
+
* identical to the Svelte source.
|
|
8401
|
+
*/
|
|
8402
|
+
|
|
8403
|
+
.smooth-cursor {
|
|
8404
|
+
--_sc-hot: color-mix(in oklab, var(--_sc-color) 45%, white);
|
|
8405
|
+
--_sc-deep: color-mix(in oklab, var(--_sc-color) 82%, black);
|
|
8406
|
+
--_sc-ink: var(--smooth-cursor-label-color, #fff);
|
|
8407
|
+
}
|
|
8408
|
+
|
|
8409
|
+
.smooth-cursor .sc-pointer,
|
|
8410
|
+
.smooth-cursor .sc-label {
|
|
8411
|
+
position: absolute;
|
|
8412
|
+
top: 0;
|
|
8413
|
+
left: 0;
|
|
8414
|
+
will-change: transform;
|
|
8415
|
+
}
|
|
8416
|
+
|
|
8417
|
+
/* The arrow always paints over the pill when the pill catches up behind it. */
|
|
8418
|
+
.smooth-cursor .sc-pointer {
|
|
8419
|
+
z-index: 1;
|
|
8420
|
+
}
|
|
8421
|
+
|
|
8422
|
+
.smooth-cursor .sc-arrow {
|
|
8423
|
+
display: block;
|
|
8424
|
+
overflow: visible;
|
|
8425
|
+
filter: drop-shadow(0 1px 1.25px rgb(0 0 0 / 0.32))
|
|
8426
|
+
drop-shadow(0 4px 9px color-mix(in oklab, var(--_sc-color) 38%, transparent));
|
|
8427
|
+
}
|
|
8428
|
+
|
|
8429
|
+
/* Rotating mode: turn the arrowhead so it points "up" — the engine's 0deg. */
|
|
8430
|
+
.smooth-cursor .sc-pointer--rotate .sc-arrow {
|
|
8431
|
+
rotate: 32.5deg;
|
|
8432
|
+
}
|
|
8433
|
+
|
|
8434
|
+
.smooth-cursor .sc-arrow-rim {
|
|
8435
|
+
stroke: #fff;
|
|
8436
|
+
stroke-width: 3;
|
|
8437
|
+
stroke-linejoin: round;
|
|
8438
|
+
paint-order: stroke fill;
|
|
8439
|
+
}
|
|
8440
|
+
|
|
8441
|
+
.smooth-cursor .sc-stop-hot {
|
|
8442
|
+
stop-color: var(--_sc-hot);
|
|
8443
|
+
}
|
|
8444
|
+
.smooth-cursor .sc-stop-body {
|
|
8445
|
+
stop-color: var(--_sc-color);
|
|
8446
|
+
}
|
|
8447
|
+
.smooth-cursor .sc-stop-deep {
|
|
8448
|
+
stop-color: var(--_sc-deep);
|
|
8449
|
+
}
|
|
8450
|
+
|
|
8451
|
+
/* Name pill: tucked under the arrow's back edge, square-ish corner pointing at the tip. */
|
|
8452
|
+
.smooth-cursor .sc-label {
|
|
8453
|
+
translate: 13px 17px;
|
|
8454
|
+
transform-origin: 0 0;
|
|
8455
|
+
display: flex;
|
|
8456
|
+
align-items: center;
|
|
8457
|
+
max-width: 180px;
|
|
8458
|
+
height: 22px;
|
|
8459
|
+
padding: 0 9px;
|
|
8460
|
+
border-radius: 3px 11px 11px 11px;
|
|
8461
|
+
background: linear-gradient(
|
|
8462
|
+
180deg,
|
|
8463
|
+
color-mix(in oklab, var(--_sc-color) 86%, white) 0%,
|
|
8464
|
+
var(--_sc-color) 55%,
|
|
8465
|
+
color-mix(in oklab, var(--_sc-color) 92%, black) 100%
|
|
8466
|
+
);
|
|
8467
|
+
color: var(--_sc-ink);
|
|
8468
|
+
box-shadow:
|
|
8469
|
+
0 0 0 1px rgb(255 255 255 / 0.92),
|
|
8470
|
+
inset 0 1px 0 rgb(255 255 255 / 0.28),
|
|
8471
|
+
0 1px 2px rgb(0 0 0 / 0.28),
|
|
8472
|
+
0 6px 16px -4px color-mix(in oklab, var(--_sc-color) 45%, transparent);
|
|
8473
|
+
opacity: 1;
|
|
8474
|
+
}
|
|
8475
|
+
|
|
8476
|
+
.smooth-cursor .sc-label-text {
|
|
8477
|
+
overflow: hidden;
|
|
8478
|
+
font-size: 12px;
|
|
8479
|
+
font-weight: 500;
|
|
8480
|
+
line-height: 1;
|
|
8481
|
+
letter-spacing: 0.01em;
|
|
8482
|
+
white-space: nowrap;
|
|
8483
|
+
text-overflow: ellipsis;
|
|
8484
|
+
text-shadow: 0 1px 0 rgb(0 0 0 / 0.14);
|
|
5749
8485
|
}
|
|
5750
|
-
|
|
5751
|
-
|
|
8486
|
+
|
|
8487
|
+
.smooth-cursor .sc-label.is-idle {
|
|
8488
|
+
opacity: 0.35;
|
|
8489
|
+
}
|
|
8490
|
+
|
|
8491
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
8492
|
+
.smooth-cursor .sc-label {
|
|
8493
|
+
transition: opacity 300ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
8494
|
+
}
|
|
5752
8495
|
}
|
|
5753
8496
|
.ft-sources-trigger {
|
|
5754
8497
|
border: 1px solid
|
|
@@ -5884,47 +8627,69 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
5884
8627
|
transform: scale(0) rotate(150deg);
|
|
5885
8628
|
}
|
|
5886
8629
|
}
|
|
8630
|
+
/*
|
|
8631
|
+
* Port note: Svelte scoped these rules; plain CSS is global, so every
|
|
8632
|
+
* selector below is anchored on a class this component owns and puts on its
|
|
8633
|
+
* own elements (`.ft-step`, `.ft-step-bullet*`, `.ft-step-connector*`,
|
|
8634
|
+
* `.ft-step-glyph`, `.ft-step-check`, `.ft-step-trigger`, `.ft-step-animate`
|
|
8635
|
+
* — all of them the Svelte source's own names, already on the elements'
|
|
8636
|
+
* class lists). No anchor had to be added. Everything below is copied
|
|
8637
|
+
* verbatim from the Svelte source's <style> block.
|
|
8638
|
+
*/
|
|
8639
|
+
|
|
5887
8640
|
/*
|
|
5888
8641
|
* The only place this component reaches for the brand purple — the
|
|
5889
|
-
* current bullet's fill/halo and a
|
|
5890
|
-
*
|
|
5891
|
-
*
|
|
5892
|
-
*
|
|
5893
|
-
*
|
|
5894
|
-
*
|
|
5895
|
-
* in `Link`.
|
|
8642
|
+
* current bullet's fill/halo and a lit rail. No semantic token owns it,
|
|
8643
|
+
* so it's declared locally with a light-dark() fallback, retintable from
|
|
8644
|
+
* higher up the tree via `--ft-accent`. Mirrors ToggleGroupItem's
|
|
8645
|
+
* identical `--ft-toggle-group-accent` pattern. Never redeclare
|
|
8646
|
+
* `--ft-accent` itself: that would shadow whatever an ancestor set, the
|
|
8647
|
+
* exact bug an earlier wave shipped in `Link`.
|
|
5896
8648
|
*
|
|
5897
|
-
*
|
|
5898
|
-
*
|
|
5899
|
-
* (`.ft-step`, `.ft-step-bullet`, `.ft-step-connector`, `.ft-step-trigger`
|
|
5900
|
-
* — all of them the Svelte source's own names, already the first token of
|
|
5901
|
-
* the element's class list). No anchor had to be added.
|
|
8649
|
+
* Every private `--_x` reads a public `--ft-step-*` first, so a consumer
|
|
8650
|
+
* can retune the rail from a class without touching this file.
|
|
5902
8651
|
*/
|
|
5903
8652
|
.ft-step {
|
|
5904
8653
|
--ft-nav-accent: var(
|
|
5905
8654
|
--ft-accent,
|
|
5906
8655
|
light-dark(oklch(0.5432 0.2528 300.22), oklch(0.604 0.2606 301.75))
|
|
5907
8656
|
);
|
|
8657
|
+
/* What a lit rail settles to: the accent at reduced strength. */
|
|
8658
|
+
--_rail: var(--ft-step-rail, color-mix(in oklab, var(--ft-nav-accent) 58%, transparent));
|
|
8659
|
+
/* The head of the travelling light. White-hot on dark; on a light
|
|
8660
|
+
* surface a white core would vanish, so it stays close to the accent. */
|
|
8661
|
+
--_hot: var(
|
|
8662
|
+
--ft-step-glint,
|
|
8663
|
+
light-dark(
|
|
8664
|
+
color-mix(in oklab, var(--ft-nav-accent) 82%, white),
|
|
8665
|
+
color-mix(in oklab, var(--ft-nav-accent) 45%, white)
|
|
8666
|
+
)
|
|
8667
|
+
);
|
|
8668
|
+
--_sweep: var(--ft-step-sweep-duration, 420ms);
|
|
8669
|
+
/* One beat = how far behind the previous rail the next one lights, so
|
|
8670
|
+
* a multi-step jump reads as a single run of light. */
|
|
8671
|
+
--_beat: calc(var(--_sweep) * 0.7);
|
|
8672
|
+
--_ease-out: var(--ft-ease-out, cubic-bezier(0.16, 1, 0.3, 1));
|
|
5908
8673
|
}
|
|
5909
8674
|
|
|
5910
8675
|
/*
|
|
5911
8676
|
* A step's whole visible state — the bullet's fill, its label colour, the
|
|
5912
|
-
* halo around the current one, and the
|
|
5913
|
-
*
|
|
5914
|
-
* in the library.
|
|
8677
|
+
* halo around the current one, and the rail behind it — eases in on the
|
|
8678
|
+
* same clock as everything else in the library.
|
|
5915
8679
|
*
|
|
5916
8680
|
* Declared outside any `prefers-reduced-motion` query on purpose: none of
|
|
5917
|
-
* these
|
|
5918
|
-
*
|
|
5919
|
-
*
|
|
5920
|
-
*
|
|
5921
|
-
*
|
|
5922
|
-
*
|
|
8681
|
+
* these properties moves anything. A colour that crossfades and a static
|
|
8682
|
+
* ring that appears are state changes, not travel, and suppressing them
|
|
8683
|
+
* under reduced motion would make the stepper flicker rather than settle.
|
|
8684
|
+
* The focus ring is safe from this list because it lives on a different
|
|
8685
|
+
* element (`.ft-step-trigger`), so no `box-shadow` here is ever a focus
|
|
8686
|
+
* indicator.
|
|
5923
8687
|
*
|
|
5924
8688
|
* 150ms = tokens.DURATIONS.fast, cubic-bezier(0.4, 0, 0.2, 1) = tokens.EASINGS.inout
|
|
5925
8689
|
*/
|
|
5926
8690
|
.ft-step-bullet,
|
|
5927
|
-
.ft-step-connector
|
|
8691
|
+
.ft-step-connector,
|
|
8692
|
+
.ft-step-connector::before {
|
|
5928
8693
|
--ft-step-signal: var(--ft-step-signal-duration, var(--ft-duration-fast, 150ms))
|
|
5929
8694
|
var(--ft-ease-inout, cubic-bezier(0.4, 0, 0.2, 1));
|
|
5930
8695
|
transition:
|
|
@@ -5933,19 +8698,120 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
5933
8698
|
box-shadow var(--ft-step-signal);
|
|
5934
8699
|
}
|
|
5935
8700
|
|
|
8701
|
+
/* ---------------------------------------------------------------- bullets */
|
|
8702
|
+
|
|
8703
|
+
/*
|
|
8704
|
+
* The outline is an inset box-shadow, not a border: it then rides the
|
|
8705
|
+
* same (possibly delayed) transition as the fill, so a step the light is
|
|
8706
|
+
* still travelling towards keeps its ring until the light lands instead
|
|
8707
|
+
* of dropping it the instant `current` changes.
|
|
8708
|
+
*/
|
|
8709
|
+
.ft-step-bullet-upcoming {
|
|
8710
|
+
background: color-mix(in oklab, currentColor 5%, transparent);
|
|
8711
|
+
box-shadow: inset 0 0 0 1px
|
|
8712
|
+
var(--ft-step-outline, var(--border, color-mix(in oklab, currentColor 22%, transparent)));
|
|
8713
|
+
}
|
|
8714
|
+
|
|
5936
8715
|
.ft-step-bullet-done {
|
|
5937
8716
|
background: var(--ft-status-done, light-dark(oklch(0.5 0.14 145), oklch(0.72 0.15 145)));
|
|
5938
8717
|
color: light-dark(oklch(1 0 0), oklch(0.15 0 0));
|
|
8718
|
+
box-shadow:
|
|
8719
|
+
inset 0 1px 0 rgb(255 255 255 / 0.22),
|
|
8720
|
+
0 1px 2px rgb(0 0 0 / 0.12);
|
|
5939
8721
|
}
|
|
5940
8722
|
|
|
5941
8723
|
.ft-step-bullet-current {
|
|
5942
8724
|
background: var(--ft-nav-accent);
|
|
5943
8725
|
color: light-dark(oklch(1 0 0), oklch(0.15 0 0));
|
|
5944
|
-
box-shadow:
|
|
8726
|
+
box-shadow:
|
|
8727
|
+
inset 0 1px 0 rgb(255 255 255 / 0.28),
|
|
8728
|
+
0 1px 2px rgb(0 0 0 / 0.14);
|
|
5945
8729
|
}
|
|
5946
8730
|
|
|
5947
|
-
|
|
5948
|
-
|
|
8731
|
+
/*
|
|
8732
|
+
* The halo lives on its own layer so it can breathe through `opacity`
|
|
8733
|
+
* alone — never re-painting a box-shadow per frame, never scaling. At
|
|
8734
|
+
* rest (SSR, reduced motion) it is simply on.
|
|
8735
|
+
*/
|
|
8736
|
+
.ft-step-bullet-halo::before {
|
|
8737
|
+
content: "";
|
|
8738
|
+
position: absolute;
|
|
8739
|
+
inset: 0;
|
|
8740
|
+
border-radius: inherit;
|
|
8741
|
+
pointer-events: none;
|
|
8742
|
+
box-shadow:
|
|
8743
|
+
0 0 0 4px color-mix(in oklab, var(--ft-nav-accent) 18%, transparent),
|
|
8744
|
+
0 0 18px 2px color-mix(in oklab, var(--ft-nav-accent) 30%, transparent);
|
|
8745
|
+
}
|
|
8746
|
+
|
|
8747
|
+
.ft-step-glyph {
|
|
8748
|
+
display: inline-block;
|
|
8749
|
+
}
|
|
8750
|
+
|
|
8751
|
+
/* ------------------------------------------------------------------ rails */
|
|
8752
|
+
|
|
8753
|
+
/*
|
|
8754
|
+
* The rail is a hairline track (the connector itself, `bg-border`) with
|
|
8755
|
+
* two layers on top: `::before`, the settled fill, and `::after`, the
|
|
8756
|
+
* light that travels once across it when it lights.
|
|
8757
|
+
*
|
|
8758
|
+
* At rest the fill is full-length and only its colour changes, so the
|
|
8759
|
+
* no-motion path is a pure cross-fade.
|
|
8760
|
+
*/
|
|
8761
|
+
.ft-step-connector {
|
|
8762
|
+
/* Horizontal clip only — the travelling light may glow above and below
|
|
8763
|
+
* the rail but never spill past its ends onto a bullet. */
|
|
8764
|
+
clip-path: inset(-10px 0);
|
|
8765
|
+
}
|
|
8766
|
+
.ft-step[data-orientation="vertical"] .ft-step-connector {
|
|
8767
|
+
clip-path: inset(0 -10px);
|
|
8768
|
+
}
|
|
8769
|
+
|
|
8770
|
+
.ft-step-connector::before,
|
|
8771
|
+
.ft-step-connector::after {
|
|
8772
|
+
content: "";
|
|
8773
|
+
position: absolute;
|
|
8774
|
+
pointer-events: none;
|
|
8775
|
+
border-radius: inherit;
|
|
8776
|
+
}
|
|
8777
|
+
|
|
8778
|
+
.ft-step-connector::before {
|
|
8779
|
+
inset: 0;
|
|
8780
|
+
background-color: transparent;
|
|
8781
|
+
}
|
|
8782
|
+
.ft-step-connector-lit::before {
|
|
8783
|
+
background-color: var(--_rail);
|
|
8784
|
+
}
|
|
8785
|
+
|
|
8786
|
+
.ft-step-connector::after {
|
|
8787
|
+
top: 0;
|
|
8788
|
+
bottom: 0;
|
|
8789
|
+
left: 0;
|
|
8790
|
+
width: 45%;
|
|
8791
|
+
opacity: 0;
|
|
8792
|
+
background: linear-gradient(
|
|
8793
|
+
90deg,
|
|
8794
|
+
transparent,
|
|
8795
|
+
color-mix(in oklab, var(--ft-nav-accent) 55%, transparent) 45%,
|
|
8796
|
+
var(--ft-nav-accent) 78%,
|
|
8797
|
+
var(--_hot) 97%,
|
|
8798
|
+
var(--_hot)
|
|
8799
|
+
);
|
|
8800
|
+
filter: drop-shadow(0 0 3px color-mix(in oklab, var(--ft-nav-accent) 80%, transparent));
|
|
8801
|
+
}
|
|
8802
|
+
.ft-step[data-orientation="vertical"] .ft-step-connector::after {
|
|
8803
|
+
right: 0;
|
|
8804
|
+
width: auto;
|
|
8805
|
+
height: 45%;
|
|
8806
|
+
bottom: auto;
|
|
8807
|
+
background: linear-gradient(
|
|
8808
|
+
180deg,
|
|
8809
|
+
transparent,
|
|
8810
|
+
color-mix(in oklab, var(--ft-nav-accent) 55%, transparent) 45%,
|
|
8811
|
+
var(--ft-nav-accent) 78%,
|
|
8812
|
+
var(--_hot) 97%,
|
|
8813
|
+
var(--_hot)
|
|
8814
|
+
);
|
|
5949
8815
|
}
|
|
5950
8816
|
|
|
5951
8817
|
.ft-step-trigger:focus-visible {
|
|
@@ -5953,6 +8819,150 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
5953
8819
|
box-shadow: 0 0 0 3px color-mix(in oklab, var(--ft-nav-accent) 35%, transparent);
|
|
5954
8820
|
border-radius: 0.375rem;
|
|
5955
8821
|
}
|
|
8822
|
+
|
|
8823
|
+
/* ----------------------------------------------------------------- motion */
|
|
8824
|
+
|
|
8825
|
+
/*
|
|
8826
|
+
* Everything below travels, so it is doubly gated: the OS preference
|
|
8827
|
+
* (this query) and `.ft-step-animate`, which the root only hands out on
|
|
8828
|
+
* the client once it has read the same preference. The resting state
|
|
8829
|
+
* above is the fallback for both.
|
|
8830
|
+
*
|
|
8831
|
+
* `--ft-step-order` (rails) and `--ft-step-arrival` (bullets) are written
|
|
8832
|
+
* inline by `Step` — beats since the light set off from the previous
|
|
8833
|
+
* active step, so one jump across several steps lights them in sequence.
|
|
8834
|
+
*/
|
|
8835
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
8836
|
+
/* The fill grows along the rail instead of cross-fading, and retracts
|
|
8837
|
+
* the same way when the reader steps back. An unlit fill stays
|
|
8838
|
+
* transparent while collapsed: `.ft-step-animate` lands on elements
|
|
8839
|
+
* already painted (hydration, a post-paint effect, the OS preference
|
|
8840
|
+
* flipping), and a fill that turned the rail colour in that same style
|
|
8841
|
+
* change would show every unlit rail fully lit for its delay, then
|
|
8842
|
+
* retract. Its colour only drops once a retraction has finished
|
|
8843
|
+
* (a 0s transition delayed past the sweep); lighting switches it on
|
|
8844
|
+
* instantly while the fill is still collapsed. */
|
|
8845
|
+
.ft-step-animate .ft-step-connector::before {
|
|
8846
|
+
transform: scaleX(0);
|
|
8847
|
+
transform-origin: left center;
|
|
8848
|
+
transition:
|
|
8849
|
+
transform var(--_sweep) var(--_ease-out) calc(var(--ft-step-order, 0) * var(--_beat)),
|
|
8850
|
+
background-color 0s linear calc(var(--ft-step-order, 0) * var(--_beat) + var(--_sweep));
|
|
8851
|
+
}
|
|
8852
|
+
.ft-step-animate[data-orientation="vertical"] .ft-step-connector::before {
|
|
8853
|
+
transform: scaleY(0);
|
|
8854
|
+
transform-origin: center top;
|
|
8855
|
+
}
|
|
8856
|
+
.ft-step-animate .ft-step-connector-lit::before,
|
|
8857
|
+
.ft-step-animate[data-orientation="vertical"] .ft-step-connector-lit::before {
|
|
8858
|
+
transform: none;
|
|
8859
|
+
transition: transform var(--_sweep) var(--_ease-out)
|
|
8860
|
+
calc(var(--ft-step-order, 0) * var(--_beat));
|
|
8861
|
+
}
|
|
8862
|
+
|
|
8863
|
+
/* The light: a comet whose head rides exactly on the fill's leading
|
|
8864
|
+
* edge (same duration, same curve, translate range chosen so head =
|
|
8865
|
+
* fill edge), then fades once it has arrived. Keyed on the lit class,
|
|
8866
|
+
* so it plays once each time a rail lights — and once on first paint,
|
|
8867
|
+
* as the arrival. */
|
|
8868
|
+
.ft-step-animate .ft-step-connector-lit::after {
|
|
8869
|
+
animation:
|
|
8870
|
+
ft-step-sweep-x var(--_sweep) var(--_ease-out) calc(var(--ft-step-order, 0) * var(--_beat))
|
|
8871
|
+
both,
|
|
8872
|
+
ft-step-sweep-fade calc(var(--_sweep) * 0.7) linear
|
|
8873
|
+
calc(var(--ft-step-order, 0) * var(--_beat) + var(--_sweep) * 0.6) both;
|
|
8874
|
+
}
|
|
8875
|
+
.ft-step-animate[data-orientation="vertical"] .ft-step-connector-lit::after {
|
|
8876
|
+
animation-name: ft-step-sweep-y, ft-step-sweep-fade;
|
|
8877
|
+
}
|
|
8878
|
+
|
|
8879
|
+
/* A bullet the light is heading for settles when it gets there, not
|
|
8880
|
+
* the instant `current` changes. */
|
|
8881
|
+
.ft-step-animate .ft-step-bullet {
|
|
8882
|
+
transition-delay: calc(var(--ft-step-arrival, 0) * var(--_beat));
|
|
8883
|
+
}
|
|
8884
|
+
|
|
8885
|
+
/* The glyph swap: a short flip on whichever glyph just mounted, and the
|
|
8886
|
+
* check stroke drawing itself behind it. */
|
|
8887
|
+
.ft-step-animate .ft-step-glyph {
|
|
8888
|
+
transform-origin: center;
|
|
8889
|
+
animation: ft-step-flip 200ms var(--_ease-out) calc(var(--ft-step-arrival, 0) * var(--_beat))
|
|
8890
|
+
both;
|
|
8891
|
+
}
|
|
8892
|
+
.ft-step-animate .ft-step-check path {
|
|
8893
|
+
stroke-dasharray: 1;
|
|
8894
|
+
animation: ft-step-draw 320ms var(--_ease-out)
|
|
8895
|
+
calc(var(--ft-step-arrival, 0) * var(--_beat) + 60ms) both;
|
|
8896
|
+
}
|
|
8897
|
+
|
|
8898
|
+
/* The breathing halo — opacity only, no scale — faded in on arrival
|
|
8899
|
+
* through `filter` so the two animations never fight over `opacity`. */
|
|
8900
|
+
.ft-step-animate .ft-step-bullet-halo::before {
|
|
8901
|
+
animation:
|
|
8902
|
+
ft-step-halo-in 360ms var(--_ease-out) calc(var(--ft-step-arrival, 0) * var(--_beat)) both,
|
|
8903
|
+
ft-step-breathe 1.2s ease-in-out infinite alternate;
|
|
8904
|
+
}
|
|
8905
|
+
}
|
|
8906
|
+
|
|
8907
|
+
@keyframes ft-step-sweep-x {
|
|
8908
|
+
from {
|
|
8909
|
+
transform: translateX(-100%);
|
|
8910
|
+
}
|
|
8911
|
+
to {
|
|
8912
|
+
/* head (right edge, at 45% width) lands on the rail's far end */
|
|
8913
|
+
transform: translateX(122.3%);
|
|
8914
|
+
}
|
|
8915
|
+
}
|
|
8916
|
+
@keyframes ft-step-sweep-y {
|
|
8917
|
+
from {
|
|
8918
|
+
transform: translateY(-100%);
|
|
8919
|
+
}
|
|
8920
|
+
to {
|
|
8921
|
+
transform: translateY(122.3%);
|
|
8922
|
+
}
|
|
8923
|
+
}
|
|
8924
|
+
@keyframes ft-step-sweep-fade {
|
|
8925
|
+
from {
|
|
8926
|
+
opacity: 1;
|
|
8927
|
+
}
|
|
8928
|
+
to {
|
|
8929
|
+
opacity: 0;
|
|
8930
|
+
}
|
|
8931
|
+
}
|
|
8932
|
+
@keyframes ft-step-breathe {
|
|
8933
|
+
from {
|
|
8934
|
+
opacity: 0.5;
|
|
8935
|
+
}
|
|
8936
|
+
to {
|
|
8937
|
+
opacity: 1;
|
|
8938
|
+
}
|
|
8939
|
+
}
|
|
8940
|
+
@keyframes ft-step-halo-in {
|
|
8941
|
+
from {
|
|
8942
|
+
filter: opacity(0);
|
|
8943
|
+
}
|
|
8944
|
+
to {
|
|
8945
|
+
filter: opacity(1);
|
|
8946
|
+
}
|
|
8947
|
+
}
|
|
8948
|
+
@keyframes ft-step-flip {
|
|
8949
|
+
from {
|
|
8950
|
+
transform: perspective(60px) rotateX(90deg);
|
|
8951
|
+
opacity: 0;
|
|
8952
|
+
}
|
|
8953
|
+
to {
|
|
8954
|
+
transform: perspective(60px) rotateX(0deg);
|
|
8955
|
+
opacity: 1;
|
|
8956
|
+
}
|
|
8957
|
+
}
|
|
8958
|
+
@keyframes ft-step-draw {
|
|
8959
|
+
from {
|
|
8960
|
+
stroke-dashoffset: 1;
|
|
8961
|
+
}
|
|
8962
|
+
to {
|
|
8963
|
+
stroke-dashoffset: 0;
|
|
8964
|
+
}
|
|
8965
|
+
}
|
|
5956
8966
|
/*
|
|
5957
8967
|
* The two-column ⇄ stacked switch is FLEX WRAPPING, not a `@container`
|
|
5958
8968
|
* query, and deliberately so: an element is styled by the query containers
|
|
@@ -7007,6 +10017,263 @@ svg[data-state="error"] .ft-statusmorph-cross-b {
|
|
|
7007
10017
|
border-color: var(--ft-field-accent);
|
|
7008
10018
|
box-shadow: 0 0 0 3px color-mix(in oklab, var(--ft-field-accent) 25%, transparent);
|
|
7009
10019
|
}
|
|
10020
|
+
/*
|
|
10021
|
+
* Timeline "light rail". Mirrors the Svelte <style> block rule for rule. The
|
|
10022
|
+
* Svelte compiler scoped every selector; here each one is anchored on the
|
|
10023
|
+
* source's own root class `.tl-root` so no generic name leaks into the page.
|
|
10024
|
+
*/
|
|
10025
|
+
.tl-root {
|
|
10026
|
+
/* Public hooks: --timeline-accent (colour). --tl-progress is written by the component. */
|
|
10027
|
+
--_tl-accent: var(--timeline-accent, var(--primary, oklch(0.7 0.13 285)));
|
|
10028
|
+
--_tl-cool: oklch(0.72 0.1 262);
|
|
10029
|
+
/* Light surfaces: the glow leans on the cool tint so a dark accent never reads as a smudge. */
|
|
10030
|
+
--_tl-glow: color-mix(in oklab, var(--_tl-accent) 40%, var(--_tl-cool));
|
|
10031
|
+
--_tl-hot: color-mix(in oklab, var(--_tl-accent) 45%, white);
|
|
10032
|
+
--_tl-core: var(--_tl-accent);
|
|
10033
|
+
--_tl-hair: rgba(0, 0, 0, 0.12);
|
|
10034
|
+
--_tl-ring: rgba(0, 0, 0, 0.2);
|
|
10035
|
+
--_tl-surface: var(--background, #fafafa);
|
|
10036
|
+
--_tl-muted: rgba(0, 0, 0, 0.42);
|
|
10037
|
+
--_tl-glow-a: 38%;
|
|
10038
|
+
--_tl-ease: cubic-bezier(0.16, 1, 0.3, 1);
|
|
10039
|
+
--_tl-x: 2rem;
|
|
10040
|
+
}
|
|
10041
|
+
|
|
10042
|
+
.dark .tl-root {
|
|
10043
|
+
--_tl-glow: color-mix(in oklab, var(--_tl-accent) 72%, var(--_tl-cool));
|
|
10044
|
+
--_tl-core: var(--_tl-hot);
|
|
10045
|
+
--_tl-hair: rgba(255, 255, 255, 0.12);
|
|
10046
|
+
--_tl-ring: rgba(255, 255, 255, 0.2);
|
|
10047
|
+
--_tl-muted: rgba(255, 255, 255, 0.38);
|
|
10048
|
+
--_tl-glow-a: 60%;
|
|
10049
|
+
}
|
|
10050
|
+
|
|
10051
|
+
/* ── Rail ─────────────────────────────────────────────── */
|
|
10052
|
+
.tl-root .tl-rail {
|
|
10053
|
+
position: absolute;
|
|
10054
|
+
top: 0;
|
|
10055
|
+
left: calc(var(--_tl-x) - 1px);
|
|
10056
|
+
width: 3px;
|
|
10057
|
+
pointer-events: none;
|
|
10058
|
+
-webkit-mask-image: linear-gradient(
|
|
10059
|
+
to bottom,
|
|
10060
|
+
transparent 0,
|
|
10061
|
+
#000 7%,
|
|
10062
|
+
#000 93%,
|
|
10063
|
+
transparent 100%
|
|
10064
|
+
);
|
|
10065
|
+
mask-image: linear-gradient(to bottom, transparent 0, #000 7%, #000 93%, transparent 100%);
|
|
10066
|
+
}
|
|
10067
|
+
|
|
10068
|
+
.tl-root .tl-rail-line,
|
|
10069
|
+
.tl-root .tl-trail {
|
|
10070
|
+
position: absolute;
|
|
10071
|
+
inset: 0 auto 0 1px;
|
|
10072
|
+
width: 1px;
|
|
10073
|
+
}
|
|
10074
|
+
|
|
10075
|
+
.tl-root .tl-rail-line {
|
|
10076
|
+
background: var(--_tl-hair);
|
|
10077
|
+
}
|
|
10078
|
+
|
|
10079
|
+
/* The filled part: faint far behind, brightening into the head, nothing past it. */
|
|
10080
|
+
.tl-root .tl-trail {
|
|
10081
|
+
background: linear-gradient(
|
|
10082
|
+
to bottom,
|
|
10083
|
+
transparent 0,
|
|
10084
|
+
color-mix(in oklab, var(--_tl-accent) 22%, transparent) calc(var(--tl-progress) - 320px),
|
|
10085
|
+
color-mix(in oklab, var(--_tl-glow) 85%, transparent) var(--tl-progress),
|
|
10086
|
+
transparent var(--tl-progress)
|
|
10087
|
+
);
|
|
10088
|
+
}
|
|
10089
|
+
|
|
10090
|
+
/* ── Head ─────────────────────────────────────────────── */
|
|
10091
|
+
.tl-root .tl-head {
|
|
10092
|
+
position: absolute;
|
|
10093
|
+
top: 0;
|
|
10094
|
+
left: calc(var(--_tl-x) + 0.5px);
|
|
10095
|
+
z-index: 50;
|
|
10096
|
+
width: 0;
|
|
10097
|
+
height: 0;
|
|
10098
|
+
pointer-events: none;
|
|
10099
|
+
transform: translate3d(0, var(--tl-progress), 0);
|
|
10100
|
+
opacity: 0;
|
|
10101
|
+
}
|
|
10102
|
+
|
|
10103
|
+
.tl-root .tl-head[data-ready="true"] {
|
|
10104
|
+
opacity: 1;
|
|
10105
|
+
}
|
|
10106
|
+
|
|
10107
|
+
.tl-root .tl-head > span {
|
|
10108
|
+
position: absolute;
|
|
10109
|
+
display: block;
|
|
10110
|
+
border-radius: 999px;
|
|
10111
|
+
}
|
|
10112
|
+
|
|
10113
|
+
.tl-root .tl-head-streak {
|
|
10114
|
+
left: -1px;
|
|
10115
|
+
top: -96px;
|
|
10116
|
+
width: 2px;
|
|
10117
|
+
height: 96px;
|
|
10118
|
+
background: linear-gradient(
|
|
10119
|
+
to top,
|
|
10120
|
+
var(--_tl-hot),
|
|
10121
|
+
color-mix(in oklab, var(--_tl-glow) 55%, transparent) 35%,
|
|
10122
|
+
transparent
|
|
10123
|
+
);
|
|
10124
|
+
filter: blur(0.6px);
|
|
10125
|
+
}
|
|
10126
|
+
|
|
10127
|
+
.tl-root .tl-head-halo {
|
|
10128
|
+
left: -28px;
|
|
10129
|
+
top: -28px;
|
|
10130
|
+
width: 56px;
|
|
10131
|
+
height: 56px;
|
|
10132
|
+
background: radial-gradient(
|
|
10133
|
+
closest-side,
|
|
10134
|
+
color-mix(in oklab, var(--_tl-glow) var(--_tl-glow-a), transparent),
|
|
10135
|
+
color-mix(in oklab, var(--_tl-glow) 14%, transparent) 55%,
|
|
10136
|
+
transparent
|
|
10137
|
+
);
|
|
10138
|
+
filter: blur(6px);
|
|
10139
|
+
}
|
|
10140
|
+
|
|
10141
|
+
.tl-root .tl-head-core {
|
|
10142
|
+
left: -3.5px;
|
|
10143
|
+
top: -3.5px;
|
|
10144
|
+
width: 7px;
|
|
10145
|
+
height: 7px;
|
|
10146
|
+
background: var(--_tl-core);
|
|
10147
|
+
box-shadow:
|
|
10148
|
+
0 0 0 1.5px color-mix(in oklab, var(--_tl-hot) 45%, transparent),
|
|
10149
|
+
0 0 10px 1px color-mix(in oklab, var(--_tl-glow) 70%, transparent);
|
|
10150
|
+
}
|
|
10151
|
+
|
|
10152
|
+
/* ── Dots ─────────────────────────────────────────────── */
|
|
10153
|
+
.tl-root .tl-dot {
|
|
10154
|
+
position: relative;
|
|
10155
|
+
display: grid;
|
|
10156
|
+
place-items: center;
|
|
10157
|
+
width: 15px;
|
|
10158
|
+
height: 15px;
|
|
10159
|
+
border-radius: 999px;
|
|
10160
|
+
border: 1px solid var(--_tl-ring);
|
|
10161
|
+
background: var(--_tl-surface);
|
|
10162
|
+
transform: scale(0.8);
|
|
10163
|
+
}
|
|
10164
|
+
|
|
10165
|
+
.tl-root .tl-dot-core {
|
|
10166
|
+
width: 7px;
|
|
10167
|
+
height: 7px;
|
|
10168
|
+
border-radius: 999px;
|
|
10169
|
+
background: var(--_tl-core);
|
|
10170
|
+
opacity: 0;
|
|
10171
|
+
transform: scale(0.2);
|
|
10172
|
+
}
|
|
10173
|
+
|
|
10174
|
+
.tl-root .tl-dot-flare {
|
|
10175
|
+
position: absolute;
|
|
10176
|
+
inset: -1px;
|
|
10177
|
+
border-radius: 999px;
|
|
10178
|
+
border: 1px solid color-mix(in oklab, var(--_tl-glow) 70%, transparent);
|
|
10179
|
+
opacity: 0;
|
|
10180
|
+
pointer-events: none;
|
|
10181
|
+
}
|
|
10182
|
+
|
|
10183
|
+
.tl-root .tl-dot[data-lit="true"] {
|
|
10184
|
+
transform: scale(1);
|
|
10185
|
+
border-color: color-mix(in oklab, var(--_tl-accent) 55%, var(--_tl-ring));
|
|
10186
|
+
box-shadow: 0 0 12px color-mix(in oklab, var(--_tl-glow) 40%, transparent);
|
|
10187
|
+
}
|
|
10188
|
+
|
|
10189
|
+
.tl-root .tl-dot[data-lit="true"] .tl-dot-core {
|
|
10190
|
+
opacity: 1;
|
|
10191
|
+
transform: scale(1);
|
|
10192
|
+
}
|
|
10193
|
+
|
|
10194
|
+
/* ── Labels ───────────────────────────────────────────── */
|
|
10195
|
+
/* Sits above the label out of flow, so the dot centres on the label itself. */
|
|
10196
|
+
.tl-root .tl-index {
|
|
10197
|
+
position: absolute;
|
|
10198
|
+
bottom: calc(100% + 0.2rem);
|
|
10199
|
+
display: block;
|
|
10200
|
+
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
10201
|
+
font-size: 0.6875rem;
|
|
10202
|
+
letter-spacing: 0.12em;
|
|
10203
|
+
color: var(--_tl-muted);
|
|
10204
|
+
transition: color 260ms ease;
|
|
10205
|
+
}
|
|
10206
|
+
|
|
10207
|
+
.tl-root .tl-heading {
|
|
10208
|
+
color: var(--_tl-muted);
|
|
10209
|
+
transition: color 260ms ease;
|
|
10210
|
+
}
|
|
10211
|
+
|
|
10212
|
+
.tl-root .tl-row[data-state="active"] .tl-heading {
|
|
10213
|
+
color: color-mix(in oklab, var(--_tl-accent) 28%, var(--foreground, #0a0a0a));
|
|
10214
|
+
}
|
|
10215
|
+
|
|
10216
|
+
.tl-root .tl-row[data-state="active"] .tl-index {
|
|
10217
|
+
color: color-mix(in oklab, var(--_tl-glow) 70%, var(--foreground, #0a0a0a));
|
|
10218
|
+
}
|
|
10219
|
+
|
|
10220
|
+
.tl-root .tl-row[data-state="past"] .tl-label-text,
|
|
10221
|
+
.tl-root .tl-row[data-state="past"] .tl-content {
|
|
10222
|
+
opacity: 0.5;
|
|
10223
|
+
}
|
|
10224
|
+
|
|
10225
|
+
/* ── Motion ───────────────────────────────────────────── */
|
|
10226
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
10227
|
+
.tl-root[data-motion="full"] .tl-head {
|
|
10228
|
+
transition: opacity 500ms var(--_tl-ease);
|
|
10229
|
+
}
|
|
10230
|
+
|
|
10231
|
+
.tl-root[data-motion="full"] .tl-dot {
|
|
10232
|
+
transition:
|
|
10233
|
+
transform 260ms var(--_tl-ease),
|
|
10234
|
+
border-color 260ms ease,
|
|
10235
|
+
box-shadow 260ms ease;
|
|
10236
|
+
}
|
|
10237
|
+
|
|
10238
|
+
.tl-root[data-motion="full"] .tl-dot-core {
|
|
10239
|
+
transition:
|
|
10240
|
+
transform 260ms var(--_tl-ease),
|
|
10241
|
+
opacity 200ms ease;
|
|
10242
|
+
}
|
|
10243
|
+
|
|
10244
|
+
.tl-root[data-motion="full"] .tl-dot[data-lit="true"] .tl-dot-flare {
|
|
10245
|
+
animation: tl-ignite 700ms var(--_tl-ease) both;
|
|
10246
|
+
}
|
|
10247
|
+
|
|
10248
|
+
.tl-root[data-motion="full"] .tl-label-text,
|
|
10249
|
+
.tl-root[data-motion="full"] .tl-content {
|
|
10250
|
+
transition: opacity 300ms var(--_tl-ease);
|
|
10251
|
+
}
|
|
10252
|
+
}
|
|
10253
|
+
|
|
10254
|
+
@keyframes tl-ignite {
|
|
10255
|
+
from {
|
|
10256
|
+
opacity: 0.9;
|
|
10257
|
+
transform: scale(1);
|
|
10258
|
+
}
|
|
10259
|
+
to {
|
|
10260
|
+
opacity: 0;
|
|
10261
|
+
transform: scale(2.6);
|
|
10262
|
+
}
|
|
10263
|
+
}
|
|
10264
|
+
|
|
10265
|
+
/* ── Reduced motion: a plain filled rail, no glow, dots lit by position ── */
|
|
10266
|
+
.tl-root[data-motion="reduced"] .tl-trail {
|
|
10267
|
+
background: linear-gradient(
|
|
10268
|
+
to bottom,
|
|
10269
|
+
color-mix(in oklab, var(--_tl-accent) 70%, transparent) var(--tl-progress),
|
|
10270
|
+
transparent var(--tl-progress)
|
|
10271
|
+
);
|
|
10272
|
+
}
|
|
10273
|
+
|
|
10274
|
+
.tl-root[data-motion="reduced"] .tl-dot[data-lit="true"] {
|
|
10275
|
+
box-shadow: none;
|
|
10276
|
+
}
|
|
7010
10277
|
/*
|
|
7011
10278
|
* Declared locally, once, from the shared consumer-facing `--ft-accent` —
|
|
7012
10279
|
* the same indirection `Button` (`--ft-btn-accent`) and `Popover`
|