mykiwi/mykiwi.blogpublic Fork 0
bf3cf90170888299b6939d18c034327377a52922
Commits
Clone
git clone https://git.rickub.com/mykiwi/mykiwi.blog.git
git clone ssh://git@rickub.com/mykiwi/mykiwi.blog.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

style.scss · 1530 lines · 28.4 KBSCSS Blame HistoryRaw
Port fzakaria.com design to Hugo and add a homepage profile 1bdbd06 Romain Gautier yesterday1// ---------------------------------------------------------------------------
2// mykiwi.blog — core design ported from fzakaria.com (MIT-licensed).
3// Prose in Newsreader, structural chrome in JetBrains Mono, warm paper/ink
4// palette with a dark-mode swap. Personal-only sections (bio colophon,
5// readership/talks pages, WordPress archive) were left out.
6// ---------------------------------------------------------------------------
7
8@use "sass:list";
9
10$wide: 67.5625rem;
11
12%chrome {
13 font-family: var(--mono);
14 font-size: 0.72rem;
15 font-weight: 500;
16 letter-spacing: 0.11em;
17 text-transform: uppercase;
18 font-variant-numeric: tabular-nums;
19 color: var(--ink-faint);
20}
21
22// --- Fonts -----------------------------------------------------------------
23
24@font-face {
25 font-family: "Newsreader";
26 font-style: normal;
27 font-weight: 400 700;
28 font-display: swap;
29 src: url("/fonts/Newsreader-latin.woff2") format("woff2");
30 unicode-range:
31 u+0000-00ff, u+0131, u+0152-0153, u+02bb-02bc, u+02c6, u+02da, u+02dc,
32 u+0304, u+0308, u+0329, u+2000-206f, u+20ac, u+2122, u+2191, u+2193, u+2212,
33 u+2215, u+feff, u+fffd;
34}
35
36@font-face {
37 font-family: "Newsreader";
38 font-style: normal;
39 font-weight: 400 700;
40 font-display: swap;
41 src: url("/fonts/Newsreader-latin-ext.woff2") format("woff2");
42 unicode-range:
43 u+0100-02ba, u+02bd-02c5, u+02c7-02cc, u+02ce-02d7, u+02dd-02ff, u+0304,
44 u+0308, u+0329, u+1d00-1dbf, u+1e00-1e9f, u+1ef2-1eff, u+2020, u+20a0-20ab,
45 u+20ad-20c0, u+2113, u+2c60-2c7f, u+a720-a7ff;
46}
47
48@font-face {
49 font-family: "Newsreader";
50 font-style: italic;
51 font-weight: 400 700;
52 font-display: swap;
53 src: url("/fonts/Newsreader-italic-latin.woff2") format("woff2");
54 unicode-range:
55 u+0000-00ff, u+0131, u+0152-0153, u+02bb-02bc, u+02c6, u+02da, u+02dc,
56 u+0304, u+0308, u+0329, u+2000-206f, u+20ac, u+2122, u+2191, u+2193, u+2212,
57 u+2215, u+feff, u+fffd;
58}
59
60@font-face {
61 font-family: "Newsreader";
62 font-style: italic;
63 font-weight: 400 700;
64 font-display: swap;
65 src: url("/fonts/Newsreader-italic-latin-ext.woff2") format("woff2");
66 unicode-range:
67 u+0100-02ba, u+02bd-02c5, u+02c7-02cc, u+02ce-02d7, u+02dd-02ff, u+0304,
68 u+0308, u+0329, u+1d00-1dbf, u+1e00-1e9f, u+1ef2-1eff, u+2020, u+20a0-20ab,
69 u+20ad-20c0, u+2113, u+2c60-2c7f, u+a720-a7ff;
70}
71
72@font-face {
73 font-family: "JetBrains Mono";
74 font-style: normal;
75 font-weight: 400;
76 font-display: swap;
77 src: url("/fonts/JetBrainsMono-Regular.woff2") format("woff2");
78}
79
80// --- Tokens ------------------------------------------------------------
81
82:root {
83 --serif:
84 "Newsreader", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia,
85 "Times New Roman", serif;
86 --mono:
87 "JetBrains Mono", ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo,
88 Consolas, "Liberation Mono", monospace;
89
90 --paper: #f5f2ec;
91 --paper-raised: #ebe6da;
92 --ink: #1a1815;
93 --ink-muted: #565046;
94 --ink-faint: #6f685b;
95 --rule: #dcd5c5;
96 --rule-strong: #c2b9a6;
97 --accent: #9e3413;
98 --accent-wash: #9e34131f;
99 --glow: #fffdf6;
100 --image-mat: #ebe6da;
101
102 --measure: 36rem;
103 --gutter: 0rem;
104 --gap: 0rem;
105 --margin-col: 0rem;
106 --pad: 1.5rem;
107
108 --root-max: 19.5px;
109 --step: 1.6rem;
110
111 color-scheme: light dark;
112}
113
114@media (prefers-color-scheme: dark) {
115 :root {
116 --paper: #15171a;
117 --paper-raised: #1d2025;
118 --ink: #ddd8cd;
119 --ink-muted: #9b958a;
120 --ink-faint: #8a8377;
121 --rule: #2b2f35;
122 --rule-strong: #3f454d;
123 --accent: #e08a45;
124 --accent-wash: #e08a4526;
125 --glow: #1f242b;
126 }
127}
128
129@media (min-width: $wide) {
130 :root {
131 --gutter: 4.5rem;
132 --gap: 2rem;
133 --margin-col: 13.5rem;
134 }
135}
136
137@media (min-width: 87.5rem) {
138 :root {
139 --gutter: 6rem;
140 --gap: 2.5rem;
141 --margin-col: 16rem;
142 }
143}
144
145@media (max-width: 34rem) {
146 :root {
147 --pad: 1.15rem;
148 --step: 1.35rem;
149 }
150}
151
152// --- Reset -----------------------------------------------------------------
153
154*,
155*::before,
156*::after {
157 box-sizing: border-box;
158}
159
160body,
161h1,
162h2,
163h3,
164h4,
165h5,
166h6,
167p,
168ul,
169ol,
170dl,
171dd,
172figure,
173blockquote,
174pre {
175 margin: 0;
176}
177
178html {
179 font-size: clamp(17px, 0.95rem + 0.2vw, var(--root-max));
180 -webkit-text-size-adjust: 100%;
181 scroll-behavior: smooth;
182}
183
184@media (prefers-reduced-motion: reduce) {
185 html {
186 scroll-behavior: auto;
187 }
188}
189
190body {
191 font-family: var(--serif);
192 font-weight: 400;
193 font-size: 1rem;
194 line-height: 1.62;
195 color: var(--ink);
196 background-color: var(--paper);
197 background-image: radial-gradient(
198 75rem 32rem at 14% -6%,
199 var(--glow) 0%,
200 transparent 68%
201 );
202 background-repeat: no-repeat;
203 text-rendering: optimizeLegibility;
204 -webkit-font-smoothing: antialiased;
205 min-height: 100vh;
206 overflow-wrap: break-word;
207}
208
209::selection {
210 background: var(--accent);
211 color: var(--paper);
212}
213
214// --- Layout ------------------------------------------------------------
215
216.wrap {
217 width: 100%;
218 max-width: calc(
219 var(--gutter) + var(--measure) + var(--gap) + var(--margin-col) + 2 *
220 var(--pad)
221 );
222 margin-inline: auto;
223 padding-inline: var(--pad);
224 padding-bottom: calc(var(--step) * 2);
225}
226
227.column {
228 max-width: var(--measure);
229 margin-left: var(--gutter);
230}
231
232.skip-link {
233 position: absolute;
234 left: -9999px;
235 top: 0;
236 padding: 0.5rem 0.9rem;
237 background: var(--accent);
238 color: var(--paper);
239 font-family: var(--mono);
240 font-size: 0.8rem;
241 z-index: 10;
242
243 &:focus {
244 left: 0.5rem;
245 top: 0.5rem;
246 }
247}
248
249:focus-visible {
250 outline: 2px solid var(--accent);
251 outline-offset: 3px;
252 border-radius: 1px;
253}
254
255.visually-hidden {
256 position: absolute;
257 width: 1px;
258 height: 1px;
259 margin: -1px;
260 padding: 0;
261 overflow: hidden;
262 clip-path: inset(50%);
263 white-space: nowrap;
264 border: 0;
265}
266
267// --- Masthead ----------------------------------------------------------
268
269.masthead {
270 padding-top: calc(var(--step) * 1.6);
271 padding-bottom: var(--step);
272 margin-bottom: calc(var(--step) * 1.4);
273 position: relative;
274 display: flex;
275 align-items: baseline;
276 justify-content: space-between;
277 gap: 0 1rem;
278
279 &__signal {
280 position: absolute;
281 left: 0;
282 right: 0;
283 bottom: 0;
284 height: 26px;
285 -webkit-mask-image: linear-gradient(
286 to right,
287 #000 0%,
288 #000 62%,
289 transparent 96%
290 );
291 mask-image: linear-gradient(to right, #000 0%, #000 62%, transparent 96%);
292
293 svg {
294 display: block;
295 width: 100%;
296 height: 100%;
297 }
298
299 path {
300 fill: none;
301 stroke: url("#signal-ramp");
302 stroke-width: 1.5;
303 stroke-linecap: round;
304 stroke-linejoin: round;
305 vector-effect: non-scaling-stroke;
306 }
307 }
308
309 .signal-ramp__lead {
310 stop-color: var(--accent);
311 }
312
313 .signal-ramp__body,
314 .signal-ramp__tail {
315 stop-color: var(--rule-strong);
316 }
317}
318
319.masthead__title {
320 font-size: 1.5rem;
321 font-weight: 600;
322 line-height: 1.1;
323 letter-spacing: -0.018em;
324
325 a {
326 color: inherit;
327 text-decoration: none;
328 }
329
330 a:hover {
331 color: var(--accent);
332 }
333}
334
335// Signpost to the colophon, shown only at widths where the colophon is
336// reordered below the post list and nothing on first screen hints it is
337// there. Turned on alongside that reorder, further down.
338.masthead__about {
339 @extend %chrome;
340 display: none;
341 flex: none;
342 color: var(--ink-muted);
343 text-decoration: none;
344 border-bottom: 1px solid var(--rule);
345
346 &:hover {
347 color: var(--accent);
348 border-bottom-color: var(--accent);
349 }
350}
351
352// --- Prose ---------------------------------------------------------------
353
354.prose {
355 > * + * {
356 margin-top: var(--step);
357 }
358
359 p,
360 ul,
361 ol,
362 dl {
363 line-height: 1.65;
364 }
365
366 div > * + *,
367 details > * + *,
368 li > * + *,
369 td > * + *,
370 th > * + * {
371 margin-top: 0.7rem;
372 }
373
374 h1,
375 h2,
376 h3,
377 h4,
378 h5,
379 h6 {
380 font-weight: 600;
381 line-height: 1.2;
382 letter-spacing: -0.012em;
383 margin-bottom: 0;
384 position: relative;
385 scroll-margin-top: 1.5rem;
386 }
387
388 :is(h1, h2, h3, h4, h5, h6) + :not(h1, h2, h3, h4, h5, h6) {
389 margin-top: 0.55rem;
390 }
391
392 :is(h1, h2, h3, h4, h5, h6) + :is(h1, h2, h3, h4, h5, h6) {
393 margin-top: calc(var(--step) * 1.1);
394 }
395
396 h1 {
397 font-size: 1.62rem;
398 margin-top: calc(var(--step) * 2);
399 }
400 h2 {
401 font-size: 1.4rem;
402 margin-top: calc(var(--step) * 1.7);
403 }
404 h3 {
405 font-size: 1.18rem;
406 margin-top: calc(var(--step) * 1.35);
407 }
408 h4,
409 h5,
410 h6 {
411 font-size: 1rem;
412 font-family: var(--mono);
413 font-weight: 600;
414 letter-spacing: 0.02em;
415 margin-top: calc(var(--step) * 1.1);
416 }
417
418 .hanchor {
419 position: absolute;
420 right: calc(100% + 0.9rem);
421 top: 0.06em;
422 font-family: var(--mono);
423 font-size: 0.78em;
424 font-weight: 400;
425 color: var(--accent);
426 opacity: 0.4;
427 text-decoration: none;
428 transition: opacity 0.15s ease;
429
430 &:hover,
431 &:focus-visible {
432 opacity: 1;
433 }
434 }
435
436 @media (max-width: $wide) {
437 .hanchor {
438 position: static;
439 margin-right: 0.4em;
440 font-size: 0.7em;
441 vertical-align: 0.1em;
442 }
443 }
444
445 ul,
446 ol {
447 padding-left: 1.35rem;
448 }
449
450 li + li {
451 margin-top: 0.35rem;
452 }
453
454 li > ul,
455 li > ol {
456 margin-top: 0.35rem;
457 }
458
459 ul {
460 list-style: none;
461 padding-left: 1.15rem;
462 }
463
464 ul > li {
465 position: relative;
466
467 &::before {
468 content: "";
469 position: absolute;
470 left: -1.05rem;
471 top: 0.66em;
472 width: 0.38rem;
473 height: 1px;
474 background: var(--accent);
475 opacity: 0.75;
476 }
477 }
478
479 ul ul > li::before {
480 background: var(--rule-strong);
481 }
482
483 ol {
484 list-style: none;
485 counter-reset: ol;
486 padding-left: 1.85rem;
487 }
488
489 ol > li {
490 counter-increment: ol;
491 position: relative;
492
493 &::before {
494 content: counter(ol) ".";
495 position: absolute;
496 right: calc(100% + 0.5rem);
497 top: 0.06em;
498 font-family: var(--mono);
499 font-size: 0.75em;
500 color: var(--ink-faint);
501 font-variant-numeric: tabular-nums;
502 }
503 }
504
505 dt {
506 font-weight: 600;
507 }
508
509 dd {
510 margin-left: 1.35rem;
511 }
512
513 strong,
514 b {
515 font-weight: 700;
516 }
517
518 hr {
519 border: 0;
520 height: 1px;
521 background: linear-gradient(
522 to right,
523 var(--rule-strong),
524 var(--rule) 45%,
525 transparent
526 );
527 margin-block: calc(var(--step) * 1.6);
528 }
529
530 sup,
531 sub {
532 line-height: 0;
533 font-size: 0.7em;
534 }
535}
536
537a {
538 color: inherit;
539 text-decoration: underline;
540 text-decoration-color: var(--accent);
541 text-decoration-thickness: 1px;
542 text-underline-offset: 0.17em;
543 transition:
544 color 0.15s ease,
545 text-decoration-color 0.15s ease;
546
547 &:hover {
548 color: var(--accent);
549 text-decoration-thickness: 2px;
550 }
551}
552
553// --- Blockquote --------------------------------------------------------
554
555blockquote {
556 padding-left: 1.15rem;
557 border-left: 2px solid var(--rule-strong);
558 color: var(--ink-muted);
559
560 > * + * {
561 margin-top: 0.7rem;
562 }
563}
564
565// --- Code ----------------------------------------------------------------
566
567code,
568kbd,
569samp {
570 font-family: var(--mono);
571 font-variant-ligatures: none;
572 font-feature-settings:
573 "liga" 0,
574 "calt" 0;
575}
576
577:not(pre) > code {
578 font-size: 0.82em;
579 background: var(--paper-raised);
580 border: 1px solid var(--rule);
581 border-radius: 3px;
582 padding: 0.08em 0.26em;
583 color: var(--ink);
584 white-space: break-spaces;
585 word-break: break-word;
586}
587
588a :not(pre) > code,
589:not(pre) > code:has(a) {
590 color: inherit;
591}
592
593kbd {
594 font-size: 0.78em;
595 background: var(--paper);
596 border: 1px solid var(--rule-strong);
597 border-bottom-width: 2px;
598 border-radius: 3px;
599 padding: 0.08em 0.36em;
600 color: var(--ink);
601 white-space: nowrap;
602}
603
604// Hugo/Chroma wraps a fenced code block in <div class="highlight"><pre
605// class="chroma"><code class="language-x" data-lang="x">. The language tag
606// is read off that data-lang attribute and floats over the block like a
607// fieldset legend.
608.highlight {
609 position: relative;
610
611 code[data-lang]::before {
612 @extend %chrome;
613 content: attr(data-lang);
614 position: absolute;
615 z-index: 1;
616 top: 0;
617 right: 0.85rem;
618 transform: translateY(-50%);
619 padding-inline: 0.4rem;
620 background: var(--paper);
621 font-size: 0.6rem;
622 line-height: 1;
623 color: var(--ink-faint);
624 pointer-events: none;
625 }
626}
627
628pre {
629 font-family: var(--mono);
630 font-size: 0.78rem;
631 line-height: 1.55;
632 background: var(--paper-raised);
633 border: 1px solid var(--rule);
634 border-left: 2px solid var(--rule-strong);
635 border-radius: 3px;
636 padding: 0.85rem 1rem;
637 overflow-x: auto;
638 tab-size: 4;
639 color: var(--ink);
640
641 code {
642 background: none;
643 border: 0;
644 padding: 0;
645 font-size: inherit;
646 color: inherit;
647 }
648}
649
650// --- Collapsible blocks --------------------------------------------------
651
652.prose details {
653 border: 1px solid var(--rule);
654 border-left: 2px solid var(--rule-strong);
655 border-radius: 3px;
656 padding: 0 0.9rem;
657
658 > summary {
659 font-family: var(--mono);
660 font-size: 0.78rem;
661 color: var(--ink);
662 padding: 0.6rem 0;
663 cursor: pointer;
664 list-style: none;
665 display: flex;
666 align-items: baseline;
667 gap: 0.5rem;
668
669 &::-webkit-details-marker {
670 display: none;
671 }
672
673 &::before {
674 content: "";
675 width: 0;
676 height: 0;
677 border-left: 0.5rem solid var(--accent);
678 border-top: 0.29rem solid transparent;
679 border-bottom: 0.29rem solid transparent;
680 align-self: center;
681 transition: transform 0.15s ease;
682 display: inline-block;
683 }
684
685 &:hover {
686 color: var(--accent);
687 }
688 }
689
690 &[open] {
691 padding-bottom: 0.9rem;
692
693 > summary {
694 margin-bottom: 0.9rem;
695 border-bottom: 1px solid var(--rule);
696 color: var(--accent);
697
698 &::before {
699 transform: rotate(90deg);
700 }
701 }
702 }
703
704 .highlight {
705 margin-inline: -0.9rem;
706 }
707
708 pre {
709 border-inline: 0;
710 border-radius: 0;
711 }
712}
713
714@media (prefers-reduced-motion: reduce) {
715 .prose details > summary::before {
716 transition: none;
717 }
718}
719
720// --- Tables ----------------------------------------------------------------
721
722.table-scroll {
723 overflow-x: auto;
724 max-width: 100%;
725}
726
727table {
728 border-collapse: collapse;
729 width: 100%;
730 font-size: 0.85rem;
731 font-variant-numeric: tabular-nums;
732
733 th,
734 td {
735 padding: 0.45rem 0.7rem;
736 text-align: left;
737 border: 0;
738 border-bottom: 1px solid var(--rule);
739 vertical-align: top;
740 }
741
742 th:first-child,
743 td:first-child {
744 padding-left: 0;
745 }
746
747 th:last-child,
748 td:last-child {
749 padding-right: 0;
750 }
751
752 th {
753 @extend %chrome;
754 color: var(--ink-muted);
755 border-bottom: 1px solid var(--rule-strong);
756 letter-spacing: 0.055em;
757 line-height: 1.35;
758 }
759
760 tbody tr:last-child td {
761 border-bottom: 0;
762 }
763
764 tbody tr:hover td {
765 background: var(--accent-wash);
766 }
767}
768
769// --- Figures and media -----------------------------------------------------
770
771img,
772video,
773canvas,
774svg {
775 max-width: 100%;
776 height: auto;
777}
778
779.prose img,
780.prose video {
781 display: block;
782 max-width: min(var(--image-width, 100%), 100%);
783 margin-inline: auto;
784 border: 1px solid var(--rule);
785 border-radius: 3px;
786 background: var(--image-mat);
787}
788
789.prose a img {
790 border-color: var(--rule-strong);
791}
792
793iframe,
794embed,
795object {
796 max-width: 100%;
797 border: 0;
798}
799
800iframe[src*="youtube"],
801iframe[src*="vimeo"] {
802 display: block;
803 width: 100%;
804 aspect-ratio: 16 / 9;
805 height: auto;
806 margin-inline: auto;
807 border: 1px solid var(--rule);
808 border-radius: 3px;
809 background: var(--image-mat);
810}
811
812// Goldmark's own footnote list, styled plainly — the margin-sidenote
813// treatment from fzakaria.com needs a custom relocation pass this port
814// does not carry.
815.footnotes {
816 margin-top: calc(var(--step) * 2);
817 padding-top: var(--step);
818 border-top: 1px solid var(--rule);
819 font-size: 0.85rem;
820 color: var(--ink-muted);
821}
822
823// --- Alerts ------------------------------------------------------------
824
825$alerts: (
826 "note": (
827 #0b5fa5,
828 #6fb2e8,
829 ),
830 "tip": (
831 #1a7f37,
832 #79c98d,
833 ),
834 "important": (
835 #7145c4,
836 #b79ded,
837 ),
838 "warning": (
839 #8a6100,
840 #dfb051,
841 ),
842 "caution": (
843 #b1201d,
844 #ec8b7f,
845 ),
846);
847
848.alert {
849 --alert: var(--rule-strong);
850 border-left: 2px solid var(--alert);
851 background: var(--paper-raised);
852 padding: 0.85rem 1.1rem;
853 border-radius: 0 3px 3px 0;
854 color: var(--ink);
855
856 > * + * {
857 margin-top: 0.65rem;
858 }
859
860 p:first-child > strong:first-child {
861 @extend %chrome;
862 display: block;
863 color: var(--alert);
864 margin-bottom: 0.3rem;
865 }
866
867 :not(pre) > code {
868 background: transparent;
869 border-color: transparent;
870 padding: 0;
871 }
872
873 @each $name, $pair in $alerts {
874 &.alert-#{$name} {
875 --alert: #{list.nth($pair, 1)};
876
877 @media (prefers-color-scheme: dark) {
878 --alert: #{list.nth($pair, 2)};
879 }
880 }
881 }
882}
883
884blockquote.alert {
885 border-left-color: var(--alert);
886 color: var(--ink);
887}
888
889// --- Post header -----------------------------------------------------------
890
891.post-header {
892 margin-bottom: calc(var(--step) * 1.5);
893}
894
895.post-kicker {
896 @extend %chrome;
897 display: flex;
898 flex-wrap: wrap;
899 gap: 0 0.5rem;
900 margin-bottom: 0.7rem;
901
902 .sep {
903 color: var(--rule-strong);
904 }
905
906 a {
907 color: inherit;
908 text-decoration: none;
909 border-bottom: 1px solid var(--rule-strong);
910
911 &:hover {
912 color: var(--accent);
913 border-bottom-color: var(--accent);
914 }
915 }
916}
917
918.post-title {
919 font-size: clamp(1.85rem, 1.3rem + 2.1vw, 2.85rem);
920 font-weight: 600;
921 line-height: 1.08;
922 letter-spacing: -0.025em;
923 text-wrap: balance;
924}
925
926.post-rule {
927 width: 3.5rem;
928 height: 2px;
929 background: var(--accent);
930 margin: 1.1rem auto 0 0;
931 border: 0;
932}
933
934.post-body {
935 margin-top: calc(var(--step) * 1.5);
936}
937
938// --- Site footer -------------------------------------------------------
939
940.site-foot {
941 @extend %chrome;
942 margin-top: calc(var(--step) * 2.5);
943 padding-top: var(--step);
944 border-top: 1px solid var(--rule);
945 text-transform: none;
946 letter-spacing: 0.02em;
947 font-size: 0.7rem;
948 line-height: 1.75;
949 color: var(--ink-faint);
950 display: flex;
951 flex-wrap: wrap;
952 justify-content: center;
953 text-align: center;
954 gap: 0 0.5rem;
955
956 a {
957 color: var(--ink-muted);
958 text-decoration: none;
959 border-bottom: 1px solid var(--rule);
960
961 &:hover {
962 color: var(--accent);
963 border-bottom-color: var(--accent);
964 }
965 }
966
967 .sep {
968 color: var(--rule-strong);
969 }
970
971 .rss {
972 display: inline-flex;
973 align-items: center;
974 gap: 0.3rem;
975 border-bottom: 0;
976
977 svg {
978 width: 0.85em;
979 height: 0.85em;
980 fill: currentColor;
981 }
982 }
983
984 // Own row, so the path gets the whole measure rather than whatever is left
985 // over beside the RSS link.
986 .store-path-row {
987 flex-basis: 100%;
988 }
989
990 // A store path is a single 56-character token: broken across lines it is
991 // unreadable and awkward to select. Hold it on one line and let it shrink
992 // instead.
993 .store-path {
994 font-size: min(0.7rem, 2.3vw);
995 letter-spacing: 0;
996 white-space: nowrap;
997 color: inherit;
998 background: none;
999 border: 0;
1000 padding: 0;
1001 }
1002}
1003
1004// --- Index ---------------------------------------------------------------
1005
1006.page-index {
1007 display: flow-root;
1008}
1009
1010// Bio card. Floats into the margin column beside the post list; below $wide
1011// there is no margin column to float into, so it drops below the list
1012// instead (further down).
1013.colophon {
1014 float: right;
1015 width: var(--margin-col);
1016 margin-right: calc((var(--gap) + var(--margin-col)) * -1);
1017 margin-bottom: var(--step);
1018 // Jumped to from the masthead; leave air above it on arrival.
1019 scroll-margin-top: var(--step);
1020 font-size: 0.8rem;
1021 line-height: 1.55;
1022 color: var(--ink-muted);
1023}
1024
1025.colophon__avatar {
1026 width: 100%;
1027 max-width: 8.5rem;
1028 border-radius: 3px;
1029 border: 1px solid var(--rule-strong);
1030 display: block;
1031 margin-bottom: 0.85rem;
1032 filter: grayscale(0.35);
1033 transition: filter 0.3s ease;
1034
1035 &:hover {
1036 filter: grayscale(0);
1037 }
1038}
1039
1040.colophon__name {
1041 font-weight: 600;
1042 font-size: 0.95rem;
1043 line-height: 1.3;
1044 color: var(--ink);
1045 margin-bottom: 0.35rem;
1046
1047 &-last {
1048 font-weight: 500;
1049 color: var(--ink-faint);
1050 }
1051}
1052
1053.colophon__bio {
1054 margin-bottom: 1rem;
1055
1056 a {
1057 text-decoration-color: var(--rule-strong);
1058 }
1059}
1060
1061.colophon__links {
1062 list-style: none;
1063 margin: 0;
1064 padding: 0;
1065 border-top: 1px solid var(--rule);
1066
1067 // The key sits above its value rather than beside it: a two-column split
1068 // leaves too little room for an email address in monospace without
1069 // breaking it across lines.
1070 li {
1071 padding-block: 0.4rem;
1072 border-bottom: 1px solid var(--rule);
1073 }
1074
1075 .key {
1076 @extend %chrome;
1077 display: block;
1078 font-size: 0.6rem;
1079 margin-bottom: 0.05rem;
1080 }
1081
1082 .val {
1083 display: block;
1084 font-family: var(--mono);
1085 font-size: 0.68rem;
1086
1087 a {
1088 color: var(--ink-muted);
1089 text-decoration: none;
1090 border-bottom: 1px solid var(--rule-strong);
1091
1092 &:hover {
1093 color: var(--accent);
1094 border-bottom-color: var(--accent);
1095 }
1096 }
1097 }
1098}
1099
1100// Narrow: the float is dropped and the card moves below the article list.
1101@media (max-width: $wide) {
1102 .masthead__about {
1103 display: inline-block;
1104 }
1105
1106 .page-index {
1107 display: flex;
1108 flex-direction: column;
1109 }
1110
1111 .colophon {
1112 float: none;
1113 width: 100%;
1114 margin-right: 0;
1115 margin-bottom: 0;
1116 margin-top: calc(var(--step) * 2);
1117 padding-top: var(--step);
1118 border-top: 1px solid var(--rule);
1119 order: 3;
1120 display: grid;
1121 grid-template-columns: 8.5rem 1fr;
1122 gap: 0 1.25rem;
1123 align-items: start;
1124 }
1125
1126 .colophon__avatar {
1127 margin-bottom: 0;
1128 grid-row: span 2;
1129 }
1130
1131 .index-body {
1132 order: 2;
1133 }
1134
1135 @media (max-width: 30rem) {
1136 .colophon {
1137 grid-template-columns: 1fr;
1138 gap: 1rem;
1139 }
1140
1141 .colophon__avatar {
1142 max-width: 6.5rem;
1143 }
1144 }
1145}
1146
1147.index-lead {
1148 display: block;
1149 text-decoration: none;
1150 margin-bottom: calc(var(--step) * 2);
1151 padding-left: 1rem;
1152 border-left: 2px solid var(--accent);
1153 position: relative;
1154
1155 .label {
1156 @extend %chrome;
1157 color: var(--accent);
1158 display: block;
1159 margin-bottom: 0.4rem;
1160 }
1161
1162 .title {
1163 font-size: 1.5rem;
1164 font-weight: 600;
1165 line-height: 1.15;
1166 letter-spacing: -0.02em;
1167 text-wrap: balance;
1168 display: block;
1169 color: inherit;
1170 text-decoration: none;
1171
1172 &::after {
1173 content: "";
1174 position: absolute;
1175 inset: 0;
1176 }
1177 }
1178
1179 .excerpt a {
1180 position: relative;
1181 z-index: 1;
1182 }
1183
1184 .excerpt {
1185 display: block;
1186 color: var(--ink-muted);
1187 font-size: 0.92rem;
1188 margin-top: 0.5rem;
1189 }
1190
1191 .more {
1192 @extend %chrome;
1193 color: var(--accent);
1194 display: block;
1195 margin-top: 0.7rem;
1196 }
1197
1198 &:hover .title {
1199 color: var(--accent);
1200 }
1201}
1202
1203.year {
1204 margin-top: calc(var(--step) * 2);
1205 position: relative;
1206
1207 &:first-of-type {
1208 margin-top: 0;
1209 }
1210}
1211
1212.year__label {
1213 @extend %chrome;
1214 font-size: 0.78rem;
1215 color: var(--ink-faint);
1216 padding-bottom: 0.4rem;
1217 margin-bottom: 0.6rem;
1218 border-bottom: 1px solid var(--rule);
1219 display: flex;
1220 justify-content: space-between;
1221 align-items: baseline;
1222
1223 .count {
1224 font-size: 0.66rem;
1225 color: var(--rule-strong);
1226 }
1227}
1228
1229@media (min-width: $wide) {
1230 .year__label {
1231 position: absolute;
1232 right: calc(100% + 0.9rem);
1233 top: 0.1rem;
1234 width: calc(var(--gutter) - 0.9rem);
1235 display: block;
1236 border-bottom: 0;
1237 padding-bottom: 0;
1238 margin-bottom: 0;
1239 text-align: right;
1240 letter-spacing: 0.04em;
1241
1242 .count {
1243 display: none;
1244 }
1245 }
1246
1247 .year__list {
1248 border-top: 1px solid var(--rule);
1249 padding-top: 0.35rem;
1250 }
1251}
1252
1253.year__list {
1254 list-style: none;
1255 margin: 0;
1256 padding: 0;
1257}
1258
1259.entry {
1260 display: grid;
1261 grid-template-columns: 4.25rem 1fr;
1262 gap: 0 0.85rem;
1263 align-items: baseline;
1264 padding-block: 0.42rem;
1265
1266 @media (max-width: 34rem) {
1267 grid-template-columns: 1fr;
1268 gap: 0.12rem;
1269 padding-block: 0.5rem;
1270 }
1271
1272 + .entry {
1273 border-top: 1px solid var(--rule);
1274 }
1275
1276 .date {
1277 @extend %chrome;
1278 font-size: 0.68rem;
1279 white-space: nowrap;
1280 }
1281
1282 a {
1283 text-decoration: none;
1284 line-height: 1.35;
1285 color: var(--ink);
1286 text-decoration: underline;
1287 text-decoration-color: transparent;
1288 text-underline-offset: 0.17em;
1289 }
1290
1291 &:hover a {
1292 color: var(--accent);
1293 text-decoration-color: var(--accent);
1294 }
1295
1296 &:hover .date {
1297 color: var(--accent);
1298 }
1299}
1300
1301// --- Motion --------------------------------------------------------------
1302
1303@media (prefers-reduced-motion: no-preference) {
1304 @keyframes rise {
1305 from {
1306 opacity: 0;
1307 transform: translateY(0.5rem);
1308 }
1309 to {
1310 opacity: 1;
1311 transform: none;
1312 }
1313 }
1314
1315 .rise {
1316 animation: rise 0.5s cubic-bezier(0.22, 0.68, 0.35, 1) backwards;
1317 animation-delay: calc(var(--i, 0) * 60ms);
1318 }
1319
1320 @keyframes signal-sweep {
1321 to {
1322 stroke-dashoffset: 0;
1323 }
1324 }
1325
1326 .masthead__signal path {
1327 stroke-dasharray: 100;
1328 stroke-dashoffset: 100;
1329 animation: signal-sweep 1.1s cubic-bezier(0.32, 0.5, 0.3, 1) 0.18s forwards;
Smooth page transitions with htmx boost, morph, and preload ca8b900 Romain Gautier yesterday1330 // Every page's signal is the same number of curve commands (32 bytes ->
1331 // fixed M + 30 C), just different coordinates - so the browser can
1332 // interpolate straight from one `d` to the next when htmx morphs it in
1333 // on navigation, instead of snapping. Only fires on a same-node update;
1334 // a fresh page load has no prior `d` to transition from.
1335 transition: d 0.7s cubic-bezier(0.32, 0.5, 0.3, 1);
1336 }
1337}
1338
1339// htmx's boosted navigation wraps every swap in document.startViewTransition
1340// (see hx-boost:inherited in baseof.html); browsers don't honor
1341// prefers-reduced-motion for that on their own, so without this the default
1342// cross-fade would still run for anyone who has asked for less motion.
1343@media (prefers-reduced-motion: reduce) {
1344 ::view-transition-group(*),
1345 ::view-transition-old(*),
1346 ::view-transition-new(*) {
1347 animation: none !important;
Port fzakaria.com design to Hugo and add a homepage profile 1bdbd06 Romain Gautier yesterday1348 }
1349}
1350
1351// --- Print -----------------------------------------------------------------
1352
1353@media print {
1354 :root {
1355 --paper: #fff;
1356 --paper-raised: #fff;
1357 --ink: #000;
1358 --ink-muted: #333;
1359 --ink-faint: #555;
1360 --rule: #bbb;
1361 --rule-strong: #888;
1362 --accent: #000;
1363 --gutter: 0rem;
1364 --margin-col: 0rem;
1365 --gap: 0rem;
1366 }
1367
1368 body {
1369 background: #fff;
1370 }
1371
1372 .colophon,
1373 .skip-link {
1374 display: none;
1375 }
1376
1377 details {
1378 border: 0;
1379 padding: 0;
1380 }
1381
1382 details > summary::before {
1383 content: none;
1384 }
1385
1386 pre,
1387 blockquote,
1388 details,
1389 .alert {
1390 break-inside: avoid;
1391 }
1392
1393 a::after {
1394 content: " (" attr(href) ")";
1395 font-size: 0.75em;
1396 color: #555;
1397 }
1398
1399 a[href^="#"]::after {
1400 content: "";
1401 }
1402}
1403
1404// ---------------------------------------------------------------------------
1405// Rouge/Chroma syntax theme — "Ochre" (unchanged from fzakaria.com).
1406// ---------------------------------------------------------------------------
1407
1408:root {
1409 --syn-comment: #6f685b;
1410 --syn-keyword: #9a3d05;
1411 --syn-string: #3f6b32;
1412 --syn-number: #6b4fa8;
1413 --syn-func: #1c5570;
1414 --syn-type: #7a6114;
1415 --syn-var: #7c4a2d;
1416 --syn-punct: #6b6558;
1417 --syn-error: #b1201d;
1418 --syn-error-bg: #b1201d1a;
1419 --syn-ins-bg: #1a7f3714;
1420 --syn-del-bg: #b1201d14;
1421 --syn-ins-fg: #1a6d33;
1422 --syn-del-fg: #a3231f;
1423}
1424
1425@media (prefers-color-scheme: dark) {
1426 :root {
1427 --syn-comment: #8d867a;
1428 --syn-keyword: #e08a45;
1429 --syn-string: #a6c98d;
1430 --syn-number: #c3a2ec;
1431 --syn-func: #7fb6d6;
1432 --syn-type: #ddc477;
1433 --syn-var: #dda58c;
1434 --syn-punct: #8b857a;
1435 --syn-error: #ec8b7f;
1436 --syn-error-bg: #ec8b7f1f;
1437 --syn-ins-bg: #79c98d1a;
1438 --syn-del-bg: #ec8b7f1a;
1439 --syn-ins-fg: #8fd0a1;
1440 --syn-del-fg: #ef9a8f;
1441 }
1442}
1443
1444.highlight {
1445 .c, .ch, .cd, .cm, .cp, .cpf, .c1, .cs {
1446 color: var(--syn-comment);
1447 font-style: italic;
1448 }
1449
1450 .k, .kc, .kd, .kn, .kp, .kr, .kv {
1451 color: var(--syn-keyword);
1452 }
1453
1454 .kt, .nc, .nn, .no, .ne {
1455 color: var(--syn-type);
1456 }
1457
1458 .nf, .fm, .nb, .bp, .na, .nt {
1459 color: var(--syn-func);
1460 }
1461
1462 .nv, .vc, .vg, .vi, .vm, .nl, .py {
1463 color: var(--syn-var);
1464 }
1465
1466 .s, .sa, .sb, .sc, .dl, .sd, .s2, .se, .sh, .si, .sx, .s1, .ss, .sr {
1467 color: var(--syn-string);
1468 }
1469
1470 .m, .mb, .mf, .mh, .mi, .mo, .il {
1471 color: var(--syn-number);
1472 }
1473
1474 .o, .ow, .p, .pi, .ni {
1475 color: var(--syn-punct);
1476 }
1477
1478 .err {
1479 color: var(--syn-error);
1480 background-color: var(--syn-error-bg);
1481 border-radius: 2px;
1482 }
1483
1484 .gd {
1485 color: var(--syn-del-fg);
1486 background-color: var(--syn-del-bg);
1487 }
1488
1489 .gi {
1490 color: var(--syn-ins-fg);
1491 background-color: var(--syn-ins-bg);
1492 }
1493
1494 .gh, .gu {
1495 color: var(--syn-func);
1496 font-weight: 600;
1497 }
1498
1499 .gp {
1500 color: var(--syn-comment);
1501 user-select: none;
1502 }
1503
1504 .go {
1505 color: var(--ink-muted);
1506 }
1507
1508 .ge {
1509 font-style: italic;
1510 }
1511
1512 .gs {
1513 font-weight: 700;
1514 }
1515
1516 .gr, .gt {
1517 color: var(--syn-error);
1518 }
1519
1520 .w {
1521 color: var(--rule-strong);
1522 }
1523
1524 .lineno, .gl {
1525 color: var(--ink-faint);
1526 opacity: 0.6;
1527 user-select: none;
1528 padding-right: 0.85rem;
1529 }
1530}