:root {
  --ink: #172D4A;
  --navy: #224564;
  --copy: #3E5568;
  --orange: #CB4215;
  --warm: #FFF4EE;
  --site-white: #FCFDFD;
  --white: var(--site-white);
  --line: rgba(23, 45, 74, .14);
  --shell: min(1320px, calc(100% - 80px));

  /* Service page layout v2 tokens (Bethany's 9/13 mock), promoted 2026-09-13 */
  --sp-pad: 96px;
  --sp-shell: 1320px;
  --sp-gutter: 80px;
  --sp-h2: clamp(30px, 3vw, 40px);
  --sp-body: 21px; /* 9/27 (Bethany): body copy 21px, line height 1.5 site-wide (was 20 / 1.6), her pick on MOCK body-size_2026-09-27 */

  --sp-navy: #172D4A;
  --sp-navy2: #224564;
  --sp-sub: #3E5568;
  --sp-wash: #FFF4EE;
  --sp-orange: #CB4215;
  --sp-orange-deep: #CB4215;
}
@media (max-width: 900px) {
  :root { --shell: calc(100% - 48px); --sp-pad: 64px; --sp-gutter: 48px; }
}
@media (max-width: 700px) {
  :root { --shell: calc(100% - 40px); --sp-gutter: 40px; --sp-pad: 48px; } /* --sp-pad was the 600px breakpoint; raised to 700 (Bethany 2026-09-14) so .sp-section padding is capped at 48px for the whole phone range, not just <=600 */
}

