/* ==========================================================================
   Daniel L Carpenter Law LLC
   Editorial layout for a text-heavy practice site. No CSS framework: the
   page shapes here are a prose column, a card grid, and a comparison table,
   and hand-rolling them removes a render-blocking CDN dependency.
   ========================================================================== */

/* --------------------------------------------------------------- fonts --
   Served from this origin rather than fonts.googleapis.com. The Google
   stylesheet was render-blocking on a third party: a DNS lookup, a TLS
   handshake, and a CSS fetch had to finish before the browser learned which
   font files it needed — and the LCP element on most of these pages is a
   heading, so that delay was the largest-contentful-paint number.

   The two latin faces are preloaded in base.html. Every other subset is
   listed here for its unicode-range and is fetched only if a page actually
   contains those characters, so carrying them costs a reader nothing.

   Regenerate with: python scripts/fetch_fonts.py
   ------------------------------------------------------------------------ */

/* Inter, latin */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-latin.260c81a4759b.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Inter, latin-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-latin-ext.1ad231aac0a8.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Inter, vietnamese */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-vietnamese.9df17551da76.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* Inter, greek */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-greek.8c7f6aea5e86.woff2") format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* Inter, greek-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-greek-ext.318d4ba568ac.woff2") format('woff2');
  unicode-range: U+1F00-1FFF;
}
/* Inter, cyrillic */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-cyrillic.de93fdc85e3d.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* Inter, cyrillic-ext */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/inter-cyrillic-ext.251d36f2b5a6.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}
/* Source Serif 4, latin */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("../fonts/source-serif-4-latin.e9192c2fe0a3.woff2") format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
/* Source Serif 4, latin-ext */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("../fonts/source-serif-4-latin-ext.33ba75072ebc.woff2") format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
/* Source Serif 4, vietnamese */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("../fonts/source-serif-4-vietnamese.450ee651d349.woff2") format('woff2');
  unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
}
/* Source Serif 4, greek */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("../fonts/source-serif-4-greek.d5197bb3c0b5.woff2") format('woff2');
  unicode-range: U+0370-0377, U+037A-037F, U+0384-038A, U+038C, U+038E-03A1, U+03A3-03FF;
}
/* Source Serif 4, cyrillic */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("../fonts/source-serif-4-cyrillic.98b50dcfe9a5.woff2") format('woff2');
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
/* Source Serif 4, cyrillic-ext */
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url("../fonts/source-serif-4-cyrillic-ext.62017e5fbc67.woff2") format('woff2');
  unicode-range: U+0460-052F, U+1C80-1C8A, U+20B4, U+2DE0-2DFF, U+A640-A69F, U+FE2E-FE2F;
}

/* ------------------------------------------------------------- colour --
   The palette is NOT defined here. It arrives as a :root block inlined by
   base.html from the Colours row in the database, so the attorney can change
   it in admin without a deploy — see core/theme.py for the token reference and
   the contrast rules that gate a save.

   That means this file contains no palette colour. Every value below is
   var(--token), and adding a hex here would create a colour that the admin
   cannot reach and the contrast checker cannot see. The only literals are #fff
   and #000, which are fixed points rather than choices: white is what sits on
   the filled maroon and charcoal bands, and black is for print. The tokens
   available are:

     --maroon-deep --maroon --maroon-mid --maroon-hairline
     --on-maroon-muted --on-maroon-note --charcoal --on-charcoal-muted
     --paper --zone --card --ink --ink-body --ink-muted --ink-secondary
     --gray --rule
     --focus --error --error-text --error-bg --disabled-fg --disabled-bg

   The governing rule of the system: beige owns the light layer, gray owns the
   dark layer. Page and section backgrounds run warm (--paper, --zone, --card);
   the dark band, outlines and UI rules stay cool (--charcoal, --gray). Warm and
   cool neutrals must never sit adjacent at similar lightness, which is what
   makes a mixed-temperature palette read as muddy rather than deliberate.
   ---------------------------------------------------------------------- */

