/*
 * ericville26 — the article
 * =========================
 * Reading is the job here, so the whole file is organised around one idea:
 * a single measure, and a vertical rhythm that never breaks.
 *
 * The measure is 68ch. Everything in the body sits on it, and the only things
 * allowed to break out are figures — which is what makes breaking out mean
 * something.
 *
 * Spacing is derived, not chosen ad hoc. --lh is the body line box; every gap
 * is a multiple of it, so paragraphs, lists, headings and figures all land on
 * the same beat no matter how they are combined in the editor.
 *
 * Borders are used sparingly, per the same rule as the rest of the theme: a
 * rule earns its place by separating two things that would otherwise be
 * confused. Captions, callouts and quotes are distinguished by type, colour
 * and space instead.
 */

.ev26-article{
  --measure:68ch;
  --lh:1.72rem;          /* the body line box; the unit everything else uses */
  --rail:190px;          /* the TOC column */
}

/* ── reading progress ───────────────────────────────
 * 2px, fixed, accent. The one piece of chrome an article gets. */
.ev26-article .progress{position:fixed;top:0;left:0;height:2px;width:0;background:var(--accent);z-index:300;transition:width .1s linear}
@media (prefers-reduced-motion:reduce){.ev26-article .progress{transition:none}}

/* ── breadcrumb ─────────────────────────────────────
 * Small, quiet, and genuinely a trail: Home / Lab / Essay. It replaced a
 * hardcoded two-item list that said the same thing on every post. */
/* #1500 — accessibility fix. --faint measures ~3.3:1 against a near-white
   ground, under the 4.5:1 floor for this size of text; on the tinted section
   grounds Eric flagged it was worse. --muted clears AA on its own. */
.ev26-article .crumb{display:flex;flex-wrap:wrap;align-items:center;gap:9px;font-size:var(--t-meta);font-weight:600;letter-spacing:var(--tr-crumb);color:var(--muted);padding:26px 0 0}
.ev26-article .crumb a{color:var(--muted);transition:color var(--fast) var(--ease)}
.ev26-article .crumb a:hover{color:var(--accent)}
.ev26-article .crumb [aria-current]{color:var(--text)}
.ev26-article .crumb span[aria-hidden]{color:var(--line-strong)}

/* ── head ───────────────────────────────────────────
 * Narrower than the body measure (52ch) so the title has a shape and the deck
 * does not run the full width of the page.
 *
 * TEXT IS MEASURED; RULES ARE NOT. The head used to be one 52ch block, so the
 * byline's two hairlines ended wherever the title's measure ended -- about half
 * the page, with the banner immediately below it spanning the whole content
 * column. A rule that stops where the text happens to stop reads as an
 * accident; a rule that spans its container reads as a decision. So the head is
 * now a grid: the type sits in a 52ch column, and the byline spans the full
 * content width, ending exactly where the banner and the prose's right edge do.
 *
 * WHY A GRID rather than dropping the max-width and re-applying it per element.
 * `ch` is resolved against the font-size of the element it is written on, and
 * the h1 is 60px against the head's 16px -- "52ch" on the h1 would be roughly
 * three times the measure it replaced. Written as a track on .art-head the unit
 * still resolves at the head's own font-size, so the measure is the identical
 * number of pixels it was before; only the byline's span changes.
 *
 * min(52ch,100%) rather than a bare 52ch: a fixed track wider than the grid
 * container overflows it, where the old max-width simply stopped growing. Below
 * ~640px the column is narrower than 52ch, the text already fills it, and the
 * rules land where they always did -- so phones see no change at all.
 *
 * The margins below are unchanged and do the same work: grid suppresses margin
 * collapsing, but every adjacency here already has a zero on one side (kind 20 /
 * h1 0, h1 0 / deck 20, deck 0 / byline 30), so nothing was collapsing and the
 * vertical rhythm is bit-for-bit what it was. */
.ev26-article .art-head{max-width:none;padding:34px 0 0;display:grid;grid-template-columns:minmax(0,min(52ch,100%)) minmax(0,1fr)}
.ev26-article .art-head>*{grid-column:1}
.ev26-article .kind{display:flex;align-items:center;gap:12px;font-family:var(--sans);font-size:var(--t-label);font-weight:700;letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--accent);margin-bottom:20px}
.ev26-article .kind i{width:28px;height:2px;background:var(--accent);border-radius:2px}
.ev26-article .art-head h1{display:block;font-size:var(--t-d-head);line-height:1.02;letter-spacing:var(--disp-track);font-weight:var(--disp-weight);color:var(--ink);margin:0}
.ev26-article .art-head .deck{margin:20px 0 0;font-size:var(--t-lead);line-height:1.55;color:var(--muted);max-width:46ch}

