Repository navigation
Expand file tree
/
Copy pathstyle.css
More file actions
1050 lines (925 loc) · 35.9 KB
/
Copy pathstyle.css
File metadata and controls
1050 lines (925 loc) · 35.9 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
/*
Theme Name: Aviendha
Theme URI: https://imagewize.com/themes/aviendha
Author: Jasper Frumau
Author URI: https://imagewize.com
Description: Aviendha is a lean full-site-editing starter theme for WordPress. It ships a design system (theme.json), WooCommerce block templates, and style variations — no theme-level patterns. Content is composed directly from blocks. Built to be forked and customized, similar to Sage in classic theming.
Requires at least: 6.6
Tested up to: 7.1
Requires PHP: 8.0
Version: 1.18.4
License: GNU General Public License v3 or later
License URI: https://www.gnu.org/licenses/gpl-3.0.html
Text Domain: aviendha
Tags: e-commerce, full-site-editing, custom-colors, custom-logo, custom-menu, editor-style, featured-images, grid-layout, template-editing, translation-ready, wide-blocks
Aviendha WordPress Theme, (C) 2026 Jasper Frumau
Aviendha is distributed under the terms of the GNU GPL v3 (or later).
*/
/*
* The design system lives in theme.json — this file only holds what
* theme.json cannot express: sticky positioning, pseudo-classes, media
* queries, and overrides of core block styles that ship `!important`.
*
* 1. Template parts (global)
* 2. Header
* 2.1 Sticky masthead
* 2.2 Scroll edge (light header)
* 2.3 Wordmark and logo
* 2.4 CTA button
* 2.5 Navigation underline
* 2.6 Overlay navigation
* 2.7 Account icon
* 3. Footer
* 4. Utilities
* 4.1 Eyebrow
* 5. Content rhythm
* 6. Single post
* 6.1 Post meta line
* 6.2 Two-column article and sticky sidebar
* 6.3 Prose
* 6.4 Post tail and author card
* 6.5 Sidebar widgets
* 6.6 Related posts
* 6.7 Comments
* 6.8 Reading-progress bar
*/
/* -------------------------------------------------------------------------
* 1. Template parts (global)
* ------------------------------------------------------------------------- */
/*
* Core's `:where(.wp-site-blocks) > *` global style adds a 24px
* margin-block-start to every top-level block, including the
* wp-block-template-part wrapper WordPress injects around header/footer —
* not to the .aviendha-header--dark/.foot block inside it, so setting
* margin on those directly has no effect on the wrapper. Reset it for all
* template parts generally (same fix as Imagewize's Elayne theme uses),
* since no template part should carry the inter-block content gap.
*/
.wp-site-blocks > .wp-block-template-part {
margin-block-start: 0;
}
/*
* Pin the footer to the bottom on short pages, where it would otherwise float
* mid-viewport with dead space beneath it.
*
* Safe to make `.wp-site-blocks` a flex column: its children stretch to full
* width by default, so the constrained-layout margins that produce alignwide
* and alignfull still resolve against the same box they did before.
*/
.wp-site-blocks {
display: flex;
flex-direction: column;
min-height: 100vh;
}
/*
* `main` takes up the slack. Its background is transparent, so on an ordinary
* prose page the stretch is indistinguishable from the content area around it —
* base on base, nothing to see.
*/
.wp-site-blocks > main {
flex: 1 0 auto;
}
/*
* The WooCommerce coming-soon template wraps its `main` in the block's own
* `.wp-block-woocommerce-coming-soon` div, so `main` is no longer a direct child
* of `.wp-site-blocks` and the rule above cannot reach it. The wrapper is the
* direct child instead, and — with no background of its own — it stands in for
* `main` here: growing it stretches base on base, invisibly, and the footer
* still settles at the bottom on a short page.
*/
.wp-site-blocks > .wp-block-woocommerce-coming-soon {
flex: 1 0 auto;
}
/*
* Unless the page ends in a full-bleed section, where that same transparent
* stretch reads as a base-coloured strip below the section's own colour. Then
* the section itself should absorb the space instead, so its background simply
* continues to the footer.
*
* Growing the footer rather than `main` was the other way to hide the strip, but
* it is the same region either way — only the colour changes — and a viewport's
* worth of it in the footer's tertiary reads as an enormous footer on a short
* page (622px of it on the Sample Page). Absorbing the space is what removes it.
*
* Scoped with `:has()` rather than applied to every page for two reasons: `float`
* is ignored on flex items, so an `alignleft`/`alignright` image inside
* `entry-content` would stop wrapping its text — a real cost on prose pages, and
* one they get nothing back for, since their filler is already invisible. Pages
* that end in an `alignfull` section are section-built and do not float. Where
* `:has()` is unsupported the chain simply never engages and the base-coloured
* strip comes back, which is the unstyled behaviour anyway.
*/
.wp-site-blocks > main:has(> .entry-content > :last-child.alignfull),
.wp-site-blocks > main:has(> .entry-content > :last-child.alignfull) > .entry-content {
display: flex;
flex-direction: column;
}
.wp-site-blocks > main:has(> .entry-content > :last-child.alignfull) > .entry-content,
.wp-site-blocks > main:has(> .entry-content > :last-child.alignfull) > .entry-content > :last-child {
flex: 1 0 auto;
}
/* -------------------------------------------------------------------------
* 2. Header
* ------------------------------------------------------------------------- */
/* 2.1 Sticky masthead
* ------------------------------------------------------------------------- */
/*
* Both variants stick. The rules below are scoped to `.aviendha-header` rather
* than `.aviendha-header--dark` wherever they are tonal-neutral, so the light
* header is a colour alternative rather than a header with features missing.
*/
.aviendha-header {
position: sticky;
top: 0;
z-index: 50;
}
/*
* When the header part renders inside a wrapper element (template-part
* `tagName`, or the block editor's part boundary), the wrapper is only as
* tall as the header itself, so a sticky child has no scroll range to move
* within and never sticks. Make the wrapper the sticky element in that case.
*/
.wp-block-template-part:has(> .aviendha-header) {
position: sticky;
top: 0;
z-index: 50;
}
/* 2.2 Scroll edge (light header)
* ------------------------------------------------------------------------- */
/*
* The light header sits on `base` and so does the page under it, so a resting
* border has no tonal change to describe — it reads as a scratch rather than a
* boundary. Instead the edge appears only once the page has moved, when the
* sticky masthead genuinely is above something.
*
* Done with a scroll-driven animation rather than a scroll listener because the
* theme ships no JavaScript. Where `scroll()` is unsupported the header simply
* stays flush, which is the rest state we are choosing anyway — so no fallback
* is needed. The dark header is excluded: it carries its own light hairline in
* the block markup, and a `border-light` shadow under it would read as a seam.
*
* The colours are literal because a keyframe needs the transparent stop to be
* the same colour at zero alpha: `#e5ded2` is `border-light`, `#211c1a` is
* `contrast`. Same hex-with-alpha idiom the dark header's border uses.
*/
@supports (animation-timeline: scroll()) {
.aviendha-header:not(.aviendha-header--dark) {
animation: aviendha-header-edge linear both;
animation-range: 0 8px;
animation-timeline: scroll(root block);
}
}
@keyframes aviendha-header-edge {
from {
box-shadow:
0 1px 0 0 #e5ded200,
0 8px 24px -18px #211c1a00;
}
to {
box-shadow:
0 1px 0 0 #e5ded2,
0 8px 24px -18px #211c1a80;
}
}
/* 2.3 Wordmark and logo
* ------------------------------------------------------------------------- */
.aviendha-header .wp-block-site-title a {
font-family: var(--wp--preset--font-family--display);
font-weight: 800;
font-size: 1.15rem;
letter-spacing: -0.03em;
text-decoration: none;
}
.aviendha-header .wp-block-site-title a:hover {
text-decoration: none;
}
/* For the Aviendha marketing site: hide logo when using text wordmark */
body .aviendha-header--dark .wp-block-site-logo {
display: none;
}
/* 2.4 CTA button
* ------------------------------------------------------------------------- */
/*
* Shape and type are shared; colour is not. The light header uses the filled
* `primary` button straight from theme.json (`styles.elements.button`), so it
* needs no colour rules here at all — including hover, which theme.json already
* takes to `primary-alt`. Only the dark header's outline treatment is below.
*/
.aviendha-header__cta .wp-block-button__link {
font-family: var(--wp--preset--font-family--mono);
font-size: var(--wp--preset--font-size--x-small);
font-weight: 600;
letter-spacing: 0.04em;
padding: 0.5rem 0.9rem;
border-radius: 999px;
white-space: nowrap;
transition: background-color 0.18s, border-color 0.18s, color 0.18s;
}
/*
* Drop the CTA below 600px, where the wordmark, the hamburger and the two icons
* leave less than the button's ~150px and it runs off the right edge. Above that
* it always has room — §2.7 keeps the navigation collapsed until 1024px, and by
* the time the menu goes inline the row is wide enough for both.
*
* The `.wp-block-buttons >` part is load-bearing, not decoration: core emits
* `.wp-block-buttons > .wp-block-button { display: inline-block }`, and a lone
* class selector here loses to it and leaves the button visible.
*/
@media (max-width: 599px) {
.aviendha-header .wp-block-buttons > .aviendha-header__cta {
display: none;
}
}
/* 2.5 Navigation underline
* ------------------------------------------------------------------------- */
/*
* Wipe-in underline on hover, held open for the current page. `currentColor`
* rather than `primary` so the same rule serves both headers — primary against
* the dark header's `main` background is too low-contrast to read as a marker.
*
* Hooked on `[aria-current="page"]`, which core puts on the link itself, rather
* than the `.current-menu-item` class it puts on the `li`. Scoped to the
* top-level container so submenu items do not pick it up.
*/
.aviendha-header .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content {
position: relative;
text-decoration: none;
}
.aviendha-header .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content::after {
background: currentColor;
bottom: -0.25em;
content: "";
height: 2px;
left: 0;
position: absolute;
right: 0;
transform: scaleX(0);
transform-origin: left;
transition: transform 0.16s ease;
}
.aviendha-header .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content:hover::after,
.aviendha-header .wp-block-navigation__container > .wp-block-navigation-item > .wp-block-navigation-item__content[aria-current="page"]::after {
transform: scaleX(1);
}
/*
* The mobile overlay stacks the same links full-width, where an underline
* spanning the whole row reads as a divider rather than a marker.
*/
.aviendha-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation-item__content::after {
content: none;
}
.aviendha-header--dark .aviendha-header__cta .wp-block-button__link {
border-color: rgb(250 247 242 / 0.3);
}
.aviendha-header--dark .aviendha-header__cta .wp-block-button__link:hover {
background-color: var(--wp--preset--color--base);
/* !important needed: the saved button markup carries has-base-color,
* and core emits `.has-base-color { color: ... !important }` — a plain
* override here loses to that, leaving white text on the white hover
* background. */
color: var(--wp--preset--color--main) !important;
border-color: var(--wp--preset--color--base);
}
/* 2.6 Actions cluster order
* ------------------------------------------------------------------------- */
/*
* `.aviendha-header__actions` (parts/header.html, parts/header-dark.html)
* holds the icon/CTA group and the navigation block in that source order, so
* the hamburger renders last — rightmost, with the CTA immediately before
* it — which is what a collapsed header (below 1024px, see §2.7) wants.
*
* Once the navigation goes inline at 1024px+, that same order would put the
* link row after the icons and CTA, which reads backwards for a desktop
* masthead — so only there, pull it back in front with `order`.
*/
@media (min-width: 1024px) {
.aviendha-header__actions .wp-block-navigation {
order: -1;
}
}
/* 2.7 Overlay navigation
* ------------------------------------------------------------------------- */
/*
* Raise the overlay breakpoint from core's 600px to 1024px.
*
* `overlayMenu: "mobile"` only takes the three keywords, so the width at which
* the navigation collapses is not configurable — core hardcodes it in two rules
* inside `@media (min-width: 600px)`: one flips `.wp-block-navigation__responsive-container`
* from the hidden fixed-position overlay to an inline block, the other hides the
* hamburger. Between 600px and 1024px that left the inline menu competing with
* the wordmark, the cart and account icons and the CTA, and the row wrapped — a
* 105px-tall masthead on a tablet.
*
* Restoring those two declarations to their base values across the band is the
* whole fix: everything else about the overlay, including the fixed positioning
* it needs when open, already lives outside the media query.
*
* 1024px rather than a rounder 960px because the masthead's own contents decide
* it: this menu's six items plus the wordmark, icons and CTA measure 973px, so
* at 960px the row still wrapped. A longer menu would want this raised again.
*/
@media (min-width: 600px) and (max-width: 1023px) {
.aviendha-header .wp-block-navigation__responsive-container:not(.hidden-by-default):not(.is-menu-open) {
display: none;
}
.aviendha-header .wp-block-navigation__responsive-container-open:not(.always-shown) {
display: flex;
}
}
/*
* Core shrink-wraps the overlay's link list to its own content width, then
* right-aligns that shrink-wrapped box against the modal's already-padded
* edge (`align-items: flex-end` on the container-content, matching the
* collapsed hamburger's own justification) — the same edge inset the close
* button sits inside. Right-anchoring a shrink-wrapped box that way is
* fragile: anything that widens the list past its measured content width
* (a longer translated label, a larger accessibility text-size setting)
* pushes its edge past the modal boundary with no margin to absorb it, and
* the link reads as clipped against the screen edge.
*
* Stretch the list to the full padded content width instead, then
* right-align each link's own text inside that guaranteed box. The list can
* no longer be wider than the box it's aligned within, so its edge — and
* the close button's — stay pinned to the same padded inset regardless of
* label length.
*/
.aviendha-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__responsive-container-content {
align-items: stretch;
}
.aviendha-header .wp-block-navigation__responsive-container.is-menu-open .wp-block-navigation__container {
text-align: right;
}
/*
* Core insets the overlay (and, with it, the close button pinned to its
* top-right corner) from the screen edge via the `--wp--style--root--padding-*`
* custom properties that `settings.useRootPaddingAwareAlignments` is meant to
* supply. Here they resolve to nothing usable, so the overlay's own padding
* collapses to 0 and the close button lands flush against the literal
* top-right corner of the screen — well above and outside of where the
* hamburger it replaces actually sits.
*
* Give the overlay the header's own padding directly instead of relying on
* that chain, so the close button opens right where the hamburger was. This
* also becomes the right-hand inset the link list (§ above) stretches
* against, keeping both edges aligned.
*/
.aviendha-header .wp-block-navigation__responsive-container.is-menu-open {
padding-top: var(--wp--preset--spacing--small);
padding-right: var(--wp--preset--spacing--small);
}
/*
* The dark header's navigation has no background of its own, so core's
* `.wp-block-navigation:not(.has-background) …is-menu-open` rule paints the
* mobile overlay white — while the block's `textColor: "base"` keeps the
* links and close button white too, leaving the open menu unreadable.
*
* Scoped to `.is-menu-open`: with `overlayMenu: "mobile"` the container
* carries no `hidden-by-default` class, so above 600px core reuses that same
* element to render the inline desktop nav. An unscoped rule here would
* darken those desktop links against the dark masthead.
*
* !important needed: the navigation markup carries has-base-color, and core
* emits `.has-base-color { color: ... !important }`.
*/
.aviendha-header--dark .wp-block-navigation__responsive-container.is-menu-open,
.aviendha-header--dark .wp-block-navigation__responsive-container.is-menu-open * {
color: var(--wp--preset--color--main) !important;
}
/* 2.8 Account icon
* ------------------------------------------------------------------------- */
/*
* The customer-account block renders as a link, so it picks up the global
* `primary` link colour — rose, which is too low-contrast on the dark header's
* `main` background and reads as a different element from the mini cart beside
* it. Inherit the surrounding header text colour instead, so the account icon
* follows the cart in both headers: `base` on the dark header, `contrast` on
* the light one. The icon's SVG paints in `currentColor`, so it comes along.
*/
.aviendha-header .wp-block-woocommerce-customer-account a {
color: inherit;
}
/*
* Size the account icon. WooCommerce ships its sizing rule against
* `.wc-block-customer-account__account-icon`, but the block actually renders
* the SVG with `class="icon"` (its `iconClass` default) — the two never match,
* so the icon collapses to zero and is invisible in every display mode. Give
* it an explicit size here; the `:not()` leaves the dropdown caret, which
* carries its own dimensions, alone. `em` so it tracks the header font size,
* matching WooCommerce's intended 1.5em.
*/
.aviendha-header .wp-block-woocommerce-customer-account svg:not(.wc-block-customer-account__caret) {
height: 1.5em;
width: 1.5em;
}
/* -------------------------------------------------------------------------
* 3. Footer
* ------------------------------------------------------------------------- */
/* Match redesign mockup */
.foot {
background-color: var(--wp--preset--color--tertiary);
}
.foot .shell {
display: flex;
flex-wrap: wrap;
gap: 1.5rem;
justify-content: space-between;
align-items: center;
font-size: 0.85rem;
color: var(--wp--preset--color--secondary);
}
.foot .wp-block-navigation {
margin: 0;
padding: 0;
}
.foot .wp-block-navigation__container {
margin: 0;
padding: 0;
list-style: none;
}
.foot .wp-block-navigation-item {
margin: 0;
padding: 0;
}
.foot a {
text-decoration: none;
}
.foot a:hover {
color: var(--wp--preset--color--primary);
}
/* 3.1 Mobile footer layout
* ------------------------------------------------------------------------- */
/*
* The footer navigation never collapses into a hamburger — the block itself
* sets `overlayMenu: "never"` (see parts/footer.html), so core renders a plain
* list at every width and emits no overlay markup. All that's left to do here
* is stack the footer on narrow screens.
*/
@media (max-width: 600px) {
.foot .shell {
flex-direction: column;
align-items: flex-start;
gap: 1rem;
}
/*
* With no assigned menu the nav falls back to a page list, which core nests
* as `__container > .wp-block-page-list > li` — so both levels need to
* stack, not just the outer container.
*
* align-items is required too: core defaults `--navigation-layout-align` to
* `center` for a row, and once the direction flips to column that variable
* governs the horizontal axis, centering each link inside the nav's
* shrink-to-fit width instead of aligning them left.
*/
.foot .wp-block-navigation__container,
.foot .wp-block-navigation .wp-block-page-list {
align-items: flex-start;
flex-direction: column;
gap: 0.5rem;
width: 100%;
}
}
/* -------------------------------------------------------------------------
* 4. Utilities
* ------------------------------------------------------------------------- */
/* 4.1 Eyebrow
* ------------------------------------------------------------------------- */
/*
* The theme's one repeated structural device: a mono, letter-spaced label
* introduced by a short rule. Add it as a class on any block that carries a
* short piece of text — a paragraph, a post-terms block — to mark a section
* without spending a heading on it.
*
* theme.json can't express it: the leading rule is a pseudo-element, and the
* class has to be available to arbitrary blocks rather than to one block type.
*/
.aviendha-eyebrow {
align-items: baseline;
color: var(--wp--preset--color--main-accent);
display: flex;
font-family: var(--wp--preset--font-family--mono);
font-size: var(--wp--preset--font-size--xx-small);
font-weight: 600;
gap: 0.6rem;
letter-spacing: 0.14em;
line-height: 1.4;
text-transform: uppercase;
}
.aviendha-eyebrow::before {
background: currentColor;
content: "";
flex: none;
height: 1px;
translate: 0 -0.28em;
width: 1.5rem;
}
.aviendha-eyebrow a {
color: inherit;
text-decoration: none;
}
.aviendha-eyebrow a:hover {
color: var(--wp--preset--color--primary);
}
/* -------------------------------------------------------------------------
* 5. Content rhythm
* ------------------------------------------------------------------------- */
/*
* theme.json sets the global `blockGap` that separates blocks, and an `h2` top
* margin that opens a section up. What it cannot express is the other half of
* the pairing — a heading should sit *close* to the block it introduces, which
* needs a sibling selector.
*
* Without this the full block gap lands between a heading and its own first
* paragraph, and the heading reads as belonging to the text above it.
*/
.entry-content :is(h2, h3, h4, h5, h6) + * {
margin-block-start: var(--wp--preset--spacing--small);
}
/* -------------------------------------------------------------------------
* 6. Single post
*
* All scoped to the `.single` body class core adds on single posts, so none
* of it leaks onto pages or archives. Layout primitives (the sticky sidebar,
* the two-column collapse) and pseudo-elements live here because theme.json
* cannot express them; colours and type reference the presets as everywhere
* else.
* ------------------------------------------------------------------------- */
/* 6.1 Post meta line
* ------------------------------------------------------------------------- */
/*
* A mono, letter-spaced byline under the title: avatar, author, date. Built
* from core blocks (avatar / post-author-name / post-date) rather than one
* block, so each piece can be styled and a reading-time block can slot in
* later without disturbing the rest.
*/
.aviendha-post-meta {
color: var(--wp--preset--color--main-accent);
font-family: var(--wp--preset--font-family--mono);
gap: 0.55rem;
letter-spacing: 0.08em;
text-transform: uppercase;
}
.aviendha-post-meta .wp-block-avatar {
line-height: 0;
}
.aviendha-post-meta .wp-block-avatar img {
border-radius: 999px;
}
/* "By" reads muted (inherits the block colour); the name link takes contrast. */
.aviendha-post-meta .wp-block-post-author-name::before {
content: "By ";
}
.aviendha-post-meta .wp-block-post-author-name a {
color: var(--wp--preset--color--contrast);
font-weight: 600;
text-decoration: none;
}
/* A hairline dot separates the date from the author; the flex gap does the spacing. */
.aviendha-post-meta .wp-block-post-date::before {
color: var(--wp--preset--color--sand-deep);
content: "·";
padding-right: 0.55rem;
}
.aviendha-post-meta .wp-block-post-date a,
.aviendha-post-meta .wp-block-post-date time {
color: inherit;
text-decoration: none;
}
/* The lede under the title: colour and size come from the block; cap the measure. */
.aviendha-post-lede {
max-width: 56ch;
}
/* 6.2 Two-column article and sticky sidebar
* ------------------------------------------------------------------------- */
/*
* The content column has no width (it grows); the sidebar column is a fixed
* 300px. Two columns that both carry a percentage summing to 100% wrap onto
* two rows once the column gap is added, so the grow-plus-fixed pairing is
* what keeps them on one row.
*
* Sticky is not a core group support, so the inner sidebar group carries a
* class and the positioning lives here. The offset clears the sticky masthead
* (~66px) plus a little breathing room.
*/
.single .aviendha-sidebar__sticky {
position: sticky;
top: 5.5rem;
}
/*
* Collapse to one column below 980px — earlier than core's own 782px column
* stacking, because the 300px sidebar beside a shrinking content column gets
* cramped before then. Once stacked, the sidebar drops its sticky behaviour
* (nothing to stick against in a single column) and sits below the article.
*/
@media (max-width: 980px) {
.single .aviendha-article > .wp-block-column {
flex-basis: 100%;
}
.single .aviendha-sidebar__sticky {
position: static;
}
}
/* 6.3 Prose
* ------------------------------------------------------------------------- */
/*
* theme.json and §5 handle block rhythm; these are the post-body flourishes
* that need element or pseudo selectors: a display-face pull quote, primary
* list markers, and a drop cap on a post that opens with a paragraph.
*/
.single .entry-content blockquote {
border-left: 3px solid var(--wp--preset--color--primary);
font-family: var(--wp--preset--font-family--display);
font-size: var(--wp--preset--font-size--large);
font-weight: 500;
letter-spacing: -0.02em;
line-height: 1.3;
margin-inline: 0;
padding: var(--wp--preset--spacing--small) 0 var(--wp--preset--spacing--small) var(--wp--preset--spacing--medium);
}
.single .entry-content li::marker {
color: var(--wp--preset--color--primary);
}
/*
* Drop cap only when the very first child is a paragraph — `:first-child`
* rather than `:first-of-type`, so a post opening with a heading, list or
* image is left alone rather than having a paragraph further down capitalised.
*/
.single .entry-content > p:first-child::first-letter {
color: var(--wp--preset--color--primary);
float: left;
font-family: var(--wp--preset--font-family--display);
font-size: 3.1em;
font-weight: 700;
line-height: 0.78;
padding: 0.06em 0.12em 0 0;
}
/* 6.4 Post tail and author card
* ------------------------------------------------------------------------- */
/* Tags render as mono outline pills (post-terms with an empty separator). */
.single .aviendha-tags {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.single .aviendha-tags a {
border: 1px solid var(--wp--preset--color--border-light);
border-radius: 999px;
color: var(--wp--preset--color--secondary);
font-family: var(--wp--preset--font-family--mono);
font-size: var(--wp--preset--font-size--xx-small);
letter-spacing: 0.06em;
padding: 0.35em 0.7em;
text-decoration: none;
transition: border-color 0.14s, color 0.14s;
}
.single .aviendha-tags a:hover {
border-color: var(--wp--preset--color--primary);
color: var(--wp--preset--color--primary);
}
/* The author card is core/post-author; background/padding/radius are block attrs. */
.single .aviendha-author-card {
align-items: flex-start;
display: flex;
gap: var(--wp--preset--spacing--small);
}
.single .aviendha-author-card .wp-block-post-author__avatar img {
border-radius: 999px;
}
.single .aviendha-author-card .wp-block-post-author__byline {
color: var(--wp--preset--color--main-accent);
font-family: var(--wp--preset--font-family--mono);
font-size: var(--wp--preset--font-size--xx-small);
letter-spacing: 0.1em;
margin: 0;
text-transform: uppercase;
}
.single .aviendha-author-card .wp-block-post-author__name {
font-family: var(--wp--preset--font-family--display);
font-size: var(--wp--preset--font-size--medium);
font-weight: 600;
margin: 0.15em 0 0.3em;
}
.single .aviendha-author-card .wp-block-post-author__bio {
color: var(--wp--preset--color--secondary);
font-size: var(--wp--preset--font-size--small);
margin: 0;
}
/* 6.5 Sidebar widgets
* ------------------------------------------------------------------------- */
/* A mono label with a hairline under it, distinct from the display headings. */
.single .aviendha-widget-title {
border-bottom: 1px solid var(--wp--preset--color--border-light);
color: var(--wp--preset--color--main-accent);
font-family: var(--wp--preset--font-family--mono);
font-weight: 600;
letter-spacing: 0.14em;
margin-bottom: var(--wp--preset--spacing--small);
padding-bottom: var(--wp--preset--spacing--2-x-small);
text-transform: uppercase;
}
/* Recent (core/latest-posts) — title over a mono date, hairline between items. */
.single .aviendha-mini-posts {
list-style: none;
margin: 0;
padding-left: 0;
}
.single .aviendha-mini-posts li {
border-bottom: 1px solid var(--wp--preset--color--border-light);
padding-block: var(--wp--preset--spacing--x-small);
}
.single .aviendha-mini-posts li:last-child {
border-bottom: 0;
}
.single .aviendha-mini-posts a {
color: var(--wp--preset--color--contrast);
display: block;
font-size: var(--wp--preset--font-size--small);
font-weight: 500;
line-height: 1.3;
text-decoration: none;
}
.single .aviendha-mini-posts a:hover {
color: var(--wp--preset--color--primary);
}
.single .aviendha-mini-posts .wp-block-latest-posts__post-date {
color: var(--wp--preset--color--main-accent);
display: block;
font-family: var(--wp--preset--font-family--mono);
font-size: var(--wp--preset--font-size--xx-small);
letter-spacing: 0.06em;
margin-top: 0.15em;
}
/* Topics (core/categories) — a plain hairline-separated list. */
.single .aviendha-topics {
list-style: none;
margin: 0;
padding-left: 0;
}
.single .aviendha-topics li {
border-bottom: 1px solid var(--wp--preset--color--border-light);
padding-block: 0.3rem;
}
.single .aviendha-topics li:last-child {
border-bottom: 0;
}
.single .aviendha-topics a {
color: var(--wp--preset--color--secondary);
font-size: var(--wp--preset--font-size--small);
text-decoration: none;
}
.single .aviendha-topics a:hover {
color: var(--wp--preset--color--primary);
}
/*
* Sidebar CTA button: base on main, inverting the theme.json primary button.
* The named-colour classes core emits carry `!important`, so the hover has to
* as well to win — same idiom the dark header's CTA hover uses (§2.5).
*/
.single .aviendha-aside-cta .wp-block-button__link:hover {
background-color: var(--wp--preset--color--white) !important;
color: var(--wp--preset--color--main) !important;
}
/* 6.6 Related posts
* ------------------------------------------------------------------------- */
/*
* The query loop renders a grid of <li> cards. The featured image sits flush
* to the card's top edge (card `overflow: hidden` clips it to the radius); the
* text blocks carry their own inline padding. A card without a featured image
* keeps its top spacing from the eyebrow's own top margin, so both cases read.
*/
.single .aviendha-related__grid .wp-block-post-template > li {
background: var(--wp--preset--color--base);
border: 1px solid var(--wp--preset--color--border-light);
border-radius: var(--wp--preset--border-radius--lg);
overflow: hidden;
padding-bottom: var(--wp--preset--spacing--medium);
transition: transform 0.16s, box-shadow 0.16s, border-color 0.16s;
}
.single .aviendha-related__grid .wp-block-post-template > li:hover {
border-color: var(--wp--preset--color--sand-deep);
box-shadow: 0 16px 32px -22px rgb(33 28 26 / 0.55);
transform: translateY(-3px);
}
.single .aviendha-related__grid .wp-block-post-featured-image {
margin: 0;
}
.single .aviendha-related__grid .wp-block-post-featured-image img {
aspect-ratio: 16 / 10;
border-radius: 0;
object-fit: cover;
width: 100%;
}
.single .aviendha-related__grid :is(.wp-block-post-terms, .wp-block-post-title, .wp-block-post-excerpt) {
padding-inline: var(--wp--preset--spacing--medium);
}
/* 6.7 Comments
* ------------------------------------------------------------------------- */
.single .aviendha-comments .wp-block-comment-template {
list-style: none;
margin-top: var(--wp--preset--spacing--large);
padding-left: 0;
}
.single .aviendha-comments .wp-block-comment-template > li {
border-bottom: 1px solid var(--wp--preset--color--border-light);
padding-block: var(--wp--preset--spacing--medium);
}
.single .aviendha-comments .wp-block-avatar img {
border-radius: 999px;
}
.single .aviendha-comment__meta {
gap: 0.6rem;
}
.single .aviendha-comment__meta .wp-block-comment-author-name {
font-family: var(--wp--preset--font-family--display);
font-weight: 600;
}
.single .aviendha-comment__meta .wp-block-comment-author-name a {
text-decoration: none;
}
.single .aviendha-comment__meta .wp-block-comment-date,
.single .aviendha-comment__meta .wp-block-comment-date a {
color: var(--wp--preset--color--main-accent);
font-family: var(--wp--preset--font-family--mono);
font-size: var(--wp--preset--font-size--xx-small);
letter-spacing: 0.06em;
text-decoration: none;
}
/*
* Comment form. Core renders the browser-default field: a white box with a
* sharp grey border, which reads as a foreign element on the cream page. Put
* the fields on `base` with a hairline border and the theme radius, and give
* their labels the same mono treatment the sidebar widgets and meta line use,
* so the form belongs to the design rather than the browser.
*/
.single .aviendha-comments .comment-form label {
color: var(--wp--preset--color--main-accent);
display: block;
font-family: var(--wp--preset--font-family--mono);
font-size: var(--wp--preset--font-size--xx-small);
letter-spacing: 0.1em;
margin-bottom: var(--wp--preset--spacing--2-x-small);
text-transform: uppercase;
}
.single .aviendha-comments .comment-form :is(textarea, input[type="text"], input[type="email"], input[type="url"]) {
background: var(--wp--preset--color--base);
border: 1px solid var(--wp--custom--color--control-border);
border-radius: var(--wp--preset--border-radius--md);
/* Keep padding and border inside the 100% width. Core's comments-form
block styles already set this, but without it the fields would overflow
the column on phones, as the product review form's did. */
box-sizing: border-box;
color: var(--wp--preset--color--contrast);
font-family: var(--wp--preset--font-family--primary);
font-size: var(--wp--preset--font-size--base);
padding: 0.75em 0.9em;
width: 100%;
}
.single .aviendha-comments .comment-form textarea {
min-height: 130px;
resize: vertical;
}