/* Recently — public profile, post and document pages.

   These pages are user-themeable: everything reads from the unprefixed --bg,
   --fg, --accent set, which the data-theme attribute on <html> swaps. Product
   chrome (landing, auth, editor, dashboard) deliberately uses the separate
   --app-* tokens so a user's theme can never restyle the application UI.

   Sans-serif throughout, including the themes -- the old "paper" theme's
   Georgia stack is gone. */

:root {
  --bg: #ffffff;
  --fg: #0d0d12;
  --muted: #5b5f6e;
  --border: #e8e9f0;
  --surface: #f4f5f9;
  --sidebar: #e9eaf1;
  --accent: #6d4aff;
  --accent-fg: #ffffff;
  --radius: 16px;
  --radius-sm: 10px;
  --font: "Inter Var", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --font-heading: "Space Grotesk", var(--font);
  --width: 36rem;
  --shadow: 0 4px 16px rgba(13, 13, 18, 0.08);
  --code-bg: #15151b;
  --code-fg: #f3f3f6;
  --code-border: #292932;
}

[data-theme="ink"] {
  --bg: #0d0d12; --fg: #f2f2f5; --muted: #9096a3; --border: #24242e;
  --surface: #17171f; --sidebar: #101017; --accent: #c2f04c; --accent-fg: #0d0d12;
  --shadow: 0 4px 16px rgba(0, 0, 0, 0.5);
  --code-bg: #08080c; --code-fg: #f2f2f5; --code-border: #30303a;
}

/* Formerly a cream/serif theme. Now the loud one: lime on off-white with a
   violet accent. Key unchanged so existing profiles need no migration. */
[data-theme="paper"] {
  --bg: #fbfbf4; --fg: #14140f; --muted: #5c5c50; --border: #e3e3d2;
  --surface: #eef5d8; --sidebar: #e2ebc6; --accent: #6d4aff; --accent-fg: #ffffff;
}

[data-theme="midnight"] {
  --bg: #0b0b1a; --fg: #e6e6f5; --muted: #8b8fb0; --border: #1e1e3a;
  --surface: #14142b; --sidebar: #0f0f22; --accent: #8b6cff; --accent-fg: #ffffff;
  --shadow: 0 4px 20px rgba(0, 0, 0, 0.6);
  --code-bg: #060611; --code-fg: #eeeeff; --code-border: #292947;
}

[data-theme="terminal"] {
  --bg: #04140c; --fg: #b9f5c8; --muted: #5f8f6c; --border: #10361f;
  --surface: #08200f; --sidebar: #06190c; --accent: #22c55e; --accent-fg: #04140c;
  --font: ui-monospace, SFMono-Regular, "SF Mono", Menlo, monospace;
  --font-heading: var(--font);
  --radius: 4px;
  --radius-sm: 4px;
  --shadow: none;
  --code-bg: #020905; --code-fg: #c9fbd5; --code-border: #15592d;
}

[data-theme="sunset"] {
  --bg: #fff8f6; --fg: #2a1116; --muted: #8a5f66; --border: #ffdfd7;
  --surface: #ffeae4; --sidebar: #f7dcd5; --accent: #ff5c7a; --accent-fg: #ffffff;
  --shadow: 0 4px 16px rgba(255, 92, 122, 0.16);
}

[data-theme="mint"] {
  --bg: #f5fdfb; --fg: #0a2620; --muted: #4d7a70; --border: #cdeee6;
  --surface: #dff7f1; --sidebar: #d2eee7; --accent: #0d9488; --accent-fg: #ffffff;
  --shadow: 0 4px 16px rgba(13, 148, 136, 0.14);
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--fg);
  font-family: var(--font);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
  font-family: var(--font-heading);
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

a { color: inherit; }

/* --- profile ------------------------------------------------------------- */

.profile, .post, .archive, .doc {
  max-width: var(--width);
  margin: 0 auto;
  padding: 3rem 1.25rem 4rem;
}

.profile-edit-action {
  position: fixed;
  right: max(1rem, env(safe-area-inset-right));
  bottom: max(1rem, env(safe-area-inset-bottom));
  z-index: 20;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: .625rem 1rem;
  border: 1.5px solid var(--accent);
  border-radius: 999px;
  background: var(--accent);
  box-shadow: var(--shadow);
  color: var(--accent-fg);
  font-size: .875rem;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  transition: transform .15s ease, box-shadow .15s ease;
}

.profile-edit-action:hover { transform: translateY(-2px); }
.profile-edit-action:focus-visible {
  outline: 3px solid var(--fg);
  outline-offset: 3px;
}

.profile-header { text-align: center; }

/* The ring lives on the wrapper so it looks identical whether the photo
   loaded or the initial is showing through. */
.avatar-wrap {
  position: relative;
  width: 96px; height: 96px;
  margin: 0 auto;
  border-radius: 50%;
  box-shadow: 0 0 0 3px var(--bg), 0 0 0 6px var(--accent);
}

.avatar-initial {
  position: absolute; inset: 0;
  display: grid; place-items: center;
  border-radius: 50%;
  background: var(--surface);
  font-family: var(--font-heading);
  font-size: 2.25rem; font-weight: 700;
  color: var(--accent);
}

.avatar {
  position: relative;
  display: block;
  width: 96px; height: 96px;
  border-radius: 50%;
  object-fit: cover;
}

.profile-name { margin: 1.5rem 0 .375rem; font-size: 2rem; }
.profile-bio { margin: 0 0 .375rem; color: var(--fg); }
.profile-location { margin: 0; color: var(--muted); font-size: .875rem; font-weight: 500; }

/* Icons must not shrink -- flex would squash the circles into ovals once a few
   platforms are connected -- so they wrap onto a second row instead. */
.socials {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem;
  justify-content: center;
  margin-top: 1.25rem;
}

.socials a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--surface);
  color: var(--muted);
  transition: background .15s ease, color .15s ease, transform .15s ease;
}

.socials a svg { flex: none; }

.socials a:hover {
  background: var(--accent);
  color: var(--accent-fg);
  transform: translateY(-2px);
}

/* The Now block uses the same open, bordered surface as the link cards; its
   accent label and live dot provide the emphasis. */
.now {
  position: relative;
  margin: 2.25rem 0;
  padding: 1.125rem 1.25rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  background: transparent;
  overflow: visible;
}

.now-label {
  display: inline-flex;
  align-items: center;
  gap: .375rem;
  font-size: .6875rem; font-weight: 700; letter-spacing: .12em;
  text-transform: uppercase; color: var(--accent);
}

.now-label::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent);
}

.now-text { margin: .5rem 0 .25rem; font-size: 1.125rem; font-weight: 500; }
.now-time { font-size: .75rem; color: var(--muted); font-weight: 500; }

/* --- blocks -------------------------------------------------------------- */

/* Blocks sit on each profile's effective grid (the container carries
   is-cols-2 or is-cols-4). Widths are stored in
   quarter-columns and Python emits the already-resolved span as is-w{n}, so
   this stylesheet never does the arithmetic.

   Placement is auto-flow: order is the only stored input.

   --block-row is the height of one grid row, tuned per breakpoint to sit near
   the column width so a 1x1 reads square. The grid itself stays content-sized
   because headings are labels, while link cards lock to their selected row span
   so media cannot stretch neighboring cards. */
.blocks {
  --block-row: 4.5rem;
  --block-gap: .625rem;
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  grid-auto-rows: auto;
  gap: var(--block-gap);
  margin: 2rem 0;
}

/* On a phone the four-column grid is clamped to two columns, so its cells are
   ~166px and the row grows to match -- a Small stays square rather than
   flattening into a button. Left alone at two columns, where the 4.5rem row is
   what every existing page was laid out against. Equal specificity to the
   breakpoint overrides below, which come later and win. */
.blocks.is-cols-4 { --block-row: 10.375rem; }

/* Every span is clamped to two columns below 45rem, so the phone grid is the
   two-column grid whatever the setting says. The four-column rules live in the
   desktop breakpoint; here is-w3/is-w4 are simply full width. */
.block { min-width: 0; min-height: var(--block-row); }
.block.is-w1 { grid-column: span 1; }
.block.is-w2, .block.is-w3, .block.is-w4 { grid-column: span 2; }

/* Height spans: n rows plus the gaps between them. Clamped to two rows on
   phones for the same reason the widths are -- a 4-row tower on a 390px screen
   is a scroll trap, not a layout. */
.block.is-h1 { grid-row: span 1; }
.block.is-h2, .block.is-h3, .block.is-h4 {
  grid-row: span 2;
  min-height: calc(2 * var(--block-row) + var(--block-gap));
}

.block-heading { min-height: 0; }

