// --------------------------------------------------------------------------- // mykiwi.blog — core design ported from fzakaria.com (MIT-licensed). // Prose in Newsreader, structural chrome in JetBrains Mono, warm paper/ink // palette with a dark-mode swap. Personal-only sections (bio colophon, // readership/talks pages, WordPress archive) were left out. // --------------------------------------------------------------------------- @use "sass:list"; $wide: 67.5625rem; %chrome { font-family: var(--mono); font-size: 0.72rem; font-weight: 500; letter-spacing: 0.11em; text-transform: uppercase; font-variant-numeric: tabular-nums; color: var(--ink-faint); } // --- Fonts ----------------------------------------------------------------- @font-face { font-family: "Newsreader"; font-style: normal; font-weight: 400 700; font-display: swap; src: url("/fonts/Newsreader-latin.woff2") format("woff2"); unicode-range: u+0000-00ff, u+0131, u+0152-0153, u+02bb-02bc, u+02c6, u+02da, u+02dc, u+0304, u+0308, u+0329, u+2000-206f, u+20ac, u+2122, u+2191, u+2193, u+2212, u+2215, u+feff, u+fffd; } @font-face { font-family: "Newsreader"; font-style: normal; font-weight: 400 700; font-display: swap; src: url("/fonts/Newsreader-latin-ext.woff2") format("woff2"); unicode-range: u+0100-02ba, u+02bd-02c5, u+02c7-02cc, u+02ce-02d7, u+02dd-02ff, u+0304, u+0308, u+0329, u+1d00-1dbf, u+1e00-1e9f, u+1ef2-1eff, u+2020, u+20a0-20ab, u+20ad-20c0, u+2113, u+2c60-2c7f, u+a720-a7ff; } @font-face { font-family: "Newsreader"; font-style: italic; font-weight: 400 700; font-display: swap; src: url("/fonts/Newsreader-italic-latin.woff2") format("woff2"); unicode-range: u+0000-00ff, u+0131, u+0152-0153, u+02bb-02bc, u+02c6, u+02da, u+02dc, u+0304, u+0308, u+0329, u+2000-206f, u+20ac, u+2122, u+2191, u+2193, u+2212, u+2215, u+feff, u+fffd; } @font-face { font-family: "Newsreader"; font-style: italic; font-weight: 400 700; font-display: swap; src: url("/fonts/Newsreader-italic-latin-ext.woff2") format("woff2"); unicode-range: u+0100-02ba, u+02bd-02c5, u+02c7-02cc, u+02ce-02d7, u+02dd-02ff, u+0304, u+0308, u+0329, u+1d00-1dbf, u+1e00-1e9f, u+1ef2-1eff, u+2020, u+20a0-20ab, u+20ad-20c0, u+2113, u+2c60-2c7f, u+a720-a7ff; } @font-face { font-family: "JetBrains Mono"; font-style: normal; font-weight: 400; font-display: swap; src: url("/fonts/JetBrainsMono-Regular.woff2") format("woff2"); } // --- Tokens ------------------------------------------------------------ :root { --serif: "Newsreader", "Iowan Old Style", "Palatino Linotype", Palatino, Georgia, "Times New Roman", serif; --mono: "JetBrains Mono", ui-monospace, "SFMono-Regular", "Cascadia Mono", Menlo, Consolas, "Liberation Mono", monospace; --paper: #f5f2ec; --paper-raised: #ebe6da; --ink: #1a1815; --ink-muted: #565046; --ink-faint: #6f685b; --rule: #dcd5c5; --rule-strong: #c2b9a6; --accent: #9e3413; --accent-wash: #9e34131f; --glow: #fffdf6; --image-mat: #ebe6da; --measure: 36rem; --gutter: 0rem; --gap: 0rem; --margin-col: 0rem; --pad: 1.5rem; --root-max: 19.5px; --step: 1.6rem; color-scheme: light dark; } @media (prefers-color-scheme: dark) { :root { --paper: #15171a; --paper-raised: #1d2025; --ink: #ddd8cd; --ink-muted: #9b958a; --ink-faint: #8a8377; --rule: #2b2f35; --rule-strong: #3f454d; --accent: #e08a45; --accent-wash: #e08a4526; --glow: #1f242b; } } @media (min-width: $wide) { :root { --gutter: 4.5rem; --gap: 2rem; --margin-col: 13.5rem; } } @media (min-width: 87.5rem) { :root { --gutter: 6rem; --gap: 2.5rem; --margin-col: 16rem; } } @media (max-width: 34rem) { :root { --pad: 1.15rem; --step: 1.35rem; } } // --- Reset ----------------------------------------------------------------- *, *::before, *::after { box-sizing: border-box; } body, h1, h2, h3, h4, h5, h6, p, ul, ol, dl, dd, figure, blockquote, pre { margin: 0; } html { font-size: clamp(17px, 0.95rem + 0.2vw, var(--root-max)); -webkit-text-size-adjust: 100%; scroll-behavior: smooth; } @media (prefers-reduced-motion: reduce) { html { scroll-behavior: auto; } } body { font-family: var(--serif); font-weight: 400; font-size: 1rem; line-height: 1.62; color: var(--ink); background-color: var(--paper); background-image: radial-gradient( 75rem 32rem at 14% -6%, var(--glow) 0%, transparent 68% ); background-repeat: no-repeat; text-rendering: optimizeLegibility; -webkit-font-smoothing: antialiased; min-height: 100vh; overflow-wrap: break-word; } ::selection { background: var(--accent); color: var(--paper); } // --- Layout ------------------------------------------------------------ .wrap { width: 100%; max-width: calc( var(--gutter) + var(--measure) + var(--gap) + var(--margin-col) + 2 * var(--pad) ); margin-inline: auto; padding-inline: var(--pad); padding-bottom: calc(var(--step) * 2); } .column { max-width: var(--measure); margin-left: var(--gutter); } .skip-link { position: absolute; left: -9999px; top: 0; padding: 0.5rem 0.9rem; background: var(--accent); color: var(--paper); font-family: var(--mono); font-size: 0.8rem; z-index: 10; &:focus { left: 0.5rem; top: 0.5rem; } } :focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; border-radius: 1px; } .visually-hidden { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0; } // --- Masthead ---------------------------------------------------------- .masthead { padding-top: calc(var(--step) * 1.6); padding-bottom: var(--step); margin-bottom: calc(var(--step) * 1.4); position: relative; display: flex; align-items: baseline; justify-content: space-between; gap: 0 1rem; &__signal { position: absolute; left: 0; right: 0; bottom: 0; height: 26px; -webkit-mask-image: linear-gradient( to right, #000 0%, #000 62%, transparent 96% ); mask-image: linear-gradient(to right, #000 0%, #000 62%, transparent 96%); svg { display: block; width: 100%; height: 100%; } path { fill: none; stroke: url("#signal-ramp"); stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round; vector-effect: non-scaling-stroke; } } .signal-ramp__lead { stop-color: var(--accent); } .signal-ramp__body, .signal-ramp__tail { stop-color: var(--rule-strong); } } .masthead__title { font-size: 1.5rem; font-weight: 600; line-height: 1.1; letter-spacing: -0.018em; a { color: inherit; text-decoration: none; } a:hover { color: var(--accent); } } // Signpost to the colophon, shown only at widths where the colophon is // reordered below the post list and nothing on first screen hints it is // there. Turned on alongside that reorder, further down. .masthead__about { @extend %chrome; display: none; flex: none; color: var(--ink-muted); text-decoration: none; border-bottom: 1px solid var(--rule); &:hover { color: var(--accent); border-bottom-color: var(--accent); } } // --- Prose --------------------------------------------------------------- .prose { > * + * { margin-top: var(--step); } p, ul, ol, dl { line-height: 1.65; } div > * + *, details > * + *, li > * + *, td > * + *, th > * + * { margin-top: 0.7rem; } h1, h2, h3, h4, h5, h6 { font-weight: 600; line-height: 1.2; letter-spacing: -0.012em; margin-bottom: 0; position: relative; scroll-margin-top: 1.5rem; } :is(h1, h2, h3, h4, h5, h6) + :not(h1, h2, h3, h4, h5, h6) { margin-top: 0.55rem; } :is(h1, h2, h3, h4, h5, h6) + :is(h1, h2, h3, h4, h5, h6) { margin-top: calc(var(--step) * 1.1); } h1 { font-size: 1.62rem; margin-top: calc(var(--step) * 2); } h2 { font-size: 1.4rem; margin-top: calc(var(--step) * 1.7); } h3 { font-size: 1.18rem; margin-top: calc(var(--step) * 1.35); } h4, h5, h6 { font-size: 1rem; font-family: var(--mono); font-weight: 600; letter-spacing: 0.02em; margin-top: calc(var(--step) * 1.1); } .hanchor { position: absolute; right: calc(100% + 0.9rem); top: 0.06em; font-family: var(--mono); font-size: 0.78em; font-weight: 400; color: var(--accent); opacity: 0.4; text-decoration: none; transition: opacity 0.15s ease; &:hover, &:focus-visible { opacity: 1; } } @media (max-width: $wide) { .hanchor { position: static; margin-right: 0.4em; font-size: 0.7em; vertical-align: 0.1em; } } ul, ol { padding-left: 1.35rem; } li + li { margin-top: 0.35rem; } li > ul, li > ol { margin-top: 0.35rem; } ul { list-style: none; padding-left: 1.15rem; } ul > li { position: relative; &::before { content: ""; position: absolute; left: -1.05rem; top: 0.66em; width: 0.38rem; height: 1px; background: var(--accent); opacity: 0.75; } } ul ul > li::before { background: var(--rule-strong); } ol { list-style: none; counter-reset: ol; padding-left: 1.85rem; } ol > li { counter-increment: ol; position: relative; &::before { content: counter(ol) "."; position: absolute; right: calc(100% + 0.5rem); top: 0.06em; font-family: var(--mono); font-size: 0.75em; color: var(--ink-faint); font-variant-numeric: tabular-nums; } } dt { font-weight: 600; } dd { margin-left: 1.35rem; } strong, b { font-weight: 700; } hr { border: 0; height: 1px; background: linear-gradient( to right, var(--rule-strong), var(--rule) 45%, transparent ); margin-block: calc(var(--step) * 1.6); } sup, sub { line-height: 0; font-size: 0.7em; } } a { color: inherit; text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 0.17em; transition: color 0.15s ease, text-decoration-color 0.15s ease; &:hover { color: var(--accent); text-decoration-thickness: 2px; } } // --- Blockquote -------------------------------------------------------- blockquote { padding-left: 1.15rem; border-left: 2px solid var(--rule-strong); color: var(--ink-muted); > * + * { margin-top: 0.7rem; } } // --- Code ---------------------------------------------------------------- code, kbd, samp { font-family: var(--mono); font-variant-ligatures: none; font-feature-settings: "liga" 0, "calt" 0; } :not(pre) > code { font-size: 0.82em; background: var(--paper-raised); border: 1px solid var(--rule); border-radius: 3px; padding: 0.08em 0.26em; color: var(--ink); white-space: break-spaces; word-break: break-word; } a :not(pre) > code, :not(pre) > code:has(a) { color: inherit; } kbd { font-size: 0.78em; background: var(--paper); border: 1px solid var(--rule-strong); border-bottom-width: 2px; border-radius: 3px; padding: 0.08em 0.36em; color: var(--ink); white-space: nowrap; } // Hugo/Chroma wraps a fenced code block in
. The language tag
// is read off that data-lang attribute and floats over the block like a
// fieldset legend.
.highlight {
position: relative;
code[data-lang]::before {
@extend %chrome;
content: attr(data-lang);
position: absolute;
z-index: 1;
top: 0;
right: 0.85rem;
transform: translateY(-50%);
padding-inline: 0.4rem;
background: var(--paper);
font-size: 0.6rem;
line-height: 1;
color: var(--ink-faint);
pointer-events: none;
}
}
pre {
font-family: var(--mono);
font-size: 0.78rem;
line-height: 1.55;
background: var(--paper-raised);
border: 1px solid var(--rule);
border-left: 2px solid var(--rule-strong);
border-radius: 3px;
padding: 0.85rem 1rem;
overflow-x: auto;
tab-size: 4;
color: var(--ink);
code {
background: none;
border: 0;
padding: 0;
font-size: inherit;
color: inherit;
}
}
// --- Collapsible blocks --------------------------------------------------
.prose details {
border: 1px solid var(--rule);
border-left: 2px solid var(--rule-strong);
border-radius: 3px;
padding: 0 0.9rem;
> summary {
font-family: var(--mono);
font-size: 0.78rem;
color: var(--ink);
padding: 0.6rem 0;
cursor: pointer;
list-style: none;
display: flex;
align-items: baseline;
gap: 0.5rem;
&::-webkit-details-marker {
display: none;
}
&::before {
content: "";
width: 0;
height: 0;
border-left: 0.5rem solid var(--accent);
border-top: 0.29rem solid transparent;
border-bottom: 0.29rem solid transparent;
align-self: center;
transition: transform 0.15s ease;
display: inline-block;
}
&:hover {
color: var(--accent);
}
}
&[open] {
padding-bottom: 0.9rem;
> summary {
margin-bottom: 0.9rem;
border-bottom: 1px solid var(--rule);
color: var(--accent);
&::before {
transform: rotate(90deg);
}
}
}
.highlight {
margin-inline: -0.9rem;
}
pre {
border-inline: 0;
border-radius: 0;
}
}
@media (prefers-reduced-motion: reduce) {
.prose details > summary::before {
transition: none;
}
}
// --- Tables ----------------------------------------------------------------
.table-scroll {
overflow-x: auto;
max-width: 100%;
}
table {
border-collapse: collapse;
width: 100%;
font-size: 0.85rem;
font-variant-numeric: tabular-nums;
th,
td {
padding: 0.45rem 0.7rem;
text-align: left;
border: 0;
border-bottom: 1px solid var(--rule);
vertical-align: top;
}
th:first-child,
td:first-child {
padding-left: 0;
}
th:last-child,
td:last-child {
padding-right: 0;
}
th {
@extend %chrome;
color: var(--ink-muted);
border-bottom: 1px solid var(--rule-strong);
letter-spacing: 0.055em;
line-height: 1.35;
}
tbody tr:last-child td {
border-bottom: 0;
}
tbody tr:hover td {
background: var(--accent-wash);
}
}
// --- Figures and media -----------------------------------------------------
img,
video,
canvas,
svg {
max-width: 100%;
height: auto;
}
.prose img,
.prose video {
display: block;
max-width: min(var(--image-width, 100%), 100%);
margin-inline: auto;
border: 1px solid var(--rule);
border-radius: 3px;
background: var(--image-mat);
}
.prose a img {
border-color: var(--rule-strong);
}
iframe,
embed,
object {
max-width: 100%;
border: 0;
}
iframe[src*="youtube"],
iframe[src*="vimeo"] {
display: block;
width: 100%;
aspect-ratio: 16 / 9;
height: auto;
margin-inline: auto;
border: 1px solid var(--rule);
border-radius: 3px;
background: var(--image-mat);
}
// Goldmark's own footnote list, styled plainly — the margin-sidenote
// treatment from fzakaria.com needs a custom relocation pass this port
// does not carry.
.footnotes {
margin-top: calc(var(--step) * 2);
padding-top: var(--step);
border-top: 1px solid var(--rule);
font-size: 0.85rem;
color: var(--ink-muted);
}
// --- Alerts ------------------------------------------------------------
$alerts: (
"note": (
#0b5fa5,
#6fb2e8,
),
"tip": (
#1a7f37,
#79c98d,
),
"important": (
#7145c4,
#b79ded,
),
"warning": (
#8a6100,
#dfb051,
),
"caution": (
#b1201d,
#ec8b7f,
),
);
.alert {
--alert: var(--rule-strong);
border-left: 2px solid var(--alert);
background: var(--paper-raised);
padding: 0.85rem 1.1rem;
border-radius: 0 3px 3px 0;
color: var(--ink);
> * + * {
margin-top: 0.65rem;
}
p:first-child > strong:first-child {
@extend %chrome;
display: block;
color: var(--alert);
margin-bottom: 0.3rem;
}
:not(pre) > code {
background: transparent;
border-color: transparent;
padding: 0;
}
@each $name, $pair in $alerts {
&.alert-#{$name} {
--alert: #{list.nth($pair, 1)};
@media (prefers-color-scheme: dark) {
--alert: #{list.nth($pair, 2)};
}
}
}
}
blockquote.alert {
border-left-color: var(--alert);
color: var(--ink);
}
// --- Post header -----------------------------------------------------------
.post-header {
margin-bottom: calc(var(--step) * 1.5);
}
.post-kicker {
@extend %chrome;
display: flex;
flex-wrap: wrap;
gap: 0 0.5rem;
margin-bottom: 0.7rem;
.sep {
color: var(--rule-strong);
}
a {
color: inherit;
text-decoration: none;
border-bottom: 1px solid var(--rule-strong);
&:hover {
color: var(--accent);
border-bottom-color: var(--accent);
}
}
}
.post-title {
font-size: clamp(1.85rem, 1.3rem + 2.1vw, 2.85rem);
font-weight: 600;
line-height: 1.08;
letter-spacing: -0.025em;
text-wrap: balance;
}
.post-rule {
width: 3.5rem;
height: 2px;
background: var(--accent);
margin: 1.1rem auto 0 0;
border: 0;
}
.post-body {
margin-top: calc(var(--step) * 1.5);
}
// --- Site footer -------------------------------------------------------
.site-foot {
@extend %chrome;
margin-top: calc(var(--step) * 2.5);
padding-top: var(--step);
border-top: 1px solid var(--rule);
text-transform: none;
letter-spacing: 0.02em;
font-size: 0.7rem;
line-height: 1.75;
color: var(--ink-faint);
display: flex;
flex-wrap: wrap;
justify-content: center;
text-align: center;
gap: 0 0.5rem;
a {
color: var(--ink-muted);
text-decoration: none;
border-bottom: 1px solid var(--rule);
&:hover {
color: var(--accent);
border-bottom-color: var(--accent);
}
}
.sep {
color: var(--rule-strong);
}
.rss {
display: inline-flex;
align-items: center;
gap: 0.3rem;
border-bottom: 0;
svg {
width: 0.85em;
height: 0.85em;
fill: currentColor;
}
}
.lang-switch {
display: inline-flex;
gap: 0.5rem;
}
.lang-switch__current {
color: var(--ink-muted);
}
// Own row, so the path gets the whole measure rather than whatever is left
// over beside the RSS link.
.store-path-row {
flex-basis: 100%;
}
// A store path is a single 56-character token: broken across lines it is
// unreadable and awkward to select. Hold it on one line and let it shrink
// instead.
.store-path {
font-size: min(0.7rem, 2.3vw);
letter-spacing: 0;
white-space: nowrap;
color: inherit;
background: none;
border: 0;
padding: 0;
}
}
// --- Index ---------------------------------------------------------------
.page-index {
display: flow-root;
}
// Bio card. Floats into the margin column beside the post list; below $wide
// there is no margin column to float into, so it drops below the list
// instead (further down).
.colophon {
float: right;
width: var(--margin-col);
margin-right: calc((var(--gap) + var(--margin-col)) * -1);
margin-bottom: var(--step);
// Jumped to from the masthead; leave air above it on arrival.
scroll-margin-top: var(--step);
font-size: 0.8rem;
line-height: 1.55;
color: var(--ink-muted);
}
.colophon__avatar {
width: 100%;
max-width: 8.5rem;
border-radius: 3px;
border: 1px solid var(--rule-strong);
display: block;
margin-bottom: 0.85rem;
filter: grayscale(0.35);
transition: filter 0.3s ease;
background-size: cover;
background-position: center;
&:hover {
filter: grayscale(0);
}
}
.colophon__name {
font-weight: 600;
font-size: 0.95rem;
line-height: 1.3;
color: var(--ink);
margin-bottom: 0.35rem;
&-last {
font-weight: 500;
color: var(--ink-faint);
}
}
.colophon__bio {
margin-bottom: 1rem;
a {
text-decoration-color: var(--rule-strong);
}
}
.colophon__links {
list-style: none;
margin: 0;
padding: 0;
border-top: 1px solid var(--rule);
// The key sits above its value rather than beside it: a two-column split
// leaves too little room for an email address in monospace without
// breaking it across lines.
li {
padding-block: 0.4rem;
border-bottom: 1px solid var(--rule);
}
.key {
@extend %chrome;
display: block;
font-size: 0.6rem;
margin-bottom: 0.05rem;
}
.val {
display: block;
font-family: var(--mono);
font-size: 0.68rem;
a {
color: var(--ink-muted);
text-decoration: none;
border-bottom: 1px solid var(--rule-strong);
&:hover {
color: var(--accent);
border-bottom-color: var(--accent);
}
}
}
}
// Narrow: the float is dropped and the card moves below the article list.
@media (max-width: $wide) {
.masthead__about {
display: inline-block;
}
.page-index {
display: flex;
flex-direction: column;
}
.colophon {
float: none;
width: 100%;
margin-right: 0;
margin-bottom: 0;
margin-top: calc(var(--step) * 2);
padding-top: var(--step);
border-top: 1px solid var(--rule);
order: 3;
display: grid;
grid-template-columns: 8.5rem 1fr;
gap: 0 1.25rem;
align-items: start;
}
.colophon__avatar {
margin-bottom: 0;
grid-row: span 2;
}
.index-body {
order: 2;
}
@media (max-width: 30rem) {
.colophon {
grid-template-columns: 1fr;
gap: 1rem;
}
.colophon__avatar {
max-width: 6.5rem;
}
}
}
.index-lead {
display: block;
text-decoration: none;
margin-bottom: calc(var(--step) * 2);
padding-left: 1rem;
border-left: 2px solid var(--accent);
position: relative;
.label {
@extend %chrome;
color: var(--accent);
display: block;
margin-bottom: 0.4rem;
}
.title {
font-size: 1.5rem;
font-weight: 600;
line-height: 1.15;
letter-spacing: -0.02em;
text-wrap: balance;
display: block;
color: inherit;
text-decoration: none;
&::after {
content: "";
position: absolute;
inset: 0;
}
}
.excerpt a {
position: relative;
z-index: 1;
}
.excerpt {
display: block;
color: var(--ink-muted);
font-size: 0.92rem;
margin-top: 0.5rem;
}
.more {
@extend %chrome;
color: var(--accent);
display: block;
margin-top: 0.7rem;
}
&:hover .title {
color: var(--accent);
}
}
.year {
margin-top: calc(var(--step) * 2);
position: relative;
&:first-of-type {
margin-top: 0;
}
}
.year__label {
@extend %chrome;
font-size: 0.78rem;
color: var(--ink-faint);
padding-bottom: 0.4rem;
margin-bottom: 0.6rem;
border-bottom: 1px solid var(--rule);
display: flex;
justify-content: space-between;
align-items: baseline;
.count {
font-size: 0.66rem;
color: var(--rule-strong);
}
}
@media (min-width: $wide) {
.year__label {
position: absolute;
right: calc(100% + 0.9rem);
top: 0.1rem;
width: calc(var(--gutter) - 0.9rem);
display: block;
border-bottom: 0;
padding-bottom: 0;
margin-bottom: 0;
text-align: right;
letter-spacing: 0.04em;
.count {
display: none;
}
}
.year__list {
border-top: 1px solid var(--rule);
padding-top: 0.35rem;
}
}
.year__list {
list-style: none;
margin: 0;
padding: 0;
}
.entry {
display: grid;
grid-template-columns: 4.25rem 1fr;
gap: 0 0.85rem;
align-items: baseline;
padding-block: 0.42rem;
@media (max-width: 34rem) {
grid-template-columns: 1fr;
gap: 0.12rem;
padding-block: 0.5rem;
}
+ .entry {
border-top: 1px solid var(--rule);
}
.date {
@extend %chrome;
font-size: 0.68rem;
white-space: nowrap;
}
a {
text-decoration: none;
line-height: 1.35;
color: var(--ink);
text-decoration: underline;
text-decoration-color: transparent;
text-underline-offset: 0.17em;
}
&:hover a {
color: var(--accent);
text-decoration-color: var(--accent);
}
&:hover .date {
color: var(--accent);
}
}
// --- Motion --------------------------------------------------------------
@media (prefers-reduced-motion: no-preference) {
@keyframes rise {
from {
opacity: 0;
transform: translateY(0.5rem);
}
to {
opacity: 1;
transform: none;
}
}
.rise {
animation: rise 0.5s cubic-bezier(0.22, 0.68, 0.35, 1) backwards;
animation-delay: calc(var(--i, 0) * 60ms);
}
@keyframes signal-sweep {
to {
stroke-dashoffset: 0;
}
}
.masthead__signal path {
stroke-dasharray: 100;
stroke-dashoffset: 100;
animation: signal-sweep 1.1s cubic-bezier(0.32, 0.5, 0.3, 1) 0.18s forwards;
// Every page's signal is the same number of curve commands (32 bytes ->
// fixed M + 30 C), just different coordinates - so the browser can
// interpolate straight from one `d` to the next when htmx morphs it in
// on navigation, instead of snapping. Only fires on a same-node update;
// a fresh page load has no prior `d` to transition from.
transition: d 0.7s cubic-bezier(0.32, 0.5, 0.3, 1);
}
}
// htmx's boosted navigation wraps every swap in document.startViewTransition
// (see hx-boost:inherited in baseof.html); browsers don't honor
// prefers-reduced-motion for that on their own, so without this the default
// cross-fade would still run for anyone who has asked for less motion.
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
// --- Print -----------------------------------------------------------------
@media print {
:root {
--paper: #fff;
--paper-raised: #fff;
--ink: #000;
--ink-muted: #333;
--ink-faint: #555;
--rule: #bbb;
--rule-strong: #888;
--accent: #000;
--gutter: 0rem;
--margin-col: 0rem;
--gap: 0rem;
}
body {
background: #fff;
}
.colophon,
.skip-link {
display: none;
}
details {
border: 0;
padding: 0;
}
details > summary::before {
content: none;
}
pre,
blockquote,
details,
.alert {
break-inside: avoid;
}
a::after {
content: " (" attr(href) ")";
font-size: 0.75em;
color: #555;
}
a[href^="#"]::after {
content: "";
}
}
// ---------------------------------------------------------------------------
// Rouge/Chroma syntax theme — "Ochre" (unchanged from fzakaria.com).
// ---------------------------------------------------------------------------
:root {
--syn-comment: #6f685b;
--syn-keyword: #9a3d05;
--syn-string: #3f6b32;
--syn-number: #6b4fa8;
--syn-func: #1c5570;
--syn-type: #7a6114;
--syn-var: #7c4a2d;
--syn-punct: #6b6558;
--syn-error: #b1201d;
--syn-error-bg: #b1201d1a;
--syn-ins-bg: #1a7f3714;
--syn-del-bg: #b1201d14;
--syn-ins-fg: #1a6d33;
--syn-del-fg: #a3231f;
}
@media (prefers-color-scheme: dark) {
:root {
--syn-comment: #8d867a;
--syn-keyword: #e08a45;
--syn-string: #a6c98d;
--syn-number: #c3a2ec;
--syn-func: #7fb6d6;
--syn-type: #ddc477;
--syn-var: #dda58c;
--syn-punct: #8b857a;
--syn-error: #ec8b7f;
--syn-error-bg: #ec8b7f1f;
--syn-ins-bg: #79c98d1a;
--syn-del-bg: #ec8b7f1a;
--syn-ins-fg: #8fd0a1;
--syn-del-fg: #ef9a8f;
}
}
.highlight {
.c, .ch, .cd, .cm, .cp, .cpf, .c1, .cs {
color: var(--syn-comment);
font-style: italic;
}
.k, .kc, .kd, .kn, .kp, .kr, .kv {
color: var(--syn-keyword);
}
.kt, .nc, .nn, .no, .ne {
color: var(--syn-type);
}
.nf, .fm, .nb, .bp, .na, .nt {
color: var(--syn-func);
}
.nv, .vc, .vg, .vi, .vm, .nl, .py {
color: var(--syn-var);
}
.s, .sa, .sb, .sc, .dl, .sd, .s2, .se, .sh, .si, .sx, .s1, .ss, .sr {
color: var(--syn-string);
}
.m, .mb, .mf, .mh, .mi, .mo, .il {
color: var(--syn-number);
}
.o, .ow, .p, .pi, .ni {
color: var(--syn-punct);
}
.err {
color: var(--syn-error);
background-color: var(--syn-error-bg);
border-radius: 2px;
}
.gd {
color: var(--syn-del-fg);
background-color: var(--syn-del-bg);
}
.gi {
color: var(--syn-ins-fg);
background-color: var(--syn-ins-bg);
}
.gh, .gu {
color: var(--syn-func);
font-weight: 600;
}
.gp {
color: var(--syn-comment);
user-select: none;
}
.go {
color: var(--ink-muted);
}
.ge {
font-style: italic;
}
.gs {
font-weight: 700;
}
.gr, .gt {
color: var(--syn-error);
}
.w {
color: var(--rule-strong);
}
.lineno, .gl {
color: var(--ink-faint);
opacity: 0.6;
user-select: none;
padding-right: 0.85rem;
}
}