mykiwi/mykiwi.blogpublic Fork 0
a74fe0a29252e8de5b737ff5cf56888380055981
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 · 1539 lines · 28.5 KBSCSS Blame HistoryRaw
Port fzakaria.com design to Hugo and add a homepage profile 1bdbd06 Romain Gautier 21h ago1// ---------------------------------------------------------------------------
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
Add French/Portuguese/Japanese support, block indexing until launch f8c7bc5 Romain Gautier 17h ago984 .lang-switch {
985 display: inline-flex;
986 gap: 0.5rem;
987 }
988
989 .lang-switch__current {
990 color: var(--ink-muted);
991 }
992
Port fzakaria.com design to Hugo and add a homepage profile 1bdbd06 Romain Gautier 21h ago993 // Own row, so the path gets the whole measure rather than whatever is left
994 // over beside the RSS link.
995 .store-path-row {
996 flex-basis: 100%;
997 }
998
999 // A store path is a single 56-character token: broken across lines it is
1000 // unreadable and awkward to select. Hold it on one line and let it shrink
1001 // instead.
1002 .store-path {
1003 font-size: min(0.7rem, 2.3vw);
1004 letter-spacing: 0;
1005 white-space: nowrap;
1006 color: inherit;
1007 background: none;
1008 border: 0;
1009 padding: 0;
1010 }
1011}
1012
1013// --- Index ---------------------------------------------------------------
1014
1015.page-index {
1016 display: flow-root;
1017}
1018
1019// Bio card. Floats into the margin column beside the post list; below $wide
1020// there is no margin column to float into, so it drops below the list
1021// instead (further down).
1022.colophon {
1023 float: right;
1024 width: var(--margin-col);
1025 margin-right: calc((var(--gap) + var(--margin-col)) * -1);
1026 margin-bottom: var(--step);
1027 // Jumped to from the masthead; leave air above it on arrival.
1028 scroll-margin-top: var(--step);
1029 font-size: 0.8rem;
1030 line-height: 1.55;
1031 color: var(--ink-muted);
1032}
1033
1034.colophon__avatar {
1035 width: 100%;
1036 max-width: 8.5rem;
1037 border-radius: 3px;
1038 border: 1px solid var(--rule-strong);
1039 display: block;
1040 margin-bottom: 0.85rem;
1041 filter: grayscale(0.35);
1042 transition: filter 0.3s ease;
1043
1044 &:hover {
1045 filter: grayscale(0);
1046 }
1047}
1048
1049.colophon__name {
1050 font-weight: 600;
1051 font-size: 0.95rem;
1052 line-height: 1.3;
1053 color: var(--ink);
1054 margin-bottom: 0.35rem;
1055
1056 &-last {
1057 font-weight: 500;
1058 color: var(--ink-faint);
1059 }
1060}
1061
1062.colophon__bio {
1063 margin-bottom: 1rem;
1064
1065 a {
1066 text-decoration-color: var(--rule-strong);
1067 }
1068}
1069
1070.colophon__links {
1071 list-style: none;
1072 margin: 0;
1073 padding: 0;
1074 border-top: 1px solid var(--rule);
1075
1076 // The key sits above its value rather than beside it: a two-column split
1077 // leaves too little room for an email address in monospace without
1078 // breaking it across lines.
1079 li {
1080 padding-block: 0.4rem;
1081 border-bottom: 1px solid var(--rule);
1082 }
1083
1084 .key {
1085 @extend %chrome;
1086 display: block;
1087 font-size: 0.6rem;
1088 margin-bottom: 0.05rem;
1089 }
1090
1091 .val {
1092 display: block;
1093 font-family: var(--mono);
1094 font-size: 0.68rem;
1095
1096 a {
1097 color: var(--ink-muted);
1098 text-decoration: none;
1099 border-bottom: 1px solid var(--rule-strong);
1100
1101 &:hover {
1102 color: var(--accent);
1103 border-bottom-color: var(--accent);
1104 }
1105 }
1106 }
1107}
1108
1109// Narrow: the float is dropped and the card moves below the article list.
1110@media (max-width: $wide) {
1111 .masthead__about {
1112 display: inline-block;
1113 }
1114
1115 .page-index {
1116 display: flex;
1117 flex-direction: column;
1118 }
1119
1120 .colophon {
1121 float: none;
1122 width: 100%;
1123 margin-right: 0;
1124 margin-bottom: 0;
1125 margin-top: calc(var(--step) * 2);
1126 padding-top: var(--step);
1127 border-top: 1px solid var(--rule);
1128 order: 3;
1129 display: grid;
1130 grid-template-columns: 8.5rem 1fr;
1131 gap: 0 1.25rem;
1132 align-items: start;
1133 }
1134
1135 .colophon__avatar {
1136 margin-bottom: 0;
1137 grid-row: span 2;
1138 }
1139
1140 .index-body {
1141 order: 2;
1142 }
1143
1144 @media (max-width: 30rem) {
1145 .colophon {
1146 grid-template-columns: 1fr;
1147 gap: 1rem;
1148 }
1149
1150 .colophon__avatar {
1151 max-width: 6.5rem;
1152 }
1153 }
1154}
1155
1156.index-lead {
1157 display: block;
1158 text-decoration: none;
1159 margin-bottom: calc(var(--step) * 2);
1160 padding-left: 1rem;
1161 border-left: 2px solid var(--accent);
1162 position: relative;
1163
1164 .label {
1165 @extend %chrome;
1166 color: var(--accent);
1167 display: block;
1168 margin-bottom: 0.4rem;
1169 }
1170
1171 .title {
1172 font-size: 1.5rem;
1173 font-weight: 600;
1174 line-height: 1.15;
1175 letter-spacing: -0.02em;
1176 text-wrap: balance;
1177 display: block;
1178 color: inherit;
1179 text-decoration: none;
1180
1181 &::after {
1182 content: "";
1183 position: absolute;
1184 inset: 0;
1185 }
1186 }
1187
1188 .excerpt a {
1189 position: relative;
1190 z-index: 1;
1191 }
1192
1193 .excerpt {
1194 display: block;
1195 color: var(--ink-muted);
1196 font-size: 0.92rem;
1197 margin-top: 0.5rem;
1198 }
1199
1200 .more {
1201 @extend %chrome;
1202 color: var(--accent);
1203 display: block;
1204 margin-top: 0.7rem;
1205 }
1206
1207 &:hover .title {
1208 color: var(--accent);
1209 }
1210}
1211
1212.year {
1213 margin-top: calc(var(--step) * 2);
1214 position: relative;
1215
1216 &:first-of-type {
1217 margin-top: 0;
1218 }
1219}
1220
1221.year__label {
1222 @extend %chrome;
1223 font-size: 0.78rem;
1224 color: var(--ink-faint);
1225 padding-bottom: 0.4rem;
1226 margin-bottom: 0.6rem;
1227 border-bottom: 1px solid var(--rule);
1228 display: flex;
1229 justify-content: space-between;
1230 align-items: baseline;
1231
1232 .count {
1233 font-size: 0.66rem;
1234 color: var(--rule-strong);
1235 }
1236}
1237
1238@media (min-width: $wide) {
1239 .year__label {
1240 position: absolute;
1241 right: calc(100% + 0.9rem);
1242 top: 0.1rem;
1243 width: calc(var(--gutter) - 0.9rem);
1244 display: block;
1245 border-bottom: 0;
1246 padding-bottom: 0;
1247 margin-bottom: 0;
1248 text-align: right;
1249 letter-spacing: 0.04em;
1250
1251 .count {
1252 display: none;
1253 }
1254 }
1255
1256 .year__list {
1257 border-top: 1px solid var(--rule);
1258 padding-top: 0.35rem;
1259 }
1260}
1261
1262.year__list {
1263 list-style: none;
1264 margin: 0;
1265 padding: 0;
1266}
1267
1268.entry {
1269 display: grid;
1270 grid-template-columns: 4.25rem 1fr;
1271 gap: 0 0.85rem;
1272 align-items: baseline;
1273 padding-block: 0.42rem;
1274
1275 @media (max-width: 34rem) {
1276 grid-template-columns: 1fr;
1277 gap: 0.12rem;
1278 padding-block: 0.5rem;
1279 }
1280
1281 + .entry {
1282 border-top: 1px solid var(--rule);
1283 }
1284
1285 .date {
1286 @extend %chrome;
1287 font-size: 0.68rem;
1288 white-space: nowrap;
1289 }
1290
1291 a {
1292 text-decoration: none;
1293 line-height: 1.35;
1294 color: var(--ink);
1295 text-decoration: underline;
1296 text-decoration-color: transparent;
1297 text-underline-offset: 0.17em;
1298 }
1299
1300 &:hover a {
1301 color: var(--accent);
1302 text-decoration-color: var(--accent);
1303 }
1304
1305 &:hover .date {
1306 color: var(--accent);
1307 }
1308}
1309
1310// --- Motion --------------------------------------------------------------
1311
1312@media (prefers-reduced-motion: no-preference) {
1313 @keyframes rise {
1314 from {
1315 opacity: 0;
1316 transform: translateY(0.5rem);
1317 }
1318 to {
1319 opacity: 1;
1320 transform: none;
1321 }
1322 }
1323
1324 .rise {
1325 animation: rise 0.5s cubic-bezier(0.22, 0.68, 0.35, 1) backwards;
1326 animation-delay: calc(var(--i, 0) * 60ms);
1327 }
1328
1329 @keyframes signal-sweep {
1330 to {
1331 stroke-dashoffset: 0;
1332 }
1333 }
1334
1335 .masthead__signal path {
1336 stroke-dasharray: 100;
1337 stroke-dashoffset: 100;
1338 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 18h ago1339 // Every page's signal is the same number of curve commands (32 bytes ->
1340 // fixed M + 30 C), just different coordinates - so the browser can
1341 // interpolate straight from one `d` to the next when htmx morphs it in
1342 // on navigation, instead of snapping. Only fires on a same-node update;
1343 // a fresh page load has no prior `d` to transition from.
1344 transition: d 0.7s cubic-bezier(0.32, 0.5, 0.3, 1);
1345 }
1346}
1347
1348// htmx's boosted navigation wraps every swap in document.startViewTransition
1349// (see hx-boost:inherited in baseof.html); browsers don't honor
1350// prefers-reduced-motion for that on their own, so without this the default
1351// cross-fade would still run for anyone who has asked for less motion.
1352@media (prefers-reduced-motion: reduce) {
1353 ::view-transition-group(*),
1354 ::view-transition-old(*),
1355 ::view-transition-new(*) {
1356 animation: none !important;
Port fzakaria.com design to Hugo and add a homepage profile 1bdbd06 Romain Gautier 21h ago1357 }
1358}
1359
1360// --- Print -----------------------------------------------------------------
1361
1362@media print {
1363 :root {
1364 --paper: #fff;
1365 --paper-raised: #fff;
1366 --ink: #000;
1367 --ink-muted: #333;
1368 --ink-faint: #555;
1369 --rule: #bbb;
1370 --rule-strong: #888;
1371 --accent: #000;
1372 --gutter: 0rem;
1373 --margin-col: 0rem;
1374 --gap: 0rem;
1375 }
1376
1377 body {
1378 background: #fff;
1379 }
1380
1381 .colophon,
1382 .skip-link {
1383 display: none;
1384 }
1385
1386 details {
1387 border: 0;
1388 padding: 0;
1389 }
1390
1391 details > summary::before {
1392 content: none;
1393 }
1394
1395 pre,
1396 blockquote,
1397 details,
1398 .alert {
1399 break-inside: avoid;
1400 }
1401
1402 a::after {
1403 content: " (" attr(href) ")";
1404 font-size: 0.75em;
1405 color: #555;
1406 }
1407
1408 a[href^="#"]::after {
1409 content: "";
1410 }
1411}
1412
1413// ---------------------------------------------------------------------------
1414// Rouge/Chroma syntax theme — "Ochre" (unchanged from fzakaria.com).
1415// ---------------------------------------------------------------------------
1416
1417:root {
1418 --syn-comment: #6f685b;
1419 --syn-keyword: #9a3d05;
1420 --syn-string: #3f6b32;
1421 --syn-number: #6b4fa8;
1422 --syn-func: #1c5570;
1423 --syn-type: #7a6114;
1424 --syn-var: #7c4a2d;
1425 --syn-punct: #6b6558;
1426 --syn-error: #b1201d;
1427 --syn-error-bg: #b1201d1a;
1428 --syn-ins-bg: #1a7f3714;
1429 --syn-del-bg: #b1201d14;
1430 --syn-ins-fg: #1a6d33;
1431 --syn-del-fg: #a3231f;
1432}
1433
1434@media (prefers-color-scheme: dark) {
1435 :root {
1436 --syn-comment: #8d867a;
1437 --syn-keyword: #e08a45;
1438 --syn-string: #a6c98d;
1439 --syn-number: #c3a2ec;
1440 --syn-func: #7fb6d6;
1441 --syn-type: #ddc477;
1442 --syn-var: #dda58c;
1443 --syn-punct: #8b857a;
1444 --syn-error: #ec8b7f;
1445 --syn-error-bg: #ec8b7f1f;
1446 --syn-ins-bg: #79c98d1a;
1447 --syn-del-bg: #ec8b7f1a;
1448 --syn-ins-fg: #8fd0a1;
1449 --syn-del-fg: #ef9a8f;
1450 }
1451}
1452
1453.highlight {
1454 .c, .ch, .cd, .cm, .cp, .cpf, .c1, .cs {
1455 color: var(--syn-comment);
1456 font-style: italic;
1457 }
1458
1459 .k, .kc, .kd, .kn, .kp, .kr, .kv {
1460 color: var(--syn-keyword);
1461 }
1462
1463 .kt, .nc, .nn, .no, .ne {
1464 color: var(--syn-type);
1465 }
1466
1467 .nf, .fm, .nb, .bp, .na, .nt {
1468 color: var(--syn-func);
1469 }
1470
1471 .nv, .vc, .vg, .vi, .vm, .nl, .py {
1472 color: var(--syn-var);
1473 }
1474
1475 .s, .sa, .sb, .sc, .dl, .sd, .s2, .se, .sh, .si, .sx, .s1, .ss, .sr {
1476 color: var(--syn-string);
1477 }
1478
1479 .m, .mb, .mf, .mh, .mi, .mo, .il {
1480 color: var(--syn-number);
1481 }
1482
1483 .o, .ow, .p, .pi, .ni {
1484 color: var(--syn-punct);
1485 }
1486
1487 .err {
1488 color: var(--syn-error);
1489 background-color: var(--syn-error-bg);
1490 border-radius: 2px;
1491 }
1492
1493 .gd {
1494 color: var(--syn-del-fg);
1495 background-color: var(--syn-del-bg);
1496 }
1497
1498 .gi {
1499 color: var(--syn-ins-fg);
1500 background-color: var(--syn-ins-bg);
1501 }
1502
1503 .gh, .gu {
1504 color: var(--syn-func);
1505 font-weight: 600;
1506 }
1507
1508 .gp {
1509 color: var(--syn-comment);
1510 user-select: none;
1511 }
1512
1513 .go {
1514 color: var(--ink-muted);
1515 }
1516
1517 .ge {
1518 font-style: italic;
1519 }
1520
1521 .gs {
1522 font-weight: 700;
1523 }
1524
1525 .gr, .gt {
1526 color: var(--syn-error);
1527 }
1528
1529 .w {
1530 color: var(--rule-strong);
1531 }
1532
1533 .lineno, .gl {
1534 color: var(--ink-faint);
1535 opacity: 0.6;
1536 user-select: none;
1537 padding-right: 0.85rem;
1538 }
1539}