/*
 * sonoran.co — site stylesheet
 *
 * Originally ported from a v3 field-notebook spec; tokens, type, and layout
 * have evolved since. This file is now the canonical source for the live
 * site, paired with schedule.css for the booking page. A visible component
 * reference lives at design/design-system.html and the decisions doc at
 * design/design-system.md.
 *
 * WCAG 2.1 AA NOTE:
 * --copper darkened from #a85a25 (4.44:1 on --paper, FAIL) to #974f1e (5.34:1, PASS)
 * to clear AA-normal contrast for small mono labels (.label, .svc-num, .platforms,
 * .bg-side h4, .proj-card .pn, etc.). --copper-tint matched in lockstep.
 * --copper-bright (#c07a3e) is unchanged; only used on the dark --ink Approach
 * section and the hero photo overlay, where it passes at 5.06:1.
 */

:root {
  /* --paper is the sheet/card color — cooler and lighter than the body bg below
     so the sheet reads as "lifted" off the gutter strips. --paper-2 is the body
     bg, used in the dot-strip area outside the sheet. Contrast is intentionally
     subtle so the page reads as a single warm spread with a faint frame. */
  --paper: #f5f3ed;
  --paper-2: #eeeae0;
  --ink: #1a1a18;
  --ink-2: #2a2a26;
  --mid: #5d5a51;
  --copper: #974f1e;
  --copper-bright: #c07a3e;
  --copper-tint: rgba(151, 79, 30, 0.10);     /* hover/focus subtleties — barely there */
  --copper-tint-mid: rgba(151, 79, 30, 0.35);  /* visible-but-quiet borders (eyebrows, tags) */
  /* Validation / error state. Pure red (R=204, G=B=32) — intentionally
     outside the copper hue family so errors read as "wrong," not as another
     accent. #cc2020 on --paper is 5.06:1 (above AA). Use sparingly — only
     for actual validation / wrong-state UI, not for "important" or
     "highlighted." */
  --error: #cc2020;
  --error-tint: rgba(204, 32, 32, 0.10);
  --rule: rgba(26, 26, 24, 0.18);
  --rule-soft: rgba(26, 26, 24, 0.10);
  --gutter: clamp(20px, 4vw, 56px);
  --container: 1320px;
  /* 12-col scaffold: --col-gap is the single gap token used by every two-/three-column row.
     The row patterns (7/5, 2/4/6) are applied to each layout via grid-template-columns; they
     stack to a single column at 880px. */
  --col-gap: clamp(24px, 3vw, 40px);

  /* Text-width tokens. Two scales, each appropriate to context:
     • Container-level text (H2, deck) sits directly in .container with no inner
       grid, so it uses 12-col fractions of the container interior — 67% = 8/12,
       58% = 7/12. This scales with viewport.
     • Track-level text (body paragraphs inside grid tracks) uses character caps
       so the value stays content-aware regardless of which fr-track wraps it. */
  --w-h2: 66.67%;     /* 8 of 12 cols — section headlines (released to 100% ≤1024px) */
  --w-deck: 58.33%;   /* 7 of 12 cols — italic decks under H2s (released to 100% ≤1024px) */
  --w-body: 60ch;     /* comfortable body paragraph width */
  --w-lead: 40ch;     /* narrower for hero-sub / contact-lead emphasis */

  /* PARAGRAPH TIER SYSTEM — every paragraph on the page picks ONE of these.
     Don't invent new italic-serif-mid treatments inline; they collide with
     the section-deck role and create noise.
       Tier 1 · Lede     → italic display, --mid, 20–26px (one per section,
                           directly under the H2). .section-deck, .contact-card .lead.
                           Hero-sub is the inverse-photo variant: sans, --paper.
       Tier 2 · Body     → roman body sans, --ink, 17–18px, 60ch.
                           .svc-intro p, .bg-text p, .work-body p.
       Tier 3 · Aside    → roman body sans, --mid, 14–15px. Supporting paragraphs
                           that sit alongside Tier 2 — never duplicate Tier 1.
                           Sidebar paragraphs in .bg-side.
       Tier 4 · Accent   → italic display, --copper, intentionally larger or
                           distinct (24–32px or color-shifted) so it doesn't
                           read as a second deck. blockquotes, .pullq. */

  /* Type system. Three voices:
     --font-display : Source Serif 4 (wordmark, headlines, italic accents, CTA italics)
     --font-body    : Source Sans 3 (body paragraphs, center nav links)
     --font-label   : JetBrains Mono (eyebrows, status pills, tag chips, buttons) */
  --font-display: 'Source Serif 4', Georgia, serif;
  --font-body: 'Source Sans 3', -apple-system, sans-serif;
  --font-label: 'JetBrains Mono', monospace;
  --label-tracking: 0.16em;
}
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
html { scroll-behavior: smooth; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
body {
  font-family: var(--font-body);
  font-size: 17px; line-height: 1.65;
  color: var(--ink); background: var(--paper-2);
  position: relative;
}
/* Side-anchored dot grid: two strips originating from content edges. */
body::before, body::after {
  content: '';
  position: fixed; top: 0; bottom: 0;
  pointer-events: none; z-index: 0;
  background-image: radial-gradient(circle, var(--rule) 1px, transparent 1.2px);
  background-size: 24px 24px;
  background-repeat: repeat;
}
body::before {
  left: 0;
  right: calc(50% + (min(100vw, 1320px) / 2) - var(--gutter) + 19px);
  background-position: right top;
}
body::after {
  left: calc(50% + (min(100vw, 1320px) / 2) - var(--gutter) + 19px);
  right: 0;
  background-position: left top;
}
body > * { position: relative; z-index: 1; }
/* Text selection — distinct from UI selection state (calendar day / time slot,
   which use ink fill to read as "committed"). Text selection is transient, so
   it gets the copper accent treatment instead. .how section overrides below. */
::selection { background: var(--copper); color: var(--paper); }
a { color: inherit; text-decoration: none; }
a:focus-visible, button:focus-visible { outline: 2px solid var(--copper); outline-offset: 3px; border-radius: 2px; }
/* On dark backdrops --copper falls below 3:1 (WCAG 2.2 non-text contrast).
   Approach section is dark --ink; hero CTAs sit over the Weaver's Needle photo
   whose darker regions are at or below --ink luminance. Both override to
   --copper-bright for a visible focus ring against the dark backdrop. */
.how a:focus-visible, .how button:focus-visible,
.hero a:focus-visible, .hero button:focus-visible { outline-color: var(--copper-bright); }
/* Skip link target: <main tabindex="-1"> receives focus but should not show an outline ring. */
main:focus { outline: none; }
/* Sticky nav offset for fragment-link landings (skip link + section anchors). */
main, section[id] { scroll-margin-top: 64px; }
.skip-link { position: fixed; top: -100%; left: 16px; padding: 10px 16px; background: var(--ink); color: var(--paper); font-size: 14px; z-index: 1000; }
.skip-link:focus { top: 0; }

h1, h2, h3 { font-family: var(--font-display); font-weight: 400; line-height: 1.05; }
h2 { font-size: clamp(38px, 5.2vw, 64px); line-height: 1.1; letter-spacing: -0.012em; }
h3 { font-size: 22px; letter-spacing: 0; }

/* MONO is a primary voice */
.m { font-family: var(--font-label); }
.label {
  font-family: var(--font-label);
  font-size: 11px; letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--copper);
}