:root {
  --serif: "Source Serif 4", Georgia, "Times New Roman", serif;
  --sans:  "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;

  --measure: 40rem;
  --wide:    68rem;

  /* Height of the sticky masthead. Anything that scrolls to a position has to
     know it, or it lands underneath the header. */
  --masthead-h: 4.6rem;

  --step--1: clamp(0.86rem, 0.84rem + 0.1vw, 0.92rem);
  --step-0:  clamp(1.02rem, 0.99rem + 0.15vw, 1.12rem);
  --step-1:  clamp(1.2rem, 1.13rem + 0.35vw, 1.4rem);
  --step-2:  clamp(1.45rem, 1.32rem + 0.62vw, 1.85rem);
  --step-3:  clamp(1.8rem, 1.55rem + 1.15vw, 2.6rem);
  --step-4:  clamp(2.15rem, 1.7rem + 2vw, 3.4rem);
}

*, *::before, *::after { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  * { animation-duration: 0.01ms !important; transition-duration: 0.01ms !important; }
}

body {
  margin: 0;
  font-family: var(--sans);
  font-size: var(--step-0);
  line-height: 1.65;
  color: var(--ink-body);
  background: var(--paper);
  -webkit-font-smoothing: antialiased;
}

/* Weight 400, not 600. The serif is carrying the character here, and at
   display sizes a 600 Source Serif reads as emphasis rather than as a voice.
   Interface labels stay at 500-600, but they are set in the sans. */
h1, h2, h3, h4 {
  font-family: var(--serif);
  color: var(--ink);
  line-height: 1.18;
  letter-spacing: -0.012em;
  font-weight: 400;
  margin: 0 0 0.6em;
  text-wrap: balance;
}
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }

p { margin: 0 0 1.15em; }
p:last-child { margin-bottom: 0; }

a { color: var(--maroon); text-underline-offset: 0.18em; }
a:hover { color: var(--maroon-deep); }

:focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 3px;
  border-radius: 2px;
}

[disabled], [aria-disabled="true"] {
  color: var(--disabled-fg);
  background: var(--disabled-bg);
  cursor: not-allowed;
}

img { max-width: 100%; height: auto; display: block; }

/* A <picture> is only there to offer the browser a WebP before the fallback,
   and it is an inline box by default — which would make it, not the <img>,
   the flex item in the masthead and the sized child in the portrait grid.
   display: contents takes it back out of the layout it was never meant to
   join, so every rule written against `img` keeps applying. */
picture { display: contents; }

hr { border: 0; border-top: 1px solid var(--rule); margin: 2.5rem 0; }

/* The lightest neutral a reader must still be able to read against. Anything
   quieter than this fails AA on the beige sections. */
.muted, .small.muted { color: var(--ink-muted); }

/* Jumping to an in-page anchor — a section link, the skip link, a table of
   contents — must not park the target under the sticky masthead. */
[id] { scroll-margin-top: calc(var(--masthead-h) + 1rem); }

/* --------------------------------------------------------------- layout -- */

.wrap { width: min(100% - 2.5rem, var(--wide)); margin-inline: auto; }
.wrap--narrow { width: min(100% - 2.5rem, var(--measure)); margin-inline: auto; }

.prose { max-width: var(--measure); }
.prose > * + h2 { margin-top: 2.2em; }
.prose > * + h3 { margin-top: 1.8em; }

/* Three light values, kept distinct: the page is --paper, an alternating band
   is --zone, and a card is --card. If they drift together the page flattens,
   and --zone is the only place warm chroma should be noticeable.

   There is deliberately no cool light surface. A cool section alternating with
   a warm one is the warm/cool adjacency at similar lightness that the palette
   rules out — the interruption is the charcoal band's job, not a neutral's. */
.section { padding: clamp(2.75rem, 6vw, 4.75rem) 0; }
.section + .section { border-top: 1px solid var(--rule); }
.section--zone { background: var(--zone); border-top: 1px solid var(--rule); }

/* The one cool dark surface. Statistics strips, intake forms, and any section
   that has to interrupt the warm flow. A filled maroon button sitting on it is
   the brightest thing on the page, which is why the closing call to action and
   the contact form both live here. Maroon *text* on charcoal is 1.03:1 and is
   never correct. */
