/* Insights shares the landing page's palette and type; articles use a reading measure. */
.insights-main { padding: clamp(2.5rem, 6vw, 5rem) var(--gutter); }
.insights-wrap { max-width: 1100px; margin-inline: auto; }
.reading-wrap { max-width: 68ch; margin-inline: auto; }
.insights-heading { margin-bottom: 3rem; }
.insights-heading > * + *, .post-heading > * + * { margin-top: 1rem; }
.insights-heading h1 { font-size: var(--t-sect); }
.insights-heading .eyebrow, .post-heading .eyebrow { font-size: 0.875rem; }
.insight-list { list-style: none; padding: 0; margin: 0; }

/* Space between one section of the index and the next. The operating
   documents end in a list whose last entry carries a border-bottom, so
   without this the rule sat flush against the following heading -- the two
   sections read as one. The essays section has no such rule and got its
   separation from the panel's own margin, which is why only this seam
   showed it. */
/* Index pages are mostly sections, but an intro can be loose paragraphs. Both
   need spacing, and sections need more of it than a paragraph does. */
.insights-wrap > * + * { margin-top: 1.25rem; }
.insights-wrap > section + section { margin-top: 3.5rem; }
.insight-entry {
  display: grid; grid-template-columns: 5rem minmax(0, 1fr); gap: 1.5rem;
  padding-block: 2rem; border-top: 1px solid var(--line);
}
.insight-entry:last-child { border-bottom: 1px solid var(--line); }
.insight-number { color: var(--accent-text); font-size: 0.9375rem; font-weight: 600; }
.insight-entry .eyebrow { font-size: 0.875rem; }
.insight-entry h3 { margin-top: 0.65rem; font-size: clamp(1.4rem, 2.5vw, 1.85rem); line-height: 1.25; }
.insight-entry h3 a { text-decoration-thickness: 1px; text-underline-offset: 0.2em; }
.insight-entry h3 a:hover, .back-link:hover, .post-pagination a:hover { color: var(--accent-text); }
.insight-excerpt { margin-top: 0.85rem; max-width: 68ch; }
.back-link { display: inline-block; padding-block: 0.5rem; text-underline-offset: 0.2em; }
.post-heading { margin-block: 2rem 2.5rem; padding-bottom: 2rem; border-bottom: 1px solid var(--line); }
/* overflow-wrap alone breaks a long name mid-syllable -- "HomeLabRemo / te" on
   a narrow phone. break-word only breaks a word that cannot fit on a line of
   its own, so ordinary titles wrap between words and only a genuinely
   over-long one is split. */
.post-heading h1 { font-size: clamp(1.75rem, 4vw, 3rem); line-height: 1.15; overflow-wrap: break-word; }
.post-byline { font-size: 0.9375rem; }
/* break-word, not anywhere: anywhere splits ordinary prose mid-syllable on a
   narrow column. Long URLs and identifiers still break rather than overflow. */
.post-body { font-size: 1.125rem; line-height: 1.75; overflow-wrap: break-word; }
.post-body > * { margin: 0; }
.post-body > * + * { margin-top: 1.25rem; }
.post-body h2 { margin-top: 2.5rem; margin-bottom: 1.25rem; font-size: 1.5rem; line-height: 1.3; }
.post-body ul { padding-left: 1.4rem; }
.post-body li + li { margin-top: 0.35rem; }
.post-body .post-tags { font-size: 0.9375rem; color: var(--accent-text); }
.post-pagination {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
  gap: 1.5rem; margin-top: 3rem; padding-top: 1.5rem; border-top: 1px solid var(--line);
}
.post-pagination a { line-height: 1.5; text-underline-offset: 0.2em; overflow-wrap: anywhere; }
.post-pagination span { display: block; margin-bottom: 0.5rem; font-size: 0.875rem; color: var(--body); }
.nav-links a[aria-current="page"] { color: var(--ink); border-bottom-color: var(--accent); }
@media (max-width: 36rem) {
  .insight-entry { grid-template-columns: minmax(0, 1fr); gap: 0.75rem; }
}