/* Byline. A single hairline above and below is the one rule that earns its
   keep here: it separates authorship from the article without boxing it.
   It is the one thing in the head that spans both tracks, which is what makes
   the two hairlines full-width while the type above them stays measured. */
.ev26-article .art-head .byline{grid-column:1 / -1}
/* #1500 — accessibility fix, same as .crumb above: --faint under AA at this
   text size, --muted clears it. */
.ev26-article .byline{display:flex;flex-wrap:wrap;align-items:center;gap:10px 22px;margin:30px 0 0;padding:16px 0;border-top:1px solid var(--line);border-bottom:1px solid var(--line);font-size:var(--t-meta);color:var(--muted)}
.ev26-article .byline-avatar{border-radius:999px;width:32px;height:32px}
.ev26-article .byline-who{color:var(--ink);font-weight:600}
.ev26-article .byline-comments{color:var(--muted);text-decoration:underline;text-decoration-color:var(--line-strong);text-underline-offset:3px}
.ev26-article .byline-comments:hover{color:var(--accent);text-decoration-color:var(--accent)}

/* ── banner ─────────────────────────────────────────
 * Optional. No border and no fixed aspect: a tall diagram and a wide photo
 * both belong, and cropping either to 21/9 loses the thing worth showing. */
.ev26-article .art-banner{margin:44px 0 0;border-radius:var(--r-m);overflow:hidden;background:var(--sunken)}
/* Capped. Without a ceiling a tall diagram renders as a 1000px wall before a
   reader reaches a single sentence. Cropping to a band keeps every post's head
   the same shape and gets the body above the fold; the full image is still in
   the article where it can be looked at properly. */
.ev26-article .art-banner img{width:100%;height:auto;max-height:min(56vh,520px);object-fit:cover;object-position:center;display:block}
.ev26-article .art-banner figcaption{padding:12px 2px 0;font-size:var(--t-meta);line-height:1.5;color:var(--faint)}

/* ── facts table (case studies only) ────────────────
 * Four hard facts -- Role, Client, Timeframe, Collaborators -- read between
 * the byline and the first sentence by someone deciding whether to read the
 * first sentence at all.
 *
 * WHICH RULES SURVIVED, AND WHY. The house rule is that a border earns its
 * place only by separating two things that would otherwise be confused, and
 * this is the case that qualifies: four label/value pairs sitting side by side
 * in one horizontal band genuinely do run together without a divider, and no
 * amount of gap fixes it -- widen the gap enough to read as separation and the
 * band stops reading as one object.
 *
 * So the VERTICAL hairlines stay: they are doing the work. Everything else is
 * gone. No outer box (the byline's existing bottom rule already closes the
 * head above it, and whitespace opens the body below it), no rule under the
 * labels, no fill, no radius. Cells that start a row have no left rule, so the
 * band has no edges -- only the seams between cells.
 *
 * Widths are 1fr each rather than auto, so the seams land on a regular
 * interval instead of tracking how long each value happens to be.
 *
 * The band spans the WHOLE body grid -- contents rail plus gap plus measure --
 * rather than the measure alone. Two reasons, one of each kind: its left edge
 * then lines up with the breadcrumb, title and byline above it and its right
 * edge with the prose below it, so it is aligned to something rather than
 * floated at an arbitrary width; and four columns of 68ch is 150px each, which
 * is narrow enough that "AI Engineering Team" breaks across two lines. */
.ev26-article .art-facts{display:grid;grid-template-columns:repeat(4,minmax(0,1fr));max-width:calc(var(--rail) + 64px + var(--measure));margin:26px 0 0}
.ev26-article .art-facts>div{padding:0 20px;border-left:1px solid var(--line);min-width:0}
.ev26-article .art-facts>div:nth-child(4n+1){padding-left:0;border-left:0}
/* Fifth fact onward would wrap to a second row; it needs the horizontal seam
   the single-row case does not. Latent today -- there are four fields -- but a
   fifth must not silently overlap the row above it. */
.ev26-article .art-facts>div:nth-child(n+5){margin-top:18px;padding-top:18px;border-top:1px solid var(--line)}
.ev26-article .art-facts dt{font-family:var(--sans);font-size:var(--t-label);font-weight:700;letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--faint);margin:0 0 8px}
/* 15px/500 in --ink. Values legitimately carry inline <br> -- "Researcher /
   Data Science Team / AI Engineering Team / AI PM" is one field -- so the line
   height is set for a stacked list, not for a single line. */
.ev26-article .art-facts dd{margin:0;font-size:var(--t-body);font-weight:500;line-height:1.5;color:var(--ink);overflow-wrap:break-word}