.section--dark {
  background: var(--charcoal);
  color: var(--on-charcoal-muted);
  border-top: 0;
}
.section--dark h2, .section--dark h3 { color: #fff; }
.section--dark a { color: #fff; }
.section--dark a:hover { text-decoration-thickness: 2px; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--maroon);
  color: #fff;
  padding: 0.75rem 1.25rem;
  z-index: 200;
}
.skip-link:focus { left: 0; }

/* ---------------------------------------------------------------- header -- */

/* Filled maroon, which along with the footer and the primary buttons is the
   whole budget for it. Solid rather than the translucent-and-blurred white it
   used to be: the blur existed to keep a white bar legible over scrolling
   content, and a saturated band does not have that problem. */
.masthead {
  position: sticky;
  top: 0;
  z-index: 100;
  background: var(--maroon);
  border-bottom: 1px solid var(--maroon-hairline);
}

.masthead__inner {
  display: flex;
  align-items: center;
  gap: 1.5rem;
  min-height: 4.5rem;
  padding-block: 0.6rem;
}

.brand {
  display: flex;
  align-items: center;
  gap: 0.7rem;
  text-decoration: none;
  color: #fff;
  flex-shrink: 0;
}
.brand__mark { width: 2.4rem; height: 2.4rem; flex-shrink: 0; }
/* A wordmark, not a heading — it stays at 600 so it holds its own at 1.12rem
   against the maroon behind it. */
.brand__name {
  font-family: var(--serif);
  font-size: 1.12rem;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.01em;
  color: #fff;
}
.brand__rule {
  display: block;
  font-family: var(--sans);
  font-size: 0.68rem;
  font-weight: 500;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--on-maroon-muted);
  margin-top: 0.15rem;
}