.container { max-width: var(--container); margin: 0 auto; padding: 0 var(--gutter); }

/* PAGE FRAME — sheet inside */
.sheet {
  max-width: var(--container);
  margin: 0 auto;
  background: var(--paper);
  border-left: 1px solid var(--rule);
  border-right: 1px solid var(--rule);
  position: relative;
}
/* NAV — sticky bar along top of sheet. Editorial typography (italic serif
   logo, plain text links, italic-serif CTA) on a 1fr auto 1fr grid that
   keeps the center cluster optically centered. */
nav.site {
  position: sticky; top: 0; z-index: 100;
  background: rgba(243, 240, 232, 0.92);
  backdrop-filter: saturate(140%) blur(14px);
  -webkit-backdrop-filter: saturate(140%) blur(14px);
  border-bottom: 1px solid var(--ink);
}
.nav-inner {
  max-width: var(--container);
  margin: 0 auto;
  /* Vertical padding moved to interactive children below (logo/links/status/cta)
     so each gets a tap target that meets WCAG 2.5.8, and the bar height stays
     content-driven rather than padding-driven. */
  padding: 0 var(--gutter);
  display: grid; grid-template-columns: 1fr auto 1fr;
  gap: 24px;
  /* Baseline align so the 21px logo and the 16px italic CTA share a typographic
     line rather than centering on different vertical mid-points. */
  align-items: baseline;
}
.nav-logo {
  display: inline-block;
  font-family: var(--font-display);
  font-size: 21px; font-weight: 600; line-height: 1;
  letter-spacing: -0.005em;
  color: var(--ink);
  padding: 18px 0; /* drives bar height + tap target on the wordmark */
}
.nav-logo .accent { color: var(--copper); }
.nav-links {
  display: flex; gap: 28px; list-style: none; justify-content: center;
}
.nav-links a {
  display: inline-block;
  font-family: var(--font-body);
  font-size: 13px; letter-spacing: 0.04em;
  color: var(--mid);
  /* Vertical padding pushes the click target above the WCAG 2.5.8 (AA)
     24×24 floor and toward the 44×44 (AAA) recommendation. Keeps the
     visual nav height stable since the nav-inner has its own padding. */
  padding: 14px 4px;
  /* No color transition — Chromium leaves the color stuck at the start value
     when transitioning between two colors here, the same quirk that broke
     border-color earlier. Snap on hover/active is fine at this size. */
}
.nav-links a:hover { color: var(--ink); }
/* Scrollspy active state — JS sets aria-current="true" on the link whose
   section is in the viewport's upper-middle band. */