.block-link {
  display: flex;
  align-items: center;
  gap: .875rem;
  overflow: hidden;
  padding: 1rem 1.125rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  text-decoration: none;
  background: transparent;
  transition: border-color .12s ease, transform .12s ease, box-shadow .12s ease;
}

.block-link.is-h1 { height: var(--block-row); }
.block-link.is-h2,
.block-link.is-h3,
.block-link.is-h4 {
  height: calc(2 * var(--block-row) + var(--block-gap));
}

.block-link:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow);
}

.block-link.is-highlighted {
  border-color: var(--accent);
  background: var(--accent);
  color: var(--accent-fg);
}

/* Image layouts promote the stored icon_url to a real image, which is why no
   data migration was needed. The "text" layout renders no image at all, so a
   link that carries an icon_url can still be shown as pure text. */
.block-icon {
  border-radius: 8px;
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  object-fit: cover;
}

.block-layout-image_left.has-image { flex-direction: row; }
.block-layout-image_right.has-image { flex-direction: row-reverse; }

.block-layout-image_top.has-image {
  flex-direction: column;
  align-items: stretch;
  gap: .75rem;
}

/* Once a link carries a real image the card is mostly that image, so the
   padding drops to a thin frame and the artwork takes the full tile height.
   A fixed thumbnail left most of a 112px tile empty. */
.block-layout-image_left.has-image,
.block-layout-image_right.has-image,
.block-layout-image_top.has-image {
  align-items: stretch;
  gap: .25rem;
  padding: .6875rem;
}

/* Inset so the corners stay concentric with the card's own radius. The floor
   keeps the small-radius themes (terminal, at 4px) from computing a negative
   value, without ever exceeding the card's own corner. */
.block-layout-image_left.has-image > .block-icon,
.block-layout-image_right.has-image > .block-icon,
.block-layout-image_top.has-image > .block-icon {
  border-radius: max(4px, calc(var(--radius) - .6875rem));
}

/* Square, sized to the standard tile's inner height so it fills the card with
   just the frame showing. Deliberately not stretched: when a neighbour makes
   the row taller, a stretched side image degenerates into a 100x277 strip. */
.block-layout-image_left.has-image > .block-icon,
.block-layout-image_right.has-image > .block-icon {
  flex: none;
  align-self: center;
  width: 3.125rem;
  height: 3.125rem;
}

.block-layout-image_top.has-image > .block-icon {
  flex: 1;
  width: 100%;
  height: auto;
  min-height: 0;
}

.block-layout-image_only.has-image {
  align-items: stretch;
  padding: .375rem;
}

.block-layout-image_only.has-image > .block-icon {
  align-self: stretch;
  flex: 1;
  width: 100%;
  height: auto;
  border-radius: max(4px, calc(var(--radius) - .375rem));
  background: var(--bg);
  object-fit: contain;
}

@media (max-width: 44.9375rem) {
  /* Side-by-side image and copy need the full phone width. Vertically stacked,
     text-only and image-only cards keep the width selected in the editor. */
  :is(.block-layout-image_left, .block-layout-image_right).has-image {
    grid-column: span 2;
  }

  /* Narrow columns make titles and descriptions wrap more often. Keep the
     selected row size as a floor, but let one-row cards grow with their copy
     instead of clipping it against the fixed tile height. */
  .block-link.is-h1 {
    height: auto;
    min-height: var(--block-row);
  }

  /* A side-by-side card now owns the full row, so it no longer needs the square
     minimum used by half-width cells in a four-column profile. */
  :is(.block-layout-image_left, .block-layout-image_right).has-image.is-h1 {
    min-height: 6rem;
  }

  /* Full-width mobile cards have enough room for useful side media. */
  :is(.block-layout-image_left, .block-layout-image_right).has-image > .block-icon {
    align-self: stretch;
    width: min(42%, 10rem);
    height: auto;
  }
}

/* A desktop 1x1 on the four-column grid is a ~160px cell, so side media and
   text still need to stack there. Mobile side-image cards are full-width. */
@media (min-width: 45rem) {
  .blocks.is-cols-4
    > .block-layout-image_left.has-image.is-w1:is(.is-h2, .is-h3, .is-h4),
  .blocks.is-cols-4
    > .block-layout-image_right.has-image.is-w1:is(.is-h2, .is-h3, .is-h4) {
    flex-direction: column;
    text-align: center;
    gap: .5rem;
  }

  .blocks.is-cols-4
    > .block-layout-image_left.has-image.is-w1:is(.is-h2, .is-h3, .is-h4)
    > .block-body,
  .blocks.is-cols-4
    > .block-layout-image_right.has-image.is-w1:is(.is-h2, .is-h3, .is-h4)
    > .block-body {
    flex: none;
    align-items: center;
  }

  .blocks.is-cols-4
    > :is(.block-layout-image_left, .block-layout-image_right).has-image.is-w1:is(.is-h2, .is-h3, .is-h4)
    > .block-icon {
    align-self: stretch;
    flex: 1;
    width: 100%;
    height: auto;
    min-height: 0;
  }

  .blocks.is-cols-4
    > :is(.block-layout-image_left, .block-layout-image_right).has-image.is-w1.is-h1
    .block-desc {
    display: none;
  }
}

/* The card's own padding is now just a frame for the image, so the text keeps
   its inset here. Applied on both sides rather than only away from the image:
   a link can be set to an image layout without ever getting an image, and that
   text would otherwise sit against the frame.

   `flex: 1` matters for image_right: without it the body has no grow factor,
   so in a row-reverse flex line both children pack against the right edge and
   the text reads as right-aligned. Growing the body pins the image to the
   right while the text stays left-aligned. */
.block-layout-image_left.has-image > .block-body,
.block-layout-image_right.has-image > .block-body,
.block-layout-image_top.has-image > .block-body {
  justify-content: center;
  padding: .25rem .5rem;
}

.block-layout-image_left.has-image > .block-body,
.block-layout-image_right.has-image > .block-body { flex: 1; }

.block-layout-image_top.has-image > .block-body {
  flex: none;
  padding: .25rem .375rem .375rem;
}

.block-body { display: flex; flex-direction: column; min-width: 0; }
.block-title,
.block-desc {
  display: -webkit-box;
  overflow: hidden;
  overflow-wrap: anywhere;
  -webkit-box-orient: vertical;
}
.block-title {
  flex-shrink: 0;
  font-weight: 600;
  -webkit-line-clamp: 2;
}
.block-desc {
  font-size: .8125rem;
  color: var(--muted);
  -webkit-line-clamp: 6;
}
.is-highlighted .block-desc { color: inherit; opacity: .8; }

/* Headings label the group below them, so they need more room above than the
   grid gap gives -- otherwise the label reads as attached to the preceding
   group. Padding rather than margin because the label bottom-aligns in its
   cell, so the extra height lands above the text either way. Skipped on the
   first block, where the grid's own top margin already does the job. */
.block-heading {
  margin: 0;
  align-self: end;
  padding-bottom: .25rem;
  font-size: .75rem; text-transform: uppercase; letter-spacing: .12em;
  font-weight: 700; color: var(--muted);
}

.block-heading:not(:first-child) { padding-top: 1.25rem; }

.block-text {
  font-size: .9375rem;
  padding: 1rem 1.125rem;
  background: var(--surface);
  border-radius: var(--radius);
  overflow-wrap: anywhere;
}

.block-text p:first-child { margin-top: 0; }
.block-text p:last-child { margin-bottom: 0; }

.post-cover, .post-card-cover {
  width: 100%; border-radius: var(--radius); display: block;
}

/* Sized image blocks fill their cell so the grid stays tidy; a full-width 2x1
   image keeps its natural proportions, as it did before the grid existed. The
   frame gives light photos an edge so they don't bleed into the page. */
.block-image {
  display: flex;
  flex-direction: column;
  /* figure carries a default 1em/40px margin, which insets the whole tile and
     makes it read as smaller than the embed beside it. */
  margin: 0;
  padding: .375rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
}

.block-image img {
  width: 100%;
  border-radius: max(0px, calc(var(--radius) - .375rem));
  display: block;
  flex: 1;
  min-height: 0;
  object-fit: cover;
}

.block-image a { display: contents; }

.block-image figcaption {
  font-size: .8125rem;
  color: var(--muted);
  margin-top: .5rem;
  padding: 0 .25rem .125rem;
}

.block-embed { display: flex; }

.block-embed iframe {
  width: 100%; aspect-ratio: 16 / 9; border: 0;
  border-radius: var(--radius); display: block;
}

/* Once an embed is given a cell taller than 16:9 it should fill it rather than
   leave a gap under the player. */
.block-embed.is-h2 iframe,
.block-embed.is-h4 iframe { aspect-ratio: auto; height: 100%; }

