/* ===========================================================================
   Blue Ocean Marketing — shared client-site stylesheet.

   ONE file, served to every client site and cached across all of them. There
   is nothing site-specific in here: each site's palette arrives as a `:root`
   override emitted inline by layout.twig from that site's `theme` row, which
   is why every color below that could vary by brand is a var() rather than
   a literal.

   The literals that remain are deliberate: white text and dark shadows over
   a darkened hero photo stay legible on any brand, so they are not themeable.

   The values here are only a fallback for a page rendered without its theme
   block. App\Utils\Content::DEFAULT_THEME is the authority and doubles as the
   allowlist of themeable tokens — keep the two in sync.
   =========================================================================== */
:root {
    --bg: #0f1419;
    --panel: #1a2332;
    /* One step darker than --panel, for insets that need to read as "sunk
       into" a dark section: code blocks and form fields. */
    --panel-deep: #0b1018;
    --text: #e7ecf3;
    --muted: #8b9bb4;
    --accent: #3d8bfd;
    /* Whatever stays readable ON --accent. Split out from a hardcoded #fff so
       a client with a pale brand (a bright yellow, say) can flip it to a dark
       value and keep every button, pill and CTA band legible. */
    --accent-contrast: #ffffff;
    --border: #2a3548;
    --error: #f66;
    /* Review stars. Not brand-derived — a gold star is a gold star. */
    --star: #f5b942;
    /* Light-section tokens — used by the alternating light bands
       (services, work, reviews, FAQ) between the dark hero/about/
       quote sections. Kept separate from the dark --bg/--panel/etc.
       above rather than swapping the whole theme. */
    --light-bg: #f7f8fa;
    --light-panel: #ffffff;
    --light-text: #1a2332;
    --light-muted: #5b6b84;
    --light-border: #e7ebf0;
    /* A third, visibly-darker-than-light-bg gray step — used for
       one section (see .section-mid) so the page isn't just a
       strict light/dark checkerboard; still light-family (dark
       text stays readable), just a clear shade down from
       --light-bg. */
    --mid-bg: #dde2e8;
    --mid-border: #c7cedb;
}
* { box-sizing: border-box; }
body {
    margin: 0;
    font-family: system-ui, -apple-system, Segoe UI, Roboto, sans-serif;
    background: var(--bg);
    color: var(--text);
    line-height: 1.5;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
}
a { color: var(--accent); text-decoration: none; }
a:hover { text-decoration: underline; }
header {
    position: sticky;
    top: 0;
    z-index: 100;
    background: var(--light-panel);
    color: var(--light-text);
    border-bottom: 1px solid var(--light-border);
    box-shadow: 0 1px 2px rgba(15, 20, 25, 0.06);
}
.header-inner {
    max-width: 1200px;
    margin: 0 auto;
    padding: 0.75rem 1.5rem;
    min-height: 76px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1.5rem;
    /* A long business name doesn't always fit next to the
       hamburger on narrow viewports (the phone pill itself moves
       into the nav dropdown at that width — see .nav-phone-cta —
       so it's just these two on mobile). Rather than truncating
       the name, let it wrap onto a second line instead. */
    flex-wrap: wrap;
}
header .brand {
    display: inline-flex;
    align-items: center;
    gap: 0.65rem;
}
header .brand:hover { text-decoration: none; }
/* logo_display: 'logo' | 'both' | 'text' (default) — see
   App\Utils\Content::business() for the fallback logic and
   content.php's business.logo/business.logo_display for how to
   set it per site. */