/* Headings in an article take their hierarchy from family, size and weight.
   Never from colour.
 *
 * basetags.css sets `h2{color:var(--color-accent)}` and `article h3{color:
 * var(--color-accent)}` globally, which is why every case-study subhead was
 * blue while its h2 was not -- the accent was applied at two different
 * specificities to two different levels, so the page had two heading colours
 * and neither of them meant anything. The .prose rules above already win on
 * specificity for h2/h3/h4; this states the rule for the whole ladder,
 * including the h5/h6 nothing above claims, so a deeper heading cannot pick up
 * a stray colour later. Stated as one rule so it reads as an intent rather
 * than as four coincidences.
 *
 * It also survives Stage 11, when basetags.css and metadata.css are deleted:
 * this file will still be the place that says headings are ink. */
.ev26-article .prose :is(h1,h2,h3,h4,h5,h6){color:var(--ink)}

/* ── the two-column body ────────────────────────────
 * Sticky contents rail on the left, article on the right. The rail is what
 * makes a long essay scannable; it collapses away below 1100px, where there
 * is no room for it and the article should have the full measure. */
.ev26-article .art-body{display:grid;grid-template-columns:var(--rail) minmax(0,var(--measure));gap:64px;align-items:start;margin:52px 0 0}
/* Short pieces get no contents rail, so the grid collapses to one column
   rather than leaving the article stranded in the 190px gutter. */
.ev26-article .art-body.no-toc{grid-template-columns:minmax(0,var(--measure))}
.ev26-article .toc{position:sticky;top:104px;font-family:var(--sans);font-size:var(--t-meta);line-height:1.45}
.ev26-article .toc h2{font-family:var(--sans);font-size:var(--t-label);font-weight:700;letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--faint);margin:0 0 14px}
.ev26-article .toc ol{list-style:none;margin:0;padding:0;display:flex;flex-direction:column}
.ev26-article .toc li{margin:0}
.ev26-article .toc a{display:block;font-family:var(--sans);padding:7px 0 7px 14px;border-left:2px solid var(--line);color:var(--muted);transition:color var(--fast) var(--ease),border-color var(--fast) var(--ease)}
.ev26-article .toc a:hover{color:var(--ink);border-color:var(--line-strong)}
.ev26-article .toc a.on{color:var(--ink);font-weight:600;border-color:var(--accent)}

/* ── the prose ──────────────────────────────────────
 * 18px/1.72 on a 68ch measure. Every vertical gap below is a multiple of --lh
 * so the column keeps its beat. */
.ev26-article .prose{font-size:var(--t-lead);line-height:1.72;color:var(--text);max-width:var(--measure)}
.ev26-article .prose>*{margin:0 0 var(--lh)}
.ev26-article .prose>*:last-child{margin-bottom:0}

/* Gutenberg wraps content groups in <section class="wp-block-group">, and
   basetags.css:69 gives EVERY section and article 20px of padding plus a 50px
   bottom margin. The rule above resets margin but never padding, so the padding
   sailed through — a property you do not set cannot be overridden. Stacked with
   the hr and the next heading that produced ~260px of dead space where ~80 was
   intended. Wrappers carry no spacing of their own; the rhythm belongs to the
   content inside them. */
.ev26-article .prose :is(section,article,.wp-block-group){padding:0;margin:0;max-width:none}
.ev26-article .prose>:is(section,article,.wp-block-group){margin-bottom:var(--lh)}
.ev26-article .prose>:is(section,article,.wp-block-group):last-child{margin-bottom:0}
.ev26-article .prose :is(section,article,.wp-block-group)>*:last-child{margin-bottom:0}

/* Headings take space from ABOVE, which is what makes a section feel like it
   starts rather than like the paragraph before it ended. */
.ev26-article .prose h2{font-size:var(--t-sub);line-height:1.12;letter-spacing:var(--tr-head);font-weight:600;color:var(--ink);margin:calc(var(--lh) * 2.1) 0 calc(var(--lh) * .55);scroll-margin-top:100px}
.ev26-article .prose h3{font-size:var(--t-title);line-height:1.2;letter-spacing:var(--tr-title);font-weight:600;color:var(--ink);margin:calc(var(--lh) * 1.5) 0 calc(var(--lh) * .4);scroll-margin-top:100px}
.ev26-article .prose h4{font-size:var(--t-lead);line-height:1.3;font-weight:600;color:var(--ink);margin:calc(var(--lh) * 1.2) 0 calc(var(--lh) * .3)}
.ev26-article .prose>h2:first-child,
.ev26-article .prose>h3:first-child{margin-top:0}

