@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.
Files changed (216) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +20 -2
  3. package/bin/lib/add.mjs +126 -0
  4. package/bin/lib/catalog.mjs +169 -0
  5. package/bin/lib/project.mjs +90 -0
  6. package/bin/omniaui.mjs +70 -0
  7. package/dist/code-block.css +163 -0
  8. package/dist/components-extra.css +914 -0
  9. package/dist/components.css +10081 -0
  10. package/dist/components.min.css +1 -0
  11. package/dist/data-table.d.ts +9 -0
  12. package/dist/data-table.js +505 -0
  13. package/dist/docs-ui.css +265 -0
  14. package/dist/oc-theme.css +69 -0
  15. package/dist/parts/.gitkeep +0 -0
  16. package/dist/parts/app-accordion-accent.css +60 -0
  17. package/dist/parts/app-alpha-tabs.css +68 -0
  18. package/dist/parts/app-busy-overlay.css +25 -0
  19. package/dist/parts/app-column-menu.css +85 -0
  20. package/dist/parts/app-confirm-dialog.css +70 -0
  21. package/dist/parts/app-cookie-consent.css +63 -0
  22. package/dist/parts/app-data-table.css +174 -0
  23. package/dist/parts/app-greeting.css +47 -0
  24. package/dist/parts/app-list-toolbar.css +81 -0
  25. package/dist/parts/app-page-header.css +54 -0
  26. package/dist/parts/app-severity-card.css +91 -0
  27. package/dist/parts/app-sidebar-dark.css +15 -0
  28. package/dist/parts/app-sortable-row.css +52 -0
  29. package/dist/parts/app-stat-card.css +68 -0
  30. package/dist/parts/app-table-actions.css +71 -0
  31. package/dist/parts/app-table-compact.css +54 -0
  32. package/dist/parts/app-top-progress.css +68 -0
  33. package/dist/parts/app-tree.css +104 -0
  34. package/dist/parts/app-upgrade-banner.css +90 -0
  35. package/dist/parts/app-version-banner.css +80 -0
  36. package/dist/parts/data-chart-line.css +167 -0
  37. package/dist/parts/forms-affix-input.css +75 -0
  38. package/dist/parts/forms-barcode-input.css +75 -0
  39. package/dist/parts/forms-chip-filter.css +91 -0
  40. package/dist/parts/forms-color-select.css +89 -0
  41. package/dist/parts/forms-decimal-input.css +51 -0
  42. package/dist/parts/forms-filter-counts.css +94 -0
  43. package/dist/parts/forms-language-select.css +76 -0
  44. package/dist/parts/forms-number-input.css +95 -0
  45. package/dist/parts/forms-password-requirements.css +55 -0
  46. package/dist/parts/forms-phone-input.css +85 -0
  47. package/dist/parts/forms-time-input.css +74 -0
  48. package/dist/parts/forms-toggle-field.css +69 -0
  49. package/dist/parts/media-art.css +21 -0
  50. package/dist/parts/media-attachment.css +160 -0
  51. package/dist/parts/media-browser-frame.css +73 -0
  52. package/dist/parts/media-card.css +83 -0
  53. package/dist/parts/media-chat-composer.css +90 -0
  54. package/dist/parts/media-doc-viewer.css +151 -0
  55. package/dist/parts/media-emoji-picker.css +88 -0
  56. package/dist/parts/media-entity-card.css +52 -0
  57. package/dist/parts/media-flip-card.css +78 -0
  58. package/dist/parts/media-image-zoom.css +68 -0
  59. package/dist/parts/media-lightbox.css +131 -0
  60. package/dist/parts/media-message-thread.css +136 -0
  61. package/dist/parts/media-message.css +160 -0
  62. package/dist/parts/media-row.css +78 -0
  63. package/dist/parts/media-stack-card.css +82 -0
  64. package/dist/parts/media-terminal-log.css +76 -0
  65. package/dist/parts/media-thumb.css +71 -0
  66. package/dist/parts/site-fact-list.css +25 -0
  67. package/dist/parts/site-link-arrow.css +34 -0
  68. package/dist/parts/site-marquee.css +34 -0
  69. package/dist/parts/site-next-teaser.css +75 -0
  70. package/dist/parts/site-price-card.css +75 -0
  71. package/dist/parts/site-product-mark.css +66 -0
  72. package/dist/parts/site-project-card.css +111 -0
  73. package/dist/parts/site-prose.css +124 -0
  74. package/dist/parts/site-stack-list.css +48 -0
  75. package/dist/parts/site-timeline.css +54 -0
  76. package/dist/showcase.css +404 -0
  77. package/manifest.json +1108 -0
  78. package/package.json +67 -4
  79. package/snippets/accordion-accent.html +24 -0
  80. package/snippets/accordion.html +11 -0
  81. package/snippets/affix-input.html +30 -0
  82. package/snippets/alert-dialog.html +22 -0
  83. package/snippets/alert.html +5 -0
  84. package/snippets/alpha-tabs.html +37 -0
  85. package/snippets/aspect-ratio.html +15 -0
  86. package/snippets/attachment.html +43 -0
  87. package/snippets/avatar.html +6 -0
  88. package/snippets/back-link.html +5 -0
  89. package/snippets/badge.html +5 -0
  90. package/snippets/barcode-input.html +18 -0
  91. package/snippets/breadcrumb.html +6 -0
  92. package/snippets/browser-frame.html +18 -0
  93. package/snippets/busy-overlay.html +31 -0
  94. package/snippets/button-group.html +21 -0
  95. package/snippets/button.html +8 -0
  96. package/snippets/calendar.html +43 -0
  97. package/snippets/card.html +17 -0
  98. package/snippets/carousel.html +21 -0
  99. package/snippets/chart-line.html +46 -0
  100. package/snippets/chart.html +27 -0
  101. package/snippets/chat-composer.html +21 -0
  102. package/snippets/checkbox.html +5 -0
  103. package/snippets/checklist.html +23 -0
  104. package/snippets/chip-filter.html +14 -0
  105. package/snippets/code-window.html +20 -0
  106. package/snippets/collapsible.html +19 -0
  107. package/snippets/color-field.html +13 -0
  108. package/snippets/color-select.html +18 -0
  109. package/snippets/column-menu.html +38 -0
  110. package/snippets/combobox.html +19 -0
  111. package/snippets/command.html +24 -0
  112. package/snippets/confirm-dialog.html +32 -0
  113. package/snippets/context-menu.html +25 -0
  114. package/snippets/cookie-consent.html +70 -0
  115. package/snippets/copy-field.html +19 -0
  116. package/snippets/counter.html +2 -0
  117. package/snippets/data-table.html +151 -0
  118. package/snippets/date-picker.html +32 -0
  119. package/snippets/decimal-input.html +20 -0
  120. package/snippets/definition-list.html +20 -0
  121. package/snippets/demo-panel.html +18 -0
  122. package/snippets/doc-viewer.html +58 -0
  123. package/snippets/drawer.html +30 -0
  124. package/snippets/dropdown-menu.html +27 -0
  125. package/snippets/dropdown.html +9 -0
  126. package/snippets/dropzone.html +13 -0
  127. package/snippets/emoji-picker.html +51 -0
  128. package/snippets/empty-state.html +17 -0
  129. package/snippets/entity-card.html +26 -0
  130. package/snippets/expandable-table.html +26 -0
  131. package/snippets/fact-list.html +14 -0
  132. package/snippets/filter-counts.html +30 -0
  133. package/snippets/flip-card.html +22 -0
  134. package/snippets/form-field.html +6 -0
  135. package/snippets/greeting.html +22 -0
  136. package/snippets/heading.html +14 -0
  137. package/snippets/hover-card.html +18 -0
  138. package/snippets/image-zoom.html +30 -0
  139. package/snippets/input-group.html +10 -0
  140. package/snippets/input.html +5 -0
  141. package/snippets/item.html +26 -0
  142. package/snippets/kbd.html +13 -0
  143. package/snippets/label.html +9 -0
  144. package/snippets/language-select.html +26 -0
  145. package/snippets/launcher-card.html +14 -0
  146. package/snippets/lightbox.html +50 -0
  147. package/snippets/link-arrow.html +10 -0
  148. package/snippets/list-toolbar.html +33 -0
  149. package/snippets/marquee.html +15 -0
  150. package/snippets/media-card.html +28 -0
  151. package/snippets/media-row.html +21 -0
  152. package/snippets/media-thumb.html +12 -0
  153. package/snippets/menubar.html +30 -0
  154. package/snippets/message-thread.html +123 -0
  155. package/snippets/message.html +51 -0
  156. package/snippets/modal.html +15 -0
  157. package/snippets/native-select.html +15 -0
  158. package/snippets/navmenu.html +23 -0
  159. package/snippets/next-teaser.html +15 -0
  160. package/snippets/number-input.html +27 -0
  161. package/snippets/otp-input.html +9 -0
  162. package/snippets/page-header.html +24 -0
  163. package/snippets/pagination.html +6 -0
  164. package/snippets/password-input.html +24 -0
  165. package/snippets/password-requirements.html +30 -0
  166. package/snippets/phone-input.html +22 -0
  167. package/snippets/popover.html +15 -0
  168. package/snippets/price-card.html +34 -0
  169. package/snippets/product-mark.html +13 -0
  170. package/snippets/progress.html +4 -0
  171. package/snippets/project-card.html +23 -0
  172. package/snippets/prose.html +54 -0
  173. package/snippets/radio.html +17 -0
  174. package/snippets/recovery-codes.html +20 -0
  175. package/snippets/resizable.html +16 -0
  176. package/snippets/scroll-area.html +20 -0
  177. package/snippets/search.html +8 -0
  178. package/snippets/segmented.html +11 -0
  179. package/snippets/select.html +7 -0
  180. package/snippets/separator.html +15 -0
  181. package/snippets/severity-card.html +35 -0
  182. package/snippets/sheet.html +32 -0
  183. package/snippets/sidebar-docs.html +24 -0
  184. package/snippets/sidebar.html +55 -0
  185. package/snippets/site-footer.html +6 -0
  186. package/snippets/site-header.html +26 -0
  187. package/snippets/skeleton.html +4 -0
  188. package/snippets/slider.html +17 -0
  189. package/snippets/sortable-row.html +31 -0
  190. package/snippets/spinner.html +14 -0
  191. package/snippets/stack-card.html +17 -0
  192. package/snippets/stack-list.html +16 -0
  193. package/snippets/stat-card.html +24 -0
  194. package/snippets/stepper.html +13 -0
  195. package/snippets/switch.html +6 -0
  196. package/snippets/table-actions.html +39 -0
  197. package/snippets/table-compact.html +24 -0
  198. package/snippets/table.html +29 -0
  199. package/snippets/tabs.html +9 -0
  200. package/snippets/tag-input.html +17 -0
  201. package/snippets/terminal-log.html +23 -0
  202. package/snippets/textarea.html +3 -0
  203. package/snippets/theme-switch.html +6 -0
  204. package/snippets/time-input.html +26 -0
  205. package/snippets/timeline.html +28 -0
  206. package/snippets/toast-stack.html +10 -0
  207. package/snippets/toast.html +36 -0
  208. package/snippets/toc.html +13 -0
  209. package/snippets/toggle-field.html +20 -0
  210. package/snippets/toggle.html +22 -0
  211. package/snippets/tooltip.html +4 -0
  212. package/snippets/top-progress.html +12 -0
  213. package/snippets/tree.html +38 -0
  214. package/snippets/upgrade-banner.html +28 -0
  215. package/snippets/user.html +15 -0
  216. package/snippets/version-banner.html +15 -0