header .brand-logo {
    display: block;
    height: 40px;
    width: auto;
    flex-shrink: 0;
}
header .brand-text {
    font-size: 1.25rem;
    font-weight: 800;
    letter-spacing: -0.01em;
    color: var(--light-text);
    line-height: 1.25;
}
header nav {
    display: flex;
    align-items: center;
    gap: 1.75rem;
    font-size: 0.95rem;
    font-weight: 600;
}
header nav a {
    color: var(--light-muted);
    transition: color 0.15s ease;
}
header nav a:hover {
    color: var(--light-text);
    text-decoration: none;
}
header .phone-cta {
    display: inline-flex;
    align-items: stretch;
    border-radius: 10px;
    overflow: hidden;
    animation: rocking 2s infinite;
    animation-timing-function: ease-out;
}
header .phone-cta a {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    background: var(--accent);
    color: var(--accent-contrast);
    font-weight: 700;
    font-size: 0.9rem;
    white-space: nowrap;
    transition: background 0.15s ease;
}
header .phone-cta a:hover {
    filter: brightness(0.85);
    text-decoration: none;
}
header .phone-cta svg { flex-shrink: 0; }
header .phone-cta-call { padding: 0.7rem 1.1rem 0.7rem 1.35rem; }
header .phone-cta-text {
    padding: 0.7rem 1.1rem;
    border-left: 1px solid rgba(255, 255, 255, 0.25);
}
/* Second .phone-cta lives inside the mobile nav dropdown (see
   .nav-phone-cta below) — hidden by default so it doesn't also
   show inline in the desktop nav row; the mobile media query
   below swaps which of the two instances is visible. */
header nav .phone-cta { display: none; }
.nav-phone-cta {
    display: none;
    justify-content: center;
    padding: 1rem 1.5rem;
    border-top: 1px solid var(--light-border);
}
@keyframes rocking {
    0%   { transform: rotate(0deg); }
    25%  { transform: rotate(0deg); }
    50%  { transform: rotate(2deg); }
    75%  { transform: rotate(-2deg); }
    100% { transform: rotate(0deg); }
}
@media (prefers-reduced-motion: reduce) {
    header .phone-cta { animation: none; }
}

/* Mobile nav toggle — pure CSS (checkbox hack), no script/CSP nonce needed */
header .nav-toggle { display: none; }
header .nav-toggle-label {
    display: none;
    cursor: pointer;
    padding: 0.5rem;
    /* margin-left: auto (not a fixed 0) keeps this pinned to the
       right edge even when .header-inner wraps it onto its own
       line (e.g. brand + logo leaves no room next to it) —
       without it, a lone wrapped flex item lands at the left
       edge of its line, not the right. */
    margin: -0.5rem -0.5rem -0.5rem auto;
}
header .nav-toggle-label span,
header .nav-toggle-label span::before,
header .nav-toggle-label span::after {
    display: block;
    width: 22px;
    height: 2px;
    background: var(--light-text);
    position: relative;
    transition: transform 0.15s ease, opacity 0.15s ease;
}
header .nav-toggle-label span::before { content: ''; position: absolute; top: -7px; }
header .nav-toggle-label span::after { content: ''; position: absolute; top: 7px; }
header .nav-toggle:checked ~ .nav-toggle-label span { background: transparent; }
header .nav-toggle:checked ~ .nav-toggle-label span::before { transform: translateY(7px) rotate(45deg); }
header .nav-toggle:checked ~ .nav-toggle-label span::after { transform: translateY(-7px) rotate(-45deg); }

@media (max-width: 860px) {
    header nav {
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        background: var(--light-panel);
        border-bottom: 1px solid var(--light-border);
        box-shadow: 0 4px 8px rgba(15, 20, 25, 0.06);
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        max-height: 0;
        overflow: hidden;
        transition: max-height 0.2s ease;
    }
    header nav a {
        padding: 0.9rem 1.5rem;
        border-top: 1px solid var(--light-border);
    }
    header .nav-toggle:checked ~ nav { max-height: 400px; }
    header .nav-toggle-label { display: block; }
    /* Swap which .phone-cta shows: the header-row one (used on
       desktop, next to the inline nav) hides, and the one inside
       the dropdown (.nav-phone-cta, last item in <nav>) takes
       over — avoids fighting a second wrapped header row for
       something that already has a natural home in the dropdown. */
    .header-inner > .phone-cta { display: none; }
    header nav .phone-cta { display: flex; }
    .nav-phone-cta { display: flex; }
}
@media (max-width: 480px) {
    header .phone-cta-call span { display: none; }
    header .phone-cta-call { padding: 0.7rem 0.9rem; }
}