.nav-links a[aria-current] {
  color: var(--ink);
  text-decoration: underline;
  text-decoration-color: var(--copper);
  text-decoration-thickness: 1px;
  text-underline-offset: 6px;
}
.nav-end {
  justify-self: end;
  display: flex; align-items: baseline; gap: 16px;
  padding: 18px 0;
}
.nav-status {
  font-family: var(--font-label);
  font-size: 11px; letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--mid); display: inline-flex; align-items: center; gap: 8px;
}
.nav-status .dot {
  width: 6px; height: 6px; border-radius: 50%; background: #4a8a4a;
  box-shadow: 0 0 0 3px rgba(74, 138, 74, 0.18);
  animation: nav-pulse 2.4s ease-in-out infinite;
}
@keyframes nav-pulse {
  0%, 100% { box-shadow: 0 0 0 3px rgba(74, 138, 74, 0.18); }
  50%      { box-shadow: 0 0 0 6px rgba(74, 138, 74, 0.06); }
}
@media (prefers-reduced-motion: reduce) {
  .nav-status .dot { animation: none; }
}
.nav-cta {
  display: inline-block;
  font-family: var(--font-display);
  font-style: italic; font-size: 16px; line-height: 1;
  color: var(--ink);
  border-bottom: 1px solid var(--copper);
  /* Top padding extends the click target above the underlined text without
     pushing the underline farther from the glyphs. */
  padding: 12px 0 2px;
  transition: color 0.18s;
}
.nav-cta .arrow { font-style: italic; margin-left: 4px; }
.nav-cta:hover { color: var(--copper); }

/* Mobile nav (≤880px): center anchor links and the booking-status pill hide;
   only the wordmark + "Let's talk" CTA remain. This is INTENTIONAL — every
   center-link target (#services, #approach, #work, #about, #projects) is just
   an in-page anchor on the same single-page document, so users can reach all
   sections by scrolling. The CTA stays so contact is one tap away. If the page
   ever spans multiple routes or grows long enough to make scrolling tedious,
   add a hamburger that mirrors the desktop links. */
@media (max-width: 880px) {
  .nav-inner { grid-template-columns: 1fr auto; }
  .nav-links, .nav-status { display: none; }
}

/* HERO — Weaver's Needle photo as a full-bleed backdrop with the H1 + subtitle
   + CTAs overlaid. The image is absolutely positioned with object-fit: cover
   so the section's height is driven by content needs (clamp min-height) not by
   the image's intrinsic 16:9 ratio — that's what was breaking mobile, where
   the 16:9 image at 375px wide rendered ~210px tall with no room for the H1
   stack below. object-position: right keeps Weaver's Needle visible when the
   image is cropped at narrower widths. */
.hero {
  position: relative;
  background: var(--ink); /* fallback if image fails to load */
  padding: 0; /* override the global section padding so the image is flush */
  color: var(--paper);
  min-height: clamp(540px, 75vh, 760px);
  overflow: hidden;
}
.hero-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: right center;
  display: block;
}
.hero-grid {
  position: relative;  /* sit above the absolute-positioned image */
  z-index: 1;
  min-height: inherit;
  padding: clamp(60px, 8vw, 120px) var(--gutter);
  display: flex;
  flex-direction: column;
  justify-content: center;
}
.hero-main { position: relative; }

.hero-h1 {
  font-size: clamp(44px, 7vw, 112px);
  line-height: 1.05;
  letter-spacing: -0.025em;
  font-weight: 400;
  /* No top margin — the hero-grid's padding-top controls the offset from the
     photo's top edge so it stays in proportion to the gutter (left padding). */
  margin: 0 0 32px;
  text-wrap: balance;
  color: var(--paper);
  /* Soft drop-shadow to lift the H1 off the photo's bright gradient regions
     without looking like a "text on plate" treatment. */
  text-shadow: 0 1px 16px rgba(0, 0, 0, 0.45);
}
.hero-h1 .row { display: block; }
.hero-h1 .row.hero-tagline-italic { font-style: italic; color: var(--paper); }
.hero-h1 .and {
  font-style: italic; color: var(--paper);
  display: inline-block;
}

.hero-sub {
  font-size: clamp(19px, 1.9vw, 22px); line-height: 1.55;
  color: var(--paper); max-width: var(--w-lead);
  margin-bottom: 32px;
  /* --copper-bright (#c07a3e) used here because the hero photo is dark; the
     standard --copper (#974f1e) loses contrast against the photograph. The
     same logic applies to the .how (Approach) dark-section overrides. */
  border-left: 2px solid var(--copper-bright);
  padding-left: 18px;
  /* Stronger text-shadow than the H1 since the smaller text needs more lift
     against the photo's mid-tone gradients. */
  text-shadow: 0 1px 12px rgba(0, 0, 0, 0.6);
}

.hero-cta-row { display: flex; flex-wrap: wrap; gap: 12px 24px; align-items: center; }

/* Mobile + tablet (≤1024px): the photo fills the full viewport width, so the
   centered text overlays the image's focal point (Weaver's Needle in the
   middle). Anchor the H1 + subtitle to the top of the hero, push the CTAs
   to the bottom — keeps the peak uncovered and improves text legibility
   against the gradient regions of the photo (sky at top, foreground silhouette
   at bottom). Desktop (>1024) keeps the centered overlay since the text sits
   left of the image's right-anchored focal point. */