/* Loaded from our own endpoint after the profile renders, so an upstream delay
   never holds up the rest of the page. */
.block-github {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: .75rem;
  padding: 1rem;
  min-height: 10.5rem;
  border: 1.5px solid var(--border);
  border-radius: var(--radius);
  background: transparent;
  overflow: hidden;
}

.github-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
}

.github-title {
  margin: 0;
  font-size: .9375rem;
  line-height: 1.3;
}

.github-summary,
.github-unavailable {
  margin: .2rem 0 0;
  color: var(--muted);
  font-size: .75rem;
  line-height: 1.4;
}

.github-profile-link {
  flex: none;
  color: var(--muted);
  font-size: .75rem;
  font-weight: 650;
  text-decoration: none;
}

.github-profile-link:hover { color: var(--accent); }

.github-scroll {
  overflow-x: auto;
  scrollbar-width: thin;
  overscroll-behavior-inline: contain;
}

.github-graph {
  display: flex;
  gap: 3px;
  width: max-content;
  min-width: 100%;
}

.github-week {
  display: grid;
  grid-template-rows: repeat(7, 9px);
  gap: 3px;
}

.github-week i,
.github-legend i {
  display: block;
  width: 9px;
  height: 9px;
  border-radius: 2px;
  background: color-mix(in srgb, var(--border) 75%, var(--bg));
}

.github-week i.is-empty { visibility: hidden; }
.github-week i[data-level="1"],
.github-legend i[data-level="1"] { background: color-mix(in srgb, var(--accent) 28%, var(--bg)); }
.github-week i[data-level="2"],
.github-legend i[data-level="2"] { background: color-mix(in srgb, var(--accent) 50%, var(--bg)); }
.github-week i[data-level="3"],
.github-legend i[data-level="3"] { background: color-mix(in srgb, var(--accent) 72%, var(--bg)); }
.github-week i[data-level="4"],
.github-legend i[data-level="4"] { background: var(--accent); }

.github-legend {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 3px;
  color: var(--muted);
  font-size: .625rem;
}

.github-legend i { flex: none; }

.github-tooltip {
  position: absolute;
  z-index: 2;
  max-width: calc(100% - 1rem);
  width: max-content;
  padding: .35rem .5rem;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--fg);
  color: var(--bg);
  box-shadow: var(--shadow);
  font-size: .6875rem;
  font-weight: 600;
  line-height: 1.35;
  text-align: center;
  white-space: normal;
  pointer-events: none;
  transform: translate(-50%, -100%);
}

.github-tooltip::after {
  position: absolute;
  top: 100%;
  left: 50%;
  width: 7px;
  height: 7px;
  background: var(--fg);
  content: "";
  transform: translate(-50%, -50%) rotate(45deg);
}

/* --- posts --------------------------------------------------------------- */

.section-title {
  font-size: .75rem; text-transform: uppercase; letter-spacing: .12em;
  font-weight: 700; color: var(--muted); margin-bottom: 1rem;
}

.stream { margin-top: 2.5rem; }

.post-card { border-top: 1.5px solid var(--border); }
.post-card-short { padding: 1.25rem 0; }
.post-card-main {
  display: block;
  padding: 1.25rem 0;
  color: inherit;
  text-decoration: none;
}
.post-card-title {
  margin: 0 0 .5rem;
  font-size: 1.1875rem;
  transition: color .15s ease;
}
.post-card-featured {
  display: inline-flex;
  margin-bottom: .625rem;
  padding: .2rem .5rem;
  border: 1px solid var(--accent);
  border-radius: 999px;
  color: var(--accent);
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .08em;
  line-height: 1;
  text-transform: uppercase;
}
.post-card-main:hover .post-card-title,
.post-card-main:focus-visible .post-card-title { color: var(--accent); }
.post-card-main:focus-visible {
  border-radius: var(--radius-sm);
  outline: 3px solid var(--accent);
  outline-offset: 4px;
}
.post-card-excerpt, .post-card-body { margin: .25rem 0; }
.post-card-body > :first-child { margin-top: 0; }
.post-card-body > :last-child { margin-bottom: 0; }
.post-card-body h1, .post-card-body h2, .post-card-body h3,
.post-card-body h4, .post-card-body h5, .post-card-body h6 {
  margin: .75rem 0 .375rem; line-height: 1.25;
}
.post-card-body h1 { font-size: 1.5rem; }
.post-card-body h2 { font-size: 1.3rem; }
.post-card-body h3 { font-size: 1.125rem; }
.post-card-body h4, .post-card-body h5, .post-card-body h6 { font-size: 1rem; }
.post-card-body ul, .post-card-body ol { padding-left: 1.5rem; }
.post-card-body pre {
  overflow-x: auto; padding: .75rem;
  border-radius: var(--radius-sm); background: var(--surface);
}
.post-card-body code { font-family: ui-monospace, Menlo, monospace; font-size: .875em; }
.post-card-body blockquote {
  margin: .75rem 0; padding-left: .875rem;
  border-left: 3px solid var(--accent); color: var(--muted);
}
.post-card-body img { max-width: 100%; height: auto; border-radius: var(--radius); }
.post-card-body table { width: 100%; border-collapse: collapse; }
.post-card-body th, .post-card-body td {
  border: 1.5px solid var(--border); padding: .5rem; text-align: left;
}
.post-card-body hr, .prose hr {
  border: 0; border-top: 1.5px solid var(--border); margin: 1.5rem 0;
}
.post-card-body .note, .post-card-body .tip, .post-card-body .danger,
.post-card-body .info, .post-card-body .caution,
.prose .note, .prose .tip, .prose .danger, .prose .info, .prose .caution {
  margin: 1rem 0; padding: .75rem 1rem;
  border-left: 4px solid var(--accent); border-radius: var(--radius-sm);
  background: var(--surface);
}
.post-card-cover { margin: .75rem 0; }

.post-card-link {
  font-size: .8125rem; color: var(--muted); word-break: break-all;
}

.post-card-time {
  display: block; margin-top: .5rem;
  font-size: .75rem; font-weight: 500; color: var(--muted);
}

/* --- posts archive ------------------------------------------------------- */

.page-archive .archive {
  max-width: none;
  padding: 0;
}

.archive-shell {
  max-width: 76rem;
  margin: 0 auto;
  padding: clamp(2.75rem, 5vw, 4.5rem) 1.5rem 0;
}

.archive-header {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 2rem;
}

.archive-identity {
  display: flex;
  align-items: center;
  gap: 1.25rem;
  min-width: 0;
}

.archive-avatar {
  position: relative;
  display: grid;
  width: 80px;
  height: 80px;
  overflow: hidden;
  flex: none;
  place-items: center;
  border-radius: 50%;
  background: var(--surface);
  color: var(--accent);
  font-family: var(--font-heading);
  font-size: 1.75rem;
  font-weight: 700;
  text-decoration: none;
}

.archive-avatar img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.archive-kicker,
.archive-card-kicker {
  display: block;
  color: var(--accent);
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.archive-header h1 {
  margin: .25rem 0 0;
  font-size: clamp(2.5rem, 5vw, 4.75rem);
  letter-spacing: -.055em;
}

.archive-header p {
  max-width: 42rem;
  margin: .4rem 0 0;
  color: var(--muted);
  font-size: .9375rem;
}

.archive-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: flex-end;
  gap: .5rem 1rem;
  padding-bottom: .35rem;
  color: var(--muted);
  font-size: .75rem;
  font-weight: 600;
}

.archive-actions a { color: inherit; text-decoration: none; }
.archive-actions a:hover { color: var(--accent); }

.archive-feature-section { margin-top: clamp(3rem, 7vw, 5rem); }

.archive-feature {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(19rem, .85fr);
  min-height: 25rem;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) + 4px);
  background: var(--bg);
  color: inherit;
  text-decoration: none;
  transition: border-color .15s ease, transform .2s ease;
}

.archive-feature:not(.has-cover) { grid-template-columns: minmax(0, 46rem); min-height: 22rem; }
.archive-feature:hover { border-color: var(--accent); transform: translateY(-3px); }

.archive-feature-cover {
  display: block;
  min-height: 100%;
  overflow: hidden;
  background: var(--surface);
}

.archive-feature-cover img,
.archive-card-cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .3s ease;
}

.archive-feature:hover img,
.archive-article-card:hover img { transform: scale(1.025); }

.archive-feature-copy {
  display: flex;
  min-width: 0;
  flex-direction: column;
  justify-content: center;
  padding: clamp(2rem, 5vw, 4rem);
}

.archive-feature h2 {
  margin: .65rem 0 1rem;
  font-size: clamp(2rem, 4vw, 3.75rem);
  line-height: 1.03;
  letter-spacing: -.05em;
}