.hero {
    background-image: linear-gradient(135deg, var(--bg) 0%, var(--panel) 100%);
    background-size: cover;
    background-position: center;
    background-repeat: no-repeat;
    padding: 5rem 1.5rem 4rem;
    text-align: left;
}
.hero-inner {
    max-width: 1200px;
    margin: 0 auto;
    display: grid;
    grid-template-columns: 1.15fr 0.85fr;
    gap: 3rem;
    align-items: center;
}
.hero-eyebrow {
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.8rem;
    font-weight: 700;
    color: #fff;
    margin: 0 0 1rem;
    text-shadow: 0 0 8px rgba(0, 0, 0, 0.7), 0 2px 4px rgba(0, 0, 0, 0.6);
}
.hero-headline {
    font-size: clamp(2rem, 4.5vw, 3.25rem);
    line-height: 1.15;
    font-weight: 800;
    margin: 0 0 1.25rem;
    color: #fff;
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.55);
}
.hero-subheadline {
    font-size: 1.1rem;
    line-height: 1.6;
    color: #fff;
    max-width: 560px;
    margin: 0 0 2rem;
    text-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
}
.hero-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 1rem;
    margin-bottom: 2.5rem;
}
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 0.85rem 1.75rem;
    border-radius: 10px;
    font-weight: 700;
    font-size: 1rem;
    white-space: nowrap;
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.btn:hover { text-decoration: none; }
.btn-primary { background: var(--accent); color: var(--accent-contrast); }
/* Derived from --accent rather than `filter: brightness()`: brightness
   darkens a mid-tone brown or green into mud, which is why the Grinstead
   site under _template had to replace this rule with a hand-picked hex and
   lost the automatic hover shade. color-mix keeps one --accent change
   re-toning the whole site. */
.btn-primary:hover { background: color-mix(in srgb, var(--accent) 85%, black); }
.btn-outline {
    background: transparent;
    color: #fff;
    border: 1.5px solid var(--border);
}
.btn-outline:hover { border-color: var(--accent); color: var(--accent); }
.hero-stats {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-start;
    gap: 2.5rem;
}
.hero-stat { display: flex; flex-direction: column; align-items: flex-start; }
.hero-stat-value {
    font-size: 1.5rem;
    font-weight: 800;
    color: #fff;
    text-shadow: 0 2px 8px rgba(0, 0, 0, 0.5);
}
.hero-stat-label {
    font-size: 0.8rem;
    color: #fff;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    margin-top: 0.25rem;
    text-shadow: 0 1px 5px rgba(0, 0, 0, 0.55);
}

/* Reusable light-card lead-capture form — used in the hero's Contact
   Us card and on /contact-us (see app/views/_lead_form.twig). No
   existing light-on-dark component to reuse (unlike .section-light,
   which is a full-width band, not a floating card), so this is
   purpose-built. Reuses the --light-* tokens for consistency with
   the rest of the site's light surfaces. */
.lead-form-card {
    background: var(--light-panel);
    color: var(--light-text);
    border-radius: 14px;
    padding: 2rem;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.35);
}
.lead-form-heading { font-size: 1.5rem; font-weight: 800; margin: 0 0 0.5rem; color: var(--light-text); }
.lead-form-intro { font-size: 0.9rem; color: var(--light-muted); margin: 0 0 1.25rem; }
.lead-form { display: flex; flex-direction: column; gap: 1rem; }
/* Honeypot — see _lead_form.twig and App\Utils\FormGuard. Taken out of the
   layout entirely rather than hidden with visibility/opacity, so it can never
   flash on a slow paint or occupy space. Not `display:none` on the input
   itself: some bots specifically skip those, and the point is that a bot
   believes this field is real. */
