-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathqueering.css
More file actions
5844 lines (5420 loc) · 249 KB
/
Copy pathqueering.css
File metadata and controls
5844 lines (5420 loc) · 249 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
/* queering.css — the shared sheet for queering.earth.
*
* THE PALETTE LIVES HERE AND ONLY HERE.
* Every recurring colour is a --qe-* token defined in this file. A page that wants
* a colour aliases a token; it does not write a hex. This is not tidiness — Star
* Stuff shipped 44 of 46 pages that printed blank because they hardcoded hexes
* instead of aliasing tokens, and the print stylesheet had nothing to reach.
*
* THE GROUND IS PAPER, NOT VOID.
* Star Stuff is a night sky. This is the other thing: a herbarium sheet in daylight.
* Warm vellum, ink, moss, rust — a Victorian specimen plate, not a dark theme with
* green in it. Keeping the two sites unmistakable is a design requirement.
*
* CONTRAST TARGET IS 7:1, NOT 4.5:1.
* The house style guide asks for 7:1 and every text token here is chosen to clear it
* against --qe-paper. tools/check-contrast.mjs measures it on screen and on paper.
*
* PLAIN VIEW IS A STYLESHEET, NEVER A SECOND DOCUMENT.
* Everything decorative — the wonk, the rotation, the botanical art, the paper wash —
* is switched off by `.plain` on <html>. There is one copy of the words. Two copies
* drift, and the accessible one is always the copy that rots.
*
* A NEW PANEL PICKS ONE OF THREE SURFACES.
* Fifteen components once shared one treatment — --qe-card, a 1px --qe-rule box, a
* 2px radius — so somebody else's words, our own commentary, and a housekeeping note
* were the same object to the eye, and a reader could only rank them by reading the
* label. Three surfaces, and a new panel takes the one that says what it is:
*
* bare space only, no fill, no box our own commentary
* ruled --qe-card inside a --qe-rule box an object mounted here
* ruled off hairlines above and below, no fill the ledger's own housekeeping
*
* THE THIRD TIER IS RULES AND NOT A TINT, and that is a measurement rather than a
* preference. A recessed --qe-paper-deep panel was tried first, and in daylight it
* drops --qe-moss to 6.90:1 and --qe-rust to 6.21:1 — both under the house 7:1 and
* both over WCAG AA, so check-contrast.mjs, which gates at AA, would have passed it
* silently. Hairlines cost nothing and every token keeps its measured value.
*
* SPACE IS A SCALE, AND THE DEVIATIONS ARE THE POINT.
* One line of body text is 1.19rem × 1.65 = 1.96rem, and --qe-space-* is quarter
* lines of it. This sheet once used twenty-five unrelated margin values, which does
* not read as a hand-kept register — it reads as noise, and it flattens the
* deviations that ARE authored. Asymmetry needs a norm to deviate from. The scale
* governs the space BETWEEN blocks; inside a block the hand is still allowed.
*
* PATINA IS A RECORD, NOT A TEXTURE.
* Age here is `.qe-provenance` — a line at the foot of every sheet saying when it was
* mounted and how often it has been corrected since, each clause linked to the entry
* in the register that did it. It is true, it is readable at any zoom, it accrues on
* its own, and it cannot be faked. TEXTURE NEVER GOES UNDER TEXT: a noise tile varies
* effective background luminance per pixel and passes every checker there is, because
* check-contrast.mjs measures computed colour pairs and cannot see a texture at all.
* Foxing belongs on the ground, the tape, the sprigs and the rules.
*
* THE GOLD GOES ON THE MEND.
* Kintsugi is not that the crack shows — it is that the most precious material in the
* workshop is spent on the break. So --qe-marigold is the seam token: it marks a
* re-determination in the register, the join in a restored attribution, and the
* provenance line of a sheet that has been corrected. --qe-lichen took over the
* routine event of mounting. A SEAM REQUIRES AN ACTUAL REPAIR IN THE REGISTER: a gold
* join on a sheet nobody ever corrected is decoration asserting a fact, which is the
* same failure as an image of text.
*/
/* ─────────────────────────────────────────────── tokens */
/* ── BEGIN generated by tools/make-fonts.mjs — do not edit by hand ────────── */
/* Self-hosted so the site makes no third-party request. Google served exactly these
subsets and exactly these unicode-range values; keeping both means glyph coverage
is unchanged and only the party serving them is. Regenerate with:
node tools/make-fonts.mjs
Never hand-edit below this line — and never add a fonts.googleapis.com link back
to a page: /privacy claims there are no third-party requests, and
check-metadata.mjs enforces that claim. */
/* Fraunces italic · vietnamese */
@font-face {
font-family: 'Fraunces';
font-style: italic;
font-weight: 400 700;
font-display: swap;
src: url(fonts/fraunces-italic-vietnamese.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* Fraunces italic · latin-ext */
@font-face {
font-family: 'Fraunces';
font-style: italic;
font-weight: 400 700;
font-display: swap;
src: url(fonts/fraunces-italic-latin-ext.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Fraunces italic · latin */
@font-face {
font-family: 'Fraunces';
font-style: italic;
font-weight: 400 700;
font-display: swap;
src: url(fonts/fraunces-italic-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Fraunces normal · vietnamese */
@font-face {
font-family: 'Fraunces';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url(fonts/fraunces-vietnamese.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* Fraunces normal · latin-ext */
@font-face {
font-family: 'Fraunces';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url(fonts/fraunces-latin-ext.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Fraunces normal · latin */
@font-face {
font-family: 'Fraunces';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url(fonts/fraunces-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Newsreader italic · vietnamese */
@font-face {
font-family: 'Newsreader';
font-style: italic;
font-weight: 400 700;
font-display: swap;
src: url(fonts/newsreader-italic-vietnamese.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* Newsreader italic · latin-ext */
@font-face {
font-family: 'Newsreader';
font-style: italic;
font-weight: 400 700;
font-display: swap;
src: url(fonts/newsreader-italic-latin-ext.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Newsreader italic · latin */
@font-face {
font-family: 'Newsreader';
font-style: italic;
font-weight: 400 700;
font-display: swap;
src: url(fonts/newsreader-italic-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Newsreader normal · vietnamese */
@font-face {
font-family: 'Newsreader';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url(fonts/newsreader-vietnamese.woff2) format('woff2');
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* Newsreader normal · latin-ext */
@font-face {
font-family: 'Newsreader';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url(fonts/newsreader-latin-ext.woff2) format('woff2');
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Newsreader normal · latin */
@font-face {
font-family: 'Newsreader';
font-style: normal;
font-weight: 400 700;
font-display: swap;
src: url(fonts/newsreader-latin.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* ── The picker families, offered under Reading ───────────────────────────────
Declared, not loaded: an @font-face costs its own bytes of CSS and the file is
fetched only when a rule using the family first matches rendered text. A reader
who picks none downloads none of them. The class rules below are what the picker
switches, and both halves are generated from one table so they cannot disagree
about which families exist or which of them may set the reading face. */
/* BBB Baskervvol · regular */
@font-face {
font-family: 'BBB Baskervvol';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/baskervvol-regular.otf) format('opentype');
}
/* BBB Baskervvol · italic */
@font-face {
font-family: 'BBB Baskervvol';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url(fonts/baskervvol-italic.otf) format('opentype');
}
/* BBB Baskervvol · bold */
@font-face {
font-family: 'BBB Baskervvol';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/baskervvol-bold.otf) format('opentype');
}
/* Adelphe · regular */
@font-face {
font-family: 'Adelphe';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/adelphe-regular.otf) format('opentype');
}
/* Adelphe · italic */
@font-face {
font-family: 'Adelphe';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url(fonts/adelphe-italic.otf) format('opentype');
}
/* Adelphe · bold */
@font-face {
font-family: 'Adelphe';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/adelphe-bold.otf) format('opentype');
}
/* Coxinelle · regular */
@font-face {
font-family: 'Coxinelle';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/coxinelle-regular.otf) format('opentype');
}
/* Coxinelle · italic */
@font-face {
font-family: 'Coxinelle';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url(fonts/coxinelle-italic.otf) format('opentype');
}
/* Coxinelle · bold */
@font-face {
font-family: 'Coxinelle';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/coxinelle-bold.otf) format('opentype');
}
/* Atkinson Hyperlegible · italic-400 */
@font-face {
font-family: 'Atkinson Hyperlegible';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url(fonts/atkinson-italic-400.woff2) format('woff2');
}
/* Atkinson Hyperlegible · italic-700 */
@font-face {
font-family: 'Atkinson Hyperlegible';
font-style: italic;
font-weight: 700;
font-display: swap;
src: url(fonts/atkinson-italic-700.woff2) format('woff2');
}
/* Atkinson Hyperlegible · roman-400 */
@font-face {
font-family: 'Atkinson Hyperlegible';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/atkinson-roman-400.woff2) format('woff2');
}
/* Atkinson Hyperlegible · roman-700 */
@font-face {
font-family: 'Atkinson Hyperlegible';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/atkinson-roman-700.woff2) format('woff2');
}
/* Redaction Inclusive · regular */
@font-face {
font-family: 'Redaction Inclusive';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/redaction-regular.woff2) format('woff2');
}
/* Insolente · regular */
@font-face {
font-family: 'Insolente';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/insolente-regular.otf) format('opentype');
}
/* Trickster · regular */
@font-face {
font-family: 'Trickster';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/trickster-regular.woff2) format('woff2');
}
/* Victorianna · regular */
@font-face {
font-family: 'Victorianna';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/victorianna-regular.otf) format('opentype');
}
/* Victorianna · italic */
@font-face {
font-family: 'Victorianna';
font-style: italic;
font-weight: 400;
font-display: swap;
src: url(fonts/victorianna-italic.otf) format('opentype');
}
/* Sporting Grotesque · regular */
@font-face {
font-family: 'Sporting Grotesque';
font-style: normal;
font-weight: 400;
font-display: swap;
src: url(fonts/sporting-regular.woff2) format('woff2');
}
/* Sporting Grotesque · bold */
@font-face {
font-family: 'Sporting Grotesque';
font-style: normal;
font-weight: 700;
font-display: swap;
src: url(fonts/sporting-bold.woff2) format('woff2');
}
/* BBB Baskervvol — Bye Bye Binary. Sets both faces: it has a real italic. */
html.qe-font-baskervvol {
--qe-display: 'BBB Baskervvol', "Iowan Old Style", Georgia, serif;
--qe-body: 'BBB Baskervvol', "Iowan Old Style", Georgia, serif;
}
/* Adelphe — Bye Bye Binary. Sets both faces: it has a real italic. */
html.qe-font-adelphe {
--qe-display: 'Adelphe', "Iowan Old Style", Georgia, serif;
--qe-body: 'Adelphe', "Iowan Old Style", Georgia, serif;
}
/* Coxinelle — Bye Bye Binary. Sets both faces: it has a real italic. */
html.qe-font-coxinelle {
--qe-display: 'Coxinelle', "Iowan Old Style", Georgia, serif;
--qe-body: 'Coxinelle', "Iowan Old Style", Georgia, serif;
}
/* Atkinson Hyperlegible — Braille Institute of America. Sets both faces: it has a real italic. */
html.qe-font-atkinson {
--qe-display: 'Atkinson Hyperlegible', "Iowan Old Style", Georgia, serif;
--qe-body: 'Atkinson Hyperlegible', "Iowan Old Style", Georgia, serif;
}
/* Redaction Inclusive — Bye Bye Binary, after Redaction by Jeremy Mickel / MCKL. Display only: no italic upstream, so Newsreader keeps the reading. */
html.qe-font-redaction {
--qe-display: 'Redaction Inclusive', "Iowan Old Style", Georgia, serif;
}
/* Insolente — Bye Bye Binary. Display only: no italic upstream, so Newsreader keeps the reading. */
html.qe-font-insolente {
--qe-display: 'Insolente', "Iowan Old Style", Georgia, serif;
}
/* Trickster — Jean-Baptiste Morizot, Velvetyne. Display only: no italic upstream, so Newsreader keeps the reading. */
html.qe-font-trickster {
--qe-display: 'Trickster', "Iowan Old Style", Georgia, serif;
}
/* Victorianna — Velvetyne. Display only: no italic upstream, so Newsreader keeps the reading. */
html.qe-font-victorianna {
--qe-display: 'Victorianna', "Iowan Old Style", Georgia, serif;
}
/* Sporting Grotesque — Lucas Le Bihan, Velvetyne. Display only: no italic upstream, so Newsreader keeps the reading. */
html.qe-font-sporting {
--qe-display: 'Sporting Grotesque', "Iowan Old Style", Georgia, serif;
}
/* ── END generated by tools/make-fonts.mjs ───────────────────────────────── */
:root {
/* Ground. Warm vellum, and one step deeper for pressed panels. */
--qe-paper: #f5efe2;
--qe-paper-deep: #ece1cd;
--qe-card: #fbf7ed;
/* Ink. All three clear 7:1 on --qe-paper. */
--qe-ink: #241f1a; /* 14.3:1 — body text */
--qe-moss: #37502f; /* 7.8:1 — secondary text, headings */
--qe-rust: #8a3520; /* 7.0:1 — links, emphasis */
/* Decoration only. NOT for text — none of these clear 7:1 on paper.
Botanical line art, rules, and the specimen marks use these. */
--qe-lichen: #9caa86;
--qe-verdigris: #4e8c7a;
--qe-marigold: #c9922e;
--qe-coral: #c4553c;
--qe-violet: #7a5c9e;
/* THE TWO LILACS ARE ONE COLOUR AT TWO STRENGTHS, and they are two tokens for the
same reason --qe-paper and --qe-paper-deep are: a wash and the thing washed onto
it cannot be one value. The moth's forewing takes the first, its hindwing and the
sea of its globe the second. Borrowed from Ezra Furman by way of the illustration
that needed them — see the moth on the home page, and ATTRIBUTIONS.md. */
--qe-lilac: #b9a2d6;
--qe-lilac-pale: #ded1ec;
/* Structure */
--qe-rule: #cdbfa4;
/* The pale flesh of a specimen — a mushroom's stipe, a cut stem. It is not the
ground, it only happened to match it in daylight, so it gets its own token. */
--qe-flesh: #ece1cd;
/* The foxed-paper wash: four soft stains, tokenised so the cabinet can restain
them. Decoration, painted under everything, never behind text alone. */
--qe-wash-a: rgba(154, 132, 92, 0.10);
--qe-wash-b: rgba(120, 140, 100, 0.09);
--qe-wash-c: rgba(160, 120, 80, 0.08);
--qe-wash-d: rgba(110, 130, 110, 0.07);
/* The shadow a lifted sheet casts. Near-black on paper; on the cabinet ground
a near-black shadow is invisible, so this is a token and not a literal. */
--qe-shade: rgba(36, 31, 26, 0.55);
/* THE FOUND MARK, and it is a RULE rather than a wash, for two separate reasons
that were each found by measuring rather than by taste.
· A tint under the word fails in the drawer. Marigold at 0.30 over --qe-paper
composites to 11.2:1 against the ink and passes comfortably; the same wash
over --qe-cab-paper composites to 6.94:1, and every alpha above it is worse,
because lightening a dark ground moves it TOWARDS light ink. That is the
gating-surface inversion this file warns about, arriving in a new component.
The colour goes on the rule and never on the glyph — and never under it.
· It is not marigold. Marigold is the seam token: a re-determination, a
restored attribution, a corrected sheet. A search hit is not a repair, and
spending the gold on one would be a gold join on a sheet nobody corrected,
which is what makes the real mends unfindable. Verdigris is not spoken for,
and a reader's own mark on somebody else's page is the right register for it. */
--qe-found: var(--qe-verdigris);
--qe-measure: 34rem; /* ~66 characters at the body size */
--qe-gutter: clamp(1.25rem, 5vw, 3rem);
/* Space. One line of body text is 1.19rem × 1.65, and the scale is quarter lines
of it, so every gap between blocks is a whole number of quarter-lines and the
page has a rhythm to deviate from. See the note at the head of this file. */
--qe-line: 1.96rem;
--qe-space-1: 0.49rem;
--qe-space-2: 0.98rem;
--qe-space-3: 1.47rem;
--qe-space-4: 1.96rem; /* one line */
--qe-space-5: 2.45rem;
--qe-space-6: 2.94rem;
--qe-space-8: 3.92rem; /* two lines */
/* Corners. A sheet that has been picked up a hundred times does not have four
identical corners, and thirteen components once carried the same 2px radius on
all four of theirs. Three profiles, spread across the components so that no two
panels a reader sees together are cornered alike. Koko, for the price of a
token: it is a radius, so it costs nothing in contrast and nothing in print. */
--qe-corner-a: 3px 2px 4px 2px;
--qe-corner-b: 2px 4px 2px 3px;
--qe-corner-c: 4px 2px 3px 2px;
--qe-corner-chip: 2px 1px 3px 1px; /* slips, chips, and the drift rail */
/* Where the four stains fall. A stain is a property of the paper and not of the
window, so these are overridden per page in the markup — the same idiom as
`--rot` on a slip — and no two sheets are foxed identically. The values below
are the front page's, and are the fallback for anything that states none. */
--qe-fox-a: 12% 8%;
--qe-fox-b: 92% 22%;
--qe-fox-c: 78% 96%;
--qe-fox-d: 4% 82%;
/* HOW THE ACCESSION STAMP MEETS THE PAPER, and it is not a colour, which is why
it is here rather than aliased as one. `multiply` is the whole washed-out
effect: the sheet's own foxing comes up through the stamp's ink the way it does
through a real impression. On a dark ground multiply darkens towards the
ground, so the same declaration takes a mark measuring 7.2:1 down to almost
nothing — verified by eye in the drawer before this token existed, because
`check-contrast.mjs` composites computed colour pairs and cannot see a blend
mode at all. It would have reported the vanished stamp as clean.
Same lesson the wash, the shade and the flesh each taught: a property that
differs between the two grounds is a token, or it is two selectors that drift. */
--qe-stamp-blend: multiply;
/* Type. Fraunces carries a WONK axis — letterforms that deviate from the
norm on purpose. Using it for the display face is not a coincidence. */
--qe-display: "Fraunces", "Iowan Old Style", Georgia, serif;
--qe-body: "Newsreader", "Iowan Old Style", Georgia, serif;
/* ── THE CABINET. The dark ground, and the only copy of its values.
Not the daylight sheet with the lamp off: the drawer shut. A herbarium
cabinet is dark warm brown, and a Victorian dark-ground plate prints its
specimens on near-black precisely so pale forms read. Nothing aliases these
names directly — the two rules under "the ground switch" do it. */
--qe-cab-paper: #2a1d19; /* the cabinet itself */
--qe-cab-paper-deep: #1f1512; /* a compartment, recessed */
--qe-cab-card: #241a16;
/* Text. 7:1 is measured against --qe-cab-paper, which is the LIGHTEST surface
any text sits on here. That is the inversion to watch: in daylight a card is
lighter than the page, so text on it gains contrast; on a dark ground a
lifted card loses it. The cards are recessed for exactly this reason. */
--qe-cab-ink: #eee3d0; /* 12.8:1 */
--qe-cab-moss: #90b784; /* 7.2:1 */
--qe-cab-rust: #e49b89; /* 7.3:1 */
/* Decoration only, same as in daylight, and deliberately still saturated.
7:1 is a rule for letters. Lifting these to clear it turns every flower
chalky and washes the plates out — the dark-ground plate keeps its
specimens saturated and spends the brightness on the text. */
--qe-cab-lichen: #9caa86;
--qe-cab-verdigris: #57a08b;
--qe-cab-marigold: #c9922e;
--qe-cab-coral: #cf6142;
--qe-cab-violet: #8f6fb5;
--qe-cab-lilac: #a98cca;
--qe-cab-lilac-pale: #6f5a8c;
--qe-cab-rule: #4a382f;
--qe-cab-flesh: #d8c9ae;
--qe-cab-wash-a: rgba(214, 165, 76, 0.09);
--qe-cab-wash-b: rgba(144, 183, 132, 0.08);
--qe-cab-wash-c: rgba(228, 155, 137, 0.07);
--qe-cab-wash-d: rgba(127, 184, 167, 0.06);
--qe-cab-shade: rgba(0, 0, 0, 0.55);
--qe-cab-stamp-blend: normal; /* see --qe-stamp-blend: multiply erases the mark here */
}
/* ─────────────────────────────────────────────── the ground switch
Two rules, because CSS cannot set a class from a media query. They carry no
colour of their own — every one is an alias of a --qe-cab-* value defined
once above, so the switch cannot drift from the palette. A drifted alias here
is a missing switch, never a wrong colour.
BOTH ARE `@media screen`. Print is daylight, always: the print sheet builds
its own black-on-white from scratch and must not inherit a ground.
The reader's own choice wins over the system's in both directions —
`html.daylight` opts out of a dark system, `html.cabinet` opts in on a light
one. Absent either class the system decides, so a reader who has never
touched the control still gets the ground their machine asked for, with no
script involved. */
@media screen and (prefers-color-scheme: dark) {
:root:not(.daylight) {
--qe-paper: var(--qe-cab-paper);
--qe-paper-deep: var(--qe-cab-paper-deep);
--qe-card: var(--qe-cab-card);
--qe-ink: var(--qe-cab-ink);
--qe-moss: var(--qe-cab-moss);
--qe-rust: var(--qe-cab-rust);
--qe-lichen: var(--qe-cab-lichen);
--qe-verdigris: var(--qe-cab-verdigris);
--qe-marigold: var(--qe-cab-marigold);
--qe-coral: var(--qe-cab-coral);
--qe-violet: var(--qe-cab-violet);
--qe-lilac: var(--qe-cab-lilac);
--qe-lilac-pale: var(--qe-cab-lilac-pale);
--qe-rule: var(--qe-cab-rule);
--qe-flesh: var(--qe-cab-flesh);
--qe-wash-a: var(--qe-cab-wash-a);
--qe-wash-b: var(--qe-cab-wash-b);
--qe-wash-c: var(--qe-cab-wash-c);
--qe-wash-d: var(--qe-cab-wash-d);
--qe-shade: var(--qe-cab-shade);
--qe-stamp-blend: var(--qe-cab-stamp-blend);
}
}
@media screen {
:root.cabinet {
--qe-paper: var(--qe-cab-paper);
--qe-paper-deep: var(--qe-cab-paper-deep);
--qe-card: var(--qe-cab-card);
--qe-ink: var(--qe-cab-ink);
--qe-moss: var(--qe-cab-moss);
--qe-rust: var(--qe-cab-rust);
--qe-lichen: var(--qe-cab-lichen);
--qe-verdigris: var(--qe-cab-verdigris);
--qe-marigold: var(--qe-cab-marigold);
--qe-coral: var(--qe-cab-coral);
--qe-violet: var(--qe-cab-violet);
--qe-lilac: var(--qe-cab-lilac);
--qe-lilac-pale: var(--qe-cab-lilac-pale);
--qe-rule: var(--qe-cab-rule);
--qe-flesh: var(--qe-cab-flesh);
--qe-wash-a: var(--qe-cab-wash-a);
--qe-wash-b: var(--qe-cab-wash-b);
--qe-wash-c: var(--qe-cab-wash-c);
--qe-wash-d: var(--qe-cab-wash-d);
--qe-shade: var(--qe-cab-shade);
--qe-stamp-blend: var(--qe-cab-stamp-blend);
}
}
/* Plain view swaps the faces for the reader's own, and nothing else about the
words changes. Colours stay: they already clear 7:1. */
html.plain {
--qe-display: system-ui, -apple-system, "Segoe UI", sans-serif;
--qe-body: system-ui, -apple-system, "Segoe UI", sans-serif;
}
/* ─────────────────────────────────────────────── base */
*, *::before, *::after { box-sizing: border-box; }
html {
/* 200% zoom has to keep working, so every size below is relative to this. */
font-size: 100%;
scroll-behavior: smooth;
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
}
body {
margin: 0;
padding: 0;
/* Positioned, and tall enough to be a sheet on a short page: both are for the
wash below, which is absolute against this box rather than fixed to the window.
`position: relative` does not make a stacking context on its own, so the
negative-z wash still paints above the canvas — body's background propagates to
the canvas and is not part of body's own painting, which is what makes that
work. Nothing else on this site positions against the window. */
position: relative;
min-height: 100vh;
background-color: var(--qe-paper);
color: var(--qe-ink);
font-family: var(--qe-body);
font-size: 1.19rem; /* ~19px */
line-height: 1.65;
font-optical-sizing: auto;
-webkit-font-smoothing: antialiased;
}
/* The foxed-paper wash: four soft, off-centre stains, no image and no noise.
Switched off in plain view and never painted on paper.
Deliberately NOT texture: a noise tile or a grain image under text varies the
effective background luminance per pixel, which no contrast checker can see. Four
soft gradients under everything, at a token's alpha, are measurable — the ancestor
stack check-contrast.mjs composites against is a real colour.
IT IS ABSOLUTE, NOT FIXED, so the stains scroll with the sheet. Pinned to the
window they held still while the paper moved under them, which is the one thing a
stain does not do.
AND IT DOES NOT TILE. It did for one draft, at a 150rem period, so that a long
sheet would not have clean paper through the middle of it. That draft shipped a
visible horizontal line at every repeat, and the reason is arithmetic rather than
blending: `transparent 70%` puts each gradient's edge at 0.7 of its radius, so the
stain at `8%` of a 2400px tile reaches 278px ABOVE the tile's top and the one at
`96%` reaches 352px below its bottom. Both get cut off square at the boundary, and
a cut-off gradient meets the next copy of itself as a step. Any fix that keeps the
tile has to constrain every page's stain positions to a safe band inside it —
which is a trap laid for whoever writes the next sheet, to buy an even cast on the
two pages long enough to need one. So: four stains over the whole sheet, and a
long sheet is sparsely foxed. That is what a big sheet of foxed paper looks like.
The spots do not multiply to fill it. */
body::before {
content: "";
position: absolute;
inset: 0;
z-index: -1;
pointer-events: none;
background-image:
radial-gradient(58rem 42rem at var(--qe-fox-a), var(--qe-wash-a), transparent 70%),
radial-gradient(46rem 38rem at var(--qe-fox-b), var(--qe-wash-b), transparent 72%),
radial-gradient(52rem 40rem at var(--qe-fox-c), var(--qe-wash-c), transparent 70%),
radial-gradient(40rem 34rem at var(--qe-fox-d), var(--qe-wash-d), transparent 74%);
}
html.plain body::before { display: none; }
/* ══════════════════════════════════════════════════════════════════════════════
READING SETTINGS — the system decides, and the reader may say otherwise
══════════════════════════════════════════════════════════════════════════════
DEFAULT TO THE SYSTEM. ALLOW IN-THE-MOMENT CONFIGURATION. Implementing
prefers-reduced-motion and prefers-contrast perfectly still only reaches the
people who know those switches exist — most have never opened that menu. And a
setting chosen once, months ago, cannot know that today is a migraine day. So the
media queries below are the DEFAULT, and each has a class that overrides it in
either direction, set from /the reading settings and remembered per browser.
Every one of these is additive contrast or additive space. Nothing here lowers a
ratio, so the 7:1 the palette already clears is a floor these states cannot dip
under — which matters because check-contrast.mjs measures the two grounds and
cannot see a class it was never told about. Keep it that way: a reading setting
that could REDUCE contrast would need the gate taught about it first. */
/* ── More contrast ───────────────────────────────────────────────────────────
The daylight palette already clears the house 7:1. This goes further for readers
who ask: ink to black, the two accents down onto the ink's own darkness, rules
darkened so a boundary is unmistakable, and the foxing lifted off the paper. */
html.qe-contrast-on,
html.qe-contrast-on.daylight {
--qe-ink: #000000; /* 20.4:1 */
--qe-moss: #1e3018; /* 13.6:1 — still moss, still not black */
--qe-rust: #6b2415; /* 11.1:1 */
--qe-rule: #6f6350;
--qe-paper: #fffdf7;
--qe-paper-deep: #f2ead8;
--qe-card: #ffffff;
}
html.qe-contrast-on.cabinet {
--qe-ink: #fffdf7;
--qe-moss: #cfe3c4;
--qe-rust: #ffc9b4;
--qe-rule: #9d8f7c;
--qe-paper: #150e0b;
--qe-paper-deep: #241a15;
--qe-card: #0d0806;
}
/* The wash is a texture, and texture never goes under text. At higher contrast it
is the first thing to go: it varies effective luminance per pixel, which is the
one thing check-contrast.mjs cannot see. */
html.qe-contrast-on body::before { display: none; }
/* The system asked for more contrast and the reader has not said otherwise. Same
declarations, reached the other way; the values live once, above. */
@media (prefers-contrast: more) {
html:not(.qe-contrast-off):not(.cabinet) {
--qe-ink: #000000; --qe-moss: #1e3018; --qe-rust: #6b2415;
--qe-rule: #6f6350; --qe-paper: #fffdf7; --qe-paper-deep: #f2ead8; --qe-card: #ffffff;
}
html:not(.qe-contrast-off).cabinet {
--qe-ink: #fffdf7; --qe-moss: #cfe3c4; --qe-rust: #ffc9b4;
--qe-rule: #9d8f7c; --qe-paper: #150e0b; --qe-paper-deep: #241a15; --qe-card: #0d0806;
}
html:not(.qe-contrast-off) body::before { display: none; }
}
/* ── Text size ───────────────────────────────────────────────────────────────
THE SITE ALREADY FOLLOWS THE BROWSER'S OWN SIZE, and that is why the first option
is not a no-op. `html { font-size: 100% }` inherits whatever the reader set as
their default, every type size on the sheet is in `rem` (129 of them; not one in
`px`), and the spacing scale and the measure are `rem` too — so raising the root
moves the line height, the gaps and the 66-character measure with it, instead of
swelling the words inside a box that stays put.
LARGER ONLY, AND THAT IS A HOUSE RULE RATHER THAN AN OMISSION. The Stimpunks style
guide sets body text at 18-20px and the sheet sits at 1.19rem, which is 19px at a
default browser. A "smaller" option would take it under that floor, so the panel
does not offer one; a reader who wants less can turn their own browser down and
this sheet will follow, which is the mechanism the first option names.
These are percentages of the reader's OWN default, not absolute sizes. Someone
running a 20px browser gets 22.5px and 25px, not 18 and 20. */
html.qe-textsize-larger { font-size: 112.5%; }
html.qe-textsize-largest { font-size: 125%; }
/* ── Looser lines ────────────────────────────────────────────────────────────
WCAG 1.4.12 asks that content survive a reader forcing line-height to 1.5 and
paragraph spacing to 2em. The body sits at 1.65 already, so this is not remedial —
it is the same request made by someone who wants more air than the sheet's own
setting, which is a reading preference no system setting expresses. */
html.qe-spacing-on {
--qe-line: 1.95;
--qe-para-gap: 1.9rem;
letter-spacing: 0.012em;
word-spacing: 0.045em;
}
html.qe-spacing-on p,
html.qe-spacing-on li,
html.qe-spacing-on dd,
html.qe-spacing-on blockquote { line-height: var(--qe-line, 1.65); }
html.qe-spacing-on p + p { margin-top: var(--qe-para-gap, 1.47rem); }
/* ── Forced colours ──────────────────────────────────────────────────────────
NOT A SETTING WE OFFER, and it cannot be: forced-colors reports an operating
system state — Windows Contrast Themes and its kin — where the browser
substitutes the reader's own palette for everything we declared. A page can only
respond to it. That is the point of it, and the reason there is no toggle for it
in the panel while there is one for contrast.
Most of this site survives the substitution already, because of decisions taken
for other reasons: every control is a real <button> with a real border, and the
register's four kinds carry WORDS as well as an accent, so a palette that
flattens their colours does not flatten their meaning. What follows repairs the
places where the substitution takes away a boundary colour was carrying alone. */
@media (forced-colors: active) {
/* The hover state on a card was a background change and nothing else, so it
vanished entirely. An outline is the repair the spec asks for. */
a.card:hover,
a.card:focus-visible { outline: 2px solid Highlight; outline-offset: 2px; }
/* Shadows are dropped in this mode. Anything that leaned on one for its edge
gets a real border in the reader's own text colour. */
.qe-plate img,
.card-wrap,
.qe-tag { border: 1px solid CanvasText; }
/* Focus must track the reader's palette, not our rust. */
a:focus-visible,
button:focus-visible,
summary:focus-visible,
input:focus-visible,
.qe-anchor:focus-visible { outline: 3px solid Highlight; outline-offset: 2px; }
/* The foxing and the paper tint are decoration that the mode flattens anyway;
removing them outright avoids a muddy composite behind text. */
body::before { display: none; }
/* The botanical art is DECORATION, so it is allowed to be forced to the reader's
ink. Colour is not information in a drawing of a leaf, and the spec is explicit
that forced-color-adjust is for the rare case where the colour IS the
information. Nothing here qualifies, so nothing here opts out. */
/* The reading panel is a box whose edge was a rule token. */
.qe-reading-panel { border: 1px solid CanvasText; }
}
/* ─────────────────────────────────────────────── skip link */
.qe-skip {
position: absolute;
left: -9999px;
top: 0;
z-index: 20;
padding: 0.75rem 1.25rem;
background: var(--qe-ink);
color: var(--qe-paper);
font-family: var(--qe-body);
text-decoration: none;
}
.qe-skip:focus { left: 0.5rem; top: 0.5rem; }
/* ─────────────────────────────────────────────── the controls */
.qe-controls {
display: flex;
justify-content: flex-end;
align-items: center;
gap: 0.85rem;
padding: 0.9rem var(--qe-gutter) 0;
/* IT WRAPS BECAUSE IT RAN OUT, AND THAT WAS MEASURED RATHER THAN GUESSED.
With four controls the tray filled a 375px phone EXACTLY — first item at
x=20, last ending at x=355 inside a 20px gutter, nothing to spare. Adding
the fox-and-hedgehog mark as a fifth would have pushed the search link to a
negative x, and since this row is `flex-end` the overflow goes off the LEFT
edge and takes the document's scrollWidth with it — the horizontal body
scroll this site's layout rule forbids outright. Wrapping is the cheap fix
and the honest one: on a narrow screen the tray becomes two right-aligned
rows, and on any width that fits it is a no-op. */
flex-wrap: wrap;
}
/* ─── the way back, first in the tray
*
* THE BREADCRUMB WAS ALREADY A ROUTE HOME AND IT WAS NOT THE ROUTE PEOPLE REACH
* FOR. Ryan kept looking in the top bar; .qe-crumbs is inside the masthead, below
* the tray, and on a sheet it is the third thing down. Both stay. A trail says
* where you are and a control says where you can go, and a reader mid-sheet
* wants the second one.
*
* IT IS LABELLED, AND THE UNLABELLED LICENCE NEXT DOOR DOES NOT REACH IT. The
* fox and the hedgehog are allowed to be a picture alone because nothing is
* withheld — that page is in every footer, every drawer menu and the finding aid.
* The home page is the one destination a reader is most likely to want and least
* likely to hunt for, so hiding it behind a drawing would be the exact complaint
* that prompted this, wearing a mark. The word does the work; the drawing only
* has to be handsome. Same build as the search link beside it, for the same reason.
*
* WHY A BUILDING, ON A SITE MADE OF SHEETS. Four marks were drawn and rasterised
* at 16, 20 and 27px, then magnified off a canvas rather than redrawn large — a
* vector redrawn large is a lie about what a reader gets, which is the lesson
* favicon.svg paid for twice and the loupe a third time. What the pixels said:
*
* · A HOUSE SILHOUETTE IS THE ONLY THING THAT READS AS HOME AT 16px. It is the
* one glyph the web has actually taught people. Every candidate without a
* pitched roof needed the word to carry the whole meaning.
* · THE SITE’S OWN MARK WAS TRIED FIRST AND LOST. The pressed leaf from
* favicon.svg is the obvious answer — home as the logo — and it does not
* survive the trip. It has a paper ground and 64px on the icon; at 20px in
* moss beside the loupe it is a dark blob with less character than the
* instrument next to it. Its midrib in paper is a white gash that splits the
* leaf into two lobes and reads as a pea pod; in lichen it is better and
* still quieter than this. And --qe-rust goes pale pink in the drawer, so the
* pin that makes the favicon legible becomes a pale bulb at the base.
* · A CABINET WAS REFUSED WITHOUT DRAWING IT. /the-cabinet-itself is a drawer
* in the menu two controls along. One picture, two destinations.
* · SO WAS A MENDED VESSEL, AND THAT ONE IS A HOUSE RULE. Kintsugi is spent
* here: --qe-marigold marks a re-determination in the register and a join in a
* restored attribution, and a seam requires an actual repair. A gold-mended
* mark in the tray would assert a correction that never happened, an arm’s
* length from the real mends on every provenance line.
*
* THREE BAYS AND NO MORE, WHICH TOOK TWO WRONG VERSIONS. A glazing grid with a
* transom and a missing pane goes muddy by 20px and the missing pane does not read
* as a void at all — it reads as a dark window, and sitting off-centre it drags
* the whole mark sideways. So: a gable mullion, two bars, and the centre bay left
* full height to be the door. A shoot drawn up through that door — the botanical
* cue this mark otherwise lacks — READS AS A SMALL PERSON STANDING IN THE DOORWAY
* at the size it ships at, which is the panicle-and-spines lesson arriving in a
* fourth costume: do not reach for one small mark where the eye expects a figure.
*
* THE RIDGE IS OFF CENTRE AND THE BAYS ARE UNEQUAL, AND THAT IS THE AGE ON IT.
* The apex is at x 11.2 against a body centred on 12, so the two slopes differ and
* the bays run 4.8, 5.4, 4.6. It is visible at 20px, it is the wonk axis this
* site already runs on its type and on the rail’s ticks, and it CLAIMS NOTHING —
* which is the whole licence for it, the same test the tick lengths have to pass
* from the other direction.
*
* STROKED, LIKE THE LOUPE, BECAUSE A FRAME IS MADE OF THIN PARTS. The animal mark
* is filled because an animal at 20px is a silhouette; this is glazing bars and a
* roof. Both parts are filled with the paper and occlude what is behind them
* rather than crossing it, so the gable does not print through the body — the
* loupe’s own finding, and in the cabinet it inverts to dark panes in a moss
* frame with no rule of its own.
*
* IT DOES NOT ANIMATE. Nothing in the instrument tray moves; the drawing-on is for
* botanical art, and a building is not a plant. */
.qe-home-link {
display: inline-flex;
align-items: center;
gap: 0.38rem;
font-family: var(--qe-body);
font-size: 0.85rem;
line-height: 1.3;
color: var(--qe-moss);
text-decoration: none;
border-bottom: 1px solid var(--qe-rule);
padding: 0.2rem 0.15rem;
}
.qe-home-link:hover { border-bottom-color: var(--qe-moss); }
.qe-home-link:focus-visible {
outline: 3px solid var(--qe-rust);
outline-offset: 2px;
}
/* On the home page itself. The control stays rather than vanishing on one page out
of thirty — the search link’s rule, for the search link’s reason. */
.qe-home-link[aria-current="page"] {
color: var(--qe-ink);
border-bottom-color: var(--qe-moss);
}
/* 1.35rem square, which is the loupe exactly, so the two instruments either side
of the ground control weigh the same. */
.qe-glasshouse {
display: block;
flex: none;
width: 1.35rem;
height: 1.35rem;
fill: none;
stroke: currentColor;
stroke-width: 1.5;
stroke-linejoin: round;
stroke-linecap: round;
}
.qe-glasshouse .glass { fill: var(--qe-paper); }
/* ─── the finding aid, reachable from the top of every page
*
* Search used to live only in the footer, which on /wild-nights is nine thousand
* words down — and most arrivals here are not via the home page, they are a shared
* link or a search result landing straight on a sheet. So it sits with the two view
* controls, which is also where it belongs conceptually: Search, Cabinet and Plain
* view are three ways of looking, and this cluster is the instrument tray.
*
* QUIET LIKE THE GROUND CONTROL, not a pill. Plain view takes the pill because it
* changes what the page IS; this only goes somewhere. It is also the only real LINK
* of the three, so a hairline under it is the honest treatment rather than a
* borrowed one — and the loupe is what tells it apart from the word beside it.
*
* IT IS DRAWN, NOT WRITTEN. A botanist's folding pocket lens: a teardrop case and a
* smaller lens ring, both pinned at the same rivet and swung apart. Sixteen candidates
* were rendered at 16 to 90px and compared, which is the lesson favicon.svg already
* paid for twice — a mark that looks good large can die small. Three findings, each
* from looking rather than reasoning:
*
* · TWO OVERLAPPING OUTLINES GO MUDDY below about 20px. So each part is filled with
* the paper and occludes what is behind it rather than crossing it.
* · THEY HAVE TO SHARE THE PIN or they are not hinged, they are stacked. The first
* draft had a plain ring beside the case with nothing reaching up to the rivet,
* and it read as two shapes that happened to touch. Both parts are teardrops with
* their apex AT the rivet now, rotated apart about that one point.
* · TWO EQUAL LOBES READ AS A WISHBONE. The case is the fatter of the two and the
* lens ring is smaller, as they are in the hand; that asymmetry is the whole
* difference between an instrument and a pair of prongs.
*
* The word carries the meaning regardless. The drawing only has to be handsome, and
* unmistakably a thing a botanist would have in a pocket. */
.qe-search-link {
display: inline-flex;