@@ -0,0 +1,265 @@
1
+ /* ===================================================================
2
+ DOCS UI — the pieces the OmniaCSS documentation site is built from, offered as components.
3
+ Index: sidebar--docs · toc · topbar (+ navmenu--site) · footerbar · search · demo panel · code-window copy ·
4
+ btn--toggle ("Show more")
5
+ Every color is an --oc-* theme token or an Omnia palette token, so light and dark follow the theme.
6
+ =================================================================== */
7
+
8
+ /* ---- Sidebar, documentation variant: .oc-sidebar.oc-sidebar--docs -------------------------------
9
+ Same parts as the app sidebar (menu, menu-button, menu-sub, group-label) plus .oc-sidebar-title.
10
+ Outlined "pill" items, always-visible sub items, no own scroll (the page shell scrolls it). */
11
+ .oc-sidebar--docs {
12
+ --oc-sidebar-width: auto;
13
+ --oc-sidebar-docs-active: oklch(from var(--oc-primary) l c h / 0.1);
14
+ inline-size: auto;
15
+ block-size: auto;
16
+ background: transparent;
17
+ border: 0;
18
+ gap: 0;
19
+ }
20
+ .oc-sidebar-title { margin: 0 0 0.75rem; font-size: 1rem; font-weight: 600; color: var(--oc-foreground); }
21
+ .oc-sidebar--docs .oc-sidebar-group-label {
22
+ margin: 1rem 0 0.5rem;
23
+ padding: 0;
24
+ font-size: 0.75rem;
25
+ text-transform: uppercase;
26
+ letter-spacing: 0.08em;
27
+ color: var(--oc-muted-foreground);
28
+ }
29
+ .oc-sidebar--docs .oc-sidebar-menu { gap: 6px; }
30
+ .oc-sidebar--docs .oc-sidebar-menu-button {
31
+ display: block;
32
+ padding: 0.5rem 0.625rem;
33
+ border: 1px solid transparent;
34
+ border-radius: 8px;
35
+ }
36
+ .oc-sidebar--docs .oc-sidebar-menu-button:hover {
37
+ color: var(--oc-foreground);
38
+ border-color: var(--oc-border);
39
+ background: oklch(from var(--oc-foreground) l c h / 0.03);
40
+ }
41
+ .oc-sidebar--docs .oc-sidebar-menu-button[aria-current="page"],
42
+ .oc-sidebar--docs .oc-sidebar-menu-button.is-active {
43
+ color: var(--oc-foreground);
44
+ font-weight: 500;
45
+ border-color: var(--oc-primary);
46
+ background: var(--oc-sidebar-docs-active);
47
+ }
48
+ .oc-sidebar--docs .oc-sidebar-menu-sub {
49
+ margin: 4px 0 0 0.625rem;
50
+ padding: 0 0 0 0.625rem;
51
+ gap: 4px;
52
+ border-inline-start: 1px dashed var(--oc-border);
53
+ }
54
+ .oc-sidebar--docs .oc-sidebar-menu-sub .oc-sidebar-menu-button { padding: 0.375rem 0.5rem; font-size: 0.84rem; }
55
+ .oc-sidebar--docs details.oc-sidebar-collapsible > summary { display: flex; }
56
+ /* Docs sidebars never switch to icon-only mode */
57
+ .oc-sidebar--docs.oc-sidebar--collapsed { inline-size: auto; }
58
+
59
+ /* ---- On this page: .oc-toc ---------------------------------------------------------------------- */
60
+ .oc-toc { position: sticky; inset-block-start: 0; max-block-size: 100%; overflow: auto; padding-block-start: 2px; padding-inline-end: 0.5rem; }
61
+ .oc-toc-title { margin: 1rem 0 0.5rem; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--oc-muted-foreground); }
62
+ .oc-toc-list { display: grid; gap: 4px; margin: 0; padding: 0; list-style: none; }
63
+ .oc-toc-link {
64
+ display: block;
65
+ padding: 0.375rem 0.5rem;
66
+ font-size: 0.875rem;
67
+ color: var(--oc-muted-foreground);
68
+ text-decoration: none;
69
+ border: 1px solid transparent;
70
+ border-radius: 8px;
71
+ overflow-wrap: anywhere;
72
+ }
73
+ .oc-toc-link:hover { color: var(--oc-foreground); border-color: var(--oc-border); }
74
+ .oc-toc-link:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
75
+ .oc-toc-link[aria-current],
76
+ .oc-toc-link.is-active { color: var(--oc-foreground); border-color: var(--oc-primary); background: oklch(from var(--oc-primary) l c h / 0.1); }
77
+ /* Scroll-spy without JavaScript: the link of the heading you are reading is highlighted (native :target-current). */
78
+ .oc-toc-list { scroll-target-group: auto; }
79
+ .oc-toc-link:target-current { color: var(--oc-foreground); border-color: var(--oc-primary); background: oklch(from var(--oc-primary) l c h / 0.1); }
80
+ .oc-toc-item--sub { margin-inline-start: 0.75rem; }
81
+ .oc-toc-item--sub .oc-toc-link { font-size: 0.8125rem; }
82
+
83
+ /* ---- Site header: .oc-topbar (+ .oc-navmenu--site) ----------------------------------------------
84
+ Brand · navigation · actions. Tune per site with --ocm-header-height, --ocm-header-bg, --ocm-header-border. */
85
+ .oc-topbar {
86
+ position: relative;
87
+ display: flex;
88
+ align-items: center;
89
+ justify-content: space-between;
90
+ gap: 1rem;
91
+ box-sizing: border-box;
92
+ min-block-size: var(--ocm-header-height, 3.75rem);
93
+ flex-wrap: wrap;
94
+ padding-inline: clamp(14px, 2vw, 28px);
95
+ color: var(--oc-foreground);
96
+ background: var(--ocm-header-bg, oklch(from var(--oc-background) l c h / 0.78));
97
+ border-block-end: 1px solid var(--ocm-header-border, var(--oc-border));
98
+ backdrop-filter: blur(6px);
99
+ }
100
+ .oc-topbar--fixed { position: fixed; inset: 0 0 auto 0; z-index: 1100; }
101
+ .oc-topbar-brand { margin: 0; font-size: 1.1rem; font-weight: 700; letter-spacing: 0.02em; color: inherit; text-decoration: none; white-space: nowrap; }
102
+ .oc-topbar-nav { display: block; }
103
+ .oc-topbar-actions { display: flex; align-items: center; gap: 0.5rem; flex-shrink: 0; margin: 0; }
104
+
105
+ /* Pill style menu (site navigation) */
106
+ .oc-navmenu--site { gap: 8px; }
107
+ .oc-navmenu--site .oc-navmenu-link {
108
+ gap: 4px;
109
+ padding: 0.5rem 0.75rem;
110
+ font-weight: 400;
111
+ border: 1px solid var(--oc-border);
112
+ border-radius: 10px;
113
+ background: oklch(from var(--oc-foreground) l c h / 0.03);
114
+ }
115
+ .oc-navmenu--site .oc-navmenu-link:hover,
116
+ .oc-navmenu--site .oc-navmenu-link[aria-current="page"] {
117
+ color: var(--oc-foreground);
118
+ border-color: var(--oc-primary);
119
+ background: oklch(from var(--oc-foreground) l c h / 0.03);
120
+ }
121
+ .oc-navmenu-icon { inline-size: 1.25rem; block-size: 1.25rem; flex-shrink: 0; }
122
+
123
+ /* CSS-only mobile menu: <input type="checkbox" class="oc-topbar-toggle"> + <label class="oc-topbar-burger"> */
124
+ .oc-topbar-toggle { position: absolute; opacity: 0; pointer-events: none; }
125
+ .oc-topbar-burger {
126
+ display: none;
127
+ align-items: center;
128
+ justify-content: center;
129
+ inline-size: 2.25rem;
130
+ block-size: 2.25rem;
131
+ border: 1px solid var(--oc-border);
132
+ border-radius: var(--oc-radius);
133
+ cursor: pointer;
134
+ color: var(--oc-foreground);
135
+ }
136
+ .oc-topbar-burger:hover { background: var(--oc-accent); }
137
+ .oc-topbar-toggle:focus-visible + .oc-topbar-burger { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
138
+ @media (max-width: 760px) {
139
+ .oc-topbar { padding-block: 8px; }
140
+ .oc-topbar--collapsible .oc-topbar-burger { display: inline-flex; }
141
+ .oc-topbar--collapsible .oc-topbar-nav { display: none; order: 3; inline-size: 100%; }
142
+ .oc-topbar--collapsible:has(.oc-topbar-toggle:checked) .oc-topbar-nav { display: block; }
143
+ }
144
+
145
+ /* ---- Site footer bar: .oc-footerbar ------------------------------------------------------------- */
146
+ .oc-footerbar {
147
+ display: flex;
148
+ align-items: center;
149
+ justify-content: center;
150
+ gap: 0.25em;
151
+ box-sizing: border-box;
152
+ block-size: var(--ocm-footer-height, 2.25rem);
153
+ padding-inline: clamp(14px, 2vw, 28px);
154
+ font-size: 0.82rem;
155
+ text-align: center;
156
+ color: var(--oc-muted-foreground);
157
+ background: var(--ocm-footer-bg, oklch(from var(--oc-background) l c h / 0.9));
158
+ border-block-start: 1px solid var(--ocm-header-border, var(--oc-border));
159
+ backdrop-filter: blur(6px);
160
+ }
161
+ .oc-footerbar a { color: var(--oc-primary); }
162
+ .oc-footerbar--fixed { position: fixed; inset: auto 0 0 0; z-index: 1000; }
163
+
164
+ /* ---- Search field: .oc-search ------------------------------------------------------------------- */
165
+ .oc-search {
166
+ display: flex;
167
+ align-items: center;
168
+ gap: 0.5rem;
169
+ inline-size: 100%;
170
+ max-inline-size: 20rem;
171
+ padding-inline: 0.625rem;
172
+ color: var(--oc-muted-foreground);
173
+ background: var(--oc-background);
174
+ border: 1px solid var(--oc-border-strong);
175
+ border-radius: var(--oc-radius);
176
+ }
177
+ .oc-search:focus-within { border-color: var(--oc-ring); box-shadow: 0 0 0 2px color-mix(in srgb, var(--oc-ring) 25%, transparent); }
178
+ .oc-search-icon { inline-size: 1rem; block-size: 1rem; flex-shrink: 0; }
179
+ .oc-search-input { flex: 1; min-inline-size: 0; padding-block: 0.5rem; font: inherit; font-size: 0.875rem; color: var(--oc-foreground); background: none; border: 0; outline: 0; }
180
+ .oc-search-input::placeholder { color: var(--oc-muted-foreground); }
181
+ .oc-search-input::-webkit-search-cancel-button { cursor: pointer; }
182
+ .oc-search-hint {
183
+ padding: 0.1rem 0.4rem;
184
+ font: 0.72rem var(--oc-font-mono, ui-monospace, monospace);
185
+ color: var(--oc-muted-foreground);
186
+ border: 1px solid var(--oc-border);
187
+ border-radius: 4px;
188
+ }
189
+ .oc-search:focus-within .oc-search-hint { display: none; }
190
+
191
+ /* ---- Demo panel: .oc-demo -----------------------------------------------------------------------
192
+ "Demo" title -> live preview -> "Code" title -> code block. Variant --tabs shows preview OR code (radio tabs, CSS only). */
193
+ .oc-demo {
194
+ display: flex;
195
+ flex-direction: column;
196
+ gap: 10px;
197
+ margin: 12px 0 20px;
198
+ padding: clamp(12px, 2vw, 20px);
199
+ border: 1px solid var(--oc-border);
200
+ border-radius: 12px;
201
+ background: color-mix(in oklch, light-dark(var(--color-white-50), var(--color-shallowblue-80)) 70%, transparent);
202
+ }
203
+ .oc-demo > .oc-preview__title { margin: 4px 0 0; }
204
+ .oc-demo__preview {
205
+ display: flex;
206
+ flex-wrap: wrap;
207
+ gap: 16px;
208
+ align-items: flex-start;
209
+ padding: clamp(12px, 2vw, 20px);
210
+ border: 1px solid var(--oc-border);
211
+ border-radius: 10px;
212
+ background: var(--oc-background);
213
+ overflow-x: auto;
214
+ }
215
+ .oc-demo__preview > * { min-width: 0; }
216
+ .oc-demo__preview--tall { min-block-size: 20rem; align-items: flex-start; overflow: visible; }
217
+ .oc-demo__preview--center { justify-content: center; align-items: center; }
218
+ .oc-demo .oc-code-block { margin: 0; }
219
+
220
+ .oc-demo__tablist { display: flex; gap: 4px; padding: 3px; inline-size: fit-content; border-radius: calc(var(--oc-radius) + 2px); background: var(--oc-muted); }
221
+ .oc-demo__tab { position: relative; padding: 0.3rem 0.9rem; font-size: 0.8125rem; font-weight: 500; color: var(--oc-muted-foreground); border-radius: var(--oc-radius); cursor: pointer; }
222
+ .oc-demo__tab input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
223
+ .oc-demo__tab:has(input:checked) { color: var(--oc-foreground); background: var(--oc-background); box-shadow: 0 1px 2px oklch(from var(--oc-foreground) l c h / 0.15); }
224
+ .oc-demo__tab:has(input:focus-visible) { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
225
+ .oc-demo--tabs > .oc-demo__code { display: none; }
226
+ .oc-demo--tabs:has(.oc-demo__tab:nth-child(2) input:checked) > .oc-demo__preview { display: none; }
227
+ .oc-demo--tabs:has(.oc-demo__tab:nth-child(2) input:checked) > .oc-demo__code { display: block; }
228
+
229
+ /* ---- Code window + copy button ------------------------------------------------------------------- */
230
+ .oc-code-copy {
231
+ position: absolute;
232
+ inset-block-start: 0.5rem;
233
+ inset-inline-end: 0.5rem;
234
+ padding: 0.25rem 0.625rem;
235
+ font: inherit;
236
+ font-size: 0.75rem;
237
+ color: var(--oc-muted-foreground);
238
+ background: var(--oc-card);
239
+ border: 1px solid var(--oc-border);
240
+ border-radius: calc(var(--oc-radius) - 2px);
241
+ cursor: pointer;
242
+ transition: color var(--oc-transition-fast), border-color var(--oc-transition-fast);
243
+ }
244
+ .oc-code-copy:hover { color: var(--oc-foreground); border-color: var(--oc-border-strong); }
245
+ .oc-code-copy:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
246
+ .oc-code-copy.is-copied { color: var(--oc-success); border-color: currentColor; }
247
+ .oc-code-window:has(.oc-code-copy) { position: relative; }
248
+ .oc-code-window__bar .oc-code-copy { position: static; margin-inline-start: auto; }
249
+
250
+ /* ---- Toggle button ("Show more / Show less"): .oc-btn--toggle ------------------------------------
251
+ <label class="oc-btn oc-btn--outline oc-btn--toggle"><input type="checkbox"> <span class="oc-btn-toggle__off">…</span> <span class="oc-btn-toggle__on">…</span></label>
252
+ Reveal content in the same container with .oc-showmore / .oc-showmore__extra. */
253
+ .oc-btn--toggle { position: relative; }
254
+ .oc-btn--toggle > input { position: absolute; opacity: 0; inset: 0; margin: 0; cursor: pointer; }
255
+ .oc-btn--toggle:has(> input:focus-visible) { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
256
+ .oc-btn--toggle .oc-btn-toggle__on,
257
+ .oc-btn--toggle:has(> input:checked) .oc-btn-toggle__off { display: none; }
258
+ .oc-btn--toggle:has(> input:checked) .oc-btn-toggle__on { display: inline; }
259
+ .oc-showmore__extra { display: none; }
260
+ .oc-showmore:has(.oc-btn--toggle > input:checked) .oc-showmore__extra { display: revert; }
261
+
262
+ /* Wide docs components take the full width of a demo preview */
263
+ .oc-demo__preview > :is(.oc-topbar, .oc-footerbar, .oc-demo, .oc-code-window, .oc-expandable-table, .oc-showmore) { flex: 1 1 100%; }
264
+ /* Marketing pieces that should span the preview stage (timeline, facts, project and price cards). */
265
+ .oc-demo__preview > :is(.oc-timeline, .oc-fact-list, .oc-project-card, .oc-price-card) { inline-size: 100%; }
@@ -0,0 +1,69 @@
1
+ /* File: oc-theme.css — generated from tokens/semantic.json by @birdycom/omniacss 0.11.0. Do not edit. */
2
+ /* Semantic theme tokens: every color is light-dark() of an Omnia palette token (oc-colors.css). */
3
+ /* Same source as the desktop export: npx omniacss tokens --format json|dtcg|python */
4
+ :root {
5
+ color-scheme: light dark;
6
+
7
+ /* Brand */
8
+ --oc-brand-1: light-dark(var(--color-teal-80), var(--color-skycyan-60));
9
+ --oc-brand-2: light-dark(var(--color-blue-40), var(--color-blue-10));
10
+ --oc-brand-3: light-dark(var(--color-purple-40), var(--color-purple-10));
11
+
12
+ /* Core surfaces */
13
+ --oc-background: light-dark(var(--color-frostblue-2), var(--color-shallowblue-95));
14
+ --oc-foreground: light-dark(var(--color-duskblue-60), var(--color-frostblue-10));
15
+ --oc-muted: light-dark(var(--color-frostblue-60), var(--color-shallowblue-50));
16
+ --oc-muted-foreground: light-dark(var(--color-stormblue-40), var(--color-mistblue-70));
17
+ --oc-card: light-dark(var(--color-white-50), var(--color-shallowblue-70));
18
+ --oc-popover: light-dark(var(--color-white-50), var(--color-shallowblue-60));
19
+ --oc-popover-foreground: var(--oc-foreground);
20
+ --oc-surface: light-dark(oklch(from var(--color-stormblue-50) l c h / 0.04), oklch(from var(--color-white-50) l c h / 0.04));
21
+ --oc-surface-strong: light-dark(oklch(from var(--color-stormblue-50) l c h / 0.08), oklch(from var(--color-white-50) l c h / 0.07));
22
+
23
+ /* Semantic accents */
24
+ --oc-primary: light-dark(var(--color-vividblue-95), var(--color-vividblue-100));
25
+ --oc-primary-foreground: light-dark(var(--color-white-50), var(--color-shallowblue-95));
26
+ --oc-secondary: var(--oc-muted);
27
+ --oc-secondary-foreground: var(--oc-foreground);
28
+ --oc-accent: var(--oc-muted);
29
+ --oc-accent-foreground: var(--oc-foreground);
30
+ --oc-destructive: light-dark(var(--color-red-70), var(--color-red-50));
31
+ --oc-destructive-foreground: var(--color-white-50);
32
+ --oc-success: light-dark(var(--color-green-60), var(--color-green-2));
33
+ --oc-success-foreground: light-dark(var(--color-white-50), var(--color-shallowblue-95));
34
+ --oc-warning: light-dark(var(--color-orange-95), var(--color-orange-50));
35
+ --oc-warning-foreground: light-dark(var(--color-white-50), var(--color-shallowblue-95));
36
+
37
+ /* Borders and inputs */
38
+ --oc-border: light-dark(var(--color-frostblue-80), var(--color-duskblue-30));
39
+ --oc-border-strong: light-dark(var(--color-mistblue-80), var(--color-stormblue-30));
40
+ --oc-input: var(--oc-border);
41
+ --oc-ring: var(--oc-primary);
42
+
43
+ /* Interaction states */
44
+ --oc-row-alt: light-dark(var(--color-frostblue-2), var(--color-shallowblue-100));
45
+ --oc-hover: light-dark(var(--color-frostblue-100), var(--color-duskblue-50));
46
+ --oc-pressed: light-dark(var(--color-frostblue-60), var(--color-duskblue-40));
47
+ --oc-selected: light-dark(var(--color-mistblue-2), var(--color-stormblue-60));
48
+ --oc-selected-foreground: var(--oc-foreground);
49
+ --oc-disabled-foreground: light-dark(var(--color-duskblue-2), var(--color-duskblue-10));
50
+
51
+ /* Gradients */
52
+ --oc-gradient-brand: linear-gradient(100deg, var(--oc-brand-1), var(--oc-brand-2) 50%, var(--oc-brand-3));
53
+
54
+ /* Shape, focus, motion, fonts */
55
+ --oc-radius: 0.5rem;
56
+ --oc-focus-width: 2px;
57
+ --oc-transition-fast: 150ms cubic-bezier(0.4, 0, 0.2, 1);
58
+ --oc-transition-normal: 200ms cubic-bezier(0.4, 0, 0.2, 1);
59
+ --oc-font-sans: system-ui, -apple-system, "Segoe UI", Roboto, Cantarell, "Helvetica Neue", sans-serif;
60
+ --oc-font-mono: "Cascadia Code", "JetBrains Mono", Consolas, ui-monospace, monospace;
61
+
62
+ /* Shadows (x y blur spread; color + alpha per mode in --oc-shadow-<name>-color) */
63
+ --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));
64
+ --oc-shadow-sm: 0px 1px 2px 0px var(--oc-shadow-sm-color);
65
+ --oc-shadow-md-color: light-dark(oklch(from var(--color-stormblue-50) l c h / 0.12), oklch(from var(--color-black-50) l c h / 0.5));
66
+ --oc-shadow-md: 0px 4px 12px -2px var(--oc-shadow-md-color);
67
+ --oc-shadow-lg-color: light-dark(oklch(from var(--color-stormblue-50) l c h / 0.16), oklch(from var(--color-black-50) l c h / 0.6));
68
+ --oc-shadow-lg: 0px 12px 32px -6px var(--oc-shadow-lg-color);
69
+ }
File without changes
@@ -0,0 +1,60 @@
1
+ /* File: packages/ui/src/parts/app-accordion-accent.css | Map: accent accordion (separate cards) -> item card + left accent -> trigger -> open state -> color modifiers (presets) -> flush combination */
2
+ /* Accordion accent: every item becomes its own card with a colored accent on the start edge.
3
+ Add .oc-accordion--accent to an .oc-accordion. The color comes from --oc-accordion-accent:
4
+ primary by default, or an existing .oc-accent--* preset (blue, cyan, green, orange, red, violet, yellow)
5
+ on the accordion (all items) or on a single .oc-accordion-item. Works with <details> and the JS hooks. */
6
+
7
+ .oc-accordion--accent {
8
+ --oc-accordion-accent: var(--oc-accent-from, var(--oc-primary));
9
+ display: grid;
10
+ gap: 0.5rem;
11
+ overflow: visible;
12
+ border: 0;
13
+ border-radius: 0;
14
+ }
15
+
16
+ /* Each item is a card; the accent is a 3px start border in the item color. */
17
+ .oc-accordion--accent .oc-accordion-item {
18
+ --oc-accordion-accent: var(--oc-accent-from, var(--oc-primary));
19
+ overflow: hidden;
20
+ background: var(--oc-card);
21
+ border: 1px solid var(--oc-border);
22
+ border-inline-start: 3px solid var(--oc-accordion-accent);
23
+ border-radius: var(--oc-radius);
24
+ transition: border-color var(--oc-transition-fast), box-shadow var(--oc-transition-fast);
25
+ }
26
+ /* The base accordion draws a line between items; cards do not need it. */
27
+ .oc-accordion--accent .oc-accordion-item + .oc-accordion-item { border-top: 1px solid var(--oc-border); }
28
+
29
+ /* Trigger: a bit tighter, title in the foreground color. */
30
+ .oc-accordion--accent .oc-accordion-trigger { padding: 0.75rem 1rem; font-weight: 600; }
31
+ .oc-accordion--accent .oc-accordion-trigger:hover { background: oklch(from var(--oc-accordion-accent) l c h / 0.06); }
32
+
33
+ /* Open item: tinted head, soft shadow and an accent-colored frame. */
34
+ .oc-accordion--accent :is(details.oc-accordion-item[open], .oc-accordion-item.is-open, .oc-accordion-item[aria-expanded="true"]) {
35
+ border-color: oklch(from var(--oc-accordion-accent) l c h / 0.35);
36
+ border-inline-start-color: var(--oc-accordion-accent);
37
+ box-shadow: 0 4px 14px oklch(from var(--color-black-60) l c h / 0.06);
38
+ }
39
+ .oc-accordion--accent :is(details.oc-accordion-item[open], .oc-accordion-item.is-open, .oc-accordion-item[aria-expanded="true"]) > .oc-accordion-trigger {
40
+ background: oklch(from var(--oc-accordion-accent) l c h / 0.08);
41
+ }
42
+ .oc-accordion--accent .oc-accordion-content { padding: 0.75rem 1rem 1rem; color: var(--oc-foreground); }
43
+
44
+ /* Optional short label at the end of the trigger ("3 items"), in the accent color. */
45
+ .oc-accordion-accent-meta { margin-inline: auto 0.75rem; font-size: 0.75rem; font-weight: 500; color: var(--oc-accordion-accent); }
46
+
47
+ /* Semantic colors (theme tokens), as an alternative to the .oc-accent--* presets. */
48
+ .oc-accordion--accent .oc-accordion-item--success,
49
+ .oc-accordion--accent.oc-accordion--success .oc-accordion-item { --oc-accordion-accent: var(--oc-success); }
50
+ .oc-accordion--accent .oc-accordion-item--warning,
51
+ .oc-accordion--accent.oc-accordion--warning .oc-accordion-item { --oc-accordion-accent: var(--oc-warning); }
52
+ .oc-accordion--accent .oc-accordion-item--danger,
53
+ .oc-accordion--accent.oc-accordion--danger .oc-accordion-item { --oc-accordion-accent: var(--oc-destructive); }
54
+
55
+ /* Accent + flush: no frame around each card except the accent edge. */
56
+ .oc-accordion--accent.oc-accordion--flush .oc-accordion-item { border-block: 0; border-inline-end: 0; border-radius: 0; }
57
+
58
+ @media (prefers-reduced-motion: reduce) {
59
+ .oc-accordion--accent .oc-accordion-item { transition: none; }
60
+ }
@@ -0,0 +1,68 @@
1
+ /* File: packages/ui/src/parts/app-alpha-tabs.css | Map: bar (scrolling row) -> item -> "All" item -> states (current, empty) -> wrap + size modifiers -> reduced motion */
2
+ /* Alpha tabs: "All" + A-Z filter bar for long lists (dictionary, contacts).
3
+ Each letter is a link (?letter=A) or a button. Current letter: aria-current="true" (or .is-active).
4
+ Letters without entries: aria-disabled="true". The row scrolls sideways on small screens. */
5
+
6
+ .oc-alpha-tabs {
7
+ display: flex;
8
+ flex-wrap: nowrap;
9
+ gap: 2px;
10
+ inline-size: 100%;
11
+ padding: 0.25rem;
12
+ overflow-x: auto;
13
+ overscroll-behavior-x: contain;
14
+ scroll-snap-type: x proximity;
15
+ scrollbar-width: thin;
16
+ background: var(--oc-muted);
17
+ border: 1px solid var(--oc-border);
18
+ border-radius: var(--oc-radius);
19
+ }
20
+
21
+ /* One letter. Square-ish, fixed width, centered text. */
22
+ .oc-alpha-tabs-item {
23
+ flex: 0 0 auto;
24
+ display: inline-grid;
25
+ place-items: center;
26
+ min-inline-size: 1.875rem;
27
+ block-size: 1.875rem;
28
+ padding-inline: 0.375rem;
29
+ font: inherit;
30
+ font-size: 0.8125rem;
31
+ font-weight: 500;
32
+ line-height: 1;
33
+ color: var(--oc-muted-foreground);
34
+ text-decoration: none;
35
+ background: none;
36
+ border: 0;
37
+ border-radius: calc(var(--oc-radius) - 2px);
38
+ cursor: pointer;
39
+ scroll-snap-align: start;
40
+ transition: color var(--oc-transition-fast), background var(--oc-transition-fast);
41
+ }
42
+ .oc-alpha-tabs-item:hover { color: var(--oc-foreground); background: var(--oc-surface-strong); }
43
+ .oc-alpha-tabs-item:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
44
+
45
+ /* "All" is wider and separated from the letters by a thin line. */
46
+ .oc-alpha-tabs-item--all { padding-inline: 0.75rem; margin-inline-end: 0.25rem; box-shadow: 0.25rem 0 0 -0.2rem var(--oc-border); }
47
+
48
+ /* Current letter: filled with the primary token. */
49
+ .oc-alpha-tabs-item[aria-current="true"],
50
+ .oc-alpha-tabs-item[aria-selected="true"],
51
+ .oc-alpha-tabs-item.is-active { color: var(--oc-primary-foreground); background: var(--oc-primary); }
52
+
53
+ /* Letter without entries: visible but not clickable. */
54
+ .oc-alpha-tabs-item[aria-disabled="true"],
55
+ .oc-alpha-tabs-item:disabled { opacity: 0.4; pointer-events: none; }
56
+
57
+ /* Wrap: letters wrap onto more rows instead of scrolling. */
58
+ .oc-alpha-tabs--wrap { flex-wrap: wrap; overflow: visible; }
59
+
60
+ /* Small: tighter letters. */
61
+ .oc-alpha-tabs--sm .oc-alpha-tabs-item { min-inline-size: 1.5rem; block-size: 1.5rem; font-size: 0.75rem; }
62
+
63
+ /* Plain: no frame (for inside a toolbar or card). */
64
+ .oc-alpha-tabs--plain { padding: 0; background: none; border: 0; }
65
+
66
+ @media (prefers-reduced-motion: reduce) {
67
+ .oc-alpha-tabs-item { transition: none; }
68
+ }
@@ -0,0 +1,25 @@
1
+ /* File: packages/ui/src/parts/app-busy-overlay.css | Map: dialog + backdrop -> box -> spinner / progress -> title + text -> motion
2
+ Busy overlay: a modal <dialog closedby="none"> shown while a long request runs (saving, uploading, processing photos).
3
+ The modal dialog makes the page inert, so nothing can be clicked twice. Based on the Verdavita admin save overlay. */
4
+
5
+ .oc-busy-overlay {
6
+ inline-size: min(100vw - 2rem, 24rem);
7
+ padding: 1.75rem 2rem;
8
+ border: 1px solid var(--oc-border);
9
+ border-radius: 14px;
10
+ background: var(--oc-card);
11
+ color: var(--oc-foreground);
12
+ text-align: center;
13
+ box-shadow: 0 1.25rem 3rem oklch(from var(--color-black-50) l c h / 0.25);
14
+ }
15
+ .oc-busy-overlay[open] { display: grid; justify-items: center; gap: 0.75rem; }
16
+ .oc-busy-overlay::backdrop { background: oklch(from var(--color-black-60) l c h / 0.5); backdrop-filter: blur(2px); }
17
+ .oc-busy-overlay > .oc-spinner { --oc-spinner-size: 2.5rem; color: var(--oc-primary); }
18
+ .oc-busy-overlay__title { margin: 0; font-size: 1rem; font-weight: 700; }
19
+ .oc-busy-overlay__text { margin: 0; color: var(--oc-muted-foreground); font-size: 0.875rem; }
20
+ .oc-busy-overlay > .oc-progress { inline-size: 100%; }
21
+
22
+ /* Fade in, so short requests do not flash: the box appears after 300ms */
23
+ .oc-busy-overlay[open], .oc-busy-overlay[open]::backdrop { animation: oc-busy-in 0.2s 0.3s both; }
24
+ @keyframes oc-busy-in { from { opacity: 0; } }
25
+ @media (prefers-reduced-motion: reduce) { .oc-busy-overlay[open], .oc-busy-overlay[open]::backdrop { animation-duration: 0s; } }
@@ -0,0 +1,85 @@
1
+ /* File: packages/ui/src/parts/app-column-menu.css | Map: menu panel -> title + list -> item states -> footer -> CSS-only column hiding (scope) */
2
+ /* Column menu: a popover with one checkbox per table column (column visibility).
3
+ CSS-only hiding: wrap the menu and the table in .oc-column-menu-scope and give each checkbox
4
+ data-col="<column number>". An unchecked box hides that column (th and td) through :has(). */
5
+
6
+ /* Panel look. Without the popover attribute it is a normal block (e.g. inside a sheet or sidebar). */
7
+ .oc-column-menu {
8
+ inline-size: 14rem;
9
+ max-inline-size: calc(100vw - 1rem);
10
+ padding: 0.375rem;
11
+ font-size: 0.875rem;
12
+ color: var(--oc-popover-foreground);
13
+ background: var(--oc-popover);
14
+ border: 1px solid var(--oc-border);
15
+ border-radius: var(--oc-radius);
16
+ box-shadow: 0 8px 24px oklch(from var(--color-black-60) l c h / 0.15);
17
+ }
18
+ /* As a popover: in the top layer, tethered to its trigger like the dropdown. */
19
+ .oc-column-menu[popover] {
20
+ position: fixed;
21
+ inset: auto;
22
+ margin: 4px 0 0;
23
+ position-area: block-end span-inline-start;
24
+ position-try-fallbacks: flip-block, flip-inline;
25
+ transition: opacity var(--oc-transition-fast), display var(--oc-transition-fast) allow-discrete, overlay var(--oc-transition-fast) allow-discrete;
26
+ }
27
+ .oc-column-menu[popover]:popover-open {
28
+ display: block;
29
+ @starting-style { opacity: 0; }
30
+ }
31
+
32
+ /* Small heading above the list ("Columns"). */
33
+ .oc-column-menu-title {
34
+ margin: 0;
35
+ padding: 0.375rem 0.5rem 0.25rem;
36
+ font-size: 0.75rem;
37
+ font-weight: 600;
38
+ color: var(--oc-muted-foreground);
39
+ }
40
+
41
+ /* The list is a <form>, so a native <button type="reset"> restores the default columns. */
42
+ .oc-column-menu-list { display: grid; gap: 1px; margin: 0; max-block-size: 18rem; overflow-y: auto; }
43
+
44
+ /* One row: label around a checkbox and the column name. */
45
+ .oc-column-menu-item {
46
+ display: flex;
47
+ align-items: center;
48
+ gap: 0.5rem;
49
+ padding: 0.375rem 0.5rem;
50
+ border-radius: calc(var(--oc-radius) - 2px);
51
+ cursor: pointer;
52
+ user-select: none;
53
+ }
54
+ .oc-column-menu-item:hover { background: var(--oc-accent); }
55
+ .oc-column-menu-item:has(:focus-visible) { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
56
+ .oc-column-menu-item input { margin: 0; accent-color: var(--oc-primary); }
57
+ /* Locked column (always visible): <input disabled checked>. */
58
+ .oc-column-menu-item:has(input:disabled) { color: var(--oc-muted-foreground); cursor: default; }
59
+ .oc-column-menu-item:has(input:disabled):hover { background: none; }
60
+
61
+ /* Footer row with "Reset" (type="reset") or other small buttons. */
62
+ .oc-column-menu-footer {
63
+ display: flex;
64
+ justify-content: flex-end;
65
+ gap: 0.25rem;
66
+ margin-block-start: 0.375rem;
67
+ padding-block-start: 0.375rem;
68
+ border-block-start: 1px solid var(--oc-border);
69
+ }
70
+
71
+ /* ---- CSS-only column hiding (columns 1 to 10) ---- */
72
+ .oc-column-menu-scope:has([data-col="1"]:not(:checked)) .oc-table :is(th, td):nth-child(1),
73
+ .oc-column-menu-scope:has([data-col="2"]:not(:checked)) .oc-table :is(th, td):nth-child(2),
74
+ .oc-column-menu-scope:has([data-col="3"]:not(:checked)) .oc-table :is(th, td):nth-child(3),
75
+ .oc-column-menu-scope:has([data-col="4"]:not(:checked)) .oc-table :is(th, td):nth-child(4),
76
+ .oc-column-menu-scope:has([data-col="5"]:not(:checked)) .oc-table :is(th, td):nth-child(5),
77
+ .oc-column-menu-scope:has([data-col="6"]:not(:checked)) .oc-table :is(th, td):nth-child(6),
78
+ .oc-column-menu-scope:has([data-col="7"]:not(:checked)) .oc-table :is(th, td):nth-child(7),
79
+ .oc-column-menu-scope:has([data-col="8"]:not(:checked)) .oc-table :is(th, td):nth-child(8),
80
+ .oc-column-menu-scope:has([data-col="9"]:not(:checked)) .oc-table :is(th, td):nth-child(9),
81
+ .oc-column-menu-scope:has([data-col="10"]:not(:checked)) .oc-table :is(th, td):nth-child(10) { display: none; }
82
+
83
+ @media (prefers-reduced-motion: reduce) {
84
+ .oc-column-menu[popover] { transition: none; }
85
+ }
@@ -0,0 +1,70 @@
1
+ /* File: packages/ui/src/parts/app-confirm-dialog.css | Map: confirm modifier (icon ring) -> close button -> typed confirm field -> confirm lock -> three-button footer -> narrow screens */
2
+ /* Confirm dialog: a variant of the alert dialog (dialog.oc-modal + .oc-alert-dialog).
3
+ Add .oc-alert-dialog--confirm next to the type modifier (--warning, --error, ...).
4
+ Extras: a larger thin icon ring, a close (X) button, an optional typed confirmation
5
+ ("type DELETE to confirm") and a third "discard" action. No JavaScript: the confirm button is a
6
+ submit button of a <form method="dialog">, so the browser blocks it until the typed value matches. */
7
+
8
+ /* Larger content box, room for the close button. */
9
+ .oc-alert-dialog--confirm { position: relative; max-inline-size: 27.5rem; padding: 1.75rem 1.5rem 0; border-radius: calc(var(--oc-radius) + 8px); }
10
+
11
+ /* Thin ring (80px) with the glyph or an SVG in the type color; the inner disc uses the card color. */
12
+ .oc-alert-dialog--confirm .oc-alert-dialog-icon {
13
+ inline-size: 5rem;
14
+ block-size: 5rem;
15
+ margin-block-end: 1.25rem;
16
+ font-size: 2.25rem;
17
+ font-weight: 400;
18
+ border-width: 2px;
19
+ background: var(--oc-card);
20
+ box-shadow: 0 0 0 6px oklch(from var(--oc-alert-dialog-color, var(--oc-warning)) l c h / 0.1);
21
+ }
22
+ .oc-alert-dialog--confirm .oc-alert-dialog-icon svg { inline-size: 2.25rem; block-size: 2.25rem; }
23
+
24
+ /* Close (X) in the top corner. Use command="close" commandfor="<dialog id>". */
25
+ .oc-alert-dialog-close {
26
+ position: absolute;
27
+ inset-block-start: 0.75rem;
28
+ inset-inline-end: 0.75rem;
29
+ display: grid;
30
+ place-items: center;
31
+ inline-size: 2rem;
32
+ block-size: 2rem;
33
+ padding: 0;
34
+ font-size: 1.25rem;
35
+ line-height: 1;
36
+ color: var(--oc-muted-foreground);
37
+ background: none;
38
+ border: 0;
39
+ border-radius: var(--oc-radius);
40
+ cursor: pointer;
41
+ }
42
+ .oc-alert-dialog-close:hover { color: var(--oc-foreground); background: var(--oc-accent); }
43
+ .oc-alert-dialog-close:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 1px; }
44
+
45
+ /* The form wraps body + footer; it adds no layout of its own. */
46
+ .oc-alert-dialog-form { display: contents; }
47
+
48
+ /* Typed confirmation: label with the word in <code>, then the input. */
49
+ .oc-alert-dialog-typed { display: grid; gap: 0.375rem; align-self: stretch; margin-block-end: 1rem; text-align: start; font-size: 0.875rem; }
50
+ .oc-alert-dialog-typed code {
51
+ padding: 0.1rem 0.35rem;
52
+ font-size: 0.8125rem;
53
+ color: var(--oc-alert-dialog-color, var(--oc-warning));
54
+ background: oklch(from var(--oc-alert-dialog-color, var(--oc-warning)) l c h / 0.1);
55
+ border-radius: 4px;
56
+ }
57
+
58
+ /* While the typed value does not match the pattern, the confirm button looks disabled. */
59
+ .oc-alert-dialog--confirm:has(.oc-alert-dialog-typed input:invalid) .oc-alert-dialog-confirm { opacity: 0.5; cursor: not-allowed; }
60
+
61
+ /* Three buttons: discard at the start, cancel + confirm at the end. */
62
+ .oc-alert-dialog--confirm .oc-modal-footer { flex-wrap: wrap; gap: 0.5rem; padding-block: 0.5rem 1.5rem; }
63
+ .oc-alert-dialog-discard { margin-inline-end: auto; }
64
+ .oc-alert-dialog--confirm .oc-modal-footer:has(.oc-alert-dialog-discard) { justify-content: flex-end; }
65
+
66
+ /* Narrow screens: full-width stacked buttons, confirm on top. */
67
+ @media (max-width: 30rem) {
68
+ .oc-alert-dialog--confirm .oc-modal-footer { flex-direction: column-reverse; }
69
+ .oc-alert-dialog--confirm .oc-modal-footer > * { inline-size: 100%; margin: 0; }
70
+ }