.lead-form-hp {
    position: absolute;
    left: -9999px;
    width: 1px;
    height: 1px;
    overflow: hidden;
}
.lead-form label {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    font-size: 0.85rem;
    font-weight: 600;
    color: var(--light-text);
}
.lead-form-optional { font-weight: 400; color: var(--light-muted); }
.lead-form input,
.lead-form textarea {
    background: var(--light-bg);
    border: 1px solid var(--light-border);
    border-radius: 8px;
    padding: 0.65rem 0.75rem;
    color: var(--light-text);
    font: inherit;
}
.lead-form input::placeholder,
.lead-form textarea::placeholder { color: var(--light-muted); }
.lead-form .error { color: var(--error); font-size: 0.85rem; margin: 0; }
.lead-form-submit { width: 100%; }
.lead-form-disclaimer {
    font-size: 0.75rem;
    color: var(--light-muted);
    margin: 1rem 0 0;
    text-align: center;
}
/* Standalone /contact-us page: no card chrome (see contact.twig) —
   just the bare form, same width the card used to constrain it to,
   centered in the section. */
.lead-form-wrap { max-width: 480px; margin: 0 auto; }
/* .lead-form's inputs default to --light-bg for contrast against
   .lead-form-card's white (--light-panel) background. On a bare
   .section-light band (--light-bg itself), invert that so inputs
   still stand out against the section. */
.section-light .lead-form input,
.section-light .lead-form textarea { background: var(--light-panel); }
/* .contact-form defaults to dark-panel colors (its usual home is a
   dark .card); override for use inside a light section. */
.section-light .contact-form label { color: var(--light-muted); }
.section-light .contact-form input,
.section-light .contact-form textarea {
    background: var(--light-panel);
    border-color: var(--light-border);
    color: var(--light-text);
}
@media (max-width: 900px) {
    .hero-inner { grid-template-columns: 1fr; }
}
@media (max-width: 600px) {
    .hero { padding: 3.5rem 1.25rem 3rem; }
    .hero-actions { flex-direction: column; align-items: stretch; }
    .hero-stats { gap: 1.5rem 2rem; }
}

/* Full-bleed homepage sections below the hero — alternating light/dark
   bands, each a direct sibling of main (see the "sections" Twig
   block below), not constrained by main's narrow 720px column. */
.section { padding: 5rem 1.5rem; }
.section-inner { max-width: 1200px; margin: 0 auto; }
.section-light { background: var(--light-bg); color: var(--light-text); }
.section-dark { background: var(--bg); color: var(--text); }
.section-mid { background: var(--mid-bg); color: var(--light-text); }
.section-header {
    max-width: 640px;
    margin: 0 auto 3rem;
    text-align: center;
}
.section-header-split {
    max-width: none;
    margin: 0 0 2.5rem;
    text-align: left;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1.5rem;
}
.section-header-split .section-heading { margin-bottom: 0; }
.section-eyebrow {
    text-transform: uppercase;
    letter-spacing: 0.08em;
    font-size: 0.8rem;
    font-weight: 700;
    color: var(--accent);
    margin: 0 0 0.75rem;
}
.section-heading {
    font-size: clamp(1.75rem, 3.5vw, 2.5rem);
    font-weight: 800;
    line-height: 1.2;
    margin: 0 0 1rem;
}
.section-intro { font-size: 1.05rem; line-height: 1.6; opacity: 0.72; margin: 0; }
/* .btn-outline defaults to white/dark-border for the hero (see above);
   override for use on a light section so it reads against a light bg. */