*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  color: var(--ink);
  background: var(--white);
  font-family: "Jost", Arial, sans-serif;
  -webkit-font-smoothing: antialiased;
}
body.menu-open { overflow: hidden; }
img { display: block; max-width: 100%; }
::selection { background: #7FB0DC; color: #fff; }
a { color: inherit; }
a:focus-visible, button:focus-visible { outline: 3px solid #f9d8c2; outline-offset: 4px; }
.nav-dropdown summary:focus-visible { outline: 3px solid #f9d8c2; outline-offset: 4px; } /* 10/6 launch audit C7: the Services toggle gets the same peach ring as the other nav links (a summary was left on the browser's blue ring) */

.skip-link {
  position: fixed;
  top: 8px;
  left: 8px;
  z-index: 100;
  padding: 10px 14px;
  background: var(--white);
  color: var(--ink);
  font-weight: 700;
  transform: translateY(-150%);
}
.skip-link:focus { transform: none; }

.eyebrow {
  margin: 0 0 14px;
  color: #CB4215;
  font-size: 15px;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: .08em;
  text-transform: uppercase;
}

.section { padding: 68px 0; }
.section + .section { padding-top: 0; }
.section + .section > .shell { border-top: 1px solid rgba(127, 176, 220, .35); padding-top: 68px; }
.shell { width: var(--shell); margin-inline: auto; }
/* Type scale v2 (2026-08-23): one heading weight, distinct size steps. Sizes standardized to the service-page scale (Bethany, 2026-09-13) */
.section-heading { margin: 0; max-width: none; color: var(--ink); font-family: "Jost", Arial, sans-serif; font-size: clamp(30px, 3vw, 40px); font-weight: 600; line-height: 1.15; letter-spacing: -.04em; }
.intro-copy { max-width: none; margin: 18px 0 0; color: var(--copy); font-size: var(--sp-body); line-height: 1.5; }

.editorial-split {
  display: grid;
  grid-template-columns: minmax(0, .88fr) minmax(400px, 1.12fr);
  gap: clamp(42px, 5vw, 60px);
  align-items: center;
}
.editorial-split--reverse { grid-template-columns: minmax(400px, 1.12fr) minmax(0, .88fr); }
.editorial-split--reverse .editorial-media { order: 2; }
.editorial-media { position: relative; }
.editorial-media img { position: relative; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.editorial-media.editorial-media--landscape img { aspect-ratio: 3 / 2; max-height: 380px; } /* 10/7 CSS sweep: the values Our Process has always shown, folded in from its page-level copy; two classes so it beats the phone 4/4.6 rule on its own instead of by load order */
.editorial-copy p:not(.eyebrow) { margin: 18px 0 0; color: var(--copy); font-size: var(--sp-body); line-height: 1.5; }

/* 2026-09-14: underline replaced by a trailing caret (::after) so the link end reads as a chevron
   instead of a rule; any hand-authored <span>›</span>/&rsaquo; in the markup was stripped so
   nothing doubles up (kept the ::after approach over "skip when a span exists" since a couple of
   links had a bare &rsaquo; with no span at all, which a :has() skip-check wouldn't have caught). */
.text-link {
  display: inline-flex;
  align-items: center;
  margin-top: 28px;
  color: #CB4215; /* 9/27 (Bethany): links in the original eyebrow orange */
  font: 400 17px "Jost", Arial, sans-serif; /* 9/27 (Bethany): arrow links regular weight, not bold */
  text-decoration: none;
  transition: color 160ms ease;
}
.text-link::after {
  content: "\203A";
  display: inline-block;
  margin-left: 8px;
  color: currentColor;
  font-size: 1.15em;
  line-height: 1;
  transition: transform 160ms ease;
}
.text-link span { font-size: 21px; line-height: .7; color: currentColor; }
.text-link:hover,
.text-link:focus-visible { color: #B23A0F; }
.text-link:hover::after,
.text-link:focus-visible::after { transform: translateX(2px); }

/* Materials (.capability-grid) desktop restyle (Bethany 2026-09-15): the old 2-column layout read
   dated (a decorative top hairline over every card, the H3 crammed straight against the photo, and
   the 3:2 photos ballooning to ~620px wide in a 2-column grid). Now 3 columns so photos run
   smaller, no top hairline, a proper photo/H3/paragraph rhythm, and the fifth item (odd count)
   just falls into row 2 left-aligned via normal grid flow, no extra rule needed for that. */
.capability-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 32px; margin-top: 30px; } /* 10/7 CSS sweep: 30px at every width, the value Our Process (the only page with this grid) has always shown; it came from a page-level copy that won by load order, now folded in here */
.capability { padding-top: 0; border-top: 0; }
.capability img { border-radius: 6px; margin: 0 0 16px; }
/* Materials H3 (Bethany 2026-09-15): the plain site H3, sentence case as written in the markup, no letter-spacing, weight 600 (was 700), navy; opted out of the Type scale v2 uppercase treatment */
.capability h3 { margin: 0; color: var(--ink); font-family: "Jost", Arial, sans-serif; font-size: 24px; font-weight: 600; line-height: 1.15; text-transform: none; letter-spacing: normal; }
.capability p { margin: 8px 0 0; color: var(--copy); font-size: 18px; line-height: 1.6; }
@media (max-width: 700px) {
  /* Materials (.capability-grid) as a plain stacked list on phone: no photos, hairline dividers
     between items instead of the grid's decorative top-border accent (Bethany 2026-09-14).
     Phone list mode unchanged by the 2026-09-15 desktop restyle above: the paragraph is pinned back
     to its phone values here since the base rule above now carries the desktop values. */
  .capability img { display: none !important; } /* !important kept: each img carries an inline style="...display:block" that would otherwise win */
  .capability-grid { grid-template-columns: 1fr; gap: 0; }
  .capability { border-top: 1px solid rgba(23, 45, 74, .15); padding: 24px 0; }
  .capability:first-child { border-top: 0; padding-top: 0; }
  .capability p { font-size: var(--sp-body); } /* 10/7 CSS sweep: the 24px grid margin and 9px paragraph margin that sat here never showed (the page-level copies won); phones keep 30px and 8px from the base rules */
}

.process-list { margin-top: 40px; } /* 10/7 CSS sweep: 40px, the value Our Process has always shown (folded in from its page-level copy) */
.process-detail {
  position: relative;
  display: grid;
  grid-template-columns: 2fr 3fr;
  gap: 48px;
  align-items: start;
  padding: 56px 0;
  border-top: 1px solid rgba(127, 176, 220, .35);
}
.process-detail:nth-child(even) { grid-template-columns: 3fr 2fr; }
.process-detail:nth-child(even) .process-detail-media { order: 2; }
/* Media locked to the text column's height (Bethany 2026-09-15): same technique as .sp-who-photo /
   .sp-open-photo-wrap, min-height 320px covers the "text under 240px" fallback. */
.process-detail-media { position: relative; height: 100%; min-height: 320px; }
.process-detail-media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 900px) {
  .process-detail-media { height: auto; min-height: 0; }
  .process-detail-media img { position: static; aspect-ratio: 4 / 3; width: 100%; height: auto; }
  .process-detail, .process-detail:nth-child(even) { grid-template-columns: 1fr; gap: 32px; }
  .process-detail:nth-child(even) .process-detail-media { order: 0; }
}
.process-detail p { margin: 16px 0 0; color: var(--copy); font-size: var(--sp-body); line-height: 1.5; }
.process-notes li { color: var(--navy); font-size: 18px; } /* 10/7 CSS sweep: the list's margin comes from .dot-list (every .process-notes list is also a .dot-list); the old .process-notes margin lost to it on order and never showed */

/* CTA card (Bethany, approved 2026-09-14, replaces the old pale-blue full-width .cta-band):
   contained card on the site white, standing 80px above and below, before the navy footer.
   9/14 to 9/23 history: cta-orange.png, then a CSS gradient with the plan linework in ::after at 45%
   (white-line blueprint tried and rejected 9/23; lighter and darker orange lines also rejected), then
   a gradient export. 9/24 FINAL (Bethany, "yes"): flat brand orange band with the plan drawing in the
   corners, her Canva export at banners/cta-band-2026-09-24.png. Matches .home-cta-card. */
.cta-share { padding-block: 80px; background: var(--site-white); }
.cta-share-card { position: relative; isolation: isolate; overflow: hidden; width: 100%; max-width: 760px; margin: 0 auto; /* was width:900px/max-width:100% (Bethany 2026-09-15, narrower card) */ background: url("photos/banners/cta-band-2026-09-24.png") center / cover no-repeat; border: none; border-radius: 6px; padding: 40px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 24px; text-align: center; } /* Padding bumped to 56px top/bottom 2026-09-15 to hold the larger headline, then back down to 40px same day (headline stays 48px max). */
.cta-share-card > * { position: relative; z-index: 1; }
.cta-share-card h2 { margin: 0; max-width: none; font-family: "Jost", Arial, sans-serif; font-size: clamp(36px, 3.4vw, 48px); font-weight: 600; line-height: 1.15; color: var(--site-white); text-wrap: balance; text-align: center; text-shadow: 0 1px 2px rgba(110, 30, 0, .28); } /* sized up 2026-09-15 from clamp(30,3vw,40); faint shadow 9/23 for contrast */
.cta-share-button { display: inline-flex; min-height: 46px; align-items: center; justify-content: center; padding: 12px 22px; background: #CB4215; border: 1px solid #FCFDFD; border-radius: 6px; color: #FCFDFD; font-family: "Jost", Arial, sans-serif; font-size: 15px; font-weight: 600; letter-spacing: .04em; text-transform: uppercase; text-decoration: none; white-space: nowrap; transition: background 180ms ease, color 180ms ease, border-color 180ms ease; } /* filled 2026-09-14 (Bethany): near-white fill, deep-orange text, replaces the outline-only white button. 9/23 (Bethany): 1px outline in the text orange, matches .home-cta-button */
.cta-share-button:hover, .cta-share-button:focus-visible { background: #B23A0F; border-color: #FCFDFD; color: #FCFDFD; } /* 9/27 (Bethany, option E of MOCK cta-button_2026-09-27): filled in the blueprint line color, white text, 1px white outline; hover a shade deeper. Matches .home-cta-button */
@media (max-width: 700px) {
  /* in-flow CTA card shown on phone again (Bethany 2026-09-15, sticky bar removed): 16px gutters
     each side. .cta-share-card sits inside .shell, which already carries its own ~20px side
     padding at this width, so widen the card by 8px (4px/side) via a negative margin instead of
     hardcoding a gutter value that would drift out of sync with --shell. Also clears the base
     rule's max-width:100% here (Bethany 2026-09-15 fix), which otherwise caps the card back down
     to the shell's own width and cancels half the negative margin, leaving a lopsided gutter. */
  .cta-share-card { width: calc(100% + 8px); max-width: none; margin-inline: -4px; padding: 32px 20px; gap: 20px; }
  .cta-share-card h2 { font-size: 28px; margin: 0 0 8px; }
}
.button { display: inline-flex; min-height: 46px; align-items: center; justify-content: center; padding: 12px 22px; background: var(--orange); border: none; border-radius: 5px; color: var(--white); font-family: "Jost", Arial, sans-serif; font-size: 15px; font-weight: 600; letter-spacing: .04em; text-decoration: none; text-transform: uppercase; white-space: nowrap; transition: background 180ms ease; }
.button:hover, .button:focus-visible { background: #B23A0F; }
.button span { margin-left: 10px; font-size: 21px; }

/* footer reveal (Bethany 2026-09-13, from the J.L. Young reference): footer pinned behind the page; main carries a bottom margin = footer height, set by cape-nav.js */
main { position: relative; z-index: 1; background: var(--site-white); }
.site-footer { position: fixed; left: 0; right: 0; bottom: 0; z-index: 0; padding: 120px 0 40px; background: #224564; color: color-mix(in srgb, var(--site-white) 86%, transparent); }
.site-footer .shell { width: min(1320px, calc(100% - 80px)); }
/* .cta-share now lives in <main>, its own last section (Bethany 2026-09-14, un-pinned from the footer); the footer keeps its default 120px top padding since nothing inside it supplies its own spacing anymore. */
.footer-grid { display: grid; grid-template-columns: 1.2fr 1fr 1fr 1.3fr; gap: 0; }
.footer-grid > * { padding: 0 40px; }
.footer-grid > *:first-child { padding-left: 0; }
.footer-grid > *:last-child { padding-right: 0; }
.footer-grid > * + * { border-left: 1px solid color-mix(in srgb, var(--white) 20%, transparent); }
.footer-logo { width: 190px; height: auto; object-fit: contain; margin-bottom: 16px; }
.footer-address { margin: 0 0 20px; }
.footer-address p { margin: 0; color: color-mix(in srgb, var(--site-white) 86%, transparent); font-size: 17px; line-height: 1.35; }
.footer-contact { display: flex; flex-direction: column; gap: 6px; }
.footer-contact a { color: color-mix(in srgb, var(--site-white) 86%, transparent); font-size: 17px; line-height: 1.5; text-decoration: none; }
.footer-contact a:hover, .footer-contact a:focus-visible { color: var(--white); text-decoration: underline; text-decoration-color: #7FB0DC; text-underline-offset: 4px; }
.footer-social { display: flex; gap: 16px; margin: 16px 0 0; }
.footer-social a { display: inline-flex; color: color-mix(in srgb, var(--site-white) 86%, transparent); }
.footer-social a:hover, .footer-social a:focus-visible { color: var(--white); }
.footer-social svg { width: 22px; height: 22px; fill: currentColor; }
.footer-heading { margin: 0 0 18px; color: var(--white); font-family: "Jost", Arial, sans-serif; font-size: 18px; font-weight: 600; letter-spacing: .06em; text-transform: uppercase; }
.footer-links { display: grid; gap: 8px; margin: 0; padding: 0; list-style: none; }
.footer-links a { color: color-mix(in srgb, var(--site-white) 86%, transparent); font-size: 17px; line-height: 1.35; text-decoration: none; }
.footer-links a:hover, .footer-links a:focus-visible { color: var(--white); text-decoration: underline; text-decoration-color: #7FB0DC; text-underline-offset: 4px; }
.footer-fine { margin-top: 64px; padding-top: 24px; color: color-mix(in srgb, var(--site-white) 70%, transparent); font-size: 14px; display: flex; justify-content: space-between; align-items: center; gap: 12px; }
.footer-fine a { color: color-mix(in srgb, var(--site-white) 70%, transparent); text-decoration: none; }
.footer-fine a:hover, .footer-fine a:focus-visible { text-decoration: underline; }
.footer-fine-links { display: flex; gap: 24px; white-space: nowrap; } /* 10/7 (Bethany): "Privacy policy" and "Terms of use" never wrap to two lines (keep in sync with index.html) */
/* 10/6 launch audit B8: 44px tap areas on the footer icons and links. An invisible ::after grows the target; the drawn icons and text, and everything around them, stay where they were. Keep in sync with index.html's copy. */
.footer-social a, .footer-links a, .footer-fine a { position: relative; }
.footer-social a::after { content: ""; position: absolute; inset: -11px; }
.footer-links a::after, .footer-fine a::after { content: ""; position: absolute; left: -4px; right: -4px; top: 50%; height: 44px; transform: translateY(-50%); }
@media (max-width: 700px) {
  .footer-fine { flex-direction: column; align-items: center; text-align: center; gap: 6px; } /* 10/7 late (Bethany, from her phone): everything in the phone footer is centered (keep in sync with index.html) */
  .footer-fine-links { justify-content: center; }
  /* site-wide phone pass (Bethany 2026-09-14): footer plain flow (not pinned/revealed; cape-nav.js
     also skips the margin math below 700px), only the brand block + bottom bar shown, centered.
     The position:static override has to sit AFTER the unconditional ".site-footer { position: fixed }"
     rule above, or plain source order lets that rule win regardless of this media query. */
  .site-footer { position: static; padding-bottom: 96px; } /* 40px base + 56px clearance for the phone call/text bar (Bethany 2026-09-15 bugfix: the clearance lives on the footer, not body padding, so it sits inside the footer's navy box instead of showing as a white band under it) */
  main { margin-bottom: 0; } /* footer is static here, not pinned/revealed, so no reveal margin (cape-nav.js clears its inline margin below 700px) */
  .footer-grid > div:not(.footer-brand) { display: none; } /* 10/7 CSS sweep: a one-column/28px-gap .footer-grid line here never applied (the 900px block below comes later and won); only the brand block shows, so it made no difference and is gone */
  .footer-brand { display: flex; flex-direction: column; align-items: center; text-align: center; }
  .footer-address p { text-align: center; }
  .footer-contact { align-items: center; }
  .footer-social { justify-content: center; }
}
/* We serve column (Bethany 2026-09-13, restyled to the J.L. Young reference): two county sub-groups, side by side, chip labels */
.footer-towns { display: grid; grid-template-columns: 1fr 1fr; gap: 40px; }
.footer-town-group { display: flex; flex-direction: column; }
.footer-town-list { display: grid; gap: 8px; }
.footer-town { margin: 0; color: color-mix(in srgb, var(--site-white) 86%, transparent); font-size: 17px; line-height: 1.35; }

@media (max-width: 900px) {
  .editorial-split, .editorial-split--reverse { grid-template-columns: 1fr 1fr; gap: 40px; }
  .footer-grid { grid-template-columns: 1fr 1fr; gap: 32px 40px; }
  .footer-grid > :first-child { grid-column: 1 / -1; }
  .footer-grid > :last-child { grid-column: 1 / -1; }
  .footer-grid > * { padding: 0; border-left: 0; }
  .footer-grid > * + * { border-left: 0; border-top: 1px solid color-mix(in srgb, var(--white) 20%, transparent); padding-top: 24px; }
}

@media (max-width: 700px) {
  .section { padding: 48px 0; } /* was 54px (Bethany 2026-09-14: cap section padding at 48px on phone) */
  .section + .section > .shell { padding-top: 48px; }
  .editorial-split, .editorial-split--reverse { grid-template-columns: 1fr; }
  .editorial-split--reverse .editorial-media { order: 0; }
  .editorial-media img { aspect-ratio: 4 / 4.6; }
  .process-detail { padding: 42px 0; }
}

@media (max-width: 600px) {
  .footer-grid { grid-template-columns: 1fr; }
  .footer-grid > * { grid-column: auto; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { scroll-behavior: auto !important; transition-duration: .01ms !important; } /* !important kept: the universal selector has zero specificity, so nothing else would let it beat the per-element transition rules */
}

/* ---------- Nav v3 (Bethany, 2026-09-10) ----------
   Over the hero: links orange on a dark fade, Contact is an outlined pill.
   Past the hero (or on pages with no hero): bar goes #F9D8C2, links go a step darker.
   Phone number removed from the nav (footer and Contact page carry it). */
.page-banner { position: relative; }
@media (max-width: 700px) {
  /* site-wide hardening (Bethany 2026-09-14): any sticky hero/banner pattern (.page-banner, .hero)
     must not stay pinned at phone width, or it can reappear under later sections while scrolling
     (the bleed-through bug found on the homepage and on portfolio-draft.html/projects.html). No live
     page turns a banner sticky any more; a page that does must carry its own phone override. */
  .page-banner, .hero { position: relative; }
}

main > .section:first-child { padding-top: 40px; }

/* Service page layout v2 (Bethany's 9/13 mock), promoted 2026-09-13 */
header.site-header .nav-shell { width: min(var(--sp-shell), calc(100% - var(--sp-gutter))); margin-inline: auto; }
.sp-wrap { width: min(var(--sp-shell), calc(100% - var(--sp-gutter))); margin-inline: auto; }
.sp-eyebrow { margin: 0 0 12px; color: var(--sp-orange); font: 600 15px/1 "Jost", Arial, sans-serif; letter-spacing: .08em; text-transform: uppercase; }
.sp-h2 { margin: 0 0 20px; font: 600 var(--sp-h2)/1.15 "Jost", Arial, sans-serif; letter-spacing: -.01em; color: var(--sp-navy); }
.sp-body-copy { max-width: 68ch; margin: 0 0 16px; color: var(--sp-sub); font: 400 var(--sp-body)/1.5 "Jost", Arial, sans-serif; }
.sp-body-copy:last-child { margin-bottom: 0; }
.sp-section { padding-block: var(--sp-pad); }

/* 1-2. title band: solid navy, no photo, no overlap card, directly under the in-flow nav */
.sp-title { background: #224564 url("photos/banners/title-band-2026-09-25.png") center / cover no-repeat; padding-top: 76px; padding-bottom: 84px; } /* 9/25 (Bethany): her gradient export with the CTA corner drawing at 38%, baked; replaces the edge-to-edge plan band */
/* 9/25: the 2026-09-15 phone override for the old plan band is gone; the new baked band is one image, cover/center, on every width */
.sp-title h1 { margin: 0; font: 600 clamp(48px, 4.6vw, 66px)/1.1 "Jost", Arial, sans-serif; letter-spacing: -.01em; color: var(--site-white); text-align: center; }
.sp-title .sp-eyebrow { text-align: center; color: #F35B1F; } /* 9/25 (Bethany): title and eyebrow centered on every band, matching the centered CTA. 9/28 (Bethany): on the navy band the dark orange was hard to read, so the band eyebrow uses the logo's brighter orange (the logo sits right above it in the nav); everywhere else the eyebrow stays #CB4215 */

/* 3. opening: two columns on white, standard section padding */
.sp-open { background: var(--site-white); }
.sp-open.sp-section { padding-block: 64px; }
.sp-open-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: stretch; }
.sp-open-photo-wrap { position: relative; height: 100%; }
.sp-open-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center bottom; }
.sp-open-text .sp-eyebrow { margin-top: 32px; }
/* ---------- Shared bullet-list style (Bethany 2026-09-14): .dot-list is the canonical class.
   li keeps padding-left as the gutter (indenting every wrapped line, not just the first); the
   marker is an absolutely positioned ::before, so text and inline children (legal.html mixes a
   <strong> label with plain text in one <li>) flow exactly like normal prose. */
.dot-list { margin: 0 0 0 24px; padding: 0; list-style: none; }
.dot-list li { position: relative; padding-left: 26px; line-height: 1.6; }
.dot-list li::before { content: ""; position: absolute; left: 2px; top: .42em; width: 6px; height: 11px; border: solid #CB4215; border-width: 0 2px 2px 0; transform: rotate(45deg); } /* 9/26 (Bethany): orange check marks (option B of MOCK process-bullets_2026-09-26) replace the dots */
.dot-list li + li { margin-top: 8px; }

/* 9/26 (Bethany): the "what we build" list is a row of outlined navy tags (option C of MOCK service-list_2026-09-26), same on desktop and phone; the orange-dot three-column grid and its phone overrides are gone */
.sp-wwb-list { list-style: none; margin: 0; padding: 0; display: flex; flex-wrap: wrap; gap: 10px; }
.sp-wwb-list li { padding: 9px 16px; border: 1px solid var(--sp-navy2, #224564); border-radius: 4px; color: var(--sp-navy2, #224564); font: 500 16px/1.2 "Jost", Arial, sans-serif; }

/* 4. who this is for: pale wash band, not navy */
.sp-who { background: var(--sp-wash); }
.sp-who.sp-section { padding-block: 64px; }
.sp-who .sp-wrap { display: grid; grid-template-columns: 1fr 1fr; gap: 64px; align-items: start; }
/* Photo locked to the text column's height (Bethany 2026-09-15): the wrapper takes its height
   from the grid row (set by the text column's natural height, since the wrapper's own only
   child is absolutely positioned and contributes none), so the photo never runs taller than
   the text. Same technique as .sp-open-photo-wrap / the homepage pillars photo. */
.sp-who-photo { position: relative; height: 100%; min-height: 320px; }
.sp-who-photo img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: center; display: block; }

/* 5. gallery: square corners throughout */
.sp-gallery { background: var(--site-white); padding-bottom: 64px; }
.sp-gallery-wide { display: block; width: 100%; aspect-ratio: 21 / 9; object-fit: cover; margin: 0 0 24px; }
.sp-gallery-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }
.sp-gallery-row img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }

/* 6. difference statement */
.sp-diff { background: var(--site-white); text-align: center; padding-top: 0; padding-bottom: 64px; }
.sp-diff > .sp-wrap { border-top: 1px solid rgba(127, 176, 220, .35); padding-top: 64px; }
.sp-diff h2 { margin: 0; font: 600 clamp(30px, 3vw, 40px)/1.15 "Jost", Arial, sans-serif; color: var(--sp-navy); }
.sp-diff .sp-eyebrow { margin: 20px 0; } /* 10/7 CSS sweep: the eyebrow's 20px top margin used to leak in from a general .sp-diff p rule written for a paragraph this section no longer has; that rule is gone and the spacing is written out here on the eyebrow's own rule. Same spacing as before */
/* Property Care has no gallery: Difference follows the wash band directly, so no hairline there */
.sp-who + .sp-diff > .sp-wrap { border-top: 0; }

/* 6.5 FAQ, standard section padding, sits between Difference and CTA */
.sp-faq.sp-section { padding-top: 0; }
.sp-faq > .sp-wrap { border-top: 1px solid rgba(127, 176, 220, .35); padding-top: 64px; }

/* 8. cta: retired 2026-09-14 (Bethany), the old pale-blue .sp-cta band. Replaced everywhere by .cta-share (see the CTA card rules above). */

/* responsive */
@media (max-width: 900px) {
  .sp-open-grid { grid-template-columns: 1fr; gap: 24px; }
  .sp-open-photo-wrap { order: -1; height: auto; aspect-ratio: 4 / 5; }
  .sp-who .sp-wrap { grid-template-columns: 1fr; gap: 24px; }
  .sp-who-photo { order: -1; height: auto; min-height: 0; aspect-ratio: 4 / 3; }
  .sp-gallery-row { gap: 16px; }
}
@media (max-width: 600px) {
  .sp-gallery-row { grid-template-columns: 1fr; }
}

/* Projects gallery + project page v1, 2026-09-14 */

/* ---- Project page template (TEMP project-page) ---- */
.proj-hero-wrap { background: var(--site-white); padding-top: 48px; }
/* Project opening two-column intro (Bethany 2026-09-14, Best Bower restructure): headline + intro
   paragraph left, one project photo right, ~1.05/.95 split, centered vertically against the photo so
   a short text block never floats at the top. */
.proj-open { padding: 64px 0; background: var(--site-white); }
.proj-open-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 56px; align-items: center; }
.proj-open-grid h2.sp-h2 { margin-bottom: 0; }
.proj-open-rule { width: 56px; height: 3px; margin: 10px 0 24px 0; background: #CB4215; }
/* 9/27 (Bethany): the short orange line goes under the OPENING heading of every page (service pages, Our Process, About, Contact; the homepage and project pages had it already), never under section headings */
.open-rule { width: 56px; height: 3px; margin: 10px 0 20px 0; background: #CB4215; }
.sp-h2:has(+ .open-rule), .about-intro h2:has(+ .open-rule), .contact-info h1:has(+ .open-rule) { margin-bottom: 0; }
.open-rule + .intro-copy, .open-rule + .contact-intro { margin-top: 0; }
.proj-open-text { max-width: none; }
/* Narrative sub-headings (Bethany 2026-09-14): "Project Scope" / "Getting to the Root" / "Cozy
   Courtyard" nest under their eyebrow as H3s, not full section H2s. Shared so every project page
   picks this up once it gets the .proj-open layout. */
.proj-block h3.sp-h3 { margin: 0 0 8px; font: 600 24px/1.2 "Jost", Arial, sans-serif; color: var(--sp-navy, #172D4A); }
.proj-open-photo-wrap { position: relative; height: 100%; min-height: 320px; overflow: hidden; } /* 9/28: clips the scaled opener photo (Patio with a View uses transform: scale(1.4)) so it cannot spill over the text */
.proj-open-photo-wrap img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; display: block; }
/* Fallback for pages whose opening copy is placeholder-short: fixed 3:2 photo instead of forced equal-height stretch */
.proj-open--fixed-ratio .proj-open-grid { align-items: center; }
.proj-open--fixed-ratio .proj-open-photo-wrap { height: auto; min-height: 0; aspect-ratio: 3 / 2; }
.proj-open--fixed-ratio .proj-open-photo-wrap img { position: static; width: 100%; height: 100%; }
@media (max-width: 900px) {
  .proj-open-grid { grid-template-columns: 1fr; gap: 24px; }
  .proj-open-photo-wrap { height: auto; min-height: 0; aspect-ratio: 3 / 2; }
}
/* Photos section (Bethany 2026-09-14, Best Bower restructure): the hero slider + thumbnails, moved
   below the narrative as their own full-width section instead of sitting under the title band. */
.proj-photos { padding-top: 80px; background: var(--site-white); }
.proj-photos > .sp-wrap > .sp-eyebrow { margin: 0 0 16px; }
.proj-photos .proj-hero-wrap { padding-top: 0; }
/* Section-to-section spacing (Bethany 2026-09-14, Best Bower restructure): a flat 80px between
   each section's visible content, measured edge to edge, with no two paddings stacking to make
   it more. .proj-open keeps its own 64px top/bottom as set; the neighbor on each side gives up
   just enough of its own padding so the two together total 80, never 80 plus that side's normal
   padding on top of it. Scoped with :has()/adjacency so no other page's .sp-title or .sp-section
   is affected. */
.sp-title:has(+ .proj-open) { padding-bottom: 16px; }
.proj-open + .sp-section { padding-top: 16px; }
.sp-section:has(+ .proj-photos) { padding-bottom: 0; }
/* Opening narrative spacing (2026-09-14): 64px from the hero thumbnail strip to the opening H2
   (overrides .sp-section's normal 96px top padding for the section right after the hero), and
   24px from that H2 down to the Before eyebrow (the H2 is that block's first child now that the
   headline sits above the eyebrow; .sp-h2's own 20px default stays everywhere else, including
   the After block, which still runs eyebrow then H2). */
.proj-hero-wrap + .sp-section { padding-top: 64px; }
.proj-block > .sp-h2:first-child { margin-bottom: 16px; }
/* 9/25: .sp-intro-copy retired; the two project pages that used it (smaller intro text, Bethany flagged) now use .sp-body-copy */

/* Project-page photo slider, 2026-09-14: 16/9 box (was 21/9; too wide, cropped too much off 4:3 and
   portrait photos, Bethany 2026-09-14), square corners, crossfade/pause pattern from the homepage
   hero (index.html .slides/.slide/.slide-controls), scoped under its own class
   names so it can share cape-interior-drafts.js safely with unrelated page elements.
   Dots replaced with a thumbnail strip below the box, 2026-09-14 (later same day). */
/* 9/28 a11y pass: screen-reader-only text (the slider's polite live region). Off-screen 1px box, no layout footprint. */
.visually-hidden { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; border: 0; }
.proj-hero-slider { position: relative; overflow: hidden; aspect-ratio: 16 / 9; outline-offset: 4px; }
.proj-hero-slides, .hero-slide { position: absolute; inset: 0; }
.hero-slide { opacity: 0; transition: opacity 800ms ease; }
.hero-slide.is-active { opacity: 1; z-index: 1; }
.hero-slide img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center; }
/* Portrait-orientation slide photos that genuinely can't crop to 16:9 (a tall subject like a full
   staircase, specimen tree, or a scenic full-frame shot): contain instead of cover. Bethany 2026-09-14
   (later same day): flat navy behind a contain photo reads as a narrow column, so the letterbox is now
   a blurred, darkened copy of the same photo instead of flat color. Set on the .hero-slide wrapper
   (not the img) via class="has-blur-bg" style="--slide-bg:url(...)" so the backdrop can sit behind the
   img in its own layer. */
.hero-slide img.contain { object-fit: contain; background: #0C1A2B; position: relative; z-index: 1; }
/* has-blur-bg slides: the img's own letterbox background must go transparent, or its opaque box
   (which is always the full 100%/100% slide area, contain or not) paints flat navy right over the
   blurred ::before layer sitting behind it (Bethany 2026-09-14, caught on first render). */
.hero-slide.has-blur-bg img.contain { background: transparent; }
.hero-slide.has-blur-bg { background: #0C1A2B; }
.hero-slide.has-blur-bg::before,
.hero-slide.has-blur-bg::after { content: ""; position: absolute; inset: 0; z-index: 0; }
.hero-slide.has-blur-bg::before { background: var(--slide-bg) center / cover no-repeat; filter: blur(24px); transform: scale(1.15); }
.hero-slide.has-blur-bg::after { background: rgba(12, 26, 43, .45); }
/* The lightbox on the Portfolio cards reuses this same markup but must stay exactly as it was
   (already contain, on its own 21/9 box, flat navy) -- never show the blurred backdrop there. */
.ptc-lightbox .hero-slide.has-blur-bg::before,
.ptc-lightbox .hero-slide.has-blur-bg::after { content: none; }
.hero-slide-controls { position: absolute; right: 20px; bottom: 20px; z-index: 10; display: flex; align-items: center; gap: 3px; opacity: .8; transition: opacity 180ms ease; }
.hero-slide-controls:hover, .hero-slide-controls:focus-within { opacity: 1; }
.hero-pause { display: grid; width: 34px; height: 34px; padding: 0; place-items: center; border: 1px solid color-mix(in srgb, var(--site-white) 65%, transparent); border-radius: 50%; background: rgba(23, 45, 74, .35); color: var(--site-white); font: 700 11px/1 "Jost", Arial, sans-serif; cursor: pointer; transition: border-color 160ms ease, background-color 160ms ease; }
.hero-pause:hover, .hero-pause:focus-visible { border-color: #518EC4; background: rgba(127, 176, 220, .35); }

/* Main-photo prev/next arrows (2026-09-18, restyle): white chevron on a 44px translucent navy
   circle, 60% opacity resting / 100% on hover-focus. Now rendered on the project page's own
   slider too (markup added 2026-09-18), not just the portfolio card lightbox. Generic part of the
   shared slider component; .ptc-lightbox overrides its own look further down (untouched). */
.hero-slide-arrow { position: absolute; top: 50%; transform: translateY(-50%); z-index: 10; background: color-mix(in srgb, var(--navy) 88%, transparent); border: none; color: var(--site-white); font-size: 22px; width: 44px; height: 44px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; opacity: .6; transition: opacity 150ms ease; }
.hero-slide-arrow:hover, .hero-slide-arrow:focus-visible { opacity: 1; }
.hero-slide-prev { left: 16px; }
.hero-slide-next { right: 16px; }

/* Thumbnail strip restyle (2026-09-18, owner reference): flush under the main photo, full width,
   thumbnails butted together with zero gap, no border, no radius, all one height, cover-cropped.
   Active thumb full color; the rest sit at 55% brightness via filter, nothing else layered on top
   (replaces the old per-thumb navy gradient wash + orange border-color active state). Scoped to
   the plain (non-lightbox) markup; .ptc-lightbox re-declares its own untouched look below. */
.proj-thumb-strip { position: relative; }
.proj-hero-thumbs { display: flex; flex-wrap: nowrap; gap: 0; margin: 0; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; -ms-overflow-style: none; }
.proj-hero-thumbs::-webkit-scrollbar { display: none; }
.hero-thumb { position: relative; flex: 0 0 auto; width: auto; height: 100px; aspect-ratio: 4 / 3; padding: 0; margin: 0; border: 0; border-radius: 0; outline: none; cursor: pointer; scroll-snap-align: start; filter: brightness(.55); transition: filter 160ms ease; }
.hero-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; }
.hero-thumb.is-active { filter: brightness(1); }
@media (max-width: 700px) {
  .hero-thumb { height: 72px; }
  /* 9/23 phone pass: pause button was 34px, under the ~44px touch target */
  .hero-pause { width: 44px; height: 44px; }
  /* 10/7 CSS sweep: a 44px .thumb-strip-arrow size sat here but never applied (the base rule below comes later and won); the 10/6 launch audit gave those arrows a 44px tap area through ::after with the drawn arrow kept at 32px, so the dead line is gone */
}
/* Thumbs-fill (2026-09-18): when the JS measures no overflow, each thumbnail grows to share the
   full strip width instead of sitting at its fixed size with empty space after it. */
.proj-hero-thumbs.thumbs-fill { gap: 0; }
.proj-hero-thumbs.thumbs-fill .hero-thumb { flex: 1 1 0; min-width: 0; width: auto; aspect-ratio: auto; height: 100px; }

/* Thumb-strip scroll arrows (2026-09-18): same navy-circle style as the main arrows, 32px, shown
   only when the strip overflows (measured on load/resize in cape-interior-drafts.js) and hidden
   via the [hidden] attribute otherwise. */
.thumb-strip-arrow { position: absolute; top: 50%; transform: translateY(-50%); z-index: 10; background: color-mix(in srgb, var(--navy) 88%, transparent); border: none; color: var(--site-white); font-size: 15px; width: 32px; height: 32px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; opacity: .6; transition: opacity 150ms ease; }
.thumb-strip-arrow:hover, .thumb-strip-arrow:focus-visible { opacity: 1; }
.thumb-strip-arrow[hidden] { display: none; }
.thumb-strip-arrow::after { content: ""; position: absolute; inset: -6px; border-radius: 50%; } /* 10/6 launch audit C6: the drawn arrow stays 32px; the tap area is 44px */
.thumb-strip-prev { left: 8px; }
.thumb-strip-next { right: 8px; }

/* .ptc-lightbox keeps its previous thumb-strip look untouched (2026-09-18): the resting navy
   gradient wash + orange active border that the base rules above no longer carry. */
.ptc-lightbox .hero-thumb::after { content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none; background: linear-gradient(to bottom, rgba(12, 26, 43, .45) 0%, rgba(12, 26, 43, .52) 40%, rgba(12, 26, 43, .62) 60%, rgba(12, 26, 43, .5) 100%); transition: opacity 200ms ease; }
.ptc-lightbox .hero-thumb:hover::after, .ptc-lightbox .hero-thumb:focus-visible::after { opacity: .5; }
.ptc-lightbox .hero-thumb.is-active { border: 2px solid #CB4215; }
.ptc-lightbox .hero-thumb.is-active::after { opacity: 0; }
@media (prefers-reduced-motion: reduce) {
  .hero-slide { transition: none; }
}

/* two-column project layout (left narrative, right sticky facts panel), 2026-09-14 */
.proj-layout { display: grid; grid-template-columns: 1.6fr 1fr; gap: 64px; align-items: start; }
.proj-left { max-width: 68ch; }
.proj-block + .proj-block { margin-top: 48px; }
.proj-panel { position: sticky; top: 120px; background: #FFF4EE; padding: 32px; }
.proj-panel-heading { margin: 0 0 16px; color: var(--sp-navy, #172D4A); font: 600 24px/1.2 "Jost", Arial, sans-serif; }
.proj-panel-block + .proj-panel-block { margin-top: 28px; }
.proj-panel .text-link { margin-top: 0; } /* 9/28 (Bethany): the Our process link sat 56px below Materials (block gap plus the link's own 28px); now it is one block like the others, under a How we build label */
.proj-panel-label { margin: 0 0 8px; color: var(--sp-orange, #CB4215); font: 600 15px/1 "Jost", Arial, sans-serif; letter-spacing: .08em; text-transform: uppercase; }
.proj-panel-value { margin: 0; padding-left: 20px; color: var(--sp-navy, #172D4A); font: 400 18px/1.5 "Jost", Arial, sans-serif; } /* 9/28 (Bethany): values indented 20px under their labels, her pick on MOCK facts-panel-indent */
.proj-panel-links { display: flex; flex-direction: column; gap: 10px; padding-left: 20px; }
.proj-panel-links a { display: inline-flex; align-items: center; color: #CB4215; font: 400 18px/1.4 "Jost", Arial, sans-serif; text-decoration: none; } /* 9/27 (Bethany): link text regular weight, the one site orange */
/* 9/28 (Bethany's rule): a link that stands on its own (in a list, under a gallery, in the facts panel) gets the sideways arrow; a link inside a sentence gets the underline and no arrow; the phone and email on Contact are the one exception (no arrow, her call 9/27) */
.proj-panel-links a::after { content: "\203A"; display: inline-block; margin-left: 8px; font-size: 1.15em; line-height: 1; color: currentColor; transition: transform 160ms ease; }
.proj-panel-links a:hover, .proj-panel-links a:focus-visible { color: #B23A0F; }
.proj-panel-links a:hover::after, .proj-panel-links a:focus-visible::after { transform: translateX(2px); }
@media (max-width: 900px) {
  .proj-layout { grid-template-columns: 1fr; gap: 32px; }
  .proj-left { max-width: none; }
  .proj-panel { position: static; top: auto; }
}

.proj-gallery-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-top: 20px; }
.proj-gallery-grid img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.proj-photo-caption { margin: 10px 0 0; color: var(--sp-sub, #3E5568); font: 400 15px/1.5 "Jost", Arial, sans-serif; }
.proj-gallery-trigger { display: block; padding: 0; border: 0; background: none; cursor: pointer; }

/* Lightbox for .proj-gallery-grid rows, 2026-09-14. Same visual pattern as portfolio-draft.html's
   own lightbox (deepest-navy overlay, round arrow buttons, close top-right) but its own class names
   and a shared, generic script in cape-interior-drafts.js, since portfolio-draft.html's version is
   page-local (inline style/script), not a shared mechanism. */
.proj-lightbox { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center; background: rgba(12, 26, 43, .92); }
.proj-lightbox[hidden] { display: none; }
.proj-lightbox-figure { margin: 0; display: flex; flex-direction: column; align-items: center; gap: 14px; max-width: 90vw; max-height: 90vh; }
.proj-lightbox-img { display: block; flex: 1 1 auto; min-height: 0; max-width: 90vw; max-height: 80vh; object-fit: contain; user-select: none; }
.proj-lightbox-caption { margin: 0; flex: 0 0 auto; color: var(--site-white); font: 400 15px/1.5 "Jost", Arial, sans-serif; text-align: center; }
.proj-lightbox-close { position: absolute; top: 20px; right: 24px; background: none; border: none; color: var(--site-white); font-size: 32px; cursor: pointer; padding: 8px; line-height: 1; opacity: .8; transition: opacity 150ms; }
.proj-lightbox-close:hover, .proj-lightbox-close:focus-visible { opacity: 1; }
.proj-lightbox-arrow { position: absolute; top: 50%; transform: translateY(-50%); background: color-mix(in srgb, var(--site-white) 12%, transparent); border: none; color: var(--site-white); font-size: 28px; width: 48px; height: 48px; border-radius: 50%; cursor: pointer; display: flex; align-items: center; justify-content: center; opacity: .8; transition: opacity 150ms, background 150ms; }
.proj-lightbox-arrow:hover, .proj-lightbox-arrow:focus-visible { opacity: 1; background: color-mix(in srgb, var(--site-white) 22%, transparent); }
.proj-lightbox-prev { left: 16px; }
.proj-lightbox-next { right: 16px; }

/* nested inside the "After" proj-block now, 2026-09-14: left-aligned, no outer shell padding of its own */
.proj-quote { background: var(--site-white); padding: 32px 0 0; }
.proj-quote-shell { width: 100%; margin-inline: 0; text-align: left; }
.proj-quote blockquote { margin: 0; }
.proj-quote blockquote p { margin: 0; font: 400 clamp(22px, 2.2vw, 30px)/1.4 "Jost", Arial, sans-serif; color: var(--sp-navy, #172D4A); }
.proj-quote blockquote footer { margin-top: 22px; font: 700 15px/1 "Jost", Arial, sans-serif; letter-spacing: .12em; text-transform: uppercase; color: #172D4A; /* 10/6 (Bethany): navy, same as the homepage band attribution */ }
/* 10/6 (Bethany): a homeowner quote in the opener block, under the opening paragraph: peach block, navy quote at body size, name in orange (her pick, MOCK project-quote-position_2026-10-06). Sits after the general .proj-quote rules so it wins; the plain .proj-quote stays for a quote in the After block. */
.proj-quote--opener { background: #FFF4EE; padding: 24px 28px; border-radius: 6px; margin-top: 24px; }
.proj-quote--opener blockquote p { font-size: 21px; }
.proj-quote--opener blockquote footer { margin-top: 14px; font-size: 13px; color: #CB4215; }

@media (max-width: 900px) { .proj-gallery-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 600px) {
  .proj-gallery-grid { grid-template-columns: 1fr; }
}

/* Portfolio "Browse by project type" cards (2026-09-14): five photo cards, homepage
   cape-cinematic-service visual language (navy gradient wash, orange 8% tint, centered
   white title with the same text-shadow, hover deepens wash + scales image 1.025), but
   built as its own small reusable class family (ptc-) rather than reusing the homepage's
   nth-child-specific cascade. 3-up then 2-up at 1320 shell width. */
/* 9/23 (Bethany): project and gallery cards restyled to match the homepage service cards exactly: 20px gap, no white border, the same soft shadow, the same rest wash (36% ends, 58% band under the label), the same hover (orange 35% over navy 30%, photo dimmed to 55%), the same label size. */
/* 9/23 (Bethany): five cards per grid with no empty slot: a 6-column grid, the first three cards span 2 columns each (a row of three), the last two span 3 each (a row of two, wider and shorter). Phone breakpoints below collapse it back to 2-up and 1-up. */
.ptc-grid { display: grid; grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 20px; margin-top: 32px; }
.ptc-grid > .ptc-card { grid-column: span 2; }
.ptc-grid > .ptc-card:nth-child(-n+2) { grid-column: span 3; aspect-ratio: 2 / 1; } /* 9/23 later (Bethany): the two wide cards on TOP, three below */
.ptc-card { position: relative; display: block; width: 100%; aspect-ratio: 4 / 3; overflow: hidden; border: 0; padding: 0; cursor: pointer; background: var(--navy); font: inherit; text-decoration: none; box-shadow: 0 10px 24px rgba(12, 26, 43, .16), 0 2px 6px rgba(12, 26, 43, .10); transition: box-shadow 500ms ease; }
.ptc-card:hover, .ptc-card:focus-visible { box-shadow: 0 16px 34px rgba(12, 26, 43, .24), 0 3px 8px rgba(12, 26, 43, .14); }
.ptc-card img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform 500ms cubic-bezier(.2,.7,.2,1), filter 300ms ease; }
/* 9/23 final: hover = the nav link wipe, same as the homepage service cards. #CB4215 at 85% fills the card from the top over 400ms; the flat navy rest wash (::after) stays underneath. */
.ptc-card::before { content: ""; position: absolute; left: 0; right: 0; top: 0; height: 0; z-index: 3; pointer-events: none; background: rgba(222, 74, 24, .85); transition: height 400ms ease; /* 9/28 (Bethany): hover wipe stays the original #DE4A18, her pick over the darker site orange */ } /* z-index 3: above the navy wash (::after, z 2), below the label (z 3, later in paint order) */
.ptc-card:hover::before, .ptc-card:focus-visible::before { height: 100%; }
@media (hover: none) { .ptc-card::before { display: none; } } /* 9/28 (Bethany): no orange wipe on touch screens; a tap fired it unreliably and it read as a glitch */
@media (prefers-reduced-motion: reduce) { .ptc-card::before { transition: none; } }
/* Rest wash = the old hover-darkness gradient (2026-09-14); hover no longer darkens navy further,
   it tints warm orange over a light navy base instead, while the photo zooms a touch more. */
/* 9/23 final (Bethany, from the hover-labels mockup): flat navy wash at rest, no mid band; project cards (a.ptc-card) hide their label until hover, category cards (button.ptc-card) keep theirs; phones show every label at the bottom over a light gradient. Photos are the toned (-tone.jpg) copies. */
.ptc-card::after { content: ""; position: absolute; inset: 0; z-index: 2; pointer-events: none; background: rgba(12, 26, 43, .25); transition: background 300ms ease; }
button.ptc-card::after { background: rgba(12, 26, 43, .62); } /* 9/26 (Bethany): category cards only get the homepage service card wash; project cards keep .25 */
.ptc-card:hover img, .ptc-card:focus-visible img { transform: scale(1.025); }
a.ptc-card .ptc-card-label { opacity: 0; }
a.ptc-card:hover .ptc-card-label, a.ptc-card:focus-visible .ptc-card-label { opacity: 1; }
@media (hover: hover) { .ptc-card:hover::after, .ptc-card:focus-visible::after { background: rgba(12, 26, 43, .45); } } /* 9/30 (Bethany): same navy under the orange wipe on every card type during hover */
@media (hover: hover) { button.ptc-card:hover::after, button.ptc-card:focus-visible::after { background: rgba(12, 26, 43, .45); } }
.ptc-card:hover .ptc-card-label, .ptc-card:focus-visible .ptc-card-label { text-shadow: none; }
.ptc-card-label { position: absolute; inset: 0; z-index: 3; display: flex; flex-direction: column; align-items: center; justify-content: center; margin: 0; padding: 0 20px; text-align: center; color: var(--site-white); font-family: "Jost", Arial, sans-serif; font-size: clamp(26px, 2.1vw, 34px); font-weight: 600; text-shadow: none; transition: opacity 300ms ease; } /* 9/26 (Bethany): no text shadow, same as the homepage service cards; the .62 wash carries the labels */
@media (hover: none), (max-width: 700px) {
  /* 9/23 later (Bethany: text hard to read on the phone cards): the lower half of the card goes to a solid navy band under the label, .20 at the top to .85 at the bottom (was .55) */
  .ptc-card::after { background: linear-gradient(to bottom, rgba(12, 26, 43, .20) 0%, rgba(12, 26, 43, .25) 45%, rgba(12, 26, 43, .70) 70%, rgba(12, 26, 43, .85) 100%); }
  a.ptc-card .ptc-card-label { opacity: 1; }
  .ptc-card .ptc-card-label { justify-content: flex-end; padding-bottom: 20px; font-size: clamp(24px, 6.5vw, 30px); opacity: 1; }
}
/* Second line for a card's town, when the label needs one (Community projects cards, 2026-09-14): same
   Jost family and text-shadow treatment as the name line, smaller and normal weight, small gap above it. */
.ptc-card-sub { display: block; margin-top: 6px; font-size: 18px; font-weight: 400; line-height: 1.5; } /* 9/23 (Bethany): same as the homepage service card subtext (18px) */
.ptc-card:focus-visible { outline: 2px solid var(--orange); outline-offset: 3px; }
@media (max-width: 900px) { .ptc-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } .ptc-grid > .ptc-card, .ptc-grid > .ptc-card:nth-child(-n+2) { grid-column: span 1; aspect-ratio: 4 / 3; } }
@media (max-width: 540px) { .ptc-grid { grid-template-columns: 1fr; } }

/* Card lightbox (2026-09-14): opens the SAME hero-slider/thumb-strip component the project
   page uses (.proj-hero-wrap/.proj-hero-slider/.hero-slide/.proj-hero-thumbs/.hero-thumb),
   rebuilt fresh into .ptc-lightbox-slot on each open (see initHeroSlider in cape-interior-drafts.js)
   so slide/thumb counts always match the clicked group; the project page's own slider is untouched. */
/* Desktop lightbox rebuilt (Bethany 2026-09-14, 2nd pass): fills the whole screen, no fixed
   16:9/21:9 box, opaque overlay, image contain-scaled so a portrait photo uses the full
   available height instead of the old fixed-aspect stage shrinking it down. Stage = viewport
   minus a 96px thumb strip and 24px margins on every other edge. Project page's own slider
   (same initHeroSlider component, different wrap) is untouched: none of this is scoped any
   wider than .ptc-lightbox. */
.ptc-lightbox { position: fixed; inset: 0; z-index: 9999; display: flex; align-items: center; justify-content: center; background: #0C1A2B; padding: 24px; }
.ptc-lightbox[hidden] { display: none; }
.ptc-lightbox-inner { width: 100%; height: 100%; max-width: none; }
.ptc-lightbox-slot { width: 100%; height: 100%; } /* the height:100% chain below needs every ancestor's height to be definite, including this otherwise-unstyled slot the wrap gets injected into */
.ptc-lightbox .proj-hero-wrap { width: 100%; height: 100%; background: none; padding-top: 0; display: flex; flex-direction: column; } /* explicit height, not flex-stretch: .proj-hero-slider's own children are all position:absolute and contribute no intrinsic height, so flex:1 on it needs a definite ancestor height to resolve against or it collapses to 0 */
.ptc-lightbox .proj-hero-slider { flex: 1 1 auto; min-height: 0; width: 100%; border: 0; background: transparent; aspect-ratio: auto; }
.ptc-lightbox .hero-slide img { object-fit: contain; }
/* Lightbox thumb strip (2026-09-14): a group's photo count varies, so unlike the project page's
   own thumb row (which fills the shell width evenly and never overflows), this strip becomes a
   horizontal scroller once thumbs don't fit, instead of clipping the last one; centers when they
   all fit. No background/box of any kind behind the row or the individual thumbs. */
.ptc-lightbox .proj-hero-thumbs {
  flex: 0 0 auto;
  height: 96px;
  margin-top: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scroll-padding-inline: 20px;
  scrollbar-width: thin;
  scrollbar-color: rgba(255, 255, 255, .35) transparent;
}
.ptc-lightbox .proj-hero-thumbs::-webkit-scrollbar { height: 6px; }
.ptc-lightbox .proj-hero-thumbs::-webkit-scrollbar-track { background: transparent; }
.ptc-lightbox .proj-hero-thumbs::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .35); border-radius: 3px; }
.ptc-lightbox .hero-thumb {
  filter: none; /* the lightbox keeps its own thumb look (2026-09-18): no brightness dimming, wash and active border via the ::after rules above */
  flex: 0 0 auto;
  width: auto;
  height: 84px;
  aspect-ratio: 4 / 3;
  scroll-snap-align: center;
  background: none; /* buttons carry a default UA background (~#efefef); showed through as a
    white/gray box around every thumb since the 4:3 box and the cover-fit image never quite
    agreed on every edge pixel */
  border: 2px solid transparent;
  border-radius: 0;
}
.ptc-lightbox .hero-slide-arrow { background: rgba(252, 253, 253, .82); color: #172D4A; opacity: 1; }
.ptc-lightbox .hero-slide-arrow:hover, .ptc-lightbox .hero-slide-arrow:focus-visible { background: var(--site-white); }
.ptc-lightbox .proj-hero-counter { position: absolute; top: 16px; left: 16px; z-index: 10; margin: 0; color: color-mix(in srgb, var(--site-white) 70%, transparent); font: 500 14px/1 "Jost", Arial, sans-serif; }
.ptc-lightbox-close { position: absolute; top: 20px; right: 24px; z-index: 10000; width: 44px; height: 44px; display: flex; align-items: center; justify-content: center; background: none; border: none; color: var(--site-white); font-size: 32px; cursor: pointer; padding: 0; line-height: 1; opacity: .8; transition: opacity 150ms; }
.ptc-lightbox-close:hover, .ptc-lightbox-close:focus-visible { opacity: 1; }

@media (max-width: 700px) {
  /* Browse-by-type lightbox on phone (Bethany 2026-09-14): fully opaque overlay, stage fills the
     viewport width with the image contained (no fixed 16:9/21:9 box, no white border, no extra
     letterboxing beyond what object-fit:contain itself needs), smaller edge-hugging arrows,
     smaller scrollable thumbs, borderless 44x44 close button. Desktop lightbox untouched. */
  .ptc-lightbox { background: #0C1A2B; padding: 0; }
  .ptc-lightbox-inner { width: 100%; max-width: none; }
  .ptc-lightbox .proj-hero-wrap { padding-top: 0; }
  .ptc-lightbox .proj-hero-slider {
    width: 100vw;
    aspect-ratio: auto;
    height: calc(100svh - 56px - 110px - 24px);
    border: 0;
    background: transparent;
  }
  .ptc-lightbox .hero-slide img { object-fit: contain; }
  .ptc-lightbox .hero-slide-arrow { width: 40px; height: 40px; font-size: 20px; background: rgba(252, 253, 253, .82); color: #172D4A; opacity: 1; } /* was a 12%-white circle with a white glyph (base rule): unreadable over photo content, only worked on the portrait slide's dark letterboxing. Solid-reading white circle + navy glyph shows on both photo and navy. */
  .ptc-lightbox .hero-slide-arrow:hover, .ptc-lightbox .hero-slide-arrow:focus-visible { background: var(--site-white); }
  .ptc-lightbox .hero-slide-prev { left: 8px; }
  .ptc-lightbox .hero-slide-next { right: 8px; }
  .ptc-lightbox .proj-hero-thumbs { gap: 8px; margin-top: 10px; }
  .ptc-lightbox .hero-thumb { flex: 0 0 72px; width: 72px; }
  .ptc-lightbox-close { top: 0; right: 0; width: 44px; height: 44px; padding: 0; display: flex; align-items: center; justify-content: center; border: 0; }
}

/* Sticky bottom action bar, v2 (Bethany 2026-09-15, new spec): phone-only, two buttons only
   (Call us / Text us), no CTA and no hamburger this time (the header's own hamburger stays the
   only menu toggle). Markup is injected once at the end of <body> by cape-nav.js, guarded
   against duplicate injection, hidden here via CSS above 700px and while the footer is in view
   (footer-in-view IntersectionObserver toggles .is-hidden, also in cape-nav.js) or a lightbox
   is open (body.ptc-lightbox-open, reuses the existing flag). The in-flow .cta-share-card stays
   visible on the page too, this bar is purely a persistent call/text shortcut. The footer's
   56px bar clearance lives with the other phone footer rules above. */
@media (max-width: 700px) {
  .phone-cta-bar {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 40;
    display: flex;
    align-items: center;
    gap: 12px;
    height: 56px;
    padding: 12px;
    background: #224564;
    border-top: 1px solid rgba(252, 253, 253, .25);
    transition: transform 220ms ease;
  }
  .phone-cta-bar.is-hidden { transform: translateY(100%); }
  .phone-cta-bar .pcb-btn {
    flex: 1 1 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 40px;
    padding: 0 12px;
    border: 1px solid var(--site-white); /* was 2px (Bethany 2026-09-15 follow-up) */
    border-radius: 6px;
    background: transparent;
    color: var(--site-white);
    font-family: "Jost", Arial, sans-serif;
    font-size: 15px;
    font-weight: 600;
    letter-spacing: .04em;
    text-transform: uppercase;
    text-decoration: none;
    transition: background 180ms ease, color 180ms ease;
  }
  .phone-cta-bar .pcb-btn:hover, .phone-cta-bar .pcb-btn:active, .phone-cta-bar .pcb-btn:focus-visible {
    background: var(--site-white);
    color: #224564;
  }
  .phone-cta-bar .pcb-icon { flex: 0 0 auto; width: 18px; height: 18px; }
  .phone-cta-bar .pcb-btn { position: relative; }
  .phone-cta-bar .pcb-btn::after { content: ""; position: absolute; inset: -3px 0; } /* 10/6 launch audit C6: the drawn button stays 40px tall; the tap area is 44px */
}
@media (min-width: 701px) {
  .phone-cta-bar { display: none; }
}
body.ptc-lightbox-open .phone-cta-bar { display: none; }

/* 9/23: plain in-text link (link blue, underlined); .text-link stays the arrow CTA style. Moved here from about.html so project pages can use it. */
.inline-link { color: inherit; text-decoration: underline; text-decoration-color: rgba(203, 66, 21, .6); text-decoration-thickness: 0.5px; text-underline-offset: 4px; font-weight: 400; } /* 9/27 (Bethany): never bold */ /* 9/27 (Bethany): option A of MOCK inline-link, copy color with a thin orange underline so it sits in the sentence */
.inline-link:hover, .inline-link:focus-visible { color: #B23A0F; }

/* 9/24: click-to-play YouTube block on project pages (Bethany): poster from the project's own photos, iframe loads only on click */
.proj-video { position: relative; aspect-ratio: 16 / 9; overflow: hidden; border-radius: 6px; background: #172D4A; margin-top: 20px; }
.proj-video img, .proj-video iframe { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; border: 0; display: block; }
.proj-video-play { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; padding: 0; background: rgba(23, 45, 74, .18); border: 0; cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background 180ms ease; }
.proj-video-play:hover, .proj-video-play:focus-visible { background: rgba(23, 45, 74, .32); }
.proj-video-play span { width: 84px; height: 84px; border-radius: 50%; background: #CB4215; display: flex; align-items: center; justify-content: center; box-shadow: 0 6px 24px rgba(0,0,0,.35); }
.proj-video-play span::before { content: ""; display: block; width: 0; height: 0; border-style: solid; border-width: 16px 0 16px 28px; border-color: transparent transparent transparent #FCFDFD; margin-left: 6px; }
.proj-video.is-playing img, .proj-video.is-playing .proj-video-play { display: none; }
@media (hover: none), (max-width: 700px) { .proj-video-play span { width: 68px; height: 68px; } }

/* 9/27 (Bethany): "See it built" on the service pages. Two portfolio-style project cards above the gallery photos, each with a caption under it; the gallery photos themselves link to the matching Portfolio gallery. */
.sp-related-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin: 0 0 56px; }
.sp-related-card { aspect-ratio: 2 / 1; }
.sp-related-card::after { background: none; } /* no navy wash on these: over the toned photos it read green (Bethany 9/27); the phone rule below restores the band under the label */
@media (hover: hover) { .sp-related-card:hover::after, .sp-related-card:focus-visible::after { background: none; } } /* 9/29 (Bethany): hover rules only where a real hover exists; a phone tap counted as hover and dropped the label band */ /* the orange ::before wipe carries the hover, same as the portfolio */
.sp-related-cap { margin: 10px 0 0; color: #172D4A; font: 600 18px/1.3 "Jost", Arial, sans-serif; }
.sp-related-cap span { margin-left: 6px; color: #3E5568; font: 400 15px/1.3 "Jost", Arial, sans-serif; }
.sp-gallery a:has(> img) { display: block; }
.sp-gallery-links--phone { display: none; } /* 9/28 (Bethany): the gallery photos link to the Portfolio gallery, but phones have no hover to show it, so a text link shows under the photos at phone widths only */
@media (hover: none), (max-width: 700px) { .sp-gallery-links--phone { display: flex; margin-top: 20px; } }
@media (max-width: 700px) { .sp-related-grid { grid-template-columns: 1fr; gap: 24px; margin-bottom: 44px; } }
@media (hover: none), (max-width: 700px) {
  .sp-related-cap { display: none; } /* the card label is always on at phone widths, so the caption would repeat it */
  .sp-related-card::after { background: linear-gradient(to bottom, rgba(12, 26, 43, .20) 0%, rgba(12, 26, 43, .25) 45%, rgba(12, 26, 43, .70) 70%, rgba(12, 26, 43, .85) 100%); } /* same band as the portfolio cards, so the label reads */
}
