/* ============================================================
   Visible Graphics — shared site styles
   Single source of truth for the site-wide design rules Janine
   approved: deep-green title blocks, UPPERCASE hero headings,
   green accents, no eyebrow dashes, black body text.

   Linked AFTER each page's inline <style> so these win on the
   cascade. Change the palette or hero treatment here once and it
   updates every page that links this file.
   ============================================================ */

:root {
  /* Color policy — canonical values, override per-page inline vars */
  --navy:        #536872;  /* slate: section hairlines, gallery active tab, hamburger bars */
  --navy-deep:   #536872;  /* work-item card bg placeholder (NOT the footer — see footer rule below) */
  --terracotta:  #536872;  /* THE accent, for LIGHT surfaces. Janine's Option B slate, 27 Jul 2026.
                            5.70:1 on cream. Headings accent word, checks, donate buttons, links.
                            History: was olive #5E6C5B, before that #153732, before that #2F5233. */
  --accent-light:#96ABB5;  /* alias of --accent-on-dark; kept so any stray reference still lands right */
  --accent-on-dark:#96ABB5; /* THE accent, for DARK surfaces (grey band, charcoal hero, black footer).
                            4.76:1 on #3A3A3A, 7.11:1 on #0E1F20, 8.79:1 on black. See TEAL-SWEEP.md. */
  --ink:         #000000;  /* all heading + body text on light backgrounds */
  --slate-text:  #000000;
  --slate-soft:  #000000;

  /* ---- Grays (15 Jul meeting: "one light gray, one mid gray", defined once) ----
     --gray-bg   neutral light gray for section backgrounds. Deliberately neutral so it
                 reads as distinct from the warm --cream-warm #F4EFE6 beige.
     --gray-text mid gray for SECONDARY text only (labels, captions, meta). Body copy and
                 headings stay black per the approved policy above — do not repaint them.
                 7.0:1 on white, passes WCAG AA and AAA for normal text. */
  --gray-bg:   #F2F2F0;
  --gray-text: #5A5A57;

  /* ---- Dark neutral grey for the dark sections (Review 23 Jul, sections 3 & 4a) ----
     One consistent mid-dark neutral grey replaces the teal --ion-grad on the contact
     form band (all pages) and the dark-green homepage work section. Cream text on it
     measures ~11:1. */
  --section-dark: #3A3A3A;

  /* ---- Standardized vertical section rhythm ("spacings must be exact") ----
     The site had 12 different section paddings (120/140/90/84/80/70/56/54px, several
     asymmetric like `120px 0 100px`). Collapsed to a symmetric 3-step scale. Applied to
     the shared section classes at the bottom of this file. */
  --section-pad-y:    clamp(80px, 8vw, 120px);   /* major sections */
  --section-pad-y-md: clamp(64px, 6vw, 88px);    /* secondary sections */
  --section-pad-y-sm: clamp(48px, 4.5vw, 64px);  /* compact rows */
}

/* ---- Eyebrow kickers: no leading dash anywhere on the site ---- */
.eyebrow::before { content: none !important; }
.eyebrow { gap: 0 !important; padding-left: 0 !important; }

/* ---- Page hero = charcoal title block (Ken's original), UPPERCASE heading ----
   Literal hexes (not var(--navy)/var(--terracotta)) so only the hero blocks
   shift — footer, CTA, checks, citations keep the current green.
   Values sampled from Ken's original work.html (.wk-hero): bg --navy-deep #0E1F20,
   heading --cream #FEFCF6. The accent/eyebrow was olive #5E6C5B at 3.05:1 (failing);
   Q41 resolved 27 Jul 2026 — now #96ABB5, the on-dark slate, at 7.11:1. */
