/* =====================================================================
   enaxon theme: blog.css. The blog stylesheet, loaded only on
   is_home(), is_archive(), is_search() and is_singular( 'post' ),
   after main.css and covers.css. Source: design/blog-src/src/blog.css.
   The shared tokens, header, footer, buttons, .wrap, .sec-grid, .big,
   .eyebrow, .sr-only and the "rise" keyframes live in main.css.
   Markup: templates home, archive, search, single; parts blog-masthead*;
   patterns post-card, blog-empty, more-posts; enaxon-core blocks and
   filters (docs/blocks.md).
   ===================================================================== */

/* Blog tokens: kept out of the editor palette, like --panel-*. Code tokens reach 7:1 on the code background. */
:root {
  --measure: 31em; /* 558px at 18px: 62 to 74 characters a line, 67 on average (measured) */
  /* Accent as text: 7:1 or more on --bg and --bg2 in both themes (AAA). The plain accent stays for lines, dots and borders. */
  --accent-text: color-mix(in srgb, var(--accent) 70%, var(--text));
  --tok-comment: #4A545E; --tok-keyword: #4B3BB0; --tok-string: #04633E; --tok-number: #8A3A0C;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) { --tok-comment: #9AA4AE; --tok-keyword: #B3A6FF; --tok-string: #5EE6B0; --tok-number: #F2B37A; }
}
:root[data-theme="dark"] { --tok-comment: #9AA4AE; --tok-keyword: #B3A6FF; --tok-string: #5EE6B0; --tok-number: #F2B37A; }

/* ---------- WordPress: core flow layout ----------
   Core gives every child of a flow layout block (group, query, post template) a block gap margin
   (:root :where(.is-layout-flow) > *, specificity 0,1,0). The blog markup sets its own margins, as in the
   prototype, so these containers start from zero. Same specificity and later in the page, so this wins
   over core, and every rule below wins over this. .prose keeps its own rules (Prose).
   Core also zeroes the start margin of a first child and the end margin of a last child
   (:root :where(.is-layout-flow) > :first-child, specificity 0,2,0). A rule below that sets one of those
   margins on such a child uses two classes, for example .card-body > .card-title. */
:where(#main, .blog-head, .blog-head-grid, .blog-title, .blog-intro, .blog-list, .post-list, .card, .card-body, .lead-panel,
  article.post, .post-opener, .post-intro, .post-body, .post-nav, .post-nav-grid, .more).is-layout-flow > * { margin-block: 0; }

/* Nav: on blog pages the Blog link is the current page (aria-current="page") or the current section ("true").
   The shared header CSS styles a[aria-current] for both; these rules keep the blog views right on their own. */
.nav-links a[aria-current="page"] { color: var(--text); }
.nav-links a[aria-current="page"]::before {
  content: ""; position: absolute; left: 50%; bottom: 3px; width: 4px; height: 4px; margin-left: -2px; border-radius: 50%; background: var(--accent);
}
@media (max-width: 860px) {
  .js .nav-links a[aria-current="page"]::before { left: auto; right: 6px; bottom: auto; top: 50%; margin: -2px 0 0; }
}

/* ---------- Blog masthead (parts blog-masthead, blog-masthead-archive, blog-masthead-search) ---------- */
.blog-head { position: relative; isolation: isolate; }
.blog-head::before {
  content: ""; position: absolute; inset: 0 0 -120px; z-index: -1; pointer-events: none;
  background-image: linear-gradient(var(--grid) 1px, transparent 1px), linear-gradient(90deg, var(--grid) 1px, transparent 1px);
  background-size: 48px 48px; background-position: center -1px;
  -webkit-mask-image: linear-gradient(to bottom, transparent, #000 120px), radial-gradient(ellipse 70% 90% at 72% 30%, #000 20%, transparent 75%);
  -webkit-mask-composite: source-in;
  mask-image: linear-gradient(to bottom, transparent, #000 120px), radial-gradient(ellipse 70% 90% at 72% 30%, #000 20%, transparent 75%);
  mask-composite: intersect;
}
.blog-head-grid { align-items: end; padding-block: clamp(48px, 7vw, 96px) clamp(32px, 4.5vw, 56px); }
.blog-title { grid-column: 1 / span 4; }
.blog-kicker { margin-bottom: 14px; color: var(--accent-text); }
.blog-intro { grid-column: 5 / -1; min-width: 0; }
/* An archive with no description and fewer than 2 topics prints an empty intro group: no gap for it. */
.blog-intro:not(:has(*)) { display: none; }
.blog-lead { margin: 0; max-width: 34ch; text-wrap: balance; font-size: clamp(1.25rem, 2vw, 1.4375rem); font-weight: 300; line-height: 1.5; }
.topic-nav { margin-top: 22px; }
.chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; padding: 0; list-style: none; }
.chips a {
  display: inline-flex; align-items: center; min-height: 36px; padding: 0 14px; border-radius: 999px;
  border: 1px solid var(--line2); color: var(--muted); text-decoration: none;
  font: 400 .8125rem/1.2 'IBM Plex Mono', ui-monospace, monospace;
  transition: color .15s ease, border-color .15s ease, background-color .15s ease;
}
.chips a:hover { color: var(--text); border-color: var(--text); }
.chips a[aria-current] { color: var(--text); border-color: var(--accent); background: var(--accent-soft); box-shadow: inset 0 0 0 1px var(--accent); }
@media (pointer: coarse) { .chips a { min-height: 44px; } }
@media (max-width: 960px) {
  .blog-title, .blog-intro { grid-column: 1 / -1; }
  .blog-intro { margin-top: 18px; }
}
/* Archive masthead (parts blog-masthead-archive and blog-masthead-search): the term name or search can be long, so the title takes the full row. */
.blog-head--archive .blog-title { grid-column: 1 / -1; }
.blog-head--archive .blog-intro { grid-column: 1 / span 8; margin-top: 20px; }
.blog-head--archive .big { font-size: clamp(2.5rem, 6.4vw, 5rem); overflow-wrap: break-word; }
@media (max-width: 960px) { .blog-head--archive .blog-intro { grid-column: 1 / -1; } }

/* ---------- Post list: one query. The first post on page 1 is the featured post (CSS only). ----------
   core/post-template prints ul.wp-block-post-template.post-list > li.wp-block-post > article.card (pattern enaloo/post-card).
   Core also gives each li the post classes ("post", "type-post"), so the single post rules below use article.post. */
.blog-list { padding-bottom: clamp(84px, 11vw, 144px); }
.post-list { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: clamp(16px, 3vw, 32px); margin: 0; padding: 0; list-style: none; }
.post-list > li { display: flex; min-width: 0; }
@media (max-width: 960px) { .post-list { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 640px) { .post-list { grid-template-columns: minmax(0, 1fr); } }

/* Card: one real link (the title), stretched over the card. No other links inside. */
.card {
  position: relative; display: flex; flex-direction: column; width: 100%; padding: 8px;
  border: 1px solid var(--line); border-radius: 20px; background: var(--bg2);
  transition: border-color .2s ease, background-color .2s ease;
}
.card:hover { border-color: var(--accent); background: var(--ext-hover); }
.card-body { display: flex; flex-direction: column; flex: 1; padding: 16px 12px 10px; }
.card-body > .card-title { margin: 10px 0 0; }
.card-title { font: 600 1.3125rem/1.25 'Space Grotesk', sans-serif; letter-spacing: -.012em; overflow-wrap: anywhere; }
/* core/post-title makes its link inline-block; the prototype link is inline. */
.card-title a { display: inline; color: var(--text); text-decoration: none; }
.card-title a::after { content: ""; position: absolute; inset: 0; z-index: 1; border-radius: 20px; }
.card-title a:focus-visible { outline: none; }
.card-title a:focus-visible::after { outline: 2px solid var(--accent); outline-offset: 3px; }
.card:hover .card-title a { text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 4px; }
/* The title comes first in the HTML (headings lead); the topic and date line shows above it. */
.card-meta {
  order: -1; display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 4px 16px; margin: 0;
  font: 400 .8125rem/1.4 'IBM Plex Mono', ui-monospace, monospace; color: var(--muted);
}
.card-topic { display: inline-flex; align-items: center; gap: 9px; color: var(--text); }
.card-topic::before { content: ""; width: 12px; height: 4px; border-radius: 2px; background: var(--accent); }
.card-excerpt { margin: 8px 0 0; color: var(--muted); font-size: 1rem; line-height: 1.55; }
/* core/post-excerpt prints div.card-excerpt > p.wp-block-post-excerpt__excerpt; core/term-description prints div > p. */
.card-excerpt > p, .standfirst > p, .blog-lead > p { margin: 0; }
.card-read { margin: auto 0 0; padding-top: 16px; font: 400 .8125rem/1.4 'IBM Plex Mono', ui-monospace, monospace; color: var(--muted); }

/* Featured post: the first card on page 1 of the posts page and of a category. The one raised panel, like the inspector.
   No overflow: hidden on the panel: the focus ring sits outside the card (on the stretched ::after), so clipping would hide it.
   The plate rounds its own outer corners instead (the panel radius 20px less the 1px border).
   Core adds the body class "paged" on page 2 and later. */
.lead-panel, body:not(.paged) .post-list--index > li:first-child .card {
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); padding: 0;
  border-color: var(--panel-line); background: var(--panel); box-shadow: var(--panel-shadow);
}
body:not(.paged) .post-list--index > li:first-child { grid-column: 1 / -1; }
body:not(.paged) .post-list--index > li:first-child .card:hover { border-color: var(--accent); }
.lead-panel .cover, body:not(.paged) .post-list--index > li:first-child .cover {
  grid-column: 2; grid-row: 1; height: 100%; min-height: 300px; aspect-ratio: auto; border-radius: 0 19px 19px 0; border-left: 1px solid var(--panel-line);
}
.lead-panel .card-body, body:not(.paged) .post-list--index > li:first-child .card-body {
  grid-column: 1; grid-row: 1; justify-content: center; padding: clamp(28px, 3.6vw, 48px);
}
body:not(.paged) .post-list--index > li:first-child .card-title { margin-top: 18px; font-size: clamp(1.75rem, 3vw, 2.5rem); line-height: 1.08; letter-spacing: -.026em; }
body:not(.paged) .post-list--index > li:first-child .card-excerpt { max-width: 40ch; margin-top: 16px; color: var(--text); font-size: clamp(1.125rem, 1.6vw, 1.25rem); font-weight: 300; line-height: 1.5; }
body:not(.paged) .post-list--index > li:first-child .card-read { margin-top: 0; padding-top: 26px; }
@media (max-width: 960px) {
  .lead-panel, body:not(.paged) .post-list--index > li:first-child .card { grid-template-columns: minmax(0, 1fr); }
  .lead-panel .cover, body:not(.paged) .post-list--index > li:first-child .cover {
    grid-column: 1; grid-row: 1; min-height: 0; aspect-ratio: 1200 / 630; border-radius: 19px 19px 0 0; border-left: 0; border-bottom: 1px solid var(--panel-line);
  }
  .lead-panel .card-body, body:not(.paged) .post-list--index > li:first-child .card-body { grid-row: 2; padding: 24px 22px 26px; }
}

/* Full rows for any number of posts (CSS only, from the position in the list). The last card widens when it is alone in its row,
   or when it is the second of two in a row of three, and shows its plate beside the text. The featured post counts as a full row. */
@media (min-width: 961px) {
  body:not(.paged) .post-list--index > li:not(:first-child):last-child:nth-child(3n+2),
  body.paged .post-list--index > li:last-child:nth-child(3n+1),
  .post-list:not(.post-list--index) > li:last-child:nth-child(3n+1) { grid-column: 1 / -1; }
  body:not(.paged) .post-list--index > li:not(:first-child):last-child:nth-child(3n),
  body.paged .post-list--index > li:last-child:nth-child(3n+2),
  .post-list:not(.post-list--index) > li:last-child:nth-child(3n+2) { grid-column: span 2; }
  /* Desktop: the parts of the cards in a row line up (meta, title, excerpt, read), like the home tiles.
     Each card spans 5 rows of the list and passes them down with subgrid. A subgrid shares the list's row gap,
     so the gap between rows of cards is a margin, and the list takes the last one back.
     The list and the last card can be the last child of a flow layout, so these margin rules use two classes (Core flow layout). */
  ul.wp-block-post-template.post-list { row-gap: 0; margin-bottom: calc(-1 * clamp(16px, 3vw, 32px)); }
  .post-list > li { grid-row: span 5; display: grid; grid-template-rows: subgrid; }
  .wp-block-post-template.post-list > li { margin-bottom: clamp(16px, 3vw, 32px); }
  .post-list > li > .card { grid-row: 1 / -1; display: grid; grid-template-rows: subgrid; }
  .post-list > li > .card > .card-body { grid-row: 2 / -1; display: grid; grid-template-rows: subgrid; }
  /* The featured post and the wide cards lay out side by side, so they keep their own layout. */
  body:not(.paged) .post-list--index > li:first-child { grid-row: auto; display: flex; }
  body:not(.paged) .post-list--index > li:first-child .card-body { display: flex; }
  :is(body:not(.paged) .post-list--index > li:not(:first-child):last-child:is(:nth-child(3n+2), :nth-child(3n)),
      body.paged .post-list--index > li:last-child:is(:nth-child(3n+1), :nth-child(3n+2)),
      .post-list:not(.post-list--index) > li:last-child:is(:nth-child(3n+1), :nth-child(3n+2))) { display: flex; }
  :is(body:not(.paged) .post-list--index > li:not(:first-child):last-child:is(:nth-child(3n+2), :nth-child(3n)),
      body.paged .post-list--index > li:last-child:is(:nth-child(3n+1), :nth-child(3n+2)),
      .post-list:not(.post-list--index) > li:last-child:is(:nth-child(3n+1), :nth-child(3n+2))) > .card { grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
  :is(body:not(.paged) .post-list--index > li:not(:first-child):last-child:is(:nth-child(3n+2), :nth-child(3n)),
      body.paged .post-list--index > li:last-child:is(:nth-child(3n+1), :nth-child(3n+2)),
      .post-list:not(.post-list--index) > li:last-child:is(:nth-child(3n+1), :nth-child(3n+2))) > .card > .cover { aspect-ratio: auto; height: 100%; min-height: 220px; }
  :is(body:not(.paged) .post-list--index > li:not(:first-child):last-child:is(:nth-child(3n+2), :nth-child(3n)),
      body.paged .post-list--index > li:last-child:is(:nth-child(3n+1), :nth-child(3n+2)),
      .post-list:not(.post-list--index) > li:last-child:is(:nth-child(3n+1), :nth-child(3n+2))) > .card > .card-body { display: flex; grid-row: auto; padding: 18px 20px 10px 24px; }
  :is(body:not(.paged) .post-list--index > li:not(:first-child):last-child:is(:nth-child(3n+2), :nth-child(3n)),
      body.paged .post-list--index > li:last-child:is(:nth-child(3n+1), :nth-child(3n+2)),
      .post-list:not(.post-list--index) > li:last-child:is(:nth-child(3n+1), :nth-child(3n+2))) .card-excerpt { max-width: 48ch; }
}
@media (min-width: 641px) and (max-width: 960px) {
  :is(body:not(.paged) .post-list--index > li:not(:first-child):last-child:nth-child(2n),
      body.paged .post-list--index > li:last-child:nth-child(2n+1),
      .post-list:not(.post-list--index) > li:last-child:nth-child(2n+1)) { grid-column: 1 / -1; }
  :is(body:not(.paged) .post-list--index > li:not(:first-child):last-child:nth-child(2n),
      body.paged .post-list--index > li:last-child:nth-child(2n+1),
      .post-list:not(.post-list--index) > li:last-child:nth-child(2n+1)) > .card { display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr); }
  :is(body:not(.paged) .post-list--index > li:not(:first-child):last-child:nth-child(2n),
      body.paged .post-list--index > li:last-child:nth-child(2n+1),
      .post-list:not(.post-list--index) > li:last-child:nth-child(2n+1)) > .card > .cover { aspect-ratio: auto; height: 100%; min-height: 200px; }
  :is(body:not(.paged) .post-list--index > li:not(:first-child):last-child:nth-child(2n),
      body.paged .post-list--index > li:last-child:nth-child(2n+1),
      .post-list:not(.post-list--index) > li:last-child:nth-child(2n+1)) > .card > .card-body { padding: 18px 20px 10px 24px; }
  :is(body:not(.paged) .post-list--index > li:not(:first-child):last-child:nth-child(2n),
      body.paged .post-list--index > li:last-child:nth-child(2n+1),
      .post-list:not(.post-list--index) > li:last-child:nth-child(2n+1)) .card-excerpt { max-width: 48ch; }
}

/* Empty state (pattern enaloo/blog-empty in core/query-no-results): the same panel, with the idle plate.
   The link is a core button with the ghost (outline) style; main.css gives it the .btn-ghost look. */
.lead-panel { border: 1px solid var(--panel-line); border-radius: 20px; }
.lead-panel .card-body h2 { margin: 0; font: 600 clamp(1.75rem, 3vw, 2.5rem)/1.08 'Space Grotesk', sans-serif; letter-spacing: -.026em; }
.lead-panel .card-body p { margin: 14px 0 0; max-width: 36ch; color: var(--muted); font-size: 1.125rem; }
.lead-panel .wp-block-buttons { align-self: flex-start; margin-top: 28px; }

/* Pagination: core/query-pagination markup and class names. Core makes it a flex layout
   (.is-layout-flex > :is(*, div) { margin: 0 }, specificity 0,1,1), so the push to the right needs a child selector. */
.wp-block-query-pagination {
  display: flex; flex-wrap: wrap; align-items: center; gap: 12px 24px; margin-top: clamp(40px, 5vw, 64px); padding-top: 20px;
  border-top: 1px solid var(--line); font: 400 .8125rem/1 'IBM Plex Mono', ui-monospace, monospace;
}
.wp-block-query-pagination-numbers { display: flex; flex-wrap: wrap; gap: 6px; }
.wp-block-query-pagination .page-numbers {
  display: inline-grid; place-items: center; min-width: 40px; height: 40px; padding: 0 10px; border-radius: 10px;
  color: var(--muted); text-decoration: none; transition: color .15s ease, background-color .15s ease;
}
.wp-block-query-pagination a.page-numbers:hover { color: var(--text); background: var(--chip); }
.wp-block-query-pagination .page-numbers.current {
  color: var(--text); background: var(--seg); outline: 1px solid var(--accent); outline-offset: -1px; box-shadow: 0 1px 2px rgba(0, 0, 0, .08);
}
.wp-block-query-pagination-previous, .wp-block-query-pagination-next {
  display: inline-flex; align-items: center; min-height: 44px; color: var(--text);
  text-decoration: underline; text-decoration-color: var(--line2); text-underline-offset: 4px;
}
.wp-block-query-pagination-previous:hover, .wp-block-query-pagination-next:hover { text-decoration-color: currentColor; }
.wp-block-query-pagination > .wp-block-query-pagination-next { margin-left: auto; }
@media (pointer: coarse) { .wp-block-query-pagination .page-numbers { min-width: 44px; height: 44px; } }

/* ---------- Single post (single.html) ----------
   article.post: the post-template li elements also carry the class "post" (core post classes), so the tag is part of the selector. */
article.post { padding-top: clamp(20px, 3vw, 36px); }
.crumbs ol { display: flex; flex-wrap: wrap; align-items: center; margin: 0; padding: 0; list-style: none; font: 400 .8125rem/1.4 'IBM Plex Mono', ui-monospace, monospace; color: var(--muted); }
.crumbs li + li::before { content: "/"; content: "/" / ""; margin: 0 10px; color: var(--muted); }
.crumbs a {
  display: inline-flex; align-items: center; min-height: 44px; color: var(--muted);
  text-decoration: underline; text-decoration-color: var(--line2); text-underline-offset: 4px;
}
.crumbs a:hover { color: var(--text); text-decoration-color: currentColor; }
/* Touch: 44 by 44. The padding and the equal negative margin widen the target without moving the text or the "/". */
@media (pointer: coarse) { .crumbs a { min-width: 44px; justify-content: center; padding-inline: 8px; margin-inline: -8px; } }

.post-opener { row-gap: 0; margin-top: clamp(12px, 2.4vw, 32px); }
.post-intro { grid-column: 4 / -1; grid-row: 1; min-width: 0; }
.post-title { margin: 0; max-width: 18ch; font: 600 clamp(2.5rem, 5.6vw, 4.5rem)/1.02 'Space Grotesk', sans-serif; letter-spacing: -.035em; overflow-wrap: anywhere; }
/* core/post-excerpt {className: "standfirst is-manual-only"}: prints nothing when the post has no hand written excerpt (plugin filter). */
.standfirst { margin: 24px 0 0; max-width: 40ch; font-size: clamp(1.25rem, 2vw, 1.4375rem); font-weight: 300; line-height: 1.5; }
/* Meta list in the inspector detail style: a label column and a value column. The label column is at least 76px and
   grows with the text (WCAG 1.4.12 text spacing); the rows share it through subgrid, so the values stay aligned. */
.post-meta {
  grid-column: 1 / span 3; grid-row: 1; align-self: end; display: grid; grid-template-columns: minmax(76px, max-content) minmax(0, 1fr);
  gap: 8px 10px; margin: 0; font: 400 .8125rem/1.5 'IBM Plex Mono', ui-monospace, monospace;
}
.post-meta > div {
  grid-column: 1 / -1; display: grid; grid-template-columns: minmax(76px, max-content) minmax(0, 1fr); grid-template-columns: subgrid;
  gap: 10px; align-items: baseline;
}
.post-meta dt { color: var(--muted); }
.post-meta dd { margin: 0; min-width: 0; color: var(--text); }
.post-meta a { color: var(--text); text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 3px; }
.post-meta a:hover { text-decoration-thickness: 2px; }
/* Touch: the topic link is 44px high. The negative margin keeps the row height, so the list looks the same. */
@media (pointer: coarse) { .post-meta a { display: inline-flex; align-items: center; min-height: 44px; margin-block: -12px; } }
.post-plate { grid-column: 4 / -1; grid-row: 2; margin-top: clamp(28px, 4vw, 48px); }
.post-plate .cover { border-radius: 20px; border: 1px solid var(--line); }
@media (max-width: 1179px) {
  .post-intro, .post-meta, .post-plate { grid-column: 1 / -1; }
  .post-meta { grid-row: 2; display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px 28px; margin-top: 24px; }
  .post-meta > div { display: flex; gap: 10px; }
  .post-plate { grid-row: 3; margin-top: 28px; }
}

.post-body { margin-top: clamp(40px, 6vw, 72px); row-gap: 0; }

/* Table of contents (enaloo/toc): a sticky rail at 1180px and up (like the sticky section titles), a details box below. */
.toc-rail { grid-column: 1 / span 3; grid-row: 1; position: sticky; top: calc(var(--header-h) + 40px); align-self: start; max-height: calc(100vh - var(--header-h) - 80px); overflow-y: auto; padding: 4px 8px 4px 0; }
.toc-label { margin: 0 0 14px; font: 400 .8125rem/1.4 'IBM Plex Mono', ui-monospace, monospace; color: var(--muted); }
.toc-list { position: relative; margin: 0; padding: 0; list-style: none; }
.toc-list ol { margin: 0; padding: 0; list-style: none; }
.toc-track { position: relative; padding-left: 16px; border-left: 1px solid var(--line2); }
.toc-list a {
  display: flex; align-items: center; min-height: 32px; padding: 5px 0; color: var(--muted); font-size: .9375rem; line-height: 1.35;
  text-decoration: none; overflow-wrap: anywhere; transition: color .15s ease;
}
.toc-list ol a { padding-left: 14px; font-size: .875rem; }
@media (pointer: coarse) { .toc-list a { min-height: 44px; } }
.toc-list a:hover { color: var(--text); }
.toc-list a[aria-current="true"] { color: var(--text); font-weight: 500; }
.toc-marker {
  position: absolute; left: -2px; top: 0; width: 3px; height: 20px; border-radius: 2px; background: var(--accent);
  opacity: 0; transform: translateY(0); transition: transform .22s ease-out, height .22s ease-out, opacity .15s ease;
}
.toc-rail.has-current .toc-marker { opacity: 1; }
.toc-box { grid-column: 1 / -1; margin: 0 0 36px; border: 1px solid var(--line); border-radius: 16px; background: var(--bg2); }
.toc-box summary {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 48px; padding: 0 18px; cursor: pointer;
  border-radius: 16px; list-style: none; font: 500 .8125rem/1.2 'IBM Plex Mono', ui-monospace, monospace;
}
.toc-box summary::-webkit-details-marker { display: none; }
.toc-box summary::after { content: ""; width: 8px; height: 8px; margin-top: -4px; border: solid var(--muted); border-width: 0 1.5px 1.5px 0; transform: rotate(45deg); transition: transform .2s ease; }
.toc-box[open] summary::after { margin-top: 4px; transform: rotate(-135deg); }
.toc-box .toc-list { padding: 0 18px 14px; }
.toc-box .toc-list a { min-height: 44px; border-top: 1px solid var(--line); }
@media (min-width: 1180px) { .toc-box { display: none; } }
@media (max-width: 1179px) { .toc-rail { display: none; } }
/* Site Editor only: the editor puts the TOC block inside its own element, and that element is the grid child.
   It takes the columns of the rail (the full row where the box shows), as on the page. */
.post-body > .wp-block-enaloo-toc.block-editor-block-list__block { grid-column: 1 / -1; }
@media (min-width: 1180px) {
  .post-body > .wp-block-enaloo-toc.block-editor-block-list__block { grid-column: 1 / span 3; grid-row: 1; }
}
/* While the consent banner is open, the sticky rail ends 16px above it, so the banner never covers a focused TOC link (2.4.11).
   Page scroll padding cannot move a sticky element. The rail scrolls inside, and focus scrolls a link into view in it.
   Short screens are left out: there the banner joins the page flow (shared consent CSS, max-height: 500px). */
@media (min-height: 501px) {
  html.consent-open .toc-rail { max-height: calc(100dvh - var(--header-h) - 40px - var(--consent-h, 0px) - clamp(16px, 3vw, 24px) - 16px); }
}

/* Prose (core/post-content {className: "prose"}, a flow layout): about 67 characters a line at 18px (--measure).
   Code, figures and tables use the wide area (columns 4 to 12). These rules come after core's block gap, so they win. */
.prose { grid-column: 1 / -1; min-width: 0; font-size: 1.125rem; line-height: 1.7; overflow-wrap: break-word; }
.prose > * { max-width: var(--measure); margin-block: 0; }
.prose > * + * { margin-top: 1.1em; }
.prose > .code-frame, .prose > figure { max-width: none; margin: 1.8em 0; }
.prose :is(img, video) { max-width: 100%; height: auto; }
.prose h2 { margin-top: 2.2em; font: 600 clamp(1.625rem, 2.6vw, 2rem)/1.15 'Space Grotesk', sans-serif; letter-spacing: -.02em; }
.prose h3 { margin-top: 1.7em; font: 600 1.375rem/1.25 'Space Grotesk', sans-serif; letter-spacing: -.012em; }
.prose > h2:first-child { margin-top: 0; }
.prose h2 + *, .prose h3 + * { margin-top: .6em; }
.prose a { color: var(--text); text-decoration: underline; text-decoration-color: var(--accent); text-decoration-thickness: 1px; text-underline-offset: 3px; }
.prose a:hover { text-decoration-thickness: 2px; }
.prose strong { font-weight: 600; }
.prose ul, .prose ol { padding-left: 1.6em; }
.prose ol { padding-left: 1.9em; } /* the mono "01." marker is wider than the square: this keeps it inside the column */
.prose li + li { margin-top: .4em; }
.prose li { padding-left: .3em; }
.prose ul { list-style: square; }
.prose ul > li::marker { color: var(--accent); }
.prose ol { list-style: decimal-leading-zero; }
.prose ol > li::marker { color: var(--accent); font: 500 .8em 'IBM Plex Mono', ui-monospace, monospace; }
.prose :not(pre) > code {
  padding: .1em .36em; border: 1px solid var(--line); border-radius: 6px; background: var(--chip);
  font: 400 .85em/1 'IBM Plex Mono', ui-monospace, monospace; overflow-wrap: anywhere;
}
/* Quote (core/quote: blockquote.wp-block-quote > p + cite): a rule with the timeline node on top. */
.prose blockquote { position: relative; margin: 1.8em 0; padding: 2px 0 2px 28px; border-left: 1px solid var(--line2); }
.prose blockquote::before { content: ""; position: absolute; left: -4px; top: 4px; width: 7px; height: 7px; border-radius: 50%; background: var(--accent); }
.prose blockquote p { margin: 0; font-size: clamp(1.25rem, 2vw, 1.4375rem); font-weight: 300; line-height: 1.45; }
.prose blockquote cite { display: block; margin-top: 12px; font: 400 .8125rem/1.4 'IBM Plex Mono', ui-monospace, monospace; font-style: normal; color: var(--muted); }
/* End mark: the pipeline packet after the last block. */
.prose::after { content: ""; display: block; width: 20px; height: 7px; margin-top: 40px; border-radius: 4px; background: var(--accent); }

/* Code: the inspector panel. Markup from the enaxon-core render_block_core/code filter:
   div.code-frame > div.code-bar (span.code-lang + button.code-copy) + pre[data-scroll-region] > code[translate="no"].
   The pre may keep the core class wp-block-code; core then wraps the code (white-space: break-spaces), so the frame
   sets white-space back: long lines scroll inside the frame. Token colors use the Prism class names. */
.code-frame { overflow: hidden; border: 1px solid var(--panel-line); border-radius: 16px; background: var(--panel); color: var(--panel-text); }
.code-bar {
  display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 48px; padding: 6px 6px 6px 18px;
  border-bottom: 1px solid var(--panel-line); font: 400 .78125rem/1.2 'IBM Plex Mono', ui-monospace, monospace; color: var(--tok-comment);
}
.code-copy {
  display: inline-flex; align-items: center; min-height: 36px; padding: 0 12px; border-radius: 10px; cursor: pointer;
  border: 1px solid var(--panel-line); background: var(--panel2); color: var(--panel-text);
  font: 500 .78125rem/1 'IBM Plex Mono', ui-monospace, monospace; transition: border-color .15s ease;
}
.code-copy:hover { border-color: var(--panel-muted); }
@media (pointer: coarse) { .code-copy { min-height: 44px; } }
.code-frame pre {
  margin: 0; padding: 18px 20px 20px; overflow-x: auto; font: 400 .875rem/1.7 'IBM Plex Mono', ui-monospace, monospace; tab-size: 4;
  scrollbar-width: thin; scrollbar-color: var(--line2) transparent;
  max-width: none; border: 0; border-radius: 0; background: none; color: inherit; white-space: pre;
}
.code-frame pre:focus-visible { outline: 2px solid var(--accent); outline-offset: -3px; border-radius: 0 0 15px 15px; }
.code-frame code { display: inline; font: inherit; white-space: inherit; overflow-wrap: normal; word-break: normal; direction: ltr; text-align: left; background: none; border: 0; padding: 0; }
.token.comment, .token.prolog, .token.cdata { color: var(--tok-comment); }
.token.keyword, .token.boolean, .token.builtin, .token.important, .token.property { color: var(--tok-keyword); }
.token.string, .token.char, .token.template-string, .token.regex { color: var(--tok-string); }
.token.number, .token.variable { color: var(--tok-number); }
.token.function, .token.class-name { color: var(--panel-text); font-weight: 500; }
.token.punctuation, .token.operator { color: var(--tok-comment); }

/* Figures: diagram (enaloo/diagram) and table (core/table with the enaxon-core scroll region filter). */
.prose figcaption { margin: 12px 0 0; color: var(--muted); font-size: .9375rem; line-height: 1.5; }
/* The label is followed by a real space in the HTML, so names and copied text read "Figure 1 The parts...". */
.fig-n { margin-right: 6px; font: 500 .8125rem/1 'IBM Plex Mono', ui-monospace, monospace; color: var(--text); }
.diagram-scroll { overflow-x: auto; padding: clamp(18px, 3vw, 32px); border: 1px solid var(--line); border-radius: 16px; background: var(--bg2); scrollbar-width: thin; }
/* Minimum width 724px: the 14px labels in the 880 wide viewBox never render under 11.5px (the mono minimum).
   Only the drawing: the editor shows a spinner svg in the same figure while the preview loads. */
.diagram-scroll svg { display: block; width: 100%; min-width: 724px; height: auto; }
.diagram-scroll:focus-visible, .table-scroll:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.dg-box { fill: none; stroke: var(--muted); stroke-width: 1; }
.dg-opt { stroke-dasharray: 5 4; }
.dg-acc { fill: var(--accent-soft); stroke: var(--accent); stroke-width: 1.5; }
.dg-tick { fill: none; stroke: var(--line2); stroke-width: 1; } /* decorative brackets only */
.dg-div { fill: none; stroke: var(--field-line); stroke-width: 1; } /* field dividers: 3.1:1 on the accent fill, 3.5:1 on --bg2 */
.dg-label { fill: var(--text); font: 500 15px 'IBM Plex Mono', ui-monospace, monospace; }
.dg-sub { fill: var(--muted); font: 400 14px 'IBM Plex Mono', ui-monospace, monospace; }
/* Core table CSS: the figure scrolls and every cell has a full border. With the plugin wrapper the inner .table-scroll
   scrolls instead (so its focus ring is not clipped), and only the row rules show. */
.wp-block-table:has(> .table-scroll) { overflow: visible; }
.table-scroll { overflow-x: auto; scrollbar-width: thin; }
.wp-block-table table { width: 100%; min-width: 540px; border-collapse: collapse; font-size: 1rem; line-height: 1.5; font-variant-numeric: tabular-nums; }
.wp-block-table thead, .wp-block-table tfoot, .wp-block-table th, .wp-block-table td { border: 0; }
.wp-block-table th {
  padding: 0 20px 10px 0; border-bottom: 1px solid var(--line2); text-align: left; vertical-align: bottom;
  font: 400 .8125rem/1.4 'IBM Plex Mono', ui-monospace, monospace; color: var(--muted);
}
.wp-block-table td { padding: 12px 20px 12px 0; border-bottom: 1px solid var(--line); vertical-align: top; }
.wp-block-table td:first-child { white-space: nowrap; }
/* The core "Stripes" style uses fixed light grays: use the theme chip color instead, so dark mode keeps its contrast. */
.wp-block-table.is-style-stripes { border-bottom: 0; }
.wp-block-table.is-style-stripes tbody tr:nth-child(odd) { background-color: var(--chip); }

/* Author card (enaloo/author-card): no box, a rule above.
   aside.author and ".author ." on the parts: the body of an author archive has the classes "author" and "author-{name}". */
aside.author { grid-column: 1 / -1; max-width: var(--measure); display: grid; grid-template-columns: 56px minmax(0, 1fr); gap: 20px; margin-top: 72px; padding-top: 32px; border-top: 1px solid var(--line); }
.monogram {
  display: grid; place-items: center; width: 56px; height: 56px; border-radius: 13px;
  background: var(--accent-soft); color: var(--text); border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
  font: 600 1.25rem/1 'Space Grotesk', sans-serif; letter-spacing: -.02em;
}
.author .author-name { margin: 0; font: 600 1.375rem/1.25 'Space Grotesk', sans-serif; letter-spacing: -.012em; overflow-wrap: anywhere; }
.author .author-role { margin: 3px 0 0; color: var(--accent-text); font-size: 1rem; font-weight: 500; }
.author .author-text { margin: 12px 0 0; max-width: 44ch; color: var(--muted); font-size: 1rem; }
.author .author-links { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 22px; }
@media (min-width: 1180px) {
  .prose { grid-column: 4 / -1; grid-row: 1; }
  aside.author { grid-column: 4 / span 7; grid-row: 2; }
}
@media (max-width: 480px) { aside.author { grid-template-columns: minmax(0, 1fr); gap: 16px; } .author .author-links { display: grid; grid-template-columns: 1fr 1fr; } }

/* Older and newer post: core/post-navigation-link markup, in the core/group nav.post-nav > div.post-nav-grid. */
.post-nav { margin-top: clamp(72px, 9vw, 112px); }
.post-nav-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); border-block: 1px solid var(--line); }
.post-nav-grid > .is-older { grid-column: 2; border-left: 1px solid var(--line); text-align: right; }
.post-nav-grid a { display: flex; flex-direction: column; gap: 8px; height: 100%; padding: 28px 24px 30px 0; color: var(--text); text-decoration: none; }
.post-nav-grid .is-older a { align-items: flex-end; padding: 28px 0 30px 24px; }
.post-navigation-link__label { font: 400 .8125rem/1.4 'IBM Plex Mono', ui-monospace, monospace; color: var(--muted); }
.post-navigation-link__title { max-width: 30ch; font: 600 1.1875rem/1.3 'Space Grotesk', sans-serif; letter-spacing: -.01em; text-wrap: balance; overflow-wrap: anywhere; }
.post-nav-grid a:hover .post-navigation-link__title { text-decoration: underline; text-decoration-color: var(--accent); text-underline-offset: 4px; }
/* Safety net for the newest, the oldest and a single post (the plugin filter prints nothing there):
   core prints an empty wrapper when there is no neighbour. Hide it, let the other cell take the row,
   and hide the whole nav (and its landmark) when it holds no link. */