/* Long-form essays and their entry on the Insights index. */
.insights-essays { margin-bottom: 3rem; }
.insights-essays > h2, .insights-series-heading { font-size: 1.5rem; }
.featured-essay { margin-top: 1.25rem; padding: clamp(1.25rem, 4vw, 2.5rem); background: var(--mist); border-radius: var(--r-panel); }
.featured-essay > * + * { margin-top: 1rem; }
.featured-essay .eyebrow { font-size: 0.875rem; }
.featured-essay h3 { font-size: clamp(1.75rem, 3vw, 2.5rem); line-height: 1.2; }
.featured-essay a { text-underline-offset: 0.2em; text-decoration-thickness: 1px; }
.featured-essay a:hover { color: var(--accent-text); }
/* Essays that are not the featured one. The section was written when there was
   exactly one, so a plain article inherited nothing and the entries collapsed
   against each other. They take the panel's rhythm without its background: the
   featured piece stays visually first, and these read as a list under it. */
.insights-essays > article:not(.featured-essay) { margin-top: 2rem; }
.insights-essays > article:not(.featured-essay) > * + * { margin-top: 0.5rem; }
.insights-essays > article:not(.featured-essay) h3 { font-size: 1.25rem; line-height: 1.3; }
.insights-essays > article:not(.featured-essay) a { text-underline-offset: 0.2em; text-decoration-thickness: 1px; }
.insights-essays > article:not(.featured-essay) a:hover { color: var(--accent-text); }
/* The first entry carries a border-top, so the rule lands directly under this
   line. 1.5rem put it closer to the section's own description than two entries
   are to each other -- the heading, its description and the first item read as
   one block rather than as an introduction followed by a list. */
.insights-series-description { margin-block: 0.75rem 2.5rem; }
.essay-contents { margin-bottom: 2.5rem; padding: 1.5rem; border: 1px solid var(--line); border-radius: var(--r-panel); }
.essay-contents h2 { font-size: 1.125rem; }
.essay-contents ol { padding-left: 1.25rem; }
.essay-contents li + li { margin-top: 0.65rem; }
.essay-contents a, .essay-references a { text-underline-offset: 0.15em; }
.essay-body section + section { margin-top: 3rem; }
.essay-body section > * + * { margin-top: 1.25rem; }
/* site.css resets every heading to margin: 0. The essay's sections are direct
   children of <article> with no class of their own, so neither .post-body h2
   nor the old .essay-body h2 -- a class that is not on the page -- ever reached
   them, and the headings sat flush against the prose above and below. On a
   phone the heading is the only signal that a section changed.

   Selected through the sibling that does carry a class. */
.essay-paragraph + h2, h2:has(+ .essay-paragraph) {
  line-height: 1.4; margin-top: 3.25rem; margin-bottom: 1.25rem;
}
.essay-paragraph + h2 + .essay-paragraph { margin-top: 0; }
.essay-section-number { color: var(--accent-text); }
.essay-body sup { font-size: 0.75em; line-height: 0; }
.essay-body sup a { color: var(--accent-text); }
.essay-references { padding-left: 1.5rem; font-size: 1rem; }
.essay-references li + li { margin-top: 1.25rem; }
.essay-body [id] { scroll-margin-top: 2rem; }
@media (max-width: 36rem) {
  .essay-body [id] { scroll-margin-top: 5rem; }
}

/* About contact links wrap naturally on small screens. */
.post-body .contact-links { display: flex; flex-wrap: wrap; gap: 0.5rem 1.5rem; list-style: none; padding: 1.5rem 0 0; margin-top: 2rem; border-top: 1px solid var(--line); font-size: 1rem; }
.contact-links li + li { margin-top: 0; }
.contact-links a { display: inline-flex; align-items: center; gap: 0.5rem; min-height: 44px; text-underline-offset: 0.2em; }
.contact-links svg { width: 20px; height: 20px; flex-shrink: 0; fill: none; stroke: currentColor; stroke-width: 1.75; stroke-linecap: round; stroke-linejoin: round; }
.contact-links span { overflow-wrap: anywhere; }
/* Phone and email are icon-only: the address stays out of the rendered page,
   so the anchor's aria-label carries the accessible name the removed text used
   to provide. Without it these links would announce as bare "link". */
