/* LKI Custom Theme — site.css
   ============================================================= */

/* ============================================================
   Design Tokens — NOT IN THIS FILE
   ============================================================
   Tokens live in tokens.css. functions.php enqueues it
   ahead of this file as a declared dependency, and it also carries
   the Google Fonts @import.

   Never add a :root block to this file. Change brand values in
   tokens.css so the working theme has one token source.

   ⚠️ The inline block this replaced named its easing token
   --ease-std, while the canonical file calls it --ease-standard.
   All 21 usages (20 here, 1 in single-portfolio.php) were renamed
   in the same commit. If a transition ever stops animating, check
   for a var() name that exists only in this theme.
   ============================================================ */

/* ============================================================
   Reset + Base
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; }
body {
  margin: 0; padding: 0;
  font-family: var(--font-sans);
  font-weight: var(--fw-light);
  background: var(--bg-raised);
  color: var(--fg);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
ul, ol { list-style: none; }
p { margin: 0; }
button { font-family: inherit; }

/* ============================================================
   Layout
   ============================================================ */
.container    { max-width: 1240px; margin: 0 auto; padding: 0 var(--sp-80); }
.sec          { padding: var(--sp-120) 0; }
.sec--tight   { padding: var(--sp-48) 0; }
/* Top padding only, bottom stays at the full var(--sp-120) — for a section
   that should sit close to whatever's directly above it (the proof strip)
   without also compressing the space before whatever comes after it. Added
   August 17, 2026 for Services. */
.sec--flush-top { padding-top: var(--sp-48); }
.sec--neutral { background: var(--bg); }
.sec--dark    { background: var(--bg-inverse); }

/* Full-strength lime, deliberately. Added August 17, 2026 for the portfolio
   "key statement" band (single-portfolio.php): a narrow, one-off moment
   meant to be the loudest thing on the page, not a general section wash
   living alongside a dark section. Confirmed with Lara knowing an earlier
   softer-tint version (.sec--accent) was tried and reverted the same day —
   do not reintroduce that as a general-purpose section tint. */
.sec--lime { background: var(--lki-green-lime); }

/* Light grey, not cream. Used where a section needs to read as visually
   distinct from both a neighbouring .sec--neutral above it and a
   .sec--dark below it — see page-teaching.php's Philosophy section,
   sandwiched between Formats (cream) and the CTA (dark). Added
   August 21, 2026. */
.sec--grey { background: var(--fill-subtle); }
.sec-rule     { border: none; border-top: 1px solid var(--border); margin: 0; }

/* ============================================================
   Type
   ============================================================ */
.eyebrow {
  display: block;
  font-size: var(--type-micro); line-height: var(--type-micro-lh); font-weight: var(--fw-black);
  letter-spacing: var(--track-micro); text-transform: uppercase;
  color: var(--accent-deep); margin-bottom: var(--sp-20);
}
.eyebrow--light  { color: var(--accent); }
.eyebrow--muted  { color: var(--fg-subtle); }  /* was grey-4 (1.7:1, failed AA). grey-2 is 5.8:1. Fixed Aug 16, 2026 */
.accent          { font-family: var(--font-serif); font-style: italic; font-weight: 400; }

h2.display-h2 {
  font-size: var(--type-h2);
  line-height: var(--type-h2-lh); letter-spacing: var(--track-display);
  font-weight: var(--fw-black); margin-bottom: var(--sp-24);
}
h3.h3 {
  font-size: var(--type-h4); line-height: var(--type-h4-lh); font-weight: var(--fw-black);
  letter-spacing: var(--track-tight); margin-bottom: var(--sp-8);
}
.lead {
  font-size: var(--type-lead); line-height: var(--type-lead-lh); font-weight: var(--fw-light);
  color: var(--fg-muted); max-width: 60ch;
}
.lead--light { color: var(--fg-on-dark-muted); }
.body-copy { font-size: var(--type-body); line-height: var(--type-body-lh); font-weight: var(--fw-light); color: var(--fg-muted); }
.body-copy p + p { margin-top: var(--sp-16); }
.body-copy a { color: var(--cta); text-decoration: underline; text-decoration-thickness: 1px; }
.body-copy--light { color: var(--fg-on-dark-muted); }

/* Gives an editable section's first paragraph the same size and weight
   .lead--big already carries on About and Services — there's no way to
   mark just one paragraph as special from a plain WYSIWYG editor, so this
   targets :first-child instead. A medium-weight version of this was tried
   August 21, 2026 to make the line read as heavier, but that put Hosting
   and Teaching's opening paragraph out of step with every other page's —
   reverted to match August 25, 2026. Used by page-hosting.php's and
   page-teaching.php's Opening sections. */
.body-copy--opening > p:first-child {
  font-size: var(--type-lead); line-height: 1.6; font-weight: var(--fw-light); color: var(--fg);
}

/* A short note closing out a block: a price footnote, an availability line,
   a pointer to another page. The one place --fw-medium is used. At 300 these
   dissolved into the body copy above them; at 900 they shouted, and there
   are three on the homepage.

   Replaces .about-note, which was this same idea at 900 and was the only
   thing on the site styled that way. Consolidated August 16, 2026, when the
   three notes were each styled differently. */
.callout-note {
  margin-top: var(--sp-32); max-width: 72ch;
  font-size: var(--type-body); line-height: var(--type-body-lh);
  font-weight: var(--fw-medium); color: var(--fg); letter-spacing: -.005em;
}
.callout-note a { color: var(--cta); text-decoration: underline; text-decoration-thickness: 1px; }

/* ============================================================
   Grids
   ============================================================ */
.grid-2      { display: grid; grid-template-columns: 5fr 7fr; gap: var(--sp-80); align-items: start; }
.grid-2-even { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-64); align-items: center; }

/* Sticky left column: the left side of a .grid-2 stays in view while the
   right side (usually much longer) scrolls past it. Opt in with
   .grid-2--sticky rather than changing .grid-2 itself — .grid-2 is also
   used on About, Hosting and Teaching, where this would be wrong. */
.grid-2--sticky > *:first-child { position: sticky; top: 104px; align-self: start; }

/* Mirror image of .grid-2 — the wide column moves left, the narrow one
   right. The swap is done with grid-column rather than by reordering the
   markup, so the heading stays first in the DOM. That keeps the reading
   order correct for screen readers, and keeps the heading above the body
   copy once this collapses to a single column. */
.grid-3      { display: grid; grid-template-columns: repeat(3,1fr); gap: var(--sp-24); }

/* ============================================================
   Scroll Reveal
   ============================================================ */
/* Scoped to .js .reveal, not bare .reveal. header.php stamps <html
   class="no-js"> and flips it to "js" in an inline script before the
   page paints. Without this scoping, JS disabled (or a script that
   fails) leaves every .reveal element at opacity:0 forever, since
   nothing would ever add .is-visible. Some templates gate their entire
   content behind .reveal (portfolio.php is 16 of 16 rows), so a JS
   failure there means a blank page rather than a static one. */
.js .reveal {
  opacity: 0; transform: translateY(18px);
  transition: opacity 520ms var(--ease-standard), transform 520ms var(--ease-standard);
}
.reveal.is-visible { opacity: 1; transform: none; }
.js .reveal.d1 { transition-delay: 80ms; }
.js .reveal.d2 { transition-delay: 160ms; }
.js .reveal.d3 { transition-delay: 240ms; }

/* Anyone who has asked their OS for less motion gets the content
   immediately, with no animation, regardless of the .js/.is-visible
   state above. */
@media (prefers-reduced-motion: reduce) {
  .js .reveal, .reveal.is-visible { opacity: 1 !important; transform: none !important; transition: none !important; }
}

/* ============================================================
   Navigation
   ============================================================ */
.nav {
  position: fixed; top: 0; left: 0; right: 0; z-index: 100;
  height: 84px; display: flex; align-items: center;
  transition: background var(--dur-std) var(--ease-standard);
}
.nav.scrolled {
  background: var(--bg-scrim);
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
}
.nav__inner {
  width: 100%; max-width: 1240px; margin: 0 auto; padding: 0 var(--sp-80);
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-32);
}
.nav__logo         { height: 56px; width: auto; display: block; }
.nav__logo-light   { display: block; }
.nav__logo-dark    { display: none; }
.nav.scrolled .nav__logo-light { display: none; }
.nav.scrolled .nav__logo-dark  { display: block; }
.nav__links {
  display: flex; align-items: center; gap: var(--sp-32);
  font-size: var(--type-micro); font-weight: var(--fw-black);
  letter-spacing: .06em; text-transform: uppercase;
}
.nav__link { color: var(--fg-on-dark-muted); transition: color var(--dur-fast); }
.nav__link:hover { color: var(--fg-on-dark); }
.nav.scrolled .nav__link       { color: var(--fg-muted); }
.nav.scrolled .nav__link:hover { color: var(--fg); }
.nav .nav-pill {
  display: inline-flex; align-items: center; gap: var(--sp-8);
  padding: var(--sp-8) var(--sp-8) var(--sp-8) var(--sp-16); border-radius: var(--radius-pill);
  background: var(--bg-raised-on-dark); border: 1px solid var(--border-on-dark-strong);
  color: var(--fg-on-dark);
  font-family: var(--font-sans); font-size: var(--type-micro); font-weight: var(--fw-black);
  letter-spacing: .04em; text-transform: uppercase;
  cursor: pointer; text-decoration: none;
  transition: background var(--dur-fast), border-color var(--dur-fast);
}
.nav .nav-pill:hover { background: var(--bg-raised-on-dark-hover); border-color: var(--fg-on-dark-muted); }
.nav .nav-pill .arr {
  width: 28px; height: 28px; border-radius: 50%;
  background: var(--cta); color: var(--fg);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  transition: transform var(--dur-std) var(--ease-standard),
              background var(--dur-fast) var(--ease-standard);
}
.nav .nav-pill:hover .arr { transform: rotate(45deg); }
.nav.scrolled .nav-pill { background: var(--bg-inverse); color: var(--fg-on-dark); border-color: transparent; }
.nav.scrolled .nav-pill:hover { background: var(--cta); color: var(--fg); }