.archive-feature-excerpt,
.archive-card-excerpt {
  color: var(--muted);
  line-height: 1.65;
}

.archive-card-meta {
  display: flex;
  gap: .45rem;
  color: var(--muted);
  font-size: .75rem;
  font-weight: 600;
}

.archive-feature .archive-card-meta { margin-top: 1.5rem; }

.archive-read-link {
  margin-top: 1.25rem;
  color: var(--accent);
  font-size: .8125rem;
  font-weight: 700;
}

.archive-section { margin-top: clamp(4rem, 8vw, 6rem); }
.archive-section-heading h2 {
  margin: .35rem 0 0;
  font-size: clamp(1.75rem, 3vw, 2.5rem);
  letter-spacing: -.04em;
}

.archive-article-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1.5rem;
  margin-top: 1.5rem;
}

.archive-article-card {
  display: flex;
  min-width: 0;
  min-height: 22rem;
  overflow: hidden;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  color: inherit;
  text-decoration: none;
  transition: border-color .15s ease, transform .2s ease;
}

.archive-article-card:hover { border-color: var(--accent); transform: translateY(-3px); }

.archive-card-cover {
  display: block;
  overflow: hidden;
  border-bottom: 1px solid var(--border);
  background: var(--surface);
  aspect-ratio: 16 / 9;
}

.archive-card-copy {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 1.5rem;
}

.archive-article-card h3 {
  margin: .75rem 0;
  font-size: 1.5rem;
  line-height: 1.15;
  letter-spacing: -.025em;
}

.archive-article-card:hover h3 { color: var(--accent); }
.archive-card-copy .archive-card-excerpt {
  display: -webkit-box;
  overflow: hidden;
  font-size: .875rem;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}

.archive-card-copy .archive-read-link { margin-top: auto; padding-top: 1.25rem; }

.archive-update-list {
  display: grid;
  gap: 1rem;
  max-width: 50rem;
  margin-top: 1.5rem;
}

.archive-update {
  padding: 1.5rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.archive-update > time {
  display: block;
  margin-bottom: .65rem;
  color: var(--muted);
  font-size: .6875rem;
  font-weight: 600;
}

.archive-update .post-card-body { max-width: none; }
.archive-update-cover {
  display: block;
  width: 100%;
  max-height: 24rem;
  margin-top: 1rem;
  border-radius: var(--radius-sm);
  object-fit: cover;
}

.archive-update-link {
  display: inline-block;
  margin-top: 1rem;
  color: var(--accent);
  font-size: .8125rem;
  font-weight: 700;
  text-decoration: none;
}

.archive-empty {
  max-width: 36rem;
  margin-top: 5rem;
  padding: 2rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
}

.archive-empty h2 { margin: .5rem 0; font-size: 1.75rem; }
.archive-empty p { margin: 0; color: var(--muted); }
.archive-empty a {
  display: inline-block;
  margin-top: 1.25rem;
  color: var(--accent);
  font-size: .8125rem;
  font-weight: 700;
  text-decoration: none;
}

.archive-pagination {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 1rem;
  margin-top: 4rem;
  color: var(--muted);
  font-size: .8125rem;
  font-weight: 600;
}

.archive-pagination > :last-child { justify-self: end; }
.archive-pagination a {
  color: var(--accent);
  text-decoration: none;
}

.archive-tail {
  max-width: 76rem;
  margin: 4rem auto 0;
  padding: 0 1.5rem 3rem;
}

.post-nav { margin-bottom: 1.5rem; font-size: .875rem; font-weight: 500; }
.post-nav a { color: var(--muted); text-decoration: none; }
.post-nav a:hover { color: var(--accent); }

.page-post .post {
  max-width: none;
  padding: 0;
}

.post-masthead {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-height: 4.75rem;
  padding: .75rem clamp(1rem, 4vw, 3rem);
  border-bottom: 1px solid var(--border);
}

.post-publication {
  display: inline-flex;
  align-items: center;
  gap: .75rem;
  color: var(--fg);
  text-decoration: none;
}

.post-publication-avatar,
.post-byline-avatar,
.post-author-avatar {
  position: relative;
  display: grid;
  flex: none;
  place-items: center;
  overflow: hidden;
  border-radius: 50%;
  background: var(--surface);
  color: var(--accent);
  font-family: var(--font-heading);
  font-weight: 700;
}

.post-publication-avatar { width: 36px; height: 36px; font-size: .875rem; }
.post-publication-avatar img,
.post-byline-avatar img,
.post-author-avatar img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.post-publication strong,
.post-publication small { display: block; line-height: 1.2; }
.post-publication strong { font-size: .875rem; }
.post-publication small { margin-top: .125rem; color: var(--muted); font-size: .6875rem; }
.post-wordmark { font-size: .875rem; }

.post-preview {
  max-width: 72rem;
  margin: 1.5rem auto 0;
}

.post-article {
  max-width: 76rem;
  margin: 0 auto;
  padding: clamp(2.75rem, 5vw, 4.5rem) 1.5rem 0;
}

.post-header {
  max-width: 61rem;
  margin: 0 auto;
}

.post-header h1 {
  max-width: 20ch;
  margin: 0;
  font-size: clamp(2.75rem, 6.4vw, 5.5rem);
  line-height: .99;
  letter-spacing: -.06em;
  overflow-wrap: anywhere;
}

.post-byline {
  display: flex;
  align-items: center;
  gap: .875rem;
  margin-top: 2rem;
}

.post-byline-avatar {
  width: 48px;
  height: 48px;
  box-shadow: 0 0 0 1px var(--border);
  text-decoration: none;
}

.post-byline-name {
  font-size: .9375rem;
  font-weight: 700;
  text-decoration: none;
}

.post-byline-name:hover { color: var(--accent); }

.post-meta {
  display: flex;
  align-items: center;
  gap: .5rem;
  margin: .2rem 0 0;
  color: var(--muted);
  font-size: .8125rem;
  font-weight: 500;
}

.post-cover {
  width: 100%;
  max-height: 42rem;
  margin: clamp(2.5rem, 6vw, 4.5rem) 0 0;
  border: 1px solid var(--border);
  border-radius: calc(var(--radius) + 4px);
  object-fit: cover;
}

.post-content {
  display: grid;
  grid-template-columns: 4rem minmax(0, 42rem) minmax(12rem, 16rem);
  justify-content: center;
  gap: 2.25rem;
  margin-top: clamp(3rem, 7vw, 5.5rem);
}

.post-share {
  position: sticky;
  top: 2rem;
  align-self: start;
  color: var(--muted);
}

.post-share-label,
.post-author-label,
.post-related-kicker {
  display: block;
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.post-share-label { margin-bottom: .75rem; text-align: center; }
.post-share-actions { display: grid; justify-content: center; gap: .5rem; }

.post-share-action {
  display: grid;
  width: 42px;
  height: 42px;
  padding: 0;
  place-items: center;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--bg);
  color: var(--muted);
  cursor: pointer;
  transition: border-color .15s ease, color .15s ease, transform .15s ease;
}

.post-share-action[hidden] { display: none; }
.post-share-action:hover { border-color: var(--accent); color: var(--accent); transform: translateY(-2px); }
.post-share-action:focus-visible { outline: 3px solid var(--accent); outline-offset: 2px; }
.post-share-action svg {
  width: 18px;
  height: 18px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 1.75;
}

.post-share-status {
  display: block;
  width: 7rem;
  margin: .75rem 0 0 -1.5rem;
  font-size: .6875rem;
  line-height: 1.3;
  text-align: center;
}

.post-toc {
  position: sticky;
  top: 2rem;
  align-self: start;
  min-width: 0;
  padding-left: 1.5rem;
  border-left: 1px solid var(--border);
}

.post-toc[hidden] { display: none; }

.post-toc-label {
  display: block;
  margin-bottom: .875rem;
  color: var(--muted);
  font-size: .6875rem;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
}

.post-toc-nav {
  display: grid;
  max-height: min(60vh, 28rem);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}

.post-toc-link {
  position: relative;
  padding: .45rem 0 .45rem .875rem;
  color: var(--muted);
  font-size: .8125rem;
  font-weight: 500;
  line-height: 1.4;
  text-decoration: none;
  transition: color .15s ease;
}

.post-toc-link::before {
  position: absolute;
  top: .5rem;
  bottom: .5rem;
  left: 0;
  width: 2px;
  border-radius: 99px;
  background: var(--accent);
  content: "";
  opacity: 0;
  transform: scaleY(.4);
  transition: opacity .15s ease, transform .15s ease;
}

.post-toc-link:hover { color: var(--fg); }
.post-toc-link[aria-current="true"] { color: var(--fg); font-weight: 700; }
.post-toc-link[aria-current="true"]::before { opacity: 1; transform: scaleY(1); }
.post-toc-h3 { padding-left: 1.5rem; font-size: .75rem; }

.page-post .prose {
  grid-column: 2;
  min-width: 0;
  font-size: 1.125rem;
  line-height: 1.82;
  overflow-wrap: break-word;
}

.page-post .prose > :first-child { margin-top: 0; }
.page-post .prose > :last-child { margin-bottom: 0; }
.page-post .prose p { margin: 0 0 1.5em; }
.page-post .prose > p:first-child { font-size: 1.25rem; line-height: 1.65; }
.page-post .prose h1,
.page-post .prose h2,
.page-post .prose h3,
.page-post .prose h4 {
  scroll-margin-top: 2rem;
}
.page-post .prose h1 { margin: 2.5em 0 .7em; font-size: 2rem; }
.page-post .prose h2 { margin: 2.75em 0 .75em; font-size: 1.65rem; }
.page-post .prose h3 { margin: 2.25em 0 .65em; font-size: 1.3rem; }
.page-post .prose h4 { margin: 2em 0 .6em; font-size: 1.1rem; }
.page-post .prose ul,
.page-post .prose ol { margin: 0 0 1.5em; padding-left: 1.4em; }
.page-post .prose li { margin: .4em 0; padding-left: .25em; }
.page-post .prose a { color: var(--accent); text-underline-offset: .18em; }
.page-post .prose blockquote {
  margin: 2.25rem 0;
  padding: 1.5rem 1.75rem;
  border: 0;
  border-left: 4px solid var(--accent);
  border-radius: 0 var(--radius) var(--radius) 0;
  background: var(--surface);
  color: var(--fg);
  font-size: 1.125rem;
}
.page-post .prose blockquote > :last-child { margin-bottom: 0; }
.page-post .prose pre {
  position: relative;
  margin: 2rem 0;
  padding: 2.75rem 1.25rem 1.125rem;
  border: 1px solid var(--code-border);
  background: var(--code-bg);
  color: var(--code-fg);
  font-size: .8125rem;
  line-height: 1.5;
}
.page-post .prose pre code {
  display: block;
  padding: 0;
  background: transparent;
  color: inherit;
  font-size: inherit;
}

.post-code-copy {
  position: absolute;
  top: .65rem;
  right: .65rem;
  display: inline-flex;
  align-items: center;
  gap: .35rem;
  padding: .35rem .55rem;
  border: 1px solid var(--code-border);
  border-radius: 6px;
  background: rgba(255, 255, 255, .06);
  color: #b8b8c4;
  font: 600 .6875rem/1 var(--font);
  cursor: pointer;
  transition: background .15s ease, color .15s ease;
}

.post-code-copy:hover,
.post-code-copy.is-copied { background: rgba(255, 255, 255, .12); color: var(--code-fg); }
.post-code-copy:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.post-code-copy svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-width: 1.75;
}