.contact-icon { justify-content: center; min-width: 44px; border-radius: 50%; color: var(--accent-text); }
.contact-icon:hover { background: var(--mist); }
.contact-icon svg { width: 22px; height: 22px; }
.post-body .about-principle {
  margin-block: 2rem; padding: 1.25rem 1.5rem; border-left: 3px solid var(--accent);
  border-radius: 0 8px 8px 0; background: var(--mist); color: var(--ink);
  font-size: clamp(1.35rem, 3vw, 1.75rem); line-height: 1.35; font-weight: 600;
}


/* Tables and code blocks appear for the first time in the operating documents.
   Both can exceed the reading measure -- a fixed-width command, a five-column
   table -- so both scroll within their own box rather than widening the page.
   The rule the site already follows: nothing makes the document scroll
   sideways. */
.post-body pre {
  overflow-x: auto;
  /* A pre in normal flow still sizes to its widest line, and the overflow then
     lands on the document rather than inside the box. Constraining the width
     is what makes the scroll actually happen here. */
  max-width: 100%;
  width: 100%;
  box-sizing: border-box;
  padding: 1rem 1.25rem;
  background: var(--mist);
  border-radius: var(--r-inner);
  font-size: 0.8125rem;
  line-height: 1.5;
}
/* The long lines wrap rather than scroll. A horizontally scrolling code block
   inside a vertically scrolling page is awkward on a phone -- a reader has to
   discover the scroll to see the end of a command -- and these blocks are
   commands and a directory tree, both of which survive wrapping. The
   indentation is preserved, so a wrapped line still reads as a continuation.

   This also settles an overflow the constrained pre could not: a code element
   sizes to its widest line and establishes its parent's content width from
   the inside, so the document widened even with overflow-x on the pre. */
.post-body pre code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}
.post-body :not(pre) > code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.875em;
  background: var(--mist);
  padding: 0.1em 0.35em;
  border-radius: 4px;
}

.post-body table {
  width: 100%;
  border-collapse: collapse;
  margin: 1.5rem 0;
  font-size: var(--t-small);
  display: block;
  overflow-x: auto;
}
.post-body th, .post-body td {
  text-align: left;
  padding: 0.6rem 0.75rem;
  border-bottom: 1px solid var(--line);
  vertical-align: top;
}
.post-body th { font-weight: 600; color: var(--ink); white-space: nowrap; }
/* A section reference in a table is navigation, so it takes the accent the
   site gives every other link. Inheriting the body colour made the immutable
   rules table look like plain text that happened to be clickable. */
.post-body td a[href^="#"] { color: var(--accent-text); font-weight: 600; text-decoration: none; }
.post-body td a[href^="#"]:hover { text-decoration: underline; text-underline-offset: 0.2em; }

/* The redaction banner arrives as a blockquote. */
.post-body blockquote {
  margin: 1.5rem 0;
  padding: 1rem 1.25rem;
  border-left: 3px solid var(--accent);
  background: var(--mist);
  border-radius: 0 var(--r-inner) var(--r-inner) 0;
  font-size: var(--t-small);
}
.post-body blockquote > * + * { margin-top: 0.75rem; }

/* A statement the piece is built around, not a quotation from elsewhere.
   Distinct from blockquote, which is set smaller for redaction banners: these
   lines are the loudest in the document and are sized to say so. */
.post-statement {
  margin: 2rem 0;
  padding: 1.25rem 1.5rem;
  border-left: 3px solid var(--accent);
  background: var(--mist);
  border-radius: 0 var(--r-inner) var(--r-inner) 0;
  color: var(--ink);
  font-size: var(--t-lead);
  line-height: 1.45;
}

/* The author stepping out of the argument to concede something the argument
   cannot hold. Italic rather than parenthesised: a bracket around three
   sentences reads as an interruption, while the slant just lowers the voice.
   Full size, because this is still argument -- it is the register that
   changes, not the importance. */
.post-aside { font-style: italic; color: var(--muted); }