.post-nav:not(:has(a)), .post-nav-grid > :not(:has(a)) { display: none; }
.post-nav-grid > :not(:has(a)) + .is-older, .post-nav-grid > .is-newer:has(+ :not(:has(a))) { grid-column: 1 / -1; border-left: 0; }
@media (max-width: 640px) {
  .post-nav-grid { grid-template-columns: minmax(0, 1fr); }
  .post-nav-grid > .is-older { grid-column: 1; border-left: 0; text-align: left; }
  .post-nav-grid > * + * { border-top: 1px solid var(--line); }
  .post-nav-grid a, .post-nav-grid .is-older a { align-items: flex-start; padding: 22px 0 24px; }
}

/* More posts (pattern enaloo/more-posts: section.wp-block-query.more > h2.more-title + ul.post-list) */
.more { padding-top: clamp(56px, 7vw, 88px); padding-bottom: clamp(84px, 11vw, 144px); }
.more-title { margin: 0 0 28px; font: 600 clamp(1.625rem, 2.6vw, 2rem)/1.15 'Space Grotesk', sans-serif; letter-spacing: -.02em; }
/* No other post yet (core prints no list): no lone heading. The space before the footer stays. */
.more:not(:has(.post-list)) { padding-top: 0; }
.more:not(:has(.post-list)) > * { display: none; }

