@birdycom/omniaui 0.12.6 → 0.13.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/bin/lib/copy-js.mjs +2 -0
- package/dist/components.css +720 -41
- package/dist/components.min.css +1 -1
- package/dist/contact-form.d.ts +5 -0
- package/dist/contact-form.js +138 -0
- package/dist/fly.d.ts +4 -0
- package/dist/fly.js +80 -0
- package/dist/oc-theme.css +3 -1
- package/dist/parts/app-result.css +39 -0
- package/dist/parts/forms-form.css +76 -0
- package/dist/parts/media-lightbox.css +4 -0
- package/dist/parts/site-base.css +33 -0
- package/dist/parts/site-brand-mark.css +56 -0
- package/dist/parts/site-cards.css +183 -0
- package/dist/parts/site-fly.css +40 -0
- package/dist/parts/site-layout.css +69 -0
- package/dist/parts/site-panel.css +29 -0
- package/dist/parts/site-prose.css +12 -0
- package/dist/parts/utility-hover.css +44 -0
- package/dist/showcase.css +81 -19
- package/manifest.json +72 -0
- package/package.json +4 -2
- package/snippets/brand-mark.html +41 -0
- package/snippets/feature-card.html +52 -0
- package/snippets/fly-in.html +30 -0
- package/snippets/hover-effects.html +19 -0
- package/snippets/icon-list.html +28 -0
- package/snippets/lazy.html +7 -7
- package/snippets/name-card.html +4 -4
- package/snippets/page-sections.html +50 -0
- package/snippets/panel.html +18 -0
- package/snippets/result.html +31 -0
- package/snippets/ribbon.html +8 -8
- package/snippets/shot-grid.html +27 -0
package/dist/components.css
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
/* File: oc-theme.css — generated from tokens/semantic.json by @birdycom/omniacss 0.
|
|
1
|
+
/* File: oc-theme.css — generated from tokens/semantic.json by @birdycom/omniacss 0.13.0. Do not edit. */
|
|
2
2
|
/* Semantic theme tokens: every color is light-dark() of an Omnia palette token (oc-colors.css). */
|
|
3
3
|
/* Same source as the desktop export: npx omniacss tokens --format json|dtcg|python */
|
|
4
4
|
:root {
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
--oc-foreground: light-dark(var(--color-duskblue-60), var(--color-frostblue-10));
|
|
15
15
|
--oc-muted: light-dark(var(--color-frostblue-60), var(--color-shallowblue-50));
|
|
16
16
|
--oc-muted-foreground: light-dark(var(--color-stormblue-40), var(--color-mistblue-70));
|
|
17
|
+
--oc-subtle-foreground: light-dark(var(--color-stormblue-10), var(--color-mistblue-95));
|
|
17
18
|
--oc-card: light-dark(var(--color-white-50), var(--color-shallowblue-70));
|
|
18
19
|
--oc-popover: light-dark(var(--color-white-50), var(--color-shallowblue-60));
|
|
19
20
|
--oc-popover-foreground: var(--oc-foreground);
|
|
@@ -58,6 +59,7 @@
|
|
|
58
59
|
--oc-transition-normal: 200ms cubic-bezier(0.4, 0, 0.2, 1);
|
|
59
60
|
--oc-font-sans: system-ui, -apple-system, "Segoe UI", Roboto, Cantarell, "Helvetica Neue", sans-serif;
|
|
60
61
|
--oc-font-mono: "Cascadia Code", "JetBrains Mono", Consolas, ui-monospace, monospace;
|
|
62
|
+
--oc-font-display: system-ui, -apple-system, "Segoe UI", Roboto, Cantarell, "Helvetica Neue", sans-serif;
|
|
61
63
|
|
|
62
64
|
/* Shadows (x y blur spread; color + alpha per mode in --oc-shadow-<name>-color) */
|
|
63
65
|
--oc-shadow-sm-color: light-dark(oklch(from var(--color-stormblue-50) l c h / 0.08), oklch(from var(--color-black-50) l c h / 0.4));
|
|
@@ -346,7 +348,8 @@ flex-direction: column;
|
|
|
346
348
|
justify-content: center;
|
|
347
349
|
gap: 8px;
|
|
348
350
|
font-family: inherit;
|
|
349
|
-
|
|
351
|
+
/* --oc-btn-weight: a theme can make every button bolder (600). */
|
|
352
|
+
font-weight: var(--oc-btn-weight, 500);
|
|
350
353
|
font-size: 0.875rem;
|
|
351
354
|
line-height: 1.25rem;
|
|
352
355
|
padding: 0.5rem 1rem;
|
|
@@ -481,8 +484,8 @@ flex-direction: column;
|
|
|
481
484
|
}
|
|
482
485
|
|
|
483
486
|
.oc-btn--lg {
|
|
484
|
-
font-size: 1rem;
|
|
485
|
-
padding: 0.625rem 1.5rem;
|
|
487
|
+
font-size: var(--oc-btn-lg-size, 1rem);
|
|
488
|
+
padding: var(--oc-btn-lg-padding, 0.625rem 1.5rem);
|
|
486
489
|
border-radius: calc(var(--oc-radius) + 2px);
|
|
487
490
|
}
|
|
488
491
|
|
|
@@ -710,8 +713,10 @@ flex-direction: column;
|
|
|
710
713
|
}
|
|
711
714
|
|
|
712
715
|
.oc-field-error {
|
|
716
|
+
margin: 0;
|
|
713
717
|
font-size: 0.8rem;
|
|
714
|
-
|
|
718
|
+
/* In dark mode lifted to at least OKLCH L 0.78, so the message stays readable on a dark card. */
|
|
719
|
+
color: light-dark(var(--oc-destructive), oklch(from var(--oc-destructive) max(l, 0.78) c h));
|
|
715
720
|
}
|
|
716
721
|
|
|
717
722
|
/* Field group — wraps multiple fields with consistent spacing */
|
|
@@ -724,17 +729,23 @@ flex-direction: column;
|
|
|
724
729
|
grid-template-columns: 1fr 1fr;
|
|
725
730
|
}
|
|
726
731
|
|
|
727
|
-
/*
|
|
732
|
+
/* Narrow screens: the fields of a row stack. */
|
|
733
|
+
@media (max-width: 560px) {
|
|
734
|
+
.oc-field-group--row { grid-template-columns: 1fr; }
|
|
735
|
+
}
|
|
736
|
+
|
|
737
|
+
/* Text input. A theme or a form variant (.oc-form--filled) can set the field tokens: --oc-input-bg, --oc-input-border,
|
|
738
|
+
--oc-input-padding, --oc-input-radius, --oc-input-size, --oc-ring-width and --oc-ring-alpha (focus ring). */
|
|
728
739
|
.oc-input {
|
|
729
740
|
display: block;
|
|
730
741
|
width: 100%;
|
|
731
742
|
font-family: inherit;
|
|
732
|
-
font-size: 0.875rem;
|
|
743
|
+
font-size: var(--oc-input-size, 0.875rem);
|
|
733
744
|
line-height: 1.5;
|
|
734
|
-
padding: 0.5rem 0.75rem;
|
|
735
|
-
border: 1px solid var(--oc-input);
|
|
736
|
-
border-radius: var(--oc-radius);
|
|
737
|
-
background: transparent;
|
|
745
|
+
padding: var(--oc-input-padding, 0.5rem 0.75rem);
|
|
746
|
+
border: 1px solid var(--oc-input-border, var(--oc-input));
|
|
747
|
+
border-radius: var(--oc-input-radius, var(--oc-radius));
|
|
748
|
+
background: var(--oc-input-bg, transparent);
|
|
738
749
|
color: var(--oc-foreground);
|
|
739
750
|
transition: border-color var(--oc-transition-fast), box-shadow var(--oc-transition-fast);
|
|
740
751
|
outline: none;
|
|
@@ -746,7 +757,7 @@ flex-direction: column;
|
|
|
746
757
|
|
|
747
758
|
.oc-input:focus {
|
|
748
759
|
border-color: var(--oc-ring);
|
|
749
|
-
box-shadow: 0 0 0 2px color-mix(in srgb, var(--oc-ring) 25
|
|
760
|
+
box-shadow: 0 0 0 var(--oc-ring-width, 2px) color-mix(in srgb, var(--oc-ring) var(--oc-ring-alpha, 25%), transparent);
|
|
750
761
|
}
|
|
751
762
|
|
|
752
763
|
.oc-input:disabled {
|
|
@@ -762,12 +773,13 @@ flex-direction: column;
|
|
|
762
773
|
|
|
763
774
|
.oc-input[aria-invalid="true"]:focus,
|
|
764
775
|
.oc-input--error:focus {
|
|
765
|
-
box-shadow: 0 0 0 2px color-mix(in srgb, var(--oc-destructive) 25
|
|
776
|
+
box-shadow: 0 0 0 var(--oc-ring-width, 2px) color-mix(in srgb, var(--oc-destructive) var(--oc-ring-alpha, 25%), transparent);
|
|
766
777
|
}
|
|
767
778
|
|
|
768
779
|
/* Textarea — same base as input */
|
|
769
|
-
textarea.oc-input
|
|
770
|
-
|
|
780
|
+
textarea.oc-input,
|
|
781
|
+
.oc-textarea {
|
|
782
|
+
min-height: var(--oc-textarea-min, 80px);
|
|
771
783
|
resize: vertical;
|
|
772
784
|
}
|
|
773
785
|
|
|
@@ -811,12 +823,13 @@ textarea.oc-input {
|
|
|
811
823
|
display: block;
|
|
812
824
|
width: 100%;
|
|
813
825
|
font-family: inherit;
|
|
814
|
-
font-size: 0.875rem;
|
|
826
|
+
font-size: var(--oc-input-size, 0.875rem);
|
|
815
827
|
line-height: 1.5;
|
|
816
|
-
padding:
|
|
817
|
-
|
|
818
|
-
border
|
|
819
|
-
|
|
828
|
+
padding: var(--oc-input-padding, 0.5rem 0.75rem);
|
|
829
|
+
padding-inline-end: 2rem;
|
|
830
|
+
border: 1px solid var(--oc-input-border, var(--oc-input));
|
|
831
|
+
border-radius: var(--oc-input-radius, var(--oc-radius));
|
|
832
|
+
background-color: var(--oc-input-bg, transparent);
|
|
820
833
|
color: var(--oc-foreground);
|
|
821
834
|
appearance: none;
|
|
822
835
|
background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3e%3cpath fill='none' stroke='%2371717a' stroke-linecap='round' stroke-linejoin='round' stroke-width='2' d='m2 5 6 6 6-6'/%3e%3c/svg%3e");
|
|
@@ -830,8 +843,9 @@ textarea.oc-input {
|
|
|
830
843
|
|
|
831
844
|
.oc-select:focus {
|
|
832
845
|
border-color: var(--oc-ring);
|
|
833
|
-
box-shadow: 0 0 0 2px color-mix(in srgb, var(--oc-ring) 25
|
|
846
|
+
box-shadow: 0 0 0 var(--oc-ring-width, 2px) color-mix(in srgb, var(--oc-ring) var(--oc-ring-alpha, 25%), transparent);
|
|
834
847
|
}
|
|
848
|
+
.oc-select[aria-invalid="true"] { border-color: var(--oc-destructive); }
|
|
835
849
|
|
|
836
850
|
/* Select option dark theme — prevents white background in dropdowns */
|
|
837
851
|
.oc-select option {
|
|
@@ -1599,7 +1613,7 @@ textarea.oc-input {
|
|
|
1599
1613
|
border: none;
|
|
1600
1614
|
height: 1px;
|
|
1601
1615
|
background: var(--oc-border);
|
|
1602
|
-
margin: 16px 0;
|
|
1616
|
+
margin: var(--oc-separator-space, 16px) 0;
|
|
1603
1617
|
}
|
|
1604
1618
|
|
|
1605
1619
|
.oc-separator--vertical {
|
|
@@ -3789,7 +3803,8 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
3789
3803
|
/* border-box: the gradient also runs under the transparent 1px border of .oc-btn; from the padding box it would
|
|
3790
3804
|
repeat in that border and show a thin stripe of the other end's color on both sides. */
|
|
3791
3805
|
background: linear-gradient(100deg, var(--oc-accent-from), var(--oc-accent-to)) border-box;
|
|
3792
|
-
|
|
3806
|
+
/* --oc-btn-gradient-ink: dark text on a light accent (set it with the accent). */
|
|
3807
|
+
color: var(--oc-btn-gradient-ink, var(--color-white-50));
|
|
3793
3808
|
box-shadow: 0 10px 30px -10px var(--oc-accent-to);
|
|
3794
3809
|
transition: transform 0.2s var(--oc-ease-out), box-shadow 0.2s;
|
|
3795
3810
|
}
|
|
@@ -3816,7 +3831,8 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
3816
3831
|
|
|
3817
3832
|
/* Backdrop: slowly drifting color blobs + fine grid behind the page.
|
|
3818
3833
|
<div class="oc-backdrop" aria-hidden="true"><i class="oc-backdrop__blob"></i><i class="oc-backdrop__grid"></i></div>
|
|
3819
|
-
.oc-backdrop--local keeps it inside a positioned section instead of the viewport.
|
|
3834
|
+
.oc-backdrop--local keeps it inside a positioned section instead of the viewport.
|
|
3835
|
+
A theme sets the colors: --oc-backdrop-1, -2, -3 (the blobs), --oc-backdrop-3-opacity and --oc-backdrop-grid (the lines). */
|
|
3820
3836
|
.oc-backdrop {
|
|
3821
3837
|
position: fixed;
|
|
3822
3838
|
inset: 0;
|
|
@@ -3837,24 +3853,27 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
3837
3853
|
opacity: var(--oc-backdrop-opacity, 0.35);
|
|
3838
3854
|
animation: oc-drift 24s ease-in-out infinite alternate;
|
|
3839
3855
|
}
|
|
3840
|
-
.oc-backdrop::before { background: var(--color-blue-40); inset-block-start: -18rem; inset-inline-start: -12rem; }
|
|
3841
|
-
.oc-backdrop::after { background: var(--color-purple-30); inset-block-start: 10rem; inset-inline-end: -16rem; animation-delay: -8s; }
|
|
3842
|
-
.oc-backdrop > .oc-backdrop__blob { background: var(--color-teal-40); inset-block-end: -20rem; inset-inline-start: 30%; animation-delay: -16s; opacity: calc(var(--oc-backdrop-opacity, 0.35) * 0.6); }
|
|
3856
|
+
.oc-backdrop::before { background: var(--oc-backdrop-1, var(--color-blue-40)); inset-block-start: -18rem; inset-inline-start: -12rem; }
|
|
3857
|
+
.oc-backdrop::after { background: var(--oc-backdrop-2, var(--color-purple-30)); inset-block-start: 10rem; inset-inline-end: -16rem; animation-delay: -8s; }
|
|
3858
|
+
.oc-backdrop > .oc-backdrop__blob { background: var(--oc-backdrop-3, var(--color-teal-40)); inset-block-end: -20rem; inset-inline-start: 30%; animation-delay: -16s; opacity: var(--oc-backdrop-3-opacity, calc(var(--oc-backdrop-opacity, 0.35) * 0.6)); }
|
|
3843
3859
|
.oc-backdrop > .oc-backdrop__grid {
|
|
3844
3860
|
position: absolute;
|
|
3845
3861
|
inset: 0;
|
|
3846
3862
|
background-image:
|
|
3847
|
-
linear-gradient(oklch(from var(--oc-foreground) l c h / 0.05) 1px, transparent 1px),
|
|
3848
|
-
linear-gradient(90deg, oklch(from var(--oc-foreground) l c h / 0.05) 1px, transparent 1px);
|
|
3863
|
+
linear-gradient(var(--oc-backdrop-grid, oklch(from var(--oc-foreground) l c h / 0.05)) 1px, transparent 1px),
|
|
3864
|
+
linear-gradient(90deg, var(--oc-backdrop-grid, oklch(from var(--oc-foreground) l c h / 0.05)) 1px, transparent 1px);
|
|
3849
3865
|
background-size: 64px 64px;
|
|
3850
3866
|
mask-image: radial-gradient(ellipse at 50% 0%, black 20%, transparent 70%);
|
|
3851
3867
|
}
|
|
3852
3868
|
@keyframes oc-drift { to { transform: translate(6rem, 4rem) scale(1.15); } }
|
|
3853
3869
|
|
|
3854
3870
|
/* Container, section spacing and display headings */
|
|
3855
|
-
|
|
3871
|
+
/* --oc-container is the width, --oc-container-gutter the room on each side on a narrower screen (1.25rem). */
|
|
3872
|
+
.oc-container { inline-size: min(100% - 2 * var(--oc-container-gutter, 1.25rem), var(--oc-container, 1200px)); margin-inline: auto; }
|
|
3856
3873
|
.oc-section-pad { padding-block: clamp(4rem, 9vw, 7rem); }
|
|
3857
3874
|
.oc-section-pad--tight { padding-block: clamp(2rem, 5vw, 3.5rem); }
|
|
3875
|
+
/* The hero of a home page: a little less room on top and below than a section. */
|
|
3876
|
+
.oc-section-pad--hero { padding-block: clamp(3.5rem, 9vw, 7rem) clamp(3rem, 6vw, 5rem); }
|
|
3858
3877
|
.oc-display {
|
|
3859
3878
|
margin: 0 0 1.5rem;
|
|
3860
3879
|
font-size: clamp(2.6rem, 5.6vw, 4.6rem);
|
|
@@ -3864,8 +3883,28 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
3864
3883
|
text-wrap: balance;
|
|
3865
3884
|
}
|
|
3866
3885
|
.oc-display--md { font-size: clamp(1.9rem, 4vw, 3rem); }
|
|
3886
|
+
.oc-display--sm { font-size: clamp(1.5rem, 3vw, 2.1rem); }
|
|
3867
3887
|
.oc-lead { margin: 0 0 1rem; color: var(--oc-muted-foreground); font-size: 1.15rem; line-height: 1.65; max-inline-size: 42rem; text-wrap: pretty; }
|
|
3868
|
-
|
|
3888
|
+
/* Larger and narrower, for a home hero. */
|
|
3889
|
+
.oc-lead--lg { font-size: 1.2rem; max-inline-size: 36rem; }
|
|
3890
|
+
.oc-split { display: grid; grid-template-columns: var(--oc-split-cols, repeat(auto-fit, minmax(min(100%, 24rem), 1fr))); gap: var(--oc-split-gap, 3rem); align-items: center; }
|
|
3891
|
+
/* Ratio presets (one column up to 960px): --lead makes the text column wider, --media the image column.
|
|
3892
|
+
Your own ratio: set --oc-split-cols in a class (and to 1fr in a media query for small screens). */
|
|
3893
|
+
.oc-split--lead { --oc-split-cols: 1.25fr 1fr; }
|
|
3894
|
+
.oc-split--media { --oc-split-cols: 1fr 1.15fr; }
|
|
3895
|
+
.oc-split__media { display: grid; place-items: center; }
|
|
3896
|
+
/* Columns aligned at the top (a fact list next to a long text). */
|
|
3897
|
+
.oc-split--top { align-items: start; }
|
|
3898
|
+
/* --oc-split-cols-wide: your own ratio that only applies above 960px, so the split still stacks on a phone. */
|
|
3899
|
+
@media (min-width: 961px) {
|
|
3900
|
+
.oc-split { grid-template-columns: var(--oc-split-cols-wide, var(--oc-split-cols, repeat(auto-fit, minmax(min(100%, 24rem), 1fr)))); }
|
|
3901
|
+
}
|
|
3902
|
+
@media (max-width: 960px) {
|
|
3903
|
+
.oc-split--lead, .oc-split--media { --oc-split-cols: 1fr; }
|
|
3904
|
+
/* The image (a product mark, a screenshot) comes first on a small screen, aligned at the start, and an xl tile shrinks. */
|
|
3905
|
+
.oc-split__media { order: -1; justify-items: start; }
|
|
3906
|
+
.oc-split__media .oc-icon-tile--xl { --oc-tile-size: 7rem; }
|
|
3907
|
+
}
|
|
3869
3908
|
|
|
3870
3909
|
/* Code window: editor frame with traffic lights and a file name. It follows the page theme: a light frame and light
|
|
3871
3910
|
syntax colors in light mode, the Omnia Dark editor colors in dark mode. --dark keeps it dark on a light page (the
|
|
@@ -3953,7 +3992,12 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
3953
3992
|
@keyframes oc-float { 50% { translate: 0 -12px; } }
|
|
3954
3993
|
|
|
3955
3994
|
/* Product / feature card with hover lift and accent glow */
|
|
3956
|
-
.oc-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--oc-card-min, 17rem)), 1fr)); gap: 1.25rem; }
|
|
3995
|
+
.oc-card-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, var(--oc-card-min, 17rem)), 1fr)); gap: var(--oc-card-gap, 1.25rem); }
|
|
3996
|
+
/* Wide cards (projects, case studies): from 32rem, three in a row on a wide screen. */
|
|
3997
|
+
.oc-card-grid--wide { --oc-card-min: 32rem; --oc-card-gap: 1.5rem; }
|
|
3998
|
+
/* --fit: the cards stretch over the full width when there are fewer than fit in a row (auto-fit instead of auto-fill). */
|
|
3999
|
+
.oc-card-grid--fit { grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--oc-card-min, 17rem)), 1fr)); }
|
|
4000
|
+
@media (min-width: 1280px) { .oc-card-grid--wide { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
|
|
3957
4001
|
.oc-product-card {
|
|
3958
4002
|
position: relative;
|
|
3959
4003
|
display: flex;
|
|
@@ -3967,7 +4011,7 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
3967
4011
|
var(--oc-surface);
|
|
3968
4012
|
color: var(--oc-foreground);
|
|
3969
4013
|
text-decoration: none;
|
|
3970
|
-
transition:
|
|
4014
|
+
transition: translate 0.35s var(--oc-ease-out), border-color 0.35s, --oc-glow 0.35s;
|
|
3971
4015
|
}
|
|
3972
4016
|
@property --oc-glow {
|
|
3973
4017
|
syntax: "<number>";
|
|
@@ -3976,7 +4020,8 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
3976
4020
|
}
|
|
3977
4021
|
.oc-product-card:hover {
|
|
3978
4022
|
--oc-glow: 0.22;
|
|
3979
|
-
|
|
4023
|
+
/* The lift uses translate; a fly-in (.oc-reveal--fly) animates the transform, so both keep working. */
|
|
4024
|
+
translate: 0 calc(-1 * var(--oc-hover-lift, 6px));
|
|
3980
4025
|
border-color: oklch(from var(--oc-accent-from) l c h / 0.55);
|
|
3981
4026
|
}
|
|
3982
4027
|
.oc-product-card__top { display: flex; justify-content: space-between; align-items: flex-start; margin-block-end: 0.75rem; }
|
|
@@ -4032,9 +4077,17 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
4032
4077
|
}
|
|
4033
4078
|
.oc-stat-strip__item { padding: 2rem 1.5rem; border-inline-start: 1px solid var(--oc-border); }
|
|
4034
4079
|
.oc-stat-strip__item:first-child { border-inline-start: 0; }
|
|
4035
|
-
.oc-stat-strip__value { font-size: clamp(2.2rem, 4vw, 3rem); font-weight: 700; line-height: 1.1; }
|
|
4080
|
+
.oc-stat-strip__value { font-family: var(--oc-font-display, inherit); font-size: clamp(2.2rem, 4vw, 3rem); font-weight: 700; line-height: 1.1; }
|
|
4036
4081
|
.oc-stat-strip__suffix { color: var(--oc-brand-1); }
|
|
4037
4082
|
.oc-stat-strip__label { display: block; color: var(--oc-muted-foreground); font-size: 0.92rem; }
|
|
4083
|
+
/* Plain: no lines and no background of its own, for a strip inside an .oc-band (full width) or a card. */
|
|
4084
|
+
.oc-stat-strip--plain { border-block: 0; background: none; }
|
|
4085
|
+
/* Four figures on a narrower screen: two rows of two instead of three and one. */
|
|
4086
|
+
@media (max-width: 960px) {
|
|
4087
|
+
.oc-stat-strip:has(> .oc-stat-strip__item:nth-child(4):last-child) { grid-template-columns: 1fr 1fr; }
|
|
4088
|
+
.oc-stat-strip:has(> .oc-stat-strip__item:nth-child(4):last-child) > .oc-stat-strip__item:nth-child(3) { border-inline-start: 0; }
|
|
4089
|
+
.oc-stat-strip:has(> .oc-stat-strip__item:nth-child(4):last-child) > .oc-stat-strip__item:nth-child(n + 3) { border-block-start: 1px solid var(--oc-border); }
|
|
4090
|
+
}
|
|
4038
4091
|
|
|
4039
4092
|
/* Spotlight: large highlighted panel with copy + module list */
|
|
4040
4093
|
.oc-spotlight {
|
|
@@ -4052,8 +4105,12 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
4052
4105
|
}
|
|
4053
4106
|
.oc-spotlight__title { display: flex; align-items: center; gap: 1rem; margin: 1.25rem 0 0.5rem; font-size: clamp(2.2rem, 5vw, 3.5rem); line-height: 1.1; }
|
|
4054
4107
|
.oc-spotlight__tagline { color: light-dark(var(--oc-accent-from), oklch(from var(--oc-accent-from) max(l, 0.72) c h)); font-size: 1.2rem; font-weight: 600; }
|
|
4108
|
+
/* --oc-spotlight-cols: your own ratio above 960px (copy | modules); on a smaller screen the spotlight stacks. */
|
|
4109
|
+
@media (min-width: 961px) {
|
|
4110
|
+
.oc-spotlight { grid-template-columns: var(--oc-spotlight-cols, repeat(auto-fit, minmax(min(100%, 22rem), 1fr))); }
|
|
4111
|
+
}
|
|
4055
4112
|
.oc-spotlight__modules { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr)); gap: 0.75rem; margin: 0; padding: 0; list-style: none; }
|
|
4056
|
-
.oc-spotlight__modules > li { display: flex; align-items: center; gap: 0.75rem; padding: 0.9rem; border: 1px solid var(--oc-border); border-radius: var(--oc-radius-md); background: var(--oc-surface); font-size: 0.95rem; }
|
|
4113
|
+
.oc-spotlight__modules > li { display: flex; align-items: center; gap: 0.75rem; padding: 0.9rem; border: 1px solid var(--oc-border); border-radius: var(--oc-radius-md); background: var(--oc-spotlight-module-bg, var(--oc-surface)); font-size: 0.95rem; }
|
|
4057
4114
|
|
|
4058
4115
|
/* Steps: numbered process with a gradient tick (numbers come from a CSS counter) */
|
|
4059
4116
|
.oc-steps { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 14rem), 1fr)); gap: 1.25rem; margin: 0; padding: 0; list-style: none; counter-reset: oc-step; }
|
|
@@ -4086,6 +4143,9 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
4086
4143
|
/* Tag list (tech stack) and check list */
|
|
4087
4144
|
.oc-tag-list { display: flex; flex-wrap: wrap; gap: 0.6rem; margin: 0; padding: 0; list-style: none; }
|
|
4088
4145
|
.oc-tag-list > li { padding: 0.55rem 1.1rem; border: 1px solid oklch(from var(--oc-accent-from) l c h / 0.35); border-radius: 999px; background: oklch(from var(--oc-accent-from) l c h / 0.1); font-family: var(--oc-font-mono); font-size: 0.88rem; }
|
|
4146
|
+
/* Neutral chips (no accent color) and large chips in the display font, e.g. a strip of brand names. */
|
|
4147
|
+
.oc-tag-list--neutral > li { border-color: var(--oc-border); background: var(--oc-surface); color: var(--oc-foreground); }
|
|
4148
|
+
.oc-tag-list--lg > li { padding: 0.45rem 1rem; font-family: var(--oc-font-display, inherit); font-size: 1rem; font-weight: 700; letter-spacing: 0.02em; }
|
|
4089
4149
|
.oc-check-list { display: grid; gap: 0.5rem; margin: 1.1rem 0 0; padding: 0; list-style: none; font-size: 0.93rem; }
|
|
4090
4150
|
.oc-check-list > li { display: flex; gap: 0.5rem; align-items: baseline; }
|
|
4091
4151
|
.oc-check-list > li::before { content: "✓"; color: var(--oc-brand-1); font-weight: 700; }
|
|
@@ -4120,6 +4180,8 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
4120
4180
|
.oc-site-header__nav a:not(.oc-btn):hover,
|
|
4121
4181
|
.oc-site-header__nav a[aria-current="page"] { color: var(--oc-foreground); }
|
|
4122
4182
|
.oc-site-header__toggle { display: none; padding: 0.5rem 0.7rem; border: 1px solid var(--oc-border); border-radius: var(--oc-radius-md); background: var(--oc-surface); color: var(--oc-foreground); cursor: pointer; }
|
|
4183
|
+
/* The icon in the menu button is a block, so the button is as tall as a line of text (no inline gap under it). */
|
|
4184
|
+
.oc-site-header__toggle :is(svg, img, iconify-icon, .oc-icon) { display: block; }
|
|
4123
4185
|
@media (min-width: 861px) {
|
|
4124
4186
|
/* Desktop: the popover nav is always visible in the header bar. */
|
|
4125
4187
|
.oc-site-header__nav[popover] { display: flex; }
|
|
@@ -4144,6 +4206,8 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
4144
4206
|
backdrop-filter: blur(16px);
|
|
4145
4207
|
}
|
|
4146
4208
|
.oc-site-header__nav[popover] a:not(.oc-btn) { padding: 0.75rem 0; font-size: 1.1rem; }
|
|
4209
|
+
/* The call to action (.oc-site-header__cta, a button) gets room above it in the open menu. */
|
|
4210
|
+
.oc-site-header__cta { margin-block-start: 0.75rem; }
|
|
4147
4211
|
}
|
|
4148
4212
|
|
|
4149
4213
|
/* Site footer: brand column + link columns + bottom bar */
|
|
@@ -4151,21 +4215,33 @@ details.oc-collapsible[open]::details-content { block-size: auto; }
|
|
|
4151
4215
|
margin-block-start: 4rem;
|
|
4152
4216
|
padding-block-start: 4rem;
|
|
4153
4217
|
border-block-start: 1px solid var(--oc-border);
|
|
4154
|
-
background: linear-gradient(to bottom, transparent, var(--oc-surface-strong));
|
|
4218
|
+
background: var(--oc-footer-bg, linear-gradient(to bottom, transparent, var(--oc-surface-strong)));
|
|
4155
4219
|
color: var(--oc-muted-foreground);
|
|
4156
4220
|
font-size: 0.95rem;
|
|
4221
|
+
container-type: inline-size;
|
|
4157
4222
|
}
|
|
4158
|
-
|
|
4223
|
+
/* Columns: --oc-footer-cols (about + 3 link columns). Footer narrower than 66rem (about a 1060px screen):
|
|
4224
|
+
--oc-footer-cols-md columns (3) with the about column over the full width; narrower than 54rem: two columns.
|
|
4225
|
+
Container queries on the footer, so a footer in a narrow column or a preview follows its own width. */
|
|
4226
|
+
.oc-site-footer__grid { display: grid; grid-template-columns: var(--oc-footer-cols, 1.6fr repeat(3, 1fr)); gap: 2.5rem; }
|
|
4159
4227
|
.oc-site-footer__about p { margin-block: 1rem 0; max-inline-size: 22rem; }
|
|
4160
4228
|
.oc-site-footer__title { margin: 0 0 1rem; color: var(--oc-foreground); font-size: 0.95rem; font-weight: 700; }
|
|
4161
4229
|
.oc-site-footer__list { display: flex; flex-direction: column; gap: 0.5rem; margin: 0; padding: 0; list-style: none; font-style: normal; }
|
|
4162
4230
|
.oc-site-footer a { color: inherit; text-decoration: none; }
|
|
4163
4231
|
.oc-site-footer a:hover { color: var(--oc-foreground); }
|
|
4164
|
-
.oc-site-footer__bottom { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1rem; margin-block-start: 3rem; padding-block: 1.5rem; border-block-start: 1px solid var(--oc-border); font-size: 0.85rem; }
|
|
4165
|
-
|
|
4166
|
-
|
|
4232
|
+
.oc-site-footer__bottom { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 1rem; margin-block-start: 3rem; padding-block: 1.5rem; border-block-start: 1px solid var(--oc-border); color: var(--oc-footer-bottom-color, inherit); font-size: 0.85rem; }
|
|
4233
|
+
/* A second title further down in a column (e.g. "Tools" under the projects). */
|
|
4234
|
+
.oc-site-footer__subtitle { margin-block-start: 1.75rem; }
|
|
4235
|
+
/* Legal links in the bottom bar (Terms · Privacy · Cookies) and the build number after them. */
|
|
4236
|
+
.oc-site-footer__legal { display: flex; flex-wrap: wrap; gap: 0.5rem 1.25rem; margin: 0; padding: 0; list-style: none; }
|
|
4237
|
+
.oc-site-footer__build { opacity: 0.7; font-variant-numeric: tabular-nums; }
|
|
4238
|
+
@container (max-width: 66rem) {
|
|
4239
|
+
.oc-site-footer__grid { grid-template-columns: repeat(var(--oc-footer-cols-md, 3), minmax(0, 1fr)); }
|
|
4167
4240
|
.oc-site-footer__about { grid-column: 1 / -1; }
|
|
4168
4241
|
}
|
|
4242
|
+
@container (max-width: 54rem) {
|
|
4243
|
+
.oc-site-footer__grid { grid-template-columns: 1fr 1fr; }
|
|
4244
|
+
}
|
|
4169
4245
|
|
|
4170
4246
|
/* Reveal on scroll: elements slide in when they enter the viewport (scroll-driven, no JS; visible without support) */
|
|
4171
4247
|
@supports (animation-timeline: view()) {
|
|
@@ -6320,6 +6396,47 @@ input.oc-input[type="month"] { inline-size: auto; min-inline-size: 11rem; }
|
|
|
6320
6396
|
.oc-page-header--sm { padding-block: 0.5rem 0.75rem; }
|
|
6321
6397
|
.oc-page-header--sm .oc-page-header-title { font-size: 1.125rem; }
|
|
6322
6398
|
|
|
6399
|
+
/* parts/app-result.css */
|
|
6400
|
+
/* File: packages/ui/src/parts/app-result.css */
|
|
6401
|
+
/* Map: result -> icon tile -> title -> text -> actions */
|
|
6402
|
+
/* The outcome of an action in the place where the form was: "Thank you, your message was sent" with an icon tile, a
|
|
6403
|
+
short text and a button ("Send another message"). Give it role="status" and tabindex="-1" and move the focus to it.
|
|
6404
|
+
--center centers it; the tile takes its color from an .oc-accent--* preset. */
|
|
6405
|
+
|
|
6406
|
+
.oc-result {
|
|
6407
|
+
display: grid;
|
|
6408
|
+
justify-items: start;
|
|
6409
|
+
gap: 0.75rem;
|
|
6410
|
+
}
|
|
6411
|
+
.oc-result:focus { outline: none; }
|
|
6412
|
+
.oc-result[hidden] { display: none; }
|
|
6413
|
+
.oc-result > .oc-icon-tile { margin-block-end: 0.35rem; }
|
|
6414
|
+
.oc-result__title {
|
|
6415
|
+
margin: 0;
|
|
6416
|
+
font-size: 1.2rem;
|
|
6417
|
+
line-height: 1.25;
|
|
6418
|
+
}
|
|
6419
|
+
.oc-result__text {
|
|
6420
|
+
margin: 0;
|
|
6421
|
+
color: var(--oc-muted-foreground);
|
|
6422
|
+
}
|
|
6423
|
+
.oc-result__text a {
|
|
6424
|
+
color: var(--oc-primary);
|
|
6425
|
+
text-decoration: underline;
|
|
6426
|
+
text-underline-offset: 3px;
|
|
6427
|
+
}
|
|
6428
|
+
.oc-result__actions {
|
|
6429
|
+
display: flex;
|
|
6430
|
+
flex-wrap: wrap;
|
|
6431
|
+
gap: 0.75rem;
|
|
6432
|
+
margin-block-start: 0.5rem;
|
|
6433
|
+
}
|
|
6434
|
+
.oc-result--center {
|
|
6435
|
+
justify-items: center;
|
|
6436
|
+
text-align: center;
|
|
6437
|
+
}
|
|
6438
|
+
.oc-result--center .oc-result__actions { justify-content: center; }
|
|
6439
|
+
|
|
6323
6440
|
/* parts/app-severity-card.css */
|
|
6324
6441
|
/* File: packages/ui/src/parts/app-severity-card.css | Map: card (details) -> head (summary) -> icon + title + tags -> level badge + chevron -> body + actions -> severity modifiers -> resolved state -> reduced motion */
|
|
6325
6442
|
/* Severity card: risk-colored expandable card (security finding, incident, audit item).
|
|
@@ -8259,6 +8376,84 @@ td[data-numeric] > .oc-price .oc-price__main, .oc-price--end .oc-price__main { j
|
|
|
8259
8376
|
.oc-form-section__summary::after { transition: none; }
|
|
8260
8377
|
}
|
|
8261
8378
|
|
|
8379
|
+
/* parts/forms-form.css */
|
|
8380
|
+
/* File: packages/ui/src/parts/forms-form.css */
|
|
8381
|
+
/* Map: form grid -> label hint -> actions + note -> busy -> filled variant */
|
|
8382
|
+
/* A form as one grid of fields with one gap, an "(optional)" hint in a label, a row with the submit button and a short
|
|
8383
|
+
note, the busy state while it sends (aria-busy on the form), and .oc-form--filled: fields with a fill and a stronger
|
|
8384
|
+
border, for a form on a card, a photo or a dark band. All through the field tokens of .oc-input. */
|
|
8385
|
+
|
|
8386
|
+
.oc-form {
|
|
8387
|
+
display: grid;
|
|
8388
|
+
gap: var(--oc-form-gap, 1.1rem);
|
|
8389
|
+
}
|
|
8390
|
+
.oc-form .oc-field-group { gap: var(--oc-form-gap, 1.1rem); }
|
|
8391
|
+
.oc-form .oc-field {
|
|
8392
|
+
gap: 0.4rem;
|
|
8393
|
+
margin-bottom: 0;
|
|
8394
|
+
}
|
|
8395
|
+
|
|
8396
|
+
/* <label class="oc-field-label">Phone <span class="oc-field-label__hint">(optional)</span></label> */
|
|
8397
|
+
.oc-field-label__hint {
|
|
8398
|
+
color: var(--oc-muted-foreground);
|
|
8399
|
+
font-weight: 400;
|
|
8400
|
+
}
|
|
8401
|
+
|
|
8402
|
+
/* Submit button with a short note next to it (wraps under it on a narrow form). */
|
|
8403
|
+
.oc-form-actions {
|
|
8404
|
+
display: flex;
|
|
8405
|
+
flex-wrap: wrap;
|
|
8406
|
+
align-items: center;
|
|
8407
|
+
gap: 1rem 1.5rem;
|
|
8408
|
+
margin-block-start: 0.4rem;
|
|
8409
|
+
}
|
|
8410
|
+
.oc-form-note {
|
|
8411
|
+
flex: 1 1 16rem;
|
|
8412
|
+
margin: 0;
|
|
8413
|
+
color: var(--oc-muted-foreground);
|
|
8414
|
+
font-size: 0.85rem;
|
|
8415
|
+
}
|
|
8416
|
+
.oc-form-note a {
|
|
8417
|
+
color: var(--oc-primary);
|
|
8418
|
+
text-decoration: underline;
|
|
8419
|
+
text-underline-offset: 3px;
|
|
8420
|
+
}
|
|
8421
|
+
.oc-form-note a:hover { color: var(--oc-foreground); }
|
|
8422
|
+
|
|
8423
|
+
/* While the form sends (form aria-busy="true"): the submit button dims and shows a progress cursor. */
|
|
8424
|
+
.oc-form[aria-busy="true"] :is([type="submit"], button:not([type])) {
|
|
8425
|
+
opacity: 0.7;
|
|
8426
|
+
cursor: progress;
|
|
8427
|
+
}
|
|
8428
|
+
|
|
8429
|
+
/* Filled fields: a fill (dark in dark mode), the strong border, more room and a wider focus ring. */
|
|
8430
|
+
.oc-form--filled {
|
|
8431
|
+
--oc-input-bg: light-dark(oklch(from var(--oc-foreground) l c h / 0.03), oklch(0 0 0 / 0.25));
|
|
8432
|
+
--oc-input-border: var(--oc-border-strong);
|
|
8433
|
+
--oc-input-padding: 0.75rem 0.9rem;
|
|
8434
|
+
--oc-input-radius: var(--oc-radius-md, 0.75rem);
|
|
8435
|
+
--oc-input-size: 1rem;
|
|
8436
|
+
--oc-ring-width: 3px;
|
|
8437
|
+
--oc-textarea-min: 9rem;
|
|
8438
|
+
}
|
|
8439
|
+
.oc-form--filled .oc-field-label {
|
|
8440
|
+
font-size: 0.9rem;
|
|
8441
|
+
font-weight: 600;
|
|
8442
|
+
line-height: 1.4;
|
|
8443
|
+
}
|
|
8444
|
+
.oc-form--filled .oc-field-error { font-size: 0.85rem; }
|
|
8445
|
+
.oc-form--filled .oc-select option { background: var(--oc-card); }
|
|
8446
|
+
|
|
8447
|
+
/* Honeypot: a field for bots, off screen for people. Not display:none (some bots skip hidden fields). Give the wrapper
|
|
8448
|
+
aria-hidden="true" and the input tabindex="-1" autocomplete="off"; the server ignores a form where it is filled. */
|
|
8449
|
+
.oc-honeypot {
|
|
8450
|
+
position: absolute;
|
|
8451
|
+
inset-inline-start: -10000px;
|
|
8452
|
+
inline-size: 1px;
|
|
8453
|
+
block-size: 1px;
|
|
8454
|
+
overflow: hidden;
|
|
8455
|
+
}
|
|
8456
|
+
|
|
8262
8457
|
/* parts/forms-language-select.css */
|
|
8263
8458
|
/* File: packages/ui/src/parts/forms-language-select.css
|
|
8264
8459
|
Map: wrapper (icon + native select) -> icon -> select control -> chevron -> states -> --ghost / --currency
|
|
@@ -10226,6 +10421,10 @@ a.oc-attachment-image:hover > :is(img, .oc-media-art) { filter: brightness(1.05)
|
|
|
10226
10421
|
.oc-lightbox__nav { grid-row: 1; justify-self: center; }
|
|
10227
10422
|
.oc-lightbox__nav--prev { grid-column: 1; }
|
|
10228
10423
|
.oc-lightbox__nav--next { grid-column: 3; }
|
|
10424
|
+
.oc-lightbox__close :is(svg, iconify-icon, .oc-icon) { inline-size: 1.1rem; block-size: 1.1rem; font-size: 1.1rem; }
|
|
10425
|
+
/* A <picture> (animated WebP with a still image for "reduce motion") gets the frame; the image fits in it. */
|
|
10426
|
+
.oc-lightbox__media > picture { display: grid; overflow: hidden; }
|
|
10427
|
+
.oc-lightbox__media > picture > img { max-inline-size: 100%; max-block-size: calc(100dvh - 9rem); object-fit: contain; }
|
|
10229
10428
|
|
|
10230
10429
|
/* ---- Caption with the "2 / 5" counter ---- */
|
|
10231
10430
|
.oc-lightbox__caption {
|
|
@@ -11110,6 +11309,284 @@ a.oc-message__quote:focus-visible { outline: 2px solid var(--oc-ring); outline-o
|
|
|
11110
11309
|
.oc-footerbar--dark :is(a, .oc-footerbar-links a) { color: oklch(from var(--color-white-50) l c h / 0.85); }
|
|
11111
11310
|
.oc-footerbar--dark .oc-footerbar-links a:hover { color: var(--color-white-50); }
|
|
11112
11311
|
|
|
11312
|
+
/* parts/site-base.css */
|
|
11313
|
+
/* File: packages/ui/src/parts/site-base.css */
|
|
11314
|
+
/* Map: skip link -> icon */
|
|
11315
|
+
/* Two small site helpers: a skip link for keyboard users (hidden above the page until it gets the focus) and a basic
|
|
11316
|
+
inline icon (svg or iconify-icon) that is as large as the text around it. */
|
|
11317
|
+
|
|
11318
|
+
/* <a class="oc-skip-link" href="#main">Skip to content</a> as the first element in <body>. */
|
|
11319
|
+
.oc-skip-link {
|
|
11320
|
+
position: absolute;
|
|
11321
|
+
inset-inline-start: 1rem;
|
|
11322
|
+
inset-block-start: 1rem;
|
|
11323
|
+
/* Fully above the edge, whatever its height; drops in on focus. */
|
|
11324
|
+
translate: 0 calc(-100% - 2rem);
|
|
11325
|
+
z-index: 100;
|
|
11326
|
+
padding: 0.6rem 1rem;
|
|
11327
|
+
border-radius: var(--oc-radius-md, 0.75rem);
|
|
11328
|
+
background: var(--oc-foreground);
|
|
11329
|
+
color: var(--oc-background);
|
|
11330
|
+
font-weight: 600;
|
|
11331
|
+
text-decoration: none;
|
|
11332
|
+
transition: translate var(--oc-transition-fast);
|
|
11333
|
+
}
|
|
11334
|
+
.oc-skip-link:focus { translate: none; }
|
|
11335
|
+
|
|
11336
|
+
/* Inline icon: 1.25em (1.1em in a button), never squeezed in a flex row. */
|
|
11337
|
+
.oc-icon {
|
|
11338
|
+
inline-size: 1.25em;
|
|
11339
|
+
block-size: 1.25em;
|
|
11340
|
+
flex-shrink: 0;
|
|
11341
|
+
}
|
|
11342
|
+
.oc-btn > .oc-icon {
|
|
11343
|
+
inline-size: 1.1em;
|
|
11344
|
+
block-size: 1.1em;
|
|
11345
|
+
}
|
|
11346
|
+
|
|
11347
|
+
/* parts/site-brand-mark.css */
|
|
11348
|
+
/* File: packages/ui/src/parts/site-brand-mark.css */
|
|
11349
|
+
/* Map: brand mark (icon + text) -> word (accent part in the brand gradient) -> tagline -> sizes */
|
|
11350
|
+
/* A logo built from an icon and text: the mark (svg or img) with a soft glow in the brand color, the word mark with one
|
|
11351
|
+
part in the brand gradient, and a small tagline under it. Sizes --sm and --lg (a footer, a hero or a map). */
|
|
11352
|
+
|
|
11353
|
+
.oc-brand-mark {
|
|
11354
|
+
--oc-brand-mark-icon: 2.25rem;
|
|
11355
|
+
--oc-brand-mark-word: 1.35rem;
|
|
11356
|
+
--oc-brand-mark-tagline: 0.6rem;
|
|
11357
|
+
display: inline-flex;
|
|
11358
|
+
align-items: center;
|
|
11359
|
+
gap: 0.6rem;
|
|
11360
|
+
color: var(--oc-foreground);
|
|
11361
|
+
text-decoration: none;
|
|
11362
|
+
}
|
|
11363
|
+
.oc-brand-mark__icon {
|
|
11364
|
+
flex: none;
|
|
11365
|
+
inline-size: var(--oc-brand-mark-icon);
|
|
11366
|
+
block-size: var(--oc-brand-mark-icon);
|
|
11367
|
+
filter: drop-shadow(0 6px 14px oklch(from var(--oc-brand-1) l c h / 0.35));
|
|
11368
|
+
}
|
|
11369
|
+
.oc-brand-mark__text {
|
|
11370
|
+
display: grid;
|
|
11371
|
+
line-height: 1;
|
|
11372
|
+
}
|
|
11373
|
+
.oc-brand-mark__word {
|
|
11374
|
+
font-family: var(--oc-font-display, inherit);
|
|
11375
|
+
font-size: var(--oc-brand-mark-word);
|
|
11376
|
+
font-weight: 800;
|
|
11377
|
+
letter-spacing: -0.04em;
|
|
11378
|
+
}
|
|
11379
|
+
.oc-brand-mark__accent {
|
|
11380
|
+
background: linear-gradient(90deg, var(--oc-brand-1), var(--oc-brand-2));
|
|
11381
|
+
-webkit-background-clip: text;
|
|
11382
|
+
background-clip: text;
|
|
11383
|
+
color: transparent;
|
|
11384
|
+
}
|
|
11385
|
+
.oc-brand-mark__tagline {
|
|
11386
|
+
margin-block-start: 0.3rem;
|
|
11387
|
+
color: var(--oc-subtle-foreground, var(--oc-muted-foreground));
|
|
11388
|
+
font-family: var(--oc-font-mono);
|
|
11389
|
+
font-size: var(--oc-brand-mark-tagline);
|
|
11390
|
+
font-weight: 600;
|
|
11391
|
+
letter-spacing: 0.16em;
|
|
11392
|
+
text-transform: uppercase;
|
|
11393
|
+
}
|
|
11394
|
+
.oc-brand-mark--sm {
|
|
11395
|
+
--oc-brand-mark-icon: 1.75rem;
|
|
11396
|
+
--oc-brand-mark-word: 1.1rem;
|
|
11397
|
+
--oc-brand-mark-tagline: 0.55rem;
|
|
11398
|
+
}
|
|
11399
|
+
.oc-brand-mark--lg {
|
|
11400
|
+
--oc-brand-mark-icon: 2.6rem;
|
|
11401
|
+
--oc-brand-mark-word: 1.6rem;
|
|
11402
|
+
--oc-brand-mark-tagline: 0.66rem;
|
|
11403
|
+
}
|
|
11404
|
+
|
|
11405
|
+
/* parts/site-cards.css */
|
|
11406
|
+
/* File: packages/ui/src/parts/site-cards.css */
|
|
11407
|
+
/* Map: feature card -> link card -> icon list (+ points) -> accent list + note -> badge row + accent tagline
|
|
11408
|
+
-> screenshot grid -> browser frame glow + mark */
|
|
11409
|
+
/* Cards and lists for the pages of a company site: services and features (icon tile + title + text), cards that are
|
|
11410
|
+
links, a list of icon rows in frames (or as points with a title), a list with markers in the accent color, a small
|
|
11411
|
+
note, a row of badges, a tagline in the accent color, a grid of screenshots that open in the lightbox, and a browser
|
|
11412
|
+
frame with a glow in the accent color and a product mark on it. */
|
|
11413
|
+
|
|
11414
|
+
/* Feature / service card: tile, title, text; a quiet hover. In an .oc-card-grid (--oc-card-min sets the column width). */
|
|
11415
|
+
.oc-feature-card {
|
|
11416
|
+
padding: 1.6rem;
|
|
11417
|
+
border: 1px solid var(--oc-border);
|
|
11418
|
+
border-radius: var(--oc-radius-lg, 1.25rem);
|
|
11419
|
+
background: var(--oc-surface);
|
|
11420
|
+
transition: border-color 0.3s, background 0.3s;
|
|
11421
|
+
}
|
|
11422
|
+
.oc-feature-card:hover {
|
|
11423
|
+
border-color: var(--oc-border-strong);
|
|
11424
|
+
background: var(--oc-surface-strong);
|
|
11425
|
+
}
|
|
11426
|
+
.oc-feature-card > .oc-icon-tile { margin-block-end: 1.1rem; }
|
|
11427
|
+
.oc-feature-card__title {
|
|
11428
|
+
margin: 0 0 0.6rem;
|
|
11429
|
+
font-family: var(--oc-font-display, inherit);
|
|
11430
|
+
font-size: 1.2rem;
|
|
11431
|
+
line-height: 1.25;
|
|
11432
|
+
}
|
|
11433
|
+
.oc-feature-card__text {
|
|
11434
|
+
margin: 0;
|
|
11435
|
+
color: var(--oc-muted-foreground);
|
|
11436
|
+
font-size: 0.95rem;
|
|
11437
|
+
}
|
|
11438
|
+
|
|
11439
|
+
/* Card that is a link (an agent, a tool, a document): tile, title, text and a "more" line; hover in the accent color. */
|
|
11440
|
+
.oc-link-card {
|
|
11441
|
+
display: grid;
|
|
11442
|
+
align-content: start;
|
|
11443
|
+
gap: 0.4rem;
|
|
11444
|
+
padding: 1.25rem;
|
|
11445
|
+
border: 1px solid var(--oc-border);
|
|
11446
|
+
border-radius: var(--oc-radius-lg, 1.25rem);
|
|
11447
|
+
background: var(--oc-surface);
|
|
11448
|
+
color: var(--oc-foreground);
|
|
11449
|
+
text-decoration: none;
|
|
11450
|
+
transition: border-color 0.3s, background 0.3s;
|
|
11451
|
+
}
|
|
11452
|
+
/* --oc-link-card-hover: the hover color alone (without an accent preset, so the tile keeps its own color). */
|
|
11453
|
+
.oc-link-card:hover {
|
|
11454
|
+
border-color: oklch(from var(--oc-link-card-hover, var(--oc-accent-from)) l c h / 0.5);
|
|
11455
|
+
background: var(--oc-surface-strong);
|
|
11456
|
+
}
|
|
11457
|
+
.oc-link-card:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
11458
|
+
.oc-link-card > .oc-icon-tile { margin-block-end: 0.4rem; }
|
|
11459
|
+
.oc-link-card__title { font-family: var(--oc-font-display, inherit); font-weight: 700; }
|
|
11460
|
+
.oc-link-card__text { color: var(--oc-muted-foreground); font-size: 0.93rem; }
|
|
11461
|
+
.oc-link-card__more {
|
|
11462
|
+
display: inline-flex;
|
|
11463
|
+
align-items: center;
|
|
11464
|
+
gap: 0.35rem;
|
|
11465
|
+
margin-block-start: 0.4rem;
|
|
11466
|
+
font-size: 0.9rem;
|
|
11467
|
+
font-weight: 600;
|
|
11468
|
+
}
|
|
11469
|
+
.oc-link-card__more::after { content: "→"; transition: translate 0.25s var(--oc-ease-out, ease); }
|
|
11470
|
+
.oc-link-card:hover .oc-link-card__more::after { translate: 4px 0; }
|
|
11471
|
+
|
|
11472
|
+
/* Icon list: rows with an icon in a frame. --points: an icon tile next to a title and a text, without frames. */
|
|
11473
|
+
.oc-icon-list {
|
|
11474
|
+
display: grid;
|
|
11475
|
+
gap: 0.75rem;
|
|
11476
|
+
margin: 0;
|
|
11477
|
+
padding: 0;
|
|
11478
|
+
list-style: none;
|
|
11479
|
+
}
|
|
11480
|
+
.oc-icon-list > li {
|
|
11481
|
+
display: flex;
|
|
11482
|
+
align-items: center;
|
|
11483
|
+
gap: 0.75rem;
|
|
11484
|
+
padding: 0.85rem 1rem;
|
|
11485
|
+
border: 1px solid var(--oc-border);
|
|
11486
|
+
border-radius: var(--oc-radius-md, 0.75rem);
|
|
11487
|
+
background: var(--oc-surface);
|
|
11488
|
+
}
|
|
11489
|
+
.oc-icon-list > li > :is(svg, iconify-icon, .oc-icon) {
|
|
11490
|
+
flex: none;
|
|
11491
|
+
inline-size: 1.25rem;
|
|
11492
|
+
block-size: 1.25rem;
|
|
11493
|
+
font-size: 1.25rem;
|
|
11494
|
+
color: var(--oc-primary);
|
|
11495
|
+
}
|
|
11496
|
+
.oc-icon-list--points { gap: 1rem; }
|
|
11497
|
+
.oc-icon-list--points > li {
|
|
11498
|
+
display: grid;
|
|
11499
|
+
grid-template-columns: auto 1fr;
|
|
11500
|
+
align-items: start;
|
|
11501
|
+
gap: 0.25rem 0.9rem;
|
|
11502
|
+
padding: 0;
|
|
11503
|
+
border: 0;
|
|
11504
|
+
background: none;
|
|
11505
|
+
}
|
|
11506
|
+
.oc-icon-list--points > li > .oc-icon-tile { grid-row: span 2; }
|
|
11507
|
+
.oc-icon-list__title { font-family: var(--oc-font-display, inherit); font-weight: 700; }
|
|
11508
|
+
.oc-icon-list__text { color: var(--oc-muted-foreground); font-size: 0.95rem; }
|
|
11509
|
+
|
|
11510
|
+
/* List with markers in the accent color, and a small note under a block. */
|
|
11511
|
+
.oc-list--accent {
|
|
11512
|
+
display: grid;
|
|
11513
|
+
gap: 0.6rem;
|
|
11514
|
+
margin: 0;
|
|
11515
|
+
padding-inline-start: 1.1rem;
|
|
11516
|
+
list-style: disc;
|
|
11517
|
+
color: var(--oc-muted-foreground);
|
|
11518
|
+
font-size: 0.95rem;
|
|
11519
|
+
}
|
|
11520
|
+
.oc-list--accent > li::marker { color: var(--oc-accent-from, var(--oc-primary)); }
|
|
11521
|
+
.oc-note {
|
|
11522
|
+
margin: 1.25rem 0 0;
|
|
11523
|
+
color: var(--oc-muted-foreground);
|
|
11524
|
+
font-size: 0.85rem;
|
|
11525
|
+
}
|
|
11526
|
+
.oc-note--md {
|
|
11527
|
+
max-inline-size: 60rem;
|
|
11528
|
+
font-size: 1rem;
|
|
11529
|
+
}
|
|
11530
|
+
|
|
11531
|
+
/* Row of badges or pills above a title, and a tagline in the accent color (lighter, so it reads on a dark page). */
|
|
11532
|
+
.oc-badge-row {
|
|
11533
|
+
display: flex;
|
|
11534
|
+
flex-wrap: wrap;
|
|
11535
|
+
gap: 0.5rem;
|
|
11536
|
+
margin-block-end: 1.25rem;
|
|
11537
|
+
}
|
|
11538
|
+
.oc-tagline--accent {
|
|
11539
|
+
margin: 0 0 1rem;
|
|
11540
|
+
color: light-dark(var(--oc-accent-from), color-mix(in oklch, var(--oc-accent-from) 55%, white));
|
|
11541
|
+
font-size: clamp(1.2rem, 2.5vw, 1.6rem);
|
|
11542
|
+
font-weight: 600;
|
|
11543
|
+
}
|
|
11544
|
+
|
|
11545
|
+
/* Screenshot grid: figures with the whole image visible (contain, 16:10 on the card color) and a caption;
|
|
11546
|
+
a link or a button around the image opens the lightbox
|
|
11547
|
+
(<button command="show-modal" commandfor="<lightbox id>">). A <picture> (animated WebP with a still image) works the same. */
|
|
11548
|
+
.oc-shot-grid {
|
|
11549
|
+
display: grid;
|
|
11550
|
+
grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--oc-shot-min, 18rem)), 1fr));
|
|
11551
|
+
gap: 1.25rem;
|
|
11552
|
+
}
|
|
11553
|
+
.oc-shot {
|
|
11554
|
+
margin: 0;
|
|
11555
|
+
border: 1px solid var(--oc-border);
|
|
11556
|
+
border-radius: var(--oc-radius-lg, 1.25rem);
|
|
11557
|
+
overflow: hidden;
|
|
11558
|
+
background: var(--oc-surface);
|
|
11559
|
+
}
|
|
11560
|
+
.oc-shot > :is(a, button) { display: block; inline-size: 100%; padding: 0; border: 0; background: none; cursor: zoom-in; }
|
|
11561
|
+
.oc-shot > :is(a, button):focus-visible { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
|
|
11562
|
+
.oc-shot :is(picture) { display: block; }
|
|
11563
|
+
.oc-shot img {
|
|
11564
|
+
display: block;
|
|
11565
|
+
inline-size: 100%;
|
|
11566
|
+
aspect-ratio: var(--oc-shot-ratio, 16 / 10);
|
|
11567
|
+
object-fit: contain;
|
|
11568
|
+
background: var(--oc-card);
|
|
11569
|
+
}
|
|
11570
|
+
.oc-shot > figcaption {
|
|
11571
|
+
padding: 0.8rem 1rem;
|
|
11572
|
+
color: var(--oc-muted-foreground);
|
|
11573
|
+
font-size: 0.88rem;
|
|
11574
|
+
}
|
|
11575
|
+
|
|
11576
|
+
/* Browser frame with a shadow in the accent color and a product mark on the bottom end corner. */
|
|
11577
|
+
.oc-browser-frame--glow {
|
|
11578
|
+
position: relative;
|
|
11579
|
+
box-shadow: 0 40px 90px -40px color-mix(in srgb, var(--oc-accent-from) 70%, transparent);
|
|
11580
|
+
}
|
|
11581
|
+
.oc-browser-frame--glow :is(.oc-browser-frame__view, .oc-browser-frame__body) img { transition: scale 0.6s var(--oc-ease-out, ease); }
|
|
11582
|
+
.oc-browser-frame--glow:hover :is(.oc-browser-frame__view, .oc-browser-frame__body) img { scale: 1.02; }
|
|
11583
|
+
.oc-browser-frame__mark {
|
|
11584
|
+
position: absolute;
|
|
11585
|
+
inset-block-end: 1rem;
|
|
11586
|
+
inset-inline-end: 1rem;
|
|
11587
|
+
filter: drop-shadow(0 10px 20px oklch(0 0 0 / 0.6));
|
|
11588
|
+
}
|
|
11589
|
+
|
|
11113
11590
|
/* parts/site-fact-list.css */
|
|
11114
11591
|
/* File: packages/ui/src/parts/site-fact-list.css
|
|
11115
11592
|
Map: plain -> compact -> stacked -> accent values -> narrow screens
|
|
@@ -11137,6 +11614,48 @@ a.oc-message__quote:focus-visible { outline: 2px solid var(--oc-ring); outline-o
|
|
|
11137
11614
|
/* Very narrow containers: wrap instead of squeezing label and value together. */
|
|
11138
11615
|
.oc-fact-list > div { flex-wrap: wrap; }
|
|
11139
11616
|
|
|
11617
|
+
/* parts/site-fly.css */
|
|
11618
|
+
/* File: packages/ui/src/parts/site-fly.css */
|
|
11619
|
+
/* Map: fly in (only with fly.js) -> visible -> reduced motion -> product card badge -> code window tokens */
|
|
11620
|
+
/* Cards that fly in when they scroll into view: they start from the middle of their row (--oc-fly-x, set by fly.js),
|
|
11621
|
+
70px lower, smaller and tilted, and land in their place. Without fly.js (html.oc-fly-ready is missing) or with
|
|
11622
|
+
"reduce motion" everything simply stands in its place. Options: --oc-fly-step (offset per column), --oc-fly-stagger
|
|
11623
|
+
(delay per column) and data-oc-fly-repeat (fly out again when leaving the view). The lift on hover uses translate, so it never fights the
|
|
11624
|
+
transform of the fly-in. Also: a "New" badge in a product card name and short syntax classes for a code window. */
|
|
11625
|
+
|
|
11626
|
+
.oc-fly-ready .oc-reveal--fly {
|
|
11627
|
+
/* --oc-fly-delay: set per card by fly.js from --oc-fly-stagger (delay per column). */
|
|
11628
|
+
transition:
|
|
11629
|
+
opacity 0.6s var(--oc-ease-out, ease) var(--oc-fly-delay, 0s),
|
|
11630
|
+
transform 0.9s cubic-bezier(0.16, 1, 0.3, 1) var(--oc-fly-delay, 0s),
|
|
11631
|
+
border-color 0.35s;
|
|
11632
|
+
}
|
|
11633
|
+
.oc-fly-ready .oc-reveal--fly:not(.is-visible) {
|
|
11634
|
+
opacity: 0;
|
|
11635
|
+
transform: perspective(900px) translate3d(var(--oc-fly-x, 0), 70px, 0) scale(0.9) rotateX(14deg);
|
|
11636
|
+
}
|
|
11637
|
+
@media (prefers-reduced-motion: reduce) {
|
|
11638
|
+
.oc-fly-ready .oc-reveal--fly:not(.is-visible) { opacity: 1; transform: none; }
|
|
11639
|
+
}
|
|
11640
|
+
|
|
11641
|
+
/* "New" after the name of a product card: <h3 class="oc-product-card__name">Product 1 <span class="oc-product-card__badge oc-pill">New</span></h3> */
|
|
11642
|
+
.oc-product-card__badge {
|
|
11643
|
+
margin-inline-start: 0.4rem;
|
|
11644
|
+
vertical-align: middle;
|
|
11645
|
+
font-family: var(--oc-font-sans);
|
|
11646
|
+
font-size: 0.7rem;
|
|
11647
|
+
letter-spacing: 0.04em;
|
|
11648
|
+
text-transform: uppercase;
|
|
11649
|
+
}
|
|
11650
|
+
|
|
11651
|
+
/* Short syntax classes for hand-written code in an .oc-code-window: keyword, string, constant, function, muted.
|
|
11652
|
+
They take the colors of the window (--oc-syntax-*), so they follow light and dark mode and a theme can change them. */
|
|
11653
|
+
.oc-code-window .oc-tok-k { color: var(--oc-syntax-keyword); }
|
|
11654
|
+
.oc-code-window .oc-tok-s { color: var(--oc-syntax-string); }
|
|
11655
|
+
.oc-code-window .oc-tok-c { color: var(--oc-syntax-constant); }
|
|
11656
|
+
.oc-code-window .oc-tok-f { color: var(--oc-syntax-function); }
|
|
11657
|
+
.oc-code-window .oc-tok-m { color: var(--oc-syntax-comment); }
|
|
11658
|
+
|
|
11140
11659
|
/* parts/site-header-variants.css */
|
|
11141
11660
|
/* File: packages/ui/src/parts/site-header-variants.css
|
|
11142
11661
|
Map: actions slot -> centred menu -> dark -> floating pill -> glass pill -> footer: centred, dark, newsletter, social
|
|
@@ -11209,6 +11728,77 @@ a.oc-message__quote:focus-visible { outline: 2px solid var(--oc-ring); outline-o
|
|
|
11209
11728
|
.oc-site-footer__signup .oc-input { flex: 1 1 12rem; min-inline-size: 0; }
|
|
11210
11729
|
.oc-site-footer--dark .oc-site-footer__signup .oc-input { color: var(--color-white-50); background: oklch(from var(--color-white-50) l c h / 0.08); border-color: oklch(from var(--color-white-50) l c h / 0.2); }
|
|
11211
11730
|
|
|
11731
|
+
/* parts/site-layout.css */
|
|
11732
|
+
/* File: packages/ui/src/parts/site-layout.css */
|
|
11733
|
+
/* Map: page hero -> section head / more -> action row -> group title -> band -> meta line */
|
|
11734
|
+
/* Page building blocks for a marketing or company site, on top of the showcase classes (.oc-section-pad, .oc-display):
|
|
11735
|
+
the larger header of an inner page, a section head and a "see more" row, a row of buttons, a group title with a count,
|
|
11736
|
+
a full-width band (for a stat strip) and a meta line (version · date). */
|
|
11737
|
+
|
|
11738
|
+
/* Inner page header: more room on top, less below, and a larger display title. */
|
|
11739
|
+
.oc-section-pad--page { padding-block: clamp(4rem, 10vw, 7rem) clamp(2rem, 5vw, 3rem); }
|
|
11740
|
+
.oc-display--page {
|
|
11741
|
+
margin-block-end: 1.25rem;
|
|
11742
|
+
font-size: clamp(2.5rem, 6.5vw, 4.75rem);
|
|
11743
|
+
}
|
|
11744
|
+
|
|
11745
|
+
/* Head of a section (eyebrow, title, lead) and the row with a "see all" link under the section. */
|
|
11746
|
+
.oc-section-head {
|
|
11747
|
+
max-inline-size: 46rem;
|
|
11748
|
+
margin-block-end: 3rem;
|
|
11749
|
+
}
|
|
11750
|
+
.oc-section-head--center {
|
|
11751
|
+
margin-inline: auto;
|
|
11752
|
+
text-align: center;
|
|
11753
|
+
}
|
|
11754
|
+
.oc-section-more { margin-block-start: 2.5rem; }
|
|
11755
|
+
|
|
11756
|
+
/* Row of buttons under a text: wraps on a narrow screen. */
|
|
11757
|
+
.oc-actions {
|
|
11758
|
+
display: flex;
|
|
11759
|
+
flex-wrap: wrap;
|
|
11760
|
+
gap: 0.75rem;
|
|
11761
|
+
margin-block-start: 2rem;
|
|
11762
|
+
}
|
|
11763
|
+
.oc-actions--center { justify-content: center; }
|
|
11764
|
+
.oc-actions--end { justify-content: flex-end; }
|
|
11765
|
+
.oc-actions--tight { margin-block-start: 1rem; }
|
|
11766
|
+
|
|
11767
|
+
/* Title of a group of cards with the number of items in a pill: <h3 class="oc-group-title">Apps <span class="oc-group-title__count">8</span></h3> */
|
|
11768
|
+
.oc-group-title {
|
|
11769
|
+
display: flex;
|
|
11770
|
+
align-items: center;
|
|
11771
|
+
gap: 0.75rem;
|
|
11772
|
+
margin: 0 0 1.5rem;
|
|
11773
|
+
font-size: 1.4rem;
|
|
11774
|
+
}
|
|
11775
|
+
.oc-group-title__count {
|
|
11776
|
+
padding: 0.1rem 0.6rem;
|
|
11777
|
+
border-radius: 999px;
|
|
11778
|
+
background: var(--oc-surface-strong);
|
|
11779
|
+
color: var(--oc-muted-foreground);
|
|
11780
|
+
font-size: 0.85rem;
|
|
11781
|
+
font-weight: 500;
|
|
11782
|
+
}
|
|
11783
|
+
|
|
11784
|
+
/* Band over the full width of the page with a line above and below; the content stays in its .oc-container.
|
|
11785
|
+
Put a .oc-stat-strip--plain in it for a row of key figures. */
|
|
11786
|
+
.oc-band {
|
|
11787
|
+
border-block: 1px solid var(--oc-border);
|
|
11788
|
+
background: var(--oc-band-bg, var(--oc-surface));
|
|
11789
|
+
}
|
|
11790
|
+
|
|
11791
|
+
/* Meta line under a page title: version · date, author. */
|
|
11792
|
+
.oc-meta {
|
|
11793
|
+
margin: 0 0 1rem;
|
|
11794
|
+
color: var(--oc-subtle-foreground, var(--oc-muted-foreground));
|
|
11795
|
+
font-size: 0.9rem;
|
|
11796
|
+
}
|
|
11797
|
+
|
|
11798
|
+
/* Muted and subtle text from the theme tokens, for running text inside a panel, a spotlight or a split. */
|
|
11799
|
+
.oc-text-muted { color: var(--oc-muted-foreground); }
|
|
11800
|
+
.oc-text-subtle { color: var(--oc-subtle-foreground, var(--oc-muted-foreground)); }
|
|
11801
|
+
|
|
11212
11802
|
/* parts/site-link-arrow.css */
|
|
11213
11803
|
/* File: packages/ui/src/parts/site-link-arrow.css
|
|
11214
11804
|
Map: focus ring -> back arrow -> external arrow -> color modifiers -> sizes -> reduced motion
|
|
@@ -11414,6 +12004,37 @@ a.oc-message__quote:focus-visible { outline: 2px solid var(--oc-ring); outline-o
|
|
|
11414
12004
|
.oc-next-teaser__tagline::before { transition: none; }
|
|
11415
12005
|
}
|
|
11416
12006
|
|
|
12007
|
+
/* parts/site-panel.css */
|
|
12008
|
+
/* File: packages/ui/src/parts/site-panel.css */
|
|
12009
|
+
/* Map: panel -> glow (start / end / both) */
|
|
12010
|
+
/* A framed panel on the page (a form, a call to action, a feature with a list): card background, strong border, large
|
|
12011
|
+
radius, and room above it when a link jumps to it (#form). --glow adds a soft radial light in a corner:
|
|
12012
|
+
--oc-panel-glow-color (brand 1) and --oc-panel-glow-at (top left); --glow-end puts it top right, --glow-both adds a
|
|
12013
|
+
second light (brand 3) bottom right. */
|
|
12014
|
+
|
|
12015
|
+
.oc-panel {
|
|
12016
|
+
--oc-panel-glow-color: var(--oc-brand-1);
|
|
12017
|
+
--oc-panel-glow-at: 0% 0%;
|
|
12018
|
+
position: relative;
|
|
12019
|
+
padding: var(--oc-panel-padding, clamp(1.5rem, 4vw, 2.5rem));
|
|
12020
|
+
border: 1px solid var(--oc-border-strong);
|
|
12021
|
+
border-radius: calc(var(--oc-radius-lg, 1.25rem) * 1.2);
|
|
12022
|
+
background: var(--oc-card);
|
|
12023
|
+
scroll-margin-top: var(--oc-scroll-offset, 6rem);
|
|
12024
|
+
}
|
|
12025
|
+
.oc-panel--glow {
|
|
12026
|
+
background:
|
|
12027
|
+
radial-gradient(30rem circle at var(--oc-panel-glow-at), oklch(from var(--oc-panel-glow-color) l c h / 0.12), transparent 60%),
|
|
12028
|
+
var(--oc-card);
|
|
12029
|
+
}
|
|
12030
|
+
.oc-panel--glow-end { --oc-panel-glow-at: 100% 0%; }
|
|
12031
|
+
.oc-panel--glow-both {
|
|
12032
|
+
background:
|
|
12033
|
+
radial-gradient(40rem circle at 0% 0%, oklch(from var(--oc-brand-1) l c h / 0.18), transparent 55%),
|
|
12034
|
+
radial-gradient(40rem circle at 100% 100%, oklch(from var(--oc-brand-3) l c h / 0.2), transparent 55%),
|
|
12035
|
+
var(--oc-card);
|
|
12036
|
+
}
|
|
12037
|
+
|
|
11417
12038
|
/* parts/site-price-card.css */
|
|
11418
12039
|
/* File: packages/ui/src/parts/site-price-card.css
|
|
11419
12040
|
Map: card -> head + discount badge -> period toggle -> monthly / yearly / lifetime price (:has) -> features -> featured
|
|
@@ -11833,6 +12454,18 @@ a.oc-message__quote:focus-visible { outline: 2px solid var(--oc-ring); outline-o
|
|
|
11833
12454
|
@media (prefers-reduced-motion: reduce) {
|
|
11834
12455
|
.oc-prose :where(a) { transition: none; }
|
|
11835
12456
|
}
|
|
12457
|
+
|
|
12458
|
+
/* ---- Legal text (terms, privacy, cookies): narrower, muted body text in a slightly larger size, headings and strong
|
|
12459
|
+
in the foreground, disc lists with a gap, links in brand 1. A table in an .oc-table-wrap scrolls on a phone. ---- */
|
|
12460
|
+
.oc-prose--legal { max-inline-size: 46rem; color: var(--oc-muted-foreground); font-size: 1.0625rem; }
|
|
12461
|
+
.oc-prose--legal :where(h2) { margin-block-start: 2.5rem; font-size: 1.35rem; color: var(--oc-foreground); }
|
|
12462
|
+
.oc-prose--legal :where(h3) { margin-block-start: 1.5rem; font-size: 1.05rem; color: var(--oc-foreground); }
|
|
12463
|
+
.oc-prose--legal :where(strong, b) { color: var(--oc-foreground); }
|
|
12464
|
+
.oc-prose--legal :where(ul) { display: grid; gap: 0.4rem; padding-inline-start: 1.25rem; list-style: disc; }
|
|
12465
|
+
.oc-prose--legal :where(ul > li) { margin-block-start: 0; }
|
|
12466
|
+
.oc-prose--legal :where(a) { color: var(--oc-brand-1); font-weight: inherit; text-decoration-color: currentColor; text-underline-offset: 3px; }
|
|
12467
|
+
.oc-prose--legal :where(a:hover) { color: var(--oc-foreground); }
|
|
12468
|
+
.oc-prose--legal :where(table) { font-size: 0.93rem; }
|
|
11836
12469
|
|
|
11837
12470
|
/* parts/site-stack-list.css */
|
|
11838
12471
|
/* File: packages/ui/src/parts/site-stack-list.css
|
|
@@ -11940,6 +12573,52 @@ a.oc-message__quote:focus-visible { outline: 2px solid var(--oc-ring); outline-o
|
|
|
11940
12573
|
/* Line in the accent color instead of the neutral border. */
|
|
11941
12574
|
.oc-timeline--accent { border-inline-start-color: color-mix(in oklch, var(--oc-accent-from) 55%, transparent); }
|
|
11942
12575
|
|
|
12576
|
+
/* parts/utility-hover.css */
|
|
12577
|
+
/* File: packages/ui/src/parts/utility-hover.css */
|
|
12578
|
+
/* Map: smooth timing -> lift / grow / glow / none -> steady hover area -> reduced motion */
|
|
12579
|
+
/* Hover effect of a card, chosen with one class on the card (any card: .oc-card, product, feature, link, price, project …):
|
|
12580
|
+
.oc-hover-lift moves up (--oc-hover-lift, 6px) with a soft shadow; what a product card does by default
|
|
12581
|
+
.oc-hover-grow grows a little in place (--oc-hover-scale, 1.02)
|
|
12582
|
+
.oc-hover-glow stays in place, with a glow in the accent color
|
|
12583
|
+
.oc-hover-none no movement (also turns off the default lift of a product or price card)
|
|
12584
|
+
They share one smooth curve: --oc-hover-duration (0.45s) and --oc-hover-ease. This file loads after the cards, so the class wins. */
|
|
12585
|
+
|
|
12586
|
+
:is(.oc-hover-lift, .oc-hover-grow, .oc-hover-glow, .oc-product-card) {
|
|
12587
|
+
transition:
|
|
12588
|
+
translate var(--oc-hover-duration, 0.45s) var(--oc-hover-ease, cubic-bezier(0.22, 1, 0.36, 1)),
|
|
12589
|
+
scale var(--oc-hover-duration, 0.45s) var(--oc-hover-ease, cubic-bezier(0.22, 1, 0.36, 1)),
|
|
12590
|
+
box-shadow var(--oc-hover-duration, 0.45s) var(--oc-hover-ease, cubic-bezier(0.22, 1, 0.36, 1)),
|
|
12591
|
+
border-color 0.35s,
|
|
12592
|
+
background-color 0.35s,
|
|
12593
|
+
--oc-glow 0.35s;
|
|
12594
|
+
}
|
|
12595
|
+
.oc-product-card:hover { translate: 0 calc(-1 * var(--oc-hover-lift, 6px)); }
|
|
12596
|
+
.oc-hover-lift:hover {
|
|
12597
|
+
translate: 0 calc(-1 * var(--oc-hover-lift, 6px));
|
|
12598
|
+
box-shadow: 0 1.25rem 2.5rem -1.25rem oklch(from var(--color-black-60) l c h / 0.35);
|
|
12599
|
+
}
|
|
12600
|
+
.oc-hover-grow:hover { translate: none; scale: var(--oc-hover-scale, 1.02); }
|
|
12601
|
+
.oc-hover-glow:hover {
|
|
12602
|
+
translate: none;
|
|
12603
|
+
box-shadow:
|
|
12604
|
+
0 0 0 1px oklch(from var(--oc-accent-from, var(--oc-primary)) l c h / 0.4),
|
|
12605
|
+
0 0.75rem 2.5rem -0.75rem oklch(from var(--oc-accent-from, var(--oc-primary)) l c h / 0.5);
|
|
12606
|
+
}
|
|
12607
|
+
.oc-hover-none:hover { translate: none; scale: none; }
|
|
12608
|
+
|
|
12609
|
+
/* While a card moves up, the strip it leaves keeps the hover, so a mouse at the bottom edge does not make it bounce. */
|
|
12610
|
+
:where(.oc-hover-lift) { position: relative; }
|
|
12611
|
+
:is(.oc-hover-lift, .oc-product-card:not([class*="oc-hover-"])):hover::before {
|
|
12612
|
+
content: "";
|
|
12613
|
+
position: absolute;
|
|
12614
|
+
inset: 0 0 calc(-1 * var(--oc-hover-lift, 6px) - 2px);
|
|
12615
|
+
z-index: -1;
|
|
12616
|
+
}
|
|
12617
|
+
|
|
12618
|
+
@media (prefers-reduced-motion: reduce) {
|
|
12619
|
+
:is(.oc-hover-lift, .oc-hover-grow, .oc-product-card):hover { translate: none; scale: none; }
|
|
12620
|
+
}
|
|
12621
|
+
|
|
11943
12622
|
/* File: packages/ui/src/code-block.css — Code-block component (line numbers + Omnia syntax theme) */
|
|
11944
12623
|
/* Map: pre.code base -> CSS variables -> token spans (.hl-tag, .hl-attr, .hl-string, etc.) */
|
|
11945
12624
|
/*
|