/* The opening paragraph carries a drop cap. Scoped to the FIRST paragraph only
   and switched off if a heading or figure opens the article, because a drop
   cap halfway down a page is just a large letter. */
.ev26-article .prose>p:first-child{font-size:var(--t-title);line-height:1.6;color:var(--ink)}
.ev26-article .prose>p:first-child::first-letter{float:left;font-family:var(--serif);font-weight:700;font-size:3em;line-height:.78;padding:6px 12px 0 0;color:var(--accent)}

/* Links: accent, with an underline thin and pale enough to read as texture
   rather than as a second colour. */
.ev26-article .prose a{color:var(--accent);text-decoration:underline;text-decoration-thickness:1.5px;text-underline-offset:3px;text-decoration-color:color-mix(in oklab,var(--accent) 35%,transparent);transition:text-decoration-color var(--fast) var(--ease)}
.ev26-article .prose a:hover{text-decoration-color:var(--accent)}

/* Emphasis is a highlight, not a colour change — the type ladder does
   hierarchy, so bold text stays ink and gains a tint behind it instead. */
/* background-color reset matters: basetags.css carries
   `:where(p) strong{background-color:#ffe70099}` -- a hardcoded yellow. Setting
   only background-image left that yellow sitting behind the tint. */
.ev26-article .prose strong{font-weight:600;color:var(--ink);background-color:transparent;background-image:linear-gradient(transparent 62%,var(--accent-soft) 62%)}
.ev26-article .prose em{font-style:italic}

/* ── lists ──────────────────────────────────────────
 * The old ones were browser default discs at default spacing, which collided
 * with an 18px/1.72 measure and made every list look like a form.
 *
 * Now: no bullet glyph, a 6x1.5px accent dash on the baseline of the first
 * line, and a hanging indent so wrapped lines align under the text rather than
 * under the marker. Ordered lists get a counter in the sans face at the same
 * optical weight. Items breathe at half a line box; nested lists step down in
 * colour rather than in size, so a nested item still reads as body text. */
.ev26-article .prose ul,
.ev26-article .prose ol{list-style:none;padding:0;margin:0 0 var(--lh);border-left:0}
/* basetags.css gives `article ul` a 3px left border plus asymmetric padding.
   Resetting it explicitly, because a rule that is never set cannot be
   overridden -- and that border was most of what made lists feel bolted on. */
.ev26-article .prose ul{padding-right:0}
.ev26-article .prose article ul,
.ev26-article article .prose ul{border-left:0;padding-left:0}
.ev26-article .prose li{position:relative;padding-left:28px;margin:0 0 calc(var(--lh) * .42)}
.ev26-article .prose li:last-child{margin-bottom:0}
.ev26-article .prose ul>li::before{content:"";position:absolute;left:0;top:16px;width:6px;height:1.5px;background:var(--accent);border-radius:2px}
.ev26-article .prose ol{counter-reset:ev26-ol}
.ev26-article .prose ol>li{counter-increment:ev26-ol}
.ev26-article .prose ol>li::before{content:counter(ev26-ol);position:absolute;left:0;top:5px;font-family:var(--sans);font-size:var(--t-meta);font-weight:700;line-height:1.72;color:var(--accent);font-variant-numeric:tabular-nums}
/* Nested lists: tighter, quieter, and never re-indented into a staircase. */
.ev26-article .prose li>ul,
.ev26-article .prose li>ol{margin:calc(var(--lh) * .42) 0 0}
.ev26-article .prose li li{color:var(--muted)}
.ev26-article .prose li li::before{background:var(--line-strong)}
/* A list of one-liners should feel like a list; a list of paragraphs should
   breathe. This gives the second kind room without touching the first. */
.ev26-article .prose li>p{margin:0 0 calc(var(--lh) * .4)}
.ev26-article .prose li>p:last-child{margin-bottom:0}

/* ── quotes ─────────────────────────────────────────
 * A pull quote is a change of voice, so it changes face: serif, larger, ink. */
.ev26-article .prose blockquote{margin:calc(var(--lh) * 1.2) 0;padding:0 0 0 26px;border-left:2px solid var(--accent);font-family:var(--serif);font-size:var(--t-head);line-height:1.3;letter-spacing:var(--tr-title);color:var(--ink)}
.ev26-article .prose blockquote p{margin:0 0 calc(var(--lh) * .5)}
.ev26-article .prose blockquote p:last-child{margin-bottom:0}
.ev26-article .prose blockquote cite{display:block;margin-top:12px;font-family:var(--sans);font-style:normal;font-size:var(--t-meta);font-weight:600;color:var(--faint)}