/* Reading progress (a core/html block in single.html: div.read-progress[aria-hidden]): CSS scroll driven.
   Absent without support and with reduced motion (D7: everything stops). */
.read-progress { display: none; }
@supports (animation-timeline: view()) {
  @media (prefers-reduced-motion: no-preference) {
    article.post { view-timeline: --post block; view-timeline-inset: var(--header-h) 0; }
    .read-progress {
      display: block; position: fixed; z-index: 31; left: 0; right: 0; top: calc(var(--header-h) - 2px); height: 2px; pointer-events: none;
      background: var(--accent); transform-origin: 0 50%; transform: scaleX(0);
      animation: read-progress linear both; animation-timeline: --post; animation-range: contain 0% contain 100%;
    }
  }
  @keyframes read-progress { to { transform: scaleX(1); } }
  /* The sticky header sits below the WordPress admin bar for signed in users, so the line and the timeline start there too.
     Under 601px the admin bar scrolls away and the header sticks to the top (same rule as the header in main.css). */
  @media (prefers-reduced-motion: no-preference) {
    .admin-bar article.post { view-timeline-inset: calc(var(--header-h) + var(--wp-admin--admin-bar--height, 0px)) 0; }
    .admin-bar .read-progress { top: calc(var(--wp-admin--admin-bar--height, 0px) + var(--header-h) - 2px); }
    @media screen and (max-width: 600px) {
      .admin-bar article.post { view-timeline-inset: var(--header-h) 0; }
      .admin-bar .read-progress { top: calc(var(--header-h) - 2px); }
    }
  }
}
/* Without JS the header is static at 860px and less (shared CSS), so the line would float over the text. */
@media (max-width: 860px) { html:not(.js) .read-progress { display: none; } }