/* Hamburger */
.nav__hamburger {
  display: none; flex-direction: column; justify-content: space-between;
  width: 24px; height: 18px;
  background: none; border: none; cursor: pointer; padding: 0; flex-shrink: 0;
}
.nav__hamburger span {
  display: block; height: 2px; border-radius: 2px;
  background: var(--fg-on-dark-muted);
  transition: transform var(--dur-std) var(--ease-standard), opacity var(--dur-fast), background var(--dur-std) var(--ease-standard);
}
.nav.scrolled .nav__hamburger span,
body:not(.home) .nav .nav__hamburger span { background: var(--bg-inverse); }
.nav__hamburger.is-open span:nth-child(1) { transform: translateY(8px) rotate(45deg); }
.nav__hamburger.is-open span:nth-child(2) { opacity: 0; }
.nav__hamburger.is-open span:nth-child(3) { transform: translateY(-8px) rotate(-45deg); }
.nav__drawer {
  position: fixed; top: 84px; left: 0; right: 0; z-index: 99;
  background: var(--bg-scrim-solid);
  backdrop-filter: saturate(160%) blur(14px); -webkit-backdrop-filter: saturate(160%) blur(14px);
  display: flex; flex-direction: column;
  max-height: 0; overflow: hidden;
  transition: max-height var(--dur-std) var(--ease-standard);
}
.nav__drawer.is-open { max-height: 400px; }
.nav__drawer-link {
  display: block; padding: var(--sp-12) var(--sp-32);
  font-size: var(--type-small); font-weight: var(--fw-black); letter-spacing: .06em; text-transform: uppercase;
  color: var(--fg-muted); text-decoration: none;
  border-bottom: 1px solid var(--border);
  transition: color var(--dur-fast), background var(--dur-fast);
}
.nav__drawer-link:hover { color: var(--fg); background: var(--bg-hover-tint); }
.nav__drawer-cta {
  display: block; margin: var(--sp-16) var(--sp-32) var(--sp-20); padding: var(--sp-12) var(--sp-20);
  background: var(--bg-inverse); color: var(--fg-on-dark);
  border-radius: var(--radius-pill); text-align: center;
  font-size: var(--type-small); font-weight: var(--fw-black); letter-spacing: .04em; text-transform: uppercase;
  text-decoration: none; transition: background var(--dur-fast);
}
.nav__drawer-cta:hover { background: var(--cta); color: var(--fg); }

/* ============================================================
   Hero
   ============================================================ */
.hero {
  position: relative; min-height: 100vh;
  display: flex; flex-direction: column; justify-content: flex-end;
  /* Fixed floor under the fixed nav (84px tall). Content bottom-anchors via
     flex, so on short viewports (short windows, landscape tablets) it can
     ride up past the nav with nothing to stop it. This padding-top is that
     stop: it reserves a zone the flex box can never shrink into, regardless
     of viewport height. Confirmed reproducing and fixed August 9, 2026. */
  padding-top: var(--sp-120); padding-bottom: var(--sp-96); background: var(--bg-inverse); overflow: hidden;
}
.hero__bg { position: absolute; inset: 0; z-index: 0; background: var(--bg-inverse); }

/* Photographic hero. The scrim is what keeps a headline legible over an
   arbitrary image, so it is not decoration and templates must not restate it:
   pass the picture in as --hero-image and nothing else.

   This existed as a literal three-stop rgba() triple pasted into seven
   templates until August 16, 2026, which meant changing the dark was seven
   edits and the blog hero had already drifted from the rest. */
.hero__bg--photo {
  background-image:
    linear-gradient(to top,
      var(--scrim-hero-strong) 0%,
      var(--scrim-hero-mid)   45%,
      var(--scrim-hero-soft) 100%),
    var(--hero-image, none);
  background-position: center center;
  background-size: cover;
  background-repeat: no-repeat;
}
/* Denser, for a hero carrying three lines of text over a busy abstract. */
.hero__bg--photo-dense {
  background-image:
    linear-gradient(to top,
      var(--scrim-hero-strong) 0%,
      var(--scrim-hero-dense) 45%,
      var(--scrim-hero-mid)  100%),
    var(--hero-image, none);
}
.hero__body {
  position: relative; z-index: 2;
  width: 100%; max-width: 1240px; margin: 0 auto; padding: 0 var(--sp-80);
}
.hero__h1 {
  font-size: var(--type-display);
  line-height: var(--type-display-lh); letter-spacing: var(--track-display);
  font-weight: var(--fw-black); color: var(--fg-on-dark);
  max-width: 16ch; margin-bottom: var(--sp-32);
}
.hero__h1 .accent { color: var(--accent); }

/* Homepage hero headline is long enough that the shared 16ch cap breaks it
   into 4 lines. Widened here (desktop only, via the forced <br> in
   front-page.php) so it lands as 2.
   The font-size cap is also lowered from the shared 6.2rem: at that size the
   second line ("Design Guidelines built to last.") no longer fits the
   1080px content width once .hero__body hits its own 1240px cap (~1459px
   viewport and up), which silently re-wraps it to 4 lines again. Measured
   the real breakpoint at 96px on this font; 5.5rem (88px) keeps a safe
   margin at every width, confirmed up to 3440px viewport. */
.hero__h1--home {
  max-width: 36ch;
  /* The display step, capped: this headline is longer than an interior
     hero's and wraps to four lines at the full step. */
  font-size: min(var(--type-display), 5.5rem);
}

/* The shared 16ch cap is too narrow for "Teaching the thinking," to fit
   one line on its own, so even with a forced | break before "not" (see
   lki_hero_accent() in functions.php) it kept wrapping to 3 lines instead
   of 2. Widened rather than touching the shared .hero__h1, which every
   other page's hero is already tuned against. Added August 21, 2026. */
.hero__h1--teaching { max-width: 24ch; }

/* A <br> that only renders at desktop widths, for forcing a heading break
   deliberately without risking a widow when mobile reflows narrower and
   would otherwise strand a short word alone with the forced break still in
   place. Whitespace either side collapses normally either way. */
.br-desktop { display: none; }
@media (min-width: 761px) { .br-desktop { display: inline; } }
.hero__lead {
  font-size: var(--type-lead); line-height: 1.68; color: var(--fg-on-dark-muted);
  max-width: 54ch; margin-bottom: var(--sp-48); font-weight: var(--fw-light);
}
.hero__ctas { display: flex; flex-wrap: wrap; gap: var(--sp-16); align-items: center; }

/* Kinsta Agency Partner badge. Sits under the lead as a credential, not a
   decoration, so it's sized to read clearly without competing with the
   headline. Beige file is for the dark hero background; a black variant
   also exists in assets-logo for use on cream/light sections if this badge
   is ever placed there instead. Added August 21, 2026. */
.hero__badge { display: block; width: 200px; height: auto; }

/* ============================================================
   Buttons
   ============================================================ */
.btn-pill {
  display: inline-flex; align-items: center; gap: var(--sp-8);
  padding: var(--sp-8) var(--sp-8) var(--sp-8) var(--sp-24); border-radius: var(--radius-pill);
  background: var(--bg-inverse); color: var(--fg-on-dark);
  font-family: var(--font-sans); font-size: var(--type-small); font-weight: var(--fw-black);
  letter-spacing: .01em; cursor: pointer; border: none; text-decoration: none;
  transition: background var(--dur-fast) var(--ease-standard),
              color var(--dur-fast) var(--ease-standard); white-space: nowrap;
}
.btn-pill .arr {
  width: 36px; height: 36px; border-radius: 50%;
  background: var(--cta); color: var(--fg);
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  transition: transform var(--dur-std) var(--ease-standard);
}
.btn-pill:hover { background: var(--cta); color: var(--fg); }
.btn-pill:active { background: var(--cta-hover); color: var(--fg); }
.btn-pill:hover .arr { background: var(--bg-inverse); color: var(--fg-on-dark); }
.btn-pill:hover .arr { transform: rotate(45deg); }
.btn-pill--hero {
  background: var(--bg-raised-on-dark); color: var(--fg-on-dark);
  border: 1px solid var(--border-on-dark-strong);
}
.btn-pill--hero:hover { background: var(--cta); border-color: var(--cta); color: var(--fg); }
.btn-pill--hero:active { background: var(--cta-hover); border-color: var(--cta-hover); color: var(--fg); }
.btn-ghost {
  display: inline-flex; align-items: center; gap: var(--sp-8);
  background: none; border: none; cursor: pointer; text-decoration: none;
  font-family: var(--font-sans); font-size: var(--type-small); font-weight: var(--fw-black);
  letter-spacing: .01em; color: var(--fg-on-dark-muted); transition: color var(--dur-fast);
}
.btn-ghost:hover { color: var(--cta); }
.btn-ghost--dark { color: var(--fg-muted); }
.btn-ghost--dark:hover { color: var(--fg); text-decoration: underline;
  text-decoration-color: var(--cta); text-underline-offset: 5px; text-decoration-thickness: 2px; }
.btn-outline {
  display: inline-flex; align-items: center; gap: var(--sp-8);
  padding: var(--sp-12) var(--sp-24); border-radius: var(--radius-pill);
  border: 1.5px solid var(--fg); background: transparent; color: var(--fg);
  font-family: var(--font-sans); font-size: var(--type-small); font-weight: var(--fw-black);
  cursor: pointer; text-decoration: none;
  transition: background var(--dur-fast), color var(--dur-fast), border-color var(--dur-fast);
}
.btn-outline:hover { background: var(--cta); border-color: var(--cta); color: var(--fg); }
.btn-outline:active { background: var(--cta-hover); border-color: var(--cta-hover); color: var(--fg); }
.btn-pill:focus-visible,
.btn-outline:focus-visible,
.btn-ghost:focus-visible,
.link:focus-visible {
  outline: 2px solid var(--cta);
  outline-offset: 3px;
}

/* ============================================================
   Proof Strip
   ============================================================ */