/* ── figures ────────────────────────────────────────
 * No border. A photograph has its own edges; a drawn box around it is the
 * theme talking over the content. Captions are set apart by type instead. */
.ev26-article .prose figure{margin:calc(var(--lh) * 1.3) 0}
.ev26-article .prose figure img{width:100%;height:auto;display:block;border-radius:var(--r-s);background:var(--sunken)}
.ev26-article .prose figcaption{margin-top:11px;font-size:var(--t-meta);line-height:1.5;color:var(--faint)}

/* Figures are the only thing allowed off the measure, which is what makes it
   read as emphasis. alignwide bleeds into the contents rail; alignfull goes
   edge to edge. */
.ev26-article .prose .alignwide{width:calc(100% + var(--rail) + 64px);margin-left:calc((var(--rail) + 64px) * -1);max-width:none}
.ev26-article .prose .alignfull{width:100vw;margin-left:calc(50% - 50vw);max-width:none;border-radius:0}
.ev26-article .prose .alignfull img{border-radius:0}

/* ── callout ────────────────────────────────────────
 * Filled, not outlined. */
.ev26-article .prose .is-style-callout,
.ev26-article .prose .callout{background:var(--paper);border-radius:var(--r-m);padding:26px 30px;margin:calc(var(--lh) * 1.2) 0}
.ev26-article .prose .is-style-callout>*:last-child,
.ev26-article .prose .callout>*:last-child{margin-bottom:0}

/* ── tables ─────────────────────────────────────────
 * Row rules only. Vertical rules in a small table are almost always noise. */
.ev26-article .prose table{width:100%;border-collapse:collapse;font-size:var(--t-body);line-height:1.5}
.ev26-article .prose th,
.ev26-article .prose td{text-align:left;padding:11px 16px 11px 0;border-bottom:1px solid var(--line);vertical-align:top}
.ev26-article .prose th{font-family:var(--sans);font-size:var(--t-label);font-weight:700;letter-spacing:var(--tr-label);text-transform:uppercase;color:var(--faint)}

/* ── code ───────────────────────────────────────────
 * Sits below the body size so a code run does not out-shout the sentence. */
.ev26-article .prose :is(code,kbd,samp){font-family:var(--mono)}
.ev26-article .prose code{font-size:.88em;padding:2px 6px;border-radius:4px;background:var(--sunken);color:var(--ink)}
.ev26-article .prose pre{font-family:var(--mono);background:var(--ink);color:var(--bg);border-radius:var(--r-m);padding:22px 24px;overflow-x:auto;font-size:var(--t-meta);line-height:1.6}
.ev26-article .prose pre code{background:none;padding:0;color:inherit}

/* ── separator ──────────────────────────────────────
 * A short centred rule, not a full-width line across the measure. */
/* Was --lh*2 each side, set when the surrounding wrappers were silently adding
   their own 90px. With those reset, the heading that follows already supplies
   the section break, so the rule only needs to breathe. */
.ev26-article .prose hr{border:0;height:1px;width:64px;margin:calc(var(--lh) * 1.1) auto;background:var(--line-strong)}
/* An hr immediately before a heading is doing the same job twice. */
.ev26-article .prose hr + :is(h2,h3){margin-top:calc(var(--lh) * .8)}

/* ── share row ──────────────────────────────────────*/
.ev26-article .art-foot{max-width:var(--measure);margin:calc(var(--lh) * 2.4) 0 0;padding-top:22px;border-top:1px solid var(--line);display:flex;align-items:center;justify-content:space-between;gap:20px;flex-wrap:wrap}
.ev26-article .art-foot .micro{color:var(--faint)}
.ev26-article .art-share{display:flex;gap:8px}
/* min-height:0 and padding:0 are load-bearing: forms.css:13-28 puts
   min-height:50px on EVERY <button> site-wide, which rendered the copy-link
   control as a ~110x50 pill beside three 34px circles with no icon painted.
   Same breakage on essays and projects — they inherit this rule, so fixing it
   here fixes all three article templates at once. The real fix is at source in
   forms.css, which dies in Stage 11. */
/* [hidden] must actually hide. The copy button is rendered hidden and revealed
   by JS only when the Clipboard API exists, so it is never shown broken — but
   `hidden` works through the UA stylesheet's display:none, and ANY author
   `display` outranks it. The display:flex below was forcing a dead, empty
   control on screen whether or not JS ever revealed it. */
.ev26-article .art-share [hidden]{display:none}
.ev26-article .art-share a,
.ev26-article .art-share button{width:34px;height:34px;min-height:0;padding:0;flex:0 0 auto;border-radius:999px;border:1px solid var(--line-strong);background:transparent;display:flex;align-items:center;justify-content:center;cursor:pointer;transition:var(--fast)}
/* The path selector is load-bearing: inc/icons.php ships the link glyph with
   fill="black" hardcoded ON THE PATH, and a path carrying its own fill
   presentation attribute does not inherit from the svg — so a token set on the
   parent never reached it. */