/* ---------- One page load moment (D7): masthead and featured post, or the post opener ---------- */
@media (prefers-reduced-motion: no-preference) {
  .js .blog-head-grid > *, .js .post-intro, .js .post-meta, .js .crumbs { opacity: 0; transform: translateY(14px); animation: rise .8s cubic-bezier(.2, .7, .2, 1) forwards; }
  .js .blog-head-grid > :nth-child(2), .js .post-intro { animation-delay: .08s; }
  .js .post-meta { animation-delay: .16s; }
  .js .lead-panel, .js body:not(.paged) .post-list--index > li:first-child { opacity: 0; transform: translateY(20px); animation: rise 1s cubic-bezier(.2, .7, .2, 1) .3s forwards; }
  /* The plate develops once: structure, then marks, then the one accent element. Opacity only. */
  .js .lead-panel .cv .g2, .js body:not(.paged) .post-list--index > li:first-child .cv .g2, .js .post-plate .cv .g2 { opacity: 0; animation: cv-on .6s ease .55s forwards; }
  .js .lead-panel .cv .g3, .js body:not(.paged) .post-list--index > li:first-child .cv .g3, .js .post-plate .cv .g3 { opacity: 0; animation: cv-on .6s ease .85s forwards; }
}
@keyframes cv-on { to { opacity: 1; } }