.proof {
  overflow: hidden; display: flex; padding: var(--sp-8) 0 var(--sp-16);
  -webkit-mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
  mask-image: linear-gradient(to right, transparent 0%, black 8%, black 92%, transparent 100%);
}
.proof__track {
  display: flex; flex-shrink: 0; gap: var(--sp-64); align-items: center;
  height: 96px; padding-right: var(--sp-64); animation: marquee 32s linear infinite;
}
.proof:hover .proof__track { animation-play-state: paused; }
@keyframes marquee { from { transform: translateX(0); } to { transform: translateX(-100%); } }
.proof__item { flex: 0 0 auto; display: flex; align-items: center; justify-content: center; }
.proof__logo { height: 44px; width: auto; max-width: 220px; filter: brightness(0) opacity(0.45); display: block; }

/* ============================================================
   Services
   ============================================================ */
.caps {
  display: grid; grid-template-columns: repeat(3,1fr); gap: var(--sp-40);
  margin-top: var(--sp-64); padding-top: var(--sp-48); border-top: 1px solid var(--border);
}
.cap__icon { width: 56px; height: 56px; margin-bottom: var(--sp-16); display: block; opacity: .55; }
/* Same icon as the homepage's "Systems thinking" card, tilted a few degrees
   on the Services page's Solution Engagements section. The rotation is the
   only thing that differs: a quiet visual echo back to the homepage rather
   than a second identical icon, since the section text also isn't identical
   wording, just the same idea restated for a bigger scale of project. */
.cap__icon--tilt { transform: rotate(-6deg); }

/* ============================================================
   Pricing Cards
   ============================================================ */
.pricing-card {
  background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius-md); padding: var(--sp-32) var(--sp-32);
  display: flex; flex-direction: column;
  transition: transform var(--dur-std) var(--ease-standard), box-shadow var(--dur-std) var(--ease-standard);
}
.pricing-card:hover { transform: translateY(-4px); box-shadow: var(--shadow-xs); }
.pricing-card__label {
  font-size: var(--type-micro); font-weight: var(--fw-black); letter-spacing: .14em; text-transform: uppercase;
  color: var(--accent-deep); margin-bottom: var(--sp-16);
}
.pricing-card__price { font-size: var(--type-h3); font-weight: var(--fw-black); letter-spacing: -.02em; margin-bottom: var(--sp-20); }
.pricing-card__list {
  margin-top: auto; padding-top: var(--sp-20); border-top: 1px solid var(--border);
  display: flex; flex-direction: column; gap: var(--sp-8);
}
.pricing-card__list li { font-size: var(--type-small); color: var(--fg-muted); display: flex; align-items: flex-start; gap: var(--sp-8); }
.pricing-card__list li::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent-deep); flex-shrink: 0; margin-top: var(--sp-4);
}

/* The cards were already equal height, because grid items stretch. What was
   ragged is the divider above the bullet list: the lists hold five, four and
   three items, so margin-top:auto parked each one at a different height.

   Subgrid gives all three cards the same four row tracks — label, price,
   body, list — so the list row is sized by the longest list and every
   divider lands on the same line. The body row takes 1fr so it absorbs any
   slack rather than the gap opening up above the divider.

   Opt-in class rather than styling .grid-3, which is also used by the work
   grid, single-portfolio.php and page-hosting.php. Same reasoning as the
   note on .grid-2-even--cards. */
@supports (grid-template-rows: subgrid) {
  .grid-3--cards { grid-template-rows: auto auto 1fr auto; }
  .grid-3--cards > .pricing-card {
    display: grid; grid-template-rows: subgrid; grid-row: span 4; row-gap: 0;
  }
  /* Was pushing the list down inside the old flex column. The subgrid row
     handles that placement now. */
  .grid-3--cards .pricing-card__list { margin-top: 0; }
}

/* ============================================================
   Work
   ============================================================ */
.work-header { display: flex; align-items: flex-end; justify-content: space-between; gap: var(--sp-24); margin-bottom: var(--sp-48); }
.case-study { display: flex; flex-direction: column; gap: var(--sp-12); }
.case-study__img { aspect-ratio: 4/3; overflow: hidden; }
.case-study__img img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 400ms var(--ease-standard); }
.case-study__img:hover img { transform: scale(1.03); }
.case-study__img.no-img {
  background: var(--bg); border: 1px solid var(--border);
  background-image:
    linear-gradient(to top right, transparent calc(50% - .5px), var(--fill-subtle) calc(50% - .5px), var(--fill-subtle) calc(50% + .5px), transparent calc(50% + .5px)),
    linear-gradient(to bottom right, transparent calc(50% - .5px), var(--fill-subtle) calc(50% - .5px), var(--fill-subtle) calc(50% + .5px), transparent calc(50% + .5px));
}
.case-study__client { font-size: var(--type-micro); font-weight: var(--fw-black); letter-spacing: .1em; text-transform: uppercase; color: var(--accent-deep); }
.case-study__title { font-size: var(--type-h4); font-weight: var(--fw-black); letter-spacing: -.01em; line-height: 1.3; }
.case-study__desc { font-size: var(--type-small); color: var(--fg-muted); line-height: 1.65; }

/* ============================================================
   AI / Tools
   ============================================================ */
.ai-items {
  display: grid; grid-template-columns: repeat(3,1fr); gap: var(--sp-40);
  margin-top: var(--sp-56); padding-top: var(--sp-48); border-top: 1px solid var(--border-on-dark);
}
.ai-item__icon { width: 56px; height: 56px; display: block; margin-bottom: var(--sp-16); filter: brightness(0) invert(1) opacity(.6); }
.ai-item__title { font-size: var(--type-h4); font-weight: var(--fw-black); letter-spacing: -.01em; color: var(--fg-on-dark); margin-bottom: var(--sp-8); }
.ai-item__body { font-size: var(--type-small); line-height: 1.68; color: var(--fg-on-dark-muted); }

/* Each card is an icon, a title and a paragraph. "Workflow design" fits on
   one line while the other two titles wrap to two, so the paragraphs used to
   start at three different heights and the row read as ragged.

   Subgrid hands the cards the parent's rows instead of their own, so the
   tallest title sizes one shared row and all three paragraphs start level.
   row-gap goes to 0 because the children would otherwise inherit the 40px
   parent gap between icon, title and body; the spacing there comes from the
   margins already on .ai-item__icon and .ai-item__title.

   Wrapped in @supports so browsers without subgrid keep the current ragged
   layout rather than getting two empty 40px rows under every card. */
@supports (grid-template-rows: subgrid) {
  .ai-items { grid-template-rows: auto auto auto; }
  .ai-items > * { display: grid; grid-template-rows: subgrid; grid-row: span 3; row-gap: 0; }
}

/* A bordered box for a grid of short if/then pairs on a dark section.
   Same hairline-on-transparent treatment as .sec--dark .strip__item. */
.route-card {
  border: 1px solid var(--border-on-dark); border-radius: var(--radius-md);
  padding: var(--sp-24) var(--sp-20);
  transition: transform var(--dur-std) var(--ease-standard), border-color var(--dur-std) var(--ease-standard);
}
.route-card:hover { transform: translateY(-4px); border-color: var(--border-on-dark-strong); }

/* Equal-height/width cards: scoped to the route grid specifically, not to
   .grid-2-even itself, which is shared across About, Hosting, Teaching and
   the 404 page with center-aligned content that should NOT stretch. */
/* Tighter gap than the base .grid-2-even (72px) so each card gets more
   width to wrap its text into fewer lines, which also shrinks the excess
   bottom whitespace the equal-height stretch was creating. Scoped here,
   not on .grid-2-even itself — that's shared with About, Hosting,
   Teaching and 404. */
.grid-2-even--cards { align-items: stretch; grid-auto-rows: 1fr; gap: var(--sp-32); }

/* ============================================================
   Testimonials
   ============================================================ */
.t-masonry {
  display: grid; grid-template-columns: repeat(3,1fr); gap: var(--sp-16);
  overflow: hidden; max-height: 700px; position: relative; margin-top: var(--sp-48);
}
.t-masonry::before, .t-masonry::after {
  content: ''; position: absolute; left: 0; right: 0; height: 140px; z-index: 2; pointer-events: none;
}
.t-masonry::before { top: 0; background: linear-gradient(to bottom, var(--bg) 0%, transparent 100%); }
.t-masonry::after  { bottom: 0; background: linear-gradient(to top, var(--bg) 0%, transparent 100%); }
.t-col { display: flex; flex-direction: column; gap: var(--sp-16); }
.t-col--1 { animation: t-scroll-up 30s linear infinite; }
.t-col--2 { animation: t-scroll-up 38s linear infinite; }
.t-col--3 { animation: t-scroll-up 26s linear infinite; }
.t-col:hover { animation-play-state: paused; }
@keyframes t-scroll-up { 0% { transform: translateY(0); } 100% { transform: translateY(-50%); } }
.t-card {
  background: var(--bg-raised); border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: var(--sp-20) var(--sp-24); display: flex; flex-direction: column; gap: var(--sp-2);
}
.t-card:hover { box-shadow: var(--shadow-xs); }
.t-card__mark { font-family: var(--font-serif); font-style: italic; font-size: var(--type-h2); line-height: 1; color: var(--accent-deep); display: block; margin-bottom: var(--sp-2); }
.t-card__body { font-family: var(--font-serif); font-style: italic; font-size: var(--type-body); line-height: 1.5; color: var(--fg); margin: 0 0 var(--sp-12); }
.t-card__name { font-size: var(--type-small); font-weight: var(--fw-black); color: var(--fg); margin: 0; line-height: 1.2; }
.t-card__role { font-size: var(--type-micro); color: var(--fg-muted); margin: var(--sp-2) 0 0; line-height: 1.3; }

/* ============================================================
   Quote wall — unboxed testimonials, divided by a hairline rather
   than cards. Deliberately different from .t-card (used on the
   homepage masonry) so a page carrying both a card-list (.card,
   used by Fit) and testimonials doesn't repeat the same component
   twice in a row.
   ============================================================ */
.quote-wall { display: grid; grid-template-columns: repeat(3, 1fr); row-gap: var(--sp-48); }
.quote-wall > * { padding: 0 var(--sp-32); }
.quote-wall > *:nth-child(3n+1) { padding-left: 0; }
/* Divider on columns 2 and 3 of every row, not just item 2 onward overall —
   :not(:first-child) would draw a stray one at the start of rows 2, 3, etc. */