.ev26-article .art-share svg{width:15px;height:15px;opacity:.7;transition:var(--fast)}
.ev26-article .art-share svg,
.ev26-article .art-share svg path{fill:var(--muted)}
.ev26-article .art-share a:hover svg path,
.ev26-article .art-share button:hover svg path{fill:var(--ink)}
.ev26-article .art-share a:hover,
.ev26-article .art-share button:hover{border-color:var(--ink);transform:translateY(-1px)}
.ev26-article .art-share .copied{border-color:var(--accent)}
.ev26-article .art-share .copied svg{fill:var(--accent);opacity:1}
.ev26-article .art-share a:hover svg,
.ev26-article .art-share button:hover svg{fill:var(--ink);opacity:1}

/* ── responsive ─────────────────────────────────────*/
@media (max-width:1100px){
  .ev26-article .art-body{grid-template-columns:minmax(0,1fr);gap:0}
  .ev26-article .toc{display:none}
  .ev26-article .prose{max-width:var(--measure);margin:0 auto}
  .ev26-article .prose .alignwide{width:100%;margin-left:0}
}
@media (max-width:700px){
  .ev26-article .prose{font-size:var(--t-body)}
  .ev26-article .prose h2{font-size:var(--t-head)}
  .ev26-article .prose h3{font-size:var(--t-lead)}
  .ev26-article .prose blockquote{font-size:var(--t-title);padding-left:18px}
  .ev26-article .prose>p:first-child{font-size:var(--t-lead)}
  .ev26-article .art-head{padding-top:22px}
}

/* ── facts table, responsive ────────────────────────
 * Four columns is not a small-screen answer, so the band re-flows twice.
 *
 * 2 x 2 below 1100. That is the same breakpoint at which the article loses its
 * contents rail, and it is the same fact stated twice: four columns need the
 * full body grid to work, so when the grid collapses to the bare measure the
 * band halves with it. Four cells in 68ch is 150px each -- "AI Engineering
 * Team" breaks across two lines and the row turns into four ragged paragraphs.
 * The band also centres here, because the prose centres; if it did not it
 * would stop reading as part of the same column.
 *
 * The nth-child rules are re-stated per breakpoint because the cell that
 * starts a row -- the one with no left seam -- is a different cell at every
 * column count. */
@media (max-width:1100px){
  .ev26-article .art-facts{max-width:var(--measure);margin-left:auto;margin-right:auto;grid-template-columns:repeat(2,minmax(0,1fr))}
  .ev26-article .art-facts>div{padding:0 20px;border-left:1px solid var(--line);margin-top:0;padding-top:0;border-top:0}
  .ev26-article .art-facts>div:nth-child(2n+1){padding-left:0;border-left:0}
  .ev26-article .art-facts>div:nth-child(n+3){margin-top:20px;padding-top:20px;border-top:1px solid var(--line)}
}
/* One column at phone width. Here the vertical seams have nothing left to
   separate -- the cells are already stacked -- so they go, and the horizontal
   ones take over. Labels sit above values as everywhere else, which makes the
   band read as a short definition list rather than as a broken table. */
@media (max-width:480px){
  .ev26-article .art-facts{grid-template-columns:minmax(0,1fr);margin-top:22px}
  .ev26-article .art-facts>div{padding:0;border-left:0;margin-top:0;border-top:0}
  .ev26-article .art-facts>div+div{margin-top:15px;padding-top:15px;border-top:1px solid var(--line)}
  .ev26-article .art-facts dt{margin-bottom:5px}
}

/* ══ PROJECT PAGES ONLY (#1498) ══════════════════════════════════════════════
 *
 * Everything below is scoped to `.ev26-article.project-page` — the class
 * single-projects.php puts on the wrapper, and the ONLY template that carries
 * it. Essays (single-essays.php) and case studies (single-casestudy.php) share
 * this file and must not move, so no rule here may be written at
 * `.ev26-article` alone.
 *
 * These three components are core Gutenberg blocks living in post_content
 * (a group, a table, a raw-HTML button). There is no project stylesheet, and
 * a per-post <style> tag is how the button got a hardcoded #005177 and a
 * `var(--color-white)` fade that inverted to a white bar in dark mode. The
 * styling belongs in the theme, in tokens, where dark mode is already solved.
 */

