/* baez.us: ligne claire.
   One clean ink line, flat fills, seven colours and nothing else: no gradients, no blur,
   no transparency, no glow. Anything that "floats" sits 3px (about 1mm) above the page
   and casts a hard, flat shadow in a darker tone of the paper. The poetry page is the one
   exception to the ground: it has none, only dots (see "Poetry: the void"). */

@font-face {
  font-family: "Jost"; font-style: normal; font-weight: 100 900; font-display: swap;
  src: url("../fonts/jost-latin-wght-normal.928f4210aa48.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 400; font-display: swap;
  src: url("../fonts/jetbrains-mono-latin-400-normal.caf0dfde4e44.woff2") format("woff2");
}
@font-face {
  font-family: "JetBrains Mono"; font-style: normal; font-weight: 700; font-display: swap;
  src: url("../fonts/jetbrains-mono-latin-700-normal.69002db50656.woff2") format("woff2");
}

/* ---------- The palette ----------
   Every colour on the site is one of these roles. To restyle the whole site, change the
   values below, or add a block like [data-palette="nuit"] (see the end of this section)
   and switch to it by changing data-palette="ligne-claire" on the <html> tag in
   templates/base.html. Names with no block (like ligne-claire) just use these defaults.

     bg          the page and the panels (the paper)
     bg-2        the flat shadow, table headers, inline code, alternate balloons
     ink         every line, and all body text
     muted       dates, placeholders, small print
     primary     masthead, buttons              (text on it: on-primary)
     accent      page-title banners, hover fills (text on it: on-accent)
     link        links, list bullets, error text
     focus       decoration only: the blockquote bar
                 (keyboard focus rings use ink, so they stay visible in any palette)
     code-bg     code blocks (a dark slab in both editions)
     code-fg     code text; code-dim: comments and strings; code-hot: keywords and numbers
                 (only colours with 4.5:1 on code-bg belong in these three)
     wood        the jot blocks (text on it: soot; inline code chips on it: paper)
     dot-*       the poetry page's two layers of dots, far and mid (ink over both: 4.5:1)

   Rules for any palette (check with deploy/palette-check.py): ink, muted and link must be
   readable on bg; on-primary on primary; on-accent on accent; ink on bg-2; the three
   code-* text roles on code-bg. A palette block only needs the roles it changes. */
:root {
  --bg:         #eed5a5;
  --bg-2:       #cab588;
  --ink:        #362d23;
  --muted:      #4b572f;
  --primary:    #a33f35;
  --on-primary: #eed5a5;
  --accent:     #cf854b;
  --on-accent:  #362d23;
  --link:       #a33f35;
  --focus:      #5c9288;
  --code-bg:    #362d23;
  --code-fg:    #eed5a5;
  --code-dim:   #cab588;
  --code-hot:   #cf854b;
  --wood:       #cab588;   /* cut wood: the jot blocks. These three stay the same in both editions. */
  --soot:       #362d23;   /* ink printed on wood */
  --paper:      #eed5a5;   /* chips of paper on wood (inline code) */
  --dot-far:    #cab588;   /* the poetry page's dots: wood on paper. Warm spots (orange, red) read as a rash, */
  --dot-mid:    #cab588;   /* and big ones were too busy. Ink must stay readable over --dot-mid. */

  --line: 3px solid var(--ink);      /* structure: panels, buttons, inputs */
  --rule: 2px solid var(--ink);      /* detail: table cells, separators */
  --lift: 3px;                       /* how far a panel floats */

  --sans: "Jost", "Futura", "Century Gothic", "Avenir Next", system-ui, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, Menlo, Consolas, monospace;

  color-scheme: light;
}

/* Night edition: the same seven colours, roles reversed. */
:root[data-palette="nuit"] {
  --bg:         #362d23;
  --bg-2:       #4b572f;
  --ink:        #eed5a5;
  --muted:      #cab588;
  --primary:    #a33f35;
  --on-primary: #eed5a5;
  --accent:     #cf854b;
  --on-accent:  #362d23;
  --link:       #cf854b;
  --focus:      #5c9288;
  --dot-far:    #4b572f;   /* olive on soot */
  --dot-mid:    #4b572f;
  color-scheme: dark;
}

/* ---------- Base ---------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  background: var(--bg);
  scrollbar-color: var(--ink) var(--bg-2);
  -webkit-text-size-adjust: 100%;
}
body {
  margin: 0; min-height: 100vh; min-height: 100dvh;
  display: flex; flex-direction: column;
  background: var(--bg); color: var(--ink);
  font: 400 1.1875rem/1.65 var(--sans);
}
main { flex: 1 0 auto; }
img { max-width: 100%; height: auto; }
h1, h2, h3, h4 { margin: 0 0 0.5em; font-weight: 800; line-height: 1.12; }
p { margin: 0 0 1rem; }
strong { font-weight: 800; }

::selection { background: var(--accent); color: var(--on-accent); }
:focus-visible { outline: 3px solid var(--ink); outline-offset: 2px; }
.masthead :focus-visible { outline-color: var(--on-primary); }

a { color: var(--link); text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px; }
a:not([class]):hover { background: var(--accent); color: var(--on-accent); text-decoration-color: var(--ink); }

.wrap { width: 100%; max-width: 48rem; margin: 0 auto; padding: 0 1.25rem; }
.page { padding-top: 2.25rem; padding-bottom: 3rem; }

/* ---------- Masthead ---------- */
.masthead { background: var(--primary); border-bottom: var(--line); }
.masthead-bar { display: flex; justify-content: space-between; align-items: stretch; min-height: 3.5rem; }
.brand {
  display: flex; align-items: center;
  color: var(--on-primary); text-decoration: none;
  font-size: 1.15rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase;
}
.nav-links { display: flex; margin-right: -1.25rem; }
.nav-links a, .nav-links button {
  display: flex; align-items: center; padding: 0 1.1rem;
  color: var(--on-primary); text-decoration: none;
  font-size: 0.9rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
}
/* the day/night button looks like the links, with a rule to set it apart */
.nav-links button {
  background: none; border: 0; border-left: var(--rule); border-radius: 0; cursor: pointer;
  font-family: inherit; line-height: inherit;
}
.nav-links a:hover, .nav-links button:hover { background: var(--accent); color: var(--on-accent); }
.nav-links a[aria-current] { background: var(--bg); color: var(--ink); }

/* ---------- Headings ---------- */
.page-head { display: flex; flex-wrap: wrap; align-items: flex-start; justify-content: space-between; gap: 1rem; margin-bottom: 1.75rem; }
.page-title {
  display: inline-block; margin: 0 0 1.75rem; padding: 0.06em 0.5em 0.12em;
  background: var(--accent); color: var(--on-accent); border: var(--line);
  font-size: clamp(1.9rem, 6vw, 2.7rem); font-weight: 800; line-height: 1.15;
  letter-spacing: 0.04em; text-transform: uppercase;
}
.page-head .page-title { margin: 0; }
.post-title { margin: 0 0 0.4rem; font-size: clamp(2rem, 6vw, 2.8rem); }
.entry-title { margin: 0 0 0.3rem; font-size: 1.65rem; }
.section-title {
  margin: 2.75rem 0 1.4rem; padding-bottom: 0.4rem; border-bottom: var(--line);
  font-size: 1.15rem; letter-spacing: 0.1em; text-transform: uppercase;
}
.form-title { margin: 0 0 1.25rem; padding-bottom: 0.4rem; border-bottom: var(--line); font-size: 1.15rem; letter-spacing: 0.1em; text-transform: uppercase; }
.meta { margin: 0 0 0.9rem; color: var(--muted); font-size: 0.8rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; }
.excerpt { margin: 0; }
.panel > .post-title + .meta {            /* article header: title, date, then a ruled line */
  margin-bottom: 1.5rem; padding-bottom: 1rem; border-bottom: var(--rule);
}
.backlink { margin: 0 0 1.4rem; font-size: 0.85rem; font-weight: 700; letter-spacing: 0.08em; text-transform: uppercase; }

/* ---------- Panels (the cards, reduced to ink and paper) ---------- */
.panel, .glass {          /* .glass is the old name; about.html still uses it */
  position: relative; display: block; min-width: 0;
  margin: 0 0 1.75rem; padding: 1.5rem 1.6rem;
  background: var(--bg); color: var(--ink);
  border: var(--line); border-radius: 0;
  box-shadow: var(--lift) var(--lift) 0 var(--bg-2);
  overflow-wrap: anywhere; text-decoration: none;
}
.panel > :last-child, .glass > :last-child { margin-bottom: 0; }
.glass-tight { padding: 1rem 1.25rem; }
.is-size-5 { font-size: 1.3rem; font-weight: 600; }   /* legacy helpers used by about.html */
.mb-4 { margin-bottom: 1rem; }

a.panel:hover, a.glass:hover { transform: translate(-2px, -2px); box-shadow: 5px 5px 0 var(--accent); }
a.panel:active, a.glass:active { transform: translate(var(--lift), var(--lift)); box-shadow: none; }

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 0.4em;
  padding: 0.5em 1.1em;
  background: var(--primary); color: var(--on-primary);
  border: var(--line); border-radius: 0;
  font: 800 0.9rem/1.2 var(--sans); letter-spacing: 0.08em; text-transform: uppercase;
  text-decoration: none; cursor: pointer;
}
.btn:hover { background: var(--ink); color: var(--bg); }
.btn:active { transform: translateY(2px); }
.btn-quiet { background: var(--bg); color: var(--ink); }
.btn-quiet:hover { background: var(--accent); color: var(--on-accent); }
.post-actions { display: flex; gap: 0.75rem; margin: -0.5rem 0 2.5rem; }
.btn-small { padding: 0.3em 0.8em; font-size: 0.78rem; }
.btn:disabled, .btn:disabled:hover {
  background: var(--bg-2); color: var(--muted); border-color: var(--muted); cursor: not-allowed; transform: none;
}
.pager { display: flex; justify-content: space-between; gap: 1rem; margin-top: 0.5rem; }
.pager-next { margin-left: auto; }

/* ---------- Post body (rendered Markdown) ---------- */
.post-body { font-size: 1.1875rem; line-height: 1.75; }
.post-body > :first-child { margin-top: 0; }
.post-body > :last-child { margin-bottom: 0; }
.post-body h1, .post-body h2, .post-body h3, .post-body h4 { margin: 1.8em 0 0.5em; }
.post-body h1 { font-size: 2rem; }
.post-body h2 { font-size: 1.6rem; }
.post-body h3 { font-size: 1.3rem; }
.post-body h4 { font-size: 1rem; letter-spacing: 0.1em; text-transform: uppercase; }
.post-body p, .post-body ul, .post-body ol { margin: 0 0 1.1em; }
.post-body ul, .post-body ol { padding-left: 1.5em; }
.post-body li { margin-bottom: 0.3em; }
.post-body li::marker { color: var(--link); font-weight: 800; }
.post-body blockquote { margin: 1.5em 0; padding: 0.15em 0 0.15em 1.2em; border-left: 6px solid var(--focus); }
.post-body blockquote > :last-child { margin-bottom: 0; }
.post-body hr { margin: 2em 0; border: 0; border-top: var(--line); }
.post-body pre {
  margin: 1.5em 0; padding: 1rem 1.2rem; overflow-x: auto;
  background: var(--code-bg); color: var(--code-fg); border: var(--line);
  font: 400 0.9rem/1.6 var(--mono);
}
.post-body code { padding: 0.08em 0.35em; background: var(--bg-2); font-family: var(--mono); font-size: 0.88em; }
.post-body > .highlight:first-child > pre { margin-top: 0; }   /* a code block that opens or closes a post sits flush */
.post-body > .highlight:last-child > pre { margin-bottom: 0; }
.post-body pre code { padding: 0; background: none; font-size: inherit; }

/* Syntax highlighting (Pygments classes). Three colours plus weight and slant, because only
   cream, tan and orange stay readable on the dark slab. */
.highlight .c, .highlight .ch, .highlight .cm, .highlight .c1, .highlight .cs,
.highlight .cp, .highlight .cpf { color: var(--code-dim); font-style: italic; }
.highlight .s, .highlight .sa, .highlight .sb, .highlight .sc, .highlight .dl, .highlight .sd,
.highlight .s2, .highlight .se, .highlight .sh, .highlight .si, .highlight .sx, .highlight .sr,
.highlight .s1, .highlight .ss, .highlight .na, .highlight .gu { color: var(--code-dim); }
.highlight .k, .highlight .kc, .highlight .kd, .highlight .kn, .highlight .kp, .highlight .kr,
.highlight .kt, .highlight .ow, .highlight .nt { color: var(--code-hot); font-weight: 700; }
.highlight .m, .highlight .mb, .highlight .mf, .highlight .mh, .highlight .mi, .highlight .il,
.highlight .mo, .highlight .no, .highlight .nb, .highlight .bp, .highlight .nd,
.highlight .gi { color: var(--code-hot); }
.highlight .nf, .highlight .fm, .highlight .nc, .highlight .nn, .highlight .ne,
.highlight .gh { font-weight: 700; }
.highlight .gd { color: var(--code-hot); text-decoration: line-through; }
.highlight .err { color: inherit; background: none; border: 0; }
.post-body img { display: block; margin: 1.5em auto; border: var(--line); }
.post-body table { display: block; max-width: 100%; margin: 1.5em 0; overflow-x: auto; border-collapse: collapse; }
.post-body th, .post-body td { padding: 0.45em 0.8em; border: var(--rule); text-align: left; }
.post-body th { background: var(--bg-2); }

/* ---------- Forms ---------- */
.field { margin-bottom: 1.25rem; }
.label { display: block; margin-bottom: 0.35rem; font-size: 0.8rem; font-weight: 800; letter-spacing: 0.1em; text-transform: uppercase; }
.input, .textarea {
  display: block; width: 100%; padding: 0.6rem 0.8rem;
  background: var(--bg); color: var(--ink);
  border: var(--line); border-radius: 0; box-shadow: none;
  font: inherit; -webkit-appearance: none; appearance: none;
}
.textarea { min-height: 7rem; resize: vertical; }
#post-form .textarea { font: 400 0.95rem/1.6 var(--mono); }
.input::placeholder, .textarea::placeholder { color: var(--muted); opacity: 1; }
.input:focus, .textarea:focus, .input:focus-visible, .textarea:focus-visible {
  outline: 3px solid var(--ink); outline-offset: 3px; box-shadow: none;
}
.input.is-danger, .textarea.is-danger { border-color: var(--link); }
.textarea.is-dropping { background: var(--bg-2); border-style: dashed; }
.help { margin: 0.4rem 0 0; color: var(--muted); font-size: 0.85rem; }
.help.is-danger, #upload-status.is-danger { color: var(--link); font-weight: 700; }
.editor-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; margin-bottom: 0.6rem; }
.editor-toolbar .help { margin: 0; }
.preview-pane { min-height: 20rem; padding: 1.25rem 1.4rem; border: 3px dashed var(--focus); }

/* Honeypot: off-screen, not display:none (some bots skip fields hidden that way) */
.hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

/* The browser's [hidden] must win over anything above. */
[hidden] { display: none !important; }

/* ---------- Comments: speech balloons ---------- */
.comment { margin: 0 0 1.6rem; }
.balloon {
  position: relative; margin: 0 0 1.15rem; padding: 0.85rem 1.2rem;
  background: var(--bubble, var(--bg)); border: var(--line); border-radius: 1.1rem;
  overflow-wrap: anywhere;
}
.balloon::after {                       /* the tail: a rotated square showing two of its edges */
  content: ""; position: absolute; left: 1.7rem; bottom: -10px; width: 18px; height: 18px;
  background: var(--bubble, var(--bg));
  border-right: var(--line); border-bottom: var(--line); transform: rotate(45deg);
}
.comment.alt, .note-dialog-body .comment:nth-of-type(even) { --bubble: var(--bg-2); }

/* Replies: indented under their comment on a teal rule; a long thread folds into a <details>. */
.comment-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.6rem; margin: 0.5rem 0 0 1.2rem; }
.comment-actions .tools { margin: 0; }
.replies { margin: 0 0 1.6rem 1.2rem; padding-left: 1.1rem; border-left: 6px solid var(--focus); }
.replies > .comment:last-child, .thread > .comment:last-child { margin-bottom: 0; }
.thread > summary { list-style: none; margin-bottom: 1.4rem; }
.thread > summary::-webkit-details-marker { display: none; }
.thread[open] > summary .if-closed, .thread:not([open]) > summary .if-open { display: none; }
.thread:not([open]) > summary { margin-bottom: 0; }
.reply-note { margin: -0.6rem 0 1.25rem; }
.byline { margin: 0 0 0 1.2rem; font-size: 0.85rem; }
.who { font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; }
.trip {                                  /* tripcode badge: an ink stamp beside the name */
  margin-left: 0.6rem; padding: 0.05rem 0.4rem; vertical-align: 0.05em;
  background: var(--ink); color: var(--bg); font: 700 0.72rem/1.4 var(--mono); letter-spacing: 0.1em;
}
.when { margin-left: 0.7rem; color: var(--muted); font-weight: 500; }

/* ---------- Colophon ---------- */
.colophon { border-top: var(--line); text-align: center; }
.colorbar {                              /* the palette as a printer's colour bar */
  height: 14px; border-bottom: var(--line);
  background: linear-gradient(90deg,
    var(--bg) 0 14.286%, var(--bg-2) 0 28.571%, var(--accent) 0 42.857%, var(--primary) 0 57.143%,
    var(--ink) 0 71.429%, var(--muted) 0 85.714%, var(--focus) 0);
}
.colophon p { margin: 1.4rem 0 2rem; font-size: 0.8rem; font-weight: 600; letter-spacing: 0.14em; text-transform: uppercase; }

/* ---------- Small screens ----------
   Breakpoints are in em, not px, so they also trigger when someone raises the text size or
   zooms the page in the browser's settings, not only on narrow screens. */
@media (max-width: 37.5em) {
  body { font-size: 1.0625rem; }
  .post-body { font-size: 1.0625rem; }
  .page { padding-top: 1.5rem; }
  .panel, .glass { padding: 1.15rem 1.15rem; }
  .masthead-bar { flex-wrap: wrap; min-height: 0; }
  .brand { min-height: 3rem; }
  .nav-links { flex: 1 1 100%; flex-wrap: wrap; margin: 0 -1.25rem; border-top: var(--rule); }
  .nav-links a, .nav-links button { flex: 1 1 auto; justify-content: center; padding: 0.7rem 0.3rem; font-size: 0.78rem; letter-spacing: 0.06em; }
  .nav-links > * + * { border-left: var(--rule); }
}


/* ---------- Poetry: the void ----------
   No ground, no boxes. Two grids of dots at two distances: the farther the grid, the finer
   and slower it is. The title is plain type, in ink. The dots keep to the page's own
   tones (wood on paper, olive on soot). */
.void {
  --dot: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Ccircle cx='4' cy='4' r='0.64'/%3E%3Ccircle cx='12' cy='12' r='0.64'/%3E%3C/svg%3E");
  background: transparent;                /* let the fixed field show through the page */
}
.dotfield {
  position: fixed; inset: 0; z-index: -1; overflow: hidden; pointer-events: none;
}
.dotfield span {
  position: absolute; left: 0; right: 0; top: 0;
  height: calc(100% + 2 * var(--pitch));  /* slack for the scroll shift and the drift */
  background: var(--tone);
  -webkit-mask-image: var(--dot); mask-image: var(--dot);
  -webkit-mask-size: var(--pitch) var(--pitch); mask-size: var(--pitch) var(--pitch);
  translate: 0 calc(-1 * mod(var(--scroll, 0px) * var(--rate), var(--pitch)));
  will-change: translate, transform;
}
/* One tile, two scales: small dots, wide grids. Rates follow the scale (a tile of 300px of scroll per
   px of travel), and every grid drifts one tile per --cycle, so the mid grid is the quicker one. */
.dotfield .far  { --pitch: 0.875rem; --rate: 0.04; --cycle: 70s; --tone: var(--dot-far); }
.dotfield .mid  { --pitch: 4.5rem;   --rate: 0.19; --cycle: 40s; --tone: var(--dot-mid); }
@keyframes drift { to { transform: translateY(calc(-1 * var(--pitch))); } }
@media (prefers-reduced-motion: no-preference) {
  .dotfield span { animation: drift var(--cycle) linear infinite; }
}

.void-title {                            /* the same size as every other page title, but with no banner or box */
  margin: 0.5rem 0 1.25rem; color: var(--ink); text-align: center;
  font-size: clamp(1.9rem, 6vw, 2.7rem); font-weight: 800; line-height: 1.15;
  letter-spacing: 0.04em; text-transform: uppercase;
}

/* ---------- Poetry: the line of time ----------
   One line grows down from the title, a month to a rem, newest at the top. It starts as a column of fine
   dots whose gaps close until it is a line. Each poem hangs off it by two arcs ending in a dot; the text
   sits beside the dot, with no shape around it. poetry/timeline.py decides every position; timeline.js
   draws the line, the arcs and the dots as you scroll. Written for the right-hand side and for phones
   (the line near the left edge, year labels in the gutter, every poem to its right, so they need more
   room: --yn and --span-n); wider screens centre the line and mirror the odd poems to its left
   (--y and --span). Both come from poetry/timeline.py. A year label moves to whichever side has no
   poem beside it. */
.timeline {
  --spine: 2.8rem; --h: 2.25rem; --dots: 3.275rem; --gap: 0.9rem;   /* phones: year labels in the gutter at the left */
  position: relative; height: var(--span-n); margin: 0 0 6rem;
}
.spine {
  position: absolute; top: 0; left: var(--spine); width: 2px; margin-left: -1px;
  height: var(--drawn, var(--span-n)); overflow: hidden;
}
.spine-in { position: relative; width: 2px; height: var(--span-n); }
.spine-dots { display: block; width: 2px; height: 3.375rem; fill: var(--ink); }
.spine-line { position: absolute; left: 0; right: 0; top: var(--dots); bottom: 0; background: var(--ink); }

.years, .nodes { position: absolute; inset: 0; margin: 0; padding: 0; list-style: none; }
.year {                                  /* to the left of the line unless a wide screen says otherwise */
  position: absolute; top: var(--yn); right: calc(100% - var(--spine) + 0.75rem); transform: translateY(-50%);
  font-size: 0.72rem; font-weight: 700; letter-spacing: 0.14em; color: var(--muted);
}
.year::before {                          /* a tick across the line */
  content: ""; position: absolute; right: -0.75rem; top: 50%; width: 0.5rem; height: 2px; margin-top: -1px; background: var(--ink);
}

.node { --dd: calc(var(--d) * 0.6 + 1.25rem); position: absolute; top: var(--yn); left: 0; right: 0; height: 0; }
.petal {
  position: absolute; left: var(--spine); width: var(--dd); height: var(--h); overflow: visible; pointer-events: none;
  fill: none; stroke: var(--ink); stroke-width: 2px;
}
.petal path { vector-effect: non-scaling-stroke; }
.petal.in  { top: calc(-1 * var(--h)); }
.petal.out { top: 0; }
.dot {
  position: absolute; top: 0; left: calc(var(--spine) + var(--dd)); width: 0.5rem; height: 0.5rem;
  margin: -0.25rem 0 0 -0.25rem; border-radius: 50%; background: var(--ink);
}
.leaf {
  position: absolute; top: 0; transform: translateY(-50%);
  left: calc(var(--spine) + var(--dd) + var(--gap));
  max-width: min(15rem, calc(100% - var(--spine) - var(--dd) - var(--gap) - 0.5rem));
}
.leaf .entry-title { margin: 0 0 0.15rem; font-size: 1.2rem; line-height: 1.2; }
.leaf .entry-title a { color: var(--ink); text-decoration-color: var(--link); }
.leaf p { margin: 0; }
.leaf .meta { font-size: 0.78rem; }
.leaf .when { font-size: 0.82rem; color: var(--muted); }

@media (min-width: 37.51em) and (hover: hover) {   /* wide, and a mouse; touch screens use the phone layout at any width */
  .timeline { --spine: 50%; height: var(--span); }
  .spine { height: var(--drawn, var(--span)); }
  .spine-in { height: var(--span); }
  .year, .node { top: var(--y); }
  .year.right { right: auto; left: calc(var(--spine) + 0.75rem); }
  .year.right::before { right: auto; left: -0.75rem; }
  .node { --dd: var(--d); }
  .node.left .petal { left: calc(var(--spine) - var(--dd)); transform: scaleX(-1); }
  .node.left .dot { left: calc(var(--spine) - var(--dd)); }
  .node.left .leaf {
    left: auto; right: calc(100% - var(--spine) + var(--dd) + var(--gap)); text-align: right;
    max-width: min(15rem, calc(var(--spine) - var(--dd) - var(--gap) - 0.5rem));
  }
  .node.right .leaf { max-width: min(15rem, calc(100% - var(--spine) - var(--dd) - var(--gap) - 0.5rem)); }
}

/* Drawn as you scroll (timeline.js feeds --drawn, --p1 and --p2); a wipe from the top draws an arc in order
   (nothing is left showing at zero, and the ends sit under the line and the dot). */
@media (prefers-reduced-motion: no-preference) {
  html.draws .spine { height: var(--drawn, 0px); }
  html.draws .petal.in  { clip-path: inset(0 -4px calc((1 - var(--p1, 0)) * 100%) -4px); }
  html.draws .petal.out { clip-path: inset(0 -4px calc((1 - var(--p2, 0)) * 100%) -4px); }
  html.draws .node:not(.is-reached) .dot, html.draws .year:not(.is-reached) { visibility: hidden; }
}
.void-note { font-size: 1.1rem; text-align: center; }

/* ---------- Poetry: the cover ----------
   Pixel art, scaled by whole multiples so every pixel stays square (round() snaps the width to one; the first
   width is for browsers without it). With a mouse it appears beside the poem's title while the title is hovered or
   focused, across the line from the poem where the page is empty (so it never meets the sidebar and always fits).
   Where there is no hover it sits under the poem's text, and timeline.py leaves room for it. */
.cover { display: block; margin-top: 0.55rem; }
.cover img {
  display: block; width: auto; height: calc(var(--h, 32) * 3px); max-height: 7rem; max-width: 100%;
  image-rendering: pixelated;
}
@supports (height: round(down, 1px, 1px)) {
  .cover img { height: max(calc(var(--h, 32) * 1px), round(down, 7rem, calc(var(--h, 32) * 1px))); }
}
@media (min-width: 37.51em) and (hover: hover) {
  .cover {
    position: absolute; top: 50%; z-index: 2; margin: 0; padding: 0.45rem; transform: translateY(-50%);
    background: var(--bg); border: var(--line); box-shadow: var(--lift) var(--lift) 0 var(--bg-2);
    visibility: hidden; opacity: 0; pointer-events: none;
  }
  .cover img { height: calc(var(--h, 32) * 5px); max-height: 15rem; max-width: 11rem; }
  .node.right .cover { right: calc(100% + var(--dd) + var(--gap) + 1.5rem); }   /* across the line, where it is empty */
  .node.left .cover  { left: calc(100% + var(--dd) + var(--gap) + 1.5rem); }
  .leaf:has(.entry-title a:hover, .entry-title a:focus-visible) .cover { visibility: visible; opacity: 1; }
  .node:has(.entry-title a:hover, .entry-title a:focus-visible) { z-index: 3; }
}
@supports (height: round(down, 1px, 1px)) {
  @media (min-width: 37.51em) and (hover: hover) {
    .cover img { height: max(calc(var(--h, 32) * 1px), round(down, 11rem, calc(var(--h, 32) * 1px))); }
  }
}
@media (min-width: 37.51em) and (hover: hover) and (prefers-reduced-motion: no-preference) {
  .cover { transition: opacity 0.12s linear, visibility 0.12s linear; }
}

/* ---------- The sidebar ----------
   A block of wood, the same as a jot, for moving around one page. It hangs in the left margin on a wide screen
   and follows you down; on a narrower one it folds into a block above the page. On the poetry page it is the one
   square thing in the dots: the working world, still in the room. */
.rail-wrap { --ground: var(--bg-2); }
.rail-wide { display: none; }
.rail-fold { margin: 0 0 1.75rem; }
.rail {
  --bg: var(--wood); --bg-2: var(--paper); --ink: var(--soot); --muted: var(--soot); --link: var(--soot);
  --line: 3px solid var(--soot); --rule: 2px solid var(--soot);
  position: relative; min-width: 0; padding: 0.85rem 0.8rem 0.7rem 1.75rem;
  background: var(--wood); color: var(--soot); border: 3px solid var(--soot); border-radius: 0;
  font-size: 0.9rem; line-height: 1.3;
}
.rail::before {                          /* the sawn end of the log */
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 0.8rem;
  background: var(--accent); border-right: 3px solid var(--soot);
}
.rail::after {                           /* its shadow on the ground, 3px clear of the block */
  content: ""; position: absolute; top: calc(100% + 3px); left: 0.6rem; right: 0.6rem; height: 4px; background: var(--ground);
}
.rail-title, .rail summary {
  margin: 0 0 0.6rem; padding: 0.05em 0.5em; background: var(--paper); border: 2px solid var(--soot);
  font-size: 0.78rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase;
}
.rail summary { margin: 0; cursor: pointer; list-style: none; }
.rail summary::-webkit-details-marker { display: none; }
.rail summary::after { content: "+"; float: right; }
.rail[open] summary { margin-bottom: 0.6rem; }
.rail[open] summary::after { content: "\2212"; }
.rail-list { margin: 0; padding: 0; list-style: none; }
.rail-list li { margin: 0 0 0.3rem; }
.rail-list li.sub { margin-left: 0.8rem; }
.rail-list span {                        /* two lines at most; the whole text is in the page it points to */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; overflow: hidden; min-width: 0;
}
.rail-list .stack a { flex-direction: column; align-items: flex-start; gap: 0.1rem; }   /* the note goes under the name */
.rail-list a {
  display: flex; justify-content: space-between; align-items: baseline; gap: 0.6rem;
  padding: 0.2rem 0.5rem; background: var(--paper); color: var(--soot); border: 2px solid var(--soot);
  font-weight: 700; text-decoration: none; overflow-wrap: anywhere;
}
.rail-list a:hover { background: var(--accent); color: var(--on-accent); }
.rail-list a[aria-current] { background: var(--primary); color: var(--on-primary); }
.rail-list small { flex: none; font-size: 0.72rem; font-weight: 800; letter-spacing: 0.08em; }
.rail-fold .rail-list { max-height: 14rem; overflow-y: auto; }
.rail :focus-visible { outline-color: var(--soot); }
.rail-list a[aria-current]:focus-visible { outline-color: var(--soot); }
.post-body :is(h2, h3), #comments, .jot { scroll-margin-top: 1.25rem; }
.node[id] { scroll-margin-top: 5rem; }
@media (min-width: 75em) {                                        /* 48rem of page and 13rem each side */
  .page { position: relative; }
  .rail-wide { display: block; position: absolute; top: 0; bottom: 0; right: calc(100% + 0.5rem); width: 12.5rem; }
  .rail-wide .rail { position: sticky; top: 1.25rem; margin-top: 0.4rem; }
  .rail-wide .rail-list { max-height: calc(100vh - 8.5rem); max-height: calc(100dvh - 8.5rem); overflow-y: auto; margin: -3px; padding: 3px; }   /* a long list scrolls inside the block */
  .rail-fold { display: none; }
}

/* ---------- Home: a frame, one colour, and the heart ---------- */
.sr-only {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden;
  clip-path: inset(50%); white-space: nowrap; border: 0;
}
.home main.page {                        /* the frame takes the whole window, between the bar above and the footer below */
  display: flex; max-width: none; padding: clamp(0.75rem, 3.5vmin, 2.25rem); padding-bottom: calc(clamp(0.75rem, 3.5vmin, 2.25rem) + 8px);
}
.home-frame {
  position: relative; flex: 1 1 auto; min-height: 10rem; display: grid; place-items: center;
  background: var(--wood); border: 3px solid var(--soot); border-radius: 0;
}
.home-frame::after {                     /* the frame floats: its shadow is 3px clear of it */
  content: ""; position: absolute; top: calc(100% + 3px); left: 0.6rem; right: 0.6rem; height: 4px; background: var(--bg-2);
}
.home-heart {                            /* whole multiples of the sprite's own 32 pixels (the heart is the middle half of it), so none is ever smeared */
  display: block; width: 256px; height: auto; max-width: none; image-rendering: pixelated;
}
@supports (width: round(down, 1px, 1px)) {
  .home-heart { width: max(64px, round(down, 44vmin, 32px)); }
}

/* ---------- Linux: the cabinet, seen straight on ---------- */
.jots-intro > :last-child { margin-bottom: 0; }
.cabinet {
  display: grid; grid-template-columns: 1fr 1fr; gap: 0.7rem;
  margin: 0 0 1.75rem; padding: 0.7rem; list-style: none;
  background: var(--code-bg); border: var(--line); box-shadow: var(--lift) var(--lift) 0 var(--bg-2);
}
.drawer {                                /* a drawer front: red face, long handle, label plate */
  position: relative; display: flex; flex-direction: column; align-items: flex-start; justify-content: flex-end; gap: 0.35rem;
  height: 100%; min-height: 8rem; padding: 2.4rem 1rem 0.9rem;
  background: var(--primary); color: var(--on-primary); border: 3px solid var(--code-fg);
  text-decoration: none;
}
.drawer:hover { background: var(--accent); color: var(--on-accent); }
.drawer:active { transform: translateY(2px); }
.drawer:focus-visible { outline-color: var(--code-fg); }
.drawer-handle {
  position: absolute; top: 0.7rem; left: 50%; width: 55%; height: 0.8rem; transform: translateX(-50%);
  background: var(--code-fg); border: 3px solid var(--code-bg);
}
.drawer-label {
  padding: 0.05em 0.55em; max-width: 100%;
  background: var(--code-fg); color: var(--code-bg); border: 3px solid var(--code-bg);
  font-size: 1.1rem; font-weight: 800; line-height: 1.3; letter-spacing: 0.1em; text-transform: uppercase;
  overflow-wrap: anywhere;
}
.drawer-count { font-size: 0.8rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; }

/* ---------- Jots: blocks of cut wood, each floating 1 mm above the ground ---------- */
.blocks { --ground: var(--bg-2); display: grid; gap: 1.9rem; margin-bottom: 1.75rem; }
.block {
  --bg: var(--wood); --bg-2: var(--paper); --ink: var(--soot); --muted: var(--soot); --link: var(--soot);
  --line: 3px solid var(--soot); --rule: 2px solid var(--soot);
  position: relative; min-width: 0; padding: 1.3rem 1.5rem 1.2rem 2.4rem;
  background: var(--wood); color: var(--soot);
  border: 3px solid var(--soot); border-radius: 0; overflow-wrap: anywhere;
}
.block::before {                         /* the sawn end of the log */
  content: ""; position: absolute; top: 0; bottom: 0; left: 0; width: 0.95rem;
  background: var(--accent); border-right: 3px solid var(--soot);
}
.block::after {                          /* its shadow on the ground: 3px (1 mm) clear of the block */
  content: ""; position: absolute; top: calc(100% + 3px); left: 0.6rem; right: 0.6rem; height: 4px;
  background: var(--ground);
}
.jot-body > :first-child { margin-top: 0; }
.jot-body > :last-child { margin-bottom: 0; }
.jot > .byline { margin: 0.9rem 0 0; }
.jot > .byline .when { margin-left: 0; }   /* the jot's own date, not the notes' bylines */
.note-count { margin-left: 0.7rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; }
.note-form { margin: 0; }