@media (max-width: 1024px) {
  .hero-main {
    display: flex;
    flex-direction: column;
    flex: 1;
    width: 100%;
  }
  .hero-cta-row { margin-top: auto; }
  /* Tighter top padding so the H1's offset from the top edge approaches the
     gutter value (left padding) — the asymmetric "space above text vs left of
     text" felt off when the centered hero became a top-anchored hero. */
  .hero-grid {
    padding-top: clamp(28px, 5vw, 56px);
  }
  /* Release the section H2 + deck width caps below 1024. The 8/12 and 7/12
     fractions create a deliberate "narrow editorial column" on the wide
     desktop canvas; on a phone or tablet they double-narrow the text against
     an already-narrow viewport, forcing word-by-word wraps on long headlines. */
  :root {
    --w-h2: 100%;
    --w-deck: 100%;
  }
}
/* PRIMARY CTA — one logical button with two backdrop modes:
   • .btn-primary        → paper fill, ink text. Used on dark backdrops
                           (hero photo, .how Approach section). Hovers to
                           copper bg + paper text.
   • .contact-cta        → ink fill, paper text. Used on paper backdrops
                           (Contact card, schedule page). Hovers to copper bg.
   They're the canonical pair, picked by backdrop. Don't introduce a third
   primary-CTA visual. */
.btn-primary {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-label);
  font-size: 12px; font-weight: 500; letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--ink); background: var(--paper);
  padding: 14px 22px;
  transition: background 0.2s, color 0.2s;
  border: none; cursor: pointer;
}
.btn-primary:hover { background: var(--copper); color: var(--paper); }
.btn-primary .arrow { font-family: var(--font-display); font-size: 16px; font-style: italic; }

/* CTA arrow motion — subtle slide-right on hover/focus to suggest forward
   movement. Applied to every "→" arrow on the page so the affordance reads
   consistently: hero CTAs (primary + ghost), contact CTA, nav CTA, GitHub
   link in Projects, and the LinkedIn link in About. Reduced-motion users get
   the static end state via the @media block below. */
.btn-primary .arrow,
.btn-ghost-link .arrow,
.contact-cta .arrow,
.nav-cta .arrow,
.btn-outline .arrow {
  display: inline-block;
  transition: transform 0.22s ease;
}
.btn-primary:hover .arrow,
.btn-primary:focus-visible .arrow,
.btn-ghost-link:hover .arrow,
.btn-ghost-link:focus-visible .arrow,
.contact-cta:hover .arrow,
.contact-cta:focus-visible .arrow,
.nav-cta:hover .arrow,
.nav-cta:focus-visible .arrow,
.btn-outline:hover .arrow,
.btn-outline:focus-visible .arrow {
  transform: translateX(4px);
}
@media (prefers-reduced-motion: reduce) {
  .btn-primary .arrow,
  .btn-ghost-link .arrow,
  .contact-cta .arrow,
  .nav-cta .arrow,
  .btn-outline .arrow { transition: none; }
  .btn-primary:hover .arrow,
  .btn-primary:focus-visible .arrow,
  .btn-ghost-link:hover .arrow,
  .btn-ghost-link:focus-visible .arrow,
  .contact-cta:hover .arrow,
  .contact-cta:focus-visible .arrow,
  .nav-cta:hover .arrow,
  .nav-cta:focus-visible .arrow,
  .btn-outline:hover .arrow,
  .btn-outline:focus-visible .arrow { transform: none; }
}
.btn-ghost-link {
  font-family: var(--font-display); font-style: italic;
  font-size: 19px;
  color: var(--paper);
  border-bottom: 1px solid rgba(243, 240, 232, 0.4);
  padding-bottom: 2px;
}
.btn-ghost-link:hover { color: var(--copper-bright); border-color: var(--copper-bright); }

/* SECTION CHROME — section padding establishes the editorial rhythm; same-color
   section boundaries get a 1px hairline on top to do the structural work without
   loud dividers. Where the bg changes (hero photo → paper, paper → .how dark,
   .how dark → paper), the bg shift IS the boundary, so the hairline is skipped.
   V3 alternating paper stocks + Rough.js wave edges were prototyped and shelved;
   see design/section-dividers/v3-implementation-notes.md for the reserve. */
section { padding: clamp(64px, 8vw, 112px) 0; position: relative; }
section + section:not(.how) { border-top: 1px solid var(--rule); }
.hero + section, .how + section { border-top: 0; }

/* Section eyebrow — small mono tag in a hairline box, sits directly above the
   H2 to anchor the reader and reinforce the field-guide section structure.
   `display: block; width: fit-content` keeps the box wrapped tight to the
   text while ensuring the eyebrow occupies its own row — the .how H2 is
   inline-block (for its dark-plate halo), so an inline-block eyebrow above
   it would land on the same line as the H2. */
.section-eyebrow {
  display: block;
  width: fit-content;
  font-family: var(--font-label);
  font-size: 11px; letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--copper);
  /* Stronger than --copper-tint (0.10 alpha, used for hover/focus subtleties) so
     the box reads as a deliberate label on the paper background. */
  border: 1px solid var(--copper-tint-mid);
  padding: 5px 10px;
  border-radius: 2px;
  margin-bottom: 24px;
}
/* On the dark Approach section, --copper falls below contrast on --ink. Use the
   brighter copper-bright there, matching the other dark-section accents. The
   solid --ink background masks the dotted pattern from showing through, and the
   extra margin clears the H2's 10px box-shadow halo below. */