.section-light .btn-outline,
.section-mid .btn-outline { color: var(--light-text); border-color: var(--light-border); }
@media (max-width: 640px) {
    .section { padding: 3.5rem 1.25rem; }
    .section-header-split { flex-direction: column; align-items: flex-start; }
}
.section-inner.section-inner-narrow { max-width: 760px; }
/* /privacy-policy and /terms-and-conditions body content (see
   _policy_body.twig / App\Utils\PolicyRenderer) — the only things
   in this template that render bare h2/h3/ul, so scoping to
   .section-inner-narrow (also used by FAQ, which renders neither)
   is safe. */
.section-inner-narrow h2 { font-size: 1.3rem; font-weight: 700; margin: 2rem 0 0.75rem; }
.section-inner-narrow h3 { font-size: 1.05rem; font-weight: 700; margin: 1.5rem 0 0.5rem; }
.section-inner-narrow p { line-height: 1.6; margin: 0 0 1rem; }
.section-inner-narrow ul { margin: 0 0 1rem; padding-left: 1.25rem; line-height: 1.6; }
.section-inner-narrow li { margin-bottom: 0.4rem; }
.section-cta { text-align: center; margin: 2rem 0 0; }

/* Bottom-of-homepage CTA band (see home.twig) — solid accent fill,
   distinct from both --bg/--light-bg, so it reads as a deliberate
   "stop scrolling, take action" band after the rest of the page. */
.cta-section { background: var(--accent); color: var(--accent-contrast); }
.cta-section .section-heading,
.cta-section .section-intro { color: var(--accent-contrast); }
.cta-section .section-intro { opacity: 0.92; }
.cta-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1rem;
    margin-top: 2rem;
}
/* Same .phone-cta component as the header (see header .phone-cta
   above and _phone_cta.twig), inverted: white pill/accent text
   instead of accent pill/white text, since this section's own
   background is already the accent color. No rocking animation
   here (that's scoped to `header .phone-cta` only) — a bottom-of-
   page CTA doesn't need the attention-grabbing motion. */
.cta-section .phone-cta {
    display: inline-flex;
    align-items: stretch;
    border-radius: 10px;
    overflow: hidden;
}
.cta-section .phone-cta a {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    /* Inverted pill sitting on the accent band: the two colors are each
       other's opposites, so both come from the pair rather than one being a
       literal white that stops matching once --accent-contrast changes. */
    background: var(--accent-contrast);
    color: var(--accent);
    font-weight: 700;
    font-size: 0.9rem;
    white-space: nowrap;
    transition: background 0.15s ease;
}
.cta-section .phone-cta a:hover { background: color-mix(in srgb, var(--accent) 10%, var(--accent-contrast)); text-decoration: none; }
.cta-section .phone-cta svg { flex-shrink: 0; }
.cta-section .phone-cta-call { padding: 0.7rem 1.1rem 0.7rem 1.35rem; }
.cta-section .phone-cta-text {
    padding: 0.7rem 1.1rem;
    border-left: 1px solid color-mix(in srgb, var(--accent) 25%, transparent);
}