.quote-wall > *:not(:nth-child(3n+1)) { border-left: 1px solid var(--border); }
.quote-wall__mark { font-family: var(--font-serif); font-style: italic; font-size: var(--type-h1); line-height: 1; color: var(--accent-deep); display: block; margin-bottom: var(--sp-4); }
.quote-wall__text { font-family: var(--font-serif); font-style: italic; font-size: var(--type-lead); line-height: 1.45; color: var(--fg); }
.quote-wall__name { font-size: var(--type-small); font-weight: var(--fw-black); letter-spacing: .01em; color: var(--fg); margin-top: var(--sp-24); }
.quote-wall__role { font-size: var(--type-micro); color: var(--fg-muted); margin-top: var(--sp-2); }
@media (max-width: 860px) {
  .quote-wall { grid-template-columns: 1fr; gap: var(--sp-40); }
  .quote-wall > * { padding: 0; border-left: none !important; }
}

/* ============================================================
   Fit compare — two unboxed columns split by a hairline, a checkmark
   or × per line instead of a bullet. Replaces the old two .card boxes:
   Choosing above this section already uses a bordered-card idiom, so
   Fit repeating it right after felt like the same component twice.
   ============================================================ */
.fit-compare { display: grid; grid-template-columns: 1fr 1fr; }
.fit-compare > * { padding: 0 var(--sp-40); }
.fit-compare > *:first-child { padding-left: 0; }
.fit-compare > *:not(:first-child) { border-left: 1px solid var(--border); }
.fit-compare__list { list-style: none; margin: var(--sp-20) 0 0; display: flex; flex-direction: column; gap: var(--sp-16); }
.fit-compare__list li { display: flex; align-items: flex-start; gap: var(--sp-12); font-size: var(--type-body); line-height: 1.5; color: var(--fg-muted); }
.fit-compare__list img { width: 18px; height: 18px; flex-shrink: 0; margin-top: var(--sp-4); }
@media (max-width: 760px) {
  .fit-compare { grid-template-columns: 1fr; gap: var(--sp-40); }
  .fit-compare > * { padding: 0; border-left: none !important; }
}

/* ============================================================
   About
   ============================================================ */
.about-grid  { display: grid; grid-template-columns: 2fr 3fr; gap: var(--sp-96); align-items: start; }
.about-photo { aspect-ratio: 4/5; overflow: hidden; border-radius: var(--radius-sm); }
.about-photo img { width: 100%; height: 100%; object-fit: cover; object-position: center top; display: block; }
.about-photo.no-img {
  background: var(--bg); border: 1px solid var(--border);
  background-image:
    linear-gradient(to top right, transparent calc(50% - .5px), var(--fill-subtle) calc(50% - .5px), var(--fill-subtle) calc(50% + .5px), transparent calc(50% + .5px)),
    linear-gradient(to bottom right, transparent calc(50% - .5px), var(--fill-subtle) calc(50% - .5px), var(--fill-subtle) calc(50% + .5px), transparent calc(50% + .5px));
}
.about-btns  { display: flex; flex-wrap: wrap; gap: var(--sp-12); align-items: center; margin-top: var(--sp-32); }

/* ============================================================
   FAQ
   ============================================================ */
.faq-grid  { display: grid; grid-template-columns: 4fr 8fr; gap: var(--sp-96); align-items: start; }
.faq-list  { border-top: 1.5px solid var(--fg); }
/* Rows carry horizontal padding so the hover band has room around the label
   instead of the text sitting flush against its edge. Nothing else occupies
   this grid column above the list, so the indent breaks no alignment. */
.faq-trigger {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: var(--sp-24);
  padding: var(--sp-24) var(--sp-20); background: none; border: none; border-bottom: 1px solid var(--border);
  font-family: var(--font-sans); font-size: var(--type-h4); font-weight: var(--fw-black);
  letter-spacing: -.01em; color: var(--fg); cursor: pointer; text-align: left;
  transition: background var(--dur-fast);
}
.faq-trigger:hover { background: var(--accent); }
.faq-item.open .faq-trigger { border-bottom-color: transparent; }
.faq-icon {
  width: 20px; height: 20px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--fg-muted);
  transition: transform var(--dur-std) var(--ease-standard);
}
.faq-item.open .faq-icon { transform: rotate(180deg); }
.faq-body { max-height: 0; overflow: hidden; transition: max-height 400ms var(--ease-standard); }
.faq-content {
  padding: var(--sp-2) var(--sp-20) var(--sp-32); font-size: var(--type-body); line-height: 1.74; color: var(--fg-muted);
  border-bottom: 1px solid var(--border); max-width: 68ch;
}

/* ============================================================
   CTA Section
   ============================================================ */
.cta-sec { text-align: center; padding: var(--sp-120) 0; position: relative; overflow: hidden; background: var(--bg-inverse); }
.cta-sec__flowers { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; pointer-events: none; }
.cta-sec__flowers img { width: min(900px, 120%); opacity: .06; filter: brightness(0) invert(1); }
.cta-sec .display-h2 { max-width: 26ch; margin: 0 auto var(--sp-48); color: var(--fg-on-dark); font-size: var(--type-h2); }
.cta-sec .eyebrow { color: var(--accent); }
/* The optional supporting paragraph (see $lki_cta['body'] in footer.php).
   Needs its own centering: max-width alone caps a block's width but
   doesn't center the box, so without this the text read center-aligned
   inside a box sitting flush left instead of centered like the heading
   above it. Added August 21, 2026. */
.cta-sec .lead { max-width: 46ch; margin: calc(-1 * var(--sp-32)) auto var(--sp-32); }

/* ============================================================
   Callout — a bordered card, centered on the page. Drop one on its
   own: <section class="sec callout"><div class="container">
   <div class="callout-box">...</div></div></section>, or two side by
   side at matching width via .callout-grid (each box fills its
   column, so "matching width" is guaranteed by the grid, not
   eyeballed). Content is vertically centered so uneven text length
   between two boxes can't leave one with more bottom whitespace than
   the other — found and fixed August 12, 2026.
   ============================================================ */
.callout { text-align: center; }

.callout-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-32); }
.callout-grid .callout-box { max-width: none; margin: 0; }
@media (max-width: 760px) {
  .callout-grid { grid-template-columns: 1fr; }
}

.callout-box {
  max-width: 640px; margin: 0 auto; padding: var(--sp-56) var(--sp-48);
  background: var(--bg);
  border: 1px solid var(--border);
  border-radius: var(--radius-lg);
  display: flex; flex-direction: column; justify-content: center;
}
/* One dark, one green — a stronger pair than two greys or two greens.
   Dark needs its text flipped light; green stays dark text but the default
   teal eyebrow is swapped for --lki-dark for clean contrast against mint. */
.callout-box--dark { background: var(--bg-inverse); }
.callout-box--dark .eyebrow { color: var(--accent); }
.callout-box--dark .display-h2 { color: var(--fg-on-dark); }
.callout-box--dark .body-copy { color: var(--fg-on-dark-muted); }
.callout-box--dark .link { color: var(--cta); }

.callout-box--green { background: var(--accent); }
.callout-box--green .eyebrow { color: var(--fg); }

/* .cap__icon is left-aligned by default (it sits above a left-aligned
   eyebrow everywhere else it's used); .callout-box centers its text,
   so the icon needs its own centering here rather than inheriting it. */
.callout-box .cap__icon { margin-left: auto; margin-right: auto; }

/* ============================================================
   Footer
   ============================================================ */
.footer { background: var(--bg-inverse); border-top: 1px solid var(--border-on-dark); padding: var(--sp-48) 0 var(--sp-40); }
.footer__inner { display: grid; grid-template-columns: 1fr auto auto; gap: var(--sp-40); align-items: center; }
.footer__logo { height: 56px; width: auto; opacity: .9; }
.footer__copy { font-size: var(--type-micro); color: var(--fg-on-dark-subtle); margin-top: var(--sp-8); }
.footer__nav { display: flex; flex-wrap: wrap; gap: var(--sp-8) var(--sp-24); font-size: var(--type-micro); font-weight: var(--fw-black); letter-spacing: .06em; text-transform: uppercase; }
.footer .footer__nav a { color: var(--fg-on-dark-subtle); transition: color var(--dur-fast); text-decoration: none; }
.footer .footer__nav a:hover { color: var(--cta); }
.footer__socials { display: flex; align-items: center; gap: var(--sp-8); }
.footer__social {
  display: flex; align-items: center; justify-content: center;
  width: 34px; height: 34px; border-radius: 50%;
  border: 1px solid var(--border-on-dark); text-decoration: none; transition: border-color 140ms;
}
.footer__social:hover { border-color: var(--cta); }
.footer__social img { display: block; filter: brightness(0) invert(1) opacity(0.45); transition: filter 140ms; }
.footer__social:hover img { filter: invert(64%) sepia(52%) saturate(697%) hue-rotate(296deg) brightness(103%) contrast(103%); }

/* ============================================================
   Interior nav — solid on non-hero pages
   body.nav-solid is added via body_class filter in functions.php
   ============================================================ */
body.nav-solid .nav {
  background: var(--bg-scrim);
  backdrop-filter: saturate(160%) blur(14px);
  -webkit-backdrop-filter: saturate(160%) blur(14px);
}
body.nav-solid .nav .nav__logo-light { display: none; }
body.nav-solid .nav .nav__logo-dark  { display: block; }
body.nav-solid .nav .nav__link       { color: var(--fg-muted); }
body.nav-solid .nav .nav__link:hover { color: var(--fg); }
body.nav-solid .nav .nav-pill        { background: var(--bg-inverse); color: var(--fg-on-dark); border-color: transparent; }
body.nav-solid .nav .nav-pill:hover  { background: var(--cta); color: var(--fg); }
body.nav-solid .nav .nav__hamburger span { background: var(--bg-inverse); }

/* ============================================================
   Generic Page (About, Guest Teaching, etc.)
   ============================================================ */