.how .section-eyebrow {
  color: var(--copper-bright);
  border-color: rgba(192, 122, 62, 0.5);
  background: var(--ink);
  margin-bottom: 36px;
}
.section-h2 { max-width: var(--w-h2); text-wrap: balance; margin-bottom: 32px; }
/* Both <em> and <i> get the same copper italic accent treatment so the markup
   can use the semantically correct tag without visual divergence. <em> appears
   in two places where genuine stress meaning is carried: Approach H2 "Part of
   <em>your</em> team." (your team vs. someone else's) and Services body
   "growth <em>and</em> growing pains." (both halves are real, not just the
   good half). All other italic accents on H2s ("and", "talk.", etc.) are
   purely visual and use <i>. Don't switch those <em> back to <i> in future
   edits.

   In headings (display serif), the accent inherits display-serif italic +
   copper. In body copy (Source Sans), the accent stays Source Sans italic +
   copper — no font-family swap mid-sentence. */
.section-h2 em, .section-h2 i,
.svc-intro p em, .svc-intro p i { color: var(--copper); font-style: italic; }
.section-deck {
  font-family: var(--font-display); font-style: italic;
  font-size: clamp(20px, 2.2vw, 26px); line-height: 1.45;
  color: var(--mid); max-width: var(--w-deck);
  margin-bottom: 64px;
}

/* SERVICES */
.svc-intro { margin-bottom: 64px; }
/* Section-intro body — this paragraph sits between the deck and the services
   grid, widened to --w-h2 (66.67% / 8 of 12 cols) so it bookends the narrower
   deck above with the same column structure as the H2. Wider than the
   default --w-body comfort zone (60ch), but acceptable for a single intro
   paragraph that functions as a section lede; everywhere else, body copy
   still uses --w-body. */
.svc-intro p { font-size: 17.5px; line-height: 1.7; color: var(--ink); max-width: var(--w-h2); }

.svc-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  border: 1px solid var(--ink);
}
@media (min-width: 600px) { .svc-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 880px) { .svc-grid { grid-template-columns: repeat(3, 1fr); } }
.svc-cell {
  padding: 32px 28px 36px;
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  background: transparent;
  display: flex; flex-direction: column;
  transition: background 0.25s;
  position: relative;
}
.svc-cell::before {
  content: ''; position: absolute; top: 14px; right: 14px;
  width: 8px; height: 8px;
  border-top: 1px solid var(--copper);
  border-right: 1px solid var(--copper);
  transition: width 0.25s ease, height 0.25s ease;
}
.svc-cell::after {
  content: ''; position: absolute; bottom: 14px; left: 14px;
  width: 8px; height: 8px;
  border-bottom: 1px solid var(--copper);
  border-left: 1px solid var(--copper);
  transition: width 0.25s ease, height 0.25s ease;
}
.svc-cell:hover::before, .svc-cell:hover::after { width: 12px; height: 12px; }
/* Honor reduced-motion preference: kill the corner-tick growth so hovering a
   service cell doesn't animate dimensions for users who opted out. */
@media (prefers-reduced-motion: reduce) {
  .svc-cell::before, .svc-cell::after { transition: none; }
  .svc-cell:hover::before, .svc-cell:hover::after { width: 8px; height: 8px; }
}
.svc-num {
  font-family: var(--font-label);
  font-size: 11px; letter-spacing: var(--label-tracking);
  color: var(--copper); margin-bottom: 18px;
  display: flex; justify-content: space-between; align-items: baseline;
}
.svc-num .tag { color: var(--mid); font-size: 10px; letter-spacing: var(--label-tracking); text-transform: uppercase; }
.svc-cell h3 { font-size: 26px; line-height: 1.1; margin-bottom: 12px; }
.svc-cell p { font-size: 15.5px; line-height: 1.6; color: var(--mid); flex: 1; }
.svc-cell .platforms {
  font-family: var(--font-label);
  font-size: 11.5px; color: var(--copper); margin-top: 18px;
  padding-top: 14px; border-top: 1px dashed var(--rule);
  line-height: 1.7;
}

/* HOW */
.how {
  background: var(--ink); color: var(--paper);
  margin: 0;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--ink);
  background-image: radial-gradient(circle, rgba(243,240,232,0.10) 1px, transparent 1.2px);
  background-size: 24px 24px;
}
.how .section-h2 { color: var(--paper); background: var(--ink); box-shadow: 0 0 0 10px var(--ink); border-radius: 1px; display: inline-block; }
.how .section-h2 em, .how .section-h2 i { color: var(--copper-bright); }

/* Dark-section variant of the global text-selection rule. --copper would fall
   below 3:1 contrast against --ink bg (same WCAG concern as focus rings), so
   this bumps to --copper-bright. Ink text on copper-bright reads cleanly. */
.how ::selection { background: var(--copper-bright); color: var(--ink); }

.how-spread {
  display: grid; grid-template-columns: 1fr; gap: 60px;
}
@media (min-width: 880px) {
  .how-spread { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--col-gap); }
}
.how-text p { color: rgba(243,240,232,0.78); max-width: var(--w-body); font-size: 17px; background: var(--ink); box-shadow: 0 0 0 8px var(--ink); border-radius: 1px; }
.how-text p + p { margin-top: 26px; }

