/* Finish: paper grain + sitewide typographic polish. Static CSS only: no JS, no animation. */

/* ---------- Paper grain ----------
   One 180px tiled SVG (feTurbulence rasterized once per tile, then cached), layered over each
   section's own background colour. No fixed overlay, no filter on content, nothing repaints on
   scroll. Measured on paper: mean shift about 2 of 255 levels; muted body copy keeps AA
   (4.64:1 flat, 4.56:1 with grain). Dark grain is fainter still. */

:root {
  --grain-ink: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g' x='0' y='0'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 .13 0 0 0 0 .15 0 0 0 0 .13 .2 0 0 0 -.1'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E");
  --grain-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='g' x='0' y='0'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 .98 0 0 0 0 .94 .15 0 0 0 -.08'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23g)'/%3E%3C/svg%3E");
}

/* Light surfaces: paper, cream, cream-deep. */
body,
.proof-strip,
.guidance,
.local-story,
.team,
.about,
.proof-wall,
.faq {
  background-image: var(--grain-ink);
  background-size: 180px 180px;
}

/* Dark surfaces get a fainter, warm-light grain. Film, header and footer are left alone. */
.hero,
.estimate,
.reach,
.contact {
  background-image: var(--grain-light);
  background-size: 180px 180px;
}

/* ---------- Typography ---------- */

h1,
h2,
h3,
h4 {
  text-wrap: balance;
}

p,
li,
dd,
blockquote,
figcaption,
summary {
  text-wrap: pretty;
}

/* Stacked layouts (860px and down): the heading measures are set in ch for the desktop grid and
   leave only 221-243px of a ~350px column. Let them use the column, and stack .h-seg phrases
   so the breaks follow the sentence, which text-wrap: balance cannot know. On desktop the
   segments stay inline and the ch measure already lands well. (Not <br>: SplitText treats
   a hidden <br> as a real line break.) */

@media (max-width: 860px) {
  .local-copy h2,
  .faq-intro h2,
  .story-head h2,
  .team-head h2 {
    max-width: none;
  }

  .h-seg {
    display: block;
  }
}

/* Quotes open with a hanging mark (Safari today; ignored elsewhere). */
blockquote {
  hanging-punctuation: first;
}

/* Every figure that is read as a number: aligned, lining, steady while it counts up. */
.proof-stat strong,
.estimate-result__figure,
.estimate-control__value,
.estimate-ledger dd,
.estimate-panel__meta,
.team-numeral,
.team-stage__num,
.reach-figure__num,
.pw-figure,
.pw-score,
.fact-list dd,
.faq-list summary span,
.section-index,
.guidance-row__num,
.contact-grid a[href^="tel:"] strong,
a.text-link[href^="tel:"] {
  font-variant-numeric: tabular-nums lining-nums;
}

/* "NMLS" lives inside tiny uppercase DM Mono labels. Caps set this small need air:
   open the tracking so the acronym reads as letters, not a block. */
.hero-credentials span {
  letter-spacing: .14em;
  font-variant-numeric: tabular-nums;
}

/* Raised to 11px, these need less tracking than the 8-9px originals did. */
.brand-copy small,
.fact-list dt,
.footer-person span,
.footer-bottom span {
  letter-spacing: .08em;
  font-variant-numeric: tabular-nums;
}

.brand-copy small {
  text-wrap: balance;
}

::selection {
  color: var(--cream);
  background: rgba(196, 93, 61, .92);
  text-shadow: none;
}
