@echodial/deck 0.1.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 +1327 -0
- package/bin/deck.mjs +219 -0
- package/build.mjs +338 -0
- package/dist/api-buckets.json +10486 -0
- package/dist/api.json +57896 -0
- package/dist/brand/deck-apple-touch-icon.png +0 -0
- package/dist/brand/deck-logo-dark.svg +1 -0
- package/dist/brand/deck-logo-light.svg +1 -0
- package/dist/brand/deck-logo-stacked.svg +1 -0
- package/dist/brand/deck-logo.svg +1 -0
- package/dist/brand/deck-mark.svg +7 -0
- package/dist/brand/deck-og.png +0 -0
- package/dist/collisions.json +223 -0
- package/dist/deck-adapters.js +482 -0
- package/dist/deck-adapters.min.js +23 -0
- package/dist/deck-extras.js +823 -0
- package/dist/deck-extras.min.js +5 -0
- package/dist/deck-icons.svg +184 -0
- package/dist/deck.bundle.js +2638 -0
- package/dist/deck.bundle.min.js +86 -0
- package/dist/deck.css +7904 -0
- package/dist/deck.esm.js +2644 -0
- package/dist/deck.js +1331 -0
- package/dist/deck.min.css +32 -0
- package/dist/deck.min.js +60 -0
- package/dist/layers/anchor.css +192 -0
- package/dist/layers/buttons.css +210 -0
- package/dist/layers/charts.css +337 -0
- package/dist/layers/combobox.css +248 -0
- package/dist/layers/components.css +868 -0
- package/dist/layers/container.css +199 -0
- package/dist/layers/datagrid.css +335 -0
- package/dist/layers/datepicker.css +305 -0
- package/dist/layers/forms.css +401 -0
- package/dist/layers/gradients.css +302 -0
- package/dist/layers/inputs.css +522 -0
- package/dist/layers/layers.css +87 -0
- package/dist/layers/layout.css +235 -0
- package/dist/layers/logical.css +226 -0
- package/dist/layers/media.css +400 -0
- package/dist/layers/mobile.css +245 -0
- package/dist/layers/motion.css +379 -0
- package/dist/layers/nav.css +771 -0
- package/dist/layers/perf.css +234 -0
- package/dist/layers/print.css +198 -0
- package/dist/layers/reset.css +103 -0
- package/dist/layers/space3d.css +280 -0
- package/dist/layers/toasts.css +201 -0
- package/dist/layers/tokens.css +229 -0
- package/dist/layers/type.css +114 -0
- package/dist/layers/utilities.css +241 -0
- package/dist/sizes.json +52 -0
- package/dist/usage.json +6340 -0
- package/package.json +94 -0
- package/src/00-layers.css +87 -0
- package/src/01-tokens.css +229 -0
- package/src/02-reset.css +103 -0
- package/src/03-type.css +114 -0
- package/src/04-layout.css +235 -0
- package/src/05-buttons.css +210 -0
- package/src/06-forms.css +401 -0
- package/src/07-components.css +868 -0
- package/src/08-mobile.css +245 -0
- package/src/09-utilities.css +241 -0
- package/src/10-datepicker.css +305 -0
- package/src/11-combobox.css +248 -0
- package/src/12-datagrid.css +335 -0
- package/src/13-toasts.css +201 -0
- package/src/14-charts.css +337 -0
- package/src/16-motion.css +379 -0
- package/src/18-container.css +199 -0
- package/src/19-logical.css +226 -0
- package/src/20-gradients.css +302 -0
- package/src/21-space3d.css +280 -0
- package/src/22-nav.css +771 -0
- package/src/23-inputs.css +522 -0
- package/src/24-media.css +400 -0
- package/src/25-anchor.css +192 -0
- package/src/26-perf.css +234 -0
- package/src/99-print.css +198 -0
- package/src/brand/deck-apple-touch-icon.png +0 -0
- package/src/brand/deck-logo-dark.svg +1 -0
- package/src/brand/deck-logo-light.svg +1 -0
- package/src/brand/deck-logo-stacked.svg +1 -0
- package/src/brand/deck-logo.svg +1 -0
- package/src/brand/deck-mark.svg +7 -0
- package/src/brand/deck-og.png +0 -0
- package/src/brand/sources.json +7 -0
- package/src/deck-icons.svg +184 -0
- package/src/js/deck-adapters.js +482 -0
- package/src/js/deck-extras.js +823 -0
- package/src/js/deck.js +1331 -0
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
Deck — 26 Performance and drag
|
|
3
|
+
The usual answer to a ten thousand row grid is a virtualization library:
|
|
4
|
+
measure the viewport, render a window of rows, absolutely position a
|
|
5
|
+
spacer, and reconcile on every scroll frame. It works, it costs about five
|
|
6
|
+
kilobytes, and it breaks find-in-page, printing, accessibility tree order,
|
|
7
|
+
and text selection across the boundary.
|
|
8
|
+
|
|
9
|
+
content-visibility does the same job in the engine. Off-screen subtrees are
|
|
10
|
+
skipped during layout, style, paint, and hit testing, but they stay in the
|
|
11
|
+
DOM, so Ctrl+F still finds them, the print stylesheet still prints them,
|
|
12
|
+
and a screen reader still reads them. It needs one line of CSS and no
|
|
13
|
+
JavaScript at all.
|
|
14
|
+
========================================================================== */
|
|
15
|
+
|
|
16
|
+
@layer deck.components {
|
|
17
|
+
|
|
18
|
+
/* --- Virtualized rows ----------------------------------------------------
|
|
19
|
+
contain-intrinsic-size is the placeholder height for a skipped row. Get it
|
|
20
|
+
roughly right and the scrollbar is stable; the `auto` keyword makes the
|
|
21
|
+
browser remember the real height once a row has been rendered once.
|
|
22
|
+
---------------------------------------------------------------------- */
|
|
23
|
+
.dg-virtual tbody tr {
|
|
24
|
+
content-visibility: auto;
|
|
25
|
+
contain-intrinsic-size: auto var(--dg-row-h, 44px);
|
|
26
|
+
}
|
|
27
|
+
.dg-virtual.dg-compact tbody tr { contain-intrinsic-size: auto 34px; }
|
|
28
|
+
.dg-virtual.dg-comfy tbody tr { contain-intrinsic-size: auto 56px; }
|
|
29
|
+
|
|
30
|
+
/* Skips layout, style and paint for offscreen rows with
|
|
31
|
+
content-visibility, using contain-intrinsic-size as the placeholder
|
|
32
|
+
height. One class, no windowing library. If your rows are not 56px,
|
|
33
|
+
override the intrinsic size or the scrollbar will jump. */
|
|
34
|
+
.list-virtual > .list-row {
|
|
35
|
+
content-visibility: auto;
|
|
36
|
+
contain-intrinsic-size: auto 56px;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/* Any long stack of cards: an activity feed, a chat log, search results */
|
|
40
|
+
.virtual > * {
|
|
41
|
+
content-visibility: auto;
|
|
42
|
+
contain-intrinsic-size: auto var(--item-size, 120px);
|
|
43
|
+
}
|
|
44
|
+
.virtual-sm > * { --item-size: 64px; }
|
|
45
|
+
.virtual-lg > * { --item-size: 220px; }
|
|
46
|
+
|
|
47
|
+
/* Whole sections below the fold. Cheap and safe on any page. */
|
|
48
|
+
.defer {
|
|
49
|
+
content-visibility: auto;
|
|
50
|
+
contain-intrinsic-size: auto 600px;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Printing must render everything, or half the report comes out blank */
|
|
54
|
+
@media print {
|
|
55
|
+
.dg-virtual tbody tr, .list-virtual > .list-row, .virtual > *, .defer {
|
|
56
|
+
content-visibility: visible !important;
|
|
57
|
+
contain-intrinsic-size: none !important;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/* --- Containment ---------------------------------------------------------
|
|
62
|
+
Tell the engine that a component's layout cannot affect anything outside
|
|
63
|
+
it. On a dashboard with twenty cards this is the difference between one
|
|
64
|
+
layout pass and twenty.
|
|
65
|
+
---------------------------------------------------------------------- */
|
|
66
|
+
.contain { contain: layout style; }
|
|
67
|
+
.contain-paint { contain: layout style paint; }
|
|
68
|
+
.card, .panel, .list, .dg-wrap, .chart { contain: layout style; }
|
|
69
|
+
|
|
70
|
+
/* --- Drag and drop -------------------------------------------------------
|
|
71
|
+
Deck styles the states; deck-adapters.js drives them with SortableJS when
|
|
72
|
+
it is present, or with the native HTML drag and drop API when it is not.
|
|
73
|
+
The class names are SortableJS's defaults, so no configuration is needed.
|
|
74
|
+
---------------------------------------------------------------------- */
|
|
75
|
+
.sortable { position: relative; }
|
|
76
|
+
.sortable [draggable="true"], .drag-handle { cursor: grab; touch-action: none; }
|
|
77
|
+
.sortable [draggable="true"]:active, .drag-handle:active { cursor: grabbing; }
|
|
78
|
+
|
|
79
|
+
.drag-handle {
|
|
80
|
+
display: grid;
|
|
81
|
+
place-items: center;
|
|
82
|
+
inline-size: 28px;
|
|
83
|
+
min-block-size: var(--tap);
|
|
84
|
+
color: var(--text-faint);
|
|
85
|
+
flex: 0 0 auto;
|
|
86
|
+
opacity: 0;
|
|
87
|
+
transition: opacity var(--dur-1) var(--ease-out), color var(--dur-1) var(--ease-out);
|
|
88
|
+
}
|
|
89
|
+
:is(.list-row, .dg tbody tr, .kanban-card):is(:hover, :focus-within) .drag-handle { opacity: 1; }
|
|
90
|
+
.drag-handle:hover { color: var(--text); }
|
|
91
|
+
@media (pointer: coarse) { .drag-handle { opacity: 1; } }
|
|
92
|
+
|
|
93
|
+
/* The item being dragged, following the pointer */
|
|
94
|
+
.sortable-drag {
|
|
95
|
+
opacity: 1 !important;
|
|
96
|
+
box-shadow: var(--shadow-4);
|
|
97
|
+
rotate: 1.5deg;
|
|
98
|
+
scale: 1.02;
|
|
99
|
+
cursor: grabbing;
|
|
100
|
+
}
|
|
101
|
+
/* The gap left where the item will land */
|
|
102
|
+
.sortable-ghost {
|
|
103
|
+
opacity: .4;
|
|
104
|
+
background: var(--brand-soft) !important;
|
|
105
|
+
outline: 2px dashed var(--brand-400);
|
|
106
|
+
outline-offset: -2px;
|
|
107
|
+
}
|
|
108
|
+
.sortable-ghost > * { visibility: hidden; }
|
|
109
|
+
.sortable-chosen { background: var(--surface-hover); }
|
|
110
|
+
.sortable-fallback { opacity: .9; }
|
|
111
|
+
|
|
112
|
+
/* A list that is accepting a drop */
|
|
113
|
+
.drop-target {
|
|
114
|
+
outline: 2px dashed var(--brand-400);
|
|
115
|
+
outline-offset: 3px;
|
|
116
|
+
border-radius: var(--r-md);
|
|
117
|
+
background: color-mix(in oklab, var(--brand-soft) 55%, transparent);
|
|
118
|
+
}
|
|
119
|
+
.drop-reject { outline-color: var(--bad-500); background: color-mix(in oklab, var(--bad-100) 55%, transparent); }
|
|
120
|
+
|
|
121
|
+
/* --- Kanban --------------------------------------------------------------
|
|
122
|
+
The obvious thing to build once you have drag and drop. An issue queue by
|
|
123
|
+
status is the same shape as a board.
|
|
124
|
+
---------------------------------------------------------------------- */
|
|
125
|
+
.kanban {
|
|
126
|
+
display: flex;
|
|
127
|
+
gap: var(--space-4);
|
|
128
|
+
overflow-x: auto;
|
|
129
|
+
overscroll-behavior-inline: contain;
|
|
130
|
+
padding-block-end: var(--space-3);
|
|
131
|
+
align-items: flex-start;
|
|
132
|
+
scroll-snap-type: x proximity;
|
|
133
|
+
}
|
|
134
|
+
/* One column: a fixed width with a viewport cap so a phone still shows a
|
|
135
|
+
sliver of the next, capped in height by --kanban-height. */
|
|
136
|
+
.kanban-col {
|
|
137
|
+
flex: 0 0 min(19rem, 82vw);
|
|
138
|
+
scroll-snap-align: start;
|
|
139
|
+
display: flex;
|
|
140
|
+
flex-direction: column;
|
|
141
|
+
max-block-size: var(--kanban-height, 70dvh);
|
|
142
|
+
background: var(--bg-sunken);
|
|
143
|
+
border: 1px solid var(--line);
|
|
144
|
+
border-radius: var(--r-md);
|
|
145
|
+
}
|
|
146
|
+
/* The column title and count, outside the scrolling area so they stay
|
|
147
|
+
visible while cards scroll. */
|
|
148
|
+
.kanban-head {
|
|
149
|
+
display: flex;
|
|
150
|
+
align-items: center;
|
|
151
|
+
gap: var(--space-2);
|
|
152
|
+
padding: var(--space-3) var(--space-4);
|
|
153
|
+
border-block-end: 1px solid var(--line);
|
|
154
|
+
font-size: var(--text-sm);
|
|
155
|
+
font-weight: 620;
|
|
156
|
+
position: sticky;
|
|
157
|
+
inset-block-start: 0;
|
|
158
|
+
background: inherit;
|
|
159
|
+
border-start-start-radius: var(--r-md);
|
|
160
|
+
border-start-end-radius: var(--r-md);
|
|
161
|
+
z-index: 1;
|
|
162
|
+
}
|
|
163
|
+
.kanban-count {
|
|
164
|
+
margin-inline-start: auto;
|
|
165
|
+
font-size: var(--text-xs);
|
|
166
|
+
font-weight: 600;
|
|
167
|
+
color: var(--text-muted);
|
|
168
|
+
background: var(--surface);
|
|
169
|
+
border: 1px solid var(--line);
|
|
170
|
+
border-radius: var(--r-full);
|
|
171
|
+
padding: 1px 7px;
|
|
172
|
+
font-variant-numeric: tabular-nums;
|
|
173
|
+
}
|
|
174
|
+
/* The scrolling card region, with a 5rem floor so an empty column is still
|
|
175
|
+
something you can drop onto. */
|
|
176
|
+
.kanban-body {
|
|
177
|
+
flex: 1 1 auto;
|
|
178
|
+
overflow-y: auto;
|
|
179
|
+
overscroll-behavior: contain;
|
|
180
|
+
padding: var(--space-3);
|
|
181
|
+
display: flex;
|
|
182
|
+
flex-direction: column;
|
|
183
|
+
gap: var(--space-3);
|
|
184
|
+
min-block-size: 5rem;
|
|
185
|
+
}
|
|
186
|
+
/* One card. .kanban-card-title is styling, not a heading — if the card
|
|
187
|
+
opens something, make the title a link. */
|
|
188
|
+
.kanban-card {
|
|
189
|
+
background: var(--surface);
|
|
190
|
+
border: 1px solid var(--line);
|
|
191
|
+
border-radius: var(--r-sm);
|
|
192
|
+
padding: var(--space-3);
|
|
193
|
+
box-shadow: var(--shadow-1);
|
|
194
|
+
display: flex;
|
|
195
|
+
flex-direction: column;
|
|
196
|
+
gap: var(--space-2);
|
|
197
|
+
content-visibility: auto;
|
|
198
|
+
contain-intrinsic-size: auto 110px;
|
|
199
|
+
}
|
|
200
|
+
.kanban-card:hover { box-shadow: var(--shadow-2); }
|
|
201
|
+
.kanban-card-title { font-size: var(--text-sm); font-weight: 580; }
|
|
202
|
+
.kanban-card-meta {
|
|
203
|
+
display: flex;
|
|
204
|
+
align-items: center;
|
|
205
|
+
gap: var(--space-2);
|
|
206
|
+
font-size: var(--text-xs);
|
|
207
|
+
color: var(--text-muted);
|
|
208
|
+
}
|
|
209
|
+
/* Shown in an empty column and hidden by :has(.kanban-card) as soon as one
|
|
210
|
+
arrives, so nothing has to remember to toggle it. */
|
|
211
|
+
.kanban-empty {
|
|
212
|
+
border: 1px dashed var(--line-strong);
|
|
213
|
+
border-radius: var(--r-sm);
|
|
214
|
+
padding: var(--space-5);
|
|
215
|
+
text-align: center;
|
|
216
|
+
color: var(--text-faint);
|
|
217
|
+
font-size: var(--text-sm);
|
|
218
|
+
}
|
|
219
|
+
.kanban-col:has(.kanban-card) .kanban-empty { display: none; }
|
|
220
|
+
|
|
221
|
+
/* --- Reorderable list ----------------------------------------------------- */
|
|
222
|
+
.reorder .list-row { user-select: none; }
|
|
223
|
+
.reorder .list-row.is-lifted {
|
|
224
|
+
box-shadow: var(--shadow-3);
|
|
225
|
+
background: var(--surface);
|
|
226
|
+
border-radius: var(--r-sm);
|
|
227
|
+
z-index: 2;
|
|
228
|
+
position: relative;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
@media (prefers-reduced-motion: reduce) {
|
|
232
|
+
.sortable-drag { rotate: none; scale: 1; }
|
|
233
|
+
}
|
|
234
|
+
}
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
Deck — 15 Print
|
|
3
|
+
Real work still gets printed. Invoices, packing slips, purchase orders, and
|
|
4
|
+
reports all end up on paper or in a PDF, so this is a real stylesheet and
|
|
5
|
+
not an afterthought.
|
|
6
|
+
========================================================================== */
|
|
7
|
+
|
|
8
|
+
@layer deck.print {
|
|
9
|
+
|
|
10
|
+
@page {
|
|
11
|
+
size: letter;
|
|
12
|
+
margin: 16mm 14mm;
|
|
13
|
+
}
|
|
14
|
+
@page :first { margin-block-start: 12mm; }
|
|
15
|
+
|
|
16
|
+
@media print {
|
|
17
|
+
|
|
18
|
+
/* --- Force the light palette. Dark mode is a screen idea. -------------- */
|
|
19
|
+
:root {
|
|
20
|
+
color-scheme: light only;
|
|
21
|
+
--bg: #fff;
|
|
22
|
+
--bg-sunken: #fff;
|
|
23
|
+
--surface: #fff;
|
|
24
|
+
--surface-2: #fff;
|
|
25
|
+
--surface-hover: #fff;
|
|
26
|
+
--text: #000;
|
|
27
|
+
--text-muted: #333;
|
|
28
|
+
--text-faint: #555;
|
|
29
|
+
--line: #bbb;
|
|
30
|
+
--line-strong: #888;
|
|
31
|
+
--shadow-1: none; --shadow-2: none; --shadow-3: none; --shadow-4: none;
|
|
32
|
+
--shadow-inset: none;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
html, body {
|
|
36
|
+
background: #fff !important;
|
|
37
|
+
color: #000 !important;
|
|
38
|
+
font-size: 10.5pt;
|
|
39
|
+
line-height: 1.4;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
body { padding-block-end: 0 !important; }
|
|
43
|
+
|
|
44
|
+
* {
|
|
45
|
+
box-shadow: none !important;
|
|
46
|
+
text-shadow: none !important;
|
|
47
|
+
backdrop-filter: none !important;
|
|
48
|
+
-webkit-backdrop-filter: none !important;
|
|
49
|
+
animation: none !important;
|
|
50
|
+
transition: none !important;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Keep intentional fills — badges, status chips, chart series */
|
|
54
|
+
.badge, .chip, .chart-col, .chart-col-stack > span, .chart-bar-fill,
|
|
55
|
+
.chart-meter > span, .donut, .icon-tile, .avatar, .chart-heat > * {
|
|
56
|
+
-webkit-print-color-adjust: exact;
|
|
57
|
+
print-color-adjust: exact;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/* --- Chrome that should never print ------------------------------------ */
|
|
61
|
+
.tabbar, .fab, .speed-dial, .back-to-top, .toast-region, .skip-link, .theme-dock,
|
|
62
|
+
.navbar-links, .sidebar, .datepicker, .combo-list, .menu,
|
|
63
|
+
.dg-toolbar, .dg-resize, .sheet-grip, .no-print,
|
|
64
|
+
.pagination, .segmented, .tabs, .scroller::-webkit-scrollbar {
|
|
65
|
+
display: none !important;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/* Dialogs print only if they are actually open, and then as a block */
|
|
69
|
+
dialog:not([open]) { display: none !important; }
|
|
70
|
+
dialog[open] {
|
|
71
|
+
position: static !important;
|
|
72
|
+
display: block !important;
|
|
73
|
+
max-block-size: none !important;
|
|
74
|
+
inline-size: auto !important;
|
|
75
|
+
border: 0 !important;
|
|
76
|
+
}
|
|
77
|
+
dialog::backdrop { display: none !important; }
|
|
78
|
+
|
|
79
|
+
/* --- Layout ------------------------------------------------------------ */
|
|
80
|
+
.container, .container-sm, .container-md, .container-lg, .container-xl {
|
|
81
|
+
max-inline-size: none !important;
|
|
82
|
+
padding-inline: 0 !important;
|
|
83
|
+
}
|
|
84
|
+
.section { padding-block: 0 0 8mm !important; }
|
|
85
|
+
.split { display: block !important; }
|
|
86
|
+
.grid { display: block !important; }
|
|
87
|
+
.grid > * + * { margin-block-start: 4mm; }
|
|
88
|
+
.sticky-top, .sticky, .form-actions-sticky { position: static !important; }
|
|
89
|
+
|
|
90
|
+
/* --- Surfaces ---------------------------------------------------------- */
|
|
91
|
+
.card, .panel, .list, .table-wrap, .dg-wrap, .alert, .fieldset {
|
|
92
|
+
border: 1px solid #bbb !important;
|
|
93
|
+
border-radius: 0 !important;
|
|
94
|
+
background: #fff !important;
|
|
95
|
+
break-inside: avoid;
|
|
96
|
+
max-block-size: none !important;
|
|
97
|
+
overflow: visible !important;
|
|
98
|
+
}
|
|
99
|
+
.card-footer, .list-header, .dg thead th, .table thead th {
|
|
100
|
+
background: #f2f2f2 !important;
|
|
101
|
+
-webkit-print-color-adjust: exact;
|
|
102
|
+
print-color-adjust: exact;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* --- Type -------------------------------------------------------------- */
|
|
106
|
+
h1, .h1 { font-size: 20pt; }
|
|
107
|
+
h2, .h2 { font-size: 15pt; }
|
|
108
|
+
h3, .h3 { font-size: 12.5pt; }
|
|
109
|
+
h4, .h4, h5, .h5, h6, .h6 { font-size: 11pt; }
|
|
110
|
+
.display { font-size: 22pt; }
|
|
111
|
+
.lede { font-size: 11pt; color: #333 !important; }
|
|
112
|
+
|
|
113
|
+
h1, h2, h3, h4, h5, h6 { break-after: avoid; page-break-after: avoid; }
|
|
114
|
+
p, blockquote, li, figure, .stat, .timeline-item { break-inside: avoid; }
|
|
115
|
+
.prose { max-inline-size: none; }
|
|
116
|
+
|
|
117
|
+
/* Show where a link actually goes, but not for anchors or JS handles */
|
|
118
|
+
a { color: #000 !important; text-decoration: underline; }
|
|
119
|
+
a[href^="http"]::after {
|
|
120
|
+
content: " (" attr(href) ")";
|
|
121
|
+
font-size: 8.5pt;
|
|
122
|
+
color: #555;
|
|
123
|
+
word-break: break-all;
|
|
124
|
+
}
|
|
125
|
+
a[href^="#"]::after, a[href^="javascript:"]::after, .btn::after, .no-print-url::after { content: ""; }
|
|
126
|
+
|
|
127
|
+
abbr[title]::after { content: " (" attr(title) ")"; font-size: 8.5pt; }
|
|
128
|
+
|
|
129
|
+
/* --- Tables ------------------------------------------------------------ */
|
|
130
|
+
.table, .dg { inline-size: 100% !important; font-size: 9.5pt; }
|
|
131
|
+
.table thead, .dg thead { display: table-header-group; }
|
|
132
|
+
.dg tfoot, .table tfoot { display: table-footer-group; }
|
|
133
|
+
.table tr, .dg tr { break-inside: avoid; page-break-inside: avoid; }
|
|
134
|
+
.dg :is(th, td) {
|
|
135
|
+
position: static !important;
|
|
136
|
+
block-size: auto !important;
|
|
137
|
+
padding: 4pt 6pt !important;
|
|
138
|
+
white-space: normal !important;
|
|
139
|
+
clip-path: none !important;
|
|
140
|
+
border-block-end: 1px solid #ddd !important;
|
|
141
|
+
}
|
|
142
|
+
.dg-wrap { max-block-size: none !important; overflow: visible !important; }
|
|
143
|
+
|
|
144
|
+
/* The mobile card fallbacks are a screen behaviour, not a paper one */
|
|
145
|
+
.table-stack thead, .dg-cards thead {
|
|
146
|
+
position: static !important;
|
|
147
|
+
inline-size: auto !important;
|
|
148
|
+
block-size: auto !important;
|
|
149
|
+
clip-path: none !important;
|
|
150
|
+
display: table-header-group !important;
|
|
151
|
+
overflow: visible !important;
|
|
152
|
+
}
|
|
153
|
+
.table-stack, .dg-cards { display: table !important; }
|
|
154
|
+
.table-stack tbody, .dg-cards tbody { display: table-row-group !important; }
|
|
155
|
+
.table-stack tr, .dg-cards tr { display: table-row !important; margin: 0 !important; border-radius: 0 !important; }
|
|
156
|
+
.table-stack td, .dg-cards td { display: table-cell !important; text-align: start !important; }
|
|
157
|
+
.table-stack td::before, .dg-cards td::before { content: none !important; }
|
|
158
|
+
|
|
159
|
+
/* --- Forms ------------------------------------------------------------- */
|
|
160
|
+
.input, .textarea, .select, .combo-control {
|
|
161
|
+
border: 1px solid #999 !important;
|
|
162
|
+
background: #fff !important;
|
|
163
|
+
min-block-size: auto !important;
|
|
164
|
+
}
|
|
165
|
+
.textarea { max-block-size: none !important; block-size: auto !important; }
|
|
166
|
+
.select { background-image: none !important; padding-inline-end: var(--space-3) !important; }
|
|
167
|
+
.btn, .form-actions { display: none !important; }
|
|
168
|
+
.btn.print-keep { display: inline-flex !important; border: 1px solid #999 !important; }
|
|
169
|
+
|
|
170
|
+
/* Checkboxes print as boxes with a mark, not as filled squares */
|
|
171
|
+
.check input[type="checkbox"], .check input[type="radio"] {
|
|
172
|
+
-webkit-print-color-adjust: exact;
|
|
173
|
+
print-color-adjust: exact;
|
|
174
|
+
border: 1px solid #000 !important;
|
|
175
|
+
background: #fff !important;
|
|
176
|
+
}
|
|
177
|
+
.check input:checked { background: #000 !important; border-color: #000 !important; }
|
|
178
|
+
.switch input { border: 1px solid #000 !important; }
|
|
179
|
+
|
|
180
|
+
/* --- Charts ------------------------------------------------------------ */
|
|
181
|
+
.chart, .chart-columns, .chart-svg { break-inside: avoid; }
|
|
182
|
+
.chart-col[data-value]::before { display: none !important; }
|
|
183
|
+
.chart-columns { background-image: none !important; border-block-end: 1px solid #999; }
|
|
184
|
+
|
|
185
|
+
/* --- Page break helpers ------------------------------------------------ */
|
|
186
|
+
.page-break { break-before: page; page-break-before: always; }
|
|
187
|
+
.page-break-after { break-after: page; page-break-after: always; }
|
|
188
|
+
.keep-together { break-inside: avoid; page-break-inside: avoid; }
|
|
189
|
+
.print-only { display: revert !important; }
|
|
190
|
+
|
|
191
|
+
/* Repeat a header on every page of a long report */
|
|
192
|
+
.print-header { position: fixed; inset-block-start: 0; inset-inline: 0; }
|
|
193
|
+
.print-footer { position: fixed; inset-block-end: 0; inset-inline: 0; font-size: 8.5pt; color: #555; }
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/* Hidden on screen, shown on paper */
|
|
197
|
+
.print-only { display: none; }
|
|
198
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
/* ==========================================================================
|
|
2
|
+
Deck — 02 Reset
|
|
3
|
+
========================================================================== */
|
|
4
|
+
|
|
5
|
+
@layer deck.reset {
|
|
6
|
+
|
|
7
|
+
*, *::before, *::after { box-sizing: border-box; }
|
|
8
|
+
|
|
9
|
+
* { margin: 0; }
|
|
10
|
+
|
|
11
|
+
html {
|
|
12
|
+
-webkit-text-size-adjust: 100%;
|
|
13
|
+
-moz-text-size-adjust: 100%;
|
|
14
|
+
text-size-adjust: 100%;
|
|
15
|
+
tab-size: 2;
|
|
16
|
+
scroll-behavior: smooth;
|
|
17
|
+
scroll-padding-block-start: calc(var(--control-h-lg) + var(--space-4));
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
body {
|
|
21
|
+
min-block-size: 100dvh;
|
|
22
|
+
background: var(--bg);
|
|
23
|
+
color: var(--text);
|
|
24
|
+
font-family: var(--font-sans);
|
|
25
|
+
font-size: var(--text-base);
|
|
26
|
+
line-height: var(--leading-normal);
|
|
27
|
+
font-synthesis-weight: none;
|
|
28
|
+
-webkit-font-smoothing: antialiased;
|
|
29
|
+
text-rendering: optimizeLegibility;
|
|
30
|
+
overflow-wrap: break-word;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
img, svg, video, canvas, audio, iframe, embed, object {
|
|
34
|
+
display: block;
|
|
35
|
+
max-inline-size: 100%;
|
|
36
|
+
}
|
|
37
|
+
img, video { block-size: auto; }
|
|
38
|
+
|
|
39
|
+
input, button, textarea, select { font: inherit; color: inherit; }
|
|
40
|
+
|
|
41
|
+
button { background: none; border: 0; }
|
|
42
|
+
|
|
43
|
+
p, li, figcaption { text-wrap: pretty; }
|
|
44
|
+
h1, h2, h3, h4, h5, h6 { text-wrap: balance; }
|
|
45
|
+
|
|
46
|
+
ul[class], ol[class] { list-style: none; padding: 0; }
|
|
47
|
+
|
|
48
|
+
table { border-collapse: collapse; border-spacing: 0; }
|
|
49
|
+
|
|
50
|
+
hr {
|
|
51
|
+
border: 0;
|
|
52
|
+
block-size: 1px;
|
|
53
|
+
background: var(--line);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
:target { scroll-margin-block-start: var(--space-16); }
|
|
57
|
+
|
|
58
|
+
::selection {
|
|
59
|
+
background: var(--brand-200);
|
|
60
|
+
color: var(--ink-950);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/* One focus treatment for the whole framework */
|
|
64
|
+
:focus-visible {
|
|
65
|
+
outline: 2px solid var(--focus);
|
|
66
|
+
outline-offset: 2px;
|
|
67
|
+
border-radius: var(--r-xs);
|
|
68
|
+
}
|
|
69
|
+
:focus:not(:focus-visible) { outline: none; }
|
|
70
|
+
|
|
71
|
+
/* Firefox needs help with the scrollbar; WebKit gets the thin version */
|
|
72
|
+
* { scrollbar-color: var(--ink-300) transparent; scrollbar-width: thin; }
|
|
73
|
+
::-webkit-scrollbar { inline-size: 10px; block-size: 10px; }
|
|
74
|
+
::-webkit-scrollbar-thumb {
|
|
75
|
+
background: var(--ink-300);
|
|
76
|
+
border-radius: var(--r-full);
|
|
77
|
+
border: 3px solid transparent;
|
|
78
|
+
background-clip: content-box;
|
|
79
|
+
}
|
|
80
|
+
::-webkit-scrollbar-thumb:hover { background: var(--ink-400); background-clip: content-box; }
|
|
81
|
+
|
|
82
|
+
@media (prefers-reduced-motion: reduce) {
|
|
83
|
+
html { scroll-behavior: auto; }
|
|
84
|
+
*, *::before, *::after {
|
|
85
|
+
animation-duration: .01ms !important;
|
|
86
|
+
animation-iteration-count: 1 !important;
|
|
87
|
+
transition-duration: .01ms !important;
|
|
88
|
+
scroll-behavior: auto !important;
|
|
89
|
+
}
|
|
90
|
+
/* Loading indicators keep moving, slowly. A frozen spinner reads as broken,
|
|
91
|
+
and progress feedback is information, not decoration. */
|
|
92
|
+
.spinner, .icon-spin, .skeleton, .marquee-track, .btn.is-loading::after,
|
|
93
|
+
.dg-wrap.is-loading::after, .ping::after {
|
|
94
|
+
animation-duration: 2.4s !important;
|
|
95
|
+
animation-iteration-count: infinite !important;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* Opt in per-element where a smooth auto height matters */
|
|
100
|
+
@supports (interpolate-size: allow-keywords) {
|
|
101
|
+
:root { interpolate-size: allow-keywords; }
|
|
102
|
+
}
|
|
103
|
+
}
|