.how-quote {
  /* Layer the copper corner gradient over a solid --ink fill so the dot grid
     behind the section is masked, matching the .how-text p halo treatment. */
  background:
    linear-gradient(135deg, transparent 49%, var(--copper-bright) 49%, var(--copper-bright) 51%, transparent 51%) top right / 28px 28px no-repeat,
    var(--ink);
  box-shadow: 0 0 0 8px var(--ink);
  border-radius: 1px;
  border: 1px solid rgba(243,240,232,0.18);
  padding: 36px;
}
.how-quote .label { color: var(--copper-bright); margin-bottom: 18px; display: block; }
.how-quote blockquote {
  font-family: var(--font-display); font-style: italic;
  font-size: clamp(24px, 3vw, 32px); line-height: 1.3;
  color: var(--copper-bright);
}

.how-tags {
  margin-top: 80px;
  display: grid; grid-template-columns: 1fr;
  gap: 0;
  border: 1px solid rgba(243,240,232,0.2);
}
@media (min-width: 600px) { .how-tags { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 880px) { .how-tags { grid-template-columns: repeat(4, 1fr); } }
.how-tags > div {
  background: var(--ink);
  padding: 20px 22px;
  border-right: 1px solid rgba(243,240,232,0.12);
  border-bottom: 1px solid rgba(243,240,232,0.12);
}
.how-tags h3 {
  font-family: var(--font-label);
  font-size: 10.5px; letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--copper-bright); margin-bottom: 8px; font-weight: 500;
}
.how-tags p { font-size: 14.5px; color: rgba(243,240,232,0.75); margin: 0; }
/* Inline links inside the dark section — copper-bright variant of the
   inline-copper-underline pattern. --copper would fall below 3:1 contrast on
   --ink (same concern as focus rings), so this bumps to --copper-bright with
   a matching translucent underline that thickens to solid on hover. */
.how p a {
  color: var(--copper-bright);
  border-bottom: 1px solid rgba(192, 122, 62, 0.40);
}
.how p a:hover { border-color: var(--copper-bright); }

/* WORK */
.work-list { display: flex; flex-direction: column; gap: 0; border-top: 1px solid var(--ink); }
.work-row {
  border-bottom: 1px solid var(--ink);
  padding: clamp(48px, 6vw, 72px) 0;
  display: grid; grid-template-columns: 1fr; gap: 32px;
  position: relative;
}
@media (min-width: 880px) {
  /* Meta column gets a 140px floor so labels like "Residential Landscaping"
     don't squash awkwardly at the 880px breakpoint. At wider viewports the 2fr
     allocation exceeds 140px and takes over; at the breakpoint, the floor
     holds and the figure/body columns share the remainder by their fr ratio. */
  .work-row { grid-template-columns: minmax(140px, 2fr) minmax(0, 4fr) minmax(0, 6fr); gap: var(--col-gap); align-items: start; }
}
.work-side {
  font-family: var(--font-label);
  font-size: 10.5px; letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--mid);
}
.work-side .num {
  display: block; color: var(--copper);
  font-size: 22px; font-family: var(--font-display);
  font-style: italic; letter-spacing: 0; margin-bottom: 10px;
}
.work-side strong { color: var(--ink); display: block; margin-top: 12px; font-weight: 500; }
.work-side .work-region { display: block; margin-top: 14px; }
.work-side .work-region-name { display: inline; color: var(--copper); }
.work-fig {
  aspect-ratio: 4 / 3;
  border: 1px solid var(--rule);
  background: var(--paper-2);
  background-image:
    repeating-linear-gradient(45deg, transparent 0 9px, rgba(151,79,30,0.06) 9px 10px);
  display: flex; align-items: flex-end;
  position: relative;
}
.work-fig figcaption {
  padding: 12px 16px;
  font-family: var(--font-label);
  font-size: 10px; letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--mid); background: var(--paper); border-top: 1px solid var(--rule);
  width: 100%;
}
.work-fig figcaption strong { color: var(--copper); display: block; font-weight: 500; }
.work-body h3 {
  font-size: clamp(26px, 3.2vw, 36px);
  line-height: 1.12; margin-bottom: 18px;
  text-wrap: balance;
}
.work-body p { color: var(--mid); font-size: 17px; line-height: 1.6; max-width: var(--w-body); }
.work-body .platforms {
  margin-top: 18px;
  display: flex; flex-wrap: wrap; gap: 6px;
}
.work-body .platforms span {
  font-family: var(--font-label);
  font-size: 11px; letter-spacing: 0.04em;
  color: var(--copper);
  border: 1px solid var(--copper-tint);
  padding: 3px 8px; border-radius: 2px;
}

/* BACKGROUND */
.bg-narrative {
  display: grid; grid-template-columns: 1fr; gap: 56px;
}
@media (min-width: 880px) {
  .bg-narrative { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--col-gap); }
}
.bg-text p {
  font-size: 18px; line-height: 1.75;
  color: var(--ink); max-width: var(--w-body);
}
.bg-text p + p { margin-top: 18px; }
.bg-text strong { font-weight: 500; color: var(--copper); }
.bg-text .pullq { font-family: var(--font-display); font-style: italic; color: var(--copper); }
.bg-text .location {
  margin-top: 36px; padding: 16px 0;
  border-top: 1px solid var(--ink);
  border-bottom: 1px solid var(--rule);
  font-family: var(--font-label);
  font-size: 12px; letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--mid);
}
.bg-text .location strong { color: var(--ink); font-weight: 500; }