/* ── the free-designs panel ──────────────────────────
 * Was `.cta-box.special` from basetags.css: a --color-gray-800 slab with
 * near-black heading text on it, i.e. an unreadable heading. It is a CALLOUT,
 * so it gets the callout treatment already defined above — filled, no border,
 * no radius fuss — tinted with --accent-soft rather than --paper to mark it as
 * the one place on the page asking for a click. Both tokens flip with the
 * theme, so the panel is a light mint band in light and a deep jade band in
 * dark, with --ink text legible on each. basetags.css loads AFTER this file,
 * hence the .cta-box.special pairing: it has to out-specify (0,2,0). */
.ev26-article.project-page .prose .cta-box,
.ev26-article.project-page .prose .cta-box.special{
  background:var(--accent-soft);color:var(--text);
  border-radius:var(--r-m);padding:30px 34px;
  margin:calc(var(--lh) * 1.4) 0;
}
.ev26-article.project-page .prose .cta-box>*:first-child{margin-top:0}
.ev26-article.project-page .prose .cta-box>*:last-child{margin-bottom:0}
/* The heading is a full sentence now, not a two-word label, so it drops a rung
   off the prose h3 size — at --t-head it wrapped to three lines and read as a
   section break rather than as the top of a small panel. */
.ev26-article.project-page .prose .cta-box :is(h2,h3){
  color:var(--ink);font-size:var(--t-lead);line-height:1.28;margin:0 0 12px;
}
.ev26-article.project-page .prose .cta-box p{color:var(--text);margin:0 0 22px}

/* ── buttons on a project page ───────────────────────
 * One treatment, taken from the theme's existing button: the pill in
 * v26-components.css `.btn` (line ~729), restated for the core buttons block
 * exactly as v26-ux.css does for the UX landing page. Ink ground, page-ground
 * text, 999px radius, --t-meta/700 sans.
 *
 * text-decoration:none is the actual bug fix. `.prose a` underlines every link
 * in the body — correct for prose, wrong the moment the link IS a filled
 * button, which is why "Begin Building" rendered as underlined accent-green
 * text sitting inside an amber block. */
.ev26-article.project-page .prose .wp-block-buttons{display:flex;flex-wrap:wrap;gap:12px}
.ev26-article.project-page .prose .wp-block-button__link{
  display:inline-flex;align-items:center;gap:9px;
  background:var(--ink);color:var(--bg);border:1px solid var(--ink);
  border-radius:999px;padding:13px 24px;min-height:0;
  font-family:var(--sans);font-size:var(--t-meta);font-weight:700;letter-spacing:var(--tr-ui);
  text-decoration:none;
  transition:transform var(--fast) var(--ease),background var(--fast) var(--ease);
}
.ev26-article.project-page .prose .wp-block-button__link:hover{transform:translateY(-1px)}
.ev26-article.project-page .prose .wp-block-button.is-style-outline .wp-block-button__link{
  background:transparent;color:var(--ink);border-color:var(--line-strong);
}
.ev26-article.project-page .prose .wp-block-button.is-style-outline .wp-block-button__link:hover{border-color:var(--ink)}
.ev26-article.project-page .prose .wp-block-button__link:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

/* ── the specs table ─────────────────────────────────
 * The core `is-style-stripes` fill is off the block in post_content; what is
 * left is the house table above — row rules only, uppercase --t-label heads,
 * no vertical seams, no zebra. The same read as the Lab patents list
 * (v26-lab.css `.grid.list.plain`): identical-shaped records stacked on each
 * other, separated by one hairline each, with the identifying number on its
 * own rail.
 *
 * Fixed layout because the content cannot set the widths sensibly — auto gave
 * the third column ("3D-printable version included?", mostly empty) a third of
 * the measure while "Aluminum Angle Bar (type 6061)" wrapped to three lines.
 * The two answer columns are sized to their HEADINGS, and everything else goes
 * to the part name. */
.ev26-article.project-page .prose .specs-table{margin:0}
.ev26-article.project-page .prose .specs-table table{table-layout:fixed}
/* border:0 before the row rule is not belt-and-braces. wp-block-library ships
   `.wp-block-table td,.wp-block-table th{border:1px solid}` and the core
   `is-style-stripes` style is what used to null it out — take the stripes off
   the block and the full 1px grid comes BACK, box and vertical seams and all,
   which is the opposite of the house table. So the cell is stripped first and
   given back exactly one edge. */
.ev26-article.project-page .prose .specs-table :is(th,td){
  border:0;border-bottom:1px solid var(--line);padding:12px 18px 12px 0;
}
.ev26-article.project-page .prose .specs-table :is(th,td):last-child{padding-right:0}
.ev26-article.project-page .prose .specs-table th{vertical-align:bottom;border-bottom:1px solid var(--line-strong)}
.ev26-article.project-page .prose .specs-table :is(th,td):nth-child(2){width:7.5rem}
.ev26-article.project-page .prose .specs-table :is(th,td):nth-child(3){width:11rem}
/* The counts are a column of figures being compared down the page, so they
   line up on the digit. */