/* A worked example, set beside the argument rather than inside it. The
   emphasis boxes on this site are all short -- a left bar and a tint read as
   "look here", which is wrong for three hundred words: a reader cannot hold an
   emphasis that long and starts resenting it. So this is a panel instead. Rules
   above and below rather than a bar down one side, because the job is to say
   "this is a separate object" rather than "this matters more". Type drops a
   step so the eye registers it as an aside before reading a word of it, and the
   label says what it is, so skipping it is an informed choice rather than a
   guess. */
.post-body .post-case {
  margin-block: 2.5rem;
  padding-block: 1.5rem;
  border-top: 2px solid var(--ink);
  border-bottom: 1px solid var(--line);
  font-size: 1rem;
  line-height: 1.7;
  color: var(--body);
}
.post-body .post-case > * + * { margin-top: 1rem; }
.post-case-label {
  margin-bottom: 0.875rem;
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
.post-body .post-case h3 {
  font-size: 1.25rem;
  line-height: 1.3;
  color: var(--ink);
}

/* A pointer to evidence, after the document rather than inside it: the argument
   stands on its own, and the reader who wants the worked example goes looking. */
.post-followup { margin-top: 2.5rem; padding-top: 1.25rem;
  border-top: 1px solid rgba(0, 0, 0, .1); font-size: .92rem; opacity: .8; }

/* ---- Infrastructure schematic ------------------------------------------ */

/* The diagram is a button so it opens full screen on tap, but it must not look
   or behave like one: no chrome, no default padding, and the cursor says the
   content is zoomable rather than clickable. */
.infra-schematic { margin: 2.5rem 0; }
.infra-schematic-open {
  display: block; width: 100%; padding: 0; border: 1px solid var(--line);
  border-radius: 10px; background: var(--paper); cursor: zoom-in;
  overflow: hidden;
}
.infra-schematic-open:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.infra-schematic figcaption {
  margin-top: .6rem; font-size: .85rem; color: var(--body);
}
.infra-svg { display: block; width: 100%; height: auto; }

/* Full-screen view. Wider and taller than the code modals, because a
   dependency diagram is read across rather than down, and vector text stays
   legible at any scale so it can fit rather than scroll. */
dialog.infra-modal {
  width: min(1400px, 96vw); height: min(94svh, 1100px); padding: 0;
  border: 0; border-radius: 12px; background: transparent;
}
dialog.infra-modal::backdrop { background: rgb(9 12 17 / .62); }
.infra-modal-inner {
  height: 100%; display: flex; flex-direction: column;
  border-radius: 12px; background: var(--paper); padding: 1rem;
}
.infra-modal-inner .infra-svg { flex: 1 1 auto; min-height: 0; height: 100%; }

/* On a narrow screen fitting the whole drawing into a portrait dialog makes it
   smaller than it was on the page -- the opposite of what opening it is for.
   Below the point where that happens the modal scrolls instead: the diagram
   takes a width worth reading and the reader pans. */
@media (max-width: 52rem) {
  .infra-modal-inner { overflow: auto; -webkit-overflow-scrolling: touch; }
  .infra-modal-inner .infra-svg {
    flex: 0 0 auto; width: 900px; max-width: none; height: auto;
  }
  .infra-modal-head { position: sticky; left: 0; }
}
.infra-modal-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 1rem; padding: 0 .25rem .75rem;
}
.infra-modal-head p { margin: 0; font-size: .9rem; color: var(--body); }

/* Entry and exit on the same curves the site's other dialogs use. */
dialog.infra-modal[open] .infra-modal-inner { animation: note-pop-in .22s cubic-bezier(.2, .8, .2, 1) both; }
dialog.infra-modal.is-closing .infra-modal-inner { animation: note-pop-out .16s ease-in both; }
@media (prefers-reduced-motion: reduce) {
  dialog.infra-modal[open] .infra-modal-inner,
  dialog.infra-modal.is-closing .infra-modal-inner { animation: none; }
}

/* The drawing declares system-ui, which renders San Francisco on a Mac while
   the page around it is Inter. Inheriting keeps one typeface on the page. */
/* SVG text does not inherit the page font through the button that wraps it,
   and the drawing's own system-ui attribute rendered San Francisco against the
   page's Inter. Set it here so there is one typeface and one place that says
   so. */
.infra-svg, .infra-svg text {
  font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
}