.page-main { padding-top: var(--sp-80); min-height: 60vh; }
.page-header {
  padding: var(--sp-64) 0 var(--sp-56);
  margin-bottom: var(--sp-64);
}
/* Tighter variant for pages where the header sits directly over prose rather
   than a fully separate section — the default gap was tuned for Contact and
   the Terms pages, which have more visual separation to begin with. Added
   August 17, 2026 for the Testimonial page; tightened further the same day
   after review, the first pass still left too much air before the prose. */
.page-header--tight {
  padding: var(--sp-96) 0 var(--sp-16);
  margin-bottom: var(--sp-16);
}
.page-title {
  font-size: var(--type-h1);
  font-weight: var(--fw-black); letter-spacing: -.035em; line-height: 1.06;
  color: var(--fg); max-width: 22ch; margin: 0;
}
/* Interior page titles wrap at the same 16ch cap the interior hero__h1 uses
   (see above), rather than the wider 22ch default. At 22ch a title the length
   of "Two sentences is plenty." only wraps once the fluid --type-h1 clamp has
   already shrunk close to its floor, which reads as the heading shrinking to
   fit instead of breaking to a second line. Contact, Privacy and the Terms
   pages are short enough that this cap changes nothing for them. Added
   August 17, 2026. */
.page-header--tight .page-title { max-width: 16ch; }
.page-content {
  max-width: 760px;
  padding-bottom: var(--sp-120);
}
.page-content h2 {
  font-size: var(--type-h3); font-weight: var(--fw-black); line-height: 1.25; letter-spacing: -.015em;
  margin-top: 2.2em; margin-bottom: 0.5em;
}
.page-content h3 {
  font-size: var(--type-h4); font-weight: var(--fw-black); line-height: var(--type-h4-lh); letter-spacing: var(--track-tight);
  margin-top: 1.8em; margin-bottom: 0.4em;
}
.page-content p { margin-bottom: 1.4em; }
.page-content ul { list-style: disc; padding-left: 1.5em; margin-bottom: 1.4em; }
.page-content ol { list-style: decimal; padding-left: 1.5em; margin-bottom: 1.4em; }
.page-content li { margin-bottom: 0.5em; }
.page-content img { max-width: 100%; height: auto; border-radius: var(--radius-sm); margin: 2em 0; }
.page-content a { color: var(--cta); text-decoration: underline; text-decoration-thickness: 1px; }
.page-content blockquote {
  border-left: 3px solid var(--accent-deep);
  padding-left: var(--sp-24); margin: 2em 0;
  font-size: var(--type-lead); color: var(--fg-muted); font-style: italic;
}

/* ============================================================
   Blog Archive (home.php / archive.php)
   ============================================================ */
.blog-archive { padding-top: var(--sp-80); }
.blog-archive__header {
  padding: var(--sp-64) 0 var(--sp-56);
}
.blog-archive__title {
  font-size: var(--type-h1);
  font-weight: var(--fw-black); letter-spacing: -.035em; line-height: 1.06;
  color: var(--fg); margin: 0;
}
.blog-featured { display: block; margin-bottom: var(--sp-64); }
.blog-featured__link {
  display: grid; grid-template-columns: 1.15fr 1fr;
  gap: var(--sp-48); align-items: center;
  text-decoration: none;
}
.blog-featured__img-wrap {
  position: relative;
  aspect-ratio: 4 / 3; border-radius: var(--radius-sm);
  overflow: hidden; background: var(--bg-inverse);
}
.blog-featured__img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 480ms var(--ease-standard);
}
.blog-featured__link:hover .blog-featured__img { transform: scale(1.03); }
.blog-featured__title {
  font-size: var(--type-h2);
  font-weight: var(--fw-black); letter-spacing: -.03em; line-height: 1.08;
  color: var(--fg); margin: 0 0 var(--sp-8);
}
.blog-featured__meta {
  font-size: var(--type-micro); font-weight: var(--fw-black); letter-spacing: .06em;
  text-transform: uppercase; color: var(--fg-subtle);
  margin: 0 0 var(--sp-16);
}
.blog-featured__excerpt {
  font-size: var(--type-body); line-height: 1.65; color: var(--fg-muted);
  margin: 0; max-width: 46ch;
}
.blog-featured .link { margin-top: var(--sp-16); }
.blog-grid {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-56) var(--sp-32); padding-bottom: var(--sp-80);
}
/* Portfolio archive only, not blog.php or archive.php which also use
   .blog-grid. Wider cards for a smaller set of case studies rather than
   the blog's higher-volume 3-up. */
.blog-grid--2col { grid-template-columns: repeat(2, 1fr); }
.blog-card { display: block; }
.blog-card__link { display: block; text-decoration: none; }
.blog-card__img-wrap {
  position: relative;
  aspect-ratio: 4 / 3; border-radius: var(--radius-sm);
  overflow: hidden; background: var(--bg-inverse);
}
.blog-card__img {
  position: absolute; inset: 0;
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 480ms var(--ease-standard);
}
.blog-card__link:hover .blog-card__img { transform: scale(1.04); }
.blog-card__body { padding-top: var(--sp-20); }
.blog-card__title {
  font-size: var(--type-h4);
  font-weight: var(--fw-black); letter-spacing: -.02em; line-height: 1.22;
  color: var(--fg); margin: 0 0 var(--sp-8);
}
.blog-card__meta {
  font-size: var(--type-micro); font-weight: var(--fw-black); letter-spacing: .06em;
  text-transform: uppercase; color: var(--fg-muted); opacity: .6;
  margin: 0 0 var(--sp-8);
}
.blog-card__excerpt {
  font-size: var(--type-small); line-height: 1.65; color: var(--fg-muted); margin: 0;
}
.blog-card .link { margin-top: var(--sp-12); }

/* Row 3 of every cycle of 7 grid posts: one full-width callout at the
   same size as the featured block up top (reuses .blog-featured styles
   directly), instead of 3 small cards. */
.blog-grid__callout { grid-column: 1 / -1; margin-bottom: 0; }
/* Every other callout mirrors the layout — image/text markup order is
   swapped in PHP, this just mirrors the column-width fraction to match. */
.blog-featured--reverse .blog-featured__link { grid-template-columns: 1fr 1.15fr; }

/* ============================================================
   Portfolio Archive (portfolio.php)
   ============================================================
   Same alternating pattern as blog.php, reusing its exact components:
   the first project as an opening full-width feature, then the rest in
   a 2-up card grid (.blog-grid--2col, wider cards for a smaller set of
   case studies than the blog's 3-up) with a full-width callout every
   7th grid item, alternating sides. Rebuilt August 16, 2026 from a
   straight repeating list of full-width rows, which read as one dense
   block sixteen deep with no visual rhythm.

   .blog-featured and .blog-card are reused rather than reimplemented,
   so proportions can't drift from the blog's. Only the two things below
   differ, and both differ because a portfolio entry has no date. */

.pf-archive { padding: var(--sp-96) 0 var(--sp-120); }

/* 1. .blog-featured__meta (the date) is omitted from the opening feature
      and the mid-list callouts, so their bottom margin moves onto the
      title, keeping the gap above the excerpt identical to the blog's. */
.pf-archive .blog-featured__title { margin-bottom: var(--sp-16); }

/* 2. Same fix, same reason, for .blog-card__meta inside the grid. */
.pf-archive .blog-card__title { margin-bottom: var(--sp-16); }

/* Opening feature needs its own bottom margin above the grid; a callout
   nested inside .blog-grid already gets margin-bottom:0 from the base
   rule, since grid `gap` handles its spacing instead. */
.pf-archive > .container > .blog-featured { margin-bottom: var(--sp-80); }

@media (max-width: 768px) {
  .pf-archive { padding: var(--sp-64) 0 var(--sp-80); }
  .pf-archive > .container > .blog-featured { margin-bottom: var(--sp-48); }
}

.blog-pagination { padding: var(--sp-24) 0 var(--sp-80); display: flex; justify-content: center; }
.blog-pagination .nav-links { display: flex; gap: var(--sp-8); align-items: center; }
.blog-pagination .page-numbers {
  display: flex; align-items: center; justify-content: center;
  width: 38px; height: 38px; border-radius: 50%;
  font-size: var(--type-small); font-weight: var(--fw-black); color: var(--fg-muted);
  border: 1px solid var(--border); text-decoration: none;
  transition: background var(--dur-fast), color var(--dur-fast);
}
.blog-pagination .page-numbers:hover,
.blog-pagination .page-numbers.current { background: var(--bg-inverse); color: var(--fg-on-dark); border-color: transparent; }
.blog-pagination .page-numbers.dots { border: none; width: auto; }

/* ============================================================
   Blog Single Post (single.php)
   ============================================================ */
.post-title-header { padding-top: var(--sp-80); background: var(--bg-raised); }
.post-title-header .container { padding-top: var(--sp-64); padding-bottom: var(--sp-56); border-bottom: 1px solid var(--border); }
.post-title {
  font-size: min(var(--type-h1), 4rem);
  font-weight: var(--fw-black); letter-spacing: -.032em; line-height: 1.08;
  color: var(--fg); margin: var(--sp-12) 0 var(--sp-20); max-width: 22ch;
}
/* Excerpt under the title on posts with no featured image. Scoped so it
   doesn't touch .lead's other uses (front-page.php sets its own margin
   inline). Sits between the title's own bottom margin and the meta bar. */
.post-title-header .lead { margin: 0 0 var(--sp-24); }
.post-meta-bar {
  font-size: var(--type-micro); font-weight: var(--fw-black); letter-spacing: .05em;
  text-transform: uppercase; color: var(--fg-muted);
}
.post-meta-bar .post-cat { color: var(--accent-deep); }
.post-main { padding: var(--sp-64) 0 var(--sp-120); }
.hero + .post-main { padding-top: var(--sp-80); }
.post-content { max-width: 760px; }
.post-content h2 {
  font-size: var(--type-h3); font-weight: var(--fw-black); line-height: 1.25; letter-spacing: -.015em;
  margin-top: 2.2em; margin-bottom: 0.5em;
}
.post-content h3 {
  font-size: var(--type-h4); font-weight: var(--fw-black); line-height: var(--type-h4-lh); letter-spacing: var(--track-tight);
  margin-top: 1.8em; margin-bottom: 0.4em;
}
.post-content p { margin-bottom: 1.4em; }
.post-content ul { list-style: disc; padding-left: 1.5em; margin-bottom: 1.4em; }
.post-content ol { list-style: decimal; padding-left: 1.5em; margin-bottom: 1.4em; }
.post-content li { margin-bottom: 0.5em; }
.post-content img { max-width: 100%; height: auto; border-radius: var(--radius-sm); margin: 2em 0; }
.post-content a { color: var(--cta); text-decoration: underline; text-decoration-thickness: 1px; }
.post-content blockquote {
  border-left: 3px solid var(--accent-deep);
  padding-left: var(--sp-24); margin: 2em 0;
  font-size: var(--type-lead); color: var(--fg-muted); font-style: italic;
}

