@aparte/core 0.16.7 → 0.16.8
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/dist/components/bubble/aparte-chat-bubble.d.ts +33 -18
- package/dist/components/bubble/aparte-chat-bubble.d.ts.map +1 -1
- package/dist/components/chat/aparte-chat.d.ts +32 -25
- package/dist/components/chat/aparte-chat.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-action.d.ts +1 -1
- package/dist/components/composer/aparte-composer-add-attachment.d.ts +1 -1
- package/dist/components/composer/aparte-composer-attachments.d.ts +1 -1
- package/dist/components/composer/aparte-composer-cancel.d.ts +2 -2
- package/dist/components/composer/aparte-composer-cancel.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer-input.d.ts +6 -6
- package/dist/components/composer/aparte-composer-send.d.ts +3 -3
- package/dist/components/composer/aparte-composer-send.d.ts.map +1 -1
- package/dist/components/composer/aparte-composer.d.ts +9 -2
- package/dist/components/composer/aparte-composer.d.ts.map +1 -1
- package/dist/components/context/aparte-context.d.ts +0 -1
- package/dist/components/context/aparte-context.d.ts.map +1 -1
- package/dist/components/conversation-list/aparte-conversation-list.d.ts +6 -6
- package/dist/components/elicitation/aparte-elicitation.d.ts +20 -18
- package/dist/components/elicitation/aparte-elicitation.d.ts.map +1 -1
- package/dist/components/scroll-rail/aparte-scroll-rail.d.ts +9 -2
- package/dist/components/scroll-rail/aparte-scroll-rail.d.ts.map +1 -1
- package/dist/components/sidebar/aparte-sidebar.d.ts +16 -2
- package/dist/components/sidebar/aparte-sidebar.d.ts.map +1 -1
- package/dist/components/split/aparte-split.d.ts +9 -4
- package/dist/components/split/aparte-split.d.ts.map +1 -1
- package/dist/components/status/aparte-chat-status.d.ts +3 -2
- package/dist/components/status/aparte-chat-status.d.ts.map +1 -1
- package/dist/components/viewport/aparte-chat-viewport.d.ts +27 -4
- package/dist/components/viewport/aparte-chat-viewport.d.ts.map +1 -1
- package/dist/config/icon-provider.d.ts +6 -0
- package/dist/config/icon-provider.d.ts.map +1 -1
- package/dist/config/locale.d.ts +3 -1
- package/dist/config/locale.d.ts.map +1 -1
- package/dist/custom-elements.json +11304 -11171
- package/dist/{dialog-triggers-Dw_DIlQ7.js → dialog-triggers-D8wNICrT.js} +24 -19
- package/dist/dialog-triggers-D8wNICrT.js.map +1 -0
- package/dist/generated/element-attributes.d.ts +13 -3
- package/dist/generated/element-attributes.d.ts.map +1 -1
- package/dist/{glyphs-DQTeOj4w.js → glyphs-C8z2oJUg.js} +36 -27
- package/dist/{glyphs-DQTeOj4w.js.map → glyphs-C8z2oJUg.js.map} +1 -1
- package/dist/icons/extended.d.ts +0 -6
- package/dist/icons/extended.d.ts.map +1 -1
- package/dist/icons/glyphs.d.ts +13 -4
- package/dist/icons/glyphs.d.ts.map +1 -1
- package/dist/icons.js +28 -31
- package/dist/icons.js.map +1 -1
- package/dist/index.css +831 -359
- package/dist/index.js +176 -54
- package/dist/index.js.map +1 -1
- package/dist/index.node.js +1 -1
- package/dist/primitives/icon/aparte-icon.d.ts +1 -1
- package/dist/primitives/progress-spinner/aparte-progress-spinner.d.ts +2 -3
- package/dist/primitives/progress-spinner/aparte-progress-spinner.d.ts.map +1 -1
- package/dist/primitives/select/aparte-optgroup.d.ts +1 -1
- package/dist/primitives/select/aparte-optgroup.d.ts.map +1 -1
- package/dist/primitives/select/aparte-option.d.ts +4 -4
- package/dist/primitives/select/aparte-option.d.ts.map +1 -1
- package/dist/primitives/select/aparte-select.d.ts +21 -12
- package/dist/primitives/select/aparte-select.d.ts.map +1 -1
- package/dist/renderers/segments/code.d.ts.map +1 -1
- package/dist/renderers/segments/error.d.ts.map +1 -1
- package/dist/renderers/segments/thinking.d.ts.map +1 -1
- package/dist/renderers/segments/tool-call.d.ts.map +1 -1
- package/package.json +2 -2
- package/dist/dialog-triggers-Dw_DIlQ7.js.map +0 -1
package/dist/index.css
CHANGED
|
@@ -183,7 +183,6 @@
|
|
|
183
183
|
below (it was a frozen plum hex that outlived every rebrand); the assistant is
|
|
184
184
|
plain prose (AI-chat convention) — flip it to get a two-bubble chat-app look. */
|
|
185
185
|
--aparte-message-content-bg-assistant: transparent;
|
|
186
|
-
--aparte-message-content-radius: 14px;
|
|
187
186
|
|
|
188
187
|
/* Aliases used by some segment renderers (artifact card, tool pill).
|
|
189
188
|
Mapped to existing tokens so consumers that override --aparte-surface-1/2
|
|
@@ -206,8 +205,6 @@
|
|
|
206
205
|
--aparte-thumb-remove-bg-hover: rgba(0, 0, 0, 0.85);
|
|
207
206
|
--aparte-thumb-remove-color: #ffffff;
|
|
208
207
|
|
|
209
|
-
/* Action Bar */
|
|
210
|
-
--aparte-action-bar-btn-size: 28px;
|
|
211
208
|
/* The mark (display/mark.css): how much of its intent a marked row's ground takes,
|
|
212
209
|
and how wide the bar on its start edge is. One pair for the select's chosen option,
|
|
213
210
|
the checked field choice, the active conversation and an answered question. */
|
|
@@ -215,12 +212,16 @@
|
|
|
215
212
|
--aparte-mark-bar: 2px;
|
|
216
213
|
|
|
217
214
|
/* Branch Picker */
|
|
218
|
-
--aparte-branch-picker-btn-size: 20px;
|
|
219
|
-
--aparte-branch-picker-btn-icon-size: 16px;
|
|
220
215
|
--aparte-branch-picker-label-min-width: 32px;
|
|
221
216
|
|
|
222
217
|
/* Avatars */
|
|
223
218
|
--aparte-avatar-size: 32px;
|
|
219
|
+
/* Fractions of the size, computed on the element (display/avatar.css): the initials'
|
|
220
|
+
type, the corner and the group's overlap follow the ramp instead of sitting at one
|
|
221
|
+
absolute value for 20px and 56px alike. */
|
|
222
|
+
--aparte-avatar-initials-ratio: 0.34;
|
|
223
|
+
--aparte-avatar-radius-ratio: 0.28;
|
|
224
|
+
--aparte-avatar-overlap-ratio: 0.28;
|
|
224
225
|
--aparte-avatar-image-user: none;
|
|
225
226
|
--aparte-avatar-image-assistant: none;
|
|
226
227
|
--aparte-avatar-image-size: 90%;
|
|
@@ -230,21 +231,18 @@
|
|
|
230
231
|
/* Input */
|
|
231
232
|
--aparte-input-editor-max-height: 200px;
|
|
232
233
|
|
|
233
|
-
/* Icons
|
|
234
|
-
|
|
235
|
-
--aparte-icon-size-sm: 12px;
|
|
236
|
-
--aparte-icon-size-lg: 16px;
|
|
237
|
-
--aparte-icon-size-xl: 20px;
|
|
234
|
+
/* Icons: one knob, inherited — a container declares `--aparte-icon-size` and every
|
|
235
|
+
glyph below follows. The steps are on the type scale, in the derived layer. */
|
|
238
236
|
|
|
239
|
-
/* Send button + inline action buttons */
|
|
240
|
-
--aparte-send-btn-size: 36px;
|
|
241
|
-
--aparte-input-action-btn-size: 36px;
|
|
237
|
+
/* Send button + inline action buttons (their size is the lg step, in the derived layer) */
|
|
242
238
|
--aparte-input-action-btn-icon-size: 20px;
|
|
243
239
|
--aparte-model-select-min-width: 120px;
|
|
244
240
|
|
|
245
241
|
/* Status Indicator */
|
|
246
242
|
--aparte-status-bg: transparent;
|
|
247
243
|
--aparte-status-dot-size: 6px;
|
|
244
|
+
/* The floor of every pulsing dot's opacity: above the perception threshold. */
|
|
245
|
+
--aparte-pulse-floor: 0.55;
|
|
248
246
|
|
|
249
247
|
/* Waiting Indicator (the bubble's own dots, before the first token) */
|
|
250
248
|
--aparte-waiting-height: 1.5em;
|
|
@@ -252,7 +250,6 @@
|
|
|
252
250
|
/* Thinking Segment */
|
|
253
251
|
--aparte-thinking-content-max-height: 300px;
|
|
254
252
|
--aparte-thinking-content-line-height: 1.55;
|
|
255
|
-
--aparte-thinking-toggle-size: 9px;
|
|
256
253
|
--aparte-thinking-rail-width: 2px;
|
|
257
254
|
|
|
258
255
|
/* Elicitation — the panel a tool's question is asked in.
|
|
@@ -282,8 +279,7 @@
|
|
|
282
279
|
--aparte-code-copy-icon-size: 14px;
|
|
283
280
|
--aparte-code-inline-font-size: 0.875em;
|
|
284
281
|
|
|
285
|
-
/* Scroll-to-bottom button */
|
|
286
|
-
--aparte-scroll-btn-size: 36px;
|
|
282
|
+
/* Scroll-to-bottom button (its size is the lg step, in the derived layer) */
|
|
287
283
|
--aparte-scroll-btn-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
|
288
284
|
|
|
289
285
|
/* Error segment */
|
|
@@ -291,8 +287,6 @@
|
|
|
291
287
|
--aparte-error-border: #fecaca;
|
|
292
288
|
--aparte-error-solid: #dc2626;
|
|
293
289
|
--aparte-error-text: #991b1b;
|
|
294
|
-
--aparte-error-title: #7f1d1d;
|
|
295
|
-
--aparte-error-icon-size: 20px;
|
|
296
290
|
--aparte-error-rail-width: 4px;
|
|
297
291
|
|
|
298
292
|
/* Prose (aparte-segment-content) */
|
|
@@ -327,12 +321,9 @@
|
|
|
327
321
|
|
|
328
322
|
/* Input (composer) */
|
|
329
323
|
|
|
330
|
-
/* Conversation List */
|
|
331
|
-
--aparte-conv-action-btn-size: 20px;
|
|
332
324
|
|
|
333
325
|
/* Scroll rail — the ticks beside the transcript. Off-scale on purpose: a 2px line
|
|
334
326
|
and a 14px mark are a minimap's measures, not spacing steps. */
|
|
335
|
-
--aparte-scroll-rail-width: 20px;
|
|
336
327
|
--aparte-scroll-rail-tick-size: 14px;
|
|
337
328
|
--aparte-scroll-rail-tick-thickness: 2px;
|
|
338
329
|
|
|
@@ -341,7 +332,6 @@
|
|
|
341
332
|
/* Context gauge, ring variant — a diameter, and a stroke in the ring's own 36-unit
|
|
342
333
|
box. Literals like the rail's: a 22px ring is a toolbar's measure, not a spacing step. */
|
|
343
334
|
--aparte-context-ring-size: 22px;
|
|
344
|
-
--aparte-context-ring-stroke: 4;
|
|
345
335
|
|
|
346
336
|
/* Shell — the sidebar's column, the header's row and the split's seam. */
|
|
347
337
|
--aparte-sidebar-width: 260px;
|
|
@@ -353,9 +343,15 @@
|
|
|
353
343
|
is 12px because that is a target, and it grows to the touch target on a coarse
|
|
354
344
|
pointer (responsive.css). */
|
|
355
345
|
--aparte-split-position: 38%;
|
|
356
|
-
|
|
346
|
+
/* Never more than the container has: at 320px this floor was wider than a phone, so
|
|
347
|
+
the primary pane took everything and the end pane was annihilated to 0. */
|
|
348
|
+
--aparte-split-min: min(20rem, 100%);
|
|
357
349
|
--aparte-split-max: 60%;
|
|
358
|
-
|
|
350
|
+
/* The seam's TRACK — the grab zone, and what the grid reserves. The painted line
|
|
351
|
+
inside it is `--aparte-split-seam-width` (derived layer): one token used to size
|
|
352
|
+
both, so the line could not be thinned without moving the layout, and at 4px it
|
|
353
|
+
was four times the kit's rule with no grip — an interaction drawn as a decoration. */
|
|
354
|
+
--aparte-split-handle-size: 12px;
|
|
359
355
|
--aparte-split-hit-area: 12px;
|
|
360
356
|
/* Sizes that are not steps of a scale. Each is off-scale on purpose — a 40px
|
|
361
357
|
file tile is a tile, not fourteen spacing units — so each gets a name rather
|
|
@@ -406,6 +402,9 @@
|
|
|
406
402
|
--aparte-menu-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
407
403
|
--aparte-popover-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 10px 28px rgba(0, 0, 0, 0.16);
|
|
408
404
|
--aparte-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
|
405
|
+
/* The composer laid over the transcript (overlay-composer): a thing that floats has to
|
|
406
|
+
be seen floating, and its ground is the transcript's own. */
|
|
407
|
+
--aparte-composer-overlay-shadow: 0 -4px 16px rgba(0, 0, 0, 0.06);
|
|
409
408
|
--aparte-switch-thumb-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
|
410
409
|
--aparte-range-thumb-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
|
411
410
|
|
|
@@ -444,11 +443,28 @@
|
|
|
444
443
|
--aparte-skeleton-text-last-width: 60%;
|
|
445
444
|
--aparte-progress-indeterminate-width: 40%;
|
|
446
445
|
|
|
446
|
+
/* The control height scale — four steps, and EVERY control reads one: a text
|
|
447
|
+
button used to have no height (23px of padding and line-height) beside 24, 29, 32,
|
|
448
|
+
36 and 44px neighbours, and the 36px family (send, the input's action button, the
|
|
449
|
+
scroll button) lived off the scale as literals. sm is the small control (action bar,
|
|
450
|
+
branch arrows, a row's ⋯), md the default button, lg the field and the composer's
|
|
451
|
+
controls at rest, xl the large button. */
|
|
447
452
|
--aparte-btn-size-sm: 24px;
|
|
448
453
|
--aparte-btn-size-md: 32px;
|
|
449
|
-
--aparte-btn-size-lg:
|
|
454
|
+
--aparte-btn-size-lg: 36px;
|
|
455
|
+
--aparte-btn-size-xl: 40px;
|
|
456
|
+
/* The field family's literal sizes, beside the button's: the derived knobs
|
|
457
|
+
(paddings, radius) sit in the anchored layer below, like the button's own. */
|
|
458
|
+
--aparte-field-textarea-min-height: 80px;
|
|
459
|
+
--aparte-checkbox-size: 18px;
|
|
460
|
+
--aparte-radio-size: 18px;
|
|
461
|
+
--aparte-radio-dot-size: 8px;
|
|
462
|
+
--aparte-switch-width: 40px;
|
|
463
|
+
--aparte-switch-height: 22px;
|
|
464
|
+
--aparte-switch-thumb-inset: 2px;
|
|
465
|
+
--aparte-range-thumb-size: 16px;
|
|
466
|
+
--aparte-range-track-height: 4px;
|
|
450
467
|
|
|
451
|
-
--aparte-focus-outline-offset: -2px;
|
|
452
468
|
--aparte-tool-spinner-size: 10px;
|
|
453
469
|
--aparte-model-select-chevron-room: 28px;
|
|
454
470
|
}
|
|
@@ -482,6 +498,9 @@
|
|
|
482
498
|
--aparte-scroll-btn-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
|
|
483
499
|
--aparte-select-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 10px 28px rgba(0, 0, 0, 0.55);
|
|
484
500
|
--aparte-menu-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
|
|
501
|
+
--aparte-composer-overlay-shadow: 0 -4px 16px rgba(0, 0, 0, 0.4);
|
|
502
|
+
/* Declared once at :root it darkened a dark page by 8/255: the modal state vanished. */
|
|
503
|
+
--aparte-scrim: rgba(0, 0, 0, 0.6);
|
|
485
504
|
--aparte-popover-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 10px 28px rgba(0, 0, 0, 0.55);
|
|
486
505
|
--aparte-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
|
|
487
506
|
--aparte-switch-thumb-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
@@ -491,7 +510,6 @@
|
|
|
491
510
|
--aparte-error-border: #7f1d1d;
|
|
492
511
|
--aparte-error-solid: #f87171;
|
|
493
512
|
--aparte-error-text: #fca5a5;
|
|
494
|
-
--aparte-error-title: #fecaca;
|
|
495
513
|
}
|
|
496
514
|
}
|
|
497
515
|
|
|
@@ -521,6 +539,10 @@
|
|
|
521
539
|
--aparte-menu-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
|
|
522
540
|
--aparte-popover-shadow: 0 1px 3px rgba(0, 0, 0, 0.08), 0 10px 28px rgba(0, 0, 0, 0.16);
|
|
523
541
|
--aparte-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.12);
|
|
542
|
+
/* The composer laid over the transcript (overlay-composer): a thing that floats has to
|
|
543
|
+
be seen floating, and its ground is the transcript's own. */
|
|
544
|
+
--aparte-composer-overlay-shadow: 0 -4px 16px rgba(0, 0, 0, 0.06);
|
|
545
|
+
--aparte-scrim: rgba(0, 0, 0, 0.35);
|
|
524
546
|
--aparte-switch-thumb-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
|
525
547
|
--aparte-range-thumb-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
|
|
526
548
|
--aparte-ink-l: 0.40;
|
|
@@ -528,7 +550,6 @@
|
|
|
528
550
|
--aparte-error-border: #fecaca;
|
|
529
551
|
--aparte-error-solid: #dc2626;
|
|
530
552
|
--aparte-error-text: #991b1b;
|
|
531
|
-
--aparte-error-title: #7f1d1d;
|
|
532
553
|
}
|
|
533
554
|
|
|
534
555
|
|
|
@@ -568,6 +589,8 @@
|
|
|
568
589
|
--aparte-scroll-btn-shadow: 0 2px 12px rgba(0, 0, 0, 0.35);
|
|
569
590
|
--aparte-select-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 10px 28px rgba(0, 0, 0, 0.55);
|
|
570
591
|
--aparte-menu-shadow: 0 4px 12px rgba(0, 0, 0, 0.35);
|
|
592
|
+
--aparte-composer-overlay-shadow: 0 -4px 16px rgba(0, 0, 0, 0.4);
|
|
593
|
+
--aparte-scrim: rgba(0, 0, 0, 0.6);
|
|
571
594
|
--aparte-popover-shadow: 0 1px 3px rgba(0, 0, 0, 0.4), 0 10px 28px rgba(0, 0, 0, 0.55);
|
|
572
595
|
--aparte-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.35);
|
|
573
596
|
--aparte-switch-thumb-shadow: 0 1px 2px rgba(0, 0, 0, 0.4);
|
|
@@ -587,7 +610,6 @@
|
|
|
587
610
|
--aparte-error-border: #7f1d1d;
|
|
588
611
|
--aparte-error-solid: #f87171;
|
|
589
612
|
--aparte-error-text: #fca5a5;
|
|
590
|
-
--aparte-error-title: #fecaca;
|
|
591
613
|
}
|
|
592
614
|
|
|
593
615
|
/* =========================================
|
|
@@ -653,8 +675,14 @@ aparte-chat {
|
|
|
653
675
|
--aparte-font-size-xs: calc(0.6875rem * var(--aparte-font-scale));
|
|
654
676
|
--aparte-font-size-sm: calc(0.75rem * var(--aparte-font-scale));
|
|
655
677
|
--aparte-font-size-md: calc(0.8125rem * var(--aparte-font-scale));
|
|
656
|
-
--aparte-font-size-lg: calc(0.875rem * var(--aparte-font-scale));
|
|
657
678
|
--aparte-font-size-base: calc(0.9375rem * var(--aparte-font-scale));
|
|
679
|
+
/* Above the body, in the order the names say. `lg` used to be 0.875rem — SMALLER than
|
|
680
|
+
`base` — with nothing above it, so a title and a placeholder shared a size and a
|
|
681
|
+
card's title was smaller than its body. A scale whose name lies is worse than a
|
|
682
|
+
short one. */
|
|
683
|
+
--aparte-font-size-lg: calc(1.0625rem * var(--aparte-font-scale));
|
|
684
|
+
--aparte-font-size-xl: calc(1.25rem * var(--aparte-font-scale));
|
|
685
|
+
--aparte-font-size-2xl: calc(1.5rem * var(--aparte-font-scale));
|
|
658
686
|
|
|
659
687
|
/* Elicitation and the conversation item, on the scale.
|
|
660
688
|
They were literals off every step — 0.76 / 0.78 / 0.8 / 0.82rem and a `7px 10px`
|
|
@@ -680,7 +708,6 @@ aparte-chat {
|
|
|
680
708
|
vertical half (#56) — a shorthand cannot be read by parts. */
|
|
681
709
|
--aparte-message-padding-block: var(--aparte-space-8);
|
|
682
710
|
--aparte-message-padding-inline: var(--aparte-space-6);
|
|
683
|
-
--aparte-message-padding: var(--aparte-message-padding-block) var(--aparte-message-padding-inline);
|
|
684
711
|
--aparte-message-content-padding: var(--aparte-space-5) var(--aparte-space-7);
|
|
685
712
|
--aparte-action-bar-gap: var(--aparte-space-2);
|
|
686
713
|
--aparte-branch-picker-gap: var(--aparte-space-2);
|
|
@@ -697,14 +724,15 @@ aparte-chat {
|
|
|
697
724
|
--aparte-input-padding-y: var(--aparte-space-5);
|
|
698
725
|
--aparte-conv-list-gap: var(--aparte-space-1);
|
|
699
726
|
--aparte-conv-item-gap: var(--aparte-space-3);
|
|
700
|
-
--aparte-elic-option-radius: var(--aparte-radius-
|
|
727
|
+
--aparte-elic-option-radius: var(--aparte-radius-md);
|
|
701
728
|
--aparte-elic-input-radius: var(--aparte-radius-md);
|
|
702
729
|
--aparte-tool-row-radius: var(--aparte-radius-md);
|
|
703
|
-
|
|
704
|
-
--aparte-
|
|
730
|
+
/* The split's painted seam: the kit's rule, inside a 12px track. */
|
|
731
|
+
--aparte-split-seam-width: var(--aparte-border-width);
|
|
732
|
+
--aparte-name-font-size: var(--aparte-font-size-md);
|
|
705
733
|
--aparte-timestamp-font-size: var(--aparte-font-size-sm);
|
|
706
734
|
--aparte-branch-picker-label-size: var(--aparte-font-size-sm);
|
|
707
|
-
--aparte-input-font-size: var(--aparte-font-size-
|
|
735
|
+
--aparte-input-font-size: var(--aparte-font-size-base);
|
|
708
736
|
--aparte-content-font-size: var(--aparte-font-size-base);
|
|
709
737
|
--aparte-input-editor-font-size: var(--aparte-font-size-base);
|
|
710
738
|
--aparte-status-font-size: var(--aparte-font-size-md);
|
|
@@ -717,6 +745,9 @@ aparte-chat {
|
|
|
717
745
|
moves --aparte-space-unit or --aparte-font-scale carries them along. */
|
|
718
746
|
/* A tooltip is an INVERTED surface: dark on a light theme, light on a dark one.
|
|
719
747
|
Reading the text pair gives exactly that, and for free — no third palette. */
|
|
748
|
+
/* The distance between a placed tooltip (`data-side`) and its anchor: the arrow's
|
|
749
|
+
half-diagonal, so the tip lands on the trigger rather than 2px short of it. */
|
|
750
|
+
--aparte-tooltip-gap: var(--aparte-space-3);
|
|
720
751
|
--aparte-tooltip-bg: var(--aparte-text);
|
|
721
752
|
--aparte-tooltip-color: var(--aparte-text-inverse);
|
|
722
753
|
|
|
@@ -752,6 +783,14 @@ aparte-chat {
|
|
|
752
783
|
--aparte-alert-padding: var(--aparte-space-4) var(--aparte-space-5);
|
|
753
784
|
--aparte-alert-radius: var(--aparte-radius-md);
|
|
754
785
|
--aparte-alert-rail-width: var(--aparte-space-1);
|
|
786
|
+
/* The icon scale, in rem times the type factor — the one scale in the theme that
|
|
787
|
+
was pinned in px while every type size followed `--aparte-font-scale`, so a glyph
|
|
788
|
+
beside text shrank optically the moment a reader enlarged the text. The loose
|
|
789
|
+
default is 16 (it was 14, and its documentation already said 16). */
|
|
790
|
+
--aparte-icon-size: calc(1rem * var(--aparte-font-scale));
|
|
791
|
+
--aparte-icon-size-sm: calc(0.75rem * var(--aparte-font-scale));
|
|
792
|
+
--aparte-icon-size-lg: calc(1.125rem * var(--aparte-font-scale));
|
|
793
|
+
--aparte-icon-size-xl: calc(1.25rem * var(--aparte-font-scale));
|
|
755
794
|
--aparte-alert-icon-size: var(--aparte-space-8);
|
|
756
795
|
--aparte-alert-dismiss-size: var(--aparte-btn-size-sm);
|
|
757
796
|
--aparte-alert-title-font-size: var(--aparte-font-size-md);
|
|
@@ -759,8 +798,7 @@ aparte-chat {
|
|
|
759
798
|
|
|
760
799
|
--aparte-avatar-fallback-bg: var(--aparte-surface-3);
|
|
761
800
|
--aparte-avatar-fallback-color: var(--aparte-text);
|
|
762
|
-
--aparte-avatar-group-
|
|
763
|
-
--aparte-avatar-group-ring-width: var(--aparte-border-width);
|
|
801
|
+
--aparte-avatar-group-ring-width: calc(var(--aparte-border-width) * 2);
|
|
764
802
|
--aparte-avatar-group-ring-color: var(--aparte-surface-1);
|
|
765
803
|
|
|
766
804
|
--aparte-badge-font-size: var(--aparte-font-size-2xs);
|
|
@@ -781,7 +819,7 @@ aparte-chat {
|
|
|
781
819
|
--aparte-card-header-padding: var(--aparte-space-4) var(--aparte-space-5);
|
|
782
820
|
--aparte-card-body-padding: var(--aparte-space-5);
|
|
783
821
|
--aparte-card-footer-padding: var(--aparte-space-4) var(--aparte-space-5);
|
|
784
|
-
--aparte-card-header-font-size: var(--aparte-font-size-
|
|
822
|
+
--aparte-card-header-font-size: var(--aparte-font-size-base);
|
|
785
823
|
|
|
786
824
|
--aparte-divider-margin: var(--aparte-space-5);
|
|
787
825
|
--aparte-divider-label-gap: var(--aparte-space-4);
|
|
@@ -797,22 +835,56 @@ aparte-chat {
|
|
|
797
835
|
--aparte-progress-height: var(--aparte-space-2);
|
|
798
836
|
--aparte-progress-fill: var(--aparte-primary);
|
|
799
837
|
|
|
800
|
-
|
|
838
|
+
/* The ground of a gauge or a placeholder — the thing a value is read against, so it
|
|
839
|
+
has to be seen. Derived RELATIVE to the page, not a surface level: a level sat at
|
|
840
|
+
two different distances from the ground in light and dark. */
|
|
841
|
+
--aparte-track: color-mix(in srgb, var(--aparte-text) 8%, var(--aparte-bg));
|
|
842
|
+
--aparte-skeleton-base: var(--aparte-track);
|
|
843
|
+
/* The rail is as wide as its widest tick (the current one is 1.6× the resting size);
|
|
844
|
+
it used to be a 20px literal clipping a 22.4px tick. */
|
|
845
|
+
--aparte-scroll-rail-width: calc(var(--aparte-scroll-rail-tick-size) * 1.6);
|
|
801
846
|
--aparte-skeleton-shine: var(--aparte-surface-3);
|
|
802
|
-
|
|
803
|
-
|
|
847
|
+
/* The line it stands for: as tall as the content type, and a gap that is the rest of
|
|
848
|
+
the content line, so the text that replaces it lands where it was (T21). It was 12px
|
|
849
|
+
on an 18px step for a 16px line on a 27px step — a third of a line of jump per line. */
|
|
850
|
+
--aparte-skeleton-text-height: var(--aparte-content-font-size);
|
|
851
|
+
--aparte-skeleton-text-gap: calc(var(--aparte-content-font-size) * (var(--aparte-content-line-height) - 1));
|
|
804
852
|
--aparte-skeleton-circle-size: var(--aparte-avatar-size);
|
|
805
853
|
|
|
806
854
|
--aparte-spinner-thickness: var(--aparte-space-1);
|
|
807
855
|
|
|
808
|
-
|
|
856
|
+
|
|
857
|
+
/* The field family's knobs, beside the button's — they used to be declared on
|
|
858
|
+
`.aparte-field` itself, which is why `.aparte-field-group` (their PARENT) and
|
|
859
|
+
`.aparte-color` (a sibling recipe) read a property that did not exist there and
|
|
860
|
+
rendered SQUARE: a custom property is substituted where it is declared and only
|
|
861
|
+
inherits downwards. Same reason they belong here rather than there: the theming
|
|
862
|
+
guide sends a consumer to `:root`, and every other family's knobs are here.
|
|
863
|
+
The *channels* stay local on purpose (`--aparte-checkbox-intent` and friends are
|
|
864
|
+
filled by a modifier, not set by a theme). */
|
|
865
|
+
--aparte-field-padding: var(--aparte-space-2) var(--aparte-space-3);
|
|
866
|
+
--aparte-field-padding-sm: var(--aparte-space-1) var(--aparte-space-2);
|
|
867
|
+
--aparte-field-padding-lg: var(--aparte-space-3) var(--aparte-space-4);
|
|
868
|
+
--aparte-field-radius: var(--aparte-radius-md);
|
|
869
|
+
/* The field's resting height is the lg step of the control scale, one step above the
|
|
870
|
+
default button and level with the composer's controls; `--sm` and `--lg` sit one
|
|
871
|
+
step either side. It used to be padding plus line-height, ~29px, the second
|
|
872
|
+
tallest thing in a row of five different heights. */
|
|
873
|
+
--aparte-field-size: var(--aparte-btn-size-lg);
|
|
874
|
+
--aparte-field-size-sm: var(--aparte-btn-size-md);
|
|
875
|
+
--aparte-field-size-lg: var(--aparte-btn-size-xl);
|
|
876
|
+
/* The 36px family, on the scale: named, not literal. */
|
|
877
|
+
--aparte-send-btn-size: var(--aparte-btn-size-lg);
|
|
878
|
+
--aparte-input-action-btn-size: var(--aparte-btn-size-lg);
|
|
879
|
+
--aparte-scroll-btn-size: var(--aparte-btn-size-lg);
|
|
809
880
|
|
|
810
881
|
--aparte-btn-gap: var(--aparte-space-2);
|
|
811
882
|
--aparte-btn-padding: var(--aparte-space-2) var(--aparte-space-3);
|
|
812
883
|
--aparte-btn-radius: var(--aparte-radius-md);
|
|
813
|
-
|
|
884
|
+
/* Control text is the md step (14px). One step lower was the origin of the "poor"
|
|
885
|
+
look: 13px labels in 32px boxes, beside 15px prose. */
|
|
886
|
+
--aparte-btn-font-size: var(--aparte-font-size-md);
|
|
814
887
|
--aparte-btn-bg-hover: var(--aparte-surface-2);
|
|
815
|
-
--aparte-btn-focus-offset: var(--aparte-space-1);
|
|
816
888
|
--aparte-btn-bg-active: var(--aparte-surface-3);
|
|
817
889
|
--aparte-btn-bg-toggled: var(--aparte-surface-2);
|
|
818
890
|
--aparte-btn-color-toggled: var(--aparte-text);
|
|
@@ -822,11 +894,17 @@ aparte-chat {
|
|
|
822
894
|
--aparte-btn-padding-sm: var(--aparte-space-1) var(--aparte-space-2);
|
|
823
895
|
--aparte-btn-padding-lg: var(--aparte-space-3) var(--aparte-space-5);
|
|
824
896
|
|
|
897
|
+
/* One knob for the composer's control set — the send button, the input's action
|
|
898
|
+
buttons, the editor's single-line height: the lg step at rest, the touch target
|
|
899
|
+
under a coarse pointer (responsive.css). It used to be undeclared, with `44px`
|
|
900
|
+
written as a fallback at every reader, so a desktop composer was a 62px bar around
|
|
901
|
+
15px of text and the coarse-pointer block had nothing left to enlarge. */
|
|
902
|
+
--aparte-composer-control-size: var(--aparte-btn-size-lg);
|
|
825
903
|
--aparte-input-container-min-height: var(--aparte-touch-target-size);
|
|
826
|
-
--aparte-elic-message-size: var(--aparte-font-size-
|
|
827
|
-
--aparte-elic-title-size: var(--aparte-font-size-
|
|
904
|
+
--aparte-elic-message-size: var(--aparte-font-size-base);
|
|
905
|
+
--aparte-elic-title-size: var(--aparte-font-size-base);
|
|
828
906
|
--aparte-elic-desc-size: var(--aparte-font-size-sm);
|
|
829
|
-
--aparte-elic-option-title-size: var(--aparte-font-size-
|
|
907
|
+
--aparte-elic-option-title-size: var(--aparte-font-size-md);
|
|
830
908
|
--aparte-elic-option-desc-size: var(--aparte-font-size-sm);
|
|
831
909
|
--aparte-elic-skip-size: var(--aparte-font-size-md);
|
|
832
910
|
--aparte-elic-step-size: var(--aparte-font-size-sm);
|
|
@@ -836,6 +914,17 @@ aparte-chat {
|
|
|
836
914
|
|
|
837
915
|
/* Borders */
|
|
838
916
|
--aparte-border-focus: var(--aparte-primary);
|
|
917
|
+
/* THE focus ring: a 2px outline in this colour, one spacing step OUTSIDE the box, on
|
|
918
|
+
every control. It used to be drawn two ways — this outline on seventeen recipes and a
|
|
919
|
+
soft box-shadow wash (30 % of the accent, 1.39:1 against the page) on five — and the
|
|
920
|
+
offset was −2px, inside the box, so on a bordered row the ring sat as a second
|
|
921
|
+
concentric line and the next row painted over its edge. */
|
|
922
|
+
--aparte-focus-outline-offset: var(--aparte-space-1);
|
|
923
|
+
/* The edge of a CONTROL — a field, a choice box, the select's trigger. `--aparte-border`
|
|
924
|
+
separates two regions and is right to be faint; a thing someone can touch has to be
|
|
925
|
+
seen, and six previews showed a control with no visible edge. Derived from the ink
|
|
926
|
+
and the ground so both schemes follow; the mix is a first setting. */
|
|
927
|
+
--aparte-border-control: color-mix(in srgb, var(--aparte-text) 30%, var(--aparte-surface-1));
|
|
839
928
|
|
|
840
929
|
/* Component-specific radius (overridable per app) */
|
|
841
930
|
--aparte-radius-input: var(--aparte-radius-lg);
|
|
@@ -843,19 +932,25 @@ aparte-chat {
|
|
|
843
932
|
--aparte-radius-send-btn: var(--aparte-radius-md);
|
|
844
933
|
--aparte-radius-action-btn: var(--aparte-radius-sm);
|
|
845
934
|
--aparte-radius-select: var(--aparte-radius-md);
|
|
846
|
-
--aparte-radius-avatar: var(--aparte-radius-md);
|
|
847
935
|
--aparte-radius-bubble: var(--aparte-radius-lg);
|
|
936
|
+
/* The bubble's corner IS the bubble radius above: it was a 14px literal off the scale,
|
|
937
|
+
the most visible corner of the transcript, and the knob named for it drove nothing. */
|
|
938
|
+
--aparte-message-content-radius: var(--aparte-radius-bubble);
|
|
848
939
|
--aparte-radius-code: var(--aparte-radius-lg);
|
|
849
940
|
--aparte-radius-thinking: var(--aparte-radius-lg);
|
|
850
941
|
--aparte-radius-error: var(--aparte-radius-md);
|
|
942
|
+
/* The floating surfaces. They read a step of the scale directly, so a theme that
|
|
943
|
+
wanted square menus and round bubbles had to move the step — and every other
|
|
944
|
+
reader of it. */
|
|
945
|
+
--aparte-radius-menu: var(--aparte-radius-lg);
|
|
946
|
+
--aparte-radius-popover: var(--aparte-radius-lg);
|
|
947
|
+
--aparte-radius-dialog: var(--aparte-radius-xl);
|
|
948
|
+
--aparte-radius-tooltip: var(--aparte-radius-sm);
|
|
851
949
|
|
|
852
950
|
/* The error ring on an avatar. A full shadow value, like
|
|
853
951
|
--aparte-scroll-btn-shadow: the whole ring is the knob, not its width. */
|
|
854
952
|
--aparte-avatar-error-ring: 0 0 0 2px var(--aparte-error-solid);
|
|
855
953
|
|
|
856
|
-
/* Focus ring — derived from the accent so it themes automatically. */
|
|
857
|
-
--aparte-focus-ring: 0 0 0 3px color-mix(in srgb, var(--aparte-primary) 30%, transparent);
|
|
858
|
-
|
|
859
954
|
/* Messages */
|
|
860
955
|
--aparte-message-content-text-user: var(--aparte-text);
|
|
861
956
|
--aparte-message-content-text-assistant: var(--aparte-text);
|
|
@@ -865,7 +960,9 @@ aparte-chat {
|
|
|
865
960
|
in sRGB rather than derived with `oklch(from …)`, because a wash has to keep the
|
|
866
961
|
SURFACE's lightness, not the accent's; 12 % is where the default palette reads as a
|
|
867
962
|
tint, not a fill, on both grounds. */
|
|
868
|
-
|
|
963
|
+
/* The mark's own tint: at 12 % the user bubble — the one mark that says "this turn is
|
|
964
|
+
yours" — sat at 1.03:1 on the light page. */
|
|
965
|
+
--aparte-message-content-bg-user: color-mix(in srgb, var(--aparte-primary) var(--aparte-mark-tint), var(--aparte-surface-1));
|
|
869
966
|
/* The third surface: the second, pulled 6 % toward the text. Close to what the old
|
|
870
967
|
literals encoded (`#e7dfce` from `#f1ebdf` light, `#342a40` from `#2a2333` dark —
|
|
871
968
|
5 to 9 % per channel, not one figure), now one rule that follows the masters. */
|
|
@@ -893,6 +990,12 @@ aparte-chat {
|
|
|
893
990
|
--aparte-thumb-radius: var(--aparte-radius-lg);
|
|
894
991
|
|
|
895
992
|
/* Action Bar */
|
|
993
|
+
/* The small controls of a turn and of a conversation row are the recipe's small step
|
|
994
|
+
(24px, the WCAG 2.5.8 floor). The action bar used to feed 28 with a 24 exception for
|
|
995
|
+
the last user turn, the branch arrows redrew 20 over their own `--sm`, the row's
|
|
996
|
+
`⋯` redrew 20: three control heights in one 14px row. */
|
|
997
|
+
--aparte-action-bar-btn-size: var(--aparte-btn-size-sm);
|
|
998
|
+
--aparte-conv-action-btn-size: var(--aparte-btn-size-sm);
|
|
896
999
|
--aparte-action-bar-btn-color: var(--aparte-text-muted);
|
|
897
1000
|
--aparte-action-bar-btn-hover-bg: var(--aparte-surface-2);
|
|
898
1001
|
--aparte-action-bar-btn-hover-color: var(--aparte-text);
|
|
@@ -903,11 +1006,10 @@ aparte-chat {
|
|
|
903
1006
|
--aparte-branch-picker-label-color: var(--aparte-text-muted);
|
|
904
1007
|
|
|
905
1008
|
/* Avatars */
|
|
906
|
-
--aparte-avatar-radius: var(--aparte-radius-avatar);
|
|
907
1009
|
--aparte-avatar-bg-user: var(--aparte-primary);
|
|
908
1010
|
--aparte-avatar-text-user: var(--aparte-text-inverse);
|
|
909
1011
|
--aparte-avatar-bg-assistant: var(--aparte-surface-3);
|
|
910
|
-
--aparte-avatar-text-assistant: var(--aparte-text
|
|
1012
|
+
--aparte-avatar-text-assistant: var(--aparte-text);
|
|
911
1013
|
|
|
912
1014
|
/* Text Sizes */
|
|
913
1015
|
--aparte-name-color: var(--aparte-text);
|
|
@@ -936,6 +1038,10 @@ aparte-chat {
|
|
|
936
1038
|
--aparte-code-header-bg: var(--aparte-surface-2);
|
|
937
1039
|
--aparte-code-border: var(--aparte-border);
|
|
938
1040
|
--aparte-code-header-text: var(--aparte-text-muted);
|
|
1041
|
+
/* The block's own type. It used to inherit the prose's size and leading (16px on 1.7)
|
|
1042
|
+
under the browser's generic monospace — the largest, airiest text in the message. */
|
|
1043
|
+
--aparte-code-block-font-size: var(--aparte-font-size-md);
|
|
1044
|
+
--aparte-code-block-line-height: var(--aparte-line-height-normal);
|
|
939
1045
|
|
|
940
1046
|
/* Scroll-to-bottom button */
|
|
941
1047
|
|
|
@@ -955,6 +1061,9 @@ aparte-chat {
|
|
|
955
1061
|
|
|
956
1062
|
/* Shell */
|
|
957
1063
|
--aparte-sidebar-bg: var(--aparte-surface-2);
|
|
1064
|
+
/* The one inline inset of the column's four regions — header, search, body, footer.
|
|
1065
|
+
They used to carry three (16 / 12 / 12 / 16) and the content sat on two axes. */
|
|
1066
|
+
--aparte-sidebar-inset: var(--aparte-space-3);
|
|
958
1067
|
|
|
959
1068
|
/* Conversation List */
|
|
960
1069
|
--aparte-conv-item-radius: var(--aparte-radius-md);
|
|
@@ -1034,6 +1143,28 @@ aparte-chat {
|
|
|
1034
1143
|
animation: aparte-pulse var(--aparte-duration-pulse) infinite ease-in-out;
|
|
1035
1144
|
}
|
|
1036
1145
|
|
|
1146
|
+
/* Under reduced motion the loop stops outright. The duration tokens are reset to
|
|
1147
|
+
0.01ms in responsive.css, but that leaves `infinite` in place: a 0.01ms cycle
|
|
1148
|
+
is not stillness, it is a flicker. The descendant sweep there does not reach a
|
|
1149
|
+
recipe used outside aparté's own elements, so each looping recipe stops itself,
|
|
1150
|
+
the way display/icon.css already does. */
|
|
1151
|
+
@media (prefers-reduced-motion: reduce) {
|
|
1152
|
+
.aparte-dot { animation: none; }
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
/* `hidden` means hidden. 71 recipes in these sheets set `display` on their base class,
|
|
1156
|
+
and an author declaration beats the browser's own `[hidden] { display: none }` — so a
|
|
1157
|
+
hidden `.aparte-btn` was out of the accessibility tree and still painted: the copy
|
|
1158
|
+
button of a tool-only turn stood there with `hidden` on it. Scoped to our own classes
|
|
1159
|
+
(a prefix match, not a bare `[hidden]`, so a host's markup is not touched), and
|
|
1160
|
+
`!important` because the whole point is to outrank the recipe's `display`. The
|
|
1161
|
+
handful of per-element `[hidden]` rules that predate this stay; they are now
|
|
1162
|
+
redundant, not wrong. */
|
|
1163
|
+
[class^="aparte-"][hidden],
|
|
1164
|
+
[class*=" aparte-"][hidden] {
|
|
1165
|
+
display: none !important;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1037
1168
|
/* =========================================
|
|
1038
1169
|
aparte-conversation-list
|
|
1039
1170
|
========================================= */
|
|
@@ -1065,7 +1196,7 @@ aparte-conversation-list {
|
|
|
1065
1196
|
.aparte-link:hover { color: var(--aparte-link-color-hover); }
|
|
1066
1197
|
.aparte-link:focus-visible {
|
|
1067
1198
|
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
1068
|
-
outline-offset: var(--aparte-
|
|
1199
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
1069
1200
|
}
|
|
1070
1201
|
/* Quiet — for a link inside a dense row, where a coloured one would shout. It keeps
|
|
1071
1202
|
the underline, which is the part that carries the meaning. */
|
|
@@ -1088,8 +1219,11 @@ aparte-conversation-list {
|
|
|
1088
1219
|
same thing at slightly different rhythms; a travelling wave, where a row wants one,
|
|
1089
1220
|
comes from an animation-delay on its later dots, not from a skewed curve. */
|
|
1090
1221
|
@keyframes aparte-pulse {
|
|
1091
|
-
|
|
1092
|
-
|
|
1222
|
+
/* Opacity alone: the scale that used to ride along made a row of waiting dots change
|
|
1223
|
+
width in a loop. And a floor above the perception threshold — at 0.3 the status
|
|
1224
|
+
dot spent half of every cycle at 1.55:1, and a capture froze it there. */
|
|
1225
|
+
0%, 100% { opacity: var(--aparte-pulse-floor); }
|
|
1226
|
+
50% { opacity: 1; }
|
|
1093
1227
|
}
|
|
1094
1228
|
|
|
1095
1229
|
/* One rotation, for every spinner and every spinning glyph. */
|
|
@@ -1110,9 +1244,9 @@ aparte-conversation-list {
|
|
|
1110
1244
|
* <aparte-icon name="copy"></aparte-icon>
|
|
1111
1245
|
* </button>
|
|
1112
1246
|
* <div class="aparte-btn-group" role="group" aria-label="Versions">
|
|
1113
|
-
* <button class="aparte-btn aparte-btn--surface"
|
|
1247
|
+
* <button class="aparte-btn aparte-btn--surface" aria-label="Previous"><aparte-icon name="prevBranch"></aparte-icon></button>
|
|
1114
1248
|
* <button class="aparte-btn aparte-btn--surface">1 / 2</button>
|
|
1115
|
-
* <button class="aparte-btn aparte-btn--surface"
|
|
1249
|
+
* <button class="aparte-btn aparte-btn--surface" aria-label="Next"><aparte-icon name="nextBranch"></aparte-icon></button>
|
|
1116
1250
|
* </div>
|
|
1117
1251
|
* <div class="aparte-btn-group" role="group" aria-label="View">
|
|
1118
1252
|
* <button class="aparte-btn aparte-btn--primary aparte-btn--outline" aria-pressed="true">Chat</button>
|
|
@@ -1139,6 +1273,13 @@ aparte-conversation-list {
|
|
|
1139
1273
|
*/
|
|
1140
1274
|
|
|
1141
1275
|
.aparte-btn {
|
|
1276
|
+
/* The glyph reads this: an `<aparte-icon>` (or a raw `svg.aparte-icon`) inside a button
|
|
1277
|
+
takes the button's icon size, per size modifier. */
|
|
1278
|
+
--aparte-icon-size: var(--aparte-btn-icon-size);
|
|
1279
|
+
/* The box, for EVERY button: `--icon` and `--circle` used to be the only readers of
|
|
1280
|
+
the size, so a text button was padding plus line-height — 23px beside a 32px icon
|
|
1281
|
+
button in the same row. The size is declared here and read below as a minimum. */
|
|
1282
|
+
--aparte-btn-size: var(--aparte-btn-size-md);
|
|
1142
1283
|
/* The intent, as a value. Every fill below reads THIS and nothing else, which is
|
|
1143
1284
|
what keeps the two axes independent. */
|
|
1144
1285
|
--aparte-btn-intent: var(--aparte-neutral);
|
|
@@ -1157,6 +1298,8 @@ aparte-conversation-list {
|
|
|
1157
1298
|
--aparte-btn-intent-ink: var(--aparte-btn-intent);
|
|
1158
1299
|
|
|
1159
1300
|
display: inline-flex;
|
|
1301
|
+
|
|
1302
|
+
vertical-align: middle;
|
|
1160
1303
|
align-items: center;
|
|
1161
1304
|
justify-content: center;
|
|
1162
1305
|
gap: var(--aparte-btn-gap);
|
|
@@ -1167,6 +1310,7 @@ aparte-conversation-list {
|
|
|
1167
1310
|
be set by the composer's own row rule, which is exactly the kind of thing a recipe
|
|
1168
1311
|
should not need a caller for. */
|
|
1169
1312
|
box-sizing: border-box;
|
|
1313
|
+
min-block-size: var(--aparte-btn-size);
|
|
1170
1314
|
padding: var(--aparte-btn-padding);
|
|
1171
1315
|
border: var(--aparte-border-width) solid transparent;
|
|
1172
1316
|
border-radius: var(--aparte-btn-radius);
|
|
@@ -1321,15 +1465,21 @@ aparte-conversation-list {
|
|
|
1321
1465
|
.aparte-btn--soft:active:not(:disabled) { background: color-mix(in srgb, var(--aparte-btn-intent) 30%, transparent); }
|
|
1322
1466
|
.aparte-btn--solid:active:not(:disabled) { background: var(--aparte-btn-intent); filter: brightness(0.93); }
|
|
1323
1467
|
|
|
1468
|
+
/* Drawn, not faded. Opacity on the whole button faded the glyph with its ground and
|
|
1469
|
+
read at 2:1 on the send button; "inactive" and "disappearing" are not the same
|
|
1470
|
+
message. A neutral ground, the muted ink, no intent — whatever the fill was. */
|
|
1324
1471
|
.aparte-btn:disabled,
|
|
1325
1472
|
.aparte-btn[aria-disabled='true'] {
|
|
1326
1473
|
cursor: not-allowed;
|
|
1327
|
-
|
|
1474
|
+
background: var(--aparte-surface-2);
|
|
1475
|
+
color: var(--aparte-text-muted);
|
|
1476
|
+
border-color: transparent;
|
|
1477
|
+
filter: none;
|
|
1328
1478
|
}
|
|
1329
1479
|
|
|
1330
1480
|
.aparte-btn:focus-visible {
|
|
1331
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
1332
|
-
outline-offset: var(--aparte-
|
|
1481
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
1482
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
1333
1483
|
}
|
|
1334
1484
|
|
|
1335
1485
|
/* Toggled — a disclosure that is open, a toggle that is on, a tab that is current. */
|
|
@@ -1362,25 +1512,39 @@ aparte-conversation-list {
|
|
|
1362
1512
|
.aparte-btn--block { display: flex; width: 100%; }
|
|
1363
1513
|
|
|
1364
1514
|
.aparte-btn--sm { --aparte-btn-size: var(--aparte-btn-size-sm); --aparte-btn-icon-size: var(--aparte-icon-size-sm); font-size: var(--aparte-font-size-sm); padding: var(--aparte-btn-padding-sm); }
|
|
1365
|
-
.aparte-btn--lg { --aparte-btn-size: var(--aparte-btn-size-lg); --aparte-btn-icon-size: var(--aparte-icon-size-xl); font-size: var(--aparte-font-size-
|
|
1515
|
+
.aparte-btn--lg { --aparte-btn-size: var(--aparte-btn-size-lg); --aparte-btn-icon-size: var(--aparte-icon-size-xl); font-size: var(--aparte-font-size-base); padding: var(--aparte-btn-padding-lg); }
|
|
1516
|
+
.aparte-btn--xl { --aparte-btn-size: var(--aparte-btn-size-xl); --aparte-btn-icon-size: var(--aparte-icon-size-xl); font-size: var(--aparte-font-size-base); padding: var(--aparte-btn-padding-lg); }
|
|
1366
1517
|
.aparte-btn--sm.aparte-btn--icon,
|
|
1367
1518
|
.aparte-btn--sm.aparte-btn--circle,
|
|
1368
1519
|
.aparte-btn--lg.aparte-btn--icon,
|
|
1369
|
-
.aparte-btn--lg.aparte-btn--circle
|
|
1520
|
+
.aparte-btn--lg.aparte-btn--circle,
|
|
1521
|
+
.aparte-btn--xl.aparte-btn--icon,
|
|
1522
|
+
.aparte-btn--xl.aparte-btn--circle { padding: 0; }
|
|
1370
1523
|
|
|
1371
1524
|
/* An icon inside a button never takes the pointer: the click belongs to the button,
|
|
1372
|
-
and an SVG target makes `event.target` lie to a delegated listener.
|
|
1373
|
-
the button so the two axes stay in step. */
|
|
1525
|
+
and an SVG target makes `event.target` lie to a delegated listener. */
|
|
1374
1526
|
.aparte-btn > svg,
|
|
1527
|
+
.aparte-btn > aparte-icon,
|
|
1375
1528
|
.aparte-btn > .aparte-btn__icon {
|
|
1376
1529
|
pointer-events: none;
|
|
1377
1530
|
flex-shrink: 0;
|
|
1531
|
+
}
|
|
1532
|
+
|
|
1533
|
+
/* A raw SVG or a consumer's own icon box is sized with the button so the two axes stay
|
|
1534
|
+
in step. An `<aparte-icon>` is NOT sized here: it renders its `<svg>` inside itself, a
|
|
1535
|
+
grandchild this child combinator never reached, so the documented markup kept the
|
|
1536
|
+
glyph at its loose 14px default in a button that asked for 16. The recipe feeds the
|
|
1537
|
+
icon's own knob instead — `--aparte-icon-size`, declared on `.aparte-btn` above — and
|
|
1538
|
+
`display/icon.css` draws it, at `--sm`'s 12 and `--lg`'s 20 like everything else. */
|
|
1539
|
+
.aparte-btn > svg:not(.aparte-icon),
|
|
1540
|
+
.aparte-btn > .aparte-btn__icon {
|
|
1378
1541
|
width: var(--aparte-btn-icon-size);
|
|
1379
1542
|
height: var(--aparte-btn-icon-size);
|
|
1380
1543
|
}
|
|
1381
1544
|
|
|
1382
1545
|
/* ── Group — buttons that read as one control. ───────────────────────────────── */
|
|
1383
|
-
.aparte-btn-group { display: inline-flex;
|
|
1546
|
+
.aparte-btn-group { display: inline-flex;
|
|
1547
|
+
vertical-align: middle; }
|
|
1384
1548
|
.aparte-btn-group > .aparte-btn { border-radius: 0; }
|
|
1385
1549
|
/* Logical properties, so the joined edge follows the writing direction instead of
|
|
1386
1550
|
assuming left-to-right. */
|
|
@@ -1464,24 +1628,24 @@ aparte-conversation-list {
|
|
|
1464
1628
|
/* ── The shared text-entry recipe ────────────────────────────────────────────── */
|
|
1465
1629
|
|
|
1466
1630
|
.aparte-field {
|
|
1467
|
-
/*
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
own element the way every sibling can. */
|
|
1474
|
-
--aparte-field-radius: var(--aparte-radius-md);
|
|
1475
|
-
|
|
1631
|
+
/* Every knob this family reads lives in `theme.css` on `:root` — including the
|
|
1632
|
+
radius and the paddings, which used to be declared right here. That was the one
|
|
1633
|
+
construction bug of the kit: `.aparte-field-group` is this element's PARENT and
|
|
1634
|
+
`.aparte-color` a sibling recipe, both read `--aparte-field-radius`, and a custom
|
|
1635
|
+
property declared here is invisible to both, so they computed `border-radius: 0`
|
|
1636
|
+
and every field group in the library rendered square. */
|
|
1476
1637
|
box-sizing: border-box;
|
|
1477
1638
|
display: block;
|
|
1478
1639
|
width: 100%;
|
|
1640
|
+
/* A resting height from the control scale, so a field and the button beside it stop
|
|
1641
|
+
disagreeing by 6px; the size modifiers move it a step either way. */
|
|
1642
|
+
min-block-size: var(--aparte-field-size);
|
|
1479
1643
|
font: inherit;
|
|
1480
|
-
font-size: var(--aparte-font-size-
|
|
1644
|
+
font-size: var(--aparte-font-size-md);
|
|
1481
1645
|
line-height: var(--aparte-line-height-normal);
|
|
1482
1646
|
color: var(--aparte-text);
|
|
1483
1647
|
background: var(--aparte-surface-1);
|
|
1484
|
-
border: var(--aparte-border-width) solid var(--aparte-border);
|
|
1648
|
+
border: var(--aparte-border-width) solid var(--aparte-border-control);
|
|
1485
1649
|
border-radius: var(--aparte-field-radius);
|
|
1486
1650
|
padding: var(--aparte-field-padding);
|
|
1487
1651
|
transition:
|
|
@@ -1516,10 +1680,13 @@ aparte-conversation-list {
|
|
|
1516
1680
|
border-color: var(--aparte-border-focus);
|
|
1517
1681
|
}
|
|
1518
1682
|
|
|
1683
|
+
/* Drawn, not faded: the muted ink on the quieter ground, and the edge back to the region
|
|
1684
|
+
colour. Opacity faded the text with its box and read under 3:1. */
|
|
1519
1685
|
.aparte-field:disabled {
|
|
1520
1686
|
cursor: not-allowed;
|
|
1521
|
-
opacity: var(--aparte-disabled-opacity);
|
|
1522
1687
|
background: var(--aparte-surface-2);
|
|
1688
|
+
color: var(--aparte-text-muted);
|
|
1689
|
+
border-color: var(--aparte-border);
|
|
1523
1690
|
}
|
|
1524
1691
|
|
|
1525
1692
|
.aparte-field[readonly] {
|
|
@@ -1533,37 +1700,35 @@ aparte-conversation-list {
|
|
|
1533
1700
|
border-color: var(--aparte-error);
|
|
1534
1701
|
}
|
|
1535
1702
|
|
|
1703
|
+
/* The one ring (see --aparte-focus-outline-offset in theme.css): an outline outside the
|
|
1704
|
+
box, and the border left alone — a highlighted border under an offset ring read as two
|
|
1705
|
+
concentric lines. An invalid field's ring takes the error colour. */
|
|
1536
1706
|
.aparte-field:focus-visible {
|
|
1537
|
-
outline:
|
|
1538
|
-
|
|
1539
|
-
box-shadow: var(--aparte-focus-ring);
|
|
1707
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
1708
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
1540
1709
|
}
|
|
1541
1710
|
|
|
1542
1711
|
.aparte-field[aria-invalid='true']:focus-visible {
|
|
1543
|
-
|
|
1544
|
-
box-shadow: var(--aparte-field-error-ring);
|
|
1712
|
+
outline-color: var(--aparte-error-solid);
|
|
1545
1713
|
}
|
|
1546
1714
|
|
|
1547
1715
|
/* ── Sizes ───────────────────────────────────────────────────────────────────── */
|
|
1548
1716
|
|
|
1549
1717
|
.aparte-field--sm {
|
|
1550
|
-
--aparte-field-
|
|
1551
|
-
|
|
1718
|
+
--aparte-field-size: var(--aparte-field-size-sm);
|
|
1552
1719
|
padding: var(--aparte-field-padding-sm);
|
|
1553
|
-
font-size: var(--aparte-font-size-
|
|
1720
|
+
font-size: var(--aparte-font-size-sm);
|
|
1554
1721
|
}
|
|
1555
1722
|
|
|
1556
1723
|
.aparte-field--lg {
|
|
1557
|
-
--aparte-field-
|
|
1558
|
-
|
|
1724
|
+
--aparte-field-size: var(--aparte-field-size-lg);
|
|
1559
1725
|
padding: var(--aparte-field-padding-lg);
|
|
1560
|
-
font-size: var(--aparte-font-size-
|
|
1726
|
+
font-size: var(--aparte-font-size-base);
|
|
1561
1727
|
}
|
|
1562
1728
|
|
|
1563
1729
|
/* ── Textarea ────────────────────────────────────────────────────────────────── */
|
|
1564
1730
|
|
|
1565
1731
|
.aparte-field--textarea {
|
|
1566
|
-
--aparte-field-textarea-min-height: 80px;
|
|
1567
1732
|
|
|
1568
1733
|
display: block;
|
|
1569
1734
|
min-block-size: var(--aparte-field-textarea-min-height);
|
|
@@ -1578,7 +1743,7 @@ aparte-conversation-list {
|
|
|
1578
1743
|
display: flex;
|
|
1579
1744
|
align-items: stretch;
|
|
1580
1745
|
background: var(--aparte-surface-1);
|
|
1581
|
-
border: var(--aparte-border-width) solid var(--aparte-border);
|
|
1746
|
+
border: var(--aparte-border-width) solid var(--aparte-border-control);
|
|
1582
1747
|
border-radius: var(--aparte-field-radius);
|
|
1583
1748
|
/* The addons' ground follows the group's corners; the focus ring is a shadow on the
|
|
1584
1749
|
group itself, outside this box, so it is not clipped. */
|
|
@@ -1600,8 +1765,15 @@ aparte-conversation-list {
|
|
|
1600
1765
|
border-radius: 0;
|
|
1601
1766
|
}
|
|
1602
1767
|
|
|
1768
|
+
/* The GROUP draws the ring (below): the field inside it draws none. */
|
|
1603
1769
|
.aparte-field-group > .aparte-field:focus-visible {
|
|
1604
|
-
|
|
1770
|
+
outline: none;
|
|
1771
|
+
}
|
|
1772
|
+
|
|
1773
|
+
/* A button in the group is as tall as the field it sits beside — the one row where the
|
|
1774
|
+
two recipes meet, and the one where a 4px difference shows. */
|
|
1775
|
+
.aparte-field-group > .aparte-btn {
|
|
1776
|
+
--aparte-btn-size: var(--aparte-field-size);
|
|
1605
1777
|
}
|
|
1606
1778
|
|
|
1607
1779
|
/* An addon has a ground of its own and a rule against the field: on the field's own
|
|
@@ -1628,8 +1800,8 @@ aparte-conversation-list {
|
|
|
1628
1800
|
}
|
|
1629
1801
|
|
|
1630
1802
|
.aparte-field-group:focus-within {
|
|
1631
|
-
|
|
1632
|
-
|
|
1803
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
1804
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
1633
1805
|
}
|
|
1634
1806
|
|
|
1635
1807
|
/* `aria-invalid` lives on the field itself, not the wrapper the app didn't write a
|
|
@@ -1640,7 +1812,7 @@ aparte-conversation-list {
|
|
|
1640
1812
|
}
|
|
1641
1813
|
|
|
1642
1814
|
.aparte-field-group:has(.aparte-field[aria-invalid='true']):focus-within {
|
|
1643
|
-
|
|
1815
|
+
outline-color: var(--aparte-error-solid);
|
|
1644
1816
|
}
|
|
1645
1817
|
|
|
1646
1818
|
/* ── Checkbox ────────────────────────────────────────────────────────────────── */
|
|
@@ -1664,7 +1836,6 @@ aparte-conversation-list {
|
|
|
1664
1836
|
--aparte-derived-ink: var(--aparte-on-intent);
|
|
1665
1837
|
/* No shared control-size token covers a checkbox yet (the button's own sizes are
|
|
1666
1838
|
button-specific), so its box is declared here. */
|
|
1667
|
-
--aparte-checkbox-size: 18px;
|
|
1668
1839
|
|
|
1669
1840
|
box-sizing: border-box;
|
|
1670
1841
|
appearance: none;
|
|
@@ -1675,7 +1846,7 @@ aparte-conversation-list {
|
|
|
1675
1846
|
place-content: center;
|
|
1676
1847
|
width: var(--aparte-checkbox-size);
|
|
1677
1848
|
height: var(--aparte-checkbox-size);
|
|
1678
|
-
border: var(--aparte-border-width) solid var(--aparte-border);
|
|
1849
|
+
border: var(--aparte-border-width) solid var(--aparte-border-control);
|
|
1679
1850
|
border-radius: var(--aparte-radius-sm);
|
|
1680
1851
|
background: var(--aparte-surface-1);
|
|
1681
1852
|
cursor: pointer;
|
|
@@ -1760,7 +1931,7 @@ aparte-conversation-list {
|
|
|
1760
1931
|
}
|
|
1761
1932
|
|
|
1762
1933
|
.aparte-checkbox:focus-visible {
|
|
1763
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
1934
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
1764
1935
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
1765
1936
|
}
|
|
1766
1937
|
|
|
@@ -1790,8 +1961,6 @@ aparte-conversation-list {
|
|
|
1790
1961
|
used. `middle` and not `text-bottom`: the label may wrap. */
|
|
1791
1962
|
vertical-align: middle;
|
|
1792
1963
|
--aparte-radio-intent: var(--aparte-primary);
|
|
1793
|
-
--aparte-radio-size: 18px;
|
|
1794
|
-
--aparte-radio-dot-size: 8px;
|
|
1795
1964
|
|
|
1796
1965
|
box-sizing: border-box;
|
|
1797
1966
|
appearance: none;
|
|
@@ -1802,7 +1971,7 @@ aparte-conversation-list {
|
|
|
1802
1971
|
place-content: center;
|
|
1803
1972
|
width: var(--aparte-radio-size);
|
|
1804
1973
|
height: var(--aparte-radio-size);
|
|
1805
|
-
border: var(--aparte-border-width) solid var(--aparte-border);
|
|
1974
|
+
border: var(--aparte-border-width) solid var(--aparte-border-control);
|
|
1806
1975
|
border-radius: var(--aparte-radius-full);
|
|
1807
1976
|
background: var(--aparte-surface-1);
|
|
1808
1977
|
cursor: pointer;
|
|
@@ -1844,7 +2013,7 @@ aparte-conversation-list {
|
|
|
1844
2013
|
}
|
|
1845
2014
|
|
|
1846
2015
|
.aparte-radio:focus-visible {
|
|
1847
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
2016
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
1848
2017
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
1849
2018
|
}
|
|
1850
2019
|
|
|
@@ -1875,9 +2044,6 @@ aparte-conversation-list {
|
|
|
1875
2044
|
has to live here where `:checked` can override it — a central default could never
|
|
1876
2045
|
react to the class + state combo. */
|
|
1877
2046
|
--aparte-switch-track: var(--aparte-surface-3);
|
|
1878
|
-
--aparte-switch-width: 40px;
|
|
1879
|
-
--aparte-switch-height: 22px;
|
|
1880
|
-
--aparte-switch-thumb-inset: 2px;
|
|
1881
2047
|
/* DERIVED from the track, not a fourth literal to keep in step with the other three:
|
|
1882
2048
|
the thumb used to be 16px in a 20px track with a 1px border and a 2px top inset —
|
|
1883
2049
|
2px of air above it and none below, visibly low ("le cercle pas centré"). The
|
|
@@ -1896,7 +2062,7 @@ aparte-conversation-list {
|
|
|
1896
2062
|
flex-shrink: 0;
|
|
1897
2063
|
inline-size: var(--aparte-switch-width);
|
|
1898
2064
|
block-size: var(--aparte-switch-height);
|
|
1899
|
-
border: var(--aparte-border-width) solid var(--aparte-border);
|
|
2065
|
+
border: var(--aparte-border-width) solid var(--aparte-border-control);
|
|
1900
2066
|
border-radius: var(--aparte-radius-full);
|
|
1901
2067
|
background: var(--aparte-switch-track);
|
|
1902
2068
|
cursor: pointer;
|
|
@@ -1944,7 +2110,7 @@ aparte-conversation-list {
|
|
|
1944
2110
|
}
|
|
1945
2111
|
|
|
1946
2112
|
.aparte-switch:focus-visible {
|
|
1947
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
2113
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
1948
2114
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
1949
2115
|
}
|
|
1950
2116
|
|
|
@@ -1968,8 +2134,6 @@ aparte-conversation-list {
|
|
|
1968
2134
|
|
|
1969
2135
|
.aparte-range {
|
|
1970
2136
|
--aparte-range-intent: var(--aparte-primary);
|
|
1971
|
-
--aparte-range-thumb-size: 16px;
|
|
1972
|
-
--aparte-range-track-height: 4px;
|
|
1973
2137
|
|
|
1974
2138
|
appearance: none;
|
|
1975
2139
|
-webkit-appearance: none;
|
|
@@ -2039,11 +2203,11 @@ aparte-conversation-list {
|
|
|
2039
2203
|
.aparte-range:active::-moz-range-thumb { transform: scale(1.15); }
|
|
2040
2204
|
|
|
2041
2205
|
.aparte-range:focus-visible::-webkit-slider-thumb {
|
|
2042
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
2206
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
2043
2207
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
2044
2208
|
}
|
|
2045
2209
|
.aparte-range:focus-visible::-moz-range-thumb {
|
|
2046
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
2210
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
2047
2211
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
2048
2212
|
}
|
|
2049
2213
|
|
|
@@ -2064,6 +2228,7 @@ aparte-conversation-list {
|
|
|
2064
2228
|
|
|
2065
2229
|
.aparte-field-label {
|
|
2066
2230
|
display: inline-block;
|
|
2231
|
+
vertical-align: middle;
|
|
2067
2232
|
margin-block-end: var(--aparte-space-1);
|
|
2068
2233
|
font-size: var(--aparte-font-size-sm);
|
|
2069
2234
|
font-weight: var(--aparte-font-weight-medium);
|
|
@@ -2151,7 +2316,7 @@ aparte-conversation-list {
|
|
|
2151
2316
|
inline-size: var(--aparte-color-size);
|
|
2152
2317
|
block-size: var(--aparte-color-size);
|
|
2153
2318
|
padding: 0;
|
|
2154
|
-
border: var(--aparte-border-width) solid var(--aparte-border);
|
|
2319
|
+
border: var(--aparte-border-width) solid var(--aparte-border-control);
|
|
2155
2320
|
border-radius: var(--aparte-field-radius);
|
|
2156
2321
|
background: none;
|
|
2157
2322
|
cursor: pointer;
|
|
@@ -2161,7 +2326,7 @@ aparte-conversation-list {
|
|
|
2161
2326
|
.aparte-color::-moz-color-swatch { border: none; border-radius: var(--aparte-radius-sm); }
|
|
2162
2327
|
.aparte-color:focus-visible {
|
|
2163
2328
|
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
2164
|
-
outline-offset: var(--aparte-
|
|
2329
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
2165
2330
|
}
|
|
2166
2331
|
.aparte-color:disabled { cursor: not-allowed; opacity: var(--aparte-disabled-opacity); }
|
|
2167
2332
|
|
|
@@ -2217,6 +2382,7 @@ aparte-conversation-list {
|
|
|
2217
2382
|
would invite a click. */
|
|
2218
2383
|
.aparte-output {
|
|
2219
2384
|
display: inline-block;
|
|
2385
|
+
vertical-align: middle;
|
|
2220
2386
|
padding: var(--aparte-output-padding);
|
|
2221
2387
|
border-radius: var(--aparte-radius-sm);
|
|
2222
2388
|
background: var(--aparte-output-bg);
|
|
@@ -2299,19 +2465,22 @@ aparte-conversation-list {
|
|
|
2299
2465
|
}
|
|
2300
2466
|
.aparte-field-choice:has(:focus-visible) {
|
|
2301
2467
|
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
2302
|
-
outline-offset: var(--aparte-
|
|
2468
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
2303
2469
|
}
|
|
2304
2470
|
|
|
2305
2471
|
.aparte-field-choice__body { flex: 1 1 auto; min-width: 0; }
|
|
2306
2472
|
/* =========================================
|
|
2307
2473
|
aparte-avatar — sizes, shape, image + initials fallback
|
|
2308
2474
|
=========================================
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2475
|
+
`--aparte-avatar-size` is NOT invented here: it already exists centrally for the
|
|
2476
|
+
message avatar (bubble.css), and this component reads the same one — a generic
|
|
2477
|
+
avatar and a chat-message avatar are the same object, and a size modifier applied
|
|
2478
|
+
here resizes a role-coloured message avatar too. The corner, the initials and the
|
|
2479
|
+
group's overlap are FRACTIONS of that size (`--aparte-avatar-radius-ratio`,
|
|
2480
|
+
`--aparte-avatar-initials-ratio`, `--aparte-avatar-overlap-ratio`), computed on the
|
|
2481
|
+
element so a size modifier moves them: as absolute tokens the 40px avatar drew the
|
|
2482
|
+
same 11px initials as the 32px one, the corner drifted from squircle to square up
|
|
2483
|
+
the ramp, and a 6px overlap was a fifth of a small avatar and a tenth of a large one.
|
|
2315
2484
|
|
|
2316
2485
|
<span class="aparte-avatar aparte-avatar--sm">AP</span>
|
|
2317
2486
|
<span class="aparte-avatar">JD</span>
|
|
@@ -2326,16 +2495,17 @@ aparte-conversation-list {
|
|
|
2326
2495
|
.aparte-avatar {
|
|
2327
2496
|
position: relative;
|
|
2328
2497
|
display: inline-flex;
|
|
2498
|
+
vertical-align: middle;
|
|
2329
2499
|
flex-shrink: 0;
|
|
2330
2500
|
align-items: center;
|
|
2331
2501
|
justify-content: center;
|
|
2332
2502
|
overflow: hidden;
|
|
2333
2503
|
width: var(--aparte-avatar-size);
|
|
2334
2504
|
height: var(--aparte-avatar-size);
|
|
2335
|
-
border-radius: var(--aparte-avatar-radius);
|
|
2505
|
+
border-radius: calc(var(--aparte-avatar-size) * var(--aparte-avatar-radius-ratio));
|
|
2336
2506
|
background: var(--aparte-avatar-fallback-bg);
|
|
2337
2507
|
color: var(--aparte-avatar-fallback-color);
|
|
2338
|
-
font-size: var(--aparte-avatar-
|
|
2508
|
+
font-size: calc(var(--aparte-avatar-size) * var(--aparte-avatar-initials-ratio));
|
|
2339
2509
|
font-weight: var(--aparte-font-weight-semibold);
|
|
2340
2510
|
line-height: var(--aparte-line-height-none);
|
|
2341
2511
|
text-transform: uppercase;
|
|
@@ -2359,13 +2529,13 @@ aparte-conversation-list {
|
|
|
2359
2529
|
|
|
2360
2530
|
/* Square is the default shape and needs no class (it is what the message avatar
|
|
2361
2531
|
already renders); named anyway so a square avatar can say so rather than omit. */
|
|
2362
|
-
.aparte-avatar--square { border-radius: var(--aparte-avatar-radius); }
|
|
2532
|
+
.aparte-avatar--square { border-radius: calc(var(--aparte-avatar-size) * var(--aparte-avatar-radius-ratio)); }
|
|
2363
2533
|
.aparte-avatar--circle { border-radius: var(--aparte-radius-full); }
|
|
2364
2534
|
|
|
2365
|
-
.aparte-avatar--xs { --aparte-avatar-size: var(--aparte-avatar-size-xs);
|
|
2366
|
-
.aparte-avatar--sm { --aparte-avatar-size: var(--aparte-avatar-size-sm);
|
|
2367
|
-
.aparte-avatar--lg { --aparte-avatar-size: var(--aparte-avatar-size-lg);
|
|
2368
|
-
.aparte-avatar--xl { --aparte-avatar-size: var(--aparte-avatar-size-xl);
|
|
2535
|
+
.aparte-avatar--xs { --aparte-avatar-size: var(--aparte-avatar-size-xs); }
|
|
2536
|
+
.aparte-avatar--sm { --aparte-avatar-size: var(--aparte-avatar-size-sm); }
|
|
2537
|
+
.aparte-avatar--lg { --aparte-avatar-size: var(--aparte-avatar-size-lg); }
|
|
2538
|
+
.aparte-avatar--xl { --aparte-avatar-size: var(--aparte-avatar-size-xl); }
|
|
2369
2539
|
|
|
2370
2540
|
/* ── Group — a fan of avatars that read as one party. ─────────────────────────
|
|
2371
2541
|
No z-index is set: later siblings simply paint over earlier ones in normal
|
|
@@ -2373,13 +2543,14 @@ aparte-conversation-list {
|
|
|
2373
2543
|
the one thing z-index would otherwise be needed for. */
|
|
2374
2544
|
.aparte-avatar-group {
|
|
2375
2545
|
display: inline-flex;
|
|
2546
|
+
vertical-align: middle;
|
|
2376
2547
|
align-items: center;
|
|
2377
2548
|
}
|
|
2378
2549
|
.aparte-avatar-group > .aparte-avatar {
|
|
2379
2550
|
box-shadow: 0 0 0 var(--aparte-avatar-group-ring-width) var(--aparte-avatar-group-ring-color);
|
|
2380
2551
|
}
|
|
2381
2552
|
.aparte-avatar-group > .aparte-avatar:not(:first-child) {
|
|
2382
|
-
margin-inline-start: calc(var(--aparte-avatar-
|
|
2553
|
+
margin-inline-start: calc(var(--aparte-avatar-size) * var(--aparte-avatar-overlap-ratio) * -1);
|
|
2383
2554
|
}
|
|
2384
2555
|
.aparte-avatar-group > .aparte-avatar:hover {
|
|
2385
2556
|
z-index: var(--aparte-z-raised);
|
|
@@ -2498,6 +2669,8 @@ aparte-icon {
|
|
|
2498
2669
|
--aparte-derived-ink: var(--aparte-on-intent);
|
|
2499
2670
|
|
|
2500
2671
|
display: inline-flex;
|
|
2672
|
+
|
|
2673
|
+
vertical-align: middle;
|
|
2501
2674
|
align-items: center;
|
|
2502
2675
|
justify-content: center;
|
|
2503
2676
|
gap: var(--aparte-badge-gap);
|
|
@@ -2595,6 +2768,7 @@ aparte-icon {
|
|
|
2595
2768
|
.aparte-tag {
|
|
2596
2769
|
box-sizing: border-box;
|
|
2597
2770
|
display: inline-flex;
|
|
2771
|
+
vertical-align: middle;
|
|
2598
2772
|
align-items: center;
|
|
2599
2773
|
gap: var(--aparte-tag-gap);
|
|
2600
2774
|
max-width: 100%;
|
|
@@ -2657,8 +2831,8 @@ aparte-icon {
|
|
|
2657
2831
|
* <span class="aparte-thumbnail aparte-thumbnail--lg"><img class="aparte-thumbnail__image"
|
|
2658
2832
|
* src="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2 3'%3E%3Crect width='2' height='3' fill='%23b07d33'/%3E%3C/svg%3E"
|
|
2659
2833
|
* alt="A screenshot"></span>
|
|
2660
|
-
* <span class="aparte-thumbnail"><span class="aparte-
|
|
2661
|
-
* <span class="aparte-thumbnail aparte-thumbnail--sm"><span class="aparte-
|
|
2834
|
+
* <span class="aparte-thumbnail"><span class="aparte-thumbnail__label">PDF</span></span>
|
|
2835
|
+
* <span class="aparte-thumbnail aparte-thumbnail--sm"><span class="aparte-thumbnail__label">MD</span></span>
|
|
2662
2836
|
*
|
|
2663
2837
|
* Distinct from `.aparte-avatar`, which is the same shape for a different reason: an
|
|
2664
2838
|
* avatar stands for a PERSON and falls back to initials, so it carries type styling and
|
|
@@ -2765,14 +2939,8 @@ aparte-icon {
|
|
|
2765
2939
|
}
|
|
2766
2940
|
|
|
2767
2941
|
.aparte-thumb--image[role='button']:focus-visible {
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
.aparte-thumb__img {
|
|
2772
|
-
width: 100%;
|
|
2773
|
-
height: 100%;
|
|
2774
|
-
object-fit: cover;
|
|
2775
|
-
display: block;
|
|
2942
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
2943
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
2776
2944
|
}
|
|
2777
2945
|
|
|
2778
2946
|
.aparte-thumb--file {
|
|
@@ -2781,13 +2949,6 @@ aparte-icon {
|
|
|
2781
2949
|
justify-content: center;
|
|
2782
2950
|
}
|
|
2783
2951
|
|
|
2784
|
-
.aparte-thumb__ext {
|
|
2785
|
-
font-size: var(--aparte-font-size-xs);
|
|
2786
|
-
font-weight: var(--aparte-font-weight-bold);
|
|
2787
|
-
letter-spacing: 0.03em;
|
|
2788
|
-
color: var(--aparte-text-muted);
|
|
2789
|
-
}
|
|
2790
|
-
|
|
2791
2952
|
.aparte-thumb__name {
|
|
2792
2953
|
position: absolute;
|
|
2793
2954
|
left: 0;
|
|
@@ -2818,9 +2979,13 @@ aparte-icon {
|
|
|
2818
2979
|
*/
|
|
2819
2980
|
|
|
2820
2981
|
.aparte-spinner {
|
|
2821
|
-
|
|
2822
2982
|
display: inline-block;
|
|
2983
|
+
vertical-align: middle;
|
|
2823
2984
|
flex-shrink: 0;
|
|
2985
|
+
/* The token is the ring's outer size, border included: without this the ring painted
|
|
2986
|
+
16/20/28 for tokens of 12/16/24 (the 2px stroke added on each side), and painted
|
|
2987
|
+
the token's value only on a host page with its own border-box reset. */
|
|
2988
|
+
box-sizing: border-box;
|
|
2824
2989
|
width: var(--aparte-spinner-size);
|
|
2825
2990
|
height: var(--aparte-spinner-size);
|
|
2826
2991
|
border: var(--aparte-spinner-thickness) solid currentColor;
|
|
@@ -2835,6 +3000,15 @@ aparte-icon {
|
|
|
2835
3000
|
|
|
2836
3001
|
.aparte-spinner--sm { --aparte-spinner-size: var(--aparte-spinner-size-sm); }
|
|
2837
3002
|
.aparte-spinner--lg { --aparte-spinner-size: var(--aparte-spinner-size-lg); }
|
|
3003
|
+
|
|
3004
|
+
/* Under reduced motion the loop stops outright. The duration tokens are reset to
|
|
3005
|
+
0.01ms in responsive.css, but that leaves `infinite` in place: a 0.01ms cycle
|
|
3006
|
+
is not stillness, it is a flicker. The descendant sweep there does not reach a
|
|
3007
|
+
recipe used outside aparté's own elements, so each looping recipe stops itself,
|
|
3008
|
+
the way display/icon.css already does. */
|
|
3009
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3010
|
+
.aparte-spinner { animation: none; }
|
|
3011
|
+
}
|
|
2838
3012
|
/* =========================================
|
|
2839
3013
|
aparte-progress — determinate bar + indeterminate variant
|
|
2840
3014
|
=========================================
|
|
@@ -2859,7 +3033,9 @@ aparte-icon {
|
|
|
2859
3033
|
width: 100%;
|
|
2860
3034
|
height: var(--aparte-progress-height);
|
|
2861
3035
|
border-radius: var(--aparte-radius-full);
|
|
2862
|
-
|
|
3036
|
+
/* The track: a reference the value is read against, so it has to be seen. A surface
|
|
3037
|
+
level put it at 1.06:1 in light and 1.20:1 in dark — one token, two distances. */
|
|
3038
|
+
background: var(--aparte-track);
|
|
2863
3039
|
}
|
|
2864
3040
|
|
|
2865
3041
|
.aparte-progress__bar {
|
|
@@ -2877,6 +3053,21 @@ aparte-icon {
|
|
|
2877
3053
|
animation: aparte-progress-slide var(--aparte-duration-pulse) var(--aparte-ease) infinite;
|
|
2878
3054
|
}
|
|
2879
3055
|
|
|
3056
|
+
/* Under reduced motion the loop stops outright. The duration tokens are reset to
|
|
3057
|
+
0.01ms in responsive.css, but that leaves `infinite` in place: a 0.01ms cycle
|
|
3058
|
+
is not stillness, it is a flicker. The descendant sweep there does not reach a
|
|
3059
|
+
recipe used outside aparté's own elements, so each looping recipe stops itself,
|
|
3060
|
+
the way display/icon.css already does.
|
|
3061
|
+
Stopped, the sliding segment would sit at one spot and read as a value; the whole
|
|
3062
|
+
track filled says "busy" without naming an amount. */
|
|
3063
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3064
|
+
.aparte-progress--indeterminate .aparte-progress__bar {
|
|
3065
|
+
animation: none;
|
|
3066
|
+
width: 100%;
|
|
3067
|
+
inset-inline-start: 0;
|
|
3068
|
+
}
|
|
3069
|
+
}
|
|
3070
|
+
|
|
2880
3071
|
/* inset-inline-start, not transform: translateX — a transform has no logical
|
|
2881
3072
|
axis, so an RTL page would slide the indeterminate segment backwards. Animating
|
|
2882
3073
|
a logical inset instead makes the sweep follow reading direction automatically. */
|
|
@@ -2909,10 +3100,15 @@ aparte-icon {
|
|
|
2909
3100
|
<div>
|
|
2910
3101
|
<span class="aparte-skeleton aparte-skeleton--text" aria-hidden="true"></span>
|
|
2911
3102
|
<span class="aparte-skeleton aparte-skeleton--text" aria-hidden="true"></span>
|
|
2912
|
-
<span class="aparte-skeleton aparte-skeleton--text" aria-hidden="true"></span>
|
|
3103
|
+
<span class="aparte-skeleton aparte-skeleton--text" style="max-inline-size: 60%" aria-hidden="true"></span>
|
|
2913
3104
|
</div>
|
|
2914
|
-
<span class="aparte-skeleton aparte-skeleton--rect" style="grid-column:
|
|
3105
|
+
<span class="aparte-skeleton aparte-skeleton--rect" style="grid-column: 2" aria-hidden="true"></span>
|
|
2915
3106
|
</div>
|
|
3107
|
+
|
|
3108
|
+
The last line is shorter because the last line of a paragraph is, and the block sits
|
|
3109
|
+
in the text column, under the lines it stands for — not across the avatar's. The
|
|
3110
|
+
rect's height is the family's token (`--aparte-skeleton-rect-height`), not an inline
|
|
3111
|
+
value that contradicts it.
|
|
2916
3112
|
*/
|
|
2917
3113
|
|
|
2918
3114
|
.aparte-skeleton {
|
|
@@ -2929,6 +3125,19 @@ aparte-icon {
|
|
|
2929
3125
|
animation: aparte-skeleton-shimmer var(--aparte-duration-pulse) linear infinite;
|
|
2930
3126
|
}
|
|
2931
3127
|
|
|
3128
|
+
/* Under reduced motion the loop stops outright. The duration tokens are reset to
|
|
3129
|
+
0.01ms in responsive.css, but that leaves `infinite` in place: a 0.01ms cycle
|
|
3130
|
+
is not stillness, it is a flicker. The descendant sweep there does not reach a
|
|
3131
|
+
recipe used outside aparté's own elements, so each looping recipe stops itself,
|
|
3132
|
+
the way display/icon.css already does.
|
|
3133
|
+
The shine goes with the shimmer: a stopped gradient would sit as a pale band. */
|
|
3134
|
+
@media (prefers-reduced-motion: reduce) {
|
|
3135
|
+
.aparte-skeleton {
|
|
3136
|
+
animation: none;
|
|
3137
|
+
background-image: none;
|
|
3138
|
+
}
|
|
3139
|
+
}
|
|
3140
|
+
|
|
2932
3141
|
.aparte-skeleton--text {
|
|
2933
3142
|
width: 100%;
|
|
2934
3143
|
height: var(--aparte-skeleton-text-height);
|
|
@@ -2936,7 +3145,7 @@ aparte-icon {
|
|
|
2936
3145
|
}
|
|
2937
3146
|
.aparte-skeleton--text + .aparte-skeleton--text { margin-block-start: var(--aparte-skeleton-text-gap); }
|
|
2938
3147
|
/* The ragged last line reads as "text", where a full-width block reads as a bar. */
|
|
2939
|
-
.aparte-skeleton--text:last-child { width: var(--aparte-skeleton-text-last-width); }
|
|
3148
|
+
.aparte-skeleton--text:last-child:not(:first-child) { width: var(--aparte-skeleton-text-last-width); }
|
|
2940
3149
|
|
|
2941
3150
|
.aparte-skeleton--circle {
|
|
2942
3151
|
width: var(--aparte-skeleton-circle-size);
|
|
@@ -3024,6 +3233,7 @@ aparte-icon {
|
|
|
3024
3233
|
<button class="aparte-alert__dismiss" aria-label="Dismiss"><aparte-icon name="close"></aparte-icon></button>
|
|
3025
3234
|
</div>
|
|
3026
3235
|
<div class="aparte-alert aparte-alert--danger" role="alert">
|
|
3236
|
+
<span class="aparte-alert__icon"><aparte-icon name="alertTriangle"></aparte-icon></span>
|
|
3027
3237
|
<div class="aparte-alert__body">
|
|
3028
3238
|
<p class="aparte-alert__message">The request was refused: no API key is set.</p>
|
|
3029
3239
|
</div>
|
|
@@ -3114,7 +3324,7 @@ aparte-icon {
|
|
|
3114
3324
|
}
|
|
3115
3325
|
.aparte-alert__dismiss:active:not(:disabled) { filter: brightness(0.93); }
|
|
3116
3326
|
.aparte-alert__dismiss:focus-visible {
|
|
3117
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
3327
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
3118
3328
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
3119
3329
|
}
|
|
3120
3330
|
.aparte-alert__dismiss:disabled { opacity: var(--aparte-disabled-opacity); cursor: not-allowed; pointer-events: none; }
|
|
@@ -3153,6 +3363,12 @@ aparte-icon {
|
|
|
3153
3363
|
padding: var(--aparte-card-body-padding);
|
|
3154
3364
|
}
|
|
3155
3365
|
|
|
3366
|
+
/* The body owns its edges: a paragraph's block margins fold into the padding instead of
|
|
3367
|
+
stacking on it. The sheet's own example puts a <p> here, and the body band measured
|
|
3368
|
+
twice the height of the header and footer beside it. */
|
|
3369
|
+
.aparte-card__body > :first-child { margin-block-start: 0; }
|
|
3370
|
+
.aparte-card__body > :last-child { margin-block-end: 0; }
|
|
3371
|
+
|
|
3156
3372
|
.aparte-card__footer {
|
|
3157
3373
|
display: flex;
|
|
3158
3374
|
align-items: center;
|
|
@@ -3427,7 +3643,7 @@ aparte-icon {
|
|
|
3427
3643
|
}
|
|
3428
3644
|
|
|
3429
3645
|
.aparte-tabs__tab:focus-visible {
|
|
3430
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
3646
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
3431
3647
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
3432
3648
|
}
|
|
3433
3649
|
|
|
@@ -3444,10 +3660,13 @@ aparte-icon {
|
|
|
3444
3660
|
|
|
3445
3661
|
.aparte-tabs__panel {
|
|
3446
3662
|
padding-block: var(--aparte-space-6);
|
|
3663
|
+
/* The tab's own inline inset, so the panel's text starts under the label of the tab
|
|
3664
|
+
that opened it rather than 11px to its left. */
|
|
3665
|
+
padding-inline: var(--aparte-space-5);
|
|
3447
3666
|
}
|
|
3448
3667
|
|
|
3449
3668
|
.aparte-tabs__panel:focus-visible {
|
|
3450
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
3669
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
3451
3670
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
3452
3671
|
}
|
|
3453
3672
|
|
|
@@ -3471,6 +3690,9 @@ aparte-icon {
|
|
|
3471
3690
|
its own raised chip, rather than an underline beneath a plain row. Same markup,
|
|
3472
3691
|
same states; only the container and the active tab's fill change. */
|
|
3473
3692
|
.aparte-tabs--segmented {
|
|
3693
|
+
/* A control, not a bar: the track hugs its segments. As a block-level flex row it
|
|
3694
|
+
inherited its container's width — 1207px of track for 160px of chips at 1280. */
|
|
3695
|
+
display: inline-flex;
|
|
3474
3696
|
gap: 0;
|
|
3475
3697
|
padding: var(--aparte-space-1);
|
|
3476
3698
|
background: var(--aparte-surface-2);
|
|
@@ -3490,6 +3712,11 @@ aparte-icon {
|
|
|
3490
3712
|
.aparte-tabs--segmented .aparte-tabs__tab[aria-selected='true'] {
|
|
3491
3713
|
background: var(--aparte-surface-1);
|
|
3492
3714
|
color: var(--aparte-text);
|
|
3715
|
+
/* Raised RELATIVE to the track, not an absolute surface level: surface-1 over
|
|
3716
|
+
surface-2 read as raised in light and as sunken in dark, the same rule inverting
|
|
3717
|
+
its elevation with the theme. A 1px ring in the border colour says "on top" on
|
|
3718
|
+
either ground. */
|
|
3719
|
+
box-shadow: 0 0 0 var(--aparte-border-width) var(--aparte-border);
|
|
3493
3720
|
}
|
|
3494
3721
|
/* =========================================
|
|
3495
3722
|
aparte-accordion — stacked disclosures
|
|
@@ -3506,7 +3733,21 @@ aparte-icon {
|
|
|
3506
3733
|
Shipping
|
|
3507
3734
|
<aparte-icon name="expand"></aparte-icon>
|
|
3508
3735
|
</summary>
|
|
3509
|
-
<div class="aparte-accordion__panel">Free above 50
|
|
3736
|
+
<div class="aparte-accordion__panel">Free above 50 €, otherwise 4,90 €. Two to four working days.</div>
|
|
3737
|
+
</details>
|
|
3738
|
+
<details class="aparte-accordion__item">
|
|
3739
|
+
<summary class="aparte-accordion__header">
|
|
3740
|
+
Returns
|
|
3741
|
+
<aparte-icon name="expand"></aparte-icon>
|
|
3742
|
+
</summary>
|
|
3743
|
+
<div class="aparte-accordion__panel">Thirty days, in the original packaging.</div>
|
|
3744
|
+
</details>
|
|
3745
|
+
<details class="aparte-accordion__item">
|
|
3746
|
+
<summary class="aparte-accordion__header">
|
|
3747
|
+
Payment
|
|
3748
|
+
<aparte-icon name="expand"></aparte-icon>
|
|
3749
|
+
</summary>
|
|
3750
|
+
<div class="aparte-accordion__panel">Card, PayPal, or an invoice for a company account.</div>
|
|
3510
3751
|
</details>
|
|
3511
3752
|
</div>
|
|
3512
3753
|
|
|
@@ -3574,7 +3815,7 @@ aparte-icon {
|
|
|
3574
3815
|
}
|
|
3575
3816
|
|
|
3576
3817
|
.aparte-accordion__header:focus-visible {
|
|
3577
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
3818
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
3578
3819
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
3579
3820
|
}
|
|
3580
3821
|
|
|
@@ -3584,13 +3825,22 @@ aparte-icon {
|
|
|
3584
3825
|
opacity: var(--aparte-disabled-opacity);
|
|
3585
3826
|
}
|
|
3586
3827
|
|
|
3587
|
-
|
|
3828
|
+
/* Two spellings for the chevron, because the header's documented markup is a bare
|
|
3829
|
+
`<aparte-icon>` and a renderer that wraps a raw glyph needs a class to hang it on:
|
|
3830
|
+
the wrapper `.aparte-accordion__icon` (the thinking block), or an `<aparte-icon>` /
|
|
3831
|
+
`svg.aparte-icon` sitting directly in the header. Both are sized and both turn — the
|
|
3832
|
+
documented form used to match neither rule, so the kit's own example showed an open
|
|
3833
|
+
panel under a chevron still pointing down. */
|
|
3834
|
+
.aparte-accordion__icon,
|
|
3835
|
+
.aparte-accordion__header > aparte-icon,
|
|
3836
|
+
.aparte-accordion__header > .aparte-icon {
|
|
3837
|
+
display: inline-flex;
|
|
3588
3838
|
flex-shrink: 0;
|
|
3589
|
-
/*
|
|
3590
|
-
|
|
3591
|
-
|
|
3592
|
-
|
|
3593
|
-
|
|
3839
|
+
/* Fed to the glyph through its own knob, not drawn as a width/height: the icon
|
|
3840
|
+
recipe reads `--aparte-icon-size`, and a box declared here around it would leave
|
|
3841
|
+
the glyph at its loose default. The step is the one the button recipe uses for an
|
|
3842
|
+
icon glyph, so a disclosure chevron reads as the same weight of icon everywhere. */
|
|
3843
|
+
--aparte-icon-size: var(--aparte-space-8);
|
|
3594
3844
|
color: var(--aparte-text-muted);
|
|
3595
3845
|
transition: transform var(--aparte-duration-slow) var(--aparte-ease);
|
|
3596
3846
|
}
|
|
@@ -3599,7 +3849,11 @@ aparte-icon {
|
|
|
3599
3849
|
puts aria-expanded on the header itself; native <details> puts `open` on the
|
|
3600
3850
|
ancestor and gives the browser no attribute to select on at all. */
|
|
3601
3851
|
.aparte-accordion__header[aria-expanded='true'] .aparte-accordion__icon,
|
|
3602
|
-
|
|
3852
|
+
.aparte-accordion__header[aria-expanded='true'] > aparte-icon,
|
|
3853
|
+
.aparte-accordion__header[aria-expanded='true'] > .aparte-icon,
|
|
3854
|
+
details[open] > .aparte-accordion__header .aparte-accordion__icon,
|
|
3855
|
+
details[open] > .aparte-accordion__header > aparte-icon,
|
|
3856
|
+
details[open] > .aparte-accordion__header > .aparte-icon {
|
|
3603
3857
|
transform: rotate(180deg);
|
|
3604
3858
|
}
|
|
3605
3859
|
|
|
@@ -3673,10 +3927,13 @@ details[open] > .aparte-accordion__header .aparte-accordion__icon {
|
|
|
3673
3927
|
width: max-content;
|
|
3674
3928
|
min-width: var(--aparte-menu-min-width);
|
|
3675
3929
|
max-width: var(--aparte-menu-max-width);
|
|
3930
|
+
/* The two caps are the box's outer width, padding and border included — same rule
|
|
3931
|
+
as the popover, for the same reason. */
|
|
3932
|
+
box-sizing: border-box;
|
|
3676
3933
|
padding: var(--aparte-space-2);
|
|
3677
3934
|
background: var(--aparte-surface-1);
|
|
3678
3935
|
border: var(--aparte-border-width) solid var(--aparte-border);
|
|
3679
|
-
border-radius: var(--aparte-radius-
|
|
3936
|
+
border-radius: var(--aparte-radius-menu);
|
|
3680
3937
|
box-shadow: var(--aparte-menu-shadow);
|
|
3681
3938
|
color: var(--aparte-text);
|
|
3682
3939
|
z-index: var(--aparte-z-dropdown);
|
|
@@ -3722,7 +3979,7 @@ details[open] > .aparte-accordion__header .aparte-accordion__icon {
|
|
|
3722
3979
|
}
|
|
3723
3980
|
|
|
3724
3981
|
.aparte-menu__item:focus-visible {
|
|
3725
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
3982
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
3726
3983
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
3727
3984
|
}
|
|
3728
3985
|
|
|
@@ -3735,14 +3992,14 @@ details[open] > .aparte-accordion__header .aparte-accordion__icon {
|
|
|
3735
3992
|
pointer-events: none;
|
|
3736
3993
|
}
|
|
3737
3994
|
|
|
3738
|
-
/* The check mark for menuitemcheckbox / menuitemradio.
|
|
3739
|
-
|
|
3740
|
-
|
|
3741
|
-
a plain role="menuitem"
|
|
3742
|
-
rather than a fill or a box-shadow is deliberate: a
|
|
3743
|
-
which forced-colors mode preserves, so the checked state
|
|
3744
|
-
with no separate override. */
|
|
3745
|
-
.aparte-menu__item[aria-checked]::before {
|
|
3995
|
+
/* The check mark for menuitemcheckbox / menuitemradio. The gutter is reserved on EVERY
|
|
3996
|
+
item of a panel that holds a checkable one — as an invisible glyph — so all the
|
|
3997
|
+
labels of that panel share one edge. It used to be reserved per checkable item, and
|
|
3998
|
+
a plain role="menuitem" beside a checkable one started 16px further left: two label
|
|
3999
|
+
edges in one menu. Text colour rather than a fill or a box-shadow is deliberate: a
|
|
4000
|
+
glyph inherits `color`, which forced-colors mode preserves, so the checked state
|
|
4001
|
+
survives that mode with no separate override. */
|
|
4002
|
+
.aparte-menu:has(.aparte-menu__item[aria-checked]) .aparte-menu__item::before {
|
|
3746
4003
|
content: '✓';
|
|
3747
4004
|
flex-shrink: 0;
|
|
3748
4005
|
visibility: hidden;
|
|
@@ -3817,11 +4074,14 @@ details[open] > .aparte-accordion__header .aparte-accordion__icon {
|
|
|
3817
4074
|
display: flex;
|
|
3818
4075
|
flex-direction: column;
|
|
3819
4076
|
gap: var(--aparte-space-3);
|
|
4077
|
+
/* The cap is the box's outer width: it measured 342px for a documented 320 (padding
|
|
4078
|
+
and border outside the cap) until the recipe said so itself. */
|
|
4079
|
+
box-sizing: border-box;
|
|
3820
4080
|
max-width: var(--aparte-popover-max-width);
|
|
3821
4081
|
padding: var(--aparte-space-5);
|
|
3822
4082
|
background: var(--aparte-surface-1);
|
|
3823
4083
|
border: var(--aparte-border-width) solid var(--aparte-border);
|
|
3824
|
-
border-radius: var(--aparte-radius-
|
|
4084
|
+
border-radius: var(--aparte-radius-popover);
|
|
3825
4085
|
box-shadow: var(--aparte-popover-shadow);
|
|
3826
4086
|
color: var(--aparte-text);
|
|
3827
4087
|
font-size: var(--aparte-font-size-md);
|
|
@@ -3884,7 +4144,7 @@ details[open] > .aparte-accordion__header .aparte-accordion__icon {
|
|
|
3884
4144
|
background: var(--aparte-surface-1);
|
|
3885
4145
|
color: var(--aparte-text);
|
|
3886
4146
|
border: var(--aparte-border-width) solid var(--aparte-border);
|
|
3887
|
-
border-radius: var(--aparte-radius-
|
|
4147
|
+
border-radius: var(--aparte-radius-dialog);
|
|
3888
4148
|
box-shadow: var(--aparte-menu-shadow);
|
|
3889
4149
|
}
|
|
3890
4150
|
|
|
@@ -3960,11 +4220,20 @@ body:has(.aparte-dialog[open]) {
|
|
|
3960
4220
|
.aparte-dialog:modal {
|
|
3961
4221
|
width: 100%;
|
|
3962
4222
|
max-width: 100%;
|
|
3963
|
-
|
|
4223
|
+
/* As tall as its content, capped at the screen, sitting on the bottom edge: a sheet
|
|
4224
|
+
stretched to 100dvh held a label, a field and two buttons over 586px of nothing.
|
|
4225
|
+
`fit-content`, not `auto` — on a positioned box with both block insets set, an
|
|
4226
|
+
auto height FILLS them (CSS 2 §10.6.4: the auto margins go to 0 and the height
|
|
4227
|
+
is solved for), so `auto` measured the same 720 the explicit 100dvh had. What
|
|
4228
|
+
the UA gives a dialog is `fit-content`, and it is what lets the auto top margin
|
|
4229
|
+
push the sheet onto the bottom edge. And the safe areas: the ✕ used to sit 6px
|
|
4230
|
+
from the physical top. */
|
|
4231
|
+
height: fit-content;
|
|
3964
4232
|
max-height: 100dvh;
|
|
3965
|
-
margin: 0;
|
|
4233
|
+
margin: auto 0 0;
|
|
4234
|
+
padding-block: env(safe-area-inset-top, 0px) env(safe-area-inset-bottom, 0px);
|
|
3966
4235
|
border: 0;
|
|
3967
|
-
border-radius: 0;
|
|
4236
|
+
border-radius: var(--aparte-radius-dialog) var(--aparte-radius-dialog) 0 0;
|
|
3968
4237
|
}
|
|
3969
4238
|
}
|
|
3970
4239
|
|
|
@@ -4001,23 +4270,22 @@ body:has(.aparte-dialog[open]) {
|
|
|
4001
4270
|
and skips the dark-theme override block for that reason; the artifact "paper" tokens
|
|
4002
4271
|
are the same decision made for the same reason.
|
|
4003
4272
|
|
|
4004
|
-
<span
|
|
4005
|
-
<div class="aparte-tooltip" role="tooltip"
|
|
4006
|
-
style="position: absolute; bottom: calc(100% + 8px); left: 50%; translate: -50% 0">
|
|
4273
|
+
<span class="aparte-tooltip-anchor" style="margin-block-start: 2.5rem; margin-inline-start: 5rem">
|
|
4274
|
+
<div class="aparte-tooltip" data-side="top" role="tooltip">
|
|
4007
4275
|
Copy to clipboard
|
|
4008
4276
|
<span class="aparte-tooltip__arrow"></span>
|
|
4009
4277
|
</div>
|
|
4010
4278
|
<button class="aparte-btn aparte-btn--icon" aria-label="Copy"><aparte-icon name="copy"></aparte-icon></button>
|
|
4011
4279
|
</span>
|
|
4012
4280
|
|
|
4013
|
-
|
|
4014
|
-
|
|
4015
|
-
|
|
4016
|
-
|
|
4017
|
-
|
|
4018
|
-
|
|
4019
|
-
|
|
4020
|
-
|
|
4281
|
+
`data-side` places it — `top`, `bottom`, `start` or `end` — against the
|
|
4282
|
+
`.aparte-tooltip-anchor` that wraps the trigger, `--aparte-tooltip-gap` away, and turns
|
|
4283
|
+
the arrow to match. The two inline styles that used to do this in the example were a
|
|
4284
|
+
knob missing, not a division of labour: a demo that needs inline styles to work is a
|
|
4285
|
+
recipe with a parameter it forgot. What stays yours is the viewport: nothing here flips
|
|
4286
|
+
a tooltip that would leave the screen — that needs script, a positioning library's job.
|
|
4287
|
+
Without `data-side` the box is not positioned at all, as before, and its placement is
|
|
4288
|
+
yours (the one inline style left in the example is the demo's own margin).
|
|
4021
4289
|
|
|
4022
4290
|
`pointer-events: none` is not a detail: a tooltip describes what the pointer is over,
|
|
4023
4291
|
so it must never itself become that thing, or hovering it re-triggers the hover that
|
|
@@ -4034,11 +4302,17 @@ body:has(.aparte-dialog[open]) {
|
|
|
4034
4302
|
|
|
4035
4303
|
position: relative;
|
|
4036
4304
|
display: inline-block;
|
|
4305
|
+
vertical-align: middle;
|
|
4306
|
+
/* As wide as its label, up to the cap. With a `max-width` and no intrinsic width an
|
|
4307
|
+
absolutely-positioned chip shrinks to `min-content`: "Copy to clipboard" broke into
|
|
4308
|
+
two lines at every width, 71px wide — the widest word plus padding. */
|
|
4309
|
+
width: max-content;
|
|
4310
|
+
box-sizing: border-box;
|
|
4037
4311
|
max-width: var(--aparte-tooltip-max-width);
|
|
4038
4312
|
padding: var(--aparte-space-2) var(--aparte-space-4);
|
|
4039
4313
|
background: var(--aparte-tooltip-bg);
|
|
4040
4314
|
color: var(--aparte-tooltip-color);
|
|
4041
|
-
border-radius: var(--aparte-radius-
|
|
4315
|
+
border-radius: var(--aparte-radius-tooltip);
|
|
4042
4316
|
box-shadow: var(--aparte-tooltip-shadow);
|
|
4043
4317
|
font-size: var(--aparte-font-size-sm);
|
|
4044
4318
|
line-height: var(--aparte-line-height-snug);
|
|
@@ -4050,12 +4324,49 @@ body:has(.aparte-dialog[open]) {
|
|
|
4050
4324
|
pointer-events: none;
|
|
4051
4325
|
}
|
|
4052
4326
|
|
|
4053
|
-
/*
|
|
4054
|
-
it
|
|
4055
|
-
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4327
|
+
/* Where the box goes: the anchor is the trigger's wrapper and the tooltip is placed
|
|
4328
|
+
against it. `translate` centres the box on the axis across the side: with a logical
|
|
4329
|
+
inset of 50% the box's start edge sits at the anchor's middle, and moving it back by
|
|
4330
|
+
half its own size centres it — in both writing directions, because the inset flips
|
|
4331
|
+
with the direction and the translate is half the box either way. */
|
|
4332
|
+
.aparte-tooltip-anchor {
|
|
4333
|
+
position: relative;
|
|
4334
|
+
display: inline-block;
|
|
4335
|
+
vertical-align: middle;
|
|
4336
|
+
}
|
|
4337
|
+
|
|
4338
|
+
.aparte-tooltip[data-side] {
|
|
4339
|
+
position: absolute;
|
|
4340
|
+
}
|
|
4341
|
+
|
|
4342
|
+
.aparte-tooltip[data-side='top'] {
|
|
4343
|
+
inset-block-end: calc(100% + var(--aparte-tooltip-gap));
|
|
4344
|
+
inset-inline-start: 50%;
|
|
4345
|
+
translate: -50% 0;
|
|
4346
|
+
}
|
|
4347
|
+
|
|
4348
|
+
.aparte-tooltip[data-side='bottom'] {
|
|
4349
|
+
inset-block-start: calc(100% + var(--aparte-tooltip-gap));
|
|
4350
|
+
inset-inline-start: 50%;
|
|
4351
|
+
translate: -50% 0;
|
|
4352
|
+
}
|
|
4353
|
+
|
|
4354
|
+
.aparte-tooltip[data-side='start'] {
|
|
4355
|
+
inset-inline-end: calc(100% + var(--aparte-tooltip-gap));
|
|
4356
|
+
inset-block-start: 50%;
|
|
4357
|
+
translate: 0 -50%;
|
|
4358
|
+
}
|
|
4359
|
+
|
|
4360
|
+
.aparte-tooltip[data-side='end'] {
|
|
4361
|
+
inset-inline-start: calc(100% + var(--aparte-tooltip-gap));
|
|
4362
|
+
inset-block-start: 50%;
|
|
4363
|
+
translate: 0 -50%;
|
|
4364
|
+
}
|
|
4365
|
+
|
|
4366
|
+
/* The arrow points DOWN by default — the common case, a tooltip above the thing it
|
|
4367
|
+
labels — and each `data-side` turns it toward the anchor. Centring on the box's edge
|
|
4368
|
+
uses a logical inset plus a negative margin rather than a transform, so it re-centres
|
|
4369
|
+
under `direction: rtl` without a second rule. */
|
|
4059
4370
|
.aparte-tooltip__arrow {
|
|
4060
4371
|
position: absolute;
|
|
4061
4372
|
inset-inline-start: 50%;
|
|
@@ -4074,6 +4385,26 @@ body:has(.aparte-dialog[open]) {
|
|
|
4074
4385
|
inset-block-start: calc(var(--aparte-space-4) * -0.5);
|
|
4075
4386
|
}
|
|
4076
4387
|
|
|
4388
|
+
/* On the two inline sides the arrow sits on the edge that faces the anchor, centred
|
|
4389
|
+
vertically: the box is to the START of the trigger, so its arrow is on its END edge,
|
|
4390
|
+
and the reverse. */
|
|
4391
|
+
.aparte-tooltip[data-side='start'] .aparte-tooltip__arrow {
|
|
4392
|
+
inset-block-end: auto;
|
|
4393
|
+
inset-block-start: 50%;
|
|
4394
|
+
inset-inline-start: auto;
|
|
4395
|
+
inset-inline-end: calc(var(--aparte-space-4) * -0.5);
|
|
4396
|
+
margin-inline-start: 0;
|
|
4397
|
+
margin-block-start: calc(var(--aparte-space-4) * -0.5);
|
|
4398
|
+
}
|
|
4399
|
+
|
|
4400
|
+
.aparte-tooltip[data-side='end'] .aparte-tooltip__arrow {
|
|
4401
|
+
inset-block-end: auto;
|
|
4402
|
+
inset-block-start: 50%;
|
|
4403
|
+
inset-inline-start: calc(var(--aparte-space-4) * -0.5);
|
|
4404
|
+
margin-inline-start: 0;
|
|
4405
|
+
margin-block-start: calc(var(--aparte-space-4) * -0.5);
|
|
4406
|
+
}
|
|
4407
|
+
|
|
4077
4408
|
/* ── Forced colors ───────────────────────────────────────────────────────────────
|
|
4078
4409
|
The menu and the popover already carry a real border by default, so those two
|
|
4079
4410
|
boxes survive forced-colors mode once background and box-shadow are both
|
|
@@ -4116,10 +4447,16 @@ aparte-select {
|
|
|
4116
4447
|
align-items: center;
|
|
4117
4448
|
justify-content: space-between;
|
|
4118
4449
|
gap: var(--aparte-space-4);
|
|
4450
|
+
box-sizing: border-box;
|
|
4451
|
+
min-block-size: var(--aparte-field-size);
|
|
4119
4452
|
padding: var(--aparte-space-4) var(--aparte-space-6);
|
|
4453
|
+
/* Its own size: the trigger declared none and took the host page's, so every
|
|
4454
|
+
integrator saw a different select. The control step, like the field and the
|
|
4455
|
+
button. */
|
|
4456
|
+
font-size: var(--aparte-font-size-md);
|
|
4120
4457
|
background: var(--aparte-select-bg, var(--aparte-surface-1));
|
|
4121
|
-
border: var(--aparte-border-width) solid var(--aparte-select-border, var(--aparte-border));
|
|
4122
|
-
border-radius: var(--aparte-
|
|
4458
|
+
border: var(--aparte-border-width) solid var(--aparte-select-border, var(--aparte-border-control));
|
|
4459
|
+
border-radius: var(--aparte-radius-select);
|
|
4123
4460
|
cursor: pointer;
|
|
4124
4461
|
transition: border-color var(--aparte-duration-base), box-shadow var(--aparte-duration-base);
|
|
4125
4462
|
}
|
|
@@ -4128,15 +4465,16 @@ aparte-select {
|
|
|
4128
4465
|
border-color: var(--aparte-select-border-hover, var(--aparte-primary));
|
|
4129
4466
|
}
|
|
4130
4467
|
|
|
4131
|
-
.aparte-select-trigger:focus {
|
|
4132
|
-
outline:
|
|
4133
|
-
|
|
4134
|
-
box-shadow: var(--aparte-select-ring, var(--aparte-focus-ring));
|
|
4468
|
+
.aparte-select-trigger:focus-visible {
|
|
4469
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
4470
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
4135
4471
|
}
|
|
4136
4472
|
|
|
4137
4473
|
aparte-select[disabled] .aparte-select-trigger {
|
|
4138
|
-
opacity: var(--aparte-disabled-opacity);
|
|
4139
4474
|
cursor: not-allowed;
|
|
4475
|
+
background: var(--aparte-surface-2);
|
|
4476
|
+
color: var(--aparte-text-muted);
|
|
4477
|
+
border-color: var(--aparte-border);
|
|
4140
4478
|
}
|
|
4141
4479
|
|
|
4142
4480
|
/* The label is a grid with ONE cell: the visible text and, under it, a hidden stack of
|
|
@@ -4196,8 +4534,10 @@ aparte-select[open] .aparte-select-chevron {
|
|
|
4196
4534
|
position: fixed;
|
|
4197
4535
|
/* top / left / width are set dynamically by _updatePosition() */
|
|
4198
4536
|
background: var(--aparte-select-dropdown-bg, var(--aparte-surface-1));
|
|
4199
|
-
|
|
4200
|
-
|
|
4537
|
+
/* The panel is a region, so its edge is the region border; `--aparte-select-border`
|
|
4538
|
+
is the TRIGGER's edge, a control's, and defaults to the control border. */
|
|
4539
|
+
border: var(--aparte-border-width) solid var(--aparte-border);
|
|
4540
|
+
border-radius: var(--aparte-radius-select);
|
|
4201
4541
|
box-shadow: var(--aparte-select-shadow);
|
|
4202
4542
|
z-index: var(--aparte-select-z, var(--aparte-z-dropdown));
|
|
4203
4543
|
max-height: var(--aparte-select-dropdown-max-height);
|
|
@@ -4221,8 +4561,11 @@ aparte-select[open] .aparte-select-chevron {
|
|
|
4221
4561
|
font-family: inherit;
|
|
4222
4562
|
}
|
|
4223
4563
|
|
|
4224
|
-
|
|
4225
|
-
|
|
4564
|
+
/* Inside, not outside: the field sits at the top of a scrolling panel, and an outset
|
|
4565
|
+
ring would be clipped by it. The one documented exception to the shared offset. */
|
|
4566
|
+
.aparte-select-search:focus-visible {
|
|
4567
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
4568
|
+
outline-offset: calc(-1 * var(--aparte-focus-outline-width));
|
|
4226
4569
|
}
|
|
4227
4570
|
|
|
4228
4571
|
/* Options container */
|
|
@@ -4359,6 +4702,7 @@ aparte-optgroup[collapsed] .aparte-optgroup-chevron {
|
|
|
4359
4702
|
}
|
|
4360
4703
|
|
|
4361
4704
|
.aparte-spinner-small {
|
|
4705
|
+
box-sizing: border-box;
|
|
4362
4706
|
width: var(--aparte-select-spinner-size);
|
|
4363
4707
|
height: var(--aparte-select-spinner-size);
|
|
4364
4708
|
border: 2px solid currentColor;
|
|
@@ -4366,6 +4710,12 @@ aparte-optgroup[collapsed] .aparte-optgroup-chevron {
|
|
|
4366
4710
|
border-radius: 50%;
|
|
4367
4711
|
/* `aparte-spin` is declared once, in base.css — see the shared-motion block there. */
|
|
4368
4712
|
animation: aparte-spin var(--aparte-duration-spin) linear infinite;
|
|
4713
|
+
}
|
|
4714
|
+
|
|
4715
|
+
/* The element's own sweep in responsive.css already stops this one; the rule is here
|
|
4716
|
+
so the recipe stops on its own terms too, like every other looping recipe. */
|
|
4717
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4718
|
+
.aparte-spinner-small { animation: none; }
|
|
4369
4719
|
}/**
|
|
4370
4720
|
* AparteProgressSpinner — CSS
|
|
4371
4721
|
*
|
|
@@ -4391,16 +4741,23 @@ aparte-progress-spinner svg {
|
|
|
4391
4741
|
overflow: visible;
|
|
4392
4742
|
}
|
|
4393
4743
|
|
|
4744
|
+
/* The same stroke as the CSS ring (`.aparte-spinner`), in SCREEN pixels: without
|
|
4745
|
+
`vector-effect` a stroke is in viewBox units and scaled with the box — 2.5 of 24 was
|
|
4746
|
+
1.67px in a 16px spinner, antialiased everywhere and 50 % lighter than its sibling.
|
|
4747
|
+
The track is a visible reference in the control-edge colour: at 15 % of the ink a
|
|
4748
|
+
determinate 62 % was the percentage of a circle nobody could see. */
|
|
4394
4749
|
.aparte-spinner-track {
|
|
4395
4750
|
fill: none;
|
|
4396
|
-
stroke: var(--aparte-spinner-track,
|
|
4397
|
-
stroke-width: var(--aparte-spinner-
|
|
4751
|
+
stroke: var(--aparte-spinner-track, var(--aparte-border-control));
|
|
4752
|
+
stroke-width: var(--aparte-spinner-thickness);
|
|
4753
|
+
vector-effect: non-scaling-stroke;
|
|
4398
4754
|
}
|
|
4399
4755
|
|
|
4400
4756
|
.aparte-spinner-fill {
|
|
4401
4757
|
fill: none;
|
|
4402
4758
|
stroke: var(--aparte-spinner-color, currentColor);
|
|
4403
|
-
stroke-width: var(--aparte-spinner-
|
|
4759
|
+
stroke-width: var(--aparte-spinner-thickness);
|
|
4760
|
+
vector-effect: non-scaling-stroke;
|
|
4404
4761
|
stroke-linecap: round;
|
|
4405
4762
|
transition: stroke-dashoffset 0.25s var(--aparte-ease);
|
|
4406
4763
|
}
|
|
@@ -4448,6 +4805,10 @@ aparte-chat,
|
|
|
4448
4805
|
height: 100%;
|
|
4449
4806
|
width: 100%;
|
|
4450
4807
|
overflow: hidden;
|
|
4808
|
+
/* The height an author sets IS the box: with the bottom gap below outside it,
|
|
4809
|
+
`style="height: 24rem"` rendered 336px, and a split's seam hung 16px under both
|
|
4810
|
+
panels. */
|
|
4811
|
+
box-sizing: border-box;
|
|
4451
4812
|
/* The composer used to touch the bottom edge as soon as a conversation started: the
|
|
4452
4813
|
viewport gives 16px above the composer and there was nothing below it. An app
|
|
4453
4814
|
cannot fix this from outside without padding the container, which also shrinks the
|
|
@@ -4519,6 +4880,14 @@ aparte-chat[overlay-composer] > :not(aparte-chat-viewport),
|
|
|
4519
4880
|
z-index: var(--aparte-z-raised);
|
|
4520
4881
|
}
|
|
4521
4882
|
|
|
4883
|
+
/* A thing that floats has to be seen floating. The overlaid composer's shell shares the
|
|
4884
|
+
transcript's ground, so a z-index alone left it flat on the words it covers. */
|
|
4885
|
+
aparte-chat[overlay-composer] .aparte-composer-shell,
|
|
4886
|
+
[data-aparte-chat][overlay-composer] .aparte-composer-shell,
|
|
4887
|
+
.aparte-chat-container[overlay-composer] .aparte-composer-shell {
|
|
4888
|
+
box-shadow: var(--aparte-composer-overlay-shadow);
|
|
4889
|
+
}
|
|
4890
|
+
|
|
4522
4891
|
/* center-empty: the shell centers the composer as a welcome state until the first
|
|
4523
4892
|
message, then slides to the normal layout. The component toggles [data-empty]
|
|
4524
4893
|
on itself by watching its viewport — only `flex-grow` animates, so the composer
|
|
@@ -4541,6 +4910,17 @@ aparte-chat[center-empty][data-empty] > aparte-chat-viewport {
|
|
|
4541
4910
|
height: auto;
|
|
4542
4911
|
}
|
|
4543
4912
|
|
|
4913
|
+
/* And no block room at all: at `auto` the empty viewport still stood 32px tall — the
|
|
4914
|
+
rows' wrapper keeps its block padding with no row in it — so `center` centred three
|
|
4915
|
+
items of which the first was invisible, and the welcome group landed 16px low,
|
|
4916
|
+
measured. The padding goes, not the box: capping the viewport itself left a 32px
|
|
4917
|
+
scroll surface inside a 0px box, and "an empty transcript must not overflow" is a
|
|
4918
|
+
browser test every example runs. Inline geometry is kept — the composer's inset is
|
|
4919
|
+
measured from this element. */
|
|
4920
|
+
aparte-chat[center-empty][data-empty] > aparte-chat-viewport .aparte-messages-wrapper {
|
|
4921
|
+
padding-block: 0;
|
|
4922
|
+
}
|
|
4923
|
+
|
|
4544
4924
|
/* =========================================
|
|
4545
4925
|
aparte-chat-viewport
|
|
4546
4926
|
========================================= */
|
|
@@ -4607,16 +4987,16 @@ aparte-chat-viewport.aparte-viewport--framework::-webkit-scrollbar-thumb {
|
|
|
4607
4987
|
|
|
4608
4988
|
/* ─── Scroll-to-bottom button ─────────────────────────────────────────────── */
|
|
4609
4989
|
|
|
4610
|
-
/* The button wears `aparte-btn--lg aparte-btn--circle
|
|
4611
|
-
|
|
4612
|
-
|
|
4613
|
-
is
|
|
4990
|
+
/* The button wears `aparte-btn--lg aparte-btn--circle`: `--lg` gives it the 20px glyph
|
|
4991
|
+
and the lg step of the scale (36px), `--circle` the round corner, and
|
|
4992
|
+
`--aparte-scroll-btn-size` (the same step, named for this button so a theme can move
|
|
4993
|
+
it alone) is fed to the recipe below. What stays here is only what is genuinely this
|
|
4994
|
+
button's — where it floats, and its own surface.
|
|
4614
4995
|
|
|
4615
4996
|
It used to redraw all three: its own width/height, its own `border-radius: 50%`, and
|
|
4616
4997
|
an icon-size override that existed only because the box was declared OUTSIDE the size
|
|
4617
|
-
scale, so the glyph stayed at the medium default — a 16px arrow in a 36px circle
|
|
4618
|
-
|
|
4619
|
-
the ratio fall out for free, and the override disappears with it.
|
|
4998
|
+
scale, so the glyph stayed at the medium default — a 16px arrow in a 36px circle.
|
|
4999
|
+
Naming the size on the recipe's own token makes the override disappear.
|
|
4620
5000
|
|
|
4621
5001
|
`--aparte-scroll-btn-size` stays the public knob, fed to the recipe. */
|
|
4622
5002
|
.aparte-scroll-btn {
|
|
@@ -4888,7 +5268,11 @@ aparte-chat-bubble {
|
|
|
4888
5268
|
box-sizing: border-box;
|
|
4889
5269
|
display: flex;
|
|
4890
5270
|
gap: var(--aparte-message-gap);
|
|
4891
|
-
|
|
5271
|
+
/* The two parts, not the composite `--aparte-message-padding` that used to join them
|
|
5272
|
+
on `:root`: a custom property is substituted where it is declared, so the composite
|
|
5273
|
+
froze both parts at the root and the narrow-container override of them in
|
|
5274
|
+
responsive.css never reached this row. */
|
|
5275
|
+
padding: var(--aparte-message-padding-block) var(--aparte-message-padding-inline);
|
|
4892
5276
|
width: 100%;
|
|
4893
5277
|
max-width: var(--aparte-message-max-width);
|
|
4894
5278
|
margin: 0 auto;
|
|
@@ -4976,6 +5360,11 @@ aparte-chat-bubble {
|
|
|
4976
5360
|
opacity: 0;
|
|
4977
5361
|
transition: opacity var(--aparte-duration-base) var(--aparte-ease);
|
|
4978
5362
|
height: var(--aparte-action-bar-btn-size);
|
|
5363
|
+
/* The INK meets the column, not the box: a glyph is centred in its 24px button, so
|
|
5364
|
+
its ink began half the slack — (24 − 12) / 2 — to the right of the paragraph above.
|
|
5365
|
+
Measured at +5 to +8px in 14 previews. The bar takes that slack back and the box
|
|
5366
|
+
overhangs into the message padding, where nothing else lives. */
|
|
5367
|
+
margin-inline-start: calc((var(--aparte-icon-size-sm) - var(--aparte-btn-size-sm)) / 2);
|
|
4979
5368
|
}
|
|
4980
5369
|
|
|
4981
5370
|
.aparte-message:hover .aparte-action-bar,
|
|
@@ -5040,8 +5429,6 @@ aparte-chat-bubble:last-of-type .aparte-message[data-role="assistant"]:not(.apar
|
|
|
5040
5429
|
inset-block-end: calc(-1 * (var(--aparte-message-padding-block) + var(--aparte-message-gap)));
|
|
5041
5430
|
margin: 0;
|
|
5042
5431
|
z-index: 1;
|
|
5043
|
-
/* Smaller than the last reply's 28px: this one lives in the padding. */
|
|
5044
|
-
--aparte-action-bar-btn-size: 24px;
|
|
5045
5432
|
}
|
|
5046
5433
|
}
|
|
5047
5434
|
|
|
@@ -5090,12 +5477,11 @@ aparte-chat-bubble:last-of-type .aparte-message[data-role="assistant"]:not(.apar
|
|
|
5090
5477
|
display: none;
|
|
5091
5478
|
}
|
|
5092
5479
|
|
|
5480
|
+
/* The arrows wear `--sm` and the recipe draws the box: this rule used to redraw
|
|
5481
|
+
width/height to a 20px token over it — two sources for one measure. */
|
|
5093
5482
|
.aparte-branch-prev,
|
|
5094
5483
|
.aparte-branch-next {
|
|
5095
5484
|
color: var(--aparte-branch-picker-btn-color);
|
|
5096
|
-
width: var(--aparte-branch-picker-btn-size);
|
|
5097
|
-
height: var(--aparte-branch-picker-btn-size);
|
|
5098
|
-
font-size: var(--aparte-branch-picker-btn-icon-size);
|
|
5099
5485
|
}
|
|
5100
5486
|
|
|
5101
5487
|
.aparte-branch-prev:hover:not(:disabled),
|
|
@@ -5104,9 +5490,11 @@ aparte-chat-bubble:last-of-type .aparte-message[data-role="assistant"]:not(.apar
|
|
|
5104
5490
|
background: var(--aparte-action-bar-btn-hover-bg);
|
|
5105
5491
|
}
|
|
5106
5492
|
|
|
5493
|
+
/* The button recipe draws the disabled state (a neutral ground, the muted ink); an
|
|
5494
|
+
opacity over it read the arrow at 1.74:1 — as absent, where the picker means "no
|
|
5495
|
+
further". `default` and not `not-allowed`: the end of a list is not a refusal. */
|
|
5107
5496
|
.aparte-branch-prev:disabled,
|
|
5108
5497
|
.aparte-branch-next:disabled {
|
|
5109
|
-
opacity: var(--aparte-disabled-opacity);
|
|
5110
5498
|
cursor: default;
|
|
5111
5499
|
}
|
|
5112
5500
|
|
|
@@ -5206,7 +5594,9 @@ aparte-chat-bubble[data-kind="compaction"] .aparte-message-content {
|
|
|
5206
5594
|
Unscoped so it greys the composer in EVERY host (vanilla shell + all wrappers),
|
|
5207
5595
|
not only a `[data-aparte-chat]` direct child. */
|
|
5208
5596
|
aparte-composer[data-model-gated] {
|
|
5209
|
-
|
|
5597
|
+
/* No group fade: each control draws its own disabled state (the editor's muted ink,
|
|
5598
|
+
the send button's neutral ground), so the text stays legible while it waits. */
|
|
5599
|
+
cursor: not-allowed;
|
|
5210
5600
|
}
|
|
5211
5601
|
aparte-composer[data-model-gated] aparte-composer-send {
|
|
5212
5602
|
pointer-events: none;
|
|
@@ -5362,7 +5752,7 @@ aparte-chat-viewport.aparte-viewport--framework::-webkit-scrollbar-thumb {
|
|
|
5362
5752
|
|
|
5363
5753
|
/* Disabled state */
|
|
5364
5754
|
.aparte-editor[contenteditable="false"] {
|
|
5365
|
-
|
|
5755
|
+
color: var(--aparte-text-muted);
|
|
5366
5756
|
cursor: not-allowed;
|
|
5367
5757
|
}
|
|
5368
5758
|
|
|
@@ -5403,9 +5793,9 @@ aparte-chat-viewport.aparte-viewport--framework::-webkit-scrollbar-thumb {
|
|
|
5403
5793
|
}
|
|
5404
5794
|
|
|
5405
5795
|
.aparte-send-button:disabled {
|
|
5406
|
-
opacity: var(--aparte-disabled-opacity);
|
|
5407
5796
|
cursor: not-allowed;
|
|
5408
|
-
background: var(--aparte-send-disabled-bg, var(--aparte-
|
|
5797
|
+
background: var(--aparte-send-disabled-bg, var(--aparte-surface-2));
|
|
5798
|
+
color: var(--aparte-text-muted);
|
|
5409
5799
|
}
|
|
5410
5800
|
|
|
5411
5801
|
/* =========================================
|
|
@@ -5499,11 +5889,10 @@ aparte-model-selector[hidden],
|
|
|
5499
5889
|
border-color: var(--aparte-primary);
|
|
5500
5890
|
}
|
|
5501
5891
|
|
|
5502
|
-
.aparte-provider-select:focus,
|
|
5503
|
-
.aparte-model-select:focus {
|
|
5504
|
-
outline:
|
|
5505
|
-
|
|
5506
|
-
box-shadow: var(--aparte-focus-ring);
|
|
5892
|
+
.aparte-provider-select:focus-visible,
|
|
5893
|
+
.aparte-model-select:focus-visible {
|
|
5894
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
5895
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
5507
5896
|
}
|
|
5508
5897
|
|
|
5509
5898
|
/* Dark mode overrides for selects */
|
|
@@ -5546,13 +5935,14 @@ aparte-composer {
|
|
|
5546
5935
|
it would then be the containing block of the `position: fixed` select dropdown
|
|
5547
5936
|
that exists to escape `overflow: hidden` (select.css, and the same warning in
|
|
5548
5937
|
split.css). So below 520px the transcript tightens to 8px and this stays at 16.
|
|
5549
|
-
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
|
|
5938
|
+
So the composer does not guess: the viewport MEASURES where its rows start — the
|
|
5939
|
+
transcript's padding plus the scrollbar gutter it reserves on both edges, at
|
|
5940
|
+
whatever step its container query has taken — and publishes it on the chat host as
|
|
5941
|
+
`--aparte-transcript-inset`. Padding by that puts the composer's box on the row's
|
|
5942
|
+
box at every width. Measured before: 10px apart at 768, the gutter's half at 1280,
|
|
5943
|
+
three left edges 12px apart on the reading-column demo. The fallback is for a
|
|
5944
|
+
composer with no viewport beside it. */
|
|
5945
|
+
padding-inline: var(--aparte-transcript-inset, var(--aparte-viewport-padding));
|
|
5556
5946
|
}
|
|
5557
5947
|
|
|
5558
5948
|
aparte-composer-input {
|
|
@@ -5565,7 +5955,7 @@ aparte-composer-input {
|
|
|
5565
5955
|
aparte-composer-input .aparte-ci-editor {
|
|
5566
5956
|
display: block;
|
|
5567
5957
|
width: 100%;
|
|
5568
|
-
min-height: var(--aparte-composer-control-size
|
|
5958
|
+
min-height: var(--aparte-composer-control-size);
|
|
5569
5959
|
padding: var(--aparte-input-padding-y) var(--aparte-input-padding-x);
|
|
5570
5960
|
font-size: var(--aparte-input-font-size);
|
|
5571
5961
|
line-height: var(--aparte-input-line-height);
|
|
@@ -5596,7 +5986,7 @@ aparte-composer-input .aparte-ci-editor:empty::before {
|
|
|
5596
5986
|
}
|
|
5597
5987
|
|
|
5598
5988
|
aparte-composer-input .aparte-ci-editor[aria-disabled="true"] {
|
|
5599
|
-
|
|
5989
|
+
color: var(--aparte-text-muted);
|
|
5600
5990
|
cursor: not-allowed;
|
|
5601
5991
|
}
|
|
5602
5992
|
|
|
@@ -5688,7 +6078,7 @@ aparte-composer.aparte-is-dragover:not(:has(.aparte-composer-shell)) {
|
|
|
5688
6078
|
|
|
5689
6079
|
/* Inner row — flex container for input + buttons */
|
|
5690
6080
|
/* Action buttons sized to the input's single-line height — they derive from
|
|
5691
|
-
--aparte-composer-control-size (default
|
|
6081
|
+
--aparte-composer-control-size (default: the lg step, 36px; the touch target under a coarse pointer), so a theme resizes the whole
|
|
5692
6082
|
composer control set with ONE variable and alignment holds. Combined with
|
|
5693
6083
|
the row's `align-items: flex-end` this makes the buttons read as vertically
|
|
5694
6084
|
centered against a single line of text, and keeps them anchored to the
|
|
@@ -5720,7 +6110,11 @@ aparte-composer.aparte-is-dragover:not(:has(.aparte-composer-shell)) {
|
|
|
5720
6110
|
align-items: flex-end;
|
|
5721
6111
|
gap: var(--aparte-space-4);
|
|
5722
6112
|
padding: var(--aparte-space-4) var(--aparte-space-6);
|
|
5723
|
-
|
|
6113
|
+
/* The lg step at rest — 36px, what `--aparte-send-btn-size` says — and the touch
|
|
6114
|
+
target under a coarse pointer (responsive.css). It was 44 everywhere, which made
|
|
6115
|
+
the send button the one control the coarse-pointer block could not enlarge because
|
|
6116
|
+
it already was, and a 62px bar around 15px of text on a desktop. */
|
|
6117
|
+
--aparte-composer-row-control-size: var(--aparte-composer-control-size);
|
|
5724
6118
|
--aparte-btn-size: var(--aparte-composer-row-control-size);
|
|
5725
6119
|
}
|
|
5726
6120
|
|
|
@@ -5838,6 +6232,10 @@ aparte-composer-cancel .aparte-cc-button:hover {
|
|
|
5838
6232
|
`.aparte-accordion__header` / `__item` / `__panel` and adds these two lines: a
|
|
5839
6233
|
quieter face than a real accordion header, and the padding the left rail needs. */
|
|
5840
6234
|
.aparte-thinking-header {
|
|
6235
|
+
/* The chevron sits beside the label: the accordion recipe puts it at the row's far
|
|
6236
|
+
end, which is what an accordion is, but this is a one-line disclosure, and "Reasoning"
|
|
6237
|
+
and its chevron were 692px apart at 1280 (T18). */
|
|
6238
|
+
justify-content: flex-start;
|
|
5841
6239
|
padding: var(--aparte-space-1) 0 var(--aparte-space-1) var(--aparte-space-5);
|
|
5842
6240
|
font-size: var(--aparte-font-size-sm);
|
|
5843
6241
|
color: var(--aparte-thinking-text);
|
|
@@ -5869,7 +6267,7 @@ aparte-composer-cancel .aparte-cc-button:hover {
|
|
|
5869
6267
|
margin-inline-end: var(--aparte-space-4);
|
|
5870
6268
|
/* Logical property */
|
|
5871
6269
|
text-transform: uppercase;
|
|
5872
|
-
opacity:
|
|
6270
|
+
/* The header's ink is already the muted one; an `opacity: .7` on top muted it twice. */
|
|
5873
6271
|
}
|
|
5874
6272
|
|
|
5875
6273
|
|
|
@@ -5928,11 +6326,14 @@ aparte-composer-cancel .aparte-cc-button:hover {
|
|
|
5928
6326
|
flex: none;
|
|
5929
6327
|
width: var(--aparte-space-8);
|
|
5930
6328
|
height: var(--aparte-space-8);
|
|
5931
|
-
opacity: 0.5
|
|
5932
|
-
|
|
6329
|
+
/* Quiet is a colour, not an opacity: at 0.5 the chevron measured 3.00:1 — on the
|
|
6330
|
+
WCAG floor exactly — and it is the control that reveals a `delete_file`'s
|
|
6331
|
+
arguments. The muted ink at rest, the full ink under the pointer. */
|
|
6332
|
+
color: var(--aparte-text-muted);
|
|
6333
|
+
transition: transform var(--aparte-duration-base), color var(--aparte-duration-base);
|
|
5933
6334
|
}
|
|
5934
6335
|
.aparte-tool-toggle svg { width: 100%; height: 100%; display: block; }
|
|
5935
|
-
.aparte-tool-summary:hover .aparte-tool-toggle {
|
|
6336
|
+
.aparte-tool-summary:hover .aparte-tool-toggle { color: var(--aparte-text); }
|
|
5936
6337
|
details[open] > .aparte-tool-summary .aparte-tool-toggle { transform: rotate(180deg); }
|
|
5937
6338
|
/* A rule down the leading edge, so the disclosure reads as belonging to the
|
|
5938
6339
|
pill above it rather than continuing the message text below. Without it
|
|
@@ -5947,7 +6348,7 @@ details[open] > .aparte-tool-summary .aparte-tool-toggle { transform: rotate(180
|
|
|
5947
6348
|
}
|
|
5948
6349
|
.aparte-tool-part-label {
|
|
5949
6350
|
display: block; font-size: var(--aparte-font-size-xs); text-transform: uppercase;
|
|
5950
|
-
letter-spacing: 0.04em;
|
|
6351
|
+
letter-spacing: 0.04em; color: var(--aparte-text-muted); margin-bottom: var(--aparte-space-1);
|
|
5951
6352
|
}
|
|
5952
6353
|
/* A tool's input and result WRAP. They are a message, a path, a JSON object — not
|
|
5953
6354
|
code to read line by line — and a `<pre>` keeps `white-space: pre` by default, so
|
|
@@ -5969,6 +6370,7 @@ details[open] > .aparte-tool-summary .aparte-tool-toggle { transform: rotate(180
|
|
|
5969
6370
|
green, which made a finished step shout louder than the reply it belongs to. */
|
|
5970
6371
|
.aparte-tool-label {
|
|
5971
6372
|
display: inline-flex;
|
|
6373
|
+
vertical-align: middle;
|
|
5972
6374
|
align-items: center;
|
|
5973
6375
|
gap: var(--aparte-space-3);
|
|
5974
6376
|
min-width: 0;
|
|
@@ -5985,7 +6387,7 @@ details[open] > .aparte-tool-summary .aparte-tool-toggle { transform: rotate(180
|
|
|
5985
6387
|
place-items: center;
|
|
5986
6388
|
width: 1em; height: 1em;
|
|
5987
6389
|
flex: none;
|
|
5988
|
-
|
|
6390
|
+
color: var(--aparte-text-muted);
|
|
5989
6391
|
}
|
|
5990
6392
|
.aparte-tool-icon svg { width: 1em; height: 1em; display: block; }
|
|
5991
6393
|
.aparte-tool-name { font-family: var(--aparte-code-font-family); }
|
|
@@ -5993,9 +6395,12 @@ details[open] > .aparte-tool-summary .aparte-tool-toggle { transform: rotate(180
|
|
|
5993
6395
|
Pushed to the far end by DOM order plus an auto inline-start margin, which is
|
|
5994
6396
|
the placement rule this repo already settled on: no left/right in a name, so
|
|
5995
6397
|
a right-to-left locale mirrors it for free. */
|
|
6398
|
+
/* Beside the tool's name, not at the row's far end: with `margin-inline-start: auto` the
|
|
6399
|
+
state word drifted 63px from the name at 375 and 596px at 1280. The state belongs to
|
|
6400
|
+
the label (T18). */
|
|
5996
6401
|
.aparte-tool-state {
|
|
5997
|
-
display: inline-flex;
|
|
5998
|
-
|
|
6402
|
+
display: inline-flex;
|
|
6403
|
+
vertical-align: middle; align-items: center; gap: var(--aparte-space-2);
|
|
5999
6404
|
font-size: var(--aparte-font-size-sm); font-weight: var(--aparte-font-weight-medium);
|
|
6000
6405
|
color: var(--aparte-text-muted);
|
|
6001
6406
|
user-select: none;
|
|
@@ -6031,44 +6436,22 @@ details[open] > .aparte-tool-summary .aparte-tool-toggle { transform: rotate(180
|
|
|
6031
6436
|
}
|
|
6032
6437
|
|
|
6033
6438
|
/* Pipeline waiting */
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
|
|
6043
|
-
|
|
6044
|
-
height: var(--aparte-error-icon-size);
|
|
6045
|
-
}
|
|
6046
|
-
|
|
6047
|
-
.aparte-error-content {
|
|
6048
|
-
flex: 1;
|
|
6049
|
-
min-width: 0;
|
|
6050
|
-
}
|
|
6051
|
-
|
|
6052
|
-
.aparte-error-title {
|
|
6053
|
-
font-weight: var(--aparte-font-weight-semibold);
|
|
6054
|
-
font-size: var(--aparte-font-size-lg);
|
|
6055
|
-
margin-bottom: var(--aparte-space-2);
|
|
6056
|
-
color: var(--aparte-error-title);
|
|
6057
|
-
}
|
|
6058
|
-
|
|
6059
|
-
.aparte-error-message {
|
|
6060
|
-
font-size: var(--aparte-font-size-lg);
|
|
6061
|
-
line-height: var(--aparte-line-height-normal);
|
|
6062
|
-
}
|
|
6063
|
-
|
|
6064
|
-
.aparte-error-details {
|
|
6065
|
-
margin-top: var(--aparte-space-4);
|
|
6066
|
-
padding-top: var(--aparte-space-4);
|
|
6067
|
-
border-top: var(--aparte-border-width) solid var(--aparte-error-border);
|
|
6439
|
+
/* The error segment WEARS the alert recipe — frame and parts (`aparte-alert__icon`,
|
|
6440
|
+
`__body`, `__title`, `__message` come from display/alert.css). It used to put the
|
|
6441
|
+
recipe's class on its root and redraw every part under classes of its own, with a 20px
|
|
6442
|
+
literal for the icon among derived tokens and a title colour nothing else used. What is
|
|
6443
|
+
genuinely the segment's own is the one part the alert has no word for: the details
|
|
6444
|
+
block — a transport's stack, a status line — set as code under the message. */
|
|
6445
|
+
.aparte-segment-error__details {
|
|
6446
|
+
margin: var(--aparte-space-4) 0 0;
|
|
6447
|
+
padding-block-start: var(--aparte-space-4);
|
|
6448
|
+
border-block-start: var(--aparte-border-width) solid var(--aparte-error-border);
|
|
6068
6449
|
font-family: var(--aparte-code-font-family);
|
|
6069
6450
|
font-size: var(--aparte-font-size-sm);
|
|
6070
|
-
|
|
6451
|
+
line-height: var(--aparte-line-height-normal);
|
|
6452
|
+
color: var(--aparte-text-secondary);
|
|
6071
6453
|
white-space: pre-wrap;
|
|
6454
|
+
overflow-wrap: anywhere;
|
|
6072
6455
|
}
|
|
6073
6456
|
|
|
6074
6457
|
/* ─────────────────────────────────────────────────────────────────────────────
|
|
@@ -6182,7 +6565,7 @@ details[open] > .aparte-tool-summary .aparte-tool-toggle { transform: rotate(180
|
|
|
6182
6565
|
a consumer's screenshot, then here. The padding gives the ring that much room and
|
|
6183
6566
|
the negative margin gives it back to the layout, so nothing moves; `scroll-padding`
|
|
6184
6567
|
keeps a keyboard-focused option's ring inside the viewport when the list scrolls. */
|
|
6185
|
-
--aparte-elic-ring-room: calc(var(--aparte-focus-outline-width) + var(--aparte-
|
|
6568
|
+
--aparte-elic-ring-room: calc(var(--aparte-focus-outline-width) + var(--aparte-focus-outline-offset));
|
|
6186
6569
|
padding: var(--aparte-elic-ring-room);
|
|
6187
6570
|
margin: calc(-1 * var(--aparte-elic-ring-room));
|
|
6188
6571
|
scroll-padding: var(--aparte-elic-ring-room);
|
|
@@ -6226,7 +6609,10 @@ details[open] > .aparte-tool-summary .aparte-tool-toggle { transform: rotate(180
|
|
|
6226
6609
|
.aparte-elic-options {
|
|
6227
6610
|
display: flex;
|
|
6228
6611
|
flex-direction: column;
|
|
6229
|
-
|
|
6612
|
+
/* At least the focus ring's outset: at 2px the next row painted over the bottom of
|
|
6613
|
+
the focused row's ring and ~8px of it survived. Any list of options that wears an
|
|
6614
|
+
outset ring needs a gap at least as wide as the offset. */
|
|
6615
|
+
gap: var(--aparte-space-3);
|
|
6230
6616
|
}
|
|
6231
6617
|
|
|
6232
6618
|
/* The row is `.aparte-field-choice`; the panel only tightens its padding, because a
|
|
@@ -6300,22 +6686,19 @@ textarea.aparte-elic-text {
|
|
|
6300
6686
|
min-height: var(--aparte-elic-textarea-min-height);
|
|
6301
6687
|
}
|
|
6302
6688
|
|
|
6303
|
-
.aparte-elic-other-input:focus,
|
|
6304
|
-
.aparte-elic-text:focus {
|
|
6305
|
-
border-color: var(--aparte-primary);
|
|
6306
|
-
}
|
|
6307
|
-
|
|
6308
6689
|
.aparte-elic-option--recommended {
|
|
6309
6690
|
border-color: var(--aparte-primary);
|
|
6310
6691
|
background: color-mix(in srgb, var(--aparte-primary) 6%, transparent);
|
|
6311
6692
|
}
|
|
6312
6693
|
/* One ring at a time. The recommended option is the first to receive focus, and its
|
|
6313
6694
|
tinted border under the recipe's focus ring read as a double outline (UI audit
|
|
6314
|
-
2026-08-28, §8.3 #9). While it holds focus the ring is the
|
|
6315
|
-
|
|
6695
|
+
2026-08-28, §8.3 #9). While it holds focus the ring is the one edge, so the border
|
|
6696
|
+
steps aside — and ONLY the border. This rule used to clear the background too, which
|
|
6697
|
+
made the recommended row the only one in the list with no ground at all: sampled on
|
|
6698
|
+
the preview it rendered the page byte for byte while its sisters did not. The
|
|
6699
|
+
recommended state draws in addition to the resting state, never instead of it. */
|
|
6316
6700
|
.aparte-elic-option--recommended:focus-within {
|
|
6317
|
-
|
|
6318
|
-
border-color: var(--aparte-border-focus);
|
|
6701
|
+
border-color: transparent;
|
|
6319
6702
|
}
|
|
6320
6703
|
|
|
6321
6704
|
/* The whole-request escape, in the corner and out of the way of anything that
|
|
@@ -6424,7 +6807,7 @@ textarea.aparte-elic-text {
|
|
|
6424
6807
|
|
|
6425
6808
|
.aparte-approval-args:focus-visible {
|
|
6426
6809
|
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
6427
|
-
outline-offset:
|
|
6810
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
6428
6811
|
}
|
|
6429
6812
|
|
|
6430
6813
|
/* The refusal's reason, in the user's words. Quiet by default and one line tall: it is
|
|
@@ -6444,9 +6827,9 @@ textarea.aparte-elic-text {
|
|
|
6444
6827
|
min-height: 1.6em;
|
|
6445
6828
|
}
|
|
6446
6829
|
|
|
6447
|
-
.aparte-approval-instruction:focus {
|
|
6448
|
-
outline:
|
|
6449
|
-
|
|
6830
|
+
.aparte-approval-instruction:focus-visible {
|
|
6831
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
6832
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
6450
6833
|
}
|
|
6451
6834
|
|
|
6452
6835
|
.aparte-approval-instruction::placeholder {
|
|
@@ -6595,8 +6978,8 @@ textarea.aparte-elic-text {
|
|
|
6595
6978
|
/* Inside the edge: the list clips horizontally (`overflow-x: hidden` in base.css), and
|
|
6596
6979
|
a ring drawn outside the row was cut on both sides. */
|
|
6597
6980
|
.aparte-conv-item__select:focus-visible {
|
|
6598
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
6599
|
-
outline-offset:
|
|
6981
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
6982
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
6600
6983
|
}
|
|
6601
6984
|
|
|
6602
6985
|
.aparte-conv-item__title {
|
|
@@ -6617,15 +7000,22 @@ textarea.aparte-elic-text {
|
|
|
6617
7000
|
font-weight: var(--aparte-conv-item-font-weight-active);
|
|
6618
7001
|
}
|
|
6619
7002
|
|
|
7003
|
+
/* The selection mark: a bar the width of `--aparte-mark-bar` down the row's start
|
|
7004
|
+
edge. Painted as the first pixels of a pseudo the SIZE of the row that inherits its
|
|
7005
|
+
radius, so the bar follows the curve — drawn as a 2px box of its own it stood square
|
|
7006
|
+
in a 9px corner and a sliver of the page's ground showed between the two. Not
|
|
7007
|
+
`overflow: hidden` on the row: that would clip the title button's focus ring. */
|
|
6620
7008
|
.aparte-conv-item--active::before {
|
|
6621
7009
|
content: "";
|
|
6622
7010
|
position: absolute;
|
|
6623
|
-
inset
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
background: var(--aparte-primary-ink);
|
|
7011
|
+
inset: 0;
|
|
7012
|
+
border-radius: inherit;
|
|
7013
|
+
background: linear-gradient(to right, var(--aparte-primary-ink) var(--aparte-mark-bar), transparent 0);
|
|
6627
7014
|
pointer-events: none;
|
|
6628
7015
|
}
|
|
7016
|
+
.aparte-conv-item--active:dir(rtl)::before {
|
|
7017
|
+
background: linear-gradient(to left, var(--aparte-primary-ink) var(--aparte-mark-bar), transparent 0);
|
|
7018
|
+
}
|
|
6629
7019
|
|
|
6630
7020
|
.aparte-conv-item--archived .aparte-conv-item__title {
|
|
6631
7021
|
font-style: italic;
|
|
@@ -6639,8 +7029,8 @@ textarea.aparte-elic-text {
|
|
|
6639
7029
|
.aparte-conv-item__more {
|
|
6640
7030
|
flex-shrink: 0;
|
|
6641
7031
|
opacity: 0;
|
|
6642
|
-
|
|
6643
|
-
|
|
7032
|
+
/* Fed to the recipe, not drawn here: the token names the size, the button draws it. */
|
|
7033
|
+
--aparte-btn-size: var(--aparte-conv-action-btn-size);
|
|
6644
7034
|
color: var(--aparte-text-muted);
|
|
6645
7035
|
}
|
|
6646
7036
|
|
|
@@ -6718,6 +7108,11 @@ aparte-suggestions[data-empty] {
|
|
|
6718
7108
|
flex-wrap: wrap;
|
|
6719
7109
|
gap: var(--aparte-space-2);
|
|
6720
7110
|
padding-block: var(--aparte-space-2);
|
|
7111
|
+
/* The composer's column: past its 800px cap the chips no longer followed the composer,
|
|
7112
|
+
188px of offset on a wide host. Same measure, same centring. */
|
|
7113
|
+
box-sizing: border-box;
|
|
7114
|
+
max-inline-size: var(--aparte-message-max-width);
|
|
7115
|
+
margin-inline: auto;
|
|
6721
7116
|
}
|
|
6722
7117
|
|
|
6723
7118
|
/* A starter's label is a short phrase; it must not become a two-line chip. */
|
|
@@ -6753,6 +7148,9 @@ aparte-context[data-empty] {
|
|
|
6753
7148
|
.aparte-context .aparte-progress {
|
|
6754
7149
|
flex: 1;
|
|
6755
7150
|
min-width: 4rem;
|
|
7151
|
+
/* A gauge has a measure: unbounded, the bar stretched to 1046×4px across a toolbar,
|
|
7152
|
+
88 % of its width for a line that says one number. */
|
|
7153
|
+
max-inline-size: 16rem;
|
|
6756
7154
|
}
|
|
6757
7155
|
|
|
6758
7156
|
.aparte-context__text {
|
|
@@ -6782,10 +7180,13 @@ aparte-context[data-level="danger"] .aparte-progress__bar {
|
|
|
6782
7180
|
transform: rotate(-90deg);
|
|
6783
7181
|
}
|
|
6784
7182
|
|
|
7183
|
+
/* As heavy as the bar variant, in screen pixels: the same gauge was drawn at two
|
|
7184
|
+
weights — a 4px bar and a 2.44px antialiased ring. */
|
|
6785
7185
|
.aparte-context__track,
|
|
6786
7186
|
.aparte-context__value {
|
|
6787
7187
|
fill: none;
|
|
6788
|
-
stroke-width: var(--aparte-
|
|
7188
|
+
stroke-width: var(--aparte-progress-height);
|
|
7189
|
+
vector-effect: non-scaling-stroke;
|
|
6789
7190
|
}
|
|
6790
7191
|
|
|
6791
7192
|
.aparte-context__track {
|
|
@@ -6865,7 +7266,9 @@ aparte-scroll-rail[data-empty] {
|
|
|
6865
7266
|
padding: 0;
|
|
6866
7267
|
border: 0;
|
|
6867
7268
|
border-radius: var(--aparte-radius-full);
|
|
6868
|
-
|
|
7269
|
+
/* A tick is a thing you can press; at rest in the region colour it sat at 1.15:1, a
|
|
7270
|
+
14×2px dash under the perception threshold. */
|
|
7271
|
+
background: var(--aparte-border-control);
|
|
6869
7272
|
cursor: pointer;
|
|
6870
7273
|
transition:
|
|
6871
7274
|
width var(--aparte-duration-fast) var(--aparte-ease),
|
|
@@ -6888,7 +7291,7 @@ aparte-scroll-rail[data-empty] {
|
|
|
6888
7291
|
}
|
|
6889
7292
|
|
|
6890
7293
|
.aparte-scroll-rail__tick:focus-visible {
|
|
6891
|
-
outline: var(--aparte-focus-outline-width) solid var(--aparte-
|
|
7294
|
+
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
6892
7295
|
outline-offset: var(--aparte-focus-outline-offset);
|
|
6893
7296
|
}
|
|
6894
7297
|
|
|
@@ -6971,7 +7374,10 @@ aparte-sidebar,
|
|
|
6971
7374
|
display: flex;
|
|
6972
7375
|
align-items: center;
|
|
6973
7376
|
gap: var(--aparte-space-3);
|
|
6974
|
-
|
|
7377
|
+
/* Inline, every region reads `--aparte-sidebar-inset`: the header and footer padded
|
|
7378
|
+
16 while the search and the body padded 12, and the column's content stood on two
|
|
7379
|
+
vertical axes 4px apart — measured as four left edges on the app-shell demo. */
|
|
7380
|
+
padding: var(--aparte-space-4) var(--aparte-sidebar-inset) var(--aparte-space-2);
|
|
6975
7381
|
}
|
|
6976
7382
|
|
|
6977
7383
|
.aparte-sidebar__brand {
|
|
@@ -6984,8 +7390,8 @@ aparte-sidebar,
|
|
|
6984
7390
|
}
|
|
6985
7391
|
|
|
6986
7392
|
.aparte-sidebar__search {
|
|
6987
|
-
margin: var(--aparte-space-2) var(--aparte-
|
|
6988
|
-
min-width: calc(var(--aparte-sidebar-width) - 2 * var(--aparte-
|
|
7393
|
+
margin: var(--aparte-space-2) var(--aparte-sidebar-inset);
|
|
7394
|
+
min-width: calc(var(--aparte-sidebar-width) - 2 * var(--aparte-sidebar-inset));
|
|
6989
7395
|
}
|
|
6990
7396
|
|
|
6991
7397
|
/* The body is the one region that scrolls; the list inside keeps its own gap. */
|
|
@@ -6994,7 +7400,7 @@ aparte-sidebar,
|
|
|
6994
7400
|
min-height: 0;
|
|
6995
7401
|
overflow-y: auto;
|
|
6996
7402
|
overflow-x: hidden;
|
|
6997
|
-
padding: var(--aparte-space-2) var(--aparte-
|
|
7403
|
+
padding: var(--aparte-space-2) var(--aparte-sidebar-inset);
|
|
6998
7404
|
scrollbar-width: thin;
|
|
6999
7405
|
scrollbar-color: var(--aparte-scrollbar-thumb) var(--aparte-scrollbar-track);
|
|
7000
7406
|
}
|
|
@@ -7003,7 +7409,7 @@ aparte-sidebar,
|
|
|
7003
7409
|
display: flex;
|
|
7004
7410
|
align-items: center;
|
|
7005
7411
|
gap: var(--aparte-space-3);
|
|
7006
|
-
padding: var(--aparte-space-3) var(--aparte-
|
|
7412
|
+
padding: var(--aparte-space-3) var(--aparte-sidebar-inset);
|
|
7007
7413
|
border-block-start: var(--aparte-border-width) solid var(--aparte-border);
|
|
7008
7414
|
font-size: var(--aparte-font-size-sm);
|
|
7009
7415
|
}
|
|
@@ -7048,7 +7454,7 @@ aparte-sidebar,
|
|
|
7048
7454
|
* under 48rem, where the sidebar is a drawer; above it the column is simply there.
|
|
7049
7455
|
*
|
|
7050
7456
|
* <header class="aparte-app-header">
|
|
7051
|
-
* <button class="aparte-btn aparte-btn--icon aparte-app-header__toggle" type="button" aria-label="Toggle the sidebar" data-aparte-sidebar-toggle
|
|
7457
|
+
* <button class="aparte-btn aparte-btn--icon aparte-app-header__toggle" type="button" aria-label="Toggle the sidebar" data-aparte-sidebar-toggle><aparte-icon name="menu"></aparte-icon></button>
|
|
7052
7458
|
* <span class="aparte-app-header__title">Deploy checklist</span>
|
|
7053
7459
|
* <div class="aparte-app-header__actions">
|
|
7054
7460
|
* <span class="aparte-tag">gpt-4.1</span>
|
|
@@ -7109,15 +7515,38 @@ aparte-sidebar,
|
|
|
7109
7515
|
* `height: 100dvh` for a page — and everything inside follows. Under 48rem the sidebar
|
|
7110
7516
|
* leaves the grid to become a drawer, and the header's toggle appears.
|
|
7111
7517
|
*
|
|
7112
|
-
* <div class="aparte-app-shell" style="height:
|
|
7518
|
+
* <div class="aparte-app-shell" style="height: 24rem">
|
|
7113
7519
|
* <aside class="aparte-sidebar">
|
|
7114
|
-
* <div class="aparte-sidebar__header"
|
|
7115
|
-
*
|
|
7520
|
+
* <div class="aparte-sidebar__header">
|
|
7521
|
+
* <span class="aparte-sidebar__brand">aparté</span>
|
|
7522
|
+
* <button class="aparte-btn aparte-btn--icon aparte-btn--sm" type="button" aria-label="New chat"><aparte-icon name="edit"></aparte-icon></button>
|
|
7523
|
+
* </div>
|
|
7524
|
+
* <div class="aparte-sidebar__search aparte-field-group">
|
|
7525
|
+
* <input class="aparte-field aparte-field--sm" type="search" placeholder="Search">
|
|
7526
|
+
* </div>
|
|
7527
|
+
* <div class="aparte-sidebar__body">
|
|
7528
|
+
* <div class="aparte-conv-group" role="group" aria-label="Today">
|
|
7529
|
+
* <div class="aparte-menu__label aparte-conv-group__label" aria-hidden="true">Today</div>
|
|
7530
|
+
* <div class="aparte-menu__item aparte-conv-item aparte-conv-item--active"><button class="aparte-conv-item__select" type="button"><span class="aparte-conv-item__title">Deploy checklist</span></button></div>
|
|
7531
|
+
* <div class="aparte-menu__item aparte-conv-item"><button class="aparte-conv-item__select" type="button"><span class="aparte-conv-item__title">Rename the staging bucket</span></button></div>
|
|
7532
|
+
* </div>
|
|
7533
|
+
* <div class="aparte-conv-group" role="group" aria-label="Yesterday">
|
|
7534
|
+
* <div class="aparte-menu__label aparte-conv-group__label" aria-hidden="true">Yesterday</div>
|
|
7535
|
+
* <div class="aparte-menu__item aparte-conv-item"><button class="aparte-conv-item__select" type="button"><span class="aparte-conv-item__title">Why is total a float?</span></button></div>
|
|
7536
|
+
* </div>
|
|
7537
|
+
* </div>
|
|
7538
|
+
* <div class="aparte-sidebar__footer"><span class="aparte-avatar aparte-avatar--sm">P</span> Paul</div>
|
|
7116
7539
|
* </aside>
|
|
7117
|
-
* <header class="aparte-app-header"
|
|
7540
|
+
* <header class="aparte-app-header">
|
|
7541
|
+
* <span class="aparte-app-header__title">Deploy checklist</span>
|
|
7542
|
+
* <div class="aparte-app-header__actions"><span class="aparte-tag">gpt-4.1</span></div>
|
|
7543
|
+
* </header>
|
|
7118
7544
|
* <main class="aparte-app-shell__main">
|
|
7119
7545
|
* <aparte-chat>
|
|
7120
|
-
* <aparte-chat-viewport
|
|
7546
|
+
* <aparte-chat-viewport>
|
|
7547
|
+
* <aparte-chat-bubble message-id="u1" data-role="user" content="Walk me through the deploy."></aparte-chat-bubble>
|
|
7548
|
+
* <aparte-chat-bubble message-id="a1" data-role="assistant" name="Assistant" content="Build, run the gate, tag, then push the tag — the workflow publishes from it."></aparte-chat-bubble>
|
|
7549
|
+
* </aparte-chat-viewport>
|
|
7121
7550
|
* <aparte-composer>
|
|
7122
7551
|
* <div class="aparte-composer-shell">
|
|
7123
7552
|
* <div class="aparte-composer-row">
|
|
@@ -7174,6 +7603,28 @@ aparte-sidebar,
|
|
|
7174
7603
|
min-height: 0;
|
|
7175
7604
|
height: auto;
|
|
7176
7605
|
}
|
|
7606
|
+
|
|
7607
|
+
/* A phone folds the shell to one column. The sidebar ELEMENT already leaves the grid
|
|
7608
|
+
under 48rem — it becomes a fixed drawer behind the header's toggle — but the grid
|
|
7609
|
+
kept its first column for it, and a class-only sidebar had no story at all: at 375px
|
|
7610
|
+
the shell gave 259 of its 303px to the sidebar and left the chat a 43px band with a
|
|
7611
|
+
send button cut in half. Same query as the element's own, so the recipe teaches the
|
|
7612
|
+
screen the element renders. */
|
|
7613
|
+
@media (max-width: 48rem) {
|
|
7614
|
+
.aparte-app-shell {
|
|
7615
|
+
grid-template-columns: minmax(0, 1fr);
|
|
7616
|
+
}
|
|
7617
|
+
.aparte-app-shell > .aparte-app-header,
|
|
7618
|
+
.aparte-app-shell__main {
|
|
7619
|
+
grid-column: 1;
|
|
7620
|
+
}
|
|
7621
|
+
/* A sidebar that is not (yet) a drawer — the class recipe alone, or the element
|
|
7622
|
+
before it upgrades — folds out of the flow rather than eating the column. */
|
|
7623
|
+
.aparte-app-shell > .aparte-sidebar:not([data-drawer]),
|
|
7624
|
+
.aparte-app-shell > aparte-sidebar:not([data-drawer]) {
|
|
7625
|
+
display: none;
|
|
7626
|
+
}
|
|
7627
|
+
}
|
|
7177
7628
|
/*
|
|
7178
7629
|
* aparté — the seam: two panes side by side, and the grid that lets one grow while
|
|
7179
7630
|
* the other gives way. The fourth piece of the shell, after the sidebar, the header
|
|
@@ -7265,35 +7716,47 @@ aparte-split > [data-aparte-chat],
|
|
|
7265
7716
|
box-sizing: border-box;
|
|
7266
7717
|
border: 0;
|
|
7267
7718
|
padding: 0;
|
|
7268
|
-
|
|
7719
|
+
/* A transparent TRACK: the seam is the 1px line painted by `::before`, centred in it,
|
|
7720
|
+
and the grip is a short bar drawn on the track under the pointer. The track used
|
|
7721
|
+
to be the seam — 4px of paint, four times the kit's rule, with nothing to hold. */
|
|
7722
|
+
background: transparent;
|
|
7723
|
+
background-repeat: no-repeat;
|
|
7724
|
+
background-position: center;
|
|
7269
7725
|
cursor: col-resize;
|
|
7270
7726
|
touch-action: none;
|
|
7727
|
+
}
|
|
7728
|
+
|
|
7729
|
+
.aparte-split__handle::before {
|
|
7730
|
+
content: '';
|
|
7731
|
+
position: absolute;
|
|
7732
|
+
inset-block: 0;
|
|
7733
|
+
inset-inline-start: calc(50% - var(--aparte-split-seam-width) / 2);
|
|
7734
|
+
inline-size: var(--aparte-split-seam-width);
|
|
7735
|
+
background: var(--aparte-border);
|
|
7271
7736
|
transition: background-color var(--aparte-duration-fast) var(--aparte-ease);
|
|
7272
7737
|
}
|
|
7273
7738
|
|
|
7274
|
-
.aparte-split__handle:hover,
|
|
7275
|
-
.aparte-split__handle[data-dragging] {
|
|
7739
|
+
.aparte-split__handle:hover::before,
|
|
7740
|
+
.aparte-split__handle[data-dragging]::before {
|
|
7276
7741
|
background: var(--aparte-primary);
|
|
7277
7742
|
}
|
|
7278
7743
|
|
|
7279
|
-
/*
|
|
7280
|
-
|
|
7281
|
-
|
|
7282
|
-
|
|
7283
|
-
|
|
7284
|
-
|
|
7285
|
-
|
|
7286
|
-
keyboard user has no other way to find.
|
|
7744
|
+
/* The grip: the convention of every editor's split, so the seam reads as something to
|
|
7745
|
+
take hold of. Drawn as a background so it needs no third element. */
|
|
7746
|
+
.aparte-split__handle:hover,
|
|
7747
|
+
.aparte-split__handle[data-dragging] {
|
|
7748
|
+
background-image: linear-gradient(var(--aparte-primary), var(--aparte-primary));
|
|
7749
|
+
background-size: calc(var(--aparte-split-seam-width) * 3) var(--aparte-space-8);
|
|
7750
|
+
}
|
|
7287
7751
|
|
|
7288
|
-
|
|
7289
|
-
|
|
7290
|
-
|
|
7291
|
-
|
|
7292
|
-
|
|
7752
|
+
/* The one ring. The seam's whole keyboard story is arrowing it, and its only focus
|
|
7753
|
+
indicator used to be a soft wash at 1.39:1 against the page — not weak, absent, on a
|
|
7754
|
+
4px band with `border: 0` that a keyboard user has no other way to find. The outline
|
|
7755
|
+
carries the contrast (3.54:1 light, 7.36:1 dark, measured), and it is the same outline
|
|
7756
|
+
every other control draws. */
|
|
7293
7757
|
.aparte-split__handle:focus-visible {
|
|
7294
7758
|
outline: var(--aparte-focus-outline-width) solid var(--aparte-border-focus);
|
|
7295
|
-
outline-offset:
|
|
7296
|
-
box-shadow: var(--aparte-focus-ring);
|
|
7759
|
+
outline-offset: var(--aparte-focus-outline-offset);
|
|
7297
7760
|
}
|
|
7298
7761
|
|
|
7299
7762
|
/* The hit slop: a 4px seam is a 4px target, and a pointer misses it. The pseudo-element
|
|
@@ -7382,6 +7845,14 @@ aparte-split[orientation='vertical'][primary='end']:not([data-stacked]),
|
|
|
7382
7845
|
aparte-split[orientation='vertical'] > .aparte-split__handle,
|
|
7383
7846
|
.aparte-split--vertical > .aparte-split__handle {
|
|
7384
7847
|
cursor: row-resize;
|
|
7848
|
+
background-size: var(--aparte-space-8) calc(var(--aparte-split-seam-width) * 3);
|
|
7849
|
+
}
|
|
7850
|
+
aparte-split[orientation='vertical'] > .aparte-split__handle::before,
|
|
7851
|
+
.aparte-split--vertical > .aparte-split__handle::before {
|
|
7852
|
+
inset-block: calc(50% - var(--aparte-split-seam-width) / 2) auto;
|
|
7853
|
+
inset-inline: 0;
|
|
7854
|
+
inline-size: auto;
|
|
7855
|
+
block-size: var(--aparte-split-seam-width);
|
|
7385
7856
|
}
|
|
7386
7857
|
|
|
7387
7858
|
aparte-split[orientation='vertical'] > .aparte-split__handle::after,
|
|
@@ -7639,6 +8110,13 @@ aparte-split[disabled] > .aparte-split__handle:hover {
|
|
|
7639
8110
|
.aparte-code-content-wrapper pre {
|
|
7640
8111
|
margin: 0;
|
|
7641
8112
|
padding: var(--aparte-space-6);
|
|
8113
|
+
/* The code typeface, at a code size. This rule declared neither and the block fell
|
|
8114
|
+
into the UA's generic `monospace` (Courier New on Windows) at the PROSE's size and
|
|
8115
|
+
leading; only inline code read the family. On the wrapper's `pre`, whatever class
|
|
8116
|
+
the highlighter puts on its replacement. */
|
|
8117
|
+
font-family: var(--aparte-code-font-family);
|
|
8118
|
+
font-size: var(--aparte-code-block-font-size);
|
|
8119
|
+
line-height: var(--aparte-code-block-line-height);
|
|
7642
8120
|
/* Wrap long lines instead of a horizontal scrollbar. `pre-wrap` honours
|
|
7643
8121
|
newlines + indentation but soft-wraps overflowing lines; `overflow-wrap:
|
|
7644
8122
|
anywhere` breaks unbreakable tokens (long URLs, hashes). Applies to both
|
|
@@ -7674,23 +8152,11 @@ aparte-split[disabled] > .aparte-split__handle:hover {
|
|
|
7674
8152
|
}
|
|
7675
8153
|
}
|
|
7676
8154
|
|
|
7677
|
-
/* Windows high contrast. In forced-colors mode the UA repaints colours and
|
|
7678
|
-
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
own focus colour, so the indicator survives without fighting the user's
|
|
7682
|
-
palette. Only the indicators that disappear are restated here: everything
|
|
7683
|
-
whose affordance is text or a border already survives on its own — which the
|
|
7684
|
-
split's seam does not, being a 4px band with `border: 0` whose entire keyboard
|
|
7685
|
-
story is arrowing it. */
|
|
8155
|
+
/* Windows high contrast. In forced-colors mode the UA repaints colours and drops
|
|
8156
|
+
box-shadow entirely. Every focus indicator is an outline now, which forced colours
|
|
8157
|
+
paint on their own — the one indicator drawn with a box-shadow is the error ring on
|
|
8158
|
+
an avatar, restated here as an outline so it does not vanish. */
|
|
7686
8159
|
@media (forced-colors: active) {
|
|
7687
|
-
.aparte-thumb--image[role='button']:focus-visible,
|
|
7688
|
-
.aparte-split__handle:focus-visible,
|
|
7689
|
-
.aparte-provider-select:focus,
|
|
7690
|
-
.aparte-model-select:focus {
|
|
7691
|
-
outline: var(--aparte-focus-outline-width) solid Highlight;
|
|
7692
|
-
}
|
|
7693
|
-
|
|
7694
8160
|
.aparte-message[data-error] .aparte-avatar {
|
|
7695
8161
|
outline: var(--aparte-focus-outline-width) solid CanvasText;
|
|
7696
8162
|
}
|
|
@@ -7782,7 +8248,13 @@ aparte-split[disabled] > .aparte-split__handle:hover {
|
|
|
7782
8248
|
/* Hover cannot reveal the row's ⋯ on touch — keep it visible and tappable. */
|
|
7783
8249
|
.aparte-conv-item__more {
|
|
7784
8250
|
opacity: 1;
|
|
7785
|
-
--aparte-conv-action-btn-size:
|
|
8251
|
+
--aparte-conv-action-btn-size: var(--aparte-touch-target-size);
|
|
8252
|
+
}
|
|
8253
|
+
|
|
8254
|
+
/* The composer's own controls: 36 at rest, the touch target here — the send button, the
|
|
8255
|
+
input's action button and the editor's single-line height move together. */
|
|
8256
|
+
.aparte-composer-row {
|
|
8257
|
+
--aparte-composer-control-size: var(--aparte-touch-target-size);
|
|
7786
8258
|
}
|
|
7787
8259
|
|
|
7788
8260
|
/* A 4px seam is no target for a finger — the same modality rule the buttons above
|