/* The blog and the plain pages (About, Contact, FAQ, Locations, Privacy).

   Nothing here is designed for the blog. Every element is one the homepage
   (index.html) already has, with its values copied, not approximated; the
   comment above each block names the rule it comes from. The only rules of
   the blog's own are layout (columns, gaps, widths) and article text that the
   homepage has no counterpart for, and those are built from the homepage's
   type scale (24 / 14 / 12 / 10px, weights 400 and 500), its surfaces and its
   hairlines. No red, no accent.

   Two sizes are the blog's own, because an article is read for minutes and
   the homepage's text is glanced at: running text is 16px (--read), and the
   page titles grow with the window up to the homepage's 42px.

     titles            .story__title        24px / 500 / 1.4 / -0.02em
     body              .description         14px / 400 / 1.65
     reading text      (the blog's)         16px / 400 / 1.7
     secondary text    .story__quote        14px, ink-secondary
     small text        .projects__count     12px, ink-secondary (the homepage's
                                            ink-tertiary is 2.5:1 on white, too
                                            faint to read; this is 5:1)
     attributions      .story__attr         11px, uppercase (one step up from
                                            the homepage's 10px, for reading)
     pills             .ai-chip             white, hairline, resting shadow (a label: no shadow)
     selected pill     .bk-opt.is-on        5% ink wash, ink border
     arrow buttons     .nav-btn             the half-totem point
     cards             .tile                panel, 30px squircle, no border
     boxes             .booking-card        card, hairline, 12px, resting shadow
     notes, code       .chat-bubble         #f6f6f4, 8px
     link rows         .pop__row            About's links
     arriving          .reveal / settle     10px rise, 0.7s, --ease-soft (cards only, no fade)

   Every page is one column, --max wide and centred: the header, the
   listing, the post's three columns and the footer all stop at its edges,
   and what slides sideways (the featured row, the tabs, tables, code)
   scrolls inside it. Where a post or a page falls to a single column, its
   words and boxes keep the reading measure, centred in that column; only
   grids of cards span it. A short page still ends at the window's foot.

   Generated pages link this as /blog.css?v=N -- bump N when it changes. */

/* index.html @font-face: the same self-hosted files in /fonts (Google's own
   v20 woff2s), the same rules, latin and latin-ext only. One difference:
   Inter is 400 700 here where the homepage says 400 600, because the blog
   asked Google for 400..700 (a <strong> in a plain page is 700). Google
   served the same two files for both ranges -- the full variable font, wght
   100 to 900 -- so only the descriptor changes. The generated pages preload
   the latin Inter file, as the homepage does. */