/* Per-post CTA, single-blog.php. Sits right after the article, before
   the post-footer / back-to-blog link — separate from .cta-sec (the
   sitewide footer band every page also carries) so a reader hits a
   prompt while the post is still in mind, not just at the very bottom
   of the page once footer nav and socials are already competing for it. */
.post-cta {
  max-width: 760px; margin: var(--sp-56) 0 0; padding: var(--sp-40) var(--sp-32);
  border-radius: var(--radius-lg); background: var(--bg);
  text-align: center;
}
.post-cta__text {
  font-size: var(--type-lead); font-weight: var(--fw-black); letter-spacing: -.01em;
  line-height: 1.3; color: var(--fg);
  max-width: 40ch; margin: 0 auto var(--sp-20);
}

/* ============================================================
   Book Index (page-book.php)
   ============================================================ */
/* Book hero uses the shared .hero / .hero__bg / .hero__body system
   (same height, same fonts, same transparent-to-scrolled nav as the
   homepage and single-blog/single-portfolio heroes). The rules below
   only add the crossfading photo slideshow layer. */
.hero__bg-slideshow { position: absolute; inset: 0; z-index: 0; }
.hero__bg--slide { opacity: 0; transition: opacity 1.4s ease; }
.hero__bg--slide.is-active { opacity: 1; }

.book-part { padding: var(--sp-120) 0; border-bottom: 1px solid var(--border); }
.book-part--alt { background: var(--bg); }
.book-part__header { margin-bottom: var(--sp-48); max-width: 760px; }
.book-part__title {
  font-family: var(--font-sans);
  font-size: var(--type-h2);
  font-weight: var(--fw-black);
  letter-spacing: -0.028em;
  line-height: 1.06;
  margin: var(--sp-8) 0 var(--sp-12);
}
.book-part__blurb { color: var(--fg-muted); font-size: var(--type-body); line-height: 1.75; }

.book-chapter-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-24);
}
.book-chapter-card {
  display: block;
  background: var(--bg-raised);
  border-radius: var(--radius-md);
  overflow: hidden;
  text-decoration: none;
  border: 1px solid var(--border);
  transition: transform var(--dur-std) var(--ease-standard), box-shadow var(--dur-std) var(--ease-standard);
}
.book-chapter-card:hover {
  transform: translateY(-4px);
  box-shadow: var(--shadow-xs);
}
.book-chapter-card__img img {
  width: 100%;
  aspect-ratio: 3/2;
  object-fit: cover;
  display: block;
  transition: transform 0.35s var(--ease-standard);
}
.book-chapter-card:hover .book-chapter-card__img img { transform: scale(1.04); }
.book-chapter-card__body { padding: var(--sp-12) var(--sp-16) var(--sp-16); }
.book-chapter-card__title {
  font-size: var(--type-small);
  font-weight: var(--fw-black);
  color: var(--fg);
  line-height: 1.4;
  letter-spacing: -.01em;
}

/* ============================================================
   Book Single (single-book.php)
   ============================================================ */
.chapter-gallery-sec { padding: var(--sp-80) 0; background: var(--bg); }
.chapter-gallery {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--sp-8);
}
.chapter-gallery__item { display: block; overflow: hidden; cursor: zoom-in; border-radius: var(--radius-sm); }
.chapter-gallery__item img {
  width: 100%;
  aspect-ratio: 4/3;
  object-fit: cover;
  display: block;
  transition: transform 0.35s var(--ease-standard);
}
.chapter-gallery__item:hover img { transform: scale(1.05); }

.chapter-nav { padding: var(--sp-56) 0; }
.chapter-nav__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  gap: var(--sp-24);
  align-items: center;
  border-top: 1px solid var(--border);
  padding-top: var(--sp-40);
}
.chapter-nav__link {
  display: flex; flex-direction: column; gap: var(--sp-8); text-decoration: none;
}
.chapter-nav__link--right { text-align: right; align-items: flex-end; }
.chapter-nav__dir {
  font-size: var(--type-micro); font-weight: var(--fw-black); letter-spacing: .08em;
  text-transform: uppercase; color: var(--fg-muted);
}
.chapter-nav__title {
  font-size: var(--type-small); font-weight: var(--fw-black); color: var(--fg); line-height: 1.35;
}
.chapter-nav__link:hover .chapter-nav__title { color: var(--cta); }
.chapter-nav__back { text-align: center; }

/* ============================================================
   Interior Pages — About, Teaching
   ------------------------------------------------------------
   Shared component set introduced with page-about.php and
   page-teaching.php. Everything here uses the canonical --lki-*
   tokens; the wireframe these came from used neutral greyscale
   placeholders, which are deliberately not carried over.
   ============================================================ */

/* Interior heroes reuse the homepage .hero system at a shorter
   height. The homepage hero has a fold-filling job to do; an
   interior page does not. */
.hero--page { min-height: 72vh; padding-bottom: var(--sp-80); }

/* One-step-up lead, for a single opening paragraph. */
.lead--big {
  font-size: var(--type-lead); line-height: 1.6; font-weight: var(--fw-light);
  color: var(--fg); max-width: 62ch;
}

/* .about-grid mirrored: text left, photo right (homepage is the reverse). */
.about-grid--flip { grid-template-columns: 3fr 2fr; }
/* Opt-in vertical centering — .about-grid's own align-items:start is shared
   with the homepage and Services, so this stays a modifier rather than a
   change to the base class. */
.about-grid--middle { align-items: center; }

/* Pull quote, sits under a heading as a second beat. */
.pull {
  margin-top: var(--sp-32); font-size: var(--type-lead); line-height: 1.4;
  font-weight: var(--fw-black); letter-spacing: -.01em; max-width: 34ch;
}
.sec--dark .pull { color: var(--fg-on-dark); }

/* Platform / tag chips. */
.strip { display: flex; flex-wrap: wrap; gap: var(--sp-8); margin-top: var(--sp-48); }
.strip__item {
  border: 1px solid var(--border); border-radius: var(--radius-pill);
  padding: var(--sp-8) var(--sp-16); font-size: var(--type-micro); font-weight: var(--fw-black);
  letter-spacing: .03em; color: var(--fg-muted); white-space: nowrap;
  background: var(--bg-raised);
}
.sec--dark .strip__item {
  background: transparent; border-color: var(--border-on-dark-strong);
  color: var(--fg-on-dark-muted);
}

/* 3-up photo grid. */
.gallery { display: grid; grid-template-columns: repeat(3,1fr); gap: var(--sp-12); margin-top: var(--sp-48); }
.g-item {
  position: relative; aspect-ratio: 4/3; overflow: hidden;
  border-radius: var(--radius-sm); background: var(--fill-strong);
  transition: transform var(--dur-std) var(--ease-standard);
}
.g-item img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform 400ms var(--ease-standard);
}
.g-item:hover { transform: translateY(-4px); }

/* Staggered masonry: every third tile spans two rows, so the grid reads as
   uneven photos from a real place rather than a uniform stock-photo grid.
   Pure CSS (grid-auto-flow: dense repacks the gaps), no masonry JS library —
   matches the "no dependencies" rule for this theme. */
.gallery--staggered {
  grid-auto-rows: 140px; grid-auto-flow: dense;
  /* Full-bleed: break out of .container's 1240px max-width regardless of how
     deep it's nested, without needing a separate wrapper. Only usage of
     .gallery in the theme, so this is safe to add directly to the modifier. */
  width: 100vw; position: relative; left: 50%; right: 50%;
  margin-left: -50vw; margin-right: -50vw;
}
.gallery--staggered .g-item { aspect-ratio: auto; }
.gallery--staggered .g-item:nth-child(3n+1) { grid-row: span 2; }

.g-item:hover img { transform: scale(1.05); }

/* ============================================================
   Photo-collage hero (About, "How I Got Here")
   Full-bleed, auto-scrolling masonry standing in for a static hero photo.
   Reuses the t-scroll-up keyframe from Testimonials above; alternating
   columns just run it in reverse so neighbouring columns drift apart
   instead of together. Added August 27, 2026.

   Unlike the testimonials masonry, these photos are real links (each one
   goes to its own book chapter), so :hover pauses the scroll — a moving
   target is hard to click — and only the duplicate pass (the one that
   makes the loop seamless) is aria-hidden. The first pass keeps its real
   href and alt text.
   ============================================================ */
.gc-hero {
  /* min-height keeps this a real block even before the JS-driven columns
     paint in; without it a caching hiccup that serves this rule late reads
     as a collapsed, content-height section instead of a fixed hero. */
  position: relative; overflow: hidden; min-height: 860px;
  display: flex; align-items: center; justify-content: center;
  background: var(--bg-inverse);
}
.gc-hero__bg { position: absolute; inset: 0; z-index: 0; overflow: hidden; }
.gc-hero__scrim {
  position: absolute; inset: 0; z-index: 1;
  background: radial-gradient(ellipse at center,
    var(--scrim-hero-dense) 0%, var(--scrim-hero-mid) 55%, var(--scrim-hero-soft) 100%);
  /* Sits visually on top of the photos for text legibility, but must not
     intercept the mouse — without this the scrim blocked hover AND clicks
     on every photo underneath it, silently, since it never throws an error.
     Found August 27, 2026 when hover reportedly "didn't work". */
  pointer-events: none;
}
/* 4 columns at the 'medium_large' (768px) image size — see page-about.php
   for why medium_large rather than 'medium'. 4 columns keeps each tile a
   reasonable display size for a 768px source rather than a much bigger one
   stretching it, or a much smaller one wasting the resolution. */
