@birdycom/omniaui 0.0.0-stage → 0.11.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/LICENSE +21 -0
- package/README.md +20 -2
- package/bin/lib/add.mjs +126 -0
- package/bin/lib/catalog.mjs +169 -0
- package/bin/lib/project.mjs +90 -0
- package/bin/omniaui.mjs +70 -0
- package/dist/code-block.css +163 -0
- package/dist/components-extra.css +914 -0
- package/dist/components.css +10081 -0
- package/dist/components.min.css +1 -0
- package/dist/data-table.d.ts +9 -0
- package/dist/data-table.js +505 -0
- package/dist/docs-ui.css +265 -0
- package/dist/oc-theme.css +69 -0
- package/dist/parts/.gitkeep +0 -0
- package/dist/parts/app-accordion-accent.css +60 -0
- package/dist/parts/app-alpha-tabs.css +68 -0
- package/dist/parts/app-busy-overlay.css +25 -0
- package/dist/parts/app-column-menu.css +85 -0
- package/dist/parts/app-confirm-dialog.css +70 -0
- package/dist/parts/app-cookie-consent.css +63 -0
- package/dist/parts/app-data-table.css +174 -0
- package/dist/parts/app-greeting.css +47 -0
- package/dist/parts/app-list-toolbar.css +81 -0
- package/dist/parts/app-page-header.css +54 -0
- package/dist/parts/app-severity-card.css +91 -0
- package/dist/parts/app-sidebar-dark.css +15 -0
- package/dist/parts/app-sortable-row.css +52 -0
- package/dist/parts/app-stat-card.css +68 -0
- package/dist/parts/app-table-actions.css +71 -0
- package/dist/parts/app-table-compact.css +54 -0
- package/dist/parts/app-top-progress.css +68 -0
- package/dist/parts/app-tree.css +104 -0
- package/dist/parts/app-upgrade-banner.css +90 -0
- package/dist/parts/app-version-banner.css +80 -0
- package/dist/parts/data-chart-line.css +167 -0
- package/dist/parts/forms-affix-input.css +75 -0
- package/dist/parts/forms-barcode-input.css +75 -0
- package/dist/parts/forms-chip-filter.css +91 -0
- package/dist/parts/forms-color-select.css +89 -0
- package/dist/parts/forms-decimal-input.css +51 -0
- package/dist/parts/forms-filter-counts.css +94 -0
- package/dist/parts/forms-language-select.css +76 -0
- package/dist/parts/forms-number-input.css +95 -0
- package/dist/parts/forms-password-requirements.css +55 -0
- package/dist/parts/forms-phone-input.css +85 -0
- package/dist/parts/forms-time-input.css +74 -0
- package/dist/parts/forms-toggle-field.css +69 -0
- package/dist/parts/media-art.css +21 -0
- package/dist/parts/media-attachment.css +160 -0
- package/dist/parts/media-browser-frame.css +73 -0
- package/dist/parts/media-card.css +83 -0
- package/dist/parts/media-chat-composer.css +90 -0
- package/dist/parts/media-doc-viewer.css +151 -0
- package/dist/parts/media-emoji-picker.css +88 -0
- package/dist/parts/media-entity-card.css +52 -0
- package/dist/parts/media-flip-card.css +78 -0
- package/dist/parts/media-image-zoom.css +68 -0
- package/dist/parts/media-lightbox.css +131 -0
- package/dist/parts/media-message-thread.css +136 -0
- package/dist/parts/media-message.css +160 -0
- package/dist/parts/media-row.css +78 -0
- package/dist/parts/media-stack-card.css +82 -0
- package/dist/parts/media-terminal-log.css +76 -0
- package/dist/parts/media-thumb.css +71 -0
- package/dist/parts/site-fact-list.css +25 -0
- package/dist/parts/site-link-arrow.css +34 -0
- package/dist/parts/site-marquee.css +34 -0
- package/dist/parts/site-next-teaser.css +75 -0
- package/dist/parts/site-price-card.css +75 -0
- package/dist/parts/site-product-mark.css +66 -0
- package/dist/parts/site-project-card.css +111 -0
- package/dist/parts/site-prose.css +124 -0
- package/dist/parts/site-stack-list.css +48 -0
- package/dist/parts/site-timeline.css +54 -0
- package/dist/showcase.css +404 -0
- package/manifest.json +1108 -0
- package/package.json +67 -4
- package/snippets/accordion-accent.html +24 -0
- package/snippets/accordion.html +11 -0
- package/snippets/affix-input.html +30 -0
- package/snippets/alert-dialog.html +22 -0
- package/snippets/alert.html +5 -0
- package/snippets/alpha-tabs.html +37 -0
- package/snippets/aspect-ratio.html +15 -0
- package/snippets/attachment.html +43 -0
- package/snippets/avatar.html +6 -0
- package/snippets/back-link.html +5 -0
- package/snippets/badge.html +5 -0
- package/snippets/barcode-input.html +18 -0
- package/snippets/breadcrumb.html +6 -0
- package/snippets/browser-frame.html +18 -0
- package/snippets/busy-overlay.html +31 -0
- package/snippets/button-group.html +21 -0
- package/snippets/button.html +8 -0
- package/snippets/calendar.html +43 -0
- package/snippets/card.html +17 -0
- package/snippets/carousel.html +21 -0
- package/snippets/chart-line.html +46 -0
- package/snippets/chart.html +27 -0
- package/snippets/chat-composer.html +21 -0
- package/snippets/checkbox.html +5 -0
- package/snippets/checklist.html +23 -0
- package/snippets/chip-filter.html +14 -0
- package/snippets/code-window.html +20 -0
- package/snippets/collapsible.html +19 -0
- package/snippets/color-field.html +13 -0
- package/snippets/color-select.html +18 -0
- package/snippets/column-menu.html +38 -0
- package/snippets/combobox.html +19 -0
- package/snippets/command.html +24 -0
- package/snippets/confirm-dialog.html +32 -0
- package/snippets/context-menu.html +25 -0
- package/snippets/cookie-consent.html +70 -0
- package/snippets/copy-field.html +19 -0
- package/snippets/counter.html +2 -0
- package/snippets/data-table.html +151 -0
- package/snippets/date-picker.html +32 -0
- package/snippets/decimal-input.html +20 -0
- package/snippets/definition-list.html +20 -0
- package/snippets/demo-panel.html +18 -0
- package/snippets/doc-viewer.html +58 -0
- package/snippets/drawer.html +30 -0
- package/snippets/dropdown-menu.html +27 -0
- package/snippets/dropdown.html +9 -0
- package/snippets/dropzone.html +13 -0
- package/snippets/emoji-picker.html +51 -0
- package/snippets/empty-state.html +17 -0
- package/snippets/entity-card.html +26 -0
- package/snippets/expandable-table.html +26 -0
- package/snippets/fact-list.html +14 -0
- package/snippets/filter-counts.html +30 -0
- package/snippets/flip-card.html +22 -0
- package/snippets/form-field.html +6 -0
- package/snippets/greeting.html +22 -0
- package/snippets/heading.html +14 -0
- package/snippets/hover-card.html +18 -0
- package/snippets/image-zoom.html +30 -0
- package/snippets/input-group.html +10 -0
- package/snippets/input.html +5 -0
- package/snippets/item.html +26 -0
- package/snippets/kbd.html +13 -0
- package/snippets/label.html +9 -0
- package/snippets/language-select.html +26 -0
- package/snippets/launcher-card.html +14 -0
- package/snippets/lightbox.html +50 -0
- package/snippets/link-arrow.html +10 -0
- package/snippets/list-toolbar.html +33 -0
- package/snippets/marquee.html +15 -0
- package/snippets/media-card.html +28 -0
- package/snippets/media-row.html +21 -0
- package/snippets/media-thumb.html +12 -0
- package/snippets/menubar.html +30 -0
- package/snippets/message-thread.html +123 -0
- package/snippets/message.html +51 -0
- package/snippets/modal.html +15 -0
- package/snippets/native-select.html +15 -0
- package/snippets/navmenu.html +23 -0
- package/snippets/next-teaser.html +15 -0
- package/snippets/number-input.html +27 -0
- package/snippets/otp-input.html +9 -0
- package/snippets/page-header.html +24 -0
- package/snippets/pagination.html +6 -0
- package/snippets/password-input.html +24 -0
- package/snippets/password-requirements.html +30 -0
- package/snippets/phone-input.html +22 -0
- package/snippets/popover.html +15 -0
- package/snippets/price-card.html +34 -0
- package/snippets/product-mark.html +13 -0
- package/snippets/progress.html +4 -0
- package/snippets/project-card.html +23 -0
- package/snippets/prose.html +54 -0
- package/snippets/radio.html +17 -0
- package/snippets/recovery-codes.html +20 -0
- package/snippets/resizable.html +16 -0
- package/snippets/scroll-area.html +20 -0
- package/snippets/search.html +8 -0
- package/snippets/segmented.html +11 -0
- package/snippets/select.html +7 -0
- package/snippets/separator.html +15 -0
- package/snippets/severity-card.html +35 -0
- package/snippets/sheet.html +32 -0
- package/snippets/sidebar-docs.html +24 -0
- package/snippets/sidebar.html +55 -0
- package/snippets/site-footer.html +6 -0
- package/snippets/site-header.html +26 -0
- package/snippets/skeleton.html +4 -0
- package/snippets/slider.html +17 -0
- package/snippets/sortable-row.html +31 -0
- package/snippets/spinner.html +14 -0
- package/snippets/stack-card.html +17 -0
- package/snippets/stack-list.html +16 -0
- package/snippets/stat-card.html +24 -0
- package/snippets/stepper.html +13 -0
- package/snippets/switch.html +6 -0
- package/snippets/table-actions.html +39 -0
- package/snippets/table-compact.html +24 -0
- package/snippets/table.html +29 -0
- package/snippets/tabs.html +9 -0
- package/snippets/tag-input.html +17 -0
- package/snippets/terminal-log.html +23 -0
- package/snippets/textarea.html +3 -0
- package/snippets/theme-switch.html +6 -0
- package/snippets/time-input.html +26 -0
- package/snippets/timeline.html +28 -0
- package/snippets/toast-stack.html +10 -0
- package/snippets/toast.html +36 -0
- package/snippets/toc.html +13 -0
- package/snippets/toggle-field.html +20 -0
- package/snippets/toggle.html +22 -0
- package/snippets/tooltip.html +4 -0
- package/snippets/top-progress.html +12 -0
- package/snippets/tree.html +38 -0
- package/snippets/upgrade-banner.html +28 -0
- package/snippets/user.html +15 -0
- package/snippets/version-banner.html +15 -0
|
@@ -0,0 +1,914 @@
|
|
|
1
|
+
/* File: packages/ui/src/components-extra.css */
|
|
2
|
+
/* Map: spinner · kbd · slider · toggle + toggle-group · item · aspect-ratio · hover-card · menu extras (sub-menu, check/radio items, shortcut) ·
|
|
3
|
+
menubar · context-menu · carousel · resizable · combobox · drawer · native-select (base-select) · toast stack · calendar · date-picker · chart tokens */
|
|
4
|
+
/* Depends on: components.css (tokens --oc-*, .oc-btn, .oc-dropdown-*, .oc-popover, .oc-toast). Loaded after it in the concatenated bundle.
|
|
5
|
+
Every color is an --oc-* theme token or an Omnia palette token, so light and dark follow the theme.
|
|
6
|
+
Native HTML first (popover, dialog, :has(), anchor positioning, scroll-snap); progressive enhancement is wrapped in @supports. */
|
|
7
|
+
|
|
8
|
+
/* ===================================================================
|
|
9
|
+
SPINNER — border ring, inherits currentColor. Sizes: --sm · --lg · --xl. Color: set `color` or use --primary.
|
|
10
|
+
Add role="status" + aria-label (or visually hidden text) so it is announced.
|
|
11
|
+
=================================================================== */
|
|
12
|
+
.oc-spinner {
|
|
13
|
+
--oc-spinner-size: 1.25rem;
|
|
14
|
+
display: inline-block;
|
|
15
|
+
flex: none;
|
|
16
|
+
inline-size: var(--oc-spinner-size);
|
|
17
|
+
block-size: var(--oc-spinner-size);
|
|
18
|
+
vertical-align: -0.2em;
|
|
19
|
+
border: max(2px, calc(var(--oc-spinner-size) / 10)) solid color-mix(in oklab, currentColor 22%, transparent);
|
|
20
|
+
border-block-start-color: currentColor;
|
|
21
|
+
border-radius: 50%;
|
|
22
|
+
animation: oc-spinner-rotate 0.75s linear infinite;
|
|
23
|
+
}
|
|
24
|
+
.oc-spinner--sm { --oc-spinner-size: 0.875rem; }
|
|
25
|
+
.oc-spinner--lg { --oc-spinner-size: 2rem; }
|
|
26
|
+
.oc-spinner--xl { --oc-spinner-size: 3rem; }
|
|
27
|
+
.oc-spinner--primary { color: var(--oc-primary); }
|
|
28
|
+
.oc-spinner--muted { color: var(--oc-muted-foreground); }
|
|
29
|
+
@keyframes oc-spinner-rotate { to { transform: rotate(360deg); } }
|
|
30
|
+
@media (prefers-reduced-motion: reduce) {
|
|
31
|
+
.oc-spinner { animation-duration: 2.5s; }
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/* ===================================================================
|
|
35
|
+
KBD — keyboard key. Group several keys with .oc-kbd-group. Inside a button/tooltip/menu it adapts to the surface.
|
|
36
|
+
=================================================================== */
|
|
37
|
+
.oc-kbd {
|
|
38
|
+
display: inline-flex;
|
|
39
|
+
align-items: center;
|
|
40
|
+
justify-content: center;
|
|
41
|
+
min-inline-size: 1.4rem;
|
|
42
|
+
block-size: 1.4rem;
|
|
43
|
+
padding: 0 0.35rem;
|
|
44
|
+
font: 600 0.6875rem/1 ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
|
|
45
|
+
color: var(--oc-muted-foreground);
|
|
46
|
+
background: var(--oc-muted);
|
|
47
|
+
border: 1px solid var(--oc-border);
|
|
48
|
+
border-block-end-width: 2px;
|
|
49
|
+
border-radius: calc(var(--oc-radius) - 3px);
|
|
50
|
+
white-space: nowrap;
|
|
51
|
+
user-select: none;
|
|
52
|
+
}
|
|
53
|
+
.oc-kbd-group { display: inline-flex; align-items: center; gap: 0.25rem; }
|
|
54
|
+
.oc-kbd-group > .oc-kbd-sep { color: var(--oc-muted-foreground); font-size: 0.75rem; }
|
|
55
|
+
|
|
56
|
+
/* ===================================================================
|
|
57
|
+
SLIDER — native <input type="range" class="oc-slider">. Value, step, min/max, keyboard and a11y come from the browser.
|
|
58
|
+
Fill: Firefox fills natively; for Chromium/WebKit set --oc-slider-progress (e.g. style="--oc-slider-progress: 40%"),
|
|
59
|
+
optionally kept in sync by the 1-line script shown in the docs. Vertical: .oc-slider--vertical.
|
|
60
|
+
=================================================================== */
|
|
61
|
+
.oc-slider {
|
|
62
|
+
--oc-slider-progress: 0%;
|
|
63
|
+
--oc-slider-track: 0.375rem;
|
|
64
|
+
--oc-slider-thumb: 1.125rem;
|
|
65
|
+
appearance: none;
|
|
66
|
+
display: block;
|
|
67
|
+
inline-size: 100%;
|
|
68
|
+
block-size: var(--oc-slider-thumb);
|
|
69
|
+
margin: 0;
|
|
70
|
+
padding: 0;
|
|
71
|
+
background: transparent;
|
|
72
|
+
cursor: pointer;
|
|
73
|
+
accent-color: var(--oc-primary);
|
|
74
|
+
}
|
|
75
|
+
.oc-slider:focus { outline: none; }
|
|
76
|
+
.oc-slider::-webkit-slider-runnable-track {
|
|
77
|
+
block-size: var(--oc-slider-track);
|
|
78
|
+
border-radius: 999px;
|
|
79
|
+
background: linear-gradient(to right, var(--oc-primary) var(--oc-slider-progress), var(--oc-muted) var(--oc-slider-progress));
|
|
80
|
+
box-shadow: inset 0 0 0 1px var(--oc-border);
|
|
81
|
+
}
|
|
82
|
+
.oc-slider::-webkit-slider-thumb {
|
|
83
|
+
appearance: none;
|
|
84
|
+
inline-size: var(--oc-slider-thumb);
|
|
85
|
+
block-size: var(--oc-slider-thumb);
|
|
86
|
+
margin-block-start: calc((var(--oc-slider-track) - var(--oc-slider-thumb)) / 2);
|
|
87
|
+
border-radius: 50%;
|
|
88
|
+
border: 2px solid var(--oc-primary);
|
|
89
|
+
background: var(--oc-background);
|
|
90
|
+
box-shadow: 0 1px 3px oklch(from var(--color-black-60) l c h / 0.25);
|
|
91
|
+
transition: box-shadow var(--oc-transition-fast), scale var(--oc-transition-fast);
|
|
92
|
+
}
|
|
93
|
+
.oc-slider::-moz-range-track {
|
|
94
|
+
block-size: var(--oc-slider-track);
|
|
95
|
+
border-radius: 999px;
|
|
96
|
+
background: var(--oc-muted);
|
|
97
|
+
box-shadow: inset 0 0 0 1px var(--oc-border);
|
|
98
|
+
}
|
|
99
|
+
.oc-slider::-moz-range-progress { block-size: var(--oc-slider-track); border-radius: 999px; background: var(--oc-primary); }
|
|
100
|
+
.oc-slider::-moz-range-thumb {
|
|
101
|
+
box-sizing: border-box;
|
|
102
|
+
inline-size: var(--oc-slider-thumb);
|
|
103
|
+
block-size: var(--oc-slider-thumb);
|
|
104
|
+
border-radius: 50%;
|
|
105
|
+
border: 2px solid var(--oc-primary);
|
|
106
|
+
background: var(--oc-background);
|
|
107
|
+
box-shadow: 0 1px 3px oklch(from var(--color-black-60) l c h / 0.25);
|
|
108
|
+
}
|
|
109
|
+
.oc-slider:hover::-webkit-slider-thumb { scale: 1.08; }
|
|
110
|
+
.oc-slider:focus-visible::-webkit-slider-thumb { box-shadow: 0 0 0 4px oklch(from var(--oc-ring) l c h / 0.28); }
|
|
111
|
+
.oc-slider:focus-visible::-moz-range-thumb { box-shadow: 0 0 0 4px oklch(from var(--oc-ring) l c h / 0.28); }
|
|
112
|
+
.oc-slider:disabled { opacity: 0.5; cursor: not-allowed; }
|
|
113
|
+
.oc-slider--vertical { writing-mode: vertical-lr; direction: rtl; inline-size: var(--oc-slider-thumb); block-size: 10rem; }
|
|
114
|
+
.oc-slider--vertical::-webkit-slider-runnable-track {
|
|
115
|
+
background: linear-gradient(to top, var(--oc-primary) var(--oc-slider-progress), var(--oc-muted) var(--oc-slider-progress));
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/* ===================================================================
|
|
119
|
+
TOGGLE — two-state button. Works with <button aria-pressed>, [data-state="on"] or <label class="oc-toggle"><input type="checkbox">.
|
|
120
|
+
Variants: --outline · sizes --sm · --lg. TOGGLE GROUP: .oc-toggle-group (radio inputs = single, checkbox inputs = multiple).
|
|
121
|
+
=================================================================== */
|
|
122
|
+
.oc-toggle {
|
|
123
|
+
position: relative;
|
|
124
|
+
display: inline-flex;
|
|
125
|
+
align-items: center;
|
|
126
|
+
justify-content: center;
|
|
127
|
+
gap: 0.5rem;
|
|
128
|
+
min-block-size: 2.25rem;
|
|
129
|
+
padding: 0 0.75rem;
|
|
130
|
+
font-family: inherit;
|
|
131
|
+
font-size: 0.875rem;
|
|
132
|
+
font-weight: 500;
|
|
133
|
+
line-height: 1;
|
|
134
|
+
color: var(--oc-foreground);
|
|
135
|
+
background: transparent;
|
|
136
|
+
border: 1px solid transparent;
|
|
137
|
+
border-radius: var(--oc-radius);
|
|
138
|
+
cursor: pointer;
|
|
139
|
+
user-select: none;
|
|
140
|
+
transition: background var(--oc-transition-fast), color var(--oc-transition-fast), border-color var(--oc-transition-fast);
|
|
141
|
+
}
|
|
142
|
+
.oc-toggle:hover { background: var(--oc-muted); }
|
|
143
|
+
.oc-toggle:focus-visible,
|
|
144
|
+
.oc-toggle:has(input:focus-visible) { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
|
|
145
|
+
.oc-toggle[aria-pressed="true"],
|
|
146
|
+
.oc-toggle[data-state="on"],
|
|
147
|
+
.oc-toggle:has(input:checked) {
|
|
148
|
+
background: color-mix(in oklab, var(--oc-primary) 16%, transparent);
|
|
149
|
+
color: var(--oc-foreground);
|
|
150
|
+
}
|
|
151
|
+
.oc-toggle[disabled],
|
|
152
|
+
.oc-toggle:has(input:disabled) { opacity: 0.5; pointer-events: none; }
|
|
153
|
+
.oc-toggle input { position: absolute; inset: 0; margin: 0; opacity: 0; pointer-events: none; }
|
|
154
|
+
.oc-toggle svg { inline-size: 1rem; block-size: 1rem; flex: none; }
|
|
155
|
+
.oc-toggle--outline { border-color: var(--oc-input); }
|
|
156
|
+
.oc-toggle--outline:hover { background: var(--oc-accent); }
|
|
157
|
+
.oc-toggle--sm { min-block-size: 1.875rem; padding: 0 0.5rem; font-size: 0.8125rem; }
|
|
158
|
+
.oc-toggle--lg { min-block-size: 2.75rem; padding: 0 1rem; font-size: 1rem; }
|
|
159
|
+
.oc-toggle--icon { inline-size: 2.25rem; padding: 0; }
|
|
160
|
+
|
|
161
|
+
.oc-toggle-group { display: inline-flex; align-items: center; }
|
|
162
|
+
.oc-toggle-group > .oc-toggle { border-radius: 0; }
|
|
163
|
+
.oc-toggle-group > .oc-toggle:first-child { border-start-start-radius: var(--oc-radius); border-end-start-radius: var(--oc-radius); }
|
|
164
|
+
.oc-toggle-group > .oc-toggle:last-child { border-start-end-radius: var(--oc-radius); border-end-end-radius: var(--oc-radius); }
|
|
165
|
+
.oc-toggle-group > .oc-toggle--outline + .oc-toggle--outline { margin-inline-start: -1px; }
|
|
166
|
+
.oc-toggle-group > .oc-toggle--outline[aria-pressed="true"],
|
|
167
|
+
.oc-toggle-group > .oc-toggle--outline:has(input:checked) { z-index: 1; border-color: var(--oc-primary); }
|
|
168
|
+
.oc-toggle-group--spaced { gap: 0.25rem; }
|
|
169
|
+
.oc-toggle-group--spaced > .oc-toggle { border-radius: var(--oc-radius); }
|
|
170
|
+
.oc-toggle-group--spaced > .oc-toggle--outline + .oc-toggle--outline { margin-inline-start: 0; }
|
|
171
|
+
|
|
172
|
+
/* ===================================================================
|
|
173
|
+
ITEM — media + content + actions row (settings rows, file lists, search results). Use <div>, <a> or <li>.
|
|
174
|
+
Variants: --outline · --muted · --sm. Parts: -media (--icon · --image) · -content · -title · -description · -actions · -header · -footer
|
|
175
|
+
=================================================================== */
|
|
176
|
+
.oc-item {
|
|
177
|
+
display: flex;
|
|
178
|
+
flex-wrap: wrap;
|
|
179
|
+
align-items: center;
|
|
180
|
+
gap: 1rem;
|
|
181
|
+
padding: 0.875rem 1rem;
|
|
182
|
+
font-size: 0.875rem;
|
|
183
|
+
color: var(--oc-foreground);
|
|
184
|
+
text-decoration: none;
|
|
185
|
+
background: transparent;
|
|
186
|
+
border: 1px solid transparent;
|
|
187
|
+
border-radius: var(--oc-radius);
|
|
188
|
+
transition: background var(--oc-transition-fast), border-color var(--oc-transition-fast);
|
|
189
|
+
}
|
|
190
|
+
a.oc-item:hover,
|
|
191
|
+
.oc-item--interactive:hover { background: var(--oc-surface-strong); }
|
|
192
|
+
a.oc-item:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
|
|
193
|
+
.oc-item--outline { border-color: var(--oc-border); }
|
|
194
|
+
.oc-item--muted { background: var(--oc-surface); }
|
|
195
|
+
.oc-item--sm { gap: 0.625rem; padding: 0.5rem 0.75rem; }
|
|
196
|
+
.oc-item-media { display: flex; flex: none; align-items: center; justify-content: center; align-self: flex-start; gap: 0.5rem; }
|
|
197
|
+
.oc-item-media--icon {
|
|
198
|
+
inline-size: 2.25rem;
|
|
199
|
+
block-size: 2.25rem;
|
|
200
|
+
color: var(--oc-foreground);
|
|
201
|
+
background: var(--oc-muted);
|
|
202
|
+
border: 1px solid var(--oc-border);
|
|
203
|
+
border-radius: calc(var(--oc-radius) - 2px);
|
|
204
|
+
}
|
|
205
|
+
.oc-item-media--icon svg { inline-size: 1.1rem; block-size: 1.1rem; }
|
|
206
|
+
.oc-item-media--image { inline-size: 2.5rem; block-size: 2.5rem; overflow: hidden; border-radius: calc(var(--oc-radius) - 2px); }
|
|
207
|
+
.oc-item-media--image > img { inline-size: 100%; block-size: 100%; object-fit: cover; }
|
|
208
|
+
.oc-item-content { display: flex; flex: 1 1 14rem; flex-direction: column; gap: 0.125rem; min-inline-size: 0; }
|
|
209
|
+
.oc-item-title { margin: 0; font-weight: 500; line-height: 1.35; color: var(--oc-foreground); }
|
|
210
|
+
.oc-item-description { margin: 0; font-size: 0.8125rem; line-height: 1.45; color: var(--oc-muted-foreground); text-wrap: balance; }
|
|
211
|
+
.oc-item-actions { display: flex; flex: none; align-items: center; gap: 0.5rem; }
|
|
212
|
+
.oc-item-header,
|
|
213
|
+
.oc-item-footer { flex-basis: 100%; display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
|
|
214
|
+
.oc-item-group { display: flex; flex-direction: column; }
|
|
215
|
+
.oc-item-group > .oc-item-separator { block-size: 1px; margin: 0; background: var(--oc-border); border: 0; }
|
|
216
|
+
|
|
217
|
+
/* ===================================================================
|
|
218
|
+
ASPECT RATIO — box that keeps a ratio; child img/video/iframe fills it. Custom: style="--oc-aspect: 5 / 2"
|
|
219
|
+
=================================================================== */
|
|
220
|
+
.oc-aspect {
|
|
221
|
+
--oc-aspect: 16 / 9;
|
|
222
|
+
position: relative;
|
|
223
|
+
overflow: hidden;
|
|
224
|
+
aspect-ratio: var(--oc-aspect);
|
|
225
|
+
background: var(--oc-muted);
|
|
226
|
+
border-radius: var(--oc-radius);
|
|
227
|
+
}
|
|
228
|
+
.oc-aspect--square { --oc-aspect: 1 / 1; }
|
|
229
|
+
.oc-aspect--photo { --oc-aspect: 4 / 3; }
|
|
230
|
+
.oc-aspect--portrait { --oc-aspect: 3 / 4; }
|
|
231
|
+
.oc-aspect--wide { --oc-aspect: 21 / 9; }
|
|
232
|
+
.oc-aspect > img,
|
|
233
|
+
.oc-aspect > video,
|
|
234
|
+
.oc-aspect > iframe,
|
|
235
|
+
.oc-aspect > svg,
|
|
236
|
+
.oc-aspect > picture { display: block; inline-size: 100%; block-size: 100%; border: 0; object-fit: cover; }
|
|
237
|
+
.oc-aspect--center { display: grid; place-items: center; }
|
|
238
|
+
|
|
239
|
+
/* ===================================================================
|
|
240
|
+
HOVER CARD — rich preview on hover and keyboard focus. One markup, two engines:
|
|
241
|
+
- a Chromium that supports `interestfor` opens the [popover] content as a real popover (top layer, hover delay by the browser)
|
|
242
|
+
- everywhere else :hover / :focus-within on the wrapper shows it (CSS only).
|
|
243
|
+
Anchor positioning (anchor() insets) keeps the card next to the trigger; anchor-scope makes several cards on one page independent.
|
|
244
|
+
=================================================================== */
|
|
245
|
+
.oc-hover-card { position: relative; display: inline-block; anchor-scope: --oc-hover-card; }
|
|
246
|
+
.oc-hover-card-trigger { anchor-name: --oc-hover-card; }
|
|
247
|
+
.oc-hover-card-content {
|
|
248
|
+
position: fixed;
|
|
249
|
+
inset: auto;
|
|
250
|
+
position-anchor: --oc-hover-card;
|
|
251
|
+
inset-block-start: anchor(bottom);
|
|
252
|
+
inset-inline-start: anchor(start);
|
|
253
|
+
z-index: 100;
|
|
254
|
+
display: block;
|
|
255
|
+
inline-size: 20rem;
|
|
256
|
+
max-inline-size: calc(100vw - 1rem);
|
|
257
|
+
margin: 0.5rem 0 0;
|
|
258
|
+
padding: 1rem;
|
|
259
|
+
font-size: 0.875rem;
|
|
260
|
+
color: var(--oc-popover-foreground);
|
|
261
|
+
background: var(--oc-popover);
|
|
262
|
+
border: 1px solid var(--oc-border);
|
|
263
|
+
border-radius: calc(var(--oc-radius) + 2px);
|
|
264
|
+
box-shadow: 0 8px 24px oklch(from var(--color-black-60) l c h / 0.15);
|
|
265
|
+
visibility: hidden;
|
|
266
|
+
opacity: 0;
|
|
267
|
+
translate: 0 -2px;
|
|
268
|
+
transition: opacity var(--oc-transition-fast) 0s, translate var(--oc-transition-fast) 0s, visibility 0s var(--oc-transition-fast);
|
|
269
|
+
}
|
|
270
|
+
/* invisible bridge so the pointer can travel from trigger to card */
|
|
271
|
+
.oc-hover-card-content::before { content: ""; position: absolute; inset-inline: 0; inset-block-end: 100%; block-size: 0.75rem; }
|
|
272
|
+
.oc-hover-card:hover > .oc-hover-card-content,
|
|
273
|
+
.oc-hover-card:focus-within > .oc-hover-card-content,
|
|
274
|
+
.oc-hover-card-content:popover-open {
|
|
275
|
+
visibility: visible;
|
|
276
|
+
opacity: 1;
|
|
277
|
+
translate: 0 0;
|
|
278
|
+
transition-delay: 0.35s, 0.35s, 0.35s;
|
|
279
|
+
}
|
|
280
|
+
/* flipping at screen edges only for the popover engine (fresh layout on open); the hover fallback keeps its side */
|
|
281
|
+
.oc-hover-card-content:popover-open { position-try-fallbacks: flip-block, flip-inline; }
|
|
282
|
+
.oc-hover-card--top > .oc-hover-card-content { inset-block-start: auto; inset-block-end: anchor(top); margin: 0 0 0.5rem; }
|
|
283
|
+
.oc-hover-card--top > .oc-hover-card-content::before { inset-block: 100% auto; }
|
|
284
|
+
.oc-hover-card-content--sm { inline-size: 14rem; padding: 0.75rem; }
|
|
285
|
+
@media (prefers-reduced-motion: reduce) {
|
|
286
|
+
.oc-hover-card-content { transition: none; }
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/* ===================================================================
|
|
290
|
+
MENU EXTRAS (dropdown, menubar, context menu): sub-menus, checkbox/radio items, shortcuts, destructive/disabled items
|
|
291
|
+
Sub-menu: .oc-dropdown-sub > button.oc-dropdown-item + .oc-dropdown-submenu (opens on hover and focus-within)
|
|
292
|
+
Check/radio: .oc-dropdown-item + role="menuitemcheckbox|menuitemradio" + aria-checked="true|false"
|
|
293
|
+
=================================================================== */
|
|
294
|
+
.oc-dropdown-item { position: relative; }
|
|
295
|
+
.oc-dropdown-menu[popover] { overflow: visible; } /* the sub-menus are positioned outside the panel */
|
|
296
|
+
.oc-dropdown-shortcut { margin-inline-start: auto; padding-inline-start: 1.5rem; font-size: 0.7rem; letter-spacing: 0.06em; color: var(--oc-muted-foreground); }
|
|
297
|
+
.oc-dropdown-item[aria-disabled="true"],
|
|
298
|
+
.oc-dropdown-item:disabled { opacity: 0.5; pointer-events: none; }
|
|
299
|
+
.oc-dropdown-item--destructive { color: var(--oc-destructive); }
|
|
300
|
+
.oc-dropdown-item--destructive:hover { background: oklch(from var(--oc-destructive) l c h / 0.12); color: var(--oc-destructive); }
|
|
301
|
+
.oc-dropdown-item--inset,
|
|
302
|
+
.oc-dropdown-item[role="menuitemcheckbox"],
|
|
303
|
+
.oc-dropdown-item[role="menuitemradio"] { padding-inline-start: 2rem; }
|
|
304
|
+
.oc-dropdown-item[role="menuitemcheckbox"]::before,
|
|
305
|
+
.oc-dropdown-item[role="menuitemradio"]::before {
|
|
306
|
+
content: "";
|
|
307
|
+
position: absolute;
|
|
308
|
+
inset-inline-start: 0.7rem;
|
|
309
|
+
inset-block-start: 50%;
|
|
310
|
+
inline-size: 0.75rem;
|
|
311
|
+
block-size: 0.75rem;
|
|
312
|
+
translate: 0 -50%;
|
|
313
|
+
opacity: 0;
|
|
314
|
+
}
|
|
315
|
+
.oc-dropdown-item[role="menuitemcheckbox"]::before {
|
|
316
|
+
inline-size: 0.35rem;
|
|
317
|
+
block-size: 0.65rem;
|
|
318
|
+
margin-inline-start: 0.12rem;
|
|
319
|
+
border-inline-end: 2px solid currentColor;
|
|
320
|
+
border-block-end: 2px solid currentColor;
|
|
321
|
+
translate: 0 -62%;
|
|
322
|
+
rotate: 45deg;
|
|
323
|
+
}
|
|
324
|
+
.oc-dropdown-item[role="menuitemradio"]::before { inline-size: 0.45rem; block-size: 0.45rem; margin-inline-start: 0.15rem; border-radius: 50%; background: currentColor; }
|
|
325
|
+
.oc-dropdown-item[aria-checked="true"]::before { opacity: 1; }
|
|
326
|
+
|
|
327
|
+
.oc-dropdown-sub { position: relative; }
|
|
328
|
+
.oc-dropdown-sub > .oc-dropdown-item::after {
|
|
329
|
+
content: "";
|
|
330
|
+
margin-inline-start: auto;
|
|
331
|
+
inline-size: 0.4rem;
|
|
332
|
+
block-size: 0.4rem;
|
|
333
|
+
border-inline-end: 2px solid currentColor;
|
|
334
|
+
border-block-start: 2px solid currentColor;
|
|
335
|
+
rotate: 45deg;
|
|
336
|
+
opacity: 0.7;
|
|
337
|
+
}
|
|
338
|
+
.oc-dropdown-submenu {
|
|
339
|
+
position: absolute;
|
|
340
|
+
inset-block-start: -5px;
|
|
341
|
+
inset-inline-start: calc(100% + 2px);
|
|
342
|
+
z-index: 1;
|
|
343
|
+
min-inline-size: 11rem;
|
|
344
|
+
padding: 4px;
|
|
345
|
+
background: var(--oc-popover);
|
|
346
|
+
color: var(--oc-popover-foreground);
|
|
347
|
+
border: 1px solid var(--oc-border);
|
|
348
|
+
border-radius: var(--oc-radius);
|
|
349
|
+
box-shadow: 0 8px 24px oklch(from var(--color-black-60) l c h / 0.15);
|
|
350
|
+
visibility: hidden;
|
|
351
|
+
opacity: 0;
|
|
352
|
+
translate: -4px 0;
|
|
353
|
+
transition: opacity var(--oc-transition-fast), translate var(--oc-transition-fast), visibility 0s var(--oc-transition-fast);
|
|
354
|
+
}
|
|
355
|
+
.oc-dropdown-sub:hover > .oc-dropdown-submenu,
|
|
356
|
+
.oc-dropdown-sub:focus-within > .oc-dropdown-submenu { visibility: visible; opacity: 1; translate: 0 0; transition-delay: 0s; }
|
|
357
|
+
.oc-dropdown-sub:hover > .oc-dropdown-item,
|
|
358
|
+
.oc-dropdown-sub:focus-within > .oc-dropdown-item { background: var(--oc-accent); }
|
|
359
|
+
|
|
360
|
+
/* ===================================================================
|
|
361
|
+
MENUBAR — horizontal bar of menus. Each trigger is a button with popovertarget; each menu is a
|
|
362
|
+
<div class="oc-dropdown-menu" popover> (so sub-menus, check items and shortcuts work unchanged).
|
|
363
|
+
=================================================================== */
|
|
364
|
+
.oc-menubar {
|
|
365
|
+
display: inline-flex;
|
|
366
|
+
align-items: center;
|
|
367
|
+
gap: 0.25rem;
|
|
368
|
+
padding: 0.25rem;
|
|
369
|
+
background: var(--oc-background);
|
|
370
|
+
border: 1px solid var(--oc-border);
|
|
371
|
+
border-radius: calc(var(--oc-radius) + 2px);
|
|
372
|
+
}
|
|
373
|
+
.oc-menubar-trigger {
|
|
374
|
+
padding: 0.3rem 0.7rem;
|
|
375
|
+
font-family: inherit;
|
|
376
|
+
font-size: 0.875rem;
|
|
377
|
+
font-weight: 500;
|
|
378
|
+
line-height: 1.4;
|
|
379
|
+
color: var(--oc-foreground);
|
|
380
|
+
background: transparent;
|
|
381
|
+
border: 0;
|
|
382
|
+
border-radius: calc(var(--oc-radius) - 2px);
|
|
383
|
+
cursor: pointer;
|
|
384
|
+
}
|
|
385
|
+
.oc-menubar-trigger:hover,
|
|
386
|
+
.oc-menubar-trigger:focus-visible,
|
|
387
|
+
.oc-menubar-trigger[aria-expanded="true"],
|
|
388
|
+
.oc-menubar-trigger:has(+ :popover-open),
|
|
389
|
+
.oc-menubar-trigger:popover-open { background: var(--oc-accent); outline: none; }
|
|
390
|
+
.oc-menubar-trigger:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
|
|
391
|
+
|
|
392
|
+
/* ===================================================================
|
|
393
|
+
CONTEXT MENU — a dropdown menu opened at the pointer. Markup: <div class="oc-dropdown-menu oc-context-menu" popover role="menu">.
|
|
394
|
+
Optional script (documented): on `contextmenu` call preventDefault(), set --oc-context-x / --oc-context-y, then showPopover().
|
|
395
|
+
Area: .oc-context-area gives the right-click target a dashed "drop zone" look.
|
|
396
|
+
=================================================================== */
|
|
397
|
+
.oc-dropdown-menu.oc-context-menu[popover] {
|
|
398
|
+
position: fixed;
|
|
399
|
+
position-area: none;
|
|
400
|
+
position-try-fallbacks: none;
|
|
401
|
+
inset: var(--oc-context-y, 0px) auto auto var(--oc-context-x, 0px);
|
|
402
|
+
margin: 0;
|
|
403
|
+
}
|
|
404
|
+
.oc-context-area {
|
|
405
|
+
display: grid;
|
|
406
|
+
place-items: center;
|
|
407
|
+
min-block-size: 8rem;
|
|
408
|
+
padding: 1rem;
|
|
409
|
+
font-size: 0.875rem;
|
|
410
|
+
color: var(--oc-muted-foreground);
|
|
411
|
+
border: 1px dashed var(--oc-border-strong);
|
|
412
|
+
border-radius: var(--oc-radius);
|
|
413
|
+
user-select: none;
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/* ===================================================================
|
|
417
|
+
CAROUSEL — CSS scroll-snap track. Where supported (Chromium 135+) the browser draws ::scroll-button() arrows and
|
|
418
|
+
::scroll-marker dots; elsewhere .oc-carousel-dots (anchor links) are the fallback. No JavaScript.
|
|
419
|
+
Markup: .oc-carousel > .oc-carousel-viewport (tabindex=0, role=region) > .oc-carousel-item + optional .oc-carousel-dots
|
|
420
|
+
Modifiers: --thirds (3 per view) · --halves (2 per view) · --vertical is not supported (use a list).
|
|
421
|
+
=================================================================== */
|
|
422
|
+
.oc-carousel { position: relative; anchor-scope: --oc-carousel; }
|
|
423
|
+
.oc-carousel-viewport {
|
|
424
|
+
anchor-name: --oc-carousel;
|
|
425
|
+
display: flex;
|
|
426
|
+
gap: 1rem;
|
|
427
|
+
overflow-x: auto;
|
|
428
|
+
overscroll-behavior-x: contain;
|
|
429
|
+
scroll-snap-type: x mandatory;
|
|
430
|
+
scrollbar-width: none;
|
|
431
|
+
border-radius: var(--oc-radius);
|
|
432
|
+
}
|
|
433
|
+
.oc-carousel-viewport::-webkit-scrollbar { display: none; }
|
|
434
|
+
.oc-carousel-viewport:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
435
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
436
|
+
.oc-carousel-viewport { scroll-behavior: smooth; }
|
|
437
|
+
}
|
|
438
|
+
.oc-carousel-item { flex: 0 0 100%; min-inline-size: 0; scroll-snap-align: center; }
|
|
439
|
+
.oc-carousel--halves .oc-carousel-item { flex-basis: calc((100% - 1rem) / 2); }
|
|
440
|
+
.oc-carousel--thirds .oc-carousel-item { flex-basis: calc((100% - 2rem) / 3); }
|
|
441
|
+
.oc-carousel-dots { display: flex; justify-content: center; gap: 0.5rem; padding-block-start: 0.75rem; }
|
|
442
|
+
.oc-carousel-dot {
|
|
443
|
+
inline-size: 0.5rem;
|
|
444
|
+
block-size: 0.5rem;
|
|
445
|
+
border-radius: 50%;
|
|
446
|
+
background: var(--oc-border-strong);
|
|
447
|
+
transition: background var(--oc-transition-fast);
|
|
448
|
+
}
|
|
449
|
+
.oc-carousel-dot:hover,
|
|
450
|
+
.oc-carousel-dot:focus-visible { background: var(--oc-primary); }
|
|
451
|
+
@supports (scroll-marker-group: after) {
|
|
452
|
+
.oc-carousel-dots { display: none; }
|
|
453
|
+
.oc-carousel-viewport { scroll-marker-group: after; }
|
|
454
|
+
.oc-carousel { padding-block-end: 1.5rem; }
|
|
455
|
+
.oc-carousel-viewport::scroll-marker-group {
|
|
456
|
+
position: fixed;
|
|
457
|
+
position-anchor: --oc-carousel;
|
|
458
|
+
inset-inline-start: anchor(start);
|
|
459
|
+
inset-block-start: calc(anchor(end) + 0.5rem);
|
|
460
|
+
inline-size: anchor-size(inline);
|
|
461
|
+
display: flex;
|
|
462
|
+
justify-content: center;
|
|
463
|
+
gap: 0.5rem;
|
|
464
|
+
}
|
|
465
|
+
.oc-carousel-item::scroll-marker {
|
|
466
|
+
content: "";
|
|
467
|
+
inline-size: 0.5rem;
|
|
468
|
+
block-size: 0.5rem;
|
|
469
|
+
border-radius: 999px;
|
|
470
|
+
background: var(--oc-border-strong);
|
|
471
|
+
transition: inline-size var(--oc-transition-fast), background var(--oc-transition-fast);
|
|
472
|
+
}
|
|
473
|
+
.oc-carousel-item::scroll-marker:target-current { inline-size: 1.25rem; background: var(--oc-primary); }
|
|
474
|
+
.oc-carousel-item::scroll-marker:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
475
|
+
}
|
|
476
|
+
@supports selector(::scroll-button(inline-start)) {
|
|
477
|
+
.oc-carousel-viewport::scroll-button(inline-start),
|
|
478
|
+
.oc-carousel-viewport::scroll-button(inline-end) {
|
|
479
|
+
position: fixed;
|
|
480
|
+
position-anchor: --oc-carousel;
|
|
481
|
+
inset-block-start: anchor(center);
|
|
482
|
+
translate: 0 -50%;
|
|
483
|
+
inline-size: 2.25rem;
|
|
484
|
+
block-size: 2.25rem;
|
|
485
|
+
display: grid;
|
|
486
|
+
place-items: center;
|
|
487
|
+
padding: 0;
|
|
488
|
+
font-size: 1rem;
|
|
489
|
+
color: var(--oc-foreground);
|
|
490
|
+
background: var(--oc-background);
|
|
491
|
+
border: 1px solid var(--oc-border);
|
|
492
|
+
border-radius: 50%;
|
|
493
|
+
box-shadow: 0 2px 8px oklch(from var(--color-black-60) l c h / 0.18);
|
|
494
|
+
cursor: pointer;
|
|
495
|
+
}
|
|
496
|
+
.oc-carousel-viewport::scroll-button(inline-start) { content: "\2190" / "Previous slide"; inset-inline-start: calc(anchor(start) + 0.5rem); }
|
|
497
|
+
.oc-carousel-viewport::scroll-button(inline-end) { content: "\2192" / "Next slide"; inset-inline-end: calc(anchor(end) + 0.5rem); }
|
|
498
|
+
.oc-carousel-viewport::scroll-button(inline-start):hover,
|
|
499
|
+
.oc-carousel-viewport::scroll-button(inline-end):hover { background: var(--oc-accent); }
|
|
500
|
+
.oc-carousel-viewport::scroll-button(inline-start):focus-visible,
|
|
501
|
+
.oc-carousel-viewport::scroll-button(inline-end):focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
502
|
+
.oc-carousel-viewport::scroll-button(inline-start):disabled,
|
|
503
|
+
.oc-carousel-viewport::scroll-button(inline-end):disabled { opacity: 0.35; cursor: default; }
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
/* ===================================================================
|
|
507
|
+
RESIZABLE — split panes using the native CSS `resize` property (drag the grip in the corner of the resizable panel).
|
|
508
|
+
A full-length drag handle between panes with keyboard support needs script: wrapper responsibility.
|
|
509
|
+
Markup: .oc-resizable > .oc-resizable-panel.oc-resizable-panel--resizable + .oc-resizable-panel. Modifier: --vertical.
|
|
510
|
+
=================================================================== */
|
|
511
|
+
.oc-resizable {
|
|
512
|
+
display: flex;
|
|
513
|
+
min-block-size: 10rem;
|
|
514
|
+
overflow: hidden;
|
|
515
|
+
font-size: 0.875rem;
|
|
516
|
+
background: var(--oc-card);
|
|
517
|
+
border: 1px solid var(--oc-border);
|
|
518
|
+
border-radius: var(--oc-radius);
|
|
519
|
+
}
|
|
520
|
+
.oc-resizable-panel { flex: 1 1 0; min-inline-size: 0; min-block-size: 0; padding: 1rem; overflow: auto; }
|
|
521
|
+
.oc-resizable-panel--resizable {
|
|
522
|
+
flex: 0 0 auto;
|
|
523
|
+
inline-size: 50%;
|
|
524
|
+
min-inline-size: 5rem;
|
|
525
|
+
max-inline-size: calc(100% - 5rem);
|
|
526
|
+
resize: horizontal;
|
|
527
|
+
border-inline-end: 1px solid var(--oc-border-strong);
|
|
528
|
+
}
|
|
529
|
+
.oc-resizable-panel--resizable::-webkit-resizer { background: linear-gradient(135deg, transparent 50%, var(--oc-border-strong) 50% 56%, transparent 56% 70%, var(--oc-border-strong) 70% 76%, transparent 76%); }
|
|
530
|
+
.oc-resizable--vertical { flex-direction: column; }
|
|
531
|
+
.oc-resizable--vertical > .oc-resizable-panel--resizable {
|
|
532
|
+
inline-size: auto;
|
|
533
|
+
min-inline-size: 0;
|
|
534
|
+
max-inline-size: none;
|
|
535
|
+
block-size: 50%;
|
|
536
|
+
min-block-size: 3rem;
|
|
537
|
+
max-block-size: calc(100% - 3rem);
|
|
538
|
+
resize: vertical;
|
|
539
|
+
border-inline-end: 0;
|
|
540
|
+
border-block-end: 1px solid var(--oc-border-strong);
|
|
541
|
+
}
|
|
542
|
+
.oc-resizable-box { resize: both; overflow: auto; min-inline-size: 8rem; min-block-size: 4rem; max-inline-size: 100%; }
|
|
543
|
+
|
|
544
|
+
/* ===================================================================
|
|
545
|
+
COMBOBOX — input + listbox. CSS gives the look and opens the list while the wrapper has focus (or [data-open]).
|
|
546
|
+
The wrapper script owns: filtering, aria-activedescendant, aria-selected, writing the chosen value into the input.
|
|
547
|
+
Markup: .oc-combobox > input.oc-combobox-input[role=combobox] + ul.oc-combobox-list[role=listbox] > li.oc-combobox-option[role=option][tabindex=-1]
|
|
548
|
+
=================================================================== */
|
|
549
|
+
.oc-combobox { position: relative; display: inline-block; inline-size: min(100%, 18rem); }
|
|
550
|
+
.oc-combobox-input { padding-inline-end: 2.25rem; }
|
|
551
|
+
.oc-combobox::after {
|
|
552
|
+
content: "";
|
|
553
|
+
position: absolute;
|
|
554
|
+
inset-block-start: 1.05rem;
|
|
555
|
+
inset-inline-end: 0.9rem;
|
|
556
|
+
inline-size: 0.4rem;
|
|
557
|
+
block-size: 0.4rem;
|
|
558
|
+
border-inline-end: 2px solid var(--oc-muted-foreground);
|
|
559
|
+
border-block-end: 2px solid var(--oc-muted-foreground);
|
|
560
|
+
rotate: 45deg;
|
|
561
|
+
pointer-events: none;
|
|
562
|
+
transition: rotate var(--oc-transition-fast);
|
|
563
|
+
}
|
|
564
|
+
.oc-combobox:focus-within::after,
|
|
565
|
+
.oc-combobox[data-open]::after { rotate: 225deg; translate: 0 3px; }
|
|
566
|
+
.oc-combobox-list {
|
|
567
|
+
position: absolute;
|
|
568
|
+
inset-inline: 0;
|
|
569
|
+
inset-block-start: calc(100% + 4px);
|
|
570
|
+
z-index: 100;
|
|
571
|
+
max-block-size: 15rem;
|
|
572
|
+
margin: 0;
|
|
573
|
+
padding: 4px;
|
|
574
|
+
overflow-y: auto;
|
|
575
|
+
list-style: none;
|
|
576
|
+
font-size: 0.875rem;
|
|
577
|
+
color: var(--oc-popover-foreground);
|
|
578
|
+
background: var(--oc-popover);
|
|
579
|
+
border: 1px solid var(--oc-border);
|
|
580
|
+
border-radius: var(--oc-radius);
|
|
581
|
+
box-shadow: 0 8px 24px oklch(from var(--color-black-60) l c h / 0.15);
|
|
582
|
+
visibility: hidden;
|
|
583
|
+
opacity: 0;
|
|
584
|
+
translate: 0 -4px;
|
|
585
|
+
transition: opacity var(--oc-transition-fast), translate var(--oc-transition-fast), visibility 0s var(--oc-transition-fast);
|
|
586
|
+
}
|
|
587
|
+
.oc-combobox:focus-within > .oc-combobox-list,
|
|
588
|
+
.oc-combobox[data-open] > .oc-combobox-list { visibility: visible; opacity: 1; translate: 0 0; transition-delay: 0s; }
|
|
589
|
+
.oc-combobox[data-open="false"] > .oc-combobox-list { visibility: hidden; opacity: 0; }
|
|
590
|
+
.oc-combobox-option {
|
|
591
|
+
display: flex;
|
|
592
|
+
align-items: center;
|
|
593
|
+
justify-content: space-between;
|
|
594
|
+
gap: 0.5rem;
|
|
595
|
+
padding: 0.45rem 0.625rem;
|
|
596
|
+
border-radius: calc(var(--oc-radius) - 2px);
|
|
597
|
+
cursor: pointer;
|
|
598
|
+
outline: none;
|
|
599
|
+
}
|
|
600
|
+
.oc-combobox-option:hover,
|
|
601
|
+
.oc-combobox-option:focus-visible,
|
|
602
|
+
.oc-combobox-option[data-active] { background: var(--oc-accent); color: var(--oc-accent-foreground); }
|
|
603
|
+
.oc-combobox-option[aria-selected="true"]::after {
|
|
604
|
+
content: "";
|
|
605
|
+
inline-size: 0.35rem;
|
|
606
|
+
block-size: 0.65rem;
|
|
607
|
+
border-inline-end: 2px solid currentColor;
|
|
608
|
+
border-block-end: 2px solid currentColor;
|
|
609
|
+
rotate: 45deg;
|
|
610
|
+
margin-inline-end: 0.2rem;
|
|
611
|
+
}
|
|
612
|
+
.oc-combobox-option[aria-disabled="true"] { opacity: 0.5; pointer-events: none; }
|
|
613
|
+
.oc-combobox-option[hidden],
|
|
614
|
+
.oc-combobox-empty[hidden] { display: none; }
|
|
615
|
+
.oc-combobox-group { padding: 0.5rem 0.625rem 0.25rem; font-size: 0.7rem; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--oc-muted-foreground); }
|
|
616
|
+
.oc-combobox-empty { padding: 1rem; text-align: center; color: var(--oc-muted-foreground); }
|
|
617
|
+
|
|
618
|
+
/* ===================================================================
|
|
619
|
+
DRAWER — bottom sheet on <dialog> with a drag-handle look. Open: <button command="show-modal" commandfor="id">.
|
|
620
|
+
Dismiss: command="close", Esc or closedby="any" (tap outside). Swipe-to-dismiss is not built in (needs script).
|
|
621
|
+
=================================================================== */
|
|
622
|
+
dialog.oc-drawer {
|
|
623
|
+
display: none;
|
|
624
|
+
inline-size: 100%;
|
|
625
|
+
block-size: 100%;
|
|
626
|
+
max-inline-size: none;
|
|
627
|
+
max-block-size: none;
|
|
628
|
+
margin: 0;
|
|
629
|
+
padding: 0;
|
|
630
|
+
border: 0;
|
|
631
|
+
background: transparent;
|
|
632
|
+
color: var(--oc-foreground);
|
|
633
|
+
}
|
|
634
|
+
dialog.oc-drawer[open] { display: flex; align-items: flex-end; justify-content: center; }
|
|
635
|
+
dialog.oc-drawer::backdrop { background: oklch(from var(--color-black-60) l c h / 0.5); backdrop-filter: blur(4px); }
|
|
636
|
+
.oc-drawer-content {
|
|
637
|
+
display: flex;
|
|
638
|
+
flex-direction: column;
|
|
639
|
+
inline-size: min(100%, 32rem);
|
|
640
|
+
max-block-size: 85dvh;
|
|
641
|
+
background: var(--oc-background);
|
|
642
|
+
border: 1px solid var(--oc-border);
|
|
643
|
+
border-block-end: 0;
|
|
644
|
+
border-radius: calc(var(--oc-radius) * 2) calc(var(--oc-radius) * 2) 0 0;
|
|
645
|
+
box-shadow: 0 -16px 48px oklch(from var(--color-black-60) l c h / 0.2);
|
|
646
|
+
}
|
|
647
|
+
dialog.oc-drawer[open] .oc-drawer-content {
|
|
648
|
+
transition: translate var(--oc-transition-normal), opacity var(--oc-transition-normal);
|
|
649
|
+
@starting-style { translate: 0 100%; opacity: 0; }
|
|
650
|
+
}
|
|
651
|
+
.oc-drawer-handle { flex: none; inline-size: 3rem; block-size: 0.3rem; margin: 0.625rem auto 0; background: var(--oc-border-strong); border-radius: 999px; }
|
|
652
|
+
.oc-drawer-header { display: flex; flex-direction: column; gap: 0.25rem; padding: 1rem 1.5rem 0; text-align: center; }
|
|
653
|
+
.oc-drawer-title { margin: 0; font-size: 1.05rem; font-weight: 600; color: var(--oc-foreground); }
|
|
654
|
+
.oc-drawer-description { margin: 0; font-size: 0.875rem; color: var(--oc-muted-foreground); }
|
|
655
|
+
.oc-drawer-body { flex: 1; min-block-size: 0; padding: 1rem 1.5rem; overflow-y: auto; font-size: 0.875rem; }
|
|
656
|
+
.oc-drawer-footer { display: flex; flex-direction: column; gap: 0.5rem; padding: 1rem 1.5rem 1.5rem; }
|
|
657
|
+
@media (min-width: 40rem) {
|
|
658
|
+
dialog.oc-drawer--center[open] { align-items: center; }
|
|
659
|
+
dialog.oc-drawer--center .oc-drawer-content { border-block-end: 1px solid var(--oc-border); border-radius: calc(var(--oc-radius) * 2); }
|
|
660
|
+
dialog.oc-drawer--center .oc-drawer-handle { display: none; }
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
/* ===================================================================
|
|
664
|
+
NATIVE SELECT — the real <select>. .oc-select (components.css) styles the closed control everywhere.
|
|
665
|
+
Add .oc-select--custom where `appearance: base-select` exists to also style the picker popup (rounded, themed, checkmark).
|
|
666
|
+
=================================================================== */
|
|
667
|
+
@supports (appearance: base-select) {
|
|
668
|
+
.oc-select--custom,
|
|
669
|
+
.oc-select--custom::picker(select) { appearance: base-select; }
|
|
670
|
+
.oc-select--custom { background-image: none; padding-inline-end: 0.75rem; align-items: center; }
|
|
671
|
+
.oc-select--custom::picker-icon { color: var(--oc-muted-foreground); transition: rotate var(--oc-transition-fast); }
|
|
672
|
+
.oc-select--custom:open::picker-icon { rotate: 180deg; }
|
|
673
|
+
.oc-select--custom::picker(select) {
|
|
674
|
+
padding: 4px;
|
|
675
|
+
margin-block: 4px;
|
|
676
|
+
color: var(--oc-popover-foreground);
|
|
677
|
+
background: var(--oc-popover);
|
|
678
|
+
border: 1px solid var(--oc-border);
|
|
679
|
+
border-radius: var(--oc-radius);
|
|
680
|
+
box-shadow: 0 8px 24px oklch(from var(--color-black-60) l c h / 0.15);
|
|
681
|
+
transition: opacity var(--oc-transition-fast), display var(--oc-transition-fast) allow-discrete, overlay var(--oc-transition-fast) allow-discrete;
|
|
682
|
+
}
|
|
683
|
+
.oc-select--custom:open::picker(select) { opacity: 1; @starting-style { opacity: 0; } }
|
|
684
|
+
.oc-select--custom option { display: flex; align-items: center; gap: 0.5rem; padding: 0.45rem 0.625rem; border-radius: calc(var(--oc-radius) - 2px); }
|
|
685
|
+
.oc-select--custom option:hover,
|
|
686
|
+
.oc-select--custom option:focus-visible { background: var(--oc-accent); color: var(--oc-accent-foreground); outline: none; }
|
|
687
|
+
.oc-select--custom option:checked { font-weight: 600; }
|
|
688
|
+
.oc-select--custom option::checkmark { order: 1; margin-inline-start: auto; color: var(--oc-primary); }
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/* ===================================================================
|
|
692
|
+
TOAST STACK — stacked toasts (newest in front, older ones peek out above). Hover or focus expands the stack.
|
|
693
|
+
Add .oc-toast-container--stack to .oc-toast-container; put the NEWEST toast LAST. Up to 4 visible layers.
|
|
694
|
+
=================================================================== */
|
|
695
|
+
.oc-toast-container--stack { display: grid; align-items: end; gap: 0; padding-block-start: 1.5rem; pointer-events: none; }
|
|
696
|
+
.oc-toast-container--stack > .oc-toast {
|
|
697
|
+
--oc-stack-depth: 0;
|
|
698
|
+
grid-area: 1 / 1;
|
|
699
|
+
transform-origin: 50% 100%;
|
|
700
|
+
translate: 0 calc(var(--oc-stack-depth) * -0.7rem);
|
|
701
|
+
scale: calc(1 - var(--oc-stack-depth) * 0.05);
|
|
702
|
+
opacity: calc(1 - var(--oc-stack-depth) * 0.25);
|
|
703
|
+
z-index: calc(10 - var(--oc-stack-depth));
|
|
704
|
+
transition: translate var(--oc-transition-normal), scale var(--oc-transition-normal), opacity var(--oc-transition-normal);
|
|
705
|
+
}
|
|
706
|
+
.oc-toast-container--stack > .oc-toast:nth-last-child(2) { --oc-stack-depth: 1; }
|
|
707
|
+
.oc-toast-container--stack > .oc-toast:nth-last-child(3) { --oc-stack-depth: 2; }
|
|
708
|
+
.oc-toast-container--stack > .oc-toast:nth-last-child(4) { --oc-stack-depth: 3; }
|
|
709
|
+
.oc-toast-container--stack > .oc-toast:nth-last-child(n + 5) { --oc-stack-depth: 4; opacity: 0; visibility: hidden; }
|
|
710
|
+
.oc-toast-container--stack > .oc-toast:not(:last-child) { pointer-events: none; }
|
|
711
|
+
.oc-toast-container--stack > .oc-toast:not(:last-child) > * { visibility: hidden; }
|
|
712
|
+
.oc-toast-container--stack:hover,
|
|
713
|
+
.oc-toast-container--stack:focus-within { display: flex; flex-direction: column; gap: 0.5rem; pointer-events: auto; }
|
|
714
|
+
.oc-toast-container--stack:hover > .oc-toast,
|
|
715
|
+
.oc-toast-container--stack:focus-within > .oc-toast { translate: none; scale: none; opacity: 1; visibility: visible; pointer-events: auto; }
|
|
716
|
+
.oc-toast-container--stack:hover > .oc-toast > *,
|
|
717
|
+
.oc-toast-container--stack:focus-within > .oc-toast > * { visibility: visible; }
|
|
718
|
+
@media (prefers-reduced-motion: reduce) {
|
|
719
|
+
.oc-toast-container--stack > .oc-toast { transition: none; }
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
/* ===================================================================
|
|
723
|
+
CALENDAR — month view markup (table role="grid") styled as a calendar. Markup only: the month math and selection
|
|
724
|
+
state (aria-selected, --range-*) come from your code; a native <input type="date"> remains the zero-JS option.
|
|
725
|
+
Parts: -header · -title · -nav · -grid · -weekday · -day (button) . Day states: [aria-selected=true] · --today · --outside · --range-start/-middle/-end · :disabled
|
|
726
|
+
=================================================================== */
|
|
727
|
+
.oc-calendar {
|
|
728
|
+
--oc-calendar-cell: 2.25rem;
|
|
729
|
+
display: inline-block;
|
|
730
|
+
padding: 0.75rem;
|
|
731
|
+
color: var(--oc-foreground);
|
|
732
|
+
background: var(--oc-card);
|
|
733
|
+
border: 1px solid var(--oc-border);
|
|
734
|
+
border-radius: calc(var(--oc-radius) + 2px);
|
|
735
|
+
}
|
|
736
|
+
.oc-calendar-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-block-end: 0.5rem; }
|
|
737
|
+
.oc-calendar-title { margin: 0; font-size: 0.875rem; font-weight: 600; }
|
|
738
|
+
.oc-calendar-nav {
|
|
739
|
+
display: inline-grid;
|
|
740
|
+
place-items: center;
|
|
741
|
+
inline-size: 1.75rem;
|
|
742
|
+
block-size: 1.75rem;
|
|
743
|
+
padding: 0;
|
|
744
|
+
color: var(--oc-foreground);
|
|
745
|
+
background: transparent;
|
|
746
|
+
border: 1px solid var(--oc-input);
|
|
747
|
+
border-radius: calc(var(--oc-radius) - 2px);
|
|
748
|
+
cursor: pointer;
|
|
749
|
+
}
|
|
750
|
+
.oc-calendar-nav:hover { background: var(--oc-accent); }
|
|
751
|
+
.oc-calendar-nav:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
|
|
752
|
+
.oc-calendar-grid { border-collapse: collapse; table-layout: fixed; }
|
|
753
|
+
.oc-calendar-grid th,
|
|
754
|
+
.oc-calendar-grid td { padding: 0; text-align: center; }
|
|
755
|
+
.oc-calendar-weekday { inline-size: var(--oc-calendar-cell); padding-block-end: 0.25rem; font-size: 0.75rem; font-weight: 500; color: var(--oc-muted-foreground); }
|
|
756
|
+
.oc-calendar-day {
|
|
757
|
+
display: inline-grid;
|
|
758
|
+
place-items: center;
|
|
759
|
+
inline-size: var(--oc-calendar-cell);
|
|
760
|
+
block-size: var(--oc-calendar-cell);
|
|
761
|
+
padding: 0;
|
|
762
|
+
font-family: inherit;
|
|
763
|
+
font-size: 0.875rem;
|
|
764
|
+
font-weight: 400;
|
|
765
|
+
line-height: 1;
|
|
766
|
+
color: var(--oc-foreground);
|
|
767
|
+
background: transparent;
|
|
768
|
+
border: 0;
|
|
769
|
+
border-radius: calc(var(--oc-radius) - 2px);
|
|
770
|
+
cursor: pointer;
|
|
771
|
+
font-variant-numeric: tabular-nums;
|
|
772
|
+
}
|
|
773
|
+
.oc-calendar-day:hover { background: var(--oc-accent); }
|
|
774
|
+
.oc-calendar-day:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
|
|
775
|
+
.oc-calendar-day--today { background: var(--oc-muted); font-weight: 600; }
|
|
776
|
+
.oc-calendar-day--outside { color: var(--oc-muted-foreground); opacity: 0.55; }
|
|
777
|
+
.oc-calendar-day:disabled { opacity: 0.35; pointer-events: none; }
|
|
778
|
+
.oc-calendar-day[aria-selected="true"],
|
|
779
|
+
.oc-calendar-day--range-start,
|
|
780
|
+
.oc-calendar-day--range-end { background: var(--oc-primary); color: var(--oc-primary-foreground); font-weight: 600; opacity: 1; }
|
|
781
|
+
.oc-calendar-day--range-middle { background: color-mix(in oklab, var(--oc-primary) 16%, transparent); border-radius: 0; }
|
|
782
|
+
.oc-calendar-day--range-start { border-start-end-radius: 0; border-end-end-radius: 0; }
|
|
783
|
+
.oc-calendar-day--range-end { border-start-start-radius: 0; border-end-start-radius: 0; }
|
|
784
|
+
|
|
785
|
+
/* ===================================================================
|
|
786
|
+
DATE PICKER — button trigger + popover with a calendar. The popover modifier removes padding so the calendar is the panel.
|
|
787
|
+
Zero-JS alternative: <input class="oc-input" type="date"> (native picker; inherits color-scheme, so it follows the page theme, not the OS).
|
|
788
|
+
=================================================================== */
|
|
789
|
+
.oc-popover--calendar[popover] { inline-size: auto; padding: 0; border: 0; background: transparent; box-shadow: none; }
|
|
790
|
+
.oc-popover--calendar .oc-calendar { box-shadow: 0 8px 24px oklch(from var(--color-black-60) l c h / 0.15); }
|
|
791
|
+
.oc-date-picker-trigger { justify-content: space-between; min-inline-size: 14rem; font-weight: 400; }
|
|
792
|
+
.oc-date-picker-trigger[data-empty] { color: var(--oc-muted-foreground); }
|
|
793
|
+
input.oc-input[type="date"],
|
|
794
|
+
input.oc-input[type="time"],
|
|
795
|
+
input.oc-input[type="datetime-local"],
|
|
796
|
+
input.oc-input[type="month"] { inline-size: auto; min-inline-size: 11rem; }
|
|
797
|
+
|
|
798
|
+
/* ===================================================================
|
|
799
|
+
CHART TOKENS — categorical series colors from the Omnia palette (light-dark). Use as fill/stroke/background.
|
|
800
|
+
Helpers: .oc-chart-legend · .oc-chart-swatch · .oc-chart-bars (+ --oc-bar) · .oc-chart-pie (conic-gradient from inline stops)
|
|
801
|
+
Series: nth-child auto-assigns --oc-chart-color 1..5 on .oc-chart-bars > *, .oc-chart-legend > *.
|
|
802
|
+
=================================================================== */
|
|
803
|
+
:root {
|
|
804
|
+
--oc-chart-1: light-dark(var(--color-vividblue-95), var(--color-vividblue-50));
|
|
805
|
+
--oc-chart-2: light-dark(var(--color-teal-70), var(--color-teal-30));
|
|
806
|
+
--oc-chart-3: light-dark(var(--color-orange-90), var(--color-orange-50));
|
|
807
|
+
--oc-chart-4: light-dark(var(--color-purple-50), var(--color-purple-30));
|
|
808
|
+
--oc-chart-5: light-dark(var(--color-pink-95), var(--color-pink-50));
|
|
809
|
+
--oc-chart-grid: var(--oc-border);
|
|
810
|
+
--oc-chart-axis: var(--oc-muted-foreground);
|
|
811
|
+
}
|
|
812
|
+
.oc-chart-legend { display: flex; flex-wrap: wrap; gap: 0.5rem 1rem; margin: 0; padding: 0; list-style: none; font-size: 0.8125rem; color: var(--oc-muted-foreground); }
|
|
813
|
+
.oc-chart-legend > li { display: inline-flex; align-items: center; gap: 0.4rem; }
|
|
814
|
+
.oc-chart-swatch { inline-size: 0.65rem; block-size: 0.65rem; flex: none; border-radius: 2px; background: var(--oc-chart-color, var(--oc-chart-1)); }
|
|
815
|
+
.oc-chart-legend > :nth-child(1) { --oc-chart-color: var(--oc-chart-1); }
|
|
816
|
+
.oc-chart-legend > :nth-child(2) { --oc-chart-color: var(--oc-chart-2); }
|
|
817
|
+
.oc-chart-legend > :nth-child(3) { --oc-chart-color: var(--oc-chart-3); }
|
|
818
|
+
.oc-chart-legend > :nth-child(4) { --oc-chart-color: var(--oc-chart-4); }
|
|
819
|
+
.oc-chart-legend > :nth-child(5) { --oc-chart-color: var(--oc-chart-5); }
|
|
820
|
+
.oc-chart-bars {
|
|
821
|
+
display: grid;
|
|
822
|
+
grid-auto-flow: column;
|
|
823
|
+
grid-auto-columns: 1fr;
|
|
824
|
+
align-items: end;
|
|
825
|
+
gap: 0.5rem;
|
|
826
|
+
block-size: 10rem;
|
|
827
|
+
margin: 0;
|
|
828
|
+
padding: 0 0 0.25rem;
|
|
829
|
+
list-style: none;
|
|
830
|
+
border-block-end: 1px solid var(--oc-chart-grid);
|
|
831
|
+
background: repeating-linear-gradient(to top, transparent 0 calc(25% - 1px), var(--oc-chart-grid) calc(25% - 1px) 25%);
|
|
832
|
+
}
|
|
833
|
+
.oc-chart-bars > * {
|
|
834
|
+
--oc-bar: 50%;
|
|
835
|
+
block-size: var(--oc-bar);
|
|
836
|
+
background: var(--oc-chart-color, var(--oc-chart-1));
|
|
837
|
+
border-start-start-radius: 4px;
|
|
838
|
+
border-start-end-radius: 4px;
|
|
839
|
+
font-size: 0.7rem;
|
|
840
|
+
text-align: center;
|
|
841
|
+
color: var(--oc-primary-foreground);
|
|
842
|
+
}
|
|
843
|
+
.oc-chart-bars > :nth-child(5n + 1) { --oc-chart-color: var(--oc-chart-1); }
|
|
844
|
+
.oc-chart-bars > :nth-child(5n + 2) { --oc-chart-color: var(--oc-chart-2); }
|
|
845
|
+
.oc-chart-bars > :nth-child(5n + 3) { --oc-chart-color: var(--oc-chart-3); }
|
|
846
|
+
.oc-chart-bars > :nth-child(5n + 4) { --oc-chart-color: var(--oc-chart-4); }
|
|
847
|
+
.oc-chart-bars > :nth-child(5n + 5) { --oc-chart-color: var(--oc-chart-5); }
|
|
848
|
+
.oc-chart-pie { --oc-pie-size: 9rem; inline-size: var(--oc-pie-size); aspect-ratio: 1; border-radius: 50%; background: conic-gradient(var(--oc-chart-1) 0 40%, var(--oc-chart-2) 0 65%, var(--oc-chart-3) 0 82%, var(--oc-chart-4) 0 100%); }
|
|
849
|
+
.oc-chart-pie--donut { mask: radial-gradient(circle, transparent 0 52%, var(--color-black-60) 53%); }
|
|
850
|
+
|
|
851
|
+
/* ===================================================================
|
|
852
|
+
EXTENSIONS OF EXISTING COMPONENTS (registered in the manifest): button-group · label · radio · scroll-area · separator
|
|
853
|
+
=================================================================== */
|
|
854
|
+
.oc-btn-group > .oc-btn:focus-visible { position: relative; z-index: 1; }
|
|
855
|
+
.oc-btn-group--vertical { flex-direction: column; }
|
|
856
|
+
.oc-btn-group--vertical .oc-btn,
|
|
857
|
+
.oc-btn-group--vertical .oc-btn:first-child,
|
|
858
|
+
.oc-btn-group--vertical .oc-btn:last-child { border-radius: 0; }
|
|
859
|
+
.oc-btn-group--vertical .oc-btn:first-child { border-radius: var(--oc-radius) var(--oc-radius) 0 0; }
|
|
860
|
+
.oc-btn-group--vertical .oc-btn:last-child { border-radius: 0 0 var(--oc-radius) var(--oc-radius); }
|
|
861
|
+
.oc-btn-group--vertical .oc-btn + .oc-btn { margin-left: 0; margin-top: -1px; }
|
|
862
|
+
.oc-btn-group-text {
|
|
863
|
+
display: inline-flex;
|
|
864
|
+
align-items: center;
|
|
865
|
+
padding: 0 0.75rem;
|
|
866
|
+
font-size: 0.875rem;
|
|
867
|
+
color: var(--oc-muted-foreground);
|
|
868
|
+
background: var(--oc-muted);
|
|
869
|
+
border: 1px solid var(--oc-input);
|
|
870
|
+
margin-left: -1px;
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
.oc-label--required::after { content: " *"; color: var(--oc-destructive); }
|
|
874
|
+
.oc-label--inline { display: inline-flex; align-items: center; gap: 0.5rem; margin-bottom: 0; cursor: pointer; }
|
|
875
|
+
.oc-label--muted { font-weight: 400; color: var(--oc-muted-foreground); }
|
|
876
|
+
|
|
877
|
+
.oc-radio-group { display: flex; flex-direction: column; gap: 0.625rem; margin: 0; padding: 0; border: 0; }
|
|
878
|
+
.oc-radio-group--row { flex-direction: row; flex-wrap: wrap; gap: 0.625rem 1.25rem; }
|
|
879
|
+
.oc-radio-item { display: flex; align-items: flex-start; gap: 0.625rem; font-size: 0.875rem; color: var(--oc-foreground); cursor: pointer; }
|
|
880
|
+
.oc-radio-item > .oc-radio { flex: none; margin-block-start: 0.15rem; }
|
|
881
|
+
.oc-radio-item small { display: block; font-size: 0.8125rem; color: var(--oc-muted-foreground); }
|
|
882
|
+
.oc-radio-item:has(:disabled) { opacity: 0.55; cursor: not-allowed; }
|
|
883
|
+
.oc-radio-item--card { padding: 0.75rem 1rem; border: 1px solid var(--oc-border); border-radius: var(--oc-radius); }
|
|
884
|
+
.oc-radio-item--card:has(:checked) { border-color: var(--oc-primary); background: color-mix(in oklab, var(--oc-primary) 8%, transparent); }
|
|
885
|
+
.oc-radio-item--card:has(:focus-visible) { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
|
|
886
|
+
|
|
887
|
+
.oc-scroll-area {
|
|
888
|
+
max-block-size: 14rem;
|
|
889
|
+
padding: 0.75rem 1rem;
|
|
890
|
+
overflow: auto;
|
|
891
|
+
font-size: 0.875rem;
|
|
892
|
+
background: var(--oc-card);
|
|
893
|
+
border: 1px solid var(--oc-border);
|
|
894
|
+
border-radius: var(--oc-radius);
|
|
895
|
+
scrollbar-width: thin;
|
|
896
|
+
scrollbar-color: var(--oc-border-strong) transparent;
|
|
897
|
+
}
|
|
898
|
+
.oc-scroll-area:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
899
|
+
.oc-scroll-area--x { max-block-size: none; overflow-y: hidden; white-space: nowrap; }
|
|
900
|
+
/* shadows at the edges that still have content to scroll to (pure CSS, no JavaScript) */
|
|
901
|
+
.oc-scroll-area--shadows {
|
|
902
|
+
--oc-scroll-shadow: oklch(from var(--oc-foreground) l c h / 0.18);
|
|
903
|
+
background:
|
|
904
|
+
linear-gradient(var(--oc-card) 30%, transparent) center top / 100% 2rem no-repeat local,
|
|
905
|
+
linear-gradient(transparent, var(--oc-card) 70%) center bottom / 100% 2rem no-repeat local,
|
|
906
|
+
radial-gradient(farthest-side at 50% 0, var(--oc-scroll-shadow), transparent) center top / 100% 0.6rem no-repeat scroll,
|
|
907
|
+
radial-gradient(farthest-side at 50% 100%, var(--oc-scroll-shadow), transparent) center bottom / 100% 0.6rem no-repeat scroll,
|
|
908
|
+
var(--oc-card);
|
|
909
|
+
}
|
|
910
|
+
|
|
911
|
+
.oc-separator-text { display: flex; align-items: center; gap: 0.75rem; margin: 16px 0; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.06em; color: var(--oc-muted-foreground); }
|
|
912
|
+
.oc-separator-text::before,
|
|
913
|
+
.oc-separator-text::after { content: ""; flex: 1; block-size: 1px; background: var(--oc-border); }
|
|
914
|
+
.oc-separator--strong { background: var(--oc-border-strong); }
|