/* The pop-up: notes and the new-note form, flat and front-on in the middle of the screen. */
html:has(dialog[open]) { overflow: hidden; }
.note-dialog {
  width: min(34rem, calc(100vw - 1.5rem)); max-height: calc(100vh - 1.5rem); max-height: calc(100dvh - 1.5rem);
  margin: auto; padding: 0; overflow: hidden;
  background: var(--bg); color: var(--ink); border: var(--line); border-radius: 0;
  box-shadow: var(--lift) var(--lift) 0 var(--bg-2);
}
.note-dialog[open] { display: flex; flex-direction: column; }
.note-dialog::backdrop {                 /* ink hatching over the page instead of a see-through tint */
  background: repeating-linear-gradient(45deg, transparent 0 9px, var(--ink, #362d23) 9px 10px);
}
.note-dialog-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex: none;
  padding: 0.6rem 1rem 0.6rem 1.25rem;
  background: var(--accent); color: var(--on-accent); border-bottom: var(--line);
}
.note-dialog-title { margin: 0; font-size: 1rem; letter-spacing: 0.1em; text-transform: uppercase; }
.note-dialog-body { min-height: 0; padding: 1.25rem 1.25rem 1.1rem; overflow-y: auto; overscroll-behavior: contain; }
.note-dialog-body > :last-child, .note-dialog-body > .comment:last-child { margin-bottom: 0; }
.note-dialog .balloon { white-space: pre-line; }
.note-dialog .meta { margin-bottom: 0.5rem; }
.note-dialog .textarea { min-height: 5rem; }

/* A highlighted passage: flat orange, underlined; ink when open. */
mark.note {
  background: var(--accent); color: var(--on-accent); cursor: pointer;
  text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 3px;
}
mark.note:hover, mark.note.is-open { background: var(--ink); color: var(--bg); }

/* The bar that offers "Annotate" while text is selected. */
.dock { position: fixed; left: 0; right: 0; bottom: 0; z-index: 20; background: var(--bg); border-top: var(--line); }
.dock-bar { display: flex; align-items: center; justify-content: space-between; gap: 1rem; padding-top: 0.7rem; padding-bottom: 0.7rem; font-weight: 700; }

/* ---------- Admin tools (only ever rendered for admins) ---------- */
.tools { margin: 0.5rem 0 0 1.2rem; }
.block > .tools { margin-left: 0; }
.btn.is-armed { background: var(--primary); color: var(--on-primary); }
.note-delete { margin-top: 0.5rem; }
.hl-toggle { margin-left: 0.7rem; vertical-align: 0.1em; }
@media (max-width: 37.5em) { .hl-toggle { display: block; margin: 0.4rem 0 0; } }
@media (max-width: 30em) {
  .cabinet { grid-template-columns: 1fr; }
  .block { padding: 1.1rem 1.1rem 1rem 2.1rem; }
}

/* ---------- Poetry: an entry that holds several poems, and the years of a programme ----------
   A batch of poems (a chapbook, a folio) lists its poems across the line from its title, centred on the title, with its
   cover (if it has one) above the list. With a mouse the list is shown while the entry is hovered or focused, and the
   entry's two arcs open out to run past both ends of it as it appears; the room for all of it is always kept
   (poetry/timeline.py), so nothing else moves. Where there is no hover the list simply sits under the text and the arcs
   are open all the time. Each title has the heart for a bullet, so a title that runs to two lines is still one item.
   The titles are nearly as large as the entry's own, and start further from the line than a year label reaches. */
.node { --arc: var(--arcn, var(--h)); }                  /* the two arcs are as long as the entry needs (--arcn, --arcw) */
.petal { height: var(--arc); }
.petal.in { top: calc(-1 * var(--arc)); }
.contents { margin-top: 0.6rem; }
.pieces {
  /* the heart is a 16 x 15 piece of the middle of heart.png (a 32 x 32 sprite): one pixel of it is one pixel of the page.
     Change these four if the sprite changes. */
  --heart-w: 16px; --heart-h: 15px; --heart-x: -8px; --heart-y: -9px;
  margin: 0; padding: 0; list-style: none; font-size: 1.1rem; line-height: 1.3; color: var(--ink);
}
.pieces li { position: relative; padding-left: calc(var(--heart-w) + 0.5rem); }
.pieces li + li { margin-top: 0.2rem; }
.pieces li::before {
  content: ""; position: absolute; left: 0; top: calc(0.715rem - var(--heart-h) / 2);   /* centred on the first line, however many there are */
  width: var(--heart-w); height: var(--heart-h);
  background: url("../img/heart.e98c0071ab82.png") var(--heart-x) var(--heart-y) / 32px 32px no-repeat; image-rendering: pixelated;
}
.cover-in { display: block; margin-top: 0.55rem; }
.cover-in img {
  display: block; width: auto; height: calc(var(--h, 32) * 3px); max-height: 7rem; max-width: 100%;
  image-rendering: pixelated;
}
@supports (height: round(down, 1px, 1px)) {
  .cover-in img { height: max(calc(var(--h, 32) * 1px), round(down, 7rem, calc(var(--h, 32) * 1px))); }
}
.cover-in + .pieces { margin-top: 0.6rem; }
@media (min-width: 37.51em) and (hover: hover) {
  .node { --arc: var(--h); }                                                    /* shut: as long as any entry's */
  .node.listed:has(.leaf:hover, .entry-title a:focus-visible) { --arc: var(--arcw, var(--h)); }   /* open: past both ends of the list */
  .contents {
    position: absolute; z-index: 2; margin: 0; width: max-content; max-width: min(15rem, calc(50vw - 4.9rem));
    bottom: calc(50% - var(--L) / 2);                     /* the list is centred on the entry; a cover grows upward from it */
    opacity: 0; pointer-events: none;
  }
  .node.right .contents { right: calc(100% + var(--dd) + var(--gap) + 4.4rem); text-align: right; }   /* across the line */
  .node.left  .contents { left:  calc(100% + var(--dd) + var(--gap) + 4.4rem); text-align: left; }
  .node.right .pieces li { padding-left: 0; padding-right: calc(var(--heart-w) + 0.5rem); }          /* the heart on the outer edge, as the text is */
  .node.right .pieces li::before { left: auto; right: 0; }
  .cover-in {
    width: fit-content; margin: 0 0 0.6rem; padding: 0.45rem;
    background: var(--bg); border: var(--line); box-shadow: var(--lift) var(--lift) 0 var(--bg-2);
  }
  .node.right .cover-in { margin-left: auto; }
  .cover-in img { height: calc(var(--h, 32) * 5px); max-height: 15rem; max-width: 11rem; }
  .cover-in + .pieces { margin-top: 0; }
  .pieces { min-height: var(--L); display: flex; flex-direction: column; justify-content: center; }   /* the estimate may run long: centre the titles in it */
  .node:has(.leaf:hover, .entry-title a:focus-visible) .contents { opacity: 1; }
  .node:has(.leaf:hover, .entry-title a:focus-visible) { z-index: 3; }
}
@supports (height: round(down, 1px, 1px)) {
  @media (min-width: 37.51em) and (hover: hover) {
    .cover-in img { height: max(calc(var(--h, 32) * 1px), round(down, 11rem, calc(var(--h, 32) * 1px))); }
  }
}
@media (min-width: 37.51em) and (hover: hover) and (prefers-reduced-motion: no-preference) {
  .petal { transition: top 0.3s cubic-bezier(0.2, 0.8, 0.3, 1), height 0.3s cubic-bezier(0.2, 0.8, 0.3, 1); }   /* the arcs open as the list appears */
  .contents { transition: opacity 0.3s ease-out; }
}

/* The years of a programme: the line changes colour (it is no thicker) between the month the programme began and the
   month it ended. --link is the red of the day edition and the orange of the night edition, so it reads on either
   paper. Drawn with the line as you scroll (timeline.js feeds --drawn). */
.stretch {
  position: absolute; left: var(--spine); width: 2px; margin-left: -1px; pointer-events: none;
  top: var(--yn0); height: calc(var(--yn1) - var(--yn0)); background: var(--link);
}
.node.program .dot { background: var(--link); }                /* the entry for the years is in their colour too */
.node.program .petal { stroke: var(--link); }
@media (min-width: 37.51em) and (hover: hover) {
  .stretch { top: var(--y0); height: calc(var(--y1) - var(--y0)); }
}
@media (prefers-reduced-motion: no-preference) {
  html.draws .stretch { height: clamp(0px, calc(var(--drawn, 0px) - var(--yn0)), calc(var(--yn1) - var(--yn0))); }
}
@media (prefers-reduced-motion: no-preference) and (min-width: 37.51em) and (hover: hover) {
  html.draws .stretch { height: clamp(0px, calc(var(--drawn, 0px) - var(--y0)), calc(var(--y1) - var(--y0))); }
}