.gc-masonry { display: grid; grid-template-columns: repeat(4,1fr); gap: var(--sp-8); height: 100%; }
.gc-col { display: flex; flex-direction: column; gap: var(--sp-8); }
.gc-col--1, .gc-col--3 { animation: t-scroll-up 70s linear infinite; }
.gc-col--2, .gc-col--4 { animation: t-scroll-up 70s linear infinite reverse; }
.gc-col:hover { animation-play-state: paused; }
.gc-item { display: block; overflow: hidden; flex-shrink: 0; }
.gc-item img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: transform var(--dur-std) var(--ease-standard), filter var(--dur-std) var(--ease-standard);
}
/* Hover affordance: these are real links, not decoration, so hovering one
   brightens and nudges it forward — same "this is clickable" signal as
   .g-item's hover elsewhere, without adding a border or frame to a
   collage that's deliberately frameless. */
.gc-item:hover img { transform: scale(1.06); filter: brightness(1.35); }
/* Three alternating aspect ratios per column, so the collage reads as
   varied editorial photos rather than a uniform grid. */
.gc-item--1 { aspect-ratio: 3/4; }
.gc-item--2 { aspect-ratio: 2/3; }
.gc-item--3 { aspect-ratio: 4/5; }
.gc-hero__body {
  position: relative; z-index: 2; max-width: 640px; text-align: center;
  padding: var(--sp-64) var(--sp-32);
}
.gc-hero__body .body-copy { margin: var(--sp-24) auto var(--sp-32); max-width: 56ch; }

/* Numbered blocks. .gaps is 2-up, .items is 3-up, same type treatment. */
.gaps  { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-48); margin-top: var(--sp-48); }
.items { display: grid; grid-template-columns: repeat(3,1fr); gap: var(--sp-32); margin-top: var(--sp-48); }

/* Vertically divided columns — like .items but with a rule between each
   entry instead of a card background. Drafted first as a visual mockup
   outside the codebase (page-teaching.php's Formats section) and matched
   here rather than reusing .items/.card, which read as too boxed for this
   content. .divided-cols--4 swaps the column count for a fourth entry.
   Added August 21, 2026. */
.divided-cols {
  display: grid; grid-template-columns: repeat(3,1fr);
  border-top: 1px solid var(--border); margin-top: var(--sp-32);
}
.divided-cols--4 { grid-template-columns: repeat(4,1fr); }
.divided-cols > div { padding: var(--sp-32); border-left: 1px solid var(--border); }
.divided-cols > div:first-child { border-left: none; padding-left: 0; }
.divided-cols > div:last-child { padding-right: 0; }

/* Horizontally divided rows — a number beside a heading and paragraph,
   stacked with a rule between each entry. Pairs with .grid-2--sticky's left
   column (eyebrow + heading pinned while this list scrolls past). Built for
   page-teaching.php's Topics section, same mockup as .divided-cols above.
   Added August 21, 2026. */
.divided-rows { border-top: 1px solid var(--border); }
.divided-rows__item {
  display: grid; grid-template-columns: 56px 1fr; gap: var(--sp-24);
  padding: var(--sp-40) 0; border-bottom: 1px solid var(--border);
}

.num-label {
  display: block; font-size: var(--type-small); font-weight: var(--fw-medium); color: var(--fg-subtle);
}
.divided-cols .num-label { margin-bottom: var(--sp-16); }
/* Omits the top rule for a .divided-cols instance that also drops its
   number labels — see page-teaching.php's Formats section. The vertical
   rules between columns are untouched. */
.divided-cols--flush { border-top: none; }

/* Reused inside .card as a green category kicker above the title (see
   page-teaching.php's Sessions section) rather than a grey number — paired
   with a .accent phrase in the h3 below it, the two greens this site
   already has (--accent-deep here, --accent's italic serif on the h3)
   doing the job a bigger font size alone wasn't. */
.card > .num-label { margin-bottom: var(--sp-8); color: var(--accent-deep); font-weight: var(--fw-black); text-transform: uppercase; letter-spacing: .06em; font-size: var(--type-micro); }

/* Generic bordered card. .pricing-card is deliberately not reused:
   it carries price-specific layout this does not want. */
.card {
  border: 1px solid var(--border); border-radius: var(--radius-md);
  padding: var(--sp-32) var(--sp-24); display: flex; flex-direction: column;
  background: var(--bg-raised);
  transition: transform var(--dur-std) var(--ease-standard), box-shadow var(--dur-std) var(--ease-standard);
}
.card:hover { transform: translateY(-4px); box-shadow: var(--shadow-xs); }
.card__list {
  margin-top: var(--sp-16); display: flex; flex-direction: column; gap: var(--sp-8);
  color: var(--fg-muted);
}
/* Smaller type is a card-specific compromise for fitting more into a fixed
   box. A list sitting in running body copy (unboxed) should read at the
   same size as the paragraphs around it. */
.card .card__list { font-size: var(--type-small); }
.card__list li { display: flex; align-items: flex-start; gap: var(--sp-8); }
.card__list li::before {
  content: ''; width: 6px; height: 6px; border-radius: 50%;
  background: var(--accent-deep); flex-shrink: 0; margin-top: var(--sp-4);
}

/* Inline forward link with a hover nudge. */
.link {
  font-size: var(--type-small); font-weight: var(--fw-black); text-decoration: none;
  display: inline-block; margin-top: var(--sp-24); color: var(--cta);
  transition: transform var(--dur-std) var(--ease-standard);
}
.link:hover { transform: translateX(4px); }
.sec--dark .link { color: var(--cta); }

/* ============================================================
   Responsive
   ============================================================ */
@media (max-width: 1024px) {
  .container, .nav__inner, .hero__body { padding-left: var(--sp-48); padding-right: var(--sp-48); }
  .grid-2, .grid-2-even { grid-template-columns: 1fr; gap: var(--sp-40); }
  /* .grid-2--sticky collapses to one column at this width same as .grid-2,
     but the sticky rule lives on the child and survives the collapse on its
     own. Left on, it pins the icon/eyebrow/title block near the top of the
     screen while the answer text scrolls past underneath it, reading as
     overlapping text. Sticky only makes sense next to a second column. */
  .grid-2--sticky > *:first-child { position: static; top: auto; }
  .divided-cols--4 { grid-template-columns: repeat(2,1fr); }
  .caps   { grid-template-columns: repeat(2,1fr); gap: var(--sp-32); }
  .about-grid { grid-template-columns: 1fr 1.6fr; gap: var(--sp-56); }
  .about-grid--flip { grid-template-columns: 1.6fr 1fr; }
  .faq-grid   { grid-template-columns: 1fr; gap: var(--sp-40); }
  .items      { grid-template-columns: 1fr; gap: var(--sp-32); }
  .blog-grid  { grid-template-columns: repeat(2,1fr); }
  .book-chapter-grid { grid-template-columns: repeat(2, 1fr); }
  .chapter-gallery   { grid-template-columns: repeat(2, 1fr); }
  .nav__links .nav__link { display: none; }
  .nav .nav-pill { display: none; }
  .nav__hamburger { display: flex; }
}
@media (max-width: 768px) {
  .container, .nav__inner, .hero__body { padding-left: var(--sp-32); padding-right: var(--sp-32); }
  .sec { padding: var(--sp-80) 0; }
  /* Reasserted after the rule above: .sec's shorthand padding would otherwise
     win on source order and erase the flush top at this breakpoint. */
  .sec--flush-top { padding-top: var(--sp-40); }
  .grid-3, .caps, .about-grid, .ai-items { grid-template-columns: 1fr; }
  .about-grid--flip, .gaps, .items { grid-template-columns: 1fr; gap: var(--sp-32); }
  .divided-cols, .divided-cols--4 { grid-template-columns: 1fr; border-top: none; }
  .divided-cols > div { border-left: none; border-top: 1px solid var(--border); padding: var(--sp-24) 0; }
  .divided-cols > div:first-child { border-top: none; }
  .divided-rows__item { grid-template-columns: 40px 1fr; gap: var(--sp-16); padding: var(--sp-24) 0; }
  .gallery { grid-template-columns: repeat(2,1fr); }
  .hero--page { min-height: 60vh; }
  .nav__links .nav__link:not(.nav__link--cta) { display: none; }
  .footer__inner { grid-template-columns: 1fr; gap: var(--sp-24); }
  .footer__nav   { justify-content: flex-start; }
  .t-masonry { grid-template-columns: repeat(2,1fr); }
  .t-col--3 { display: none; }
  .gc-masonry { grid-template-columns: repeat(2,1fr); }
  .gc-col--3, .gc-col--4 { display: none; }
  .gc-hero { min-height: 600px; }
  .blog-grid { grid-template-columns: 1fr; gap: var(--sp-40); }
  .blog-featured { margin-bottom: var(--sp-48); }
  .blog-featured__link { grid-template-columns: 1fr; gap: var(--sp-24); }
  .blog-grid__callout { margin-bottom: 0; }
  .book-chapter-grid { grid-template-columns: repeat(2, 1fr); gap: var(--sp-16); }
  .book-hero__title { font-size: var(--type-h1); }
  .chapter-nav__inner { grid-template-columns: 1fr 1fr; }
  .chapter-nav__back { display: none; }
  .page-title, .blog-archive__title, .post-title { font-size: var(--type-h1); }
  .page-header, .blog-archive__header { padding: var(--sp-48) 0 var(--sp-40); margin-bottom: var(--sp-48); }
}
@media (max-width: 480px) {
  .t-masonry { grid-template-columns: 1fr; max-height: 520px; }
  .t-col--2 { display: none; }
  .book-chapter-grid { grid-template-columns: 1fr; }
  .chapter-gallery   { grid-template-columns: 1fr 1fr; }
  .chapter-nav__inner { grid-template-columns: 1fr; }
  .chapter-nav__link--right { align-items: flex-start; }
}