.nav { margin-left: auto; }
.nav__list {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav__link {
  display: block;
  padding: 0.55rem 0.75rem;
  font-size: 0.94rem;
  font-weight: 500;
  color: var(--on-maroon-muted);
  text-decoration: none;
  border-radius: 3px;
}
.nav__link:hover,
.nav__link[aria-current="page"] { color: #fff; background: var(--maroon-deep); }
.nav__link[aria-current="page"] { box-shadow: inset 0 -2px 0 #fff; }

.nav__cta {
  /* An inline box ignores vertical margin outright and lets vertical padding
     bleed outside its line box without reserving the space — so an inline
     version of this button paints over whatever sits above it. That is exactly
     what it did to Contact in the open mobile menu. .nav__link is display:
     block for the same reason. */
  display: inline-block;
  /* Explicit, because inline-block starts honouring the 1.65 body line-height
     that the inline version ignored. Without this the pill grows ~8px and
     stops matching the nav links beside it. */
  line-height: 1.15;
  margin-left: 0.6rem;
  padding: 0.6rem 1.1rem;
  /* Outlined, not filled. A filled maroon button on a maroon bar is invisible,
     and a second fill in a different colour would be the third accent hue the
     palette does without. */
  background: transparent;
  border: 2px solid var(--on-maroon-note);
  color: #fff !important;
  border-radius: 3px;
  font-weight: 600;
  font-size: 0.92rem;
  text-decoration: none;
  white-space: nowrap;
}
.nav__cta:hover { background: #fff; border-color: #fff; color: var(--maroon) !important; }

.nav-toggle {
  display: none;
  margin-left: auto;
  background: none;
  border: 1px solid var(--on-maroon-note);
  border-radius: 3px;
  padding: 0.55rem 0.8rem;
  font: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  color: #fff;
  cursor: pointer;
}

@media (max-width: 62rem) {
  .nav-toggle { display: block; flex-shrink: 0; margin-left: 0; }
  /* Open is a state worth seeing, not just announcing to a screen reader. */
  .nav-toggle[aria-expanded="true"] {
    background: var(--maroon-deep);
    border-color: var(--maroon-deep);
    color: #fff;
  }

  /* The brand and the Menu button share one row.
     The brand used to be flex-shrink: 0, so on a phone it refused to give way
     and shoved the button onto a second row — the header rendered as two
     stacked lines. It now shrinks, and the wordmark scales with the viewport
     rather than overflowing it. */
  /* min-height stays at its 4.5rem default so the header matches
     --masthead-h, which scroll-margin and the panel's max-height depend on. */
  .masthead__inner { flex-wrap: wrap; gap: 0.9rem; }
  .brand { flex: 1 1 auto; min-width: 0; }
  .brand__mark { width: 2.1rem; height: 2.1rem; }
  .brand__name { font-size: clamp(0.95rem, 3.4vw, 1.12rem); }

  /* flex: 0 0 100% puts the open panel on its own row, below both. */
  .nav {
    display: none;
    order: 3;
    flex: 0 0 100%;
    margin-left: 0;
    border-top: 1px solid var(--maroon-hairline);
    padding-block: 0.75rem;
    /* A long menu on a short phone must scroll inside the header rather than
       run off the bottom of a sticky element. */
    max-height: calc(100dvh - var(--masthead-h) - 1.5rem);
    overflow-y: auto;
  }
  .nav[data-open="true"] { display: block; }
  .nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  .nav__link { padding: 0.8rem 0.5rem; border-bottom: 1px solid var(--maroon-hairline); }
  /* Full width in the panel, so the 0.9rem above it is real space rather than
     a margin the browser discards, and so text-align has something to centre. */
  .nav__cta {
    display: block;
    margin: 0.9rem 0 0;
    text-align: center;
    padding-block: 0.8rem;
    /* Roomier than the desktop pill, to clear the 44px touch target. */
    line-height: 1.5;
  }
}

/* Small phones. Below this the tagline costs more width than it earns, and the
   page gutters are worth reclaiming. */
@media (max-width: 26rem) {
  .brand__rule { display: none; }
  .wrap { width: min(100% - 2rem, var(--wide)); }
  .wrap--narrow { width: min(100% - 2rem, var(--measure)); }
  .btn-row .btn { flex: 1 1 100%; text-align: center; }
}

/* ------------------------------------------------------------------ hero -- */

/* Light, not a filled band. The masthead directly above it is already
   saturated maroon, and two saturated bands stacked is the thing the palette
   most explicitly rules out. The maroon here is an eyebrow and a button — a
   fraction of the colour budget for the same emphasis. */
.hero {
  background: var(--paper);
  color: var(--ink-body);
  padding: clamp(3.5rem, 9vw, 6.5rem) 0 clamp(3rem, 7vw, 5rem);
  border-bottom: 1px solid var(--rule);
  position: relative;
  overflow: hidden;
}
.hero h1 { color: var(--ink); max-width: 22ch; }
.hero--page h1 { max-width: 26ch; }
.hero__lead {
  font-size: var(--step-1);
  line-height: 1.5;
  max-width: 48ch;
  color: var(--ink-body);
  margin-bottom: 1.75rem;
}
.hero__eyebrow {
  font-size: 0.76rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--maroon-mid);
  margin-bottom: 1rem;
}
.hero__meta {
  margin-top: 2rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--rule);
  font-size: var(--step--1);
  color: var(--ink-muted);
  max-width: 60ch;
}

/* --------------------------------------------------------------- buttons -- */

.btn {
  display: inline-block;
  padding: 0.8rem 1.5rem;
  font-family: var(--sans);
  font-size: 0.97rem;
  font-weight: 600;
  line-height: 1.3;
  border-radius: 3px;
  border: 2px solid transparent;
  text-decoration: none;
  cursor: pointer;
  transition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
/* Exactly one filled maroon button per screen region. The secondary action is
   a cool gray outline with charcoal text — two maroon buttons side by side
   destroys the hierarchy and measurably reduces clicks on the intended one.
   There is no third button style, and adding one would mean deciding what it
   outranks. */
.btn--primary { background: var(--maroon); border-color: var(--maroon); color: #fff; }
.btn--primary:hover {
  background: var(--maroon-deep);
  border-color: var(--maroon-deep);
  color: #fff;
}
.btn--secondary {
  background: transparent;
  border-color: var(--gray);
  color: var(--ink-secondary);
}
.btn--secondary:hover { border-color: var(--ink-secondary); color: var(--ink-secondary); }

/* On the charcoal band the gray outline has nothing to separate itself from,
   so the secondary button borrows the band's own light text instead. The
   primary stays filled maroon: on charcoal it is the brightest element on the
   page, which is the whole reason the intake form sits there. */
.section--dark .btn--secondary {
  border-color: var(--on-charcoal-muted);
  color: #fff;
}
.section--dark .btn--secondary:hover { border-color: #fff; color: #fff; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.85rem;
  align-items: center;
}

/* ----------------------------------------------------------------- cards -- */

/* min() inside minmax() is load-bearing on small phones: a bare minmax(21rem, …)
   keeps a 21rem track even when the viewport is narrower than that, and the
   whole page then scrolls sideways. */
.grid {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: repeat(auto-fit, minmax(min(17rem, 100%), 1fr));
}
.grid--two { grid-template-columns: repeat(auto-fit, minmax(min(21rem, 100%), 1fr)); }

/* A white tile with one maroon mark on it — a 3px top edge rather than a
   filled block. Same visual weight at a fraction of the colour budget, which
   is what keeps a grid of twelve of these legible. */
.card {
  display: flex;
  flex-direction: column;
  background: var(--card);
  border: 1px solid var(--rule);
  border-top: 3px solid var(--maroon-mid);
  padding: 1.6rem 1.5rem;
  text-decoration: none;
  color: inherit;
}
a.card:hover { border-color: var(--gray); border-top-color: var(--maroon); }
.card h3 { font-size: var(--step-1); margin-bottom: 0.5rem; }
.card p { font-size: 0.97rem; color: var(--ink-muted); }
.card__more {
  margin-top: auto;
  padding-top: 1rem;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--maroon);
}
a.card:hover .card__more { color: var(--maroon-deep); }

/* Compact list of category links used on hub pages. */
.stack { list-style: none; margin: 0; padding: 0; }
.stack > li { border-bottom: 1px solid var(--rule); }
.stack > li:first-child { border-top: 1px solid var(--rule); }
.stack a {
  display: block;
  padding: 1.05rem 0.25rem;
  text-decoration: none;
  color: inherit;
}
.stack a:hover { background: var(--zone); }
.stack__title {
  font-family: var(--serif);
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--maroon);
  display: block;
}
.stack__blurb { font-size: 0.94rem; color: var(--ink-muted); display: block; margin-top: 0.2rem; }

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

.lede {
  font-size: var(--step-1);
  line-height: 1.55;
  color: var(--ink);
  max-width: 46ch;
}

.blocks { margin: 0; }
.blocks > div + div { margin-top: 1.5rem; }
.blocks dt, .block__title {
  font-family: var(--serif);
  font-weight: 600;
  color: var(--ink);
  font-size: 1.08rem;
}
.blocks dd { margin: 0.3rem 0 0; }

.bullets { padding-left: 1.15rem; margin: 0 0 1.15em; }
.bullets li { margin-bottom: 0.55rem; }
.bullets li::marker { color: var(--maroon-mid); }

.callout {
  border-left: 3px solid var(--maroon);
  background: var(--card);
  border-block: 1px solid var(--rule);
  border-right: 1px solid var(--rule);
  padding: 1.15rem 1.35rem;
  margin: 1.75rem 0;
  max-width: var(--measure);
}
.callout__title {
  font-family: var(--serif);
  font-weight: 600;
  color: var(--ink);
  display: block;
  margin-bottom: 0.25rem;
}
.callout p { font-size: 0.98rem; margin: 0; }

.cite {
  font-size: var(--step--1);
  color: var(--ink-muted);
  font-style: italic;
  border-top: 1px solid var(--rule);
  padding-top: 0.7rem;
  margin-top: 1.5rem;
  max-width: var(--measure);
}

.inline-links {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 1.25rem;
  margin-top: 1.4rem;
  padding: 0;
  list-style: none;
  font-size: 0.95rem;
  font-weight: 600;
}
.inline-links a { text-decoration: none; }
.inline-links a::after { content: " \2192"; color: var(--maroon-mid); }
.inline-links a:hover { text-decoration: underline; }

/* -------------------------------------------------- portrait and copy -- */

.split {
  display: grid;
  gap: clamp(1.75rem, 5vw, 3.5rem);
  grid-template-columns: minmax(0, 19rem) minmax(0, 1fr);
  align-items: start;
}
@media (max-width: 54rem) {
  .split { grid-template-columns: 1fr; }
  .portrait { max-width: 19rem; }
}

/* A white mat around the photograph, and a maroon edge under it rather than a
   frame around it — the same white-tile-on-beige device as the cards above it.
   The specification's warm tint would have gone here, but the section behind
   this is the beige band and the two are close enough in lightness that the mat
   disappeared into it. See the note in core/theme.py. */
.portrait figure { margin: 0; background: var(--card); padding: 0.7rem; }
.portrait img {
  width: 100%;
  border-bottom: 3px solid var(--maroon);
}
.portrait figcaption {
  margin-top: 0.9rem;
  font-size: var(--step--1);
  line-height: 1.5;
  color: var(--ink-muted);
}
.portrait figcaption b {
  display: block;
  font-family: var(--serif);
  font-size: 1.02rem;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 0.15rem;
}

/* ----------------------------------------------------------------- table -- */

.table-scroll {
  overflow-x: auto;
  margin: 1.75rem 0;
  border: 1px solid var(--rule);
  -webkit-overflow-scrolling: touch;
}
table.data {
  border-collapse: collapse;
  width: 100%;
  min-width: 46rem;
  font-size: 0.92rem;
  background: var(--card);
}
table.data th, table.data td {
  text-align: left;
  vertical-align: top;
  padding: 0.8rem 0.9rem;
  border-bottom: 1px solid var(--rule);
}
table.data thead th {
  background: var(--charcoal);
  color: #fff;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.82rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-bottom: 0;
  position: sticky;
  top: 0;
}
table.data tbody tr:nth-child(even) { background: var(--paper); }
table.data tbody th, table.data td:first-child { font-weight: 600; color: var(--ink); }
.table-note { font-size: var(--step--1); color: var(--ink-muted); max-width: var(--measure); }

/* Staff preview of an Insights article. Requires an admin session, so it can
   never appear to a visitor — but it is loud anyway, because the whole point
   is that a preview must not be mistaken for the published page. */
.preview-bar {
  background: var(--maroon-mid);
  color: #fff;
  padding: 0.7rem 0;
  font-size: 0.9rem;
}
.preview-bar .wrap {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.25rem;
  align-items: baseline;
  justify-content: space-between;
}
.preview-bar a { color: #fff; text-decoration: underline; font-weight: 600; }

/* ------------------------------------------------------------------ form -- */

.field { margin-bottom: 1.4rem; }
.field > label,
.field legend {
  display: block;
  font-weight: 600;
  font-size: 0.94rem;
  color: var(--ink);
  margin-bottom: 0.35rem;
  padding: 0;
}
.field__help { font-size: 0.86rem; color: var(--ink-muted); margin-top: 0.3rem; }
.field__error { font-size: 0.9rem; color: var(--error-text); margin-top: 0.35rem; font-weight: 500; }

.form-control, .form-select {
  width: 100%;
  padding: 0.7rem 0.85rem;
  font: inherit;
  font-size: 1rem;
  color: var(--ink);
  background: var(--card);
  border: 1px solid var(--gray);
  border-radius: 3px;
}
.form-control:focus, .form-select:focus { border-color: var(--maroon); }
textarea.form-control { resize: vertical; min-height: 8rem; }

.field fieldset { border: 0; margin: 0; padding: 0; }
.radio-row { display: flex; gap: 1.5rem; flex-wrap: wrap; }
.radio-row label { display: flex; align-items: center; gap: 0.45rem; font-weight: 400; }

.form-notice {
  border: 1px solid var(--rule);
  background: var(--zone);
  padding: 1.25rem 1.4rem;
  margin-bottom: 2rem;
  font-size: 0.94rem;
}
.form-notice strong { color: var(--ink); }

/* Turnstile renders a fixed-size iframe. Give it room, and let it shrink on a
   narrow screen rather than pushing the form sideways. */
.field--challenge { margin-bottom: 1.6rem; }
.field--challenge .field__help { margin: 0 0 0.5rem; }
.field--challenge .cf-turnstile { max-width: 100%; overflow: hidden; }

.errorlist {
  list-style: none;
  margin: 0 0 1.5rem;
  padding: 1rem 1.25rem;
  border-left: 3px solid var(--error);
  background: var(--error-bg);
  color: var(--error-text);
  font-size: 0.94rem;
}

/* ---------------------------------------------------------------- footer -- */

/* Deep maroon, the darkest value in the system. Along with the masthead and
   the primary buttons this is the last of the filled-maroon budget. */
.site-footer {
  background: var(--maroon-deep);
  color: var(--on-maroon-muted);
  padding: clamp(2.5rem, 5vw, 3.75rem) 0 2rem;
  font-size: 0.94rem;
  margin-top: auto;
}
.site-footer h2 {
  font-family: var(--sans);
  font-size: 0.74rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--on-maroon-note);
  margin-bottom: 0.9rem;
}
.site-footer a { color: #fff; text-decoration: none; }
.site-footer a:hover { text-decoration: underline; }
.footer-grid {
  display: grid;
  gap: 2rem;
  grid-template-columns: repeat(auto-fit, minmax(13rem, 1fr));
}
.footer-links { list-style: none; margin: 0; padding: 0; }
.footer-links li { margin-bottom: 0.45rem; }
/* An email address is one unbroken word and the narrowest column here is
   13rem. Let it break rather than push the page sideways. */
.site-footer a[href^="mailto:"] { overflow-wrap: anywhere; }

@media (max-width: 62rem) {
  /* Thumb-sized targets. These are 20px tall on a phone otherwise. */
  .footer-links li { margin-bottom: 0; }
  .footer-links a { display: inline-block; padding-block: 0.45rem; }
}

/* The attorney advertising notice and the Rule 7.2(d) attribution. Quiet, but
   still 6:1 against the band behind it — a disclaimer nobody can read is not a
   disclaimer, and this is the text most likely to be scrutinised. */
.footer-legal {
  margin-top: 2.5rem;
  padding-top: 1.5rem;
  border-top: 1px solid var(--maroon-hairline);
  font-size: 0.84rem;
  line-height: 1.6;
  color: var(--on-maroon-note);
}
.footer-legal p { margin-bottom: 0.85rem; max-width: 78ch; }
.footer-legal strong { color: #fff; font-weight: 600; }

/* --------------------------------------------------------------- article -- */

.article-meta {
  font-size: 0.88rem;
  color: var(--ink-muted);
  letter-spacing: 0.03em;
  text-transform: uppercase;
  margin-bottom: 0.75rem;
}
.article-body { max-width: var(--measure); }
.article-body h2 { font-size: var(--step-2); margin-top: 2em; }
.article-body h3 { font-size: var(--step-1); margin-top: 1.7em; }
.article-body ul, .article-body ol { padding-left: 1.15rem; }
.article-body li { margin-bottom: 0.5rem; }
.article-body blockquote {
  margin: 1.75rem 0;
  padding-left: 1.25rem;
  border-left: 3px solid var(--maroon-mid);
  font-style: italic;
  color: var(--ink);
}
.article-body img { margin: 1.75rem 0; }

.post-list { list-style: none; margin: 0; padding: 0; }
.post-list > li { padding: 1.75rem 0; border-bottom: 1px solid var(--rule); }
.post-list > li:first-child { border-top: 1px solid var(--rule); }
.post-list h2 { font-size: var(--step-2); margin-bottom: 0.35rem; }
.post-list h2 a { text-decoration: none; }

.pagination {
  display: flex;
  gap: 1.25rem;
  align-items: center;
  margin-top: 2.5rem;
  font-size: 0.94rem;
}

.tag-row { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1.5rem; }
.tag {
  font-size: 0.8rem;
  padding: 0.25rem 0.65rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  color: var(--ink-muted);
  text-decoration: none;
}
.tag:hover { border-color: var(--gray); color: var(--maroon); }

/* ------------------------------------------------------------ utilities -- */

.eyebrow {
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--maroon-mid);
  margin-bottom: 0.85rem;
}
.muted { color: var(--ink-muted); }
.small { font-size: var(--step--1); }
.mt-0 { margin-top: 0; }
.mb-0 { margin-bottom: 0; }
.center { text-align: center; }
.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* dvh tracks the mobile address bar as it collapses; vh does not, and leaves a
   gap under the footer. The vh line is the fallback for anything older. */
.page-shell { display: flex; flex-direction: column; min-height: 100vh; min-height: 100dvh; }

@media print {
  .masthead, .site-footer nav, .btn, .nav-toggle { display: none !important; }
  body { color: #000; font-size: 11pt; }
  .hero { background: none; color: #000; padding: 0 0 1rem; }
  .hero h1, .hero__lead { color: #000; }
}