.page-post .prose .hljs-comment,
.page-post .prose .hljs-quote { color: #8a8a9a; }
.page-post .prose .hljs-keyword,
.page-post .prose .hljs-selector-tag,
.page-post .prose .hljs-literal { color: #c792ea; }
.page-post .prose .hljs-string,
.page-post .prose .hljs-attribute,
.page-post .prose .hljs-template-tag { color: #c3e88d; }
.page-post .prose .hljs-number,
.page-post .prose .hljs-symbol,
.page-post .prose .hljs-bullet { color: #f78c6c; }
.page-post .prose .hljs-title,
.page-post .prose .hljs-section,
.page-post .prose .hljs-function { color: #82aaff; }
.page-post .prose .hljs-built_in,
.page-post .prose .hljs-type,
.page-post .prose .hljs-name { color: #ffcb6b; }
.page-post .prose .hljs-variable,
.page-post .prose .hljs-params { color: #f3f3f6; }

.page-post .prose pre:has(> code.language-mermaid) {
  position: relative;
  min-height: 15rem;
  margin: 2.25rem 0;
  padding: 1.5rem;
  overflow: hidden;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  color: transparent;
}

.page-post .prose pre > code.language-mermaid {
  visibility: hidden;
}

.page-post .prose pre:has(> code.language-mermaid)::before,
.page-post .prose pre:has(> code.language-mermaid)::after {
  position: absolute;
  inset: 1.5rem;
  content: "";
}

.page-post .prose pre:has(> code.language-mermaid)::before {
  background:
    linear-gradient(var(--surface) 0 0) 0 0 / 40% 30px no-repeat,
    linear-gradient(var(--surface) 0 0) 0 46px / 60% 30px no-repeat,
    linear-gradient(var(--surface) 0 0) 0 92px / 80% 30px no-repeat,
    linear-gradient(var(--surface) 0 0) 0 138px / 100% 30px no-repeat;
}

.page-post .prose pre:has(> code.language-mermaid)::after {
  background: linear-gradient(
    100deg,
    transparent 35%,
    color-mix(in srgb, var(--surface) 35%, white) 50%,
    transparent 65%
  );
  background-position: 100% 0;
  background-size: 200% 100%;
  -webkit-mask:
    linear-gradient(#000 0 0) 0 0 / 40% 30px no-repeat,
    linear-gradient(#000 0 0) 0 46px / 60% 30px no-repeat,
    linear-gradient(#000 0 0) 0 92px / 80% 30px no-repeat,
    linear-gradient(#000 0 0) 0 138px / 100% 30px no-repeat;
  mask:
    linear-gradient(#000 0 0) 0 0 / 40% 30px no-repeat,
    linear-gradient(#000 0 0) 0 46px / 60% 30px no-repeat,
    linear-gradient(#000 0 0) 0 92px / 80% 30px no-repeat,
    linear-gradient(#000 0 0) 0 138px / 100% 30px no-repeat;
  animation: post-mermaid-shimmer 1.4s ease-in-out infinite;
}

@keyframes post-mermaid-shimmer {
  to { background-position: -100% 0; }
}

.post-mermaid {
  margin: 2.25rem 0;
  padding: 1.5rem;
  overflow-x: auto;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  text-align: center;
}

.post-mermaid svg {
  display: block;
  max-width: 100%;
  height: auto;
  margin: 0 auto;
}

.post-mermaid-error {
  color: var(--muted);
  font: 600 .875rem/1.4 var(--font);
}

@media (prefers-reduced-motion: reduce) {
  .page-post .prose pre:has(> code.language-mermaid)::after {
    animation: none;
  }
}

.page-post .prose :not(pre) > code {
  padding: .15em .35em;
  border-radius: 4px;
  background: var(--surface);
}
.page-post .prose img {
  display: block;
  height: auto;
  margin: 2.25rem auto;
  border: 1px solid var(--border);
}
.page-post .prose table {
  display: block;
  width: 100%;
  margin: 2rem 0;
  overflow-x: auto;
  white-space: nowrap;
}
.page-post .prose th,
.page-post .prose td { padding: .75rem .875rem; }
.page-post .prose hr { margin: 3rem 0; }

.post-author-row {
  display: grid;
  grid-template-columns: 4rem minmax(0, 42rem) minmax(12rem, 16rem);
  justify-content: center;
  gap: 2.25rem;
  margin-top: clamp(3.5rem, 7vw, 5rem);
}

.post-author {
  display: grid;
  grid-column: 2;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: center;
  gap: 1.25rem;
  width: 100%;
  padding: .5rem 0;
}

.post-author-avatar { width: 72px; height: 72px; font-size: 1.5rem; text-decoration: none; }
.post-author-label { margin-bottom: .2rem; color: var(--muted); }
.post-author h2 { margin: 0; font-size: 1.25rem; }
.post-author h2 a { text-decoration: none; }
.post-author-copy p { margin: .35rem 0 0; color: var(--muted); font-size: .875rem; line-height: 1.5; }
.post-author-link {
  color: var(--accent);
  font-size: .8125rem;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}

.post-related {
  max-width: 76rem;
  margin: clamp(3.5rem, 7vw, 5.5rem) auto 0;
  padding: 0 1.5rem;
}

.post-related-heading {
  display: flex;
  align-items: end;
  justify-content: space-between;
  gap: 1.5rem;
}

.post-related-kicker { margin-bottom: .35rem; color: var(--accent); }
.post-related-heading h2 { margin: 0; font-size: clamp(1.75rem, 3vw, 2.5rem); letter-spacing: -.04em; }
.post-related-heading > a {
  color: var(--muted);
  font-size: .8125rem;
  font-weight: 700;
  text-decoration: none;
  white-space: nowrap;
}
.post-related-heading > a:hover { color: var(--accent); }

.post-related-grid {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1.5rem;
  padding-top: 1.5rem;
}

.post-related-card {
  display: flex;
  min-width: 0;
  min-height: 100%;
  overflow: hidden;
  flex-direction: column;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--bg);
  color: inherit;
  text-decoration: none;
  transition: border-color .15s ease, transform .15s ease;
}

.post-related-card:only-child { max-width: 32rem; }
.post-related-card:hover { border-color: var(--accent); transform: translateY(-3px); }
.post-related-cover {
  display: block;
  overflow: hidden;
  border-bottom: 1px solid var(--border);
  background: var(--bg);
  aspect-ratio: 16 / 9;
}
.post-related-cover img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .25s ease;
}
.post-related-card:hover .post-related-cover img { transform: scale(1.025); }
.post-related-copy {
  display: flex;
  flex: 1;
  flex-direction: column;
  padding: 1.25rem;
}
.post-related-meta {
  display: flex;
  gap: .4rem;
  margin: 0 0 .6rem;
  color: var(--muted);
  font-size: .6875rem;
  font-weight: 600;
}
.post-related-card h3 { margin: 0; font-size: 1.15rem; line-height: 1.25; }
.post-related-card:hover h3 { color: var(--accent); }
.post-related-copy > p:last-child {
  display: -webkit-box;
  margin: .65rem 0 0;
  overflow: hidden;
  color: var(--muted);
  font-size: .8125rem;
  line-height: 1.55;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}
.post-related-copy > p:last-child { margin-bottom: 0; }

.post-tail {
  max-width: 76rem;
  margin: 4rem auto 0;
  padding: 0 1.5rem 3rem;
}

.more-link {
  display: inline-block; margin-top: 1.25rem;
  font-size: .875rem; font-weight: 600; color: var(--accent);
  text-decoration: none;
}

.more-link:hover { text-decoration: underline; }

.prose { font-size: 1.0625rem; }
.prose img { max-width: 100%; border-radius: var(--radius); }
.prose pre { background: var(--surface); padding: 1rem; border-radius: var(--radius); overflow-x: auto; }
.prose code { font-family: ui-monospace, Menlo, monospace; font-size: .875em; }

.prose blockquote {
  margin: 1.5rem 0; padding: .25rem 0 .25rem 1.125rem;
  border-left: 4px solid var(--accent); color: var(--muted);
}

.prose table { width: 100%; border-collapse: collapse; }
.prose th, .prose td { border: 1.5px solid var(--border); padding: .5rem; text-align: left; }
.prose th { background: var(--surface); font-weight: 700; }

/* --- forms and buttons --------------------------------------------------- */

.btn {
  display: inline-block; padding: .625rem 1.25rem; border-radius: var(--radius-sm);
  border: 1.5px solid var(--border); background: var(--bg); color: var(--fg);
  font: inherit; font-weight: 600; cursor: pointer; text-decoration: none;
}

.btn:hover { border-color: var(--accent); }
.btn-primary { background: var(--accent); color: var(--accent-fg); border-color: var(--accent); }
.btn-small { padding: .375rem .875rem; font-size: .875rem; }

input, textarea, select {
  font: inherit; color: var(--fg); background: var(--bg);
  padding: .625rem .75rem; border: 1.5px solid var(--border);
  border-radius: var(--radius-sm); width: 100%;
}

input:focus, textarea:focus { outline: 2px solid var(--accent); outline-offset: 1px; }
label { font-size: .8125rem; font-weight: 600; }

.stack { display: flex; flex-direction: column; gap: .5rem; text-align: left; }
.hint, .fine, .muted { color: var(--muted); font-size: .8125rem; }
.error { color: #b42318; font-size: .875rem; }
.notice { background: var(--surface); padding: .625rem .875rem; border-radius: var(--radius-sm); font-size: .875rem; }
.field-status { font-size: .8125rem; min-height: 1.25rem; }
.field-status.ok { color: #067647; }
.field-status.bad { color: #b42318; }

.username-field, .claim {
  display: flex; align-items: center; gap: .25rem;
  border: 1.5px solid var(--border); border-radius: var(--radius-sm);
  padding: .25rem .25rem .25rem .75rem; background: var(--bg);
}

.username-field input, .claim input { border: 0; padding: .5rem .25rem; }
.username-field input:focus, .claim input:focus { outline: none; }
.prefix { color: var(--muted); white-space: nowrap; }

.divider { display: flex; align-items: center; gap: .75rem; margin: 1.5rem 0; color: var(--muted); font-size: .8125rem; }
.divider::before, .divider::after { content: ""; flex: 1; height: 1.5px; background: var(--border); }

/* --- shared page furniture ----------------------------------------------- */
/* The landing, sign-in and onboarding pages are product chrome rather than
   user-themeable content, so their styles live in marketing.css / auth.css on
   top of the --app-* tokens. What remains here is used by the public profile,
   post and document pages, which are themeable. */

.wordmark {
  display: inline-flex; align-items: baseline; gap: 3px;
  font-family: var(--font-heading);
  font-weight: 700; letter-spacing: -.03em; text-decoration: none;
}

.wordmark::after {
  content: "";
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent);
}

/* The footer is the only place the product speaks on a user's own page, so it
   stays a single quiet line of links rather than a card or a banner. */
.site-footer {
  display: flex; flex-wrap: wrap;
  justify-content: center; align-items: center; gap: .625rem;
  max-width: 60rem; margin: 3rem auto 0;
  padding: 1.5rem 1.5rem 0;
  border-top: 1.5px solid var(--border);
  color: var(--muted); font-size: .8125rem; font-weight: 500;
}

.site-footer a { color: inherit; text-decoration: none; transition: color .15s ease; }
.site-footer a:hover { color: var(--accent); }

.site-footer-brand strong { color: var(--fg); font-weight: 700; }
.site-footer-brand:hover strong { color: inherit; }

/* Element+class beats the plain `.site-footer a` rule above it. */
.site-footer a.site-footer-cta { color: var(--accent); }

.site-footer .arrow { display: inline-block; transition: transform .15s ease; }
.site-footer a:hover .arrow { transform: translateX(2px); }

/* A dot rather than a pipe: lighter, and it disappears cleanly when the row
   wraps onto two lines on a phone. */
.site-footer-sep {
  width: 3px; height: 3px; border-radius: 50%;
  background: currentColor; opacity: .45;
}

/* --- ads ----------------------------------------------------------------- */

.ad-slot {
  margin: 2.5rem 0 0; padding: .875rem; text-align: center;
  border: 1.5px dashed var(--border); border-radius: var(--radius);
}

.ad-label {
  font-size: .625rem; text-transform: uppercase; letter-spacing: .12em;
  font-weight: 700; color: var(--muted);
}

.editor-loading { padding: 4rem; text-align: center; color: var(--muted); }
.empty { color: var(--muted); }

/* --- documents ----------------------------------------------------------- */
/* about / terms / privacy. These are product pages rather than user content,
   but they reuse .doc + .prose, so they only need a slightly wider measure
   and a clear heading rhythm. */

.doc { max-width: 42rem; }
.doc h1 { margin: 1.5rem 0 1rem; font-size: 2.25rem; }
.doc h2 { margin: 2.5rem 0 .75rem; font-size: 1.375rem; }

/* --- not found ----------------------------------------------------------- */
/* Reached by following a dead link, so it stays short: what happened, whether
   the handle is free, one action. */

.notfound {
  max-width: var(--width);
  margin: 0 auto;
  padding: 6rem 1.5rem 3rem;
  text-align: center;
}

.notfound-eyebrow {
  margin: 0;
  font-size: .6875rem; font-weight: 700;
  letter-spacing: .16em; text-transform: uppercase;
  color: var(--muted);
}

.notfound-title {
  margin: .875rem 0 0;
  font-family: var(--font-heading);
  font-size: 2.25rem; font-weight: 700;
  letter-spacing: -.035em; line-height: 1.08;
}

.notfound-sub {
  margin: 1rem 0 0;
  font-size: 1.0625rem; color: var(--muted);
}

/* The handle is the reason the visitor is here, so it reads as the subject of
   the sentence rather than as body copy. */
.notfound-handle { color: var(--fg); font-weight: 600; }

.notfound-action { margin-top: 2rem; }

.notfound .arrow { display: inline-block; transition: transform .15s ease; }
.notfound-action:hover .arrow { transform: translateX(2px); }

/* Pushed away from the action so the two never read as one control group. */
.notfound .site-footer { margin-top: 5rem; }

/* --- responsive ---------------------------------------------------------- */

@media (max-width: 560px) {
  .profile, .post, .archive, .doc { padding: 2rem 1rem 3rem; }
  .profile-name { font-size: 1.625rem; }
  .doc h1 { font-size: 1.75rem; }
  .notfound { padding: 4rem 1.25rem 2.5rem; }
  .notfound-title { font-size: 1.875rem; }
  .notfound-sub { font-size: 1rem; }
}

@media (max-width: 760px) {
  .post-masthead { min-height: 4.25rem; }
  .post-publication small { display: none; }
  .post-wordmark { font-size: .8125rem; }
  .post-preview { margin: 1rem; }
  .post-article { padding: 2.25rem 1rem 0; }
  .post-header h1 { font-size: clamp(2.5rem, 12vw, 4rem); line-height: 1.02; }
  .post-byline { margin-top: 1.5rem; }
  .post-cover { margin-top: 2.5rem; border-radius: var(--radius); }
  .post-content {
    display: flex;
    flex-direction: column;
    gap: 1.75rem;
    margin-top: 3rem;
  }
  .post-share { position: static; order: 0; }
  .post-share-label { margin-bottom: .625rem; text-align: left; }
  .post-share-actions { display: flex; justify-content: flex-start; }
  .post-share-action { width: 40px; height: 40px; }
  .post-share-status { width: auto; margin: .625rem 0 0; text-align: left; }
  .post-toc { display: none; }
  .page-post .prose { order: 1; font-size: 1.0625rem; line-height: 1.78; }
  .page-post .prose > p:first-child { font-size: 1.15rem; }
  .page-post .prose h1 { font-size: 1.75rem; }
  .page-post .prose h2 { margin-top: 2.25em; font-size: 1.45rem; }
  .page-post .prose h3 { font-size: 1.2rem; }
  .page-post .prose blockquote { margin: 1.75rem 0; padding: 1.25rem; }
  .post-author-row { display: block; margin-top: 3.5rem; }
  .post-author {
    grid-template-columns: auto minmax(0, 1fr);
    padding: .25rem 0;
  }
  .post-author-avatar { width: 58px; height: 58px; }
  .post-author-link { grid-column: 2; }
  .post-related { margin-top: 4rem; padding: 0 1rem; }
  .post-related-grid { grid-template-columns: 1fr; gap: 2rem; }
  .post-related-card.has-cover {
    display: grid;
    grid-template-columns: minmax(6.5rem, .75fr) minmax(0, 1.5fr);
  }
  .post-related-card:only-child { max-width: none; }
  .post-related-cover {
    height: 100%;
    border-right: 1px solid var(--border);
    border-bottom: 0;
    aspect-ratio: auto;
  }
  .post-related-copy { padding: 1rem; }
  .post-related-copy > p:last-child { -webkit-line-clamp: 2; }
  .post-tail { margin-top: 3rem; padding: 0 1rem 2rem; }

  .archive-shell { padding: 2.25rem 1rem 0; }
  .archive-header { display: block; }
  .archive-identity { align-items: flex-start; }
  .archive-avatar { width: 58px; height: 58px; font-size: 1.25rem; }
  .archive-header h1 { font-size: 2.5rem; }
  .archive-actions { justify-content: flex-start; margin: 1.25rem 0 0 4.875rem; }
  .archive-feature-section { margin-top: 3rem; }
  .archive-feature,
  .archive-feature:not(.has-cover) {
    display: flex;
    min-height: 0;
    flex-direction: column;
  }
  .archive-feature-cover { min-height: 0; aspect-ratio: 16 / 9; }
  .archive-feature-copy { padding: 1.5rem; }
  .archive-feature h2 { font-size: 2rem; }
  .archive-section { margin-top: 4rem; }
  .archive-article-grid { grid-template-columns: 1fr; }
  .archive-article-card { min-height: 0; }
  .archive-update { padding: 1.25rem; }
  .archive-pagination { margin-top: 3rem; font-size: .75rem; }
  .archive-tail { margin-top: 3rem; padding: 0 1rem 2rem; }
}

@media (min-width: 761px) and (max-width: 1100px) {
  .post-content { grid-template-columns: 4rem minmax(0, 42rem); }
  .post-author-row { grid-template-columns: 4rem minmax(0, 42rem); }
  .post-toc { display: none; }
}

/* Desktop. Everything here is additive and gated behind min-width, so the
   phone layout -- and the editor's phone preview, which is the only place the
   block sizes are visible while editing -- is untouched.

   Only .profile widens. .post, .archive and .doc are prose and keep --width so
   their reading measure stays comfortable. */
@media (min-width: 45rem) {
  .profile { max-width: 45rem; padding: 3.5rem 2rem 5rem; }

  /* A 1x1 tile is ~340px wide here and ~425px at the next step, so it needs
     real height or it reads as a stretched button rather than a tile. */
  .blocks {
    --block-row: 7rem;
    --block-gap: .875rem;
    gap: var(--block-gap);
    margin: 2.5rem 0;
    /* Fills the hole an odd run of small blocks leaves in front of a wide one.
       Deliberately not applied on mobile, where it would reshuffle the current
       layout and diverge from the editor canvas. */
    grid-auto-flow: dense;
  }

  /* Four columns make a 1x1 ~154px wide, so the row grows to match and the
     tile reads square. Two columns keep the 7rem above, which is what every
     existing page was laid out against. */
  .blocks.is-cols-4 {
    --block-row: 9.5rem;
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  /* Spans stop being clamped once there is room for them. Python has already
     resolved the stored quarter-columns against the active column count, so
     is-w{n} is literally n columns here. */
  .blocks.is-cols-4 > .block.is-w2 { grid-column: span 2; }
  .blocks.is-cols-4 > .block.is-w3 { grid-column: span 3; }
  .blocks.is-cols-4 > .block.is-w4 { grid-column: span 4; }
  .blocks.is-cols-4 > .block.is-h3 {
    grid-row: span 3;
    min-height: calc(3 * var(--block-row) + 2 * var(--block-gap));
  }
  .blocks.is-cols-4 > .block.is-h4 {
    grid-row: span 4;
    min-height: calc(4 * var(--block-row) + 3 * var(--block-gap));
  }
  .blocks.is-cols-4 > .block-link.is-h3 {
    height: calc(3 * var(--block-row) + 2 * var(--block-gap));
  }
  .blocks.is-cols-4 > .block-link.is-h4 {
    height: calc(4 * var(--block-row) + 3 * var(--block-gap));
  }

  /* The compact two-column row cannot fit a useful top image plus two lines of
     metadata. Keep the title and give the media the recovered height; taller
     cards continue to show the description. */
  .blocks.is-cols-2 > .block-layout-image_top.has-image.is-h1 .block-desc {
    display: none;
  }

  .block { min-height: var(--block-row); }
  .block.is-h2, .block.is-h3, .block.is-h4 {
    min-height: calc(2 * var(--block-row) + var(--block-gap));
  }
  /* Re-stated because the wider .block rule above now comes later in the
     cascade at equal specificity. A heading is a label, not a tile. */
  .block-heading { min-height: 0; }

  /* The four-column row stays square for image tiles and taller presets, but a
     one-row link is content, not a square canvas. Match the compact editor card
     instead of inflating it as the profile widens. */
  .blocks.is-cols-4
    > .block-link.is-h1:not(.block-layout-image_only) {
    height: auto;
    min-height: 7rem;
  }

  /* Side media fills the padded height when the card is wide enough to leave a
     readable text column. One-row cards use a narrower panel; multi-row cards
     can devote up to 42% of their width to the image. */
  .blocks.is-cols-2
    > :is(.block-layout-image_left, .block-layout-image_right).has-image:is(.is-h1, .is-h2)
    > .block-icon,
  .blocks.is-cols-4
    > :is(.block-layout-image_left, .block-layout-image_right).has-image:not(.is-w1):is(.is-h1, .is-h2)
    > .block-icon,
  .blocks.is-cols-4
    > :is(.block-layout-image_left, .block-layout-image_right).has-image:is(.is-w3, .is-w4):is(.is-h3, .is-h4)
    > .block-icon {
    align-self: stretch;
    width: min(42%, 20rem);
    height: auto;
    aspect-ratio: auto;
  }

  /* Banner-height cards use a stable 40/60 media-to-copy split. The image still
     fills the padded card height, avoiding empty space above and below it. */
  .blocks.is-cols-2
    > :is(.block-layout-image_left, .block-layout-image_right).has-image.is-h1
    > .block-icon,
  .blocks.is-cols-4
    > :is(.block-layout-image_left, .block-layout-image_right).has-image:not(.is-w1).is-h1
    > .block-icon {
    width: 40%;
  }

  /* A card that is taller than it is wide needs a vertical composition. Stack
     side layouts and let their image occupy the available space above the text
     instead of producing a narrow, heavily cropped side strip. */
  .blocks.is-cols-2
    > :is(.block-layout-image_left, .block-layout-image_right).has-image:is(.is-h3, .is-h4),
  .blocks.is-cols-4
    > :is(.block-layout-image_left, .block-layout-image_right).has-image.is-w2:is(.is-h3, .is-h4) {
    flex-direction: column;
    align-items: stretch;
    text-align: left;
  }

  .blocks.is-cols-2
    > :is(.block-layout-image_left, .block-layout-image_right).has-image:is(.is-h3, .is-h4)
    > .block-icon,
  .blocks.is-cols-4
    > :is(.block-layout-image_left, .block-layout-image_right).has-image.is-w2:is(.is-h3, .is-h4)
    > .block-icon {
    align-self: stretch;
    flex: 1;
    width: 100%;
    height: auto;
    min-height: 0;
  }

  .blocks.is-cols-2
    > :is(.block-layout-image_left, .block-layout-image_right).has-image:is(.is-h3, .is-h4)
    > .block-body,
  .blocks.is-cols-4
    > :is(.block-layout-image_left, .block-layout-image_right).has-image.is-w2:is(.is-h3, .is-h4)
    > .block-body {
    flex: none;
  }

  /* Images get a fixed ratio per size on desktop rather than their intrinsic
     one. Left to grow naturally a single 4:3 photo drags its whole row taller,
     which then stretches every neighbour and any block spanning that row -- a
     tall embed beside one measured 454px. Fixed ratios keep the grid a grid,
     and cover crops far less than squashing a photo into a 3.5:1 tile would. */
  .block-image img {
    flex: none;
    height: auto;
    aspect-ratio: 16 / 9;
  }

  /* Tall is the one size whose whole point is vertical room. A block that is
     both tall and full width is wide enough to keep a landscape crop. */
  .block-image.is-h2.is-w1 img,
  .block-image.is-h4.is-w1 img,
  .block-image.is-h4.is-w2 img { aspect-ratio: 3 / 4; }

  .now { margin: 2.5rem 0; }
  .stream { margin-top: 3rem; }

  /* The container is now wider than a comfortable line, so the text inside it
     is capped while the dividers keep spanning the full width. */
  .profile-bio { max-width: 34rem; margin-left: auto; margin-right: auto; }
  .post-card-excerpt, .post-card-body { max-width: 62ch; }
}

@media (min-width: 64rem) {
  .profile { max-width: 54rem; padding: 4rem 2rem 5rem; }

  /* The container grows to 800px of content here, so a four-column cell is
     ~190px and the row follows it to stay square. */
  .blocks.is-cols-4 { --block-row: 11.75rem; }
}

/* --- profile layouts ----------------------------------------------------- */
/* Layout is independent from theme: these rules only compose the shared
   profile regions and continue to use the same palette and shape tokens. */

.profile-tail { min-width: 0; }

/* The alternate layouts keep a hint of their composition on phones rather
   than collapsing into four visually identical pages. */
.profile-layout-sidebar .profile-header {
  padding: 1.5rem;
  border-radius: var(--radius);
  background: var(--sidebar);
}

.profile-layout-canvas .profile-header,
.profile-layout-editorial .profile-header { text-align: left; }

.profile-layout-canvas .avatar-wrap,
.profile-layout-editorial .avatar-wrap { margin-left: 0; }

.profile-layout-canvas .socials,
.profile-layout-editorial .socials { justify-content: flex-start; }

.profile-layout-editorial .profile-name {
  font-size: clamp(2rem, 10vw, 3rem);
  letter-spacing: -.045em;
}

@media (min-width: 60rem) {
  /* Sidebar: an immersive identity rail inspired by portfolio dashboards. The
     content remains ordinary document flow in the right column. */
  .profile-layout-sidebar {
    position: relative;
    max-width: none;
    min-height: 100vh;
    padding: 0;
    background:
      linear-gradient(
        to right,
        var(--sidebar) 0 max(18rem, 34vw),
        var(--bg) max(18rem, 34vw) 100%
      );
  }

  .profile-layout-sidebar .profile-shell {
    display: grid;
    grid-template-columns: minmax(18rem, 34vw) minmax(0, 1fr);
    align-items: start;
  }

  .profile-layout-sidebar .profile-header {
    position: sticky;
    top: 0;
    display: flex;
    min-height: 100vh;
    flex-direction: column;
    align-items: flex-start;
    justify-content: center;
    padding: clamp(3rem, 7vw, 7rem);
    border-radius: 0;
    text-align: left;
  }

  .profile-layout-sidebar .avatar-wrap { margin: 0; }
  .profile-layout-sidebar .profile-name {
    max-width: 10ch;
    margin-top: 2rem;
    font-size: clamp(2.5rem, 4vw, 4.5rem);
    letter-spacing: -.055em;
  }
  .profile-layout-sidebar .profile-bio { max-width: 32rem; margin-left: 0; }
  .profile-layout-sidebar .socials { justify-content: flex-start; }

  .profile-layout-sidebar .profile-body {
    width: min(100%, 64rem);
    padding: 2rem clamp(2rem, 5vw, 5rem) 5rem;
  }

  .profile-layout-sidebar .profile-tail {
    width: min(calc(100% - max(18rem, 34vw)), 64rem);
    margin-left: max(18rem, 34vw);
    padding: 0 clamp(2rem, 5vw, 5rem) 3rem;
  }

  /* Canvas: identity stays restrained while the bento content receives most of
     the page. Unlike Sidebar, both columns sit on the same background. */
  .profile-layout-canvas {
    max-width: 82rem;
    padding: 4rem 2.5rem 5rem;
  }

  .profile-layout-canvas .profile-shell {
    display: grid;
    grid-template-columns: minmax(15rem, 19rem) minmax(0, 1fr);
    align-items: start;
    gap: clamp(3rem, 7vw, 7rem);
  }

  .profile-layout-canvas .profile-header {
    position: sticky;
    top: 4rem;
  }

  .profile-layout-canvas .profile-name {
    margin-top: 1.75rem;
    font-size: clamp(2.25rem, 3.5vw, 3.75rem);
    letter-spacing: -.055em;
  }

  .profile-layout-canvas .profile-bio {
    max-width: 28rem;
    margin-left: 0;
    font-size: 1.0625rem;
  }

  .profile-layout-canvas .profile-body > :first-child { margin-top: 0; }
  .profile-layout-canvas .profile-tail {
    width: calc(100% - min(26rem, 30vw));
    margin-left: auto;
  }

  /* Editorial: the introduction behaves like a masthead, then links and
     writing become distinct reading columns. */
  .profile-layout-editorial {
    max-width: 74rem;
    padding: 4rem 2.5rem 5rem;
  }

  .profile-layout-editorial .profile-header {
    display: grid;
    grid-template-columns: 7.5rem minmax(0, 1fr);
    column-gap: 2rem;
    padding-bottom: 3rem;
    border-bottom: 1.5px solid var(--border);
  }

  .profile-layout-editorial .avatar-wrap {
    grid-column: 1;
    grid-row: 1 / span 5;
    width: 120px;
    height: 120px;
  }

  .profile-layout-editorial .avatar-initial {
    font-size: 2.75rem;
  }

  .profile-layout-editorial .avatar {
    width: 120px;
    height: 120px;
  }

  .profile-layout-editorial .profile-name,
  .profile-layout-editorial .profile-bio,
  .profile-layout-editorial .profile-location,
  .profile-layout-editorial .socials { grid-column: 2; }

  .profile-layout-editorial .profile-name {
    margin: -.2rem 0 .5rem;
    font-size: clamp(3.25rem, 7vw, 6rem);
  }

  .profile-layout-editorial .profile-bio {
    max-width: 48rem;
    margin-left: 0;
    font-size: 1.125rem;
  }

  .profile-layout-editorial .profile-body.has-blocks.has-posts {
    display: grid;
    grid-template-columns: minmax(0, 1.65fr) minmax(17rem, .75fr);
    grid-template-areas:
      "now now"
      "blocks stream";
    column-gap: clamp(2.5rem, 6vw, 5rem);
    align-items: start;
  }

  .profile-layout-editorial .now { grid-area: now; }
  .profile-layout-editorial .blocks { grid-area: blocks; }
  .profile-layout-editorial .stream { grid-area: stream; }
  .profile-layout-editorial .blocks,
  .profile-layout-editorial .stream { margin-top: 0; }
  .profile-layout-editorial .stream .section-title { margin-top: 0; }
}

@media (min-width: 60rem) and (max-width: 74rem) {
  .profile-layout-editorial .profile-body.has-blocks.has-posts {
    grid-template-columns: minmax(0, 1.35fr) minmax(15rem, .75fr);
    column-gap: 2.5rem;
  }
}
