@birdycom/omniaui 0.11.0 → 0.11.1
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 -21
- package/README.md +21 -21
- package/bin/lib/add.mjs +126 -126
- package/bin/lib/catalog.mjs +169 -169
- package/bin/lib/project.mjs +90 -90
- package/bin/omniaui.mjs +69 -69
- package/dist/code-block.css +25 -25
- package/dist/components-extra.css +916 -914
- package/dist/components.css +6559 -6469
- package/dist/components.min.css +1 -1
- package/dist/data-table.d.ts +9 -9
- package/dist/data-table.js +505 -505
- package/dist/docs-ui.css +267 -265
- package/dist/oc-theme.css +69 -69
- package/dist/parts/app-accordion-accent.css +60 -60
- package/dist/parts/app-alpha-tabs.css +68 -68
- package/dist/parts/app-busy-overlay.css +25 -25
- package/dist/parts/app-column-menu.css +85 -85
- package/dist/parts/app-confirm-dialog.css +70 -70
- package/dist/parts/app-cookie-consent.css +63 -63
- package/dist/parts/app-data-table.css +174 -174
- package/dist/parts/app-greeting.css +47 -47
- package/dist/parts/app-list-toolbar.css +81 -81
- package/dist/parts/app-page-header.css +54 -54
- package/dist/parts/app-severity-card.css +91 -91
- package/dist/parts/app-sidebar-dark.css +15 -15
- package/dist/parts/app-sortable-row.css +52 -52
- package/dist/parts/app-stat-card.css +68 -68
- package/dist/parts/app-table-actions.css +71 -71
- package/dist/parts/app-table-compact.css +54 -54
- package/dist/parts/app-top-progress.css +68 -68
- package/dist/parts/app-tree.css +104 -104
- package/dist/parts/app-upgrade-banner.css +90 -90
- package/dist/parts/app-version-banner.css +80 -80
- package/dist/parts/data-chart-line.css +167 -167
- package/dist/parts/forms-affix-input.css +75 -75
- package/dist/parts/forms-barcode-input.css +75 -75
- package/dist/parts/forms-chip-filter.css +91 -91
- package/dist/parts/forms-color-select.css +97 -89
- package/dist/parts/forms-decimal-input.css +51 -51
- package/dist/parts/forms-filter-counts.css +94 -94
- package/dist/parts/forms-language-select.css +89 -76
- package/dist/parts/forms-number-input.css +98 -95
- package/dist/parts/forms-password-requirements.css +55 -55
- package/dist/parts/forms-phone-input.css +85 -85
- package/dist/parts/forms-time-input.css +74 -74
- package/dist/parts/forms-toggle-field.css +69 -69
- package/dist/parts/media-art.css +21 -21
- package/dist/parts/media-attachment.css +160 -160
- package/dist/parts/media-browser-frame.css +73 -73
- package/dist/parts/media-card.css +83 -83
- package/dist/parts/media-chat-composer.css +90 -90
- package/dist/parts/media-doc-viewer.css +151 -151
- package/dist/parts/media-emoji-picker.css +88 -88
- package/dist/parts/media-entity-card.css +52 -52
- package/dist/parts/media-flip-card.css +78 -78
- package/dist/parts/media-image-zoom.css +68 -68
- package/dist/parts/media-lightbox.css +131 -131
- package/dist/parts/media-message-thread.css +136 -136
- package/dist/parts/media-message.css +160 -160
- package/dist/parts/media-row.css +78 -78
- package/dist/parts/media-stack-card.css +82 -82
- package/dist/parts/media-terminal-log.css +76 -76
- package/dist/parts/media-thumb.css +71 -71
- package/dist/parts/site-fact-list.css +25 -25
- package/dist/parts/site-link-arrow.css +34 -34
- package/dist/parts/site-marquee.css +34 -34
- package/dist/parts/site-next-teaser.css +75 -75
- package/dist/parts/site-price-card.css +91 -75
- package/dist/parts/site-product-mark.css +66 -66
- package/dist/parts/site-project-card.css +111 -111
- package/dist/parts/site-prose.css +124 -124
- package/dist/parts/site-stack-list.css +48 -48
- package/dist/parts/site-timeline.css +54 -54
- package/dist/showcase.css +404 -404
- package/package.json +69 -69
- package/snippets/accordion-accent.html +24 -24
- package/snippets/accordion.html +11 -11
- package/snippets/affix-input.html +30 -30
- package/snippets/alert-dialog.html +22 -22
- package/snippets/alert.html +5 -5
- package/snippets/alpha-tabs.html +37 -37
- package/snippets/aspect-ratio.html +15 -15
- package/snippets/attachment.html +43 -43
- package/snippets/avatar.html +6 -6
- package/snippets/back-link.html +5 -5
- package/snippets/badge.html +5 -5
- package/snippets/barcode-input.html +18 -18
- package/snippets/breadcrumb.html +6 -6
- package/snippets/browser-frame.html +18 -18
- package/snippets/busy-overlay.html +31 -31
- package/snippets/button-group.html +21 -21
- package/snippets/button.html +8 -8
- package/snippets/calendar.html +43 -43
- package/snippets/card.html +17 -17
- package/snippets/carousel.html +21 -21
- package/snippets/chart-line.html +46 -46
- package/snippets/chart.html +27 -27
- package/snippets/chat-composer.html +21 -21
- package/snippets/checkbox.html +5 -5
- package/snippets/checklist.html +23 -23
- package/snippets/chip-filter.html +14 -14
- package/snippets/code-window.html +20 -20
- package/snippets/collapsible.html +19 -19
- package/snippets/color-field.html +13 -13
- package/snippets/color-select.html +18 -18
- package/snippets/column-menu.html +38 -38
- package/snippets/combobox.html +19 -19
- package/snippets/command.html +24 -24
- package/snippets/confirm-dialog.html +32 -32
- package/snippets/context-menu.html +25 -25
- package/snippets/cookie-consent.html +70 -70
- package/snippets/copy-field.html +19 -19
- package/snippets/counter.html +2 -2
- package/snippets/data-table.html +151 -151
- package/snippets/date-picker.html +32 -32
- package/snippets/decimal-input.html +20 -20
- package/snippets/definition-list.html +20 -20
- package/snippets/demo-panel.html +18 -18
- package/snippets/doc-viewer.html +58 -58
- package/snippets/drawer.html +30 -30
- package/snippets/dropdown-menu.html +27 -27
- package/snippets/dropdown.html +9 -9
- package/snippets/dropzone.html +13 -13
- package/snippets/emoji-picker.html +51 -51
- package/snippets/empty-state.html +17 -17
- package/snippets/entity-card.html +26 -26
- package/snippets/expandable-table.html +26 -26
- package/snippets/fact-list.html +14 -14
- package/snippets/filter-counts.html +30 -30
- package/snippets/flip-card.html +22 -22
- package/snippets/form-field.html +6 -6
- package/snippets/greeting.html +22 -22
- package/snippets/heading.html +14 -14
- package/snippets/hover-card.html +18 -18
- package/snippets/image-zoom.html +30 -30
- package/snippets/input-group.html +10 -10
- package/snippets/input.html +5 -5
- package/snippets/item.html +26 -26
- package/snippets/kbd.html +13 -13
- package/snippets/label.html +9 -9
- package/snippets/language-select.html +26 -26
- package/snippets/launcher-card.html +14 -14
- package/snippets/lightbox.html +50 -50
- package/snippets/link-arrow.html +10 -10
- package/snippets/list-toolbar.html +33 -33
- package/snippets/marquee.html +15 -15
- package/snippets/media-card.html +28 -28
- package/snippets/media-row.html +21 -21
- package/snippets/media-thumb.html +12 -12
- package/snippets/menubar.html +30 -30
- package/snippets/message-thread.html +123 -123
- package/snippets/message.html +51 -51
- package/snippets/modal.html +15 -15
- package/snippets/native-select.html +15 -15
- package/snippets/navmenu.html +23 -23
- package/snippets/next-teaser.html +15 -15
- package/snippets/number-input.html +27 -27
- package/snippets/otp-input.html +9 -9
- package/snippets/page-header.html +24 -24
- package/snippets/pagination.html +6 -6
- package/snippets/password-input.html +24 -24
- package/snippets/password-requirements.html +30 -30
- package/snippets/phone-input.html +22 -22
- package/snippets/popover.html +15 -15
- package/snippets/price-card.html +34 -34
- package/snippets/product-mark.html +13 -13
- package/snippets/progress.html +4 -4
- package/snippets/project-card.html +23 -23
- package/snippets/prose.html +54 -54
- package/snippets/radio.html +17 -17
- package/snippets/recovery-codes.html +20 -20
- package/snippets/resizable.html +16 -16
- package/snippets/scroll-area.html +20 -20
- package/snippets/search.html +8 -8
- package/snippets/segmented.html +11 -11
- package/snippets/select.html +7 -7
- package/snippets/separator.html +15 -15
- package/snippets/severity-card.html +35 -35
- package/snippets/sheet.html +32 -32
- package/snippets/sidebar-docs.html +24 -24
- package/snippets/sidebar.html +55 -55
- package/snippets/site-footer.html +6 -6
- package/snippets/site-header.html +26 -26
- package/snippets/skeleton.html +4 -4
- package/snippets/slider.html +17 -17
- package/snippets/sortable-row.html +31 -31
- package/snippets/spinner.html +14 -14
- package/snippets/stack-card.html +17 -17
- package/snippets/stack-list.html +16 -16
- package/snippets/stat-card.html +24 -24
- package/snippets/stepper.html +13 -13
- package/snippets/switch.html +6 -6
- package/snippets/table-actions.html +39 -39
- package/snippets/table-compact.html +24 -24
- package/snippets/table.html +29 -29
- package/snippets/tabs.html +9 -9
- package/snippets/tag-input.html +60 -17
- package/snippets/terminal-log.html +23 -23
- package/snippets/textarea.html +3 -3
- package/snippets/theme-switch.html +6 -6
- package/snippets/time-input.html +26 -26
- package/snippets/timeline.html +28 -28
- package/snippets/toast-stack.html +10 -10
- package/snippets/toast.html +36 -36
- package/snippets/toc.html +13 -13
- package/snippets/toggle-field.html +20 -20
- package/snippets/toggle.html +22 -22
- package/snippets/tooltip.html +4 -4
- package/snippets/top-progress.html +12 -12
- package/snippets/tree.html +38 -38
- package/snippets/upgrade-banner.html +28 -28
- package/snippets/user.html +15 -15
- package/snippets/version-banner.html +15 -15
|
@@ -1,78 +1,78 @@
|
|
|
1
|
-
/* File: packages/ui/src/parts/media-flip-card.css | Map: card (perspective) -> hidden checkbox -> inner (3D) -> faces
|
|
2
|
-
-> flip label -> flipped states (checkbox, .is-flipped, --hover) -> vertical -> reduced motion (cross-fade)
|
|
3
|
-
Flip card: front and back in one grid cell; the inner layer turns 180deg. Triggers: a checkbox (CSS :has()),
|
|
4
|
-
hover / focus (--hover) or the .is-flipped class for frameworks. No JavaScript. */
|
|
5
|
-
|
|
6
|
-
.oc-flip-card {
|
|
7
|
-
--oc-flip-card-turn: rotateY(180deg);
|
|
8
|
-
position: relative;
|
|
9
|
-
display: block;
|
|
10
|
-
inline-size: 100%;
|
|
11
|
-
perspective: 60rem;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/* The checkbox stays in the page (focusable, Space toggles) but is invisible. */
|
|
15
|
-
.oc-flip-card__toggle { position: absolute; inline-size: 1px; block-size: 1px; margin: 0; opacity: 0; pointer-events: none; }
|
|
16
|
-
|
|
17
|
-
.oc-flip-card__inner {
|
|
18
|
-
display: grid;
|
|
19
|
-
transform-style: preserve-3d;
|
|
20
|
-
transition: transform 0.6s cubic-bezier(0.4, 0.2, 0.2, 1);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
/* Both faces share one grid cell, so the card is as tall as the taller face. */
|
|
24
|
-
.oc-flip-card__face {
|
|
25
|
-
position: relative;
|
|
26
|
-
grid-area: 1 / 1;
|
|
27
|
-
display: grid;
|
|
28
|
-
align-content: center;
|
|
29
|
-
gap: 0.5rem;
|
|
30
|
-
min-block-size: 10rem;
|
|
31
|
-
padding: 1.25rem;
|
|
32
|
-
border: 1px solid var(--oc-border);
|
|
33
|
-
border-radius: calc(var(--oc-radius) + 4px);
|
|
34
|
-
background: var(--oc-card);
|
|
35
|
-
color: var(--oc-foreground);
|
|
36
|
-
backface-visibility: hidden;
|
|
37
|
-
}
|
|
38
|
-
.oc-flip-card__face--back {
|
|
39
|
-
transform: var(--oc-flip-card-turn);
|
|
40
|
-
border-color: transparent;
|
|
41
|
-
background: var(--oc-primary);
|
|
42
|
-
color: var(--oc-primary-foreground);
|
|
43
|
-
}
|
|
44
|
-
.oc-flip-card__title { margin: 0; font-size: 1.25rem; font-weight: 700; }
|
|
45
|
-
.oc-flip-card__text { margin: 0; font-size: 0.875rem; opacity: 0.85; }
|
|
46
|
-
|
|
47
|
-
/* Flip label ("Show answer"): its ::after covers the face, so a click anywhere flips. */
|
|
48
|
-
.oc-flip-card__flip { justify-self: start; font-size: 0.8125rem; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
|
|
49
|
-
.oc-flip-card__flip::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
|
|
50
|
-
|
|
51
|
-
/* Keyboard focus on the checkbox (or inside a --hover card) rings the card. */
|
|
52
|
-
.oc-flip-card:has(.oc-flip-card__toggle:focus-visible) .oc-flip-card__face,
|
|
53
|
-
.oc-flip-card--hover:focus-visible .oc-flip-card__face { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
54
|
-
.oc-flip-card--hover:focus-visible { outline: none; }
|
|
55
|
-
|
|
56
|
-
/* Flipped: checkbox checked, .is-flipped, or hover / focus on a --hover card. */
|
|
57
|
-
.oc-flip-card:has(> .oc-flip-card__toggle:checked) .oc-flip-card__inner,
|
|
58
|
-
.oc-flip-card.is-flipped .oc-flip-card__inner,
|
|
59
|
-
.oc-flip-card--hover:is(:hover, :focus-within) .oc-flip-card__inner { transform: var(--oc-flip-card-turn); }
|
|
60
|
-
|
|
61
|
-
/* Vertical flip (top over bottom). */
|
|
62
|
-
.oc-flip-card--vertical { --oc-flip-card-turn: rotateX(180deg); }
|
|
63
|
-
|
|
64
|
-
/* Reduced motion: no turning. The faces simply cross-fade. */
|
|
65
|
-
@media (prefers-reduced-motion: reduce) {
|
|
66
|
-
.oc-flip-card .oc-flip-card__inner { transform: none; transition: none; }
|
|
67
|
-
.oc-flip-card .oc-flip-card__face { transform: none; transition: opacity 0.2s, visibility 0.2s; }
|
|
68
|
-
.oc-flip-card .oc-flip-card__face--back { opacity: 0; visibility: hidden; }
|
|
69
|
-
.oc-flip-card:has(> .oc-flip-card__toggle:checked) .oc-flip-card__inner,
|
|
70
|
-
.oc-flip-card.is-flipped .oc-flip-card__inner,
|
|
71
|
-
.oc-flip-card--hover:is(:hover, :focus-within) .oc-flip-card__inner { transform: none; }
|
|
72
|
-
.oc-flip-card:has(> .oc-flip-card__toggle:checked) .oc-flip-card__face--front,
|
|
73
|
-
.oc-flip-card.is-flipped .oc-flip-card__face--front,
|
|
74
|
-
.oc-flip-card--hover:is(:hover, :focus-within) .oc-flip-card__face--front { opacity: 0; visibility: hidden; }
|
|
75
|
-
.oc-flip-card:has(> .oc-flip-card__toggle:checked) .oc-flip-card__face--back,
|
|
76
|
-
.oc-flip-card.is-flipped .oc-flip-card__face--back,
|
|
77
|
-
.oc-flip-card--hover:is(:hover, :focus-within) .oc-flip-card__face--back { opacity: 1; visibility: visible; }
|
|
78
|
-
}
|
|
1
|
+
/* File: packages/ui/src/parts/media-flip-card.css | Map: card (perspective) -> hidden checkbox -> inner (3D) -> faces
|
|
2
|
+
-> flip label -> flipped states (checkbox, .is-flipped, --hover) -> vertical -> reduced motion (cross-fade)
|
|
3
|
+
Flip card: front and back in one grid cell; the inner layer turns 180deg. Triggers: a checkbox (CSS :has()),
|
|
4
|
+
hover / focus (--hover) or the .is-flipped class for frameworks. No JavaScript. */
|
|
5
|
+
|
|
6
|
+
.oc-flip-card {
|
|
7
|
+
--oc-flip-card-turn: rotateY(180deg);
|
|
8
|
+
position: relative;
|
|
9
|
+
display: block;
|
|
10
|
+
inline-size: 100%;
|
|
11
|
+
perspective: 60rem;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* The checkbox stays in the page (focusable, Space toggles) but is invisible. */
|
|
15
|
+
.oc-flip-card__toggle { position: absolute; inline-size: 1px; block-size: 1px; margin: 0; opacity: 0; pointer-events: none; }
|
|
16
|
+
|
|
17
|
+
.oc-flip-card__inner {
|
|
18
|
+
display: grid;
|
|
19
|
+
transform-style: preserve-3d;
|
|
20
|
+
transition: transform 0.6s cubic-bezier(0.4, 0.2, 0.2, 1);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/* Both faces share one grid cell, so the card is as tall as the taller face. */
|
|
24
|
+
.oc-flip-card__face {
|
|
25
|
+
position: relative;
|
|
26
|
+
grid-area: 1 / 1;
|
|
27
|
+
display: grid;
|
|
28
|
+
align-content: center;
|
|
29
|
+
gap: 0.5rem;
|
|
30
|
+
min-block-size: 10rem;
|
|
31
|
+
padding: 1.25rem;
|
|
32
|
+
border: 1px solid var(--oc-border);
|
|
33
|
+
border-radius: calc(var(--oc-radius) + 4px);
|
|
34
|
+
background: var(--oc-card);
|
|
35
|
+
color: var(--oc-foreground);
|
|
36
|
+
backface-visibility: hidden;
|
|
37
|
+
}
|
|
38
|
+
.oc-flip-card__face--back {
|
|
39
|
+
transform: var(--oc-flip-card-turn);
|
|
40
|
+
border-color: transparent;
|
|
41
|
+
background: var(--oc-primary);
|
|
42
|
+
color: var(--oc-primary-foreground);
|
|
43
|
+
}
|
|
44
|
+
.oc-flip-card__title { margin: 0; font-size: 1.25rem; font-weight: 700; }
|
|
45
|
+
.oc-flip-card__text { margin: 0; font-size: 0.875rem; opacity: 0.85; }
|
|
46
|
+
|
|
47
|
+
/* Flip label ("Show answer"): its ::after covers the face, so a click anywhere flips. */
|
|
48
|
+
.oc-flip-card__flip { justify-self: start; font-size: 0.8125rem; font-weight: 600; text-decoration: underline; text-underline-offset: 3px; cursor: pointer; }
|
|
49
|
+
.oc-flip-card__flip::after { content: ""; position: absolute; inset: 0; border-radius: inherit; }
|
|
50
|
+
|
|
51
|
+
/* Keyboard focus on the checkbox (or inside a --hover card) rings the card. */
|
|
52
|
+
.oc-flip-card:has(.oc-flip-card__toggle:focus-visible) .oc-flip-card__face,
|
|
53
|
+
.oc-flip-card--hover:focus-visible .oc-flip-card__face { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
54
|
+
.oc-flip-card--hover:focus-visible { outline: none; }
|
|
55
|
+
|
|
56
|
+
/* Flipped: checkbox checked, .is-flipped, or hover / focus on a --hover card. */
|
|
57
|
+
.oc-flip-card:has(> .oc-flip-card__toggle:checked) .oc-flip-card__inner,
|
|
58
|
+
.oc-flip-card.is-flipped .oc-flip-card__inner,
|
|
59
|
+
.oc-flip-card--hover:is(:hover, :focus-within) .oc-flip-card__inner { transform: var(--oc-flip-card-turn); }
|
|
60
|
+
|
|
61
|
+
/* Vertical flip (top over bottom). */
|
|
62
|
+
.oc-flip-card--vertical { --oc-flip-card-turn: rotateX(180deg); }
|
|
63
|
+
|
|
64
|
+
/* Reduced motion: no turning. The faces simply cross-fade. */
|
|
65
|
+
@media (prefers-reduced-motion: reduce) {
|
|
66
|
+
.oc-flip-card .oc-flip-card__inner { transform: none; transition: none; }
|
|
67
|
+
.oc-flip-card .oc-flip-card__face { transform: none; transition: opacity 0.2s, visibility 0.2s; }
|
|
68
|
+
.oc-flip-card .oc-flip-card__face--back { opacity: 0; visibility: hidden; }
|
|
69
|
+
.oc-flip-card:has(> .oc-flip-card__toggle:checked) .oc-flip-card__inner,
|
|
70
|
+
.oc-flip-card.is-flipped .oc-flip-card__inner,
|
|
71
|
+
.oc-flip-card--hover:is(:hover, :focus-within) .oc-flip-card__inner { transform: none; }
|
|
72
|
+
.oc-flip-card:has(> .oc-flip-card__toggle:checked) .oc-flip-card__face--front,
|
|
73
|
+
.oc-flip-card.is-flipped .oc-flip-card__face--front,
|
|
74
|
+
.oc-flip-card--hover:is(:hover, :focus-within) .oc-flip-card__face--front { opacity: 0; visibility: hidden; }
|
|
75
|
+
.oc-flip-card:has(> .oc-flip-card__toggle:checked) .oc-flip-card__face--back,
|
|
76
|
+
.oc-flip-card.is-flipped .oc-flip-card__face--back,
|
|
77
|
+
.oc-flip-card--hover:is(:hover, :focus-within) .oc-flip-card__face--back { opacity: 1; visibility: visible; }
|
|
78
|
+
}
|
|
@@ -1,68 +1,68 @@
|
|
|
1
|
-
/* File: packages/ui/src/parts/media-image-zoom.css | Map: root + zoom variable -> toolbar + level chips
|
|
2
|
-
-> viewport (scroll = pan) -> canvas (grows with the zoom) -> zoom levels (classes + radios via :has()) -> motion
|
|
3
|
-
Image zoom: the canvas gets wider than the viewport, so the native scrollbars / touch scrolling pan the image.
|
|
4
|
-
No JavaScript and no transform tricks: zooming is just inline-size: calc(100% * var(--oc-zoom)). */
|
|
5
|
-
|
|
6
|
-
.oc-image-zoom {
|
|
7
|
-
--oc-zoom: 1;
|
|
8
|
-
--oc-image-zoom-ratio: 16 / 9;
|
|
9
|
-
display: grid;
|
|
10
|
-
gap: 0.5rem;
|
|
11
|
-
inline-size: 100%;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
/* ---- Toolbar with zoom level chips (radio buttons) ---- */
|
|
15
|
-
.oc-image-zoom__toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem; font-size: 0.8125rem; color: var(--oc-muted-foreground); }
|
|
16
|
-
.oc-image-zoom__label { margin-inline-end: 0.25rem; }
|
|
17
|
-
.oc-image-zoom__level {
|
|
18
|
-
position: relative;
|
|
19
|
-
display: inline-grid;
|
|
20
|
-
place-items: center;
|
|
21
|
-
min-inline-size: 2.5rem;
|
|
22
|
-
padding: 0.25rem 0.5rem;
|
|
23
|
-
border: 1px solid var(--oc-border);
|
|
24
|
-
border-radius: 999px;
|
|
25
|
-
background: var(--oc-card);
|
|
26
|
-
color: var(--oc-foreground);
|
|
27
|
-
font-variant-numeric: tabular-nums;
|
|
28
|
-
cursor: pointer;
|
|
29
|
-
}
|
|
30
|
-
/* The radio itself is invisible but stays focusable (keyboard: arrow keys switch levels). */
|
|
31
|
-
.oc-image-zoom__level > input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
|
|
32
|
-
.oc-image-zoom__level:has(input:checked) { border-color: var(--oc-primary); background: var(--oc-primary); color: var(--oc-primary-foreground); }
|
|
33
|
-
.oc-image-zoom__level:has(input:focus-visible) { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
34
|
-
|
|
35
|
-
/* ---- Viewport: fixed ratio window; scrolling it pans the image ---- */
|
|
36
|
-
.oc-image-zoom__viewport {
|
|
37
|
-
aspect-ratio: var(--oc-image-zoom-ratio);
|
|
38
|
-
overflow: auto;
|
|
39
|
-
overscroll-behavior: contain;
|
|
40
|
-
border: 1px solid var(--oc-border);
|
|
41
|
-
border-radius: var(--oc-radius);
|
|
42
|
-
background: var(--oc-muted);
|
|
43
|
-
scrollbar-width: thin;
|
|
44
|
-
}
|
|
45
|
-
.oc-image-zoom__viewport:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
46
|
-
|
|
47
|
-
/* ---- Canvas: same ratio as the viewport, scaled by --oc-zoom ---- */
|
|
48
|
-
.oc-image-zoom__canvas { inline-size: calc(100% * var(--oc-zoom)); aspect-ratio: var(--oc-image-zoom-ratio); }
|
|
49
|
-
.oc-image-zoom__canvas > * { display: block; inline-size: 100%; block-size: 100%; object-fit: cover; }
|
|
50
|
-
|
|
51
|
-
/* ---- Zoom levels: fixed classes, or radio chips (value = level) ---- */
|
|
52
|
-
.oc-image-zoom--150 { --oc-zoom: 1.5; }
|
|
53
|
-
.oc-image-zoom--200 { --oc-zoom: 2; }
|
|
54
|
-
.oc-image-zoom--300 { --oc-zoom: 3; }
|
|
55
|
-
.oc-image-zoom:has(.oc-image-zoom__level input[value="1"]:checked) { --oc-zoom: 1; }
|
|
56
|
-
.oc-image-zoom:has(.oc-image-zoom__level input[value="1.5"]:checked) { --oc-zoom: 1.5; }
|
|
57
|
-
.oc-image-zoom:has(.oc-image-zoom__level input[value="2"]:checked) { --oc-zoom: 2; }
|
|
58
|
-
.oc-image-zoom:has(.oc-image-zoom__level input[value="3"]:checked) { --oc-zoom: 3; }
|
|
59
|
-
.oc-image-zoom:has(.oc-image-zoom__level input[value="4"]:checked) { --oc-zoom: 4; }
|
|
60
|
-
|
|
61
|
-
/* Ratio presets. */
|
|
62
|
-
.oc-image-zoom--square { --oc-image-zoom-ratio: 1 / 1; }
|
|
63
|
-
.oc-image-zoom--photo { --oc-image-zoom-ratio: 4 / 3; }
|
|
64
|
-
|
|
65
|
-
/* Smooth resize only when motion is welcome. */
|
|
66
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
67
|
-
.oc-image-zoom__canvas { transition: inline-size var(--oc-transition-normal); }
|
|
68
|
-
}
|
|
1
|
+
/* File: packages/ui/src/parts/media-image-zoom.css | Map: root + zoom variable -> toolbar + level chips
|
|
2
|
+
-> viewport (scroll = pan) -> canvas (grows with the zoom) -> zoom levels (classes + radios via :has()) -> motion
|
|
3
|
+
Image zoom: the canvas gets wider than the viewport, so the native scrollbars / touch scrolling pan the image.
|
|
4
|
+
No JavaScript and no transform tricks: zooming is just inline-size: calc(100% * var(--oc-zoom)). */
|
|
5
|
+
|
|
6
|
+
.oc-image-zoom {
|
|
7
|
+
--oc-zoom: 1;
|
|
8
|
+
--oc-image-zoom-ratio: 16 / 9;
|
|
9
|
+
display: grid;
|
|
10
|
+
gap: 0.5rem;
|
|
11
|
+
inline-size: 100%;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/* ---- Toolbar with zoom level chips (radio buttons) ---- */
|
|
15
|
+
.oc-image-zoom__toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.25rem; font-size: 0.8125rem; color: var(--oc-muted-foreground); }
|
|
16
|
+
.oc-image-zoom__label { margin-inline-end: 0.25rem; }
|
|
17
|
+
.oc-image-zoom__level {
|
|
18
|
+
position: relative;
|
|
19
|
+
display: inline-grid;
|
|
20
|
+
place-items: center;
|
|
21
|
+
min-inline-size: 2.5rem;
|
|
22
|
+
padding: 0.25rem 0.5rem;
|
|
23
|
+
border: 1px solid var(--oc-border);
|
|
24
|
+
border-radius: 999px;
|
|
25
|
+
background: var(--oc-card);
|
|
26
|
+
color: var(--oc-foreground);
|
|
27
|
+
font-variant-numeric: tabular-nums;
|
|
28
|
+
cursor: pointer;
|
|
29
|
+
}
|
|
30
|
+
/* The radio itself is invisible but stays focusable (keyboard: arrow keys switch levels). */
|
|
31
|
+
.oc-image-zoom__level > input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
|
|
32
|
+
.oc-image-zoom__level:has(input:checked) { border-color: var(--oc-primary); background: var(--oc-primary); color: var(--oc-primary-foreground); }
|
|
33
|
+
.oc-image-zoom__level:has(input:focus-visible) { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
34
|
+
|
|
35
|
+
/* ---- Viewport: fixed ratio window; scrolling it pans the image ---- */
|
|
36
|
+
.oc-image-zoom__viewport {
|
|
37
|
+
aspect-ratio: var(--oc-image-zoom-ratio);
|
|
38
|
+
overflow: auto;
|
|
39
|
+
overscroll-behavior: contain;
|
|
40
|
+
border: 1px solid var(--oc-border);
|
|
41
|
+
border-radius: var(--oc-radius);
|
|
42
|
+
background: var(--oc-muted);
|
|
43
|
+
scrollbar-width: thin;
|
|
44
|
+
}
|
|
45
|
+
.oc-image-zoom__viewport:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
46
|
+
|
|
47
|
+
/* ---- Canvas: same ratio as the viewport, scaled by --oc-zoom ---- */
|
|
48
|
+
.oc-image-zoom__canvas { inline-size: calc(100% * var(--oc-zoom)); aspect-ratio: var(--oc-image-zoom-ratio); }
|
|
49
|
+
.oc-image-zoom__canvas > * { display: block; inline-size: 100%; block-size: 100%; object-fit: cover; }
|
|
50
|
+
|
|
51
|
+
/* ---- Zoom levels: fixed classes, or radio chips (value = level) ---- */
|
|
52
|
+
.oc-image-zoom--150 { --oc-zoom: 1.5; }
|
|
53
|
+
.oc-image-zoom--200 { --oc-zoom: 2; }
|
|
54
|
+
.oc-image-zoom--300 { --oc-zoom: 3; }
|
|
55
|
+
.oc-image-zoom:has(.oc-image-zoom__level input[value="1"]:checked) { --oc-zoom: 1; }
|
|
56
|
+
.oc-image-zoom:has(.oc-image-zoom__level input[value="1.5"]:checked) { --oc-zoom: 1.5; }
|
|
57
|
+
.oc-image-zoom:has(.oc-image-zoom__level input[value="2"]:checked) { --oc-zoom: 2; }
|
|
58
|
+
.oc-image-zoom:has(.oc-image-zoom__level input[value="3"]:checked) { --oc-zoom: 3; }
|
|
59
|
+
.oc-image-zoom:has(.oc-image-zoom__level input[value="4"]:checked) { --oc-zoom: 4; }
|
|
60
|
+
|
|
61
|
+
/* Ratio presets. */
|
|
62
|
+
.oc-image-zoom--square { --oc-image-zoom-ratio: 1 / 1; }
|
|
63
|
+
.oc-image-zoom--photo { --oc-image-zoom-ratio: 4 / 3; }
|
|
64
|
+
|
|
65
|
+
/* Smooth resize only when motion is welcome. */
|
|
66
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
67
|
+
.oc-image-zoom__canvas { transition: inline-size var(--oc-transition-normal); }
|
|
68
|
+
}
|
|
@@ -1,131 +1,131 @@
|
|
|
1
|
-
/* File: packages/ui/src/parts/media-lightbox.css | Map: thumbnails -> dialog + backdrop -> bar -> track + slides
|
|
2
|
-
-> nav buttons -> caption + counter -> single image -> small screens -> motion
|
|
3
|
-
Lightbox: one native <dialog> with a scroll-snap track of slides. Thumbnails open it with
|
|
4
|
-
command="show-modal"; prev / next are anchor links to the slide ids, so it works without JavaScript. */
|
|
5
|
-
|
|
6
|
-
/* ---- Thumbnails (buttons that open the dialog) ---- */
|
|
7
|
-
.oc-lightbox-thumbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); gap: 0.5rem; inline-size: 100%; }
|
|
8
|
-
.oc-lightbox-thumb {
|
|
9
|
-
display: block;
|
|
10
|
-
padding: 0;
|
|
11
|
-
aspect-ratio: 4 / 3;
|
|
12
|
-
overflow: hidden;
|
|
13
|
-
border: 1px solid var(--oc-border);
|
|
14
|
-
border-radius: var(--oc-radius);
|
|
15
|
-
background: var(--oc-muted);
|
|
16
|
-
cursor: zoom-in;
|
|
17
|
-
}
|
|
18
|
-
.oc-lightbox-thumb > * { inline-size: 100%; block-size: 100%; object-fit: cover; transition: transform var(--oc-transition-normal); }
|
|
19
|
-
.oc-lightbox-thumb:hover > * { transform: scale(1.04); }
|
|
20
|
-
.oc-lightbox-thumb:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
21
|
-
|
|
22
|
-
/* ---- The viewer: full-screen modal dialog, dark and blurred behind ---- */
|
|
23
|
-
.oc-lightbox {
|
|
24
|
-
inline-size: 100vw;
|
|
25
|
-
block-size: 100dvh;
|
|
26
|
-
max-inline-size: none;
|
|
27
|
-
max-block-size: none;
|
|
28
|
-
margin: 0;
|
|
29
|
-
padding: 0;
|
|
30
|
-
border: 0;
|
|
31
|
-
overflow: hidden;
|
|
32
|
-
background: transparent;
|
|
33
|
-
color: var(--color-white-50);
|
|
34
|
-
}
|
|
35
|
-
.oc-lightbox[open] { display: grid; grid-template-rows: auto minmax(0, 1fr); }
|
|
36
|
-
.oc-lightbox::backdrop { background: oklch(from var(--color-black-60) l c h / 0.88); backdrop-filter: blur(10px); }
|
|
37
|
-
|
|
38
|
-
/* ---- Top bar: title left, close button right ---- */
|
|
39
|
-
.oc-lightbox__bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.75rem 1rem; }
|
|
40
|
-
.oc-lightbox__title { margin: 0; font-size: 0.95rem; font-weight: 600; }
|
|
41
|
-
|
|
42
|
-
/* ---- Track: one slide per screen, snapping. Arrow keys scroll it when it has focus. ---- */
|
|
43
|
-
.oc-lightbox__track {
|
|
44
|
-
display: flex;
|
|
45
|
-
min-block-size: 0;
|
|
46
|
-
overflow-x: auto;
|
|
47
|
-
overscroll-behavior: contain;
|
|
48
|
-
scroll-snap-type: x mandatory;
|
|
49
|
-
scrollbar-width: none;
|
|
50
|
-
}
|
|
51
|
-
.oc-lightbox__track:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
|
|
52
|
-
.oc-lightbox__slide {
|
|
53
|
-
flex: 0 0 100%;
|
|
54
|
-
display: grid;
|
|
55
|
-
grid-template-columns: 4.5rem minmax(0, 1fr) 4.5rem;
|
|
56
|
-
grid-template-rows: minmax(0, 1fr) auto;
|
|
57
|
-
align-items: center;
|
|
58
|
-
gap: 1rem 0;
|
|
59
|
-
margin: 0;
|
|
60
|
-
padding-block-end: 1.5rem;
|
|
61
|
-
scroll-snap-align: center;
|
|
62
|
-
scroll-snap-stop: always;
|
|
63
|
-
}
|
|
64
|
-
.oc-lightbox__media { grid-column: 2; grid-row: 1; display: grid; place-items: center; min-block-size: 0; block-size: 100%; }
|
|
65
|
-
.oc-lightbox__media > * {
|
|
66
|
-
max-inline-size: 100%;
|
|
67
|
-
max-block-size: calc(100dvh - 9rem);
|
|
68
|
-
object-fit: contain;
|
|
69
|
-
border: 1px solid oklch(from var(--color-white-50) l c h / 0.15);
|
|
70
|
-
border-radius: calc(var(--oc-radius) - 2px);
|
|
71
|
-
box-shadow: 0 40px 100px -30px oklch(from var(--color-black-60) l c h / 0.9);
|
|
72
|
-
}
|
|
73
|
-
/* Placeholder artwork has no natural size: give it one. */
|
|
74
|
-
.oc-lightbox__media > .oc-media-art { inline-size: min(56rem, 100%); block-size: auto; aspect-ratio: 3 / 2; }
|
|
75
|
-
|
|
76
|
-
/* ---- Round buttons: close (button) and prev / next (links) ---- */
|
|
77
|
-
.oc-lightbox__close,
|
|
78
|
-
.oc-lightbox__nav {
|
|
79
|
-
display: inline-grid;
|
|
80
|
-
place-items: center;
|
|
81
|
-
inline-size: 2.75rem;
|
|
82
|
-
aspect-ratio: 1;
|
|
83
|
-
border: 1px solid oklch(from var(--color-white-50) l c h / 0.25);
|
|
84
|
-
border-radius: 50%;
|
|
85
|
-
background: oklch(from var(--color-white-50) l c h / 0.08);
|
|
86
|
-
color: inherit;
|
|
87
|
-
font-size: 1.1rem;
|
|
88
|
-
line-height: 1;
|
|
89
|
-
text-decoration: none;
|
|
90
|
-
cursor: pointer;
|
|
91
|
-
transition: background var(--oc-transition-fast), transform var(--oc-transition-fast);
|
|
92
|
-
}
|
|
93
|
-
.oc-lightbox__close:hover,
|
|
94
|
-
.oc-lightbox__nav:hover { background: oklch(from var(--color-white-50) l c h / 0.18); transform: scale(1.06); }
|
|
95
|
-
.oc-lightbox__close:focus-visible,
|
|
96
|
-
.oc-lightbox__nav:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
97
|
-
.oc-lightbox__nav { grid-row: 1; justify-self: center; }
|
|
98
|
-
.oc-lightbox__nav--prev { grid-column: 1; }
|
|
99
|
-
.oc-lightbox__nav--next { grid-column: 3; }
|
|
100
|
-
|
|
101
|
-
/* ---- Caption with the "2 / 5" counter ---- */
|
|
102
|
-
.oc-lightbox__caption {
|
|
103
|
-
grid-column: 1 / -1;
|
|
104
|
-
grid-row: 2;
|
|
105
|
-
display: flex;
|
|
106
|
-
flex-wrap: wrap;
|
|
107
|
-
justify-content: center;
|
|
108
|
-
gap: 0.25rem 0.75rem;
|
|
109
|
-
padding-inline: 1rem;
|
|
110
|
-
font-size: 0.95rem;
|
|
111
|
-
text-align: center;
|
|
112
|
-
color: oklch(from var(--color-white-50) l c h / 0.8);
|
|
113
|
-
}
|
|
114
|
-
.oc-lightbox__counter { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; color: oklch(from var(--color-white-50) l c h / 0.6); }
|
|
115
|
-
|
|
116
|
-
/* One image only: no prev / next and no counter needed. */
|
|
117
|
-
.oc-lightbox--single .oc-lightbox__nav,
|
|
118
|
-
.oc-lightbox--single .oc-lightbox__counter { visibility: hidden; }
|
|
119
|
-
|
|
120
|
-
/* Small screens: narrower side columns, smaller buttons. */
|
|
121
|
-
@media (max-width: 40rem) {
|
|
122
|
-
.oc-lightbox__slide { grid-template-columns: 2.75rem minmax(0, 1fr) 2.75rem; }
|
|
123
|
-
.oc-lightbox__nav { inline-size: 2.25rem; }
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/* Motion only when the user has not asked for less. */
|
|
127
|
-
@media (prefers-reduced-motion: no-preference) {
|
|
128
|
-
.oc-lightbox__track { scroll-behavior: smooth; }
|
|
129
|
-
.oc-lightbox[open] { animation: oc-lightbox-in 0.25s ease-out; }
|
|
130
|
-
}
|
|
131
|
-
@keyframes oc-lightbox-in { from { opacity: 0; scale: 0.98; } }
|
|
1
|
+
/* File: packages/ui/src/parts/media-lightbox.css | Map: thumbnails -> dialog + backdrop -> bar -> track + slides
|
|
2
|
+
-> nav buttons -> caption + counter -> single image -> small screens -> motion
|
|
3
|
+
Lightbox: one native <dialog> with a scroll-snap track of slides. Thumbnails open it with
|
|
4
|
+
command="show-modal"; prev / next are anchor links to the slide ids, so it works without JavaScript. */
|
|
5
|
+
|
|
6
|
+
/* ---- Thumbnails (buttons that open the dialog) ---- */
|
|
7
|
+
.oc-lightbox-thumbs { display: grid; grid-template-columns: repeat(auto-fill, minmax(8rem, 1fr)); gap: 0.5rem; inline-size: 100%; }
|
|
8
|
+
.oc-lightbox-thumb {
|
|
9
|
+
display: block;
|
|
10
|
+
padding: 0;
|
|
11
|
+
aspect-ratio: 4 / 3;
|
|
12
|
+
overflow: hidden;
|
|
13
|
+
border: 1px solid var(--oc-border);
|
|
14
|
+
border-radius: var(--oc-radius);
|
|
15
|
+
background: var(--oc-muted);
|
|
16
|
+
cursor: zoom-in;
|
|
17
|
+
}
|
|
18
|
+
.oc-lightbox-thumb > * { inline-size: 100%; block-size: 100%; object-fit: cover; transition: transform var(--oc-transition-normal); }
|
|
19
|
+
.oc-lightbox-thumb:hover > * { transform: scale(1.04); }
|
|
20
|
+
.oc-lightbox-thumb:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
21
|
+
|
|
22
|
+
/* ---- The viewer: full-screen modal dialog, dark and blurred behind ---- */
|
|
23
|
+
.oc-lightbox {
|
|
24
|
+
inline-size: 100vw;
|
|
25
|
+
block-size: 100dvh;
|
|
26
|
+
max-inline-size: none;
|
|
27
|
+
max-block-size: none;
|
|
28
|
+
margin: 0;
|
|
29
|
+
padding: 0;
|
|
30
|
+
border: 0;
|
|
31
|
+
overflow: hidden;
|
|
32
|
+
background: transparent;
|
|
33
|
+
color: var(--color-white-50);
|
|
34
|
+
}
|
|
35
|
+
.oc-lightbox[open] { display: grid; grid-template-rows: auto minmax(0, 1fr); }
|
|
36
|
+
.oc-lightbox::backdrop { background: oklch(from var(--color-black-60) l c h / 0.88); backdrop-filter: blur(10px); }
|
|
37
|
+
|
|
38
|
+
/* ---- Top bar: title left, close button right ---- */
|
|
39
|
+
.oc-lightbox__bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding: 0.75rem 1rem; }
|
|
40
|
+
.oc-lightbox__title { margin: 0; font-size: 0.95rem; font-weight: 600; }
|
|
41
|
+
|
|
42
|
+
/* ---- Track: one slide per screen, snapping. Arrow keys scroll it when it has focus. ---- */
|
|
43
|
+
.oc-lightbox__track {
|
|
44
|
+
display: flex;
|
|
45
|
+
min-block-size: 0;
|
|
46
|
+
overflow-x: auto;
|
|
47
|
+
overscroll-behavior: contain;
|
|
48
|
+
scroll-snap-type: x mandatory;
|
|
49
|
+
scrollbar-width: none;
|
|
50
|
+
}
|
|
51
|
+
.oc-lightbox__track:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: -2px; }
|
|
52
|
+
.oc-lightbox__slide {
|
|
53
|
+
flex: 0 0 100%;
|
|
54
|
+
display: grid;
|
|
55
|
+
grid-template-columns: 4.5rem minmax(0, 1fr) 4.5rem;
|
|
56
|
+
grid-template-rows: minmax(0, 1fr) auto;
|
|
57
|
+
align-items: center;
|
|
58
|
+
gap: 1rem 0;
|
|
59
|
+
margin: 0;
|
|
60
|
+
padding-block-end: 1.5rem;
|
|
61
|
+
scroll-snap-align: center;
|
|
62
|
+
scroll-snap-stop: always;
|
|
63
|
+
}
|
|
64
|
+
.oc-lightbox__media { grid-column: 2; grid-row: 1; display: grid; place-items: center; min-block-size: 0; block-size: 100%; }
|
|
65
|
+
.oc-lightbox__media > * {
|
|
66
|
+
max-inline-size: 100%;
|
|
67
|
+
max-block-size: calc(100dvh - 9rem);
|
|
68
|
+
object-fit: contain;
|
|
69
|
+
border: 1px solid oklch(from var(--color-white-50) l c h / 0.15);
|
|
70
|
+
border-radius: calc(var(--oc-radius) - 2px);
|
|
71
|
+
box-shadow: 0 40px 100px -30px oklch(from var(--color-black-60) l c h / 0.9);
|
|
72
|
+
}
|
|
73
|
+
/* Placeholder artwork has no natural size: give it one. */
|
|
74
|
+
.oc-lightbox__media > .oc-media-art { inline-size: min(56rem, 100%); block-size: auto; aspect-ratio: 3 / 2; }
|
|
75
|
+
|
|
76
|
+
/* ---- Round buttons: close (button) and prev / next (links) ---- */
|
|
77
|
+
.oc-lightbox__close,
|
|
78
|
+
.oc-lightbox__nav {
|
|
79
|
+
display: inline-grid;
|
|
80
|
+
place-items: center;
|
|
81
|
+
inline-size: 2.75rem;
|
|
82
|
+
aspect-ratio: 1;
|
|
83
|
+
border: 1px solid oklch(from var(--color-white-50) l c h / 0.25);
|
|
84
|
+
border-radius: 50%;
|
|
85
|
+
background: oklch(from var(--color-white-50) l c h / 0.08);
|
|
86
|
+
color: inherit;
|
|
87
|
+
font-size: 1.1rem;
|
|
88
|
+
line-height: 1;
|
|
89
|
+
text-decoration: none;
|
|
90
|
+
cursor: pointer;
|
|
91
|
+
transition: background var(--oc-transition-fast), transform var(--oc-transition-fast);
|
|
92
|
+
}
|
|
93
|
+
.oc-lightbox__close:hover,
|
|
94
|
+
.oc-lightbox__nav:hover { background: oklch(from var(--color-white-50) l c h / 0.18); transform: scale(1.06); }
|
|
95
|
+
.oc-lightbox__close:focus-visible,
|
|
96
|
+
.oc-lightbox__nav:focus-visible { outline: 2px solid var(--oc-ring); outline-offset: 2px; }
|
|
97
|
+
.oc-lightbox__nav { grid-row: 1; justify-self: center; }
|
|
98
|
+
.oc-lightbox__nav--prev { grid-column: 1; }
|
|
99
|
+
.oc-lightbox__nav--next { grid-column: 3; }
|
|
100
|
+
|
|
101
|
+
/* ---- Caption with the "2 / 5" counter ---- */
|
|
102
|
+
.oc-lightbox__caption {
|
|
103
|
+
grid-column: 1 / -1;
|
|
104
|
+
grid-row: 2;
|
|
105
|
+
display: flex;
|
|
106
|
+
flex-wrap: wrap;
|
|
107
|
+
justify-content: center;
|
|
108
|
+
gap: 0.25rem 0.75rem;
|
|
109
|
+
padding-inline: 1rem;
|
|
110
|
+
font-size: 0.95rem;
|
|
111
|
+
text-align: center;
|
|
112
|
+
color: oklch(from var(--color-white-50) l c h / 0.8);
|
|
113
|
+
}
|
|
114
|
+
.oc-lightbox__counter { font-family: ui-monospace, monospace; font-variant-numeric: tabular-nums; color: oklch(from var(--color-white-50) l c h / 0.6); }
|
|
115
|
+
|
|
116
|
+
/* One image only: no prev / next and no counter needed. */
|
|
117
|
+
.oc-lightbox--single .oc-lightbox__nav,
|
|
118
|
+
.oc-lightbox--single .oc-lightbox__counter { visibility: hidden; }
|
|
119
|
+
|
|
120
|
+
/* Small screens: narrower side columns, smaller buttons. */
|
|
121
|
+
@media (max-width: 40rem) {
|
|
122
|
+
.oc-lightbox__slide { grid-template-columns: 2.75rem minmax(0, 1fr) 2.75rem; }
|
|
123
|
+
.oc-lightbox__nav { inline-size: 2.25rem; }
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/* Motion only when the user has not asked for less. */
|
|
127
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
128
|
+
.oc-lightbox__track { scroll-behavior: smooth; }
|
|
129
|
+
.oc-lightbox[open] { animation: oc-lightbox-in 0.25s ease-out; }
|
|
130
|
+
}
|
|
131
|
+
@keyframes oc-lightbox-in { from { opacity: 0; scale: 0.98; } }
|