-
Notifications
You must be signed in to change notification settings - Fork 10
Expand file tree
/
Copy pathwarp-components.css
More file actions
1003 lines (869 loc) · 41 KB
/
warp-components.css
File metadata and controls
1003 lines (869 loc) · 41 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/* ==========================================================================
Scalar-Inspired Component Refinements
Layered styling for sidebar, code blocks, callouts, tables, header, etc.
Applied after custom.css — uses the same Warp design tokens.
========================================================================== */
/* --------------------------------------------------------------------------
1. Sidebar — Scalar treats the sidebar as a first-class surface
--------------------------------------------------------------------------
Information hierarchy (three tiers, in order of prominence):
Tier 1 Top-level section label e.g. "CODE" — eyebrow
Tier 2 Nested group label e.g. "Code Editor" — quiet header
Tier 3 Leaf link e.g. "Overview" — body
Stock Starlight applies the same `.large` class (16 px / 600 / white) to
*both* top-level and nested group `<summary>` spans, which makes nested
groups out-shout their parent section. We rebalance by giving each tier
a distinct visual treatment so weight mirrors hierarchy, with the active
page as the loudest element on screen.
-------------------------------------------------------------------------- */
/* Sidebar nav items: tighter; no transition.
A 150ms `transition: background-color` on every nav-item caused a visible
"flash of blue" when navigating to a new page — the browser smoothly
animated through Starlight's layered `aria-current` accent (a pale blue,
`var(--sl-color-text-accent)`) before settling on our unlayered override.
Removing the transition snaps the state instantly so no transient frame
gets animated into. Hover/active changes still read fine without a fade. */
.sidebar-content a {
border-radius: var(--sl-radius-sm);
}
/* Hover lands as a subtle wash rather than a chunky gray block. With the
sidebar fill matching the page background, var(--sl-color-gray-5) was
too punchy a jump (~7% → 22% lightness); this scoped rgba reads as a
gentle highlight against either dark or light canvas. */
.sidebar-content a:hover {
background-color: rgba(255, 255, 255, 0.05);
}
:root[data-theme='light'] .sidebar-content a:hover {
background-color: rgba(0, 0, 0, 0.04);
}
/* Active sidebar item.
Starlight default paints `[aria-current='page']` with
`background-color: var(--sl-color-text-accent)`, which in our dark theme
is `hsl(217, 90%, 84%)` — a pale blue. On the flush `#121212` canvas
that pale slab reads as a washed-out lavender block. Replace with a
Scalar-style calm "selected" treatment: neutral tinted surface (one step
stronger than hover so the two states differentiate), brightest text
token, and 600 weight. Reads as obviously selected without shouting. */
.sidebar-content a[aria-current='page'],
.sidebar-content a[aria-current='page']:hover,
.sidebar-content a[aria-current='page']:focus {
background-color: rgba(255, 255, 255, 0.09);
color: var(--sl-color-white);
font-weight: 600;
}
:root[data-theme='light'] .sidebar-content a[aria-current='page'],
:root[data-theme='light'] .sidebar-content a[aria-current='page']:hover,
:root[data-theme='light'] .sidebar-content a[aria-current='page']:focus {
background-color: rgba(0, 0, 0, 0.07);
color: var(--sl-color-white);
}
/* Tier 1 — top-level section label.
Editorial uppercase eyebrow at the brightest non-active color so the
section anchor is unambiguously the loudest element in its branch. */
.sidebar-content .top-level > li > details > summary .large,
.sidebar-content .top-level > li > a.large > span {
font-size: var(--sl-text-xs);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--sl-color-white);
}
/* Tier 2 — nested group label.
Quiet header: same size as leaf links so it can never out-size its
parent section. Heavier weight separates it from leaves; color drops to
gray-2 so it never out-shouts the Tier 1 eyebrow above it. */
.sidebar-content ul:not(.top-level) .large {
font-size: var(--sl-text-sm);
font-weight: 600;
text-transform: none;
letter-spacing: normal;
color: var(--sl-color-gray-2);
}
/* Soften the nested-group caret so it doesn't compete with the label. */
.sidebar-content ul:not(.top-level) > li > details > summary .caret {
color: var(--sl-color-gray-3);
}
/* Tighten spacing between a nested group label and its first child so the
header + items read as a single unit. */
.sidebar-content ul:not(.top-level) > li > details[open] > ul {
padding-block-start: 0.125rem;
}
/* Sidebar right-edge border: with the sidebar fill matching the page,
this hairline is the only thing separating the two panes — step it up
from --sl-color-hairline (6%) to --sl-color-hairline-light (8%) so it
still reads, while keeping the rest of the page's hairlines subtle. */
.sidebar-pane {
border-inline-end: 1px solid var(--sl-color-hairline-light);
}
/*
* Force instant (non-smooth) scroll on the sidebar scroller. Starlight's
* persister assigns `scrollTop` imperatively to restore scroll position on
* each navigation; if any ancestor cascades `scroll-behavior: smooth` onto
* it, that assignment becomes a visible animation from 0 → N that reads as
* a scrollbar "reset."
*/
#starlight__sidebar {
scroll-behavior: auto;
}
/* --------------------------------------------------------------------------
2. Code blocks — Scalar uses refined borders + warm backgrounds
-------------------------------------------------------------------------- */
/* Code block frame: one source of truth for the rounded card.
Apply the radius + border + clipping to the `.expressive-code` wrapper
and let it clip every child. EC's plugin tweaks the inner `<pre>` corners
per-mode (`is-terminal`, `has-title`), and previously those tweaks bled
through and produced a flat top / rounded bottom. With `overflow: hidden`
on the wrapper the inner shape is irrelevant — the card always reads as a
uniform 8px rounded rectangle. Suppress EC's own border (`--ec-brdWd: 0`)
so we don't double up the hairline. */
.expressive-code {
border-radius: var(--sl-radius-md);
overflow: hidden;
border: 1px solid var(--sl-color-hairline-light);
--ec-brdWd: 0;
max-width: 100%;
}
/* Code block typography — unified with inline code at 0.9375em (15px), one
step below the 16px body so monospace lands at roughly the same optical
weight as Inter prose without overshooting. Tight line-height keeps
single-line blocks compact without feeling cramped. */
.expressive-code {
--ec-codePadBlk: 0.75rem;
--ec-codePadInl: 1rem;
--ec-codeLineHt: 1.5;
--ec-codeFontSize: 0.9375em;
}
/* Code block surface color. Night Owl's default `#23262f` only lifts ~17
brightness levels off our page bg (`#121212`) and shares hue family, so
blocks read as a faint patch on the page. Push the dark surface to a
slightly cooler, more clearly elevated gray so code reads as a distinct
surface (Scalar pattern) and doesn't blur into the chip surface
(`--warp-control-bg`, `#1a1a1a`). Bump scrollbar opacity too —
macOS auto-hides scrollbars, and the default
`#ffffff17` thumb is invisible against the new bg, which is how lines
appeared to silently truncate. With wrap enabled globally this only
matters for blocks that opt out, but make it discoverable when it kicks in. */
.expressive-code {
--ec-codeBg: #1c1f26;
--ec-sbThumbCol: rgba(255, 255, 255, 0.18);
--ec-sbThumbHoverCol: rgba(255, 255, 255, 0.32);
}
:root[data-theme='light'] .expressive-code {
/* Light mode keeps Night Owl's default surface, but darken the scrollbar
thumb so it's visible against the soft `#f6f7f9` block bg. */
--ec-sbThumbCol: rgba(0, 0, 0, 0.18);
--ec-sbThumbHoverCol: rgba(0, 0, 0, 0.32);
}
.expressive-code pre,
pre.astro-code,
.sl-markdown-content pre {
overflow-x: auto;
}
/* Code block copy button — frosted glass effect (Scalar pattern) */
.expressive-code .copy button,
.expressive-code button.copy {
border-radius: var(--sl-radius-sm);
background: rgba(255, 255, 255, 0.08);
backdrop-filter: blur(8px);
border: 1px solid rgba(255, 255, 255, 0.1);
transition: background-color 0.15s ease, border-color 0.15s ease;
}
.expressive-code .copy button:hover,
.expressive-code button.copy:hover {
background: rgba(255, 255, 255, 0.16);
border-color: rgba(255, 255, 255, 0.18);
}
:root[data-theme='light'] .expressive-code .copy button,
:root[data-theme='light'] .expressive-code button.copy {
background: rgba(0, 0, 0, 0.04);
border: 1px solid rgba(0, 0, 0, 0.08);
}
:root[data-theme='light'] .expressive-code .copy button:hover,
:root[data-theme='light'] .expressive-code button.copy:hover {
background: rgba(0, 0, 0, 0.08);
border-color: rgba(0, 0, 0, 0.12);
}
/* Inline code — same optical size as fenced blocks (0.9375em / 15px) so
prose, callouts, and code blocks share one type scale.
Starlight's default sets the chip background but leaves text color to
inherit the muted body gray, which reads as gray-on-gray on the gray-5
chip bg in dark mode (~5.5:1, technically AA but muddy). Force the
highest-contrast text token — `--sl-color-white` is mode-aware (off-white
in dark, near-black in light) — so chips snap forward at ~10:1. */
.sl-markdown-content :not(pre) > code {
border-radius: var(--sl-radius-sm);
padding: 0.15em 0.35em;
font-size: 0.9375em;
color: var(--sl-color-white);
border: 1px solid var(--sl-color-hairline-light);
-webkit-box-decoration-break: clone;
box-decoration-break: clone;
}
/* Drop the Expressive Code frame chrome on blocks without an explicit
`title="…"` fence — the faux terminal title bar (with traffic-light dots)
and the empty editor-tab strip read as a meaningless nav bar above each
block. Titled fences keep their tab so readers can still see filenames.
The Frames plugin tags every `<figure>` with `.frame`, adds `.is-terminal`
for shell blocks, and adds `.has-title` only when a title is set. */
.expressive-code .frame:not(.has-title) .header {
display: none;
}
/* For terminal frames specifically, the plugin draws the three dots and the
header underline via ::before / ::after on the header. Belt-and-braces
nuke them in case browser rendering still allocates space for an empty
<figcaption>. */
.expressive-code .frame.is-terminal:not(.has-title) .header::before,
.expressive-code .frame.is-terminal:not(.has-title) .header::after {
display: none;
}
/* Code blocks inside asides: keep the standalone padding rhythm so a code
block looks identical inside or outside a callout. Pull a small block
margin so the card sits flush within the callout's tinted area. */
.sl-markdown-content .starlight-aside .expressive-code {
margin-block: 0.5rem;
}
/* --------------------------------------------------------------------------
3. Callouts / Asides — Scalar uses full background tints, not left-border
-------------------------------------------------------------------------- */
/* Base aside styles: Scalar-style flat tint card.
No left-rule accent — a single uniform 1px hairline carries the tint hue
on all four sides, so the box reads as a calm full-bleed surface rather
than an underlined banner.
Starlight's default applies `border-inline-start: 0.25rem solid …` (a
logical longhand) inside `@layer starlight.components`. The physical
`border-color` shorthand doesn't always cancel that logical-side width,
so we explicitly null `border-inline-start` and rebuild the four-sided
border via individual physical longhands. This guarantees a uniform 1px
hairline regardless of cascade order. */
.sl-markdown-content .starlight-aside {
border-radius: var(--sl-radius-md);
border-inline-start: 0;
border-width: 1px;
border-style: solid;
border-color: transparent;
/* 12/16 padding mirrors --ec-codePadBlk on code blocks so callouts and
fences share one density rhythm. The cascading <p> margins inside the
aside (16px) are zeroed out by the rules below — without those, this
padding would compound to ~28px and the box would feel chunky again. */
padding: 0.75rem 1rem;
}
/* Note/Info aside — blue tint */
.sl-markdown-content .starlight-aside--note {
background: rgba(165, 213, 254, 0.07);
border-top-color: rgba(165, 213, 254, 0.14);
border-right-color: rgba(165, 213, 254, 0.14);
border-bottom-color: rgba(165, 213, 254, 0.14);
border-left-color: rgba(165, 213, 254, 0.14);
}
/* Tip aside — purple tint (matches Starlight's purple tip icon/title) */
.sl-markdown-content .starlight-aside--tip {
background: rgba(192, 132, 252, 0.06);
border-top-color: rgba(192, 132, 252, 0.12);
border-right-color: rgba(192, 132, 252, 0.12);
border-bottom-color: rgba(192, 132, 252, 0.12);
border-left-color: rgba(192, 132, 252, 0.12);
}
/* Caution/Warning aside — amber tint */
.sl-markdown-content .starlight-aside--caution {
background: rgba(254, 253, 194, 0.06);
border-top-color: rgba(254, 253, 194, 0.12);
border-right-color: rgba(254, 253, 194, 0.12);
border-bottom-color: rgba(254, 253, 194, 0.12);
border-left-color: rgba(254, 253, 194, 0.12);
}
/* Danger aside — red tint */
.sl-markdown-content .starlight-aside--danger {
background: rgba(255, 120, 120, 0.07);
border-top-color: rgba(255, 120, 120, 0.14);
border-right-color: rgba(255, 120, 120, 0.14);
border-bottom-color: rgba(255, 120, 120, 0.14);
border-left-color: rgba(255, 120, 120, 0.14);
}
/* Light mode overrides for aside tints */
:root[data-theme='light'] .sl-markdown-content .starlight-aside--note {
background: rgba(0, 100, 180, 0.05);
border-top-color: rgba(0, 100, 180, 0.12);
border-right-color: rgba(0, 100, 180, 0.12);
border-bottom-color: rgba(0, 100, 180, 0.12);
border-left-color: rgba(0, 100, 180, 0.12);
}
:root[data-theme='light'] .sl-markdown-content .starlight-aside--tip {
background: rgba(126, 34, 206, 0.05);
border-top-color: rgba(126, 34, 206, 0.12);
border-right-color: rgba(126, 34, 206, 0.12);
border-bottom-color: rgba(126, 34, 206, 0.12);
border-left-color: rgba(126, 34, 206, 0.12);
}
:root[data-theme='light'] .sl-markdown-content .starlight-aside--caution {
background: rgba(168, 156, 20, 0.05);
border-top-color: rgba(168, 156, 20, 0.12);
border-right-color: rgba(168, 156, 20, 0.12);
border-bottom-color: rgba(168, 156, 20, 0.12);
border-left-color: rgba(168, 156, 20, 0.12);
}
:root[data-theme='light'] .sl-markdown-content .starlight-aside--danger {
background: rgba(195, 7, 113, 0.05);
border-top-color: rgba(195, 7, 113, 0.12);
border-right-color: rgba(195, 7, 113, 0.12);
border-bottom-color: rgba(195, 7, 113, 0.12);
border-left-color: rgba(195, 7, 113, 0.12);
}
/* Aside title: smaller, medium weight, tight to its content so a single-
paragraph aside reads as one compact block (Scalar one-liner pattern).
The title is rendered as a `<p>` inside `.sl-markdown-content`, which
inherits `margin-block: 1em` from custom.css. Zero out the top margin
so the title sits flush with the aside's top padding. */
.sl-markdown-content .starlight-aside .starlight-aside__title {
font-size: var(--sl-text-sm);
font-weight: 600;
margin-top: 0;
margin-bottom: 0.25rem;
}
/* Inline code inside asides: replace the neutral gray chip with a tinted
background that harmonizes with the callout's accent color. Starlight's
`color-mix` override is too faint (12%). We bump it to 18% so the chip
reads as part of the callout surface, not a foreign gray block. */
.sl-markdown-content .starlight-aside :not(pre) > code {
background-color: color-mix(in srgb, var(--sl-color-asides-text-accent) 18%, transparent);
border-color: color-mix(in srgb, var(--sl-color-asides-text-accent) 12%, transparent);
}
/* Collapse the outermost paragraph margins inside `__content` so the first
and last children sit flush with the title and the aside's bottom
padding respectively. Without this, the cascading `p { margin-block: 1em }`
rule would inflate the box by ~16px at each end. */
.sl-markdown-content .starlight-aside .starlight-aside__content > :first-child {
margin-top: 0;
}
.sl-markdown-content .starlight-aside .starlight-aside__content > :last-child {
margin-bottom: 0;
}
/* --------------------------------------------------------------------------
4. Tables — Scalar: no outer border, subtle rows, tighter padding
-------------------------------------------------------------------------- */
.sl-markdown-content table {
border-collapse: collapse;
width: 100%;
font-size: var(--sl-text-sm);
}
.sl-markdown-content table th {
font-weight: 600;
font-size: var(--sl-text-xs);
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--sl-color-gray-3);
border-bottom: 1px solid var(--sl-color-hairline-light);
padding: 0.5rem 0.75rem;
}
.sl-markdown-content table td {
padding: 0.5rem 0.75rem;
border-bottom: 1px solid var(--sl-color-hairline-shade);
}
.sl-markdown-content table tr:last-child td {
border-bottom: none;
}
/* Subtle row hover */
.sl-markdown-content table tbody tr:hover {
background: rgba(255, 255, 255, 0.02);
}
:root[data-theme='light'] .sl-markdown-content table tbody tr:hover {
background: rgba(0, 0, 0, 0.02);
}
/* Remove default outer border that Starlight may add */
.sl-markdown-content table,
.sl-markdown-content table th,
.sl-markdown-content table td {
border-left: none;
border-right: none;
}
/* --------------------------------------------------------------------------
5. Header — slimmer, blurred, softer border (Scalar pattern)
-------------------------------------------------------------------------- */
/* Glassmorphism header: blurred background on scroll */
header.header {
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
background: color-mix(in srgb, var(--sl-color-bg) 85%, transparent);
border-bottom: 1px solid var(--sl-color-hairline);
transition: background-color 0.2s ease;
}
/* --------------------------------------------------------------------------
6. Topic tab hover — full-row highlight instead of just icon fill
These rules style the plugin-rendered topic list (`<ul.starlight-sidebar-topics>`).
On desktop the topics live in the top header instead (see WarpTopicNav.astro
+ CustomHeader.astro), so this section now only affects the mobile drawer
instance rendered inside `<div class="md:sl-hidden">` in CustomSidebar.astro.
-------------------------------------------------------------------------- */
.starlight-sidebar-topics a {
border-radius: var(--sl-radius-sm);
transition: background-color 0.15s ease, color 0.15s ease;
}
/* Match the sidebar nav-item hover wash so topic rows and nested links
share a single visual language. */
.starlight-sidebar-topics a:hover {
background-color: rgba(255, 255, 255, 0.05);
}
:root[data-theme='light'] .starlight-sidebar-topics a:hover {
background-color: rgba(0, 0, 0, 0.04);
}
.starlight-sidebar-topics-icon {
/* Tighter than the plugin's default `0.25rem` (4px) so the topic icons
read as small architectural chips rather than rounded squares. */
border-radius: var(--sl-radius-xs);
transition: background-color 0.15s ease, border-color 0.15s ease;
}
/* On plain hover (non-active), keep icon default — only highlight the row */
.starlight-sidebar-topics a:hover:not(.starlight-sidebar-topics-current) .starlight-sidebar-topics-icon {
background-color: transparent;
border-color: var(--sl-color-gray-4);
color: inherit;
}
/* --------------------------------------------------------------------------
7. Logo alignment — flush with sidebar content
-------------------------------------------------------------------------- */
.site-title {
padding-inline-start: 0;
}
@media (min-width: 50rem) {
/* Match header padding to sidebar so logo aligns with sidebar content */
:root {
--sl-nav-pad-x: var(--sl-sidebar-pad-x);
}
/* Remove the title-wrapper's focus-ring padding that shifts the logo right */
.title-wrapper {
padding: 0;
margin: 0;
}
}
/* --------------------------------------------------------------------------
8. Pagination — lighter, Scalar-style navigation
-------------------------------------------------------------------------- */
.pagination-links a {
border: 1px solid var(--sl-color-hairline-light);
box-shadow: none;
border-radius: var(--sl-radius-sm);
padding: 0.75rem 1rem;
transition: background-color 0.15s ease, border-color 0.15s ease;
}
.pagination-links a:hover {
border-color: var(--sl-color-hairline);
background-color: var(--sl-color-gray-5);
}
:root[data-theme='light'] .pagination-links a:hover {
background-color: var(--sl-color-gray-6);
}
.pagination-links .link-title {
font-size: var(--sl-text-body);
}
/* --------------------------------------------------------------------------
9. Search box — tighter border radius like Scalar
-------------------------------------------------------------------------- */
site-search button[data-open-modal],
dialog[aria-label] {
border-radius: var(--sl-radius-sm);
}
/* --------------------------------------------------------------------------
10. Dark/Light mode smooth transition
-------------------------------------------------------------------------- */
body,
header.header,
.main-frame {
transition: background-color 0.25s ease, color 0.2s ease,
border-color 0.25s ease;
}
/* --------------------------------------------------------------------------
11. Links — Scalar uses subtle underlines on hover only
-------------------------------------------------------------------------- */
.sl-markdown-content a:not(.starlight-aside a) {
text-decoration: none;
transition: color 0.15s ease;
}
.sl-markdown-content a:not(.starlight-aside a):hover {
text-decoration: underline;
text-underline-offset: 0.15em;
}
/* Code-chip links always show an underline at rest. The chip's forced
`color: var(--sl-color-white)` (Starlight §2 above) overrides the
`--sl-color-text-accent` blue that normally signals "link" on plain prose,
so a `[`code`](url)` chip otherwise looks identical to a static code chip
until the user hovers. `:has(> code)` matches the canonical Markdown
render `<a><code>…</code></a>` and wins specificity (0,2,3) over the
`text-decoration: none` rule above (0,2,2) without `!important`. */
.sl-markdown-content a:not(.starlight-aside a):has(> code) {
text-decoration: underline;
text-underline-offset: 0.15em;
}
/* --------------------------------------------------------------------------
12. Right sidebar (TOC) — more refined
-------------------------------------------------------------------------- */
/* TOC heading: editorial treatment */
.right-sidebar-panel h2 {
font-size: var(--sl-text-xs);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--sl-color-gray-3);
}
/* TOC links: tighter, with smooth hover */
.right-sidebar-panel a {
font-size: var(--sl-text-sm);
transition: color 0.15s ease;
line-height: 1.5;
}
/* --------------------------------------------------------------------------
13. Cards / details / summary — refined borders
-------------------------------------------------------------------------- */
.sl-markdown-content details {
border-radius: var(--sl-radius-md);
border: 1px solid var(--sl-color-hairline-light);
}
.sl-markdown-content details summary {
font-weight: 500;
cursor: pointer;
transition: color 0.15s ease;
}
.sl-markdown-content details summary:hover {
color: var(--sl-color-text-accent);
}
/* --------------------------------------------------------------------------
14. Horizontal rules — ultra-subtle like Scalar
-------------------------------------------------------------------------- */
.sl-markdown-content hr {
border: none;
border-top: 1px solid var(--sl-color-hairline-light);
margin: 2em 0;
}
/* --------------------------------------------------------------------------
15. File tree — align with code-block / callout rhythm
Starlight's defaults sit in `@layer starlight.components`; unlayered rules
below win. We match the same surface (`#1c1f26`), hairline border, 6px
radius, and `0.75rem 1rem` padding the rest of our cards use, and bump the
font-size to `0.9375em` so monospace prose lands at one optical scale.
-------------------------------------------------------------------------- */
starlight-file-tree {
/* Match the code-block surface so a tree reads as a sibling card, not a
darker patch on the page. Light mode gets a soft warm tint that picks
up the same family as `--sl-color-gray-7`. */
background: #1c1f26;
border: 1px solid var(--sl-color-hairline-light);
border-radius: var(--sl-radius-md);
/* Symmetric padding so the tree reads as a balanced card. The earlier
asymmetric value was compensating for nested `<details>` rendering as
their own bordered boxes (cascade leak from section 13's
`.sl-markdown-content details` rule); now that we suppress that
bleed-through below, the tree visually centers on its own. */
padding: 0.75rem 1rem;
/* One step up so monospace prose matches inline code (`.9375em` ≈ 15px). */
font-size: 0.9375em;
/* Tiny vertical breathing room within each row without losing density. */
--y-pad: 0.125rem;
}
:root[data-theme='light'] starlight-file-tree {
background: var(--sl-color-gray-7);
}
/* CRITICAL: suppress the section-13 `.sl-markdown-content details` styles
(border + border-radius intended for collapsible info boxes) from leaking
into the FileTree's directory `<details>` elements. Without this, every
`project/`, `api/`, and `ui/` row renders inside its own rounded card,
which makes the nested structure feel like a stack of floating boxes
instead of a single tree.
The override needs `.sl-markdown-content` in the selector to beat the
original rule's specificity (0,1,1 vs a bare `starlight-file-tree details`
at 0,0,2). With it we land at (0,1,2) and win cleanly. */
.sl-markdown-content starlight-file-tree details {
border: 0;
border-radius: 0;
background: transparent;
}
/* Soften the indent guides so the structure reads but the gray rules don't
compete with the filename text.
Targeted at NESTED `ul`s only (`ul ul`) so the outermost `ul` keeps
Starlight's own `border: 0` reset — otherwise an unlayered rule on
`starlight-file-tree ul` wins the cascade against Starlight's layered
`> ul { border: 0 }` and we'd render an extra vertical hairline running
the full height of the tree on the left. */
starlight-file-tree ul ul {
border-inline-start: 1px solid var(--sl-color-hairline);
}
/* Pull the inline comment a hair further from the filename so the two read
as label + description rather than a fused string at narrow widths. */
starlight-file-tree .comment {
padding-inline-start: 1.5rem;
color: var(--sl-color-gray-3);
}
/* Directory `<summary>` lives inside `.sl-markdown-content`, where stray
prose styles can leak underlines onto it. The summary isn't an `<a>` but
the hover color rule (`var(--sl-color-text-accent)`) is fine; nuke any
underline so the hover state stays clean. */
starlight-file-tree .directory > details > summary {
text-decoration: none;
}
/* --------------------------------------------------------------------------
16. Shared control palette + sidebar search row — Scalar-style
--------------------------------------------------------------------------
`--warp-control-*` is a single set of design tokens consumed by every
chrome control we've Scalar-styled: the sidebar search pill, the Kapa
"Ask" button, and the page-title Copy dropdown trigger. Promoted to
`body` (was originally scoped to `.warp-sidebar-search` only) so any
chrome surface can inherit without re-declaring — single source of truth.
The sidebar search row itself is composed in `CustomSidebar.astro` as
`<div.warp-sidebar-search><Search /><KapaLauncher /></div>`. The default
`Search.astro` ships its own styles inside `@layer starlight.components`;
we override at the unlayered root so the modal/dialog styling stays
untouched.
-------------------------------------------------------------------------- */
/* Shared chrome palette (Scalar tokens — mirror `src/pages/api.astro`).
Inherited by Search, Ask, Copy, and any future chrome surface.
Dark-mode tokens are sourced from the warp.dev marketing brand ladder
(`warp-marketing-site-static/frontend/pages/global.css` §`--color-neutral-*`)
instead of the Oz webapp ladder. The Oz tier-700/800/900 greys carry
~11–24% blue saturation, which read as visibly cool chips against the
neutral `#121212` canvas; the warp.dev neutrals sit at near-zero saturation
with a slight warm tilt (matching `--sl-color-white`'s warm off-white)
so the trio looks like one grayscale chrome family rather than blue
stickers floating on neutral page bg. Body prose tokens
(`--sl-color-gray-*`) intentionally stay on the Oz ladder — only the
chrome controls move. */
body {
--warp-control-bg: #1e1e1d; /* warp.dev neutral-95 — raised surface */
--warp-control-bg-hover: #292929; /* warp.dev neutral-90 */
--warp-control-border: #404040; /* warp.dev neutral-80 */
--warp-control-border-hover: #585756; /* warp.dev neutral-70 */
--warp-control-text: #dbdbdb; /* Oz gray-300 — text-secondary (kept; already neutral) */
--warp-control-text-hover: hsl(40, 20%, 97%); /* warp.dev warm off-white */
--warp-control-icon: #9d9d9b; /* warp.dev neutral-40 — text-tertiary */
}
:root[data-theme='light'] body {
/* Light-mode tokens keep the neutral surface/border ladder (`gray-100`
/`gray-200`/`gray-300`) — those values already sit near zero saturation.
The hover/text/icon entries swap from cool Oz tier-600/700 greys to the
warp.dev neutral ladder so the trio reads grayscale in both themes. */
--warp-control-bg: #f3f3f3; /* Oz gray-100 / brand surface.1 (kept) */
--warp-control-bg-hover: #e7e7e7; /* Oz gray-200 / brand surface.2 (kept) */
--warp-control-border: #dbdbdb; /* Oz gray-300 / brand surface.3 (kept) */
--warp-control-border-hover: #9d9d9b; /* warp.dev neutral-40 */
--warp-control-text: #404040; /* warp.dev neutral-80 — text-secondary */
--warp-control-text-hover: #121212;/* warp.dev canvas black */
--warp-control-icon: #585756; /* warp.dev neutral-70 — text-tertiary */
}
.warp-sidebar-search {
/* Flex row pairs the search pill with the Kapa "Ask" button
(see KapaLauncher.astro). Search grows; Kapa sits at its natural label
width. `align-items: stretch` lets both controls share the same
2.25rem row height. The wrapper carries no inline padding so the row
spans the full sidebar pane width — visually distinct from the nav
items below, which sit at their own inset. */
display: flex;
align-items: stretch;
gap: 0.375rem;
padding: 0;
/* No vertical margin: the parent `.sidebar-content` already supplies
`padding-top: 1rem` (matching the right-rail TOC's `padding: 1rem ...`
in CustomPageSidebar so the search bar and "On this page" heading
share the same Y position) and `gap: 1rem` between flex children
(which provides the spacing to the sidebar nav below). Adding our own
margins here previously double-stacked with both, pushing the search
down 2rem and leaving an asymmetric 1.5rem gap underneath. */
margin-block: 0;
}
/* The default Search.astro renders <site-search><button[data-open-modal]>
...</button><dialog>...</dialog></site-search>. Style the trigger only;
the dialog is portaled to <body> and shouldn't be affected. */
.warp-sidebar-search site-search {
display: block;
/* Take all remaining space inside the flex row so the search pill spans
edge-to-edge minus the 2.25rem Kapa button on the right. `min-width: 0`
lets the inner button shrink without overflowing on narrow viewports. */
flex: 1 1 auto;
min-width: 0;
}
.warp-sidebar-search button[data-open-modal] {
/* Surface + typography are kept IDENTICAL to `.warp-kapa-button` (kapa.css)
via the shared `--warp-control-*` vars defined above, plus explicit
longhand font properties. Without explicit `font-family`, the browser
uses its default `<button>` font (system) instead of Inter — that's
what made the two buttons look like different typefaces previously. */
width: 100%;
/* `max-width: none` cancels Starlight's `@media (min-width: 50rem)
button[data-open-modal] { max-width: 22rem }` cap from the layered
defaults. Without this the pill stops growing past 22rem and looks
undersized inside our wider sidebar. */
max-width: none;
height: 2.25rem;
padding: 0 0.625rem;
border-radius: var(--sl-radius-sm);
border: 1px solid var(--warp-control-border);
background: var(--warp-control-bg);
color: var(--warp-control-text);
font-family: var(--__sl-font, 'Inter', sans-serif);
font-size: var(--sl-text-sm);
font-weight: 400;
letter-spacing: 0;
line-height: 1;
gap: 0.5rem;
transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}
.warp-sidebar-search button[data-open-modal]:hover {
border-color: var(--warp-control-border-hover);
background: var(--warp-control-bg-hover);
color: var(--warp-control-text-hover);
}
.warp-sidebar-search button[data-open-modal]:hover svg {
color: var(--warp-control-text-hover);
}
.warp-sidebar-search button[data-open-modal]:focus-visible {
outline: 2px solid var(--sl-color-accent-high);
outline-offset: 2px;
}
/* Magnifier pinned at 14×14 (matches the Ask AI icon in `kapa.css`) and at
the calmer `--warp-control-icon` color so the icon recedes a step relative
to the placeholder text. The default Search component marks it up via
`<Icon name="magnifier" />` which renders as an inline svg with no
intrinsic dimensions — we pin them here to avoid drift. */
.warp-sidebar-search button[data-open-modal] svg {
width: 14px;
height: 14px;
flex-shrink: 0;
color: var(--warp-control-icon);
transition: color 0.15s ease;
}
/* `⌘K` chip: subtle inset that picks up the pill surface, no competing
white border. Background mirrors `.warp-kapa-button__shortcut` (kapa.css)
so the two trigger surfaces feel like one family. */
.warp-sidebar-search button[data-open-modal] kbd {
background-color: rgba(255, 255, 255, 0.08);
border: 1px solid transparent;
color: var(--warp-control-text);
font-size: var(--sl-text-2xs);
}
:root[data-theme='light'] .warp-sidebar-search button[data-open-modal] kbd {
background-color: rgba(0, 0, 0, 0.06);
}
.warp-sidebar-search button[data-open-modal] kbd kbd {
background: transparent;
border: 0;
padding: 0;
}
/* --------------------------------------------------------------------------
17. Mobile sidebar drawer — keep elevation
When the sidebar fill matches the page background, the *mobile* slide-in
drawer would lose contrast against the body content underneath. Restore
it with a soft elevation shadow so the drawer reads as a layer above the
page, while still using the same canvas color (no off-shade fill).
Starlight applies `[aria-expanded]` to <starlight-menu-button> when the
menu is open and gates the mobile drawer styles via the same
`(min-width: 50rem)` breakpoint elsewhere in its stylesheet.
-------------------------------------------------------------------------- */
@media (max-width: 50rem) {
.sidebar-pane {
box-shadow: 8px 0 24px rgba(0, 0, 0, 0.45);
border-inline-end: 1px solid var(--sl-color-hairline-light);
}
/* Lighter shadow tone for the warm-white canvas. */
:root[data-theme='light'] .sidebar-pane {
box-shadow: 8px 0 24px rgba(0, 0, 0, 0.12);
}
}
/* --------------------------------------------------------------------------
18. Search dialog (Pagefind modal) — brand-aligned grayscale chrome
--------------------------------------------------------------------------
Starlight's `Search.astro` ships scoped styles inside `@layer
starlight.core` plus an inline `@import` of Pagefind's default UI sheet,
also at `layer(starlight.core)`. The defaults paint:
- The dialog frame with `--sl-color-gray-6` / `gray-5` (Oz cool blue
grays `#252b37` / `#414651`).
- The input focus ring with `--sl-color-accent` (Warp blue).
- Result hover/focus with `--sl-color-accent-high` outlines and
`--sl-color-accent-low` fills (more blue tint).
- Cancel + clear buttons in `--sl-color-text-accent` (blue).
On the neutral `#121212` canvas + the warp.dev grayscale chrome system
(§16 above), all of that read as visibly cool/blue and out of family.
Unlayered overrides below win the cascade against `starlight.core` and
pull the modal onto the same `--warp-control-*` ladder as the trigger
button it just opened from.
Selectors are scoped to `site-search dialog` (the `<dialog>` that lives
inside `<site-search>`) so they don't bleed into the Kapa Ask dialog,
which also uses a `<dialog aria-label="…">` element.
-------------------------------------------------------------------------- */
/* Dialog surface: drop the cool gray-6 fill and gray-5 border in favor of
the page canvas + a hairline. Depth comes from the backdrop blur and the
existing `box-shadow`. Same "one canvas, hairlines for separation"
pattern the rest of the site already uses (see custom.css §background). */
site-search dialog {
background-color: var(--sl-color-bg);
border: 1px solid var(--sl-color-hairline-light);
}
/* Stronger neutral backdrop. Starlight's `--sl-color-backdrop-overlay`
inherits the accent family in some themes; pin it to a flat dark scrim
so the modal still pops without a blue cast. Light mode gets a soft
warm-white wash instead. */
site-search dialog::backdrop {
background-color: rgba(18, 18, 18, 0.55);
}
:root[data-theme='light'] site-search dialog::backdrop {
background-color: rgba(255, 255, 255, 0.55);
}
/* Pagefind UI custom-property overrides. These cascade into Pagefind's own
stylesheet (which authors all its surfaces against
`--pagefind-ui-background` / `--pagefind-ui-border` / `--pagefind-ui-tag`
/ `--pagefind-ui-border-radius`) so we don't need to chase every
internal class. The shared chrome `--warp-control-*` ladder defined in
§16 is the source of truth for color; corner radii follow the chrome
rule — every clickable control surface lands at `--sl-radius-sm` (4px),
matching the trigger button this modal opened from. The dialog frame
itself stays at the Starlight default 8px (overlay tier).
`--sl-search-corners` is Starlight's own knob for the result-card
corners (defaults to `0.3125rem` = 5px, between our `sm` and `md`
tokens, which never matches anything else). Pin it to `sm` so the
list rows match the input above them. */
site-search #starlight__search {
--pagefind-ui-background: var(--warp-control-bg);
--pagefind-ui-border: var(--warp-control-border);
--pagefind-ui-tag: var(--warp-control-border);
--pagefind-ui-text: var(--sl-color-gray-2);
--pagefind-ui-primary: var(--sl-color-white);
--pagefind-ui-border-radius: var(--sl-radius-sm);
--sl-search-corners: var(--sl-radius-sm);
}
/* Input focus border: Starlight's default flips `--pagefind-ui-border` to
the saturated Warp blue accent on focus, which is the bright cyan ring
in the screenshot. Replace with the chrome ladder's hover border so the
input matches the trigger button's `:hover` affordance. */
site-search #starlight__search input:focus {
--pagefind-ui-border: var(--warp-control-border-hover);
}
/* Cancel + clear buttons: drop the blue accent color in favor of a calm
gray that recedes the way every other secondary chrome action does. */
site-search button[data-close-modal] {
color: var(--sl-color-gray-2);
}
site-search button[data-close-modal]:hover {
color: var(--sl-color-white);
}
site-search #starlight__search .pagefind-ui__search-clear::before {
background-color: var(--sl-color-gray-3);
}
site-search #starlight__search .pagefind-ui__search-clear:focus {
outline: 1px solid var(--warp-control-border-hover);
}
/* Result cards. Starlight paints the title row + each nested sub-result
with `--sl-color-black` (`#121212`), which on the cool gray-6 dialog
read as stamped-down patches. With the dialog now sharing the page
canvas, raise each result onto the chrome `--warp-control-bg` so the
list reads as a stack of tactile chips. A 1px hairline keeps the cards
distinct without a heavy outline. */
site-search #starlight__search .pagefind-ui__result-title:not(:where(.pagefind-ui__result-nested *)),
site-search #starlight__search .pagefind-ui__result-nested,
site-search #starlight__search .pagefind-ui__result-tags {
background-color: var(--warp-control-bg);
}
/* Hover / keyboard-focus state. Replace the blue accent outline + tinted
fill with the same neutral wash the chrome buttons use on hover. The
1px border swap stays inside the existing layout box, so list rows
don't shift on hover. */
site-search #starlight__search .pagefind-ui__result-title:not(:where(.pagefind-ui__result-nested *)):hover,
site-search #starlight__search .pagefind-ui__result-title:not(:where(.pagefind-ui__result-nested *)):focus-within,
site-search #starlight__search .pagefind-ui__result-nested:hover,
site-search #starlight__search .pagefind-ui__result-nested:focus-within {