/* Services grid */
.services-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 320px));
    justify-content: center;
    gap: 1.5rem;
}
.service-card {
    background: var(--light-panel);
    border: 1px solid var(--light-border);
    border-radius: 12px;
    padding: 2rem 1.75rem;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.service-card:hover { box-shadow: 0 8px 24px rgba(15, 20, 25, 0.08); transform: translateY(-2px); }
.service-icon {
    width: 48px;
    height: 48px;
    border-radius: 10px;
    background: color-mix(in srgb, var(--accent) 10%, transparent);
    color: var(--accent);
    display: flex;
    align-items: center;
    justify-content: center;
}
.service-icon svg { width: 24px; height: 24px; }
.service-card-image {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: 8px;
    display: block;
}
.service-card h3 { margin: 0.25rem 0 0; font-size: 1.15rem; font-weight: 700; }
.service-card p { margin: 0; color: var(--light-muted); font-size: 0.95rem; line-height: 1.55; flex: 1; }
.btn-block { width: 100%; margin-top: 0.25rem; }

/* About */
.about-grid {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 3rem;
    align-items: center;
}
.about-media {
    aspect-ratio: 4 / 3;
    border-radius: 12px;
    background: var(--panel) center/cover no-repeat;
    border: 1px solid var(--border);
}
.about-copy .section-heading { margin-bottom: 1.25rem; }
.about-copy .section-intro { opacity: 0.85; }
@media (max-width: 800px) {
    .about-grid { grid-template-columns: 1fr; }
    .about-media { order: -1; }
}

/* Service area map */
.map-embed {
    aspect-ratio: 16 / 9;
    border-radius: 12px;
    overflow: hidden;
    border: 1px solid var(--border);
}
.map-embed iframe { display: block; width: 100%; height: 100%; border: 0; }
.section-light .map-embed { border-color: var(--light-border); }
.section-mid .map-embed { border-color: var(--mid-border); }

main { max-width: 720px; margin: 2rem auto; padding: 0 1.5rem; flex: 1; width: 100%; }
[id] { scroll-margin-top: 96px; }
.card {
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1.5rem;
    margin-bottom: 1rem;
}
h1 { margin-top: 0; font-size: 1.75rem; }
.muted { color: var(--muted); font-size: 0.9rem; }
ul.link-list { list-style: none; padding: 0; margin: 0; }
ul.link-list li { padding: 0.75rem 0; border-bottom: 1px solid var(--border); }
ul.link-list li:last-child { border-bottom: none; }
.section-light ul.link-list li { border-color: var(--light-border); }
.product-list-item { display: flex; gap: 1rem; align-items: flex-start; }
.product-thumb {
    width: 64px;
    height: 64px;
    object-fit: cover;
    border-radius: 8px;
    border: 1px solid var(--border);
    flex-shrink: 0;
    display: block;
}
.section-light .product-thumb { border-color: var(--light-border); }
.product-hero-image {
    width: 100%;
    max-height: 520px;
    object-fit: contain;
    background: var(--light-panel);
    border-radius: 8px;
    border: 1px solid var(--light-border);
    display: block;
    margin-bottom: 1rem;
}
code {
    background: var(--panel-deep);
    padding: 0.15rem 0.4rem;
    border-radius: 4px;
    font-size: 0.9em;
}
.contact-form { display: flex; flex-direction: column; gap: 0.85rem; }
.contact-form label {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    font-size: 0.9rem;
    color: var(--muted);
}
.contact-form input,
.contact-form textarea {
    background: var(--panel-deep);
    border: 1px solid var(--border);
    border-radius: 6px;
    padding: 0.6rem;
    color: var(--text);
    font: inherit;
}
.contact-form button {
    align-self: flex-start;
    background: var(--accent);
    color: var(--accent-contrast);
    border: none;
    border-radius: 6px;
    padding: 0.6rem 1.25rem;
    font: inherit;
    cursor: pointer;
}
.contact-form .error { color: var(--error); font-size: 0.9rem; margin: 0; }
.gallery-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 0.75rem;
}
.gallery-item { color: inherit; }
.gallery-item:hover { text-decoration: none; }
.gallery-item img {
    width: 100%;
    aspect-ratio: 1 / 1;
    object-fit: cover;
    border-radius: 8px;
    border: 1px solid var(--border);
    display: block;
}
.review-list {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1.25rem;
}
.review-card {
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 1.25rem;
}
.review-card p { margin: 0.4rem 0; }
.stars { color: var(--star); letter-spacing: 0.1em; }
.faq-list details {
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 0.85rem 1rem;
    margin-bottom: 0.6rem;
}
.faq-list summary { cursor: pointer; font-weight: 600; }
.faq-list p { margin: 0.6rem 0 0; color: var(--muted); }
/* Light-section overrides — these components default to the dark
   theme's colors (used as-is on the projects index/show pages;
   reviews and FAQ render on the homepage); override
   scoped to .section-light so they read correctly on the homepage's
   light bands too. */