.page-hero { background: #0E1F20; }
.page-hero .eyebrow { color: #96ABB5; }
.page-hero h1 {
  color: #FEFCF6;
  text-transform: uppercase;   /* caps via CSS — HTML keeps normal case */
}
.page-hero h1 .accent { color: #96ABB5; }  /* on-dark slate accent word */
.page-hero .lead,
.page-hero .intro,
.page-hero p { color: rgba(255, 255, 255, 0.82); }  /* any hero paragraph reads light on the dark block (.intro listed so it beats a page's inline .page-hero .intro rule) */


/* ============================================================
   PHASE 1 — global palette and chrome (15 Jul meeting)
   ============================================================ */

/* ---- Footer: green -> BLACK on every page ----
   Targeted at the footer only, NOT done by repointing --navy-deep, because that
   variable also backs .work-item card backgrounds (same as Ken's .wk-card) and
   those are not changing. */
footer { background: #000000; }

/* Footer: Janine 28 Jul — nothing in the footer stays blue. The column headings
   ("Explore", "Capabilities", "Hours") and the phone/email links all go pure
   white on black (21:1). The address links carry no inline colour any more, so
   this file is the single place that governs them. */
footer .footer-col h5 { color: #FFFFFF; }  /* (0,1,2) to beat the pages' own .footer-col h5 (0,1,1) — no !important needed */
footer .address a { color: #FFFFFF; }
footer .address a:hover { color: rgba(255, 255, 255, 0.75); }

/* ---- Header bar + logo (Review 23 Jul, section 2a) ----
   Taller header bar, and the logo made MUCH bigger so it nearly fills the bar
   height (almost touching top/bottom). Small vertical nav padding relative to a
   large logo is what makes the logo "fill" the bar. The logo is a 2.5:1 wordmark
   (1200x480), so height drives it; width stays auto so nav links keep their room.
   Header height ~= 2*pad + logo:  desktop 2*11 + 122 = 144px; scrolled 2*8 + 96 = 112px.
   Nav-fit at 1440/1280 verified visually (screenshots) this session. */
.nav { padding-top: 11px; padding-bottom: 11px; }
.nav.scrolled { padding-top: 8px; padding-bottom: 8px; }
.nav-logo img { height: 122px; }
.nav.scrolled .nav-logo img { height: 96px; }
@media (max-width: 1024px) {
  .nav-logo img { height: 92px; }
  .nav.scrolled .nav-logo img { height: 74px; }
}
@media (max-width: 720px) {
  .nav-logo img { height: 66px; }
  .nav.scrolled .nav-logo img { height: 56px; }
}

/* ---- Hero clearance under the fixed header ----
   The nav is position:fixed, so every hero needs top padding greater than the
   bar's height or its first line disappears behind it. The bar is now ~145px
   (was ~132px), and the page-hero padding was only 90-96px — the hero eyebrow
   was rendering BEHIND the header on all five .page-hero pages (caught in the
   1440px screenshot review, not by DOM checks). Padding now clears the bar at
   every breakpoint: 145 -> 190, 114 -> 150, 88 -> 120. */
.page-hero { padding-top: 190px; }
.hero { padding-top: 190px; }
@media (max-width: 1024px) {
  .page-hero { padding-top: 150px; }
  .hero { padding-top: 150px; }
}
@media (max-width: 720px) {
  .page-hero { padding-top: 120px; }
  .hero { padding-top: 120px; }
}

/* ---- Standardized section rhythm ----
   Symmetric padding from the 3-step scale above, replacing the 12 ad-hoc values.
   Horizontal alignment to the left content edge is already handled consistently by
   .container (max-width + var(--gutter)); these rules only regularize the vertical. */
.industries,
.process,
.services,
.work,
.contact-cta,
.testimonials { padding: var(--section-pad-y) 0; }

.stats,
.sec,
.sof-section,
.logos { padding: var(--section-pad-y-md) 0; }

.credentials,
.svc-row,
.capabilities .cap-row { padding: var(--section-pad-y-sm) 0; }

/* ---- Hero heading overflow at narrow widths ----
   Pre-existing bug, surfaced by the Phase 1 QA sweep: .page-hero h1 is
   clamp(44px, 6vw, 84px), so below ~730px the 44px floor takes over and stops
   scaling. Combined with the approved UPPERCASE hero treatment, the About page's
   accent word "DEPENDABILITY" measured 375px inside a 350px content box at 390px
   wide — 5px of horizontal scroll on the whole document.
   Lowering the floor below 420px keeps it one unbroken word (39px at 390px wide,
   ~332px), which is still a large bold hero. overflow-wrap is a last-resort guard
   so no future long word can reintroduce horizontal scroll. */
@media (max-width: 420px) {
  .page-hero h1 { font-size: clamp(36px, 10vw, 44px); }
}
.page-hero h1 { overflow-wrap: break-word; }

/* ---- "Squished" sections: fluid type reached full size far too late ----
   The fluid clamps were tuned so their max only engages around 1500-1600px wide:
   .stat-number 6vw hits 92px at 1533px, .work-item-client 2vw hits 32px at 1600px,
   .hero-sub 1.3vw at 1538px, .section-header-right p 1.2vw at 1500px. A 1280px
   laptop therefore rendered everything 7-20% below full size (work card names were
   the worst, 25.6px vs 32px) — which is the compacted look Janine flagged.

   Raising the vw coefficient so each reaches its max at 1280px instead, and lifting
   the floors so narrow screens aren't tiny either. Max values are unchanged, so
   nothing gets larger than it was designed to be on a wide monitor — mid-size
   screens simply stop being shortchanged. */
.stat-number            { font-size: clamp(64px, 7.2vw, 92px); }
/* Homepage work-card titles brought down toward the gallery caption scale
   (Janine 23 Jul rev 3c). Was clamp(24px, 2.5vw, 32px) — roughly double the
   gallery's .g-name 15px on tiles of a comparable width. The category line
   under it was already 11px on both, matching. See QUESTIONS.md Q35. */
.work-item-client       { font-size: clamp(16px, 1.45vw, 19px); }
.hero-sub               { font-size: clamp(18px, 1.56vw, 20px); }
.section-header-right p { font-size: clamp(17px, 1.4vw, 18px); }

/* ============================================================
   PHASE 4 — Services page
   ============================================================ */

/* ---- Alternating light beige / dark beige section contrast ----
   The two content sections did alternate, but between --cream #FEFCF6 and
   --cream-warm #F4EFE6 — a 3% step that reads as one flat surface. Making the
   alternation explicit and deliberate: light beige for the default section,
   the deeper --cream-deep #E7E0D2 for .warm. Both are existing palette values,
   so nothing new was invented. */
.sec       { background: var(--cream); }
.sec.warm  { background: var(--cream-deep); }

/* ---- Capability rows: square crop, image and text flush ----
   The DreamWorks photo Janine referred to is the monument sign in capability
   row 2 (assets/services/design-engineering.jpg, 923x1200 portrait). Every
   cap-media image was being forced into a fixed 340px-tall landscape box, so
   these portrait originals were cropped hard through the middle — on the
   DreamWorks sign that cut off the logo.

   Square crop fixes that and squares the rows off against their text. Applied
   to all five rows rather than DreamWorks alone, because one square image among
   four landscape ones would read as a mistake; scoping it to just that row is a
   one-line change if Janine wants it. See QUESTIONS.md Q15.

   Gutter tightened 48px -> 32px and the row set to stretch so the photo and its
   text block line up rather than floating at different heights. */
.capabilities .cap-row { gap: 32px; align-items: stretch; }
.capabilities .cap-media { display: flex; }
.capabilities .cap-media img { aspect-ratio: 1 / 1; height: auto; width: 100%; object-fit: cover; }
.capabilities .cap-text { align-self: center; }

/* ============================================================
   PHASE 5 — About page
   ============================================================ */

/* ---- Uniform team photo crop ----
   Both tiers already used a circular object-fit:cover crop, so photos were
   uniform within each tier. Restated here as the single place that governs it,
   and pinned with aspect-ratio so a non-square source can never distort.
   The two tiers keep their different diameters (leads 156px, roster 100px) —
   that hierarchy is deliberate and TASKS.md doesn't ask for it to go. See Q16. */
.team-photo,
.team-roster li img {
  aspect-ratio: 1 / 1;
  object-fit: cover;
  border-radius: 50%;
  background: var(--cream-deep);
}

/* ---- About lede: two-column, heading left / body right (Review 23 Jul, 7b) ----
   Mirrors Ken's .about-intro-grid: big heading on the left, all body copy
   (paragraphs + motto + Our Story box) in the right column. */
.about-lede-grid { display: grid; grid-template-columns: 1fr 1.3fr; gap: 70px; align-items: start; }
.about-lede-head h2 {
  font-family: 'Archivo', sans-serif; font-weight: 900;
  font-size: clamp(32px, 3.6vw, 52px); letter-spacing: -0.03em; line-height: 1.05;
  color: var(--ink); max-width: 12ch; margin: 0;
}
/* Skechers Thousand Oaks, in the left column under the heading — the spot Janine
   drew in image7.png of the 28 Jul revisions. Natural 1:1 aspect, no crop, no
   caption (her sketch shows none). */
.about-lede-figure { margin: 28px 0 0; border-radius: 6px; overflow: hidden; }
.about-lede-figure img { width: 100%; height: auto; display: block; }

.about-lede-body .reading { max-width: none; }      /* fill the column, not 800px */
.about-lede-body .motto { margin: 28px 0; font-size: clamp(22px, 2.4vw, 32px); }
.about-lede-body .story-card { max-width: none; }
@media (max-width: 900px) {
  .about-lede-grid { grid-template-columns: 1fr; gap: 28px; }
  .about-lede-head h2 { max-width: none; }
  .about-lede-figure { max-width: 420px; }
}

/* ---- Gray/black heading treatment ----
   Names stay black; the secondary role line drops to the shared mid gray so the
   two read as a hierarchy. vg-styles forces --slate-soft to #000000 sitewide,
   which was making role text exactly as heavy as the name above it.
   --gray-text is 7.0:1 on the cream background, comfortably AA. */
.team-roster li span { color: var(--gray-text); }

/* ============================================================
   PHASE 6 — Statement of Faith
   ============================================================ */

/* ---- "Click to Donate" buttons ----
   Slate on cream: 5.70:1, comfortably AA. Cards are flex columns so every
   button sits on the card's bottom edge regardless of blurb length, keeping the
   row tidy. margin-top:auto does the aligning. */
.partner-card { display: flex; flex-direction: column; }
.partner-card p { margin-bottom: 20px; }

.donate-btn {
  margin-top: auto;
  align-self: flex-start;
  background: var(--terracotta);
  color: var(--cream);
  font-family: 'Archivo', sans-serif;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.12em;
  padding: 13px 22px;
  border-radius: var(--corner);
  display: inline-flex;
  align-items: center;
  gap: 9px;
  transition: background 0.25s ease, transform 0.25s ease;
}
.donate-btn::after { content: '\2192'; transition: transform 0.25s ease; }
.donate-btn:hover { background: var(--ink); transform: translateY(-1px); }
.donate-btn:hover::after { transform: translateX(3px); }
.donate-btn:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }

.donate-intro p { margin-bottom: 0; }

/* ============================================================
   PHASE 7 — shared "Contact Us" form (all pages, above the footer)
   Markup only. Netlify Forms handles submission after deploy; there is
   deliberately no JS here, and it will NOT submit in local preview.
   ============================================================ */

.contact-form-wrap { max-width: 720px; }
.contact-form-heading {
  font-family: 'Archivo', sans-serif;
  font-weight: 900;
  font-size: clamp(24px, 2.4vw, 32px);
  letter-spacing: -0.02em;
  color: var(--cream);
  margin-bottom: 24px;
}

/* Netlify honeypot — must exist in the DOM but never be seen or focusable. */
.cf-hp { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.cf-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 18px 20px; margin-bottom: 28px; }
.cf-field { display: flex; flex-direction: column; }
.cf-field-full { grid-column: 1 / -1; }

.cf-field label {
  font-family: 'Archivo', sans-serif;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--cream);          /* on the dark CTA gradient */
  margin-bottom: 8px;
}
.cf-req { color: var(--accent-on-dark); }

/* Inputs are near-white with black text: 19:1, and readable on the dark panel. */
.cf-field input,
.cf-field textarea {
  font-family: 'DM Sans', sans-serif;
  font-size: 16px;              /* 16px stops iOS zooming the page on focus */
  line-height: 1.5;
  color: var(--ink);
  background: var(--cream);
  border: 2px solid transparent;
  border-radius: var(--corner);
  padding: 14px 16px;
  width: 100%;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.cf-field textarea { resize: vertical; min-height: 110px; }

.cf-field input:hover,
.cf-field textarea:hover { border-color: #536872; }  /* 2px border against a cream input, so it takes the dark value */
.cf-field input:focus,
.cf-field textarea:focus {
  outline: none;
  border-color: #536872;
  box-shadow: 0 0 0 3px rgba(150, 171, 181, 0.35);  /* ring spreads onto the dark band, so it keeps the light tint */
}
/* Only flag invalid fields the user has actually interacted with.
   :user-invalid is the correct selector here — plain :invalid would paint all
   four required fields red the moment the page loads, and the
   :not(:placeholder-shown) trick does nothing because these inputs carry no
   placeholder attribute, so it evaluates true on an empty field. */
.cf-field input:user-invalid,
.cf-field textarea:user-invalid { border-color: #C2452D; }

.contact-form .contact-cta-btn { border: none; cursor: pointer; }

@media (max-width: 620px) {
  .cf-grid { grid-template-columns: 1fr; }
}

/* ============================================================
   REVIEW 23 JUL — sections 3 & 4a: dark-green bands -> grey
   ============================================================ */
/* 4a: homepage "Brands you know / Built by us" work section was --navy green.
   Card captions stay white (the cards carry their own image + dark overlay). */
.work { background: var(--section-dark); }

/* 3: contact form band, all pages */
.contact-cta { background: var(--section-dark); }
/* the decorative corner circle was a green tint — neutralise it on grey */
.contact-cta::before { background: rgba(255, 255, 255, 0.05); }
/* headline accent word ("visible") was mint + a green glow; on grey read it cream */
.contact-cta h2 .accent { color: var(--cream); text-shadow: none; }

/* ============================================================
   REVISION 4 (Janine 23 Jul) — marquee logos normalised by VISUAL WEIGHT
   A single shared height made wide wordmarks dominate and compact marks
   vanish: at 56px tall BODYROK rendered 425px wide while Mike's Red Tacos
   was 49px — an 8.7x spread in apparent size.
   Heights are now set per logo from its aspect ratio so the rendered AREA
   is roughly constant (h ~ 1/sqrt(aspect)), which is what the eye actually
   reads as "the same size". Widest/narrowest spread drops to about 1.6x.
   Opacity also lifted 0.78 -> 1 for legibility, as asked.
   Selectors key off the filename so both the visible set and the duplicated
   (aria-hidden) loop copy are covered.
   ============================================================ */
.logos-track img { opacity: 1; height: 54px; }
.logos-track img:hover { opacity: 1; }

/* Janine 3 Aug (separate email): Wendy's, El Pollo Loco and Skechers replaced
   with the files she sent. All three are horizontal lockups, where the old
   three were compact/stacked marks, so their aspect ratios changed a lot and
   their heights are re-derived from the same rule, not carried over:
     wendys        1.50 -> 3.45     el-pollo-loco  1.78 -> 3.62
     skechers      1.78 -> 10.99  (the old file's 1.78 was a lie — see below)
   The new derivatives are trimmed to the ink, so canvas aspect == mark aspect
   and the rule now measures the mark itself rather than the mark plus padding. */

/* very wide wordmarks — shortest */
/* 25px, not the 27px the equal-area rule alone gives: checked side by side
   against BODYROK, the other very-wide mark, Skechers is a much bolder wordmark
   and read heavier than everything around it at 27. Same ~7% trim the 23 Jul
   pass applied to BODYROK for the same reason. */
.logos-track img[src*="skechers"]         { height: 25px; }  /* aspect 11.0 */
.logos-track img[src*="bodyrok"]          { height: 30px; }  /* 7.6 */
.logos-track img[src*="salt-straw"]       { height: 42px; }  /* 4.4 */
.logos-track img[src*="prince-st-pizza"]  { height: 50px; }  /* 3.9 */
.logos-track img[src*="el-pollo-loco"]    { height: 47px; }  /* 3.6 */
.logos-track img[src*="zankou-chicken"]   { height: 50px; }  /* 3.6 */
.logos-track img[src*="wendys"]           { height: 48px; }  /* 3.5 */
.logos-track img[src*="carl-s-jr"]        { height: 52px; }  /* 3.2 */
/* mid — the reference size */
.logos-track img[src*="jamba"]            { height: 54px; }  /* 2.7 */
.logos-track img[src*="krispy-kreme"]     { height: 54px; }  /* 2.7 */
/* compact / square marks — tallest so they carry equal weight */
.logos-track img[src*="blaze-pizza"]      { height: 64px; }  /* 1.8 */
.logos-track img[src*="arbys"]            { height: 72px; }  /* 1.2 */
.logos-track img[src*="daves-hot-chicken"]{ height: 74px; }  /* 1.0 */
.logos-track img[src*="mikes-red-tacos"]  { height: 72px; }  /* 0.87 */

/* The Coffee Bean crop fix (rev 3b, .work-item-5 img object-position) was removed
   28 Jul 2026: the homepage work grid is now uncropped masonry like the gallery,
   so there is no 1:1 cover crop left to re-frame. */

/* ---- todo-hidden ----
   Per CLAUDE.md: placeholder content that must exist in the markup but must not
   render until the client supplies the missing detail. Used by the two new-employee
   cards on About and by three gallery photos with no identifying brand or location
   (see QUESTIONS.md Q3 and Q12). Removing the class is all it takes to publish them.
   Uses display:none rather than visibility so no empty grid cell is left behind. */
.todo-hidden { display: none !important; }

/* ---- Gallery: wider container so the grid extends closer to the edges ----
   (Review 23 Jul, section 9). Bigger max-width + modest side padding = fuller
   page. Only the grid section is widened (scoped to .gallery-main), not the
   charcoal hero. 4:3 crops and caption style unchanged. */
.gallery-main .container {
  max-width: 1720px;
  padding-left: clamp(20px, 3vw, 44px);
  padding-right: clamp(20px, 3vw, 44px);
}

/* ============================================================
   REVISION 6b (Janine 23 Jul) — gallery masonry, NO cropped photos
   The grid was a 3-col CSS grid with every tile forced to aspect-ratio 4/3
   and object-fit:cover, so tall/vertical shots were cut off. Now a
   CSS-columns masonry: uniform column widths, each tile keeps its own
   natural aspect ratio, heights vary, nothing is cropped.
   break-inside:avoid stops a tile splitting across a column boundary.
   ============================================================ */
.g-grid {
  display: block;
  column-count: 3;
  column-gap: 16px;
}
.g-item {
  break-inside: avoid;
  -webkit-column-break-inside: avoid;
  page-break-inside: avoid;
  display: block;
  width: 100%;
  margin: 0 0 16px;
  aspect-ratio: auto;          /* release the old forced 4/3 */
  overflow: hidden;
  position: relative;
  cursor: zoom-in;             /* lightbox affordance (6d) */
}
.g-item img {
  width: 100%;
  height: auto;                /* natural aspect — the whole photo shows */
  object-fit: fill;
  display: block;
}
@media (max-width: 900px) { .g-grid { column-count: 2; } }
@media (max-width: 620px) { .g-grid { column-count: 1; } }

/* The Products page photo rules (Revision 8: .products-media / .products-figure)
   were removed 28 Jul 2026 with the Dave's Hot Chicken photo they existed for —
   nothing else on the site used them. The Sony Studios shot in the products hero
   is now the page's only photo and carries its own .products-hero-shot rules in
   that page's inline block. The image file itself stays in assets/, still used
   by the gallery. */

/* ---- Lightbox (Revision 6d) ---- */
.lb {
  position: fixed; inset: 0; z-index: 1000;
  display: none; align-items: center; justify-content: center;
  background: rgba(0, 0, 0, 0.92);
  padding: 4vmin;
}
.lb.is-open { display: flex; }
.lb-stage { margin: 0; max-width: 100%; max-height: 100%; display: flex; flex-direction: column; gap: 14px; }
.lb-img {
  max-width: 100%;
  max-height: 82vh;
  width: auto; height: auto;
  object-fit: contain;          /* never crop in the lightbox */
  display: block; margin: 0 auto;
  border-radius: 3px;
  background: #111;
}
.lb-cap { text-align: center; display: flex; flex-direction: column; gap: 4px; }
.lb-name {
  font-family: 'Archivo', sans-serif; font-weight: 700; font-size: 17px; color: #fff;
}
.lb-loc {
  font-family: 'Archivo', sans-serif; font-size: 11px; font-weight: 700;
  letter-spacing: 0.14em; text-transform: uppercase; color: var(--accent-on-dark);
}
.lb button {
  position: absolute; background: rgba(255, 255, 255, 0.1); color: #fff;
  border: 1px solid rgba(255, 255, 255, 0.28); cursor: pointer;
  width: 48px; height: 48px; border-radius: 50%;
  font-size: 26px; line-height: 1; display: flex; align-items: center; justify-content: center;
  transition: background 0.2s ease, border-color 0.2s ease;
}
.lb button:hover { background: rgba(255, 255, 255, 0.22); border-color: #fff; }
.lb button:focus-visible { outline: 3px solid var(--accent-on-dark); outline-offset: 3px; }
.lb-close { top: 18px; right: 18px; }
.lb-prev { left: 18px; top: 50%; transform: translateY(-50%); }
.lb-next { right: 18px; top: 50%; transform: translateY(-50%); }
@media (max-width: 620px) {
  .lb-prev { left: 8px; } .lb-next { right: 8px; }
  .lb button { width: 42px; height: 42px; }
}
.g-item:focus-visible { outline: 3px solid var(--terracotta); outline-offset: 3px; }

/* ---- Gallery section heading ---- */
.g-heading {
  font-family: 'Archivo', sans-serif;
  font-weight: 900;
  font-size: clamp(30px, 3.6vw, 48px);
  letter-spacing: -0.03em;
  color: var(--ink);
  margin-bottom: 26px;
}

/* ---- Gray utilities ----
   Reusable so the gray treatment stays identical wherever it is applied
   (Phases 4-6). Body text and headings stay black. */
.gray-section { background: var(--gray-bg); }
.gray-label   { color: var(--gray-text); }

/* ============================================================
   REVIEW 23 JUL — section 10: Statement of Faith
   ============================================================ */
/* 10a: reduce the large gap between the charcoal hero and the first body text */
.page-hero + .sof-section { padding-top: 40px; }

/* 10b: scripture pullquotes — smaller verse text, shifted left (less indent) */
.pullquote { padding-left: 16px; }
/* Client 6 Aug (final polish): the verses should read "in line with the other
   sentences". The clamp is now flat at 18px — the same size as .reading body
   prose on this page, at every width. That is the clamp's own minimum, so this
   only removes the growth above 1161px (23px -> 21px on 3 Aug, now 18px).
   The pullquote stays a pullquote by every other means: Archivo 700 against the
   body's DM Sans 400, --terracotta against black, the 3px left rule, and its
   40px vertical margins. Citation stays 13px — dropping the verse to 18px did
   not leave it looking oversized. */
.pullquote p { font-size: 18px; }

/* ============================================================
   REVIEW 23 JUL — section 8b/8c: Services capability bands
   Each service is its own full-width band with an alternating beige
   background and a CONTAINED two-column row (text one side, image the
   other, alternating). Fixes the previous flush-left / oversized-image
   break, which was caused by the rows sitting in an undefined `.wrap`
   (no max-width, no padding) instead of a container.
   These rules sit after the Phase-4 and section-rhythm rules above, so
   they win the cascade over the old cap-row/cap-media declarations.
   ============================================================ */
.cap-band { padding: clamp(56px, 6vw, 84px) 0; }
.cap-light { background: var(--cream-warm); }   /* light beige */
.cap-dark  { background: var(--cream-deep); }   /* darker beige */

/* ---- Q33 resolved 27 Jul 2026: capability checkmarks on the dark beige band ----
   The accent slate --terracotta #536872 measures 4.45:1 against .cap-dark's
   --cream-deep #E7E0D2, just under the 4.5 these 15px ticks need. A one-step
   darker slate fixes it: #46586A is 5.58:1 on the dark beige and 6.40:1 on the
   light. Applied to BOTH bands so every tick on the page stays one colour —
   scoping it to .cap-dark alone would leave the two bands visibly mismatched.
   Deliberately a literal, not a palette token: this is a single-selector
   contrast correction, not a new brand colour.
   Specificity (0,2,1) matches the page's own .capabilities .cap-list li::before,
   and this file loads later, so it wins without !important. */
.capabilities .cap-list li::before { color: #46586A; }

.capabilities .cap-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(32px, 5vw, 70px);
  align-items: center;
  padding: 0;
  border-top: none;
}
/* correct alternation (the page's inline .reverse rules were duplicated and
   cancelled out): reverse row -> image left, text right */
.capabilities .cap-row.reverse .cap-text  { order: 2; }
.capabilities .cap-row.reverse .cap-media { order: 1; }

/* image ~half the container width, moderate 4:3 like Ken's .svc-visual —
   not the viewport-filling square the Phase-4 rule + inline heights produced */
.capabilities .cap-media { display: block; }
.capabilities .cap-media img {
  width: 100%;
  aspect-ratio: 4 / 3;
  height: auto;
  object-fit: cover;
  border-radius: 6px;
  display: block;
}

@media (max-width: 860px) {
  .capabilities .cap-row { grid-template-columns: 1fr; gap: 24px; }
  /* when stacked, image always below the text regardless of reverse */
  .capabilities .cap-row.reverse .cap-text  { order: 1; }
  .capabilities .cap-row.reverse .cap-media { order: 2; }
}

/* ---- section 8d: process section = Ken's layout ----
   Heading left + intro right (section-header), then FOUR bordered cards in one
   row, each with a small dash at the top, no numbers. Wraps 2x2 then 1-col. */
/* Ken 3 Aug: the intro paragraph beside this heading is removed (his X in
   image8 covers the whole paragraph). .section-header's 1fr/1.5fr split would
   otherwise reserve an empty right column, so this header collapses to one
   column. The h2 keeps its 15ch max-width, so it renders in exactly the same
   place and at the same wrap as before — only the phantom column goes. */
.process-header { margin-bottom: 48px; align-items: end; grid-template-columns: 1fr; }
.process-header .section-header-left h2 {
  font-family: 'Archivo', sans-serif; font-weight: 900;
  font-size: clamp(30px, 3.4vw, 46px); letter-spacing: -0.03em; line-height: 1.05;
  color: var(--ink); max-width: 15ch;
}
.process-header .section-header-right p { font-size: clamp(16px, 1.2vw, 18px); line-height: 1.6; color: var(--slate-text); max-width: 46ch; }
.process-grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: 20px; background: none; border: 0; margin-top: 0; }
.process-grid-4 .process-card { background: var(--cream); border: 1px solid var(--gray-line); border-radius: 4px; padding: 26px 24px; }
.process-dash { width: 36px; height: 3px; background: var(--terracotta); margin-bottom: 16px; }
.process-grid-4 .process-card h3 { font-family: 'Archivo', sans-serif; font-weight: 800; font-size: 19px; letter-spacing: -0.01em; color: var(--ink); margin-bottom: 12px; }
.process-grid-4 .process-card p { font-size: 15px; line-height: 1.6; color: var(--slate-soft); }
@media (max-width: 980px) { .process-grid-4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .process-grid-4 { grid-template-columns: 1fr; } }

/* ============================================================
   MOBILE NAV — production fix, 8 Aug 2026
   The hamburger has been inert since launch: at <=960px the page CSS hides
   .nav-links and shows .nav-hamburger, but no JavaScript was ever attached to
   it and no open state existed anywhere, so the button was decorative markup
   and mobile visitors had no navigation beyond the logo and the footer links.
   Confirmed at runtime on all 7 pages — getEventListeners returned NONE and a
   real touch tap changed nothing.

   .nav-links becomes the dropdown panel itself rather than a new element, so
   the markup is untouched and the links keep their existing type treatment.
   The panel hangs off .nav (position:fixed, so it is the positioning ancestor)
   and is revealed by .nav-open on that same .nav.
   Loaded after each page's inline block, so `display:flex` here beats the
   inline `@media (max-width:960px){ .nav-links{display:none} }`.
   ============================================================ */
@media (max-width: 960px) {
  .nav-links {
    display: flex;
    flex-direction: column;
    position: absolute;
    top: 100%;                 /* directly under the bar, follows .nav.scrolled */
    left: 0; right: 0;
    gap: 0;
    margin: 0;
    padding: 4px var(--gutter) 12px;
    /* Opaque, NOT the bar's rgba(255,255,255,.92): the panel hangs over page
       content (on the homepage, a dark hero photo) and has to stay readable. */
    background: #FFFFFF;
    border-bottom: 1px solid var(--gray-line);
    box-shadow: 0 18px 40px -24px rgba(0, 0, 0, 0.45);
    max-height: calc(100vh - 100%);
    overflow-y: auto;
    /* closed */
    opacity: 0;
    visibility: hidden;
    transform: translateY(-8px);
    pointer-events: none;
    transition: opacity .25s ease, transform .25s ease, visibility .25s;
  }
  .nav.nav-open .nav-links {
    opacity: 1;
    visibility: visible;
    transform: none;
    pointer-events: auto;
  }
  .nav-links li { width: 100%; }
  .nav-links a {
    display: block;
    padding: 16px 0;
    font-size: 15px;
    border-bottom: 1px solid var(--gray-line);
  }
  .nav-links li:last-child a { border-bottom: none; }
  /* the hover underline sweep is a desktop affordance; it reads as a stray rule
     under a stacked list, and there is no hover on touch anyway */
  .nav-links a::after { display: none; }

  /* hamburger morphs to a close X so the control shows its own state */
  .nav-hamburger span { transition: transform .25s ease, opacity .2s ease; }
  .nav.nav-open .nav-hamburger span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
  .nav.nav-open .nav-hamburger span:nth-child(2) { opacity: 0; }
  .nav.nav-open .nav-hamburger span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }
}