.ev26-article.project-page .prose .specs-table td:nth-child(2){font-variant-numeric:tabular-nums;color:var(--ink);font-weight:600}
.ev26-article.project-page .prose .specs-table td:nth-child(3){color:var(--muted)}
/* Part name, then its part NUMBER and its purpose underneath — one record in
   three registers, the way a patent row is title-then-number. The <br> lines
   after the bold name are the quiet half, so they step down in colour and
   size rather than sitting at full body weight. */
.ev26-article.project-page .prose .specs-table td:first-child{color:var(--faint);font-size:var(--t-meta);line-height:1.55}
.ev26-article.project-page .prose .specs-table td:first-child :is(strong,a){font-size:var(--t-body);line-height:1.4;color:var(--ink)}
.ev26-article.project-page .prose .specs-table td:first-child a{color:var(--accent)}
.ev26-article.project-page .prose .specs-table td:first-child strong{font-weight:600}
.ev26-article.project-page .prose .specs-table tbody tr:last-child :is(td){border-bottom:0}

/* ── the show-all control ────────────────────────────
 * The collapse itself is worth keeping — twenty-four rows is a wall — but all
 * of its styling was inline in the post: a hardcoded #005177 hover, a fade to
 * `var(--color-white)` (a light-mode-only token, so in dark the table faded
 * into a white smear), and a square button parked halfway up the last visible
 * row. Rewritten here in tokens.
 *
 * The fade goes to --bg, the actual page ground, so it holds in both themes.
 * It is also pointer-events:none, because a 170px transparent sheet lying over
 * live rows swallowed clicks on the last two part links. */
.ev26-article.project-page .prose .table-container{
  position:relative;max-height:440px;overflow:hidden;
  transition:max-height var(--med) var(--ease);
}
.ev26-article.project-page .prose .table-container.expanded{max-height:none;overflow:visible}
.ev26-article.project-page .prose .table-overlay{
  position:absolute;left:0;right:0;bottom:0;height:180px;
  display:flex;align-items:flex-end;justify-content:center;
  background:linear-gradient(to bottom,transparent,var(--bg) 66%);
  pointer-events:none;
}
/* Expanded, the control does NOT disappear — the old rule display:none'd the
   whole overlay, which meant a reader who expanded the table had no way back
   and the button vanished mid-interaction. It just stops being an overlay:
   the gradient goes and it returns to flow under the last row. */
.ev26-article.project-page .prose .table-container.expanded .table-overlay{
  position:static;height:auto;background:none;padding-top:20px;justify-content:flex-start;
}
/* The same pill as .btn / .wp-block-button__link above. min-height:0 and the
   padding reset are load-bearing: forms.css puts min-height:50px and
   padding:var(--space-s) on EVERY <button> site-wide. */
.ev26-article.project-page .prose .show-all-btn{
  pointer-events:auto;
  display:inline-flex;align-items:center;gap:9px;
  background:var(--ink);color:var(--bg);border:1px solid var(--ink);
  border-radius:999px;padding:12px 22px;min-height:0;
  font-family:var(--sans);font-size:var(--t-meta);font-weight:700;letter-spacing:var(--tr-ui);
  cursor:pointer;
  transition:transform var(--fast) var(--ease),background var(--fast) var(--ease);
}
.ev26-article.project-page .prose .show-all-btn:hover{transform:translateY(-1px);background:var(--ink)}
.ev26-article.project-page .prose .show-all-btn:focus-visible{outline:2px solid var(--accent);outline-offset:3px}

@media (prefers-reduced-motion:reduce){
  .ev26-article.project-page .prose .table-container{transition:none}
  .ev26-article.project-page .prose :is(.show-all-btn,.wp-block-button__link):hover{transform:none}
}

@media (max-width:700px){
  .ev26-article.project-page .prose .cta-box,
  .ev26-article.project-page .prose .cta-box.special{padding:24px 22px}
  /* Two 7.5/11rem columns leave nothing for the part name at phone width, so
     the answer columns shrink to their content and the name keeps the rest. */
  .ev26-article.project-page .prose .specs-table :is(th,td):nth-child(2){width:4.5rem}
  .ev26-article.project-page .prose .specs-table :is(th,td):nth-child(3){width:6.5rem}
  .ev26-article.project-page .prose .specs-table :is(th,td){padding:11px 10px 11px 0}
}