.bg-side {
  border: 1px solid var(--ink);
  padding: 0;
  background: var(--paper);
}
.bg-side > div {
  padding: 18px 22px;
  border-bottom: 1px solid var(--rule);
}
.bg-side > div:last-child { border-bottom: none; }
.bg-side h3 {
  font-family: var(--font-label);
  font-size: 10.5px; letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--copper); font-weight: 500; margin-bottom: 8px;
}
.bg-side p, .bg-side ul { font-size: 14.5px; color: var(--ink); line-height: 1.55; }
.bg-side ul { list-style: none; }
.bg-side li { padding: 2px 0; }
.bg-side a { border-bottom: 1px solid var(--rule); }
.bg-side a:hover { color: var(--copper); border-color: var(--copper); }

/* PROJECTS */
.projects-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 0;
  border: 1px solid var(--ink);
}
@media (min-width: 600px) { .projects-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 880px) { .projects-grid { grid-template-columns: repeat(4, 1fr); } }
.proj-card {
  padding: 28px 24px;
  border-right: 1px solid var(--rule);
  border-bottom: 1px solid var(--rule);
  background: transparent;
  display: flex; flex-direction: column; gap: 6px;
  transition: background 0.25s;
  min-height: 200px;
  position: relative;
}
.proj-card:hover { background: var(--copper-tint); }
.proj-card .pn {
  font-family: var(--font-label);
  font-size: 10.5px; letter-spacing: var(--label-tracking);
  color: var(--copper); margin-bottom: 14px;
  display: flex; justify-content: space-between;
}
.proj-card .pn .status {
  color: var(--mid); font-size: 9.5px; letter-spacing: var(--label-tracking); text-transform: uppercase;
}
.proj-card h3 { font-size: 26px; margin: 0; line-height: 1.1; }
.proj-card .url {
  font-family: var(--font-label);
  font-size: 11.5px; color: var(--mid); margin-top: 4px;
}
.proj-card p { font-size: 14.5px; color: var(--mid); line-height: 1.55; flex: 1; margin-top: 10px; }
.proj-card .pending {
  font-family: var(--font-label);
  font-size: 10.5px; letter-spacing: var(--label-tracking); text-transform: uppercase;
  color: var(--mid); opacity: 0.7; margin-top: 10px;
}
/* Ghost-button CTA — mono uppercase, ink-outlined, fills on hover. Used for
   "more on [external profile]" links (GitHub at the bottom of Projects,
   LinkedIn at the bottom of About). Margin-top is set per-usage so the class
   stays purely about visual style. */
.btn-outline {
  display: inline-flex; align-items: center; gap: 10px;
  font-family: var(--font-label);
  font-size: 12px; letter-spacing: 0.1em; text-transform: uppercase;
  color: var(--ink);
  border: 1px solid var(--ink);
  padding: 10px 16px;
  transition: background 0.2s, color 0.2s;
}
.btn-outline:hover { background: var(--ink); color: var(--paper); }
/* Bottom-of-Projects placement gets extra top spacing from the cards above. */
.projects-grid + .btn-outline { margin-top: 32px; }

/* CONTACT */
.contact-card {
  border: 1px solid var(--ink);
  background: var(--paper);
  padding: clamp(40px, 5vw, 72px);
  display: grid; grid-template-columns: 1fr;
  gap: 40px;
  position: relative;
}
@media (min-width: 880px) {
  .contact-card { grid-template-columns: minmax(0, 7fr) minmax(0, 5fr); gap: var(--col-gap); align-items: end; }
}
.contact-card h2 {
  font-size: clamp(56px, 9vw, 124px);
  line-height: 0.92; letter-spacing: -0.03em;
  margin-bottom: 0;
}
.contact-card h2 em, .contact-card h2 i { color: var(--copper); font-style: italic; }
.contact-card .lead {
  font-family: var(--font-display); font-style: italic;
  font-size: clamp(20px, 2.2vw, 24px); line-height: 1.45;
  color: var(--mid); margin-bottom: 28px; max-width: var(--w-lead);
}
/* Canonical primary CTA on paper backdrops — partner to .btn-primary.
   See the comment block above .btn-primary for the pair-rule. */
.contact-cta {
  /* inline-block, not inline-flex — when the button is narrow enough that
     the text wraps to two lines, inline-flex put the arrow on its own column
     to the right, leaving an awkward gap. Inline-block lets the text wrap
     normally; the &nbsp; before the arrow keeps it glued to the last word. */
  display: inline-block;
  font-family: var(--font-label);
  font-size: 12px; font-weight: 500; letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--paper); background: var(--ink);
  padding: 14px 22px;
  transition: background 0.2s;
  border: none; cursor: pointer;
}
.contact-cta:hover { background: var(--copper); }
/* Spacing inside the Contact card stays scoped here so .contact-cta can be
   used in other contexts (schedule submit, schedule confirm) without
   inheriting the card's specific layout. */