/* ---------- Forced colors ---------- */
@media (forced-colors: active) {
  .blog-head::before { display: none; }
  .nav-links a[aria-current="page"]::before { forced-color-adjust: none; background: Highlight; }
  .chips a[aria-current] { forced-color-adjust: none; background: Highlight; color: HighlightText; border-color: Highlight; box-shadow: none; }
  .card-topic::before, .prose::after, .prose blockquote::before, .toc-marker { forced-color-adjust: none; background: CanvasText; }
  .toc-marker { background: Highlight; }
  .card-title a:focus-visible::after { outline-color: Highlight; }
  .wp-block-query-pagination .page-numbers.current { outline: 2px solid Highlight; }
  .monogram { border-color: CanvasText; }
  .cover { forced-color-adjust: none; background: Canvas; border: 1px solid CanvasText; }
  .cv .ln, .cv .ld, .cv .t-soft, .cv .t-c1, .cv .t-c2 { stroke: GrayText; }
  .cv .t-ink, .cv .t-c3 { stroke: CanvasText; }
  .cv .t-acc, .cv .la { stroke: Highlight; }
  .cv .f-c1, .cv .f-hot { fill: none; }
  .cv .f-acc { fill: Highlight; }
  .cv .f-bg { fill: Canvas; }
  .diagram-scroll svg { forced-color-adjust: none; }
  .dg-box, .dg-tick, .dg-div { stroke: CanvasText; }
  .dg-acc { fill: Canvas; stroke: Highlight; stroke-width: 2; }
  .dg-label, .dg-sub { fill: CanvasText; }
  .read-progress { forced-color-adjust: none; background: Highlight; }
}

@media print {
  :root, :root:not([data-theme="light"]), :root[data-theme="dark"] { --tok-comment: #4A545E; --tok-keyword: #4B3BB0; --tok-string: #04633E; --tok-number: #8A3A0C; }
  .toc-rail, .toc-box, .code-copy, .read-progress, .post-plate, .topic-nav, .wp-block-query-pagination, .more, .author .author-links, .blog-head::before { display: none !important; }
  .code-frame pre { white-space: pre-wrap; }
  .prose a[href^="http"]::after { content: " (" attr(href) ")"; color: var(--muted); font-size: .85em; overflow-wrap: anywhere; }
  .post-body, .post-opener { display: block; }
  .card, .code-frame, .diagram, .wp-block-table, aside.author { break-inside: avoid; }
  .prose h2, .prose h3 { break-after: avoid; }
}