/* latin-ext */
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/fonts/ibm-plex-mono-v20-400-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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 400; font-display: swap;
  src: url(/fonts/ibm-plex-mono-v20-400-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;
}
/* latin-ext */
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 500; font-display: swap;
  src: url(/fonts/ibm-plex-mono-v20-500-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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'IBM Plex Mono'; font-style: normal; font-weight: 500; font-display: swap;
  src: url(/fonts/ibm-plex-mono-v20-500-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;
}
/* latin-ext */
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url(/fonts/inter-v20-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-20C4, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* latin */
@font-face {
  font-family: 'Inter'; font-style: normal; font-weight: 400 700; font-display: swap;
  src: url(/fonts/inter-v20-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;
}

:root {
  /* index.html :root */
  --font-main: 'Inter', -apple-system, 'SF Pro Text', sans-serif;
  --font-mono: 'IBM Plex Mono', ui-monospace, SFMono-Regular, Menlo, monospace;
  --paper: #ffffff;
  --panel: #fafafa;
  --card: #fcfcfb;
  --ink: #181817;
  --ink-secondary: #6e6d68;
  --ink-tertiary: #a5a49e;
  --ink-tertiary-text: #75746e;
  --hairline: rgba(24, 24, 23, 0.08);
  --hairline-strong: rgba(24, 24, 23, 0.16);
  --shadow-rest: 0 1px 2px rgba(24, 24, 23, 0.04), 0 4px 14px rgba(24, 24, 23, 0.04);
  --shadow-hover: 0 1px 2px rgba(24, 24, 23, 0.05), 0 8px 24px rgba(24, 24, 23, 0.08);
  --ease-soft: cubic-bezier(0.32, 0.72, 0, 1);
  --ease-exit: cubic-bezier(0.33, 1, 0.68, 1);
  --ease-move: cubic-bezier(0.4, 0, 0.2, 1);
  --t-fast: 160ms;
  --press-lg: 0.97;
  --press-sm: 0.92;
  /* index.html .pop */
  --pop-spring: linear(0, 0.042, 0.145, 0.277, 0.418, 0.554, 0.675, 0.778, 0.861, 0.925, 0.971, 1.003, 1.023, 1.034, 1.038, 1.038, 1.035, 1.03, 1.025, 1.019, 1.014, 1.01, 1.007, 1.004, 1.002, 1, 0.999, 0.999, 0.999, 0.999, 0.999, 0.999, 1);

  /* the page's one width: a post's three columns with the article at the
     reading measure (240 + 44 + 560 + 44 + 312). Wider windows get margin,
     not wider content */
  --max: 1200px;
  --gutter: 32px;
  --wrap: calc(var(--max) + 2 * var(--gutter));
  --read: 16px;
  /* the reading measure, about 70 characters of --read text a line. Running
     text keeps it at every width (an article, a page's words and the boxes
     in their column); a window with room to spare leaves it as margin */
  --measure: 560px;
}

/* index.html html, body, ::selection, :focus-visible */
* { box-sizing: border-box; }
html {
  font-family: var(--font-main);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  font-feature-settings: 'cv05' 1, 'cv11' 1;
  letter-spacing: -0.008em;
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}
body { margin: 0; background: var(--paper); color: var(--ink); font-size: 14px; line-height: 1.65; }
/* a backstop only: nothing on these pages is wider than the window (the
   column, the sliding rows and the closed menu each hold their own edge).
   The page is at least the window's height and the main part takes what is
   left, so on a short page the footer rests at the foot of the window, not
   partway up it with blank paper below */
body.blog { overflow-x: clip; display: flex; flex-direction: column; min-height: 100vh; min-height: 100svh; }
body.blog > main { flex: 1 0 auto; }
::selection { background: var(--ink); color: var(--paper); }
:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; border-radius: 4px; }
img { max-width: 100%; display: block; }
a { color: inherit; }
h1, h2, h3, h4, p { margin-top: 0; }

/* index.html .booking-card__btn, as the skip link */
.skip {
  position: absolute; left: 16px; top: -48px; z-index: 100;
  padding: 5px 14px; border-radius: 9px; background: var(--ink); color: var(--paper);
  font-size: 12px; font-weight: 500; line-height: 1.6; text-decoration: none; transition: top var(--t-fast) var(--ease-soft);
}
.skip:focus { top: 12px; }
/* there for a screen reader (a list's heading, what the tabs and Copy link
   just did), not drawn */
.vh {
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; border: 0;
  overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

.b-wrap { max-width: var(--wrap); margin: 0 auto; padding: 0 var(--gutter); }
body.blog main { padding-bottom: 24px; }

/* ─────────────── arriving: index.html @keyframes settle / .reveal ───────────────
   Only cards arrive (the listing's, the featured row's, More articles, the
   About tiles): text, headings, tables and figures are simply there, so a
   reader scrolling an article never meets a blank screen. And a card that
   has not arrived is still there to read: it waits 10px low, at full
   opacity, and rises into place as it scrolls in, in reading order
   (blog.js sets the order). The homepage's settle, without its fade. What
   is on screen when the page opens is still from the first paint. */
@keyframes rise {
  from { transform: translateY(10px); }
  to   { transform: none; }
}
[data-reveal].is-later:not(.is-in) { transform: translateY(10px); }
[data-reveal].is-in:not(.is-settled) { animation: rise 0.7s var(--ease-soft) both; animation-delay: var(--rd, 0ms); }
@media (prefers-reduced-motion: reduce) {
  [data-reveal].is-later:not(.is-in) { transform: none; }
  [data-reveal].is-in { animation: none; }
}

/* ─────────────── the gliding hover pill ───────────────
   One element per container, moved by blog.js to the row under the pointer. Its
   fill and motion are the homepage menu's (index.html .pop__pill). */
[data-glide] { position: relative; isolation: isolate; }
.glide {
  position: absolute; left: 0; top: 0; z-index: -1; width: 0; height: 0;
  border-radius: var(--glide-r, 12px); background: rgba(24, 24, 23, 0.045);
  opacity: 0; pointer-events: none;
  transition: transform 260ms var(--pop-spring), width 260ms var(--pop-spring), height 260ms var(--pop-spring), opacity 120ms ease-out;
}
.glide.is-on { opacity: 1; }
.glide.is-snap { transition: opacity 120ms ease-out; }

/* ─────────────── header: index.html .logo, .brand ─────────────── */
.site-header__inner { max-width: var(--wrap); margin: 0 auto; padding: 32px var(--gutter) 0; }
.brand { display: flex; align-items: center; width: fit-content; }
.logo {
  display: flex; align-items: center; gap: 7.2px; width: fit-content; z-index: 60;
  color: var(--ink); text-decoration: none; cursor: pointer;
  -webkit-tap-highlight-color: transparent; user-select: none;
}
.logo__totem-seat { position: relative; display: inline-block; width: 33.1px; height: 33.1px; flex-shrink: 0; }
.logo__icon { position: absolute; inset: 0; width: 100%; height: 100%; display: block; transition: opacity 280ms ease; }
.logo__totem-seat canvas { position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%); pointer-events: none; }
.logo__text { font-size: 24px; font-weight: 500; color: var(--ink); letter-spacing: -0.02em; line-height: 1.1; white-space: nowrap; }

/* ─────────────── link rows: index.html .pop__row ─────────────── */
.pop__rows { position: relative; --glide-r: 12px; }
.pop__row {
  position: relative; display: grid; grid-template-columns: minmax(0, 1fr) 14px; align-items: center; gap: 12px;
  padding: 9px 12px; border-radius: 12px; color: var(--ink); text-decoration: none;
  -webkit-tap-highlight-color: transparent;
}
.pop__row:focus-visible { outline: 2px solid var(--ink); outline-offset: -2px; }
/* a row that carries a mark (a :::links list) gives it the first column */
.pop__row:has(.pop__tile) { grid-template-columns: 32px minmax(0, 1fr) 14px; padding-left: 8px; }
.pop__tile {
  display: grid; place-items: center; width: 32px; height: 32px; border-radius: 9px;
  background: linear-gradient(180deg, #ffffff, #f1f1ef);
  box-shadow: 0 0 0 1px rgba(24, 24, 23, 0.07), 0 1px 2px rgba(24, 24, 23, 0.07);
  transition: transform 300ms var(--pop-spring), box-shadow 180ms ease-out;
}
.pop__tile svg { display: block; width: 18px; height: 18px; overflow: visible; filter: drop-shadow(0 1px 0.6px rgba(10, 10, 9, 0.24)); transition: transform 320ms var(--pop-spring); }
.pop__text { display: flex; flex-direction: column; min-width: 0; }
.pop__label { font-size: 14px; font-weight: 500; line-height: 1.3; letter-spacing: -0.005em; }
.pop__note { margin-top: 1px; font-size: 12px; line-height: 1.35; color: var(--ink-tertiary-text); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.pop__end { width: 14px; height: 14px; color: var(--ink-secondary); opacity: 0; transform: translateX(-5px); transition: opacity 140ms ease-out, transform 260ms var(--pop-spring); }
@media (hover: hover) and (pointer: fine) {
  .pop__row:hover .pop__tile { transform: translateY(-1px); box-shadow: 0 0 0 1px rgba(24, 24, 23, 0.09), 0 4px 10px -3px rgba(24, 24, 23, 0.18); }
  .pop__row:hover .pop__tile svg { transform: scale(1.08); }
  .pop__row:hover .pop__end { opacity: 1; transform: none; }
}
.pop__row:focus-visible .pop__end { opacity: 1; transform: none; }

/* the rows standing in a page (About's links): an index.html .booking-card
   box, no tile */
.link-card {
  margin: 0 0 28px; padding: 6px; border: 1px solid var(--hairline); border-radius: 12px;
  background: var(--card); box-shadow: var(--shadow-rest);
}
.link-card .pop__rows { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 2px 4px; }
.link-card .pop__note { white-space: normal; }
.post__body .link-card a { text-decoration: none; }
.post__body .link-card { margin: 12px 0 28px; }

/* ─────────────── pills: index.html .ai-chip ─────────────── */
.ai-chip {
  display: inline-flex; padding: 4px 10px; justify-content: center; align-items: center; gap: 3px;
  border-radius: 16px; border: 1px solid var(--hairline); background: #fff; box-shadow: var(--shadow-rest);
  font: 400 12px/1.6 var(--font-main); color: var(--ink-secondary); text-decoration: none; white-space: nowrap; cursor: pointer;
  transition: box-shadow var(--t-fast) ease, color var(--t-fast) ease, border-color var(--t-fast) ease, transform var(--t-fast) var(--ease-soft);
}
/* a chip that is only a label (a card's category, "Sample") rests flat: the
   shadow is kept for the ones that can be pressed */
span.ai-chip { cursor: default; box-shadow: none; }
@media (hover: hover) and (pointer: fine) {
  a.ai-chip:hover, button.ai-chip:hover { box-shadow: var(--shadow-hover); color: var(--ink); border-color: var(--hairline-strong); }
}
a.ai-chip:active, button.ai-chip:active { transform: scale(var(--press-lg)); }
/* the selected one: index.html .bk-opt.is-on */
.ai-chip.is-on { background: rgba(24, 24, 23, 0.05); border-color: var(--ink); color: var(--ink); box-shadow: none; }
/* index.html .ai-chip__icon */
.ai-chip__icon { width: 12px; height: 12px; flex-shrink: 0; display: block; transition: transform 0.35s var(--ease-soft); }

/* ─────────────── arrow buttons: index.html .nav-btn ─────────────── */
.nav-btn {
  display: flex; align-items: center; justify-content: center; padding: 12px;
  background: #fff; border: 1px solid var(--hairline); border-radius: 8px; box-shadow: var(--shadow-rest);
  cursor: pointer; color: var(--ink-secondary); text-decoration: none;
  transition: box-shadow var(--t-fast) ease, color var(--t-fast) ease, border-color var(--t-fast) ease, transform var(--t-fast) var(--ease-soft);
}
.nav-btn:hover { box-shadow: var(--shadow-hover); color: var(--ink); border-color: var(--hairline-strong); }
.nav-btn:active { transform: scale(var(--press-lg)); }
/* aria-disabled, not disabled, on the featured row's arrows: a disabled
   button drops the keyboard's focus to the page. So a quiet arrow can hold
   focus, and its ring must read: the arrow and the box fade to 45% each on
   their own (the box's hairline and shadow at 45% of their alpha; its white
   is the page's), not through an opacity on the button, which took the ring
   down with them to under 3:1 */
.nav-btn[disabled], .nav-btn[aria-disabled="true"], .nav-btn.is-off {
  pointer-events: none;
  border-color: rgba(24, 24, 23, 0.036);
  box-shadow: 0 1px 2px rgba(24, 24, 23, 0.018), 0 4px 14px rgba(24, 24, 23, 0.018);
}
.nav-btn[disabled] svg, .nav-btn[aria-disabled="true"] svg, .nav-btn.is-off svg { opacity: 0.45; }
.nav-btn svg { width: 8px; height: 16px; display: block; }

/* ─────────────── the booking card: index.html .booking-card ─────────────── */
.booking-card {
  position: relative; display: flex; padding: 10px 10px 10px 14px;
  justify-content: space-between; align-items: center; gap: 12px;
  border-radius: 12px; border: 1px solid var(--hairline); background: var(--card); box-shadow: var(--shadow-rest);
  transition: box-shadow 300ms ease, border-color 300ms ease;
}
@media (hover: hover) and (pointer: fine) {
  .booking-card:hover { box-shadow: var(--shadow-hover); border-color: var(--hairline-strong); }
}
.booking-card__info { display: flex; flex-direction: column; justify-content: center; align-items: flex-start; gap: 2px; flex: 1 0 0; min-width: 0; min-height: 40px; }
/* the homepage's label is 10px; a step up here, where it is read rather than glanced at */
.booking-card__label { display: block; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.02em; color: var(--ink-secondary); line-height: 1.6; }
.booking-card__label:empty { display: none; }
.booking-card__title {
  display: flex; align-items: center; align-self: stretch; min-width: 0;
  font-size: 14px; font-weight: 500; letter-spacing: -0.01em; color: var(--ink); line-height: 1.5;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.booking-card__time { display: block; flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.booking-card__btn {
  display: flex; align-items: center; justify-content: center; padding: 5px 14px;
  background: var(--ink); color: var(--paper); font-family: var(--font-main); font-size: 12px; font-weight: 500;
  letter-spacing: 0; line-height: 1.6; border: 1px solid var(--ink); border-radius: 9px; corner-shape: superellipse(1.26);
  text-decoration: none; cursor: pointer; white-space: nowrap; flex-shrink: 0;
  transition: background var(--t-fast) ease, transform var(--t-fast) var(--ease-soft);
}
.booking-card__btn:hover { background: #33332f; border-color: #33332f; }
.booking-card__btn:active { transform: scale(var(--press-lg)); }
.booking-card.is-stacked { flex-wrap: wrap; }
.booking-card.is-stacked .booking-card__info { flex: 1 0 100%; }
.booking-card.is-stacked .booking-card__btn { flex: 1 1 100%; }

/* ─────────────── text ─────────────── */
/* index.html .story__title */
.b-hero h1, .post-head h1, .doc__head h1, .post__body h2, .featured__head h2, .topics h2, .related h2, .book-band p, .fcard__title {
  font-size: 24px; font-weight: 500; line-height: 1.4; letter-spacing: -0.02em; color: var(--ink); text-wrap: pretty;
}
/* a page's own title: index.html .intro__logo-text (42px / 500 / -0.02em) on
   a wide window, stepping down with it to 28px on a phone; a post's title,
   being longer, stops at 36px */
.b-hero h1, .doc__head h1, .about__rail h1 { font-size: clamp(28px, 2.2vw + 12px, 42px); line-height: 1.2; }
.post-head h1 { font-size: clamp(26px, 1.6vw + 14px, 36px); line-height: 1.25; }
/* index.html .description .muted */
.muted { color: var(--ink-tertiary-text); }
/* index.html .projects__count, in ink-secondary: its ink-tertiary is a
   2.5:1 contrast on white, and this text (dates, bylines, captions, the
   footer, a link or two) is read, so it takes the 4.5:1 that small text
   needs. ink-tertiary stays for marks that are not words: list markers,
   the breadcrumb's slash, the heading's # */
.crumbs, .post-meta, .card__meta, .pageof, .tags__label, .doc__meta, .side__link, .site-footer__inner, .author__role, .doc__more p, .figure figcaption {
  font-size: 12px; font-weight: 400; color: var(--ink-secondary); letter-spacing: 0.04em; font-variant-numeric: tabular-nums;
}

/* ─────────────── cards: index.html .tile ─────────────── */
/* the ground is the homepage's coming-soon paper (projects/coming-soon.svg, #F7F7F5),
   framed like its media (index.html .tile__media--framed). A band, not a
   picture: 2:1, so a card is mostly its words */
.cover { position: relative; overflow: hidden; aspect-ratio: 2 / 1; background: #F7F7F5; border-radius: clamp(10px, 1.6%, 22px); }
/* a post without an image: the 3D totem (blog-totem.svg; it is cached for a
   year, so bump its ?v= when the file changes) in ink, drawn large
   and faint and cropped off the bottom-right corner, sized by the cover's
   height so it sits the same in a card, the featured row and a wide card.
   The colour fills the totem's outline (the mask), and the render's own
   light is screened over it: its dark body keeps the colour as it is and
   its highlights lift it, so the totem keeps its shading in any colour */
.cover__mark {
  position: absolute; right: -5%; bottom: -16%; height: 104%; aspect-ratio: 818 / 917;
  background: var(--ink); opacity: 0.06;
  -webkit-mask: url(/blog-totem.svg?v=1) center / contain no-repeat; mask: url(/blog-totem.svg?v=1) center / contain no-repeat;
}
.cover__mark::after { content: ''; position: absolute; inset: 0; background: url(/blog-totem.svg?v=1) center / contain no-repeat; mix-blend-mode: screen; }
/* each category has its colour (blog.json tint): a soft wash from the top-left
   corner over a thinner one, and the totem in it. A category without a
   tint keeps the plain paper and the ink totem above */
.cover--type[style] { background: radial-gradient(110% 110% at 0% 0%, var(--tint-soft), transparent 62%), linear-gradient(165deg, var(--tint-wash), #F7F7F5); }
.cover--type[style] .cover__mark { background: var(--tint); opacity: 0.17; }
.cover--image img { width: 100%; height: 100%; object-fit: cover; border-radius: 12px; }

.card, .fcard {
  display: flex; flex-direction: column; height: 100%; padding: 24px;
  background: var(--panel); border: 0; border-radius: 30px; corner-shape: squircle;
  color: var(--ink); text-decoration: none;
  transition: transform 200ms var(--ease-soft), box-shadow 200ms ease;
}
.card:hover, .fcard:hover { transform: scale(1.012); box-shadow: var(--shadow-rest); }
.card:active, .fcard:active { transform: scale(0.985); transition: transform 90ms var(--ease-soft); }
/* the grid's cards frame their cover closer: 16px all round, the same as
   the step from cover to text */
.card { padding: 16px; }
/* the featured card's own step from cover to text */
.card .cover { margin: 0 0 16px; }
.card__body { display: flex; flex-direction: column; flex: 1; }
.card__chips, .fcard__chips { display: flex; gap: 6px; flex-wrap: wrap; }
/* index.html .booking-card__title, at the reading size */
.card__title { font-size: var(--read); font-weight: 500; line-height: 1.4; letter-spacing: -0.012em; margin: 12px 0 6px; text-wrap: pretty; }
/* index.html .story__quote */
.card__excerpt, .fcard__excerpt {
  margin: 0; font-size: 14px; line-height: 1.65; color: var(--ink-secondary);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}
.card__meta { display: flex; align-items: center; gap: 8px; margin-top: auto; padding-top: 14px; }

.fcard { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.08fr); gap: 32px; }
.fcard__text { position: relative; display: flex; flex-direction: column; min-width: 0; padding-top: 4px; }
.fcard__title { margin: 16px 0 10px; }
.fcard__excerpt { max-width: 46ch; }
.fcard .cover { height: 100%; min-height: 220px; aspect-ratio: auto; }

/* ─────────────── listing ─────────────── */
.b-hero { padding: 40px 0 28px; }
.crumbs ol { list-style: none; margin: 0 0 14px; padding: 0; display: flex; flex-wrap: wrap; gap: 4px 0; }
.crumbs li + li::before { content: '/'; margin: 0 8px; color: var(--ink-tertiary); }
.crumbs a { text-decoration: none; transition: color var(--t-fast) ease; }
.crumbs a:hover { color: var(--ink); }
.crumbs li[aria-current] { color: var(--ink-secondary); }
.b-hero h1 { margin: 0 0 14px; max-width: 24ch; }
.b-hero .lede { margin: 0; max-width: 56ch; font-size: var(--read); line-height: 1.6; color: var(--ink-secondary); }
.pageof { margin: 10px 0 0; }

.featured { margin: 0 0 36px; }
.featured__head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.featured__head h2 { margin: 0; }
.featured__nav { display: flex; gap: 8px; }
/* The row slides inside the column and is cut at its edges: the next card
   shows only as far as the column goes. Scrolling sideways clips the other
   axis too, so the row is padded out above and below to hold the cards'
   shadow, and pulled back by the same margin. A card here does not grow on
   hover -- the column's edge would cut it -- it only lifts its shadow (a
   press still shrinks it). The same 4px either side holds a focused card's
   ring, which sits 4px outside the card */
.featured__track {
  list-style: none; display: flex; gap: 20px;
  margin: -20px -4px -40px; padding: 20px 4px 40px; scroll-padding-inline: 4px;
  overflow-x: auto; scroll-snap-type: x mandatory;
  scrollbar-width: none; overscroll-behavior-x: contain;
}
.featured__track::-webkit-scrollbar { display: none; }
.featured__track > li { flex: 0 0 94%; scroll-snap-align: start; }
.featured__track > li:only-child { flex-basis: 100%; }
.featured__track .fcard:hover:not(:active) { transform: none; }

/* a scrolling row cuts what passes its edge, a focus ring too, so the row
   reaches 4px past the column on either side to hold one */
.tabs { display: flex; gap: 6px; overflow-x: auto; scrollbar-width: none; margin: 0 -4px 24px; padding: 4px 4px 15px; }
.tabs::-webkit-scrollbar { display: none; }

/* Three to a row (two on a tablet, one on a phone). A card left alone on
   the last row takes the whole row instead, as a wide card: its cover
   stands under the first column's covers and its words start where the
   second column's do; two left on the last row share it, half each (the
   media rules below place them). */
.grid { list-style: none; margin: 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 20px; }
.grid > li { min-width: 0; }
.empty { color: var(--ink-secondary); padding: 48px 0; }

.pager { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin: 32px 0 0; }
.pager__nums { display: flex; gap: 6px; align-items: center; }
.pager__gap { color: var(--ink-tertiary); padding: 0 4px; }

.topics { margin: 48px 0 0; }
.topics h2 { margin: 0 0 14px; }
.topics__list, .tags ul, .doc__more ul { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 6px; }

/* the closing line, and the homepage's booking card */
.book-band { display: flex; align-items: center; justify-content: space-between; gap: 32px; margin: 48px 0 0; padding: 28px 0 0; border-top: 1px solid var(--hairline); }
.book-band p { max-width: 30ch; margin: 0; }
.book-band p a { text-underline-offset: 4px; text-decoration-color: var(--hairline-strong); }
.book-band .booking-card { flex: 0 1 420px; }

/* ─────────────── post ─────────────── */
.post-head { padding: 32px 0 32px; max-width: 800px; }
.post-head h1 { margin: 0 0 14px; max-width: 28ch; }
/* byline, date, reading time, update: each item carries its own dot in
   front, and the row is pulled left by one dot's width and clipped there, so
   the dot that starts a line (the first, or one after a wrap) is never seen
   and no line ever ends on a dot */
.post-meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 0; margin-left: -18px; clip-path: inset(-8px -8px -8px 18px); }
.post-meta > span::before {
  content: '\00B7'; content: '\00B7' / ''; display: inline-block; width: 18px; text-align: center; color: var(--ink-tertiary);
}
.post__cover { margin: 0 0 32px; }
/* the cards' own shape, 2:1, whatever shape the image is: a tall cover would
   otherwise fill the first screen and push the article below it */
.post__cover img { width: 100%; height: auto; aspect-ratio: 2 / 1; object-fit: cover; border-radius: 30px; }

.post-layout { display: grid; grid-template-columns: 240px minmax(0, 1fr) 312px; gap: 44px; align-items: start; }
.post-toc, .post-side { align-self: stretch; }

/* the contents card: an index.html .booking-card box */
.toc { position: sticky; top: 24px; }
.toc__box {
  border: 1px solid var(--hairline); border-radius: 12px; background: var(--card); box-shadow: var(--shadow-rest);
  padding: 14px 8px 10px 16px; max-height: calc(100vh - 48px); overflow: auto; scrollbar-width: thin;
}
.toc__box summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; padding-right: 8px;
  font-size: 14px; font-weight: 500; line-height: 1.5; letter-spacing: -0.01em; color: var(--ink);
}
.toc__box summary::-webkit-details-marker { display: none; }
/* the chevron: the homepage menu's */
.chev { width: 12px; height: 7px; color: var(--ink-secondary); transition: transform 0.36s var(--pop-spring); flex: none; }
.is-open > summary .chev { transform: rotate(180deg); }
.toc__list, .toc__sub { list-style: none; margin: 0; padding: 0; }
.toc__list { position: relative; margin-top: 8px; padding-left: 12px; border-left: 1px solid var(--hairline); --glide-r: 8px; }
.toc__sub { padding-left: 10px; margin-bottom: 2px; }
/* index.html .chat-bubble's 12px */
.toc a { display: block; padding: 5px 10px 5px 0; font-size: 12px; line-height: 1.6; color: var(--ink-secondary); text-decoration: none; transition: color var(--t-fast) ease; }
/* a step lighter than the sections above them, and still 4.5:1 on the card */
.toc__sub a { color: var(--ink-tertiary-text); }
.toc a:hover, .toc a[aria-current="true"] { color: var(--ink); }
.toc__mark {
  position: absolute; left: -1px; top: 0; width: 2px; height: 0; border-radius: 2px; background: var(--ink); opacity: 0;
  transition: transform 260ms var(--pop-spring), height 260ms var(--pop-spring), opacity 160ms ease-out;
}
.toc__mark.is-on { opacity: 1; }
.toc__mark.is-snap { transition: opacity 160ms ease-out; }

.post { min-width: 0; }
/* an index.html .booking-card box */
.takeaways, .post > .author {
  max-width: var(--measure); margin: 0 0 32px; padding: 14px 16px;
  border: 1px solid var(--hairline); border-radius: 12px; background: var(--card); box-shadow: var(--shadow-rest);
}
.takeaways__title { margin: 0 0 6px; font-size: 14px; font-weight: 500; line-height: 1.5; letter-spacing: -0.01em; }
.takeaways ul { margin: 0; padding-left: 1.2em; font-size: 15px; line-height: 1.6; }
.takeaways li { margin: 4px 0; }
.takeaways li::marker { color: var(--ink-tertiary); }

/* the article: index.html .description's weight and colour at the reading
   size (16px / 1.7), its titles .story__title */
.post__body { max-width: var(--measure); font-size: var(--read); line-height: 1.7; color: var(--ink); overflow-wrap: break-word; }
.post__body > :first-child { margin-top: 0; }
.post__body p { margin: 0 0 18px; }
.post__body h2 { margin: 44px 0 12px; scroll-margin-top: 24px; }
.post__body h3, .post__body h4 { margin: 30px 0 8px; font-size: 18px; font-weight: 500; line-height: 1.45; letter-spacing: -0.015em; scroll-margin-top: 24px; }
/* the heading's #, for a pointer only (the contents card links every
   section for a keyboard or a screen reader). Placed where it falls after the
   last word but taken out of the line, so the heading wraps as if it were not
   there and never leaves a word alone on its last line. On a touch screen,
   where it could not be seen before it was tapped, it is not there at all */
.anchor { position: absolute; margin-left: 6px; font-weight: 400; color: var(--ink-tertiary); text-decoration: none; opacity: 0; transition: opacity var(--t-fast) ease; }
h2:hover .anchor, h3:hover .anchor { opacity: 1; }
@media (hover: none) { .anchor { display: none; } }
.post__body a { text-decoration: underline; text-decoration-color: var(--hairline-strong); text-underline-offset: 3px; transition: text-decoration-color var(--t-fast) ease; }
.post__body a:hover { text-decoration-color: var(--ink); }
.post__body a.anchor { text-decoration: none; }
.post__body strong { font-weight: 500; }
.post__body ul, .post__body ol { margin: 0 0 16px; padding-left: 1.3em; }
.post__body li { margin: 4px 0; padding-left: 2px; }
.post__body li::marker { color: var(--ink-tertiary); }
.post__body li > ul, .post__body li > ol { margin: 4px 0 2px; }
.post__body li.task { list-style: none; position: relative; margin-left: -1.3em; padding-left: 26px; }
.post__body li.task::before { content: ''; position: absolute; left: 2px; top: 0.3em; width: 14px; height: 14px; border: 1px solid var(--hairline-strong); border-radius: 4px; background: #fff; }
.post__body li.task--done::before { background: var(--ink); border-color: var(--ink); }
.post__body li.task--done::after { content: ''; position: absolute; left: 6px; top: 0.48em; width: 6px; height: 3px; border-left: 1.5px solid var(--paper); border-bottom: 1.5px solid var(--paper); transform: rotate(-45deg); }
/* a quote: index.html .tile__quote-glyph over the words, .story__attr under them */
.post__body blockquote { margin: 28px 0; padding: 0; }
.post__body blockquote::before { content: '\201C'; display: block; height: 28px; font-size: 52px; line-height: 1; font-weight: 600; color: var(--ink); margin-bottom: 12px; }
.post__body blockquote p { margin: 0; }
.post__body blockquote p + p { margin-top: 14px; font-size: 11px; letter-spacing: 0.06em; text-transform: uppercase; color: var(--ink-tertiary-text); }
.post__body blockquote p + p a { text-decoration: none; }
.post__body hr { border: 0; border-top: 1px solid var(--hairline); margin: 40px 0; }
/* code: index.html .chat-bubble's surface */
/* inline code may wrap, so a long name never pushes past the column; a
   block keeps its lines and scrolls sideways inside its own box */
.post__body code { font-family: var(--font-mono); font-size: 0.82em; background: #f6f6f4; border-radius: 6px; padding: 1px 5px; overflow-wrap: anywhere; }
.post__body pre { margin: 20px 0; padding: 12px 14px; background: #f6f6f4; border-radius: 8px; overflow-x: auto; font-size: 14px; line-height: 1.6; }
.post__body pre code { background: none; padding: 0; font-size: 13px; white-space: pre; overflow-wrap: normal; }
.figure { margin: 28px 0; }
.figure img { width: 100%; height: auto; border-radius: 12px; }
.figure figcaption { margin-top: 10px; line-height: 1.6; }
/* a table keeps the body's 14px and the column's width: its cells wrap, so
   on a phone every sentence is there to read. Only a table with more
   columns than the screen can hold scrolls sideways, inside the column */
.table-scroll { overflow-x: auto; margin: 24px 0; font-size: 14px; line-height: 1.6; }
.table-scroll table { width: 100%; border-collapse: collapse; }
.table-scroll th { text-align: left; padding: 10px 14px 10px 0; font-size: 12px; font-weight: 500; color: var(--ink-secondary); border-bottom: 1px solid var(--hairline); }
.table-scroll td { padding: 10px 14px 10px 0; border-bottom: 1px solid var(--hairline); vertical-align: top; }
.table-scroll td:first-child { font-weight: 500; }
/* a note: index.html .chat-bubble */
.callout { margin: 24px 0; padding: 10px 14px; background: #f6f6f4; border-radius: 8px; }
.callout p { margin: 0 0 8px; }
.callout > :last-child { margin-bottom: 0; }
.callout__title { font-weight: 500; }

/* FAQ: rows on a hairline, the question as .booking-card__title, the answer as .story__quote */
.faq { margin-top: 48px; }
.faq h2 { margin-top: 0 !important; }
.faq__item { border-top: 1px solid var(--hairline); }
.faq__item:last-child { border-bottom: 1px solid var(--hairline); }
.faq__item summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; gap: 16px;
  padding: 14px 0; font-size: var(--read); font-weight: 500; line-height: 1.5; letter-spacing: -0.012em;
}
.faq__item summary::-webkit-details-marker { display: none; }
.faq__a { overflow: hidden; padding: 0 0 16px; max-width: 62ch; color: var(--ink-secondary); }
.faq__a p { margin: 0 0 10px; }

.tags { display: flex; align-items: baseline; flex-wrap: wrap; gap: 8px 12px; max-width: var(--measure); margin: 32px 0 0; }
.tags__label { margin: 0; }
.share { display: flex; align-items: center; flex-wrap: wrap; gap: 6px; max-width: var(--measure); margin: 16px 0 0; }
.post > .author { margin: 24px 0 0; }
.author p { margin: 0; }
.author__name { font-size: 14px; font-weight: 500; line-height: 1.5; letter-spacing: -0.01em; }
.author__bio { margin-top: 8px !important; color: var(--ink-secondary); }
.author__link { display: inline-block; margin-top: 8px; font-size: 12px; color: var(--ink-secondary); text-underline-offset: 3px; transition: color var(--t-fast) ease; }
.author__link:hover { color: var(--ink); }

/* the right column: a line (.story__quote), the booking card, the proof link */
.side { position: sticky; top: 24px; display: flex; flex-direction: column; gap: 12px; }
/* the bigger card: index.html's phone booking card (.m-shell .booking-card), 72px with a 48px button */
.side .booking-card { min-height: 72px; padding: 4px 12px; gap: 10px; }
.side .booking-card__btn { height: 48px; padding: 0 12px; border-radius: 10px; }
.side__text { margin: 0; color: var(--ink-secondary); }
.side__link { align-self: flex-start; text-decoration: none; transition: color var(--t-fast) ease; }
.side__link:hover { color: var(--ink); }

.related { margin-top: 56px; padding-top: 32px; border-top: 1px solid var(--hairline); }
.related h2 { margin: 0 0 18px; }

/* ─────────────── plain pages: about, contact, faq, locations, privacy ─────────────── */
.doc { max-width: var(--measure); padding: 32px 0 8px; }
.doc__head h1 { margin: 0 0 14px; max-width: 22ch; letter-spacing: -0.02em; }
.doc__lede { max-width: 56ch; margin: 0 0 10px; font-size: var(--read); line-height: 1.6; color: var(--ink-secondary); }
.doc__head { margin-bottom: 32px; }
.doc__meta { margin: 0; }
.doc__book { display: flex; flex-direction: column; gap: 12px; max-width: 420px; margin-top: 40px; }
/* in a rail the card is as wide as the rail's words */
.about__rail .doc__book { max-width: none; }
.doc__book p { margin: 0; color: var(--ink-secondary); }
.doc__more { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 12px; margin-top: 48px; padding-top: 24px; border-top: 1px solid var(--hairline); }
.doc__more p { margin: 0; }
/* official badges, as their issuers draw them, linked to the profile that awarded them */
.badges { display: flex; flex-wrap: wrap; align-items: center; gap: 16px; margin: 4px 0 20px; }
.badges a { display: block; transition: transform var(--t-fast) var(--ease-soft); }
.badges a:hover { transform: scale(1.03); }
.badges img { display: block; height: 140px; width: auto; }

/* ─────────────── About: the homepage's composition ───────────────
   A rail on the left, as the homepage's sidebar: the title, the studio's words
   (.description), the founder, the booking card, the note on the name. On the
   right, the proof and the ways in as the homepage's project tiles
   (index.html .tile: panel, 30px squircle, 24px in, scale on hover). */
.about { display: grid; grid-template-columns: minmax(0, 420px) minmax(0, 1fr); gap: 72px; align-items: start; padding: 32px 0 8px; }
.about__rail { position: sticky; top: 32px; display: flex; flex-direction: column; gap: 20px; }
.about__rail h1 { margin: 0; font-weight: 500; letter-spacing: -0.02em; text-wrap: balance; }
.about__lede { margin: 0; font-size: var(--read); line-height: 1.6; color: var(--ink-secondary); }
.rail-part p { margin: 0; }
.rail-part--small { font-size: 12px; line-height: 1.6; color: var(--ink-secondary); letter-spacing: 0.04em; }
.about__rail .doc__book { margin: 0; }
.about__main { max-width: none; }
.about__main > h2:first-child, .about__main > .faq:first-child { margin-top: 0; }
.about__main h2 { margin-top: 40px; }
/* the line that introduces a set of tiles reads as .story__quote */
.about__main > p:has(+ .tiles) { color: var(--ink-secondary); }
/* running text keeps the reading measure; the tiles take the full width,
   and so does an FAQ, whose rows are a list to scan more than text to read
   (its answers keep their own 62ch), so it ends where the tiles under it do */
.about__main > :not(.tiles):not(h2):not(.faq) { max-width: var(--measure); }
.about__main > p:has(+ .tiles) { margin-bottom: 0; }
.about__rail .doc__meta { margin: -8px 0 0; }
.about__rail .toc { position: static; }
.about__rail .toc__box { max-height: none; }

.tiles { list-style: none; margin: 16px 0 0; padding: 0; display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.tiles > li { min-width: 0; display: flex; }
/* the last tile of a set that would leave its last row short reaches to the
   row's end (gen-blog.py sets --span) */
.tiles > li[style*="--span"] { grid-column: span var(--span); }
.post__body .tiles { padding-left: 0; margin-bottom: 0; }
.post__body .tiles > li { margin: 0; padding: 0; }
/* the words start a fixed step under the mark, not at the tile's foot, so
   titles share one line across a row however long each note runs */
.tile-card {
  position: relative; display: flex; flex-direction: column; justify-content: flex-start; gap: 28px; width: 100%;
  min-height: 160px; padding: 24px;
  background: var(--panel); border-radius: 30px; corner-shape: squircle;
  color: var(--ink); text-decoration: none !important;
  transition: transform 200ms var(--ease-soft), box-shadow 200ms ease;
}
.tile-card:hover { transform: scale(1.012); box-shadow: var(--shadow-rest); }
.tile-card:active { transform: scale(0.985); transition: transform 90ms var(--ease-soft); }
/* the mark, in the totem's ink, at the homepage tiles' logo height */
.tile-card__mark svg { display: block; width: 30px; height: 30px; overflow: visible; filter: drop-shadow(0 1px 0.6px rgba(10, 10, 9, 0.24)); transition: transform 200ms var(--ease-soft); }
.tile-card:hover .tile-card__mark svg { transform: scale(1.06); }
.tile-card__text { display: flex; flex-direction: column; gap: 2px; }
.tile-card__label { display: flex; align-items: center; justify-content: space-between; gap: 8px; font-size: 14px; font-weight: 500; line-height: 1.5; letter-spacing: -0.01em; }
.tile-card__note { font-size: 12px; line-height: 1.5; color: var(--ink-secondary); letter-spacing: 0.04em; }
.tile-card .pop__end { flex: none; }
.tile-card:hover .pop__end { opacity: 1; transform: none; }
/* an awarded badge takes the tall tile, as the issuer draws it */
.tiles > li:has(.tile-card--badge) { grid-row: span 2; }
.tile-card--badge { justify-content: space-between; }
.tile-card__badge { display: block; width: auto; height: 168px; margin: 4px auto 0; }

/* ─────────────── footer: .projects__count text on a hairline ─────────────── */
.site-footer { margin-top: 48px; border-top: 1px solid var(--hairline); }
.site-footer__inner { max-width: var(--wrap); margin: 0 auto; padding: 20px var(--gutter); display: flex; align-items: center; justify-content: space-between; gap: 16px; }
.site-footer nav { display: flex; flex-wrap: wrap; gap: 2px; margin-right: -8px; --glide-r: 8px; }
.site-footer nav a { padding: 4px 8px; text-decoration: none; color: var(--ink-secondary); transition: color var(--t-fast) ease; }
.site-footer nav a:hover { color: var(--ink); }

/* ─────────────── responsive ───────────────
   desktop     1264px and up   the full column (--max), a post in three columns
   laptop      1024 to 1263    the column is the window less its gutters;
                               a post's booking card moves under the article
   tablet       641 to 1023    two cards to a row, a post in one column
                               from 959 down
   phone        640 and under  one card to a row, the featured card stacked,
                               20px gutters */
@media (min-width: 960px) {
  .toc__box summary { cursor: default; }
  .toc__box summary .chev { display: none; }
}
@media (max-width: 1263px) {
  .post-layout { grid-template-columns: 240px minmax(0, 1fr); gap: 48px; }
  .post-side { grid-column: 2; margin-top: 40px; }
  /* under the article, the booking card is as wide as the article's words */
  .side { position: static; max-width: var(--measure); }
}
@media (max-width: 1100px) {
  .about { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  /* one column: the rail and the words under it keep the reading measure,
     centred, so the page is not weighted to the left; the tiles span the column */
  .about__rail { position: static; width: 100%; max-width: var(--measure); margin-inline: auto; }
  .about__main > :not(.tiles) { max-width: var(--measure); margin-inline: auto; }
  /* a heading over tiles, and the line that introduces them, start where the
     tiles do, as More articles does over its cards on a post. The heading
     takes the column; the line is running text, so it keeps the measure (as
     it does beside the rail) and is only moved to the tiles' edge. Lifting
     its max-width did not: the measure rule above outranks this one, so the
     line stayed centred, 80 to 240px in from its heading and its tiles */
  .about__main > h2:has(+ .tiles), .about__main > h2:has(+ p + .tiles) { max-width: none; }
  .about__main > p:has(+ .tiles) { margin-inline: 0; }
  /* the rail sits above the text here, so its contents card stays folded
     (blog.js) and keeps the phone's chevron */
  .about__rail .toc__box summary { cursor: pointer; }
  .about__rail .toc__box summary .chev { display: block; }
}
/* the wide card (see .grid): the percentages are of the card's own inner
   width, worked back from the row's tracks and the cards' 16px padding, so
   the cover lines up with the first column's covers and the words with the
   second column's */
@media (min-width: 1024px) {
  /* six tracks, a card on two of them: the same three columns, with room for
     two cards to take three tracks each when they are the last row's only two */
  .grid { grid-template-columns: repeat(6, minmax(0, 1fr)); }
  .grid > li { grid-column: span 2; }
  .grid > li:nth-last-child(2):nth-child(3n+1), .grid > li:last-child:nth-child(3n+2) { grid-column: span 3; }
  .grid > li:last-child:nth-child(3n+1) { grid-column: 1 / -1; }
  .grid > li:last-child:nth-child(3n+1) > .card { display: grid; grid-template-columns: calc((100% - 8px) / 3 - 32px) minmax(0, 1fr); column-gap: 52px; align-items: start; }
  .grid > li:last-child:nth-child(3n+1) .cover { margin: 0; }
}
@media (min-width: 641px) and (max-width: 1023px) {
  .grid > li:last-child:nth-child(odd) { grid-column: 1 / -1; }
  .grid > li:last-child:nth-child(odd) > .card { display: grid; grid-template-columns: calc((100% + 12px) / 2 - 32px) minmax(0, 1fr); column-gap: 52px; align-items: start; }
  .grid > li:last-child:nth-child(odd) .cover { margin: 0; }
}
@media (max-width: 1023px) {
  .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .fcard { gap: 24px; }
  .book-band { flex-direction: column; align-items: flex-start; gap: 18px; }
  .book-band .booking-card { flex: none; width: 100%; max-width: 420px; }
}
@media (max-width: 959px) {
  :root { --gutter: 24px; }
  .post-layout { grid-template-columns: minmax(0, 1fr); gap: 0; }
  /* one column: the title, the contents card, the article and the booking
     card share the reading measure, centred in the page's column, so the
     words are not pushed to the left with a band of paper beside them. The
     cover and More articles span the column */
  .post-head, .post-toc, .post, .post-side { width: 100%; max-width: var(--measure); margin-inline: auto; }
  .post-toc { margin-bottom: 24px; }
  .toc { position: static; }
  .toc__box { max-height: none; }
  .post-side { grid-column: auto; }
  .post-head { padding-top: 24px; }
}
@media (max-width: 640px) {
  :root { --gutter: 20px; }
  .site-header__inner { padding-top: 24px; }
  .b-hero { padding: 28px 0 20px; }
  .doc { padding-top: 24px; }
  .about { padding-top: 24px; }
  .featured { margin-bottom: 28px; }
  /* the featured card stands its cover on top of its words, as a card does */
  .fcard { grid-template-columns: 1fr; gap: 16px; }
  .fcard__text { order: 2; }
  .fcard .cover { order: 1; min-height: 0; aspect-ratio: 2 / 1; height: auto; }
  .fcard__title { font-size: 20px; }
  .featured__track > li { flex-basis: 92%; }
  /* on a phone a tile is a row: mark, words, caret. The badge keeps its
     tall tile. Corners are the homepage menu card's 18px. */
  .tiles { grid-template-columns: minmax(0, 1fr); gap: 8px; }
  .tiles > li[style*="--span"] { grid-column: auto; }
  .tile-card { flex-direction: row; align-items: center; justify-content: flex-start; gap: 14px; min-height: 0; padding: 14px 18px; border-radius: 18px; }
  .tile-card__mark svg { width: 24px; height: 24px; }
  .tile-card__text { flex: 1; min-width: 0; }
  .tile-card .pop__end { opacity: 1; transform: none; }
  .tiles > li:has(.tile-card--badge) { grid-row: auto; }
  .tile-card--badge { flex-direction: column; align-items: stretch; gap: 16px; padding: 20px 18px 16px; }
  .tile-card__badge { height: 132px; }
  .grid { grid-template-columns: minmax(0, 1fr); gap: 16px; }
  .fcard { padding: 20px; }
  .pager { flex-wrap: wrap; justify-content: center; }
  .pager__nums { order: -1; width: 100%; justify-content: center; }
  .related { margin-top: 48px; }
  .site-footer__inner { flex-direction: column; align-items: flex-start; gap: 8px; }
  .site-footer nav { margin-left: -8px; }
}
/* a finger needs more than a cursor: the pills, the contents links and the
   footer links grow to a comfortable tap, and every booking card takes the
   homepage's phone card (72px, a 48px button), as the post's already does */
@media (pointer: coarse) {
  a.ai-chip, button.ai-chip { padding: 8px 12px; }
  .toc a { padding-top: 8px; padding-bottom: 8px; }
  .site-footer nav a { padding: 8px; }
  .booking-card { min-height: 72px; padding: 4px 12px; gap: 10px; }
  .booking-card__btn { height: 48px; padding: 0 12px; border-radius: 10px; }
  .booking-card.is-stacked { padding: 12px; }
}
@media print {
  [data-reveal] { transform: none !important; animation: none !important; }
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .pop__tile, .pop__tile svg, .pop__end { transition: opacity 120ms ease-out; }
  .card, .fcard, .card:hover, .fcard:hover, .tile-card, .tile-card:hover { transform: none; transition: none; }
  .glide, .toc__mark, .chev { transition: none; }
}