.contact-card .contact-cta { margin-bottom: 28px; }
.email {
  display: block;
  font-family: var(--font-display); font-style: italic;
  font-size: clamp(26px, 3vw, 36px);
  color: var(--copper); margin-bottom: 22px;
  border-bottom: 1px solid var(--copper-tint);
  padding-bottom: 6px;
}
.email:hover { border-color: var(--copper); }
.contact-details {
  font-family: var(--font-label);
  font-size: 12px; letter-spacing: 0.06em;
  color: var(--mid); line-height: 1.9;
}
.contact-details strong { color: var(--ink); font-weight: 500; }
.contact-details a:hover { color: var(--copper); }

/* FOOTER */
footer {
  border-top: 1px solid var(--ink);
  padding: 28px var(--gutter) 36px;
  font-family: var(--font-label);
  font-size: 11px; letter-spacing: 0.08em;
  color: var(--mid);
}
.footer-row {
  display: flex; justify-content: space-between; flex-wrap: wrap; gap: 16px;
  align-items: center;
}
/* Footer wordmark — mirrors the nav logo treatment (Source Serif 4 600, copper
   accent on "Strategy", no italic). Slightly smaller since it's a credential
   line, not a primary brand element. */
.footer-mark {
  font-family: var(--font-display);
  font-size: 17px; font-weight: 600;
  color: var(--ink);
  letter-spacing: 0;
}
.footer-mark .accent { color: var(--copper); }
.footer-links { display: flex; gap: 18px; list-style: none; }
.footer-links a:hover { color: var(--copper); }

/* CANONICAL FORM FIELDS — promoted from .sched-* on the schedule page so any
   future form (intake, contact, etc.) inherits the same field anatomy:
     .fields           grid container (2-col stacking to 1)
     .field            single row: <label> wrapping label + control + error
     .field--full      span both columns (multi-line textarea)
     .field-label      mono uppercase eyebrow above the control
     .field input/textarea
     .field--invalid   error state — copper border + tint glow
     .field-error      inline error text under the control */
.fields {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 22px;
}
.field { display: flex; flex-direction: column; gap: 8px; }
.field--full { grid-column: 1 / -1; }
@media (max-width: 600px) {
  .fields { grid-template-columns: 1fr; }
}
.field-label {
  font-family: var(--font-label);
  font-size: 11px;
  letter-spacing: var(--label-tracking);
  text-transform: uppercase;
  color: var(--copper);
}
.field input,
.field textarea {
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.5;
  color: var(--ink);
  background: var(--paper);
  border: 1px solid var(--rule);
  padding: 12px 14px;
  border-radius: 2px;
  transition: border-color 0.18s, box-shadow 0.18s;
  width: 100%;
}
.field input::placeholder,
.field textarea::placeholder {
  color: var(--mid);
  opacity: 0.85;
}
.field input:focus,
.field textarea:focus {
  outline: none;
  border-color: var(--copper);
  box-shadow: 0 0 0 3px var(--copper-tint);
}
.field textarea {
  resize: vertical;
  min-height: 96px;
}
/* Invalid state — JS toggles .field--invalid on the wrapper after submit.
   We don't rely on :user-invalid so the error styling can also be cleared
   on input regardless of native validity (e.g., a whitespace-only required
   field that the browser considers "valid"). The .field.field--invalid
   compound selector is intentionally more specific than .field input:focus
   so invalid fields stay error-red even when the user clicks back into
   them to fix — no source-order fragility. */
.field.field--invalid input,
.field.field--invalid textarea,
.field.field--invalid input:focus,
.field.field--invalid textarea:focus {
  border-color: var(--error);
  box-shadow: 0 0 0 3px var(--error-tint);
}
/* Reserve a fixed slot for the error message so the form doesn't jump when
   validation flips a field from valid → invalid. Empty .field-error renders
   as 1.5em of blank space; populated, the text fills that same height.
   Weight 500 keeps the message prominent; --error is the warm-red token
   reserved for validation state, distinct from --copper accents. */
.field-error {
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.45;
  color: var(--error);
  font-weight: 500;
  margin-top: 4px;
  min-height: 1.5em;
}
@media (prefers-reduced-motion: reduce) {
  .field input, .field textarea { transition: none; }
}

/* CANONICAL TERTIARY ACTION — quiet text-link button. Use for Back / Cancel /
   Skip and similar reversible flow controls. Body sans on cream, no border;
   the affordance is the hover color shift to copper. */
.btn-tertiary {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  background: none;
  border: none;
  padding: 8px 4px;
  font-family: var(--font-body);
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--mid);
  cursor: pointer;
  transition: color 0.18s;
}
.btn-tertiary:hover { color: var(--copper); }
@media (prefers-reduced-motion: reduce) {
  .btn-tertiary { transition: none; }
}

/* REVEAL — gated behind .js class so the page is not invisible without JavaScript. */
.js .reveal { opacity: 0; transform: translateY(16px); transition: opacity 0.7s ease, transform 0.7s ease; }
.js .reveal.in { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) { .js .reveal { opacity: 1; transform: none; transition: none; } html { scroll-behavior: auto; } }