/* ============================================================
   Prose lists
   ------------------------------------------------------------
   The global `ul, ol { list-style: none }` reset near the top of
   this file is right for nav, card and FAQ lists and WRONG for
   prose: without this block a bulleted list inside post or page
   content renders as loose unmarked lines.

   .page-content and .post-content were already covered further up.
   This adds .body-copy, which is the wrapper every content
   template actually shares, and is what portfolio project pages
   (`body-copy pf-intro reveal`) and the book page (`body-copy
   reveal`) use. Those two had no coverage at all.

   See WORKSPACE-file-management.md -> Global Open Issues #6.
   ============================================================ */
.body-copy ul { list-style: disc outside; padding-left: 1.5em; margin-bottom: 1.4em; }
.body-copy ol { list-style: decimal outside; padding-left: 1.5em; margin-bottom: 1.4em; }
.body-copy li { display: list-item; margin-bottom: 0.5em; }
.body-copy ul ul { list-style: circle outside; margin-bottom: 0; }

/* Never inside the component lists, which are lists only semantically.
   These sit outside .body-copy today; the rules are defensive. */
.body-copy .nav__links, .body-copy .footer__nav, .body-copy .faq-list,
.nav__links, .footer__nav, .faq-list { list-style: none; padding-left: 0; }
.nav__links li, .footer__nav li, .faq-list li { display: block; margin-bottom: 0; }

/* ============================================================
   Tables in WordPress-edited content
   ============================================================
   The theme had no table styling at all, so a table pasted into a Page
   rendered as browser default: borderless, no padding, collapsed to its
   content width (215px inside a 760px column). Added August 13, 2026 for
   Schedule A on the Managed Hosting & Care Agreement.

   Scoped to .page-content / .post-content so it only touches content coming
   out of the WordPress editor. The hand-built templates draw their own
   layouts and must not pick these up. */
.page-content table,
.post-content table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--sp-32) 0;
  font-size: var(--type-body);
}
.page-content th, .page-content td,
.post-content th, .post-content td {
  border: 1px solid var(--border);
  padding: var(--sp-12) var(--sp-12);
  text-align: left;
  vertical-align: top;
}
.page-content th,
.post-content th {
  background: var(--bg);
  font-weight: var(--fw-black);
  font-size: var(--type-micro);
  letter-spacing: .04em;
  text-transform: uppercase;
}
/* A wide table scrolls inside itself rather than breaking the page gutters.
   Same class of problem as Global Open Issue 10. */
@media (max-width: 640px) {
  .page-content table,
  .post-content table { display: block; overflow-x: auto; }
}

/* ============================================================
   Generic page: two-column layout
   ============================================================
   page.php renders content 2/3 + sidebar 1/3, but only when the "Page Sidebar"
   widget area has content. With no widgets the .page-layout wrapper is not
   output at all and .page-content keeps its original 760px single column, so
   nothing changes on the Terms and Contact pages until there is a reason to.
   Added August 14, 2026. */
.page-layout {
  display: grid;
  grid-template-columns: 2fr 1fr;
  gap: var(--sp-64);
  align-items: start;
}
/* The 760px cap is what makes the single-column version readable. Inside the
   grid the column is already constrained, so the cap has to come off or the
   content sits in a narrow strip with a gap beside it. */
.page-layout .page-content,
.page-layout .post-content { max-width: none; }

/* single-book.php's chapter list: a small thumbnail beside each title.
   Scoped to .page-sidebar__chapter rather than styling .page-sidebar li /
   a generally, since page.php's own sidebar is a plain WordPress widget
   area with no thumbnails to lay out. */
.page-sidebar__chapter-link { display: flex; align-items: center; gap: var(--sp-8); }
.page-sidebar__thumb {
  width: 40px; height: 40px; object-fit: cover; border-radius: var(--radius-sm);
  flex-shrink: 0;
}
/* Current-chapter marker: plain bold text, not a link, since it's already
   the page you're on. */
.page-sidebar__chapter-link.is-current strong { color: var(--fg); font-weight: var(--fw-black); }

.page-sidebar {
  position: sticky;
  top: 104px;
  padding-bottom: var(--sp-120);
  font-size: var(--type-body);
  color: var(--fg-muted);
}
.page-sidebar__widget { margin-bottom: var(--sp-40); }
.page-sidebar__title {
  font-size: var(--type-micro);
  font-weight: var(--fw-black);
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--fg);
  margin: 0 0 var(--sp-12);
}
.page-sidebar ul { list-style: none; padding-left: 0; }
.page-sidebar li { margin-bottom: var(--sp-8); }
.page-sidebar a { color: var(--cta); text-decoration: underline; text-decoration-thickness: 1px; }

@media (max-width: 900px) {
  .page-layout { grid-template-columns: 1fr; gap: 0; }
  .page-sidebar {
    position: static;
    padding-top: var(--sp-40);
    border-top: 1px solid var(--border);
  }
}

/* ============================================================
   Form controls + Gravity Forms submit button
   ============================================================
   The shared .lki-field-control class renders the same field treatment in
   reference specimens without recreating it. Gravity Forms gets the rules
   through its real field markup on Contact and agreement pages. */
.lki-field-label,
.gform_wrapper .gfield_label {
  display: block;
  margin-bottom: var(--sp-8);
  color: var(--fg);
  font-size: var(--type-small);
  font-weight: var(--fw-black);
}
.lki-field-control,
.gform_wrapper .gfield input[type="text"],
.gform_wrapper .gfield input[type="email"],
.gform_wrapper .gfield input[type="tel"],
.gform_wrapper .gfield input[type="url"],
.gform_wrapper .gfield input[type="number"],
.gform_wrapper .gfield textarea,
.gform_wrapper .gfield select {
  width: 100%;
  padding: var(--sp-12) var(--sp-16);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--bg-raised);
  color: var(--fg);
  font: inherit;
  line-height: 1.5;
  transition: border-color var(--dur-fast) var(--ease-standard), outline-color var(--dur-fast) var(--ease-standard);
}
.lki-field-control:focus-visible,
.gform_wrapper .gfield input:focus-visible,
.gform_wrapper .gfield textarea:focus-visible,
.gform_wrapper .gfield select:focus-visible {
  border-color: var(--accent-deep);
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.lki-field-control[aria-invalid="true"],
.gform_wrapper .gfield_error input,
.gform_wrapper .gfield_error textarea,
.gform_wrapper .gfield_error select {
  border-color: var(--lki-error);
}
.lki-field-control[aria-invalid="true"]:focus-visible,
.gform_wrapper .gfield_error input:focus-visible,
.gform_wrapper .gfield_error textarea:focus-visible,
.gform_wrapper .gfield_error select:focus-visible {
  outline-color: var(--lki-error);
}
.lki-field-message,
.gform_wrapper .gfield_validation_message {
  margin-top: var(--sp-8);
  color: var(--lki-error);
  font-size: var(--type-small);
  line-height: var(--type-small-lh);
}

/* Submit controls match .btn-pill. GF renders either an input[type=submit] or a button
   depending on version and settings, so both are covered. Added August 14, 2026
   for the hosting agreement form, which was showing the browser default. */
.gform_wrapper .gform_footer input[type="submit"],
.gform_wrapper .gform_footer button[type="submit"],
.gform_wrapper input.gform_button,
.gform_wrapper button.gform_button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: auto;
  padding: var(--sp-16) var(--sp-32);
  border-radius: var(--radius-pill);
  background: var(--bg-inverse);
  color: var(--fg-on-dark);
  font-family: var(--font-sans);
  font-size: var(--type-small);
  font-weight: var(--fw-black);
  letter-spacing: .01em;
  border: none;
  cursor: pointer;
  text-decoration: none;
  transition: background var(--dur-fast) var(--ease-standard);
}
.gform_wrapper .gform_footer input[type="submit"]:hover,
.gform_wrapper .gform_footer button[type="submit"]:hover,
.gform_wrapper input.gform_button:hover,
.gform_wrapper button.gform_button:hover {
  background: var(--cta);
  color: var(--fg);
}
.gform_wrapper .gform_footer input[type="submit"]:focus-visible,
.gform_wrapper .gform_footer button[type="submit"]:focus-visible,
.gform_wrapper input.gform_button:focus-visible,
.gform_wrapper button.gform_button:focus-visible {
  outline: 2px solid var(--cta);
  outline-offset: 3px;
}
.gform_wrapper .gform_footer { margin-top: var(--sp-32); }

/* ============================================================
   More posts — horizontal cards, two columns
   ============================================================
   Bottom of single-blog.php. Square image left, text right, two per row.
   Added August 16, 2026. Distinct from .blog-card, which is vertical and
   used by the archive grid. */
.post-more__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--sp-48) var(--sp-56);
  margin-top: var(--sp-48);
}
.post-more__card {
  display: grid;
  grid-template-columns: 38% 1fr;
  gap: var(--sp-24);
  align-items: start;
  text-decoration: none;
  color: inherit;
}
.post-more__img-wrap {
  aspect-ratio: 1 / 1;
  overflow: hidden;
  border-radius: var(--radius-sm);
  background: var(--fill-subtle);
}
.post-more__img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--dur-std) var(--ease-standard);
}
.post-more__card:hover .post-more__img { transform: scale(1.04); }
.post-more__title {
  font-size: var(--type-h4);
  font-weight: var(--fw-black);
  line-height: 1.25;
  letter-spacing: -.015em;
  color: var(--fg);
  margin: 0 0 var(--sp-8);
  transition: color var(--dur-fast) var(--ease-standard);
}
.post-more__card:hover .post-more__title { color: var(--cta); }
.post-more__excerpt {
  font-size: var(--type-body);
  line-height: 1.55;
  color: var(--fg-muted);
  margin: 0 0 var(--sp-12);
}
.post-more__meta {
  display: flex;
  align-items: center;
  gap: var(--sp-8);
  font-size: var(--type-small);
  color: var(--fg-muted);
  margin: 0;
}
.post-more__dot { opacity: .5; }

@media (max-width: 900px) {
  .post-more__grid { grid-template-columns: 1fr; gap: var(--sp-40); }
}
/* Below this the 38% image column is too narrow to read as a square, so the
   card stacks and the image goes wide. */
@media (max-width: 560px) {
  .post-more__card { grid-template-columns: 1fr; gap: var(--sp-16); }
  .post-more__img-wrap { aspect-ratio: 16 / 9; }
}