.section-light .gallery-item img { border-color: var(--light-border); }
/* Homepage "See Our Work" teaser — sized like .service-card (not
   the small .gallery-item thumbnail used on /projects and project
   photo galleries). auto-fill (not .services-grid's auto-fit) so
   a single project sits at its natural card width instead of
   stretching to fill the whole row. */
.project-teaser-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
    gap: 1.5rem;
}
.project-teaser-card {
    display: block;
    color: inherit;
    text-decoration: none;
    border: 1px solid var(--border);
    border-radius: 12px;
    padding: 1.5rem;
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.project-teaser-card:hover { box-shadow: 0 8px 24px rgba(15, 20, 25, 0.08); transform: translateY(-2px); text-decoration: none; }
.project-teaser-card img {
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    border-radius: 8px;
    display: block;
    margin-bottom: 1rem;
}
.project-teaser-card h3 { margin: 0; font-size: 1.15rem; font-weight: 700; }
.section-light .project-teaser-card { background: var(--light-panel); border-color: var(--light-border); }
.section-light .review-card { background: var(--light-panel); border-color: var(--light-border); }
.section-light .muted { color: var(--light-muted); }
.section-light .faq-list details { background: var(--light-panel); border-color: var(--light-border); }
.section-light .faq-list summary { color: var(--light-text); }
.section-light .faq-list p { color: var(--light-muted); }
footer {
    border-top: 1px solid var(--border);
    background: var(--panel);
    padding: 3.5rem 1.5rem 0;
    font-size: 0.9rem;
    color: var(--muted);
}
/* White footer variant — every rule below already reads --panel/
   --border/--text/--muted, so redefining those four custom
   properties on the footer element itself re-themes the whole
   block (including .footer-col h3, .footer-logo, etc.) without
   duplicating each rule for a second, light-footer selector. */
footer.footer-light {
    --panel: var(--light-panel);
    --border: var(--light-border);
    --text: var(--light-text);
    --muted: var(--light-muted);
}
.footer-inner { max-width: 1200px; margin: 0 auto; }
.footer-grid {
    display: grid;
    /* Column count varies — up to 5 (Business/Services/Products/
       Service Areas/Hours) when every module is populated, fewer
       when some are left empty (see nav_* globals). auto-fit keeps
       this correct regardless of how many actually render. */
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    gap: 2.5rem;
    padding-bottom: 3rem;
}
.footer-col h3 {
    color: var(--text);
    font-size: 0.85rem;
    text-transform: uppercase;
    letter-spacing: 0.05em;
    margin: 0 0 1rem;
}
/* "Services" heading is a link to #services (see footer markup) —
   keep it looking like a plain heading rather than turning
   accent-blue like a normal link. */
.footer-col h3 a { color: inherit; text-decoration: none; }
.footer-col h3 a:hover { text-decoration: underline; }
.footer-logo { color: var(--text); font-weight: 800; font-size: 1.1rem; margin-bottom: 0.75rem; }
.footer-col p { margin: 0 0 0.5rem; }
.footer-col ul { list-style: none; margin: 0; padding: 0; }
.footer-col li { margin-bottom: 0.6rem; }
.footer-hours li { line-height: 1.4; }
.footer-bottom {
    border-top: 1px solid var(--border);
    padding: 1.5rem 0;
    font-size: 0.8rem;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1.5rem;
}
.footer-bottom p { margin: 0; }
.footer-legal-links { display: flex; flex-wrap: wrap; gap: 1.25rem; }
.footer-legal-links a { color: var(--muted); }
.footer-legal-links a:hover { color: var(--text); }
@media (max-width: 800px) {
    .footer-grid { grid-template-columns: 1fr 1fr; }
}
@media (max-width: 480px) {
    .footer-grid { grid-template-columns: 1fr; gap: 2rem; }
}
