/* =============================================================================
   247 Super Signs — design system
   Mobile-first. Restrained, architectural, corporate. No neon, no glassmorphism,
   no gold-and-black cliché. Luxury communicated through type, proportion, and
   whitespace — see CLAUDE.md "Design system" for the full rationale.
   ============================================================================= */

:root {
    /* Color: graphite/steel neutrals + one restrained ember accent used sparingly. */
    --color-ink: #14171c;
    --color-charcoal: #1d2128;
    --color-graphite: #2b313a;
    --color-steel: #4a525e;
    --color-mist: #8891a0;
    --color-fog: #d7dbe1;
    --color-paper: #f4f5f7;
    --color-white: #ffffff;

    --color-accent: #d9622b;      /* restrained ember — CTAs and illumination cues only */
    --color-accent-dark: #b84f21;
    --color-accent-light: #f3ddce;

    --color-success: #2f7a4f;
    --color-error: #b3261e;

    --font-display: "Archivo", "Helvetica Neue", Arial, sans-serif;
    --font-body: "Inter", "Helvetica Neue", Arial, sans-serif;

    --container-max: 1280px;
    --container-narrow: 860px;

    --space-1: 0.25rem;
    --space-2: 0.5rem;
    --space-3: 0.75rem;
    --space-4: 1rem;
    --space-5: 1.5rem;
    --space-6: 2rem;
    --space-7: 3rem;
    --space-8: 4.5rem;
    --space-9: 6.5rem;

    --radius-sm: 3px;
    --radius-md: 5px;

    --shadow-card: 0 1px 2px rgba(20, 23, 28, 0.06), 0 6px 20px rgba(20, 23, 28, 0.06);
    --shadow-elevated: 0 10px 40px rgba(20, 23, 28, 0.16);

    --ease-standard: cubic-bezier(0.2, 0.65, 0.3, 1);
    --duration-fast: 150ms;
    --duration-base: 260ms;
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
    margin: 0;
    background: var(--color-white);
    color: var(--color-ink);
    font-family: var(--font-body);
    font-size: 16px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
}
img, picture, video { max-width: 100%; display: block; }
img { height: auto; }
a { color: inherit; text-decoration: none; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
input, textarea, select { font: inherit; color: inherit; }
h1, h2, h3, h4, h5, h6 { margin: 0; font-family: var(--font-display); font-weight: 600; letter-spacing: -0.01em; }
p { margin: 0; }

@media (prefers-reduced-motion: reduce) {
    html { scroll-behavior: auto; }
    *, *::before, *::after {
        animation-duration: 0.001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.001ms !important;
        scroll-behavior: auto !important;
    }
}

/* ---------- Focus ---------- */
:focus-visible {
    outline: 2px solid var(--color-accent);
    outline-offset: 2px;
}
a:focus:not(:focus-visible), button:focus:not(:focus-visible) { outline: none; }

/* ---------- Layout ---------- */
.container {
    width: 100%;
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--space-5);
}
.container--narrow { max-width: var(--container-narrow); }
.section { padding-block: var(--space-8); }
.section--tight { padding-block: var(--space-7); }
.section--dark { background: var(--color-ink); color: var(--color-fog); }
.section--paper { background: var(--color-paper); }

@media (min-width: 768px) {
    .container { padding-inline: var(--space-6); }
    .section { padding-block: var(--space-9); }
}

/* ---------- Type scale ---------- */
.eyebrow {
    display: inline-block;
    font-family: var(--font-body);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--color-accent);
    margin-bottom: var(--space-3);
}
.section--dark .eyebrow { color: var(--color-accent); }

h1, .h1 { font-size: clamp(2.25rem, 5vw + 1rem, 4rem); line-height: 1.05; }
h2, .h2 { font-size: clamp(1.75rem, 3vw + 1rem, 2.75rem); line-height: 1.1; }
h3, .h3 { font-size: clamp(1.25rem, 1.4vw + 1rem, 1.6rem); line-height: 1.2; }
h4, .h4 { font-size: 1.125rem; line-height: 1.3; }

.lede { font-size: clamp(1.05rem, 0.6vw + 1rem, 1.25rem); color: var(--color-steel); line-height: 1.6; }
.section--dark .lede { color: var(--color-mist); }
.text-muted { color: var(--color-steel); }
.section--dark .text-muted { color: var(--color-mist); }

/* ---------- Buttons ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2);
    padding: 0.85rem 1.5rem;
    border-radius: var(--radius-sm);
    font-weight: 600;
    font-size: 0.95rem;
    letter-spacing: 0.01em;
    transition: background var(--duration-fast) var(--ease-standard), color var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);
    border: 1px solid transparent;
    white-space: nowrap;
}
.btn--primary { background: var(--color-accent); color: var(--color-white); }
.btn--primary:hover { background: var(--color-accent-dark); }
.btn--ghost-light { background: transparent; color: var(--color-white); border-color: rgba(255,255,255,0.4); }
.btn--ghost-light:hover { border-color: #fff; background: rgba(255,255,255,0.08); }
.btn--ghost-dark { background: transparent; color: var(--color-ink); border-color: var(--color-fog); }
.btn--ghost-dark:hover { border-color: var(--color-steel); }
.btn--block { width: 100%; justify-content: center; }
.btn[disabled] { opacity: 0.6; cursor: not-allowed; }

/* ---------- Header / Nav ---------- */
.site-header {
    position: sticky;
    top: 0;
    z-index: 40;
    /* Solid, not translucent: with the bigger brand mark now on the homepage
       (.brand-mark-lg), that bold high-contrast logo would otherwise scroll
       directly underneath this bar and show through as a dim blurred smudge
       for as long as it's passing behind it — nothing else on the site was
       ever bold/saturated enough for the old rgba(...,0.94)+blur "frosted
       glass" look to visibly leak through, so it went unnoticed until now. */
    background: rgb(20, 23, 28);
    color: var(--color-white);
}
.site-header__bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 72px;
}
.brand { display: flex; align-items: center; gap: 0.6rem; font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; color: var(--color-white); }
.brand__mark { width: 44px; height: 44px; flex-shrink: 0; object-fit: contain; }
.brand__name { line-height: 1.1; }
.brand__name small { display: block; font-family: var(--font-body); font-weight: 500; font-size: 0.62rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--color-mist); }

.nav-desktop { display: none; }
.nav-desktop__list { display: flex; align-items: center; gap: var(--space-6); }
.nav-desktop__list a { font-size: 0.92rem; font-weight: 500; color: var(--color-fog); transition: color var(--duration-fast); }
.nav-desktop__list a:hover, .nav-desktop__list a[aria-current="page"] { color: var(--color-white); }
.nav-desktop__cta { display: flex; align-items: center; gap: var(--space-4); }

.hamburger {
    display: inline-flex;
    flex-direction: column;
    justify-content: center;
    gap: 5px;
    width: 42px;
    height: 42px;
    align-items: center;
}
.hamburger span { display: block; width: 22px; height: 2px; background: var(--color-white); border-radius: 2px; transition: transform var(--duration-base) var(--ease-standard), opacity var(--duration-base); }
.hamburger[aria-expanded="true"] span:nth-child(1) { transform: translateY(7px) rotate(45deg); }
.hamburger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
.hamburger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-7px) rotate(-45deg); }

@media (min-width: 960px) {
    .nav-desktop { display: flex; align-items: center; gap: var(--space-7); }
    .hamburger { display: none; }
}

/* ---------- Mobile nav panel: ~85% viewport, dimmed backdrop, not full-screen ---------- */
.mobile-nav-backdrop {
    position: fixed;
    inset: 0;
    background: rgba(10, 12, 15, 0.55);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--duration-base) var(--ease-standard);
    z-index: 49;
}
.mobile-nav-backdrop.is-open { opacity: 1; pointer-events: auto; }

.mobile-nav {
    position: fixed;
    top: 0;
    right: 0;
    height: 100%;
    width: 85vw;
    max-width: 380px;
    background: var(--color-ink);
    color: var(--color-white);
    z-index: 50;
    transform: translateX(100%);
    transition: transform var(--duration-base) var(--ease-standard);
    display: flex;
    flex-direction: column;
    box-shadow: var(--shadow-elevated);
}
.mobile-nav.is-open { transform: translateX(0); }
.mobile-nav__head { display: flex; align-items: center; justify-content: space-between; padding: var(--space-5); border-bottom: 1px solid rgba(255,255,255,0.08); }
.mobile-nav__close { width: 40px; height: 40px; display: inline-flex; align-items: center; justify-content: center; }
.mobile-nav__close svg { width: 20px; height: 20px; }
.mobile-nav__list { padding: var(--space-4) var(--space-5); overflow-y: auto; flex: 1; }
.mobile-nav__list li { border-bottom: 1px solid rgba(255,255,255,0.06); }
.mobile-nav__list a { display: block; padding: var(--space-4) 0; font-family: var(--font-display); font-size: 1.15rem; font-weight: 600; }
.mobile-nav__list .mobile-nav__sub a { font-family: var(--font-body); font-size: 0.95rem; font-weight: 400; padding: var(--space-3) 0; color: var(--color-mist); }
.mobile-nav__foot { padding: var(--space-5); border-top: 1px solid rgba(255,255,255,0.08); }

body.nav-open { overflow: hidden; }

/* ---------- Hero ---------- */
.hero {
    position: relative;
    color: var(--color-white);
    background: var(--color-ink);
    overflow: hidden;
    min-height: 78vh;
    display: flex;
    align-items: flex-end;
}
.hero__media { position: absolute; inset: 0; }
.hero__media img { width: 100%; height: 100%; object-fit: cover; object-position: center; }
.hero__scrim { position: absolute; inset: 0; background: linear-gradient(180deg, rgba(15,17,21,0.35) 0%, rgba(15,17,21,0.55) 55%, rgba(12,13,16,0.92) 100%); }
.hero__content { position: relative; padding-block: var(--space-8) var(--space-7); max-width: 760px; }
.hero__actions { display: flex; flex-wrap: wrap; gap: var(--space-4); margin-top: var(--space-6); }

/* ---------- Cards ---------- */
/* .card is a white box that gets dropped into sections of every background color,
   including .section--dark (color: var(--color-fog), a pale near-white meant for text
   sitting DIRECTLY on the dark background). Without its own explicit `color`, .card's
   title/body text inherited that fog color straight through — perfectly legible on
   ink, illegible-looking (washed pale gray on white) inside the card itself. Pinning
   .card's own text color, and re-pinning .text-muted when it's nested in a card,
   makes the card render identically regardless of what section contains it. */
.card {
    background: var(--color-white);
    color: var(--color-ink);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-card);
    overflow: hidden;
    display: flex;
    flex-direction: column;
    height: 100%;
}
.card .text-muted { color: var(--color-steel); }
.card__media { aspect-ratio: 4 / 3; overflow: hidden; background: var(--color-graphite); }
.card__media img { width: 100%; height: 100%; object-fit: cover; transition: transform 600ms var(--ease-standard); }
.card:hover .card__media img { transform: scale(1.035); }
.card__body { padding: var(--space-5); display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.card__tag { font-size: 0.72rem; font-weight: 600; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-accent); }
.card__link { margin-top: auto; padding-top: var(--space-3); font-weight: 600; font-size: 0.9rem; display: inline-flex; align-items: center; gap: 0.35rem; }

/* ---------- Grid ---------- */
.grid { display: grid; gap: var(--space-6); }
.grid--2 { grid-template-columns: repeat(1, 1fr); }
.grid--3 { grid-template-columns: repeat(1, 1fr); }
.grid--4 { grid-template-columns: repeat(1, 1fr); }
@media (min-width: 640px) {
    .grid--2 { grid-template-columns: repeat(2, 1fr); }
    .grid--4 { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 960px) {
    .grid--3 { grid-template-columns: repeat(3, 1fr); }
    .grid--4 { grid-template-columns: repeat(4, 1fr); }
}

/* ---------- Pagination (project gallery) ---------- */
.pagination { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-2); margin-top: var(--space-8); }
.pagination__link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 40px;
    height: 40px;
    padding-inline: var(--space-2);
    border-radius: var(--radius-sm);
    border: 1px solid var(--color-fog);
    font-weight: 600;
    font-size: 0.9rem;
    color: var(--color-ink);
    transition: background-color var(--duration-fast), border-color var(--duration-fast), color var(--duration-fast);
}
.pagination__link:hover { border-color: var(--color-ink); }
.pagination__link.is-active { background: var(--color-accent); border-color: var(--color-accent); color: var(--color-white); }

/* ---------- Horizontal scroll / carousel (explicit "more content" affordance) ---------- */
.hscroll {
    display: flex;
    align-items: stretch;
    gap: var(--space-5);
    overflow-x: auto;
    /* mandatory (not proximity, the old setting): guarantees the row ALWAYS comes to
       rest on a card boundary, however/wherever the touch/drag ends — including a
       release sitting exactly between two cards, which "proximity" would sometimes
       leave un-snapped, half-cut. Snapping is why the fade only needs to live on the
       right: with every card start-aligned (see .hscroll__item below) and the row
       always settling flush on a card, the LEFT-most visible card is guaranteed whole
       at every rest position (nothing to fade there — see the mask-image rule below)
       — only the right edge ever shows a genuinely cropped "peeking" card. */
    scroll-snap-type: x mandatory;
    padding-bottom: var(--space-3);
    /* The true-edge bleed now lives on .hscroll-wrap itself (see its rule below) so the
       wrap's own box — the positioning context for the edge-fade ::before/::after —
       lines up with where cards actually get cut off. Only the inset padding stays
       here; this box no longer also bleeds a negative margin of its own, or the two
       bleeds would stack and push cards an extra --space-5 past the true edge. */
    padding-inline: var(--space-5);
    /* Without this, some rows (empirically: inconsistent between otherwise-identical
       markup — a real Chromium scroll-snap quirk, not a JS/timing bug) rest with
       scrollLeft equal to the leading padding-inline instead of 0, which scrolls that
       padding out of view and leaves the first card flush against the true edge with
       no inset — while other rows correctly rest at 0. Forcing scrollLeft back to 0
       via JS does not help; the browser just re-snaps past it on the next frame.
       scroll-padding-inline tells the snap engine the padding itself counts as part of
       "start," so the natural rest position becomes 0 (padding visible) everywhere,
       consistently. */
    scroll-padding-inline: var(--space-5);
    scrollbar-width: none;
}
.hscroll::-webkit-scrollbar { display: none; }
.hscroll__item {
    flex: 0 0 auto;
    width: 82%;
    scroll-snap-align: start;
}
/* .card and .hscroll__item are often the same element (see e.g. home.php's featured-
   projects row) — .card's own `height: 100%` (needed for CSS Grid contexts) opts the
   element OUT of flex "stretch" sizing here, since a percentage height reads as
   definite even though the row's own height is only resolved BY that stretch. Force
   `auto` in this specific context so align-items: stretch on .hscroll actually
   equalizes card heights regardless of how many lines a title/summary wraps to. */
.hscroll > .card,
.hscroll .hscroll__item > .card { height: auto; align-self: stretch; }
@media (min-width: 640px) { .hscroll__item { width: 46%; } }
@media (min-width: 960px) { .hscroll__item { width: 30%; } }
/* .hscroll-wrap must bleed to the SAME true edges as its .hscroll child (see the
   negative-margin/padding bleed trick on .hscroll above) so the arrow buttons (appended
   as children of the wrap, positioned absolute against ITS box) sit flush with the true
   left/right edges rather than inset by --space-5. */
.hscroll-wrap { position: relative; margin-inline: calc(var(--space-5) * -1); }
/* Edge fade — rebuilt 2026-09-05 as a mask-image on .hscroll ITSELF, not a painted
   overlay on a separate wrapper element. The old design (a ::before/::after pair
   anchored to .hscroll-wrap, a different box from .hscroll, the element that actually
   scrolls/clips) required the wrap's bleed and the track's bleed to be kept in exact
   sync by hand for the fade to land at the true cutoff — that's precisely what drifted
   out of sync and caused the "white streak" (the fade rendering ~24px away from the
   real edge, landing mid-card instead of softening the cutoff). A mask-image applied
   straight to .hscroll can't have this problem: mask and overflow-x:auto-clipping both
   apply to the exact same box, by construction, so there's no second element's geometry
   to keep aligned — the same reasoning startup.ph's single-element hscroll uses. This
   also fades the actual card content to transparent (revealing whatever's truly behind
   it) instead of painting a solid overlay that has to match the section's background
   color — so no more per-section --fade-to overrides to keep in sync either.

   Right-side, mostly (2026-09-06) — with `scroll-snap-type: x mandatory` above
   guaranteeing the row always rests with a whole, uncropped card on the left, a left
   fade would just be softening an edge that's never actually cut, at MOST scroll
   positions — there's no rough crop there for it to smooth over. So the left fade was
   dropped for every normal position, and only the right edge (which always shows a
   genuinely sliced "peeking" card) keeps one.

   Real exception, confirmed by testing rather than assumed away: the very LAST resting
   position, at the true end of the row, is NOT guaranteed whole on the left. If the
   final card(s) don't add up to a full viewport width, the browser simply can't scroll
   any further to align the last card perfectly — it clamps at max-scroll instead,
   which can leave the left-most visible card cropped by a large amount (confirmed via
   Playwright: up to ~290px of a card cut off, not a rounding-error sliver). That one
   position gets its own narrow, explicit trigger below (`.is-end-cropped`, set by JS
   only when the true end is reached AND the left card is actually cropped there — not
   "whenever scrolled", which is the old, removed behavior) rather than reviving the
   left fade everywhere. */
@property --fade-l { syntax: '<length>'; inherits: false; initial-value: 0px; }
@property --fade-r { syntax: '<length>'; inherits: false; initial-value: 0px; }
.hscroll {
    --fade-l: 0px;
    --fade-r: 0px;
    -webkit-mask-image: linear-gradient(90deg, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent);
    mask-image: linear-gradient(90deg, transparent, #000 var(--fade-l), #000 calc(100% - var(--fade-r)), transparent);
    transition: --fade-l 200ms var(--ease-standard), --fade-r 200ms var(--ease-standard);
}
/* Fade width matches the old overlay's 32px. --fade-r only appears while JS confirms
   there's actually more to scroll right (see main.js "hscroll edge affordances") — a
   fade that's always on regardless of scroll position reads as a rendering glitch once
   the row is fully scrolled. --fade-l only appears in the one true-end-crop case above.
   No-JS fallback: both stay 0 (simply absent), which is fine since the row is still
   natively scrollable either way. */
.hscroll-wrap.has-more-right .hscroll { --fade-r: 32px; }
.hscroll-wrap.is-end-cropped .hscroll { --fade-l: 32px; }

/* Industry filter pills (projects.php) — a tighter, visually-grouped variant of the
   generic hscroll pattern. The default card-row gap/no-background reads fine for
   distinct cards, but for a row of small filter buttons it left them looking like
   loose, unrelated buttons floating on the page rather than one connected control,
   and on mobile it wasn't obvious the row continues off-screen. */
.hscroll-wrap--filters {
    background: var(--color-paper);
    border-radius: var(--radius-md);
}
.hscroll-wrap--filters .hscroll {
    gap: var(--space-2);
    padding-block: var(--space-2);
    /* No snap here: with scroll-snap-type set (needed for the card rows this same
       .hscroll class serves elsewhere), the row tends to rest with a pill's edge
       flush against the viewport edge, which reads as "that's the whole list" rather
       than "more continues off-screen." Letting it rest at its natural scroll
       position means a pill is usually left partially cut off at the edge instead —
       exactly the visible-slice hint the row needs. */
    scroll-snap-type: none;
}

/* Prev/next affordance — replaces the old always-visible native scrollbar. Injected
   by JS (see main.js) so a no-JS visitor still gets plain native touch/trackpad
   scrolling with no broken-looking controls in the markup. */
.hscroll-arrow {
    position: absolute;
    top: 50%;
    transform: translateY(-75%);
    z-index: 3;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    border: 1px solid rgba(255,255,255,0.25);
    background: rgba(20,23,28,0.55);
    backdrop-filter: blur(2px);
    color: var(--color-white);
    display: none;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    transition: background 150ms var(--ease-standard), opacity 150ms var(--ease-standard);
}
.hscroll-arrow:hover { background: rgba(20,23,28,0.85); }
.hscroll-arrow[disabled] { opacity: 0; pointer-events: none; }
.hscroll-arrow svg { width: 18px; height: 18px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.hscroll-arrow--prev { left: var(--space-4); }
.hscroll-arrow--next { right: var(--space-4); }
@media (min-width: 780px) { .hscroll-arrow { display: flex; } }

/* ---------- Process steps ---------- */
.process { display: grid; gap: var(--space-6); grid-template-columns: 1fr; }
@media (min-width: 780px) { .process { grid-template-columns: repeat(4, 1fr); } }
.process__step { border-top: 2px solid var(--color-accent); padding-top: var(--space-4); }
.process__num { font-family: var(--font-display); font-size: 0.85rem; color: var(--color-mist); }

/* ---------- Video frame ---------- */
.video-frame {
    position: relative;
    aspect-ratio: 16 / 9;
    background: var(--color-ink);
    border-radius: var(--radius-md);
    overflow: hidden;
    border: 1px solid var(--color-graphite);
}
.video-frame img { width: 100%; height: 100%; object-fit: cover; opacity: 0.75; }
.video-frame iframe { width: 100%; height: 100%; border: 0; }
.video-frame__play {
    position: absolute; inset: 0; margin: auto; width: 74px; height: 74px;
    border-radius: 50%; background: rgba(20,23,28,0.72); border: 1px solid rgba(255,255,255,0.35);
    display: flex; align-items: center; justify-content: center; color: #fff;
    transition: background var(--duration-fast), transform var(--duration-fast);
}
.video-frame__play:hover { background: var(--color-accent); transform: scale(1.05); }
.video-frame__play svg { width: 24px; height: 24px; margin-left: 3px; }

/* ---------- Forms ---------- */
.field { margin-bottom: var(--space-5); }
.field label { display: block; font-weight: 600; font-size: 0.88rem; margin-bottom: var(--space-2); }
.required-mark { color: var(--color-error); }
.field input, .field select, .field textarea {
    width: 100%;
    padding: 0.75rem 0.9rem;
    border: 1px solid var(--color-fog);
    border-radius: var(--radius-sm);
    background: var(--color-white);
    transition: border-color var(--duration-fast);
}
.field input:focus, .field select:focus, .field textarea:focus { border-color: var(--color-accent); }
.field textarea { min-height: 140px; resize: vertical; }
.field__error { color: var(--color-error); font-size: 0.85rem; margin-top: var(--space-2); }
.field--checkbox { display: flex; align-items: flex-start; gap: var(--space-3); }
.field--checkbox input { width: auto; }
.form-alert { padding: var(--space-4) var(--space-5); border-radius: var(--radius-sm); margin-bottom: var(--space-5); font-weight: 500; }
.form-alert--success { background: #e7f3ea; color: var(--color-success); }
.form-alert--error { background: #fbe9e7; color: var(--color-error); }

/* ---------- Enquiry card (premium two-column contact presentation) ---------- */
.enquiry-card {
    background: var(--color-ink);
    color: var(--color-fog);
    /* Deliberately larger than --radius-md (5px, the sharp/corporate radius used
       everywhere else on the site) — this one component is styled after a softer,
       more "premium enquiry form" reference the owner supplied, so it gets its own
       generous radius rather than changing the shared token every other card/button
       on the site relies on. */
    border-radius: 22px;
    overflow: hidden;
    box-shadow: var(--shadow-card);
    display: grid;
    grid-template-columns: 1fr;
}
.enquiry-card .eyebrow { color: var(--color-accent); }
.enquiry-card .text-muted { color: var(--color-mist); }
@media (min-width: 860px) {
    .enquiry-card { grid-template-columns: 1fr 1fr; }
}
.enquiry-card__media { position: relative; min-height: 320px; display: flex; align-items: flex-end; }
.enquiry-card__media img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.enquiry-card__media::after {
    content: "";
    position: absolute; inset: 0;
    background: linear-gradient(180deg, rgba(20,23,28,0.45) 0%, rgba(20,23,28,0.82) 45%, rgba(20,23,28,0.97) 100%);
}
.enquiry-card__media-content { position: relative; z-index: 1; padding: var(--space-7); }
.enquiry-card__service-area {
    display: flex; align-items: flex-start; gap: var(--space-3);
    margin-top: var(--space-6);
    padding-top: var(--space-5);
    border-top: 1px solid rgba(255,255,255,0.16);
}
.enquiry-card__service-area svg { width: 20px; height: 20px; flex-shrink: 0; color: var(--color-accent); margin-top: 2px; }
.enquiry-card__service-area strong { display: block; font-size: 0.72rem; letter-spacing: 0.08em; text-transform: uppercase; color: var(--color-mist); margin-bottom: 2px; font-weight: 600; }
.enquiry-card__form { padding: var(--space-7); }
.enquiry-card__form .field label { color: var(--color-mist); font-size: 0.76rem; letter-spacing: 0.07em; text-transform: uppercase; font-weight: 600; }
.enquiry-card__form .field input,
.enquiry-card__form .field select,
.enquiry-card__form .field textarea {
    background: transparent;
    border: none;
    border-bottom: 1px solid rgba(255,255,255,0.24);
    border-radius: 0;
    color: var(--color-white);
    padding: var(--space-3) 0.1rem;
}
.enquiry-card__form .field input::placeholder,
.enquiry-card__form .field textarea::placeholder { color: rgba(215,219,225,0.42); }
.enquiry-card__form .field input:focus,
.enquiry-card__form .field select:focus,
.enquiry-card__form .field textarea:focus { border-bottom-color: var(--color-accent); }
.enquiry-card__form .field select option { color: var(--color-ink); }
.enquiry-card__form .field textarea { min-height: 110px; }
.enquiry-card__form .field__error { color: #ff9d94; }
.enquiry-card__form .form-disclaimer { display: block; margin-top: var(--space-5); font-size: 0.8rem; color: var(--color-mist); }

/* A monochrome, low-color "stamp" treatment for the logo mark — used where a big,
   elegant brand moment is wanted without the full-color icon competing for attention
   (e.g. the closing signature block on the contact page). */
/* Full-color brand mark, inline within the enquiry card's left column (between the
   lede paragraph and the Service Area callout) — not a separate full-width section.
   An earlier version tried a monochrome "stamp" treatment there instead (see git
   history / project notes if resurrecting it); the owner decided the client may not
   want monochrome after all, so this is just the real logo at a modest inline size.
   `.enquiry-card__media img` (the background photo, absolute+100%+cover) would
   otherwise also match this image since it's nested inside the same `.enquiry-card
   __media` container — this needs to win over that with more specific overrides,
   not just different values, since `position:absolute` in particular doesn't lose to
   a plain `position:static` declaration on specificity grounds alone. */
.enquiry-card__media-content img.enquiry-card__logo {
    position: static;
    display: block;
    width: 72px;
    height: 73px;
    object-fit: contain;
    margin-top: var(--space-6);
    inset: auto;
}

/* Homepage "Who We Are" brand mark (mockup, pending owner sign-off). Sized up
   noticeably on wider screens: the section's text column is capped narrow
   (container--narrow), so a size that reads fine against a phone's edge-to-edge
   width looks small against a wide laptop viewport's open space. Bump it up
   past the tablet breakpoint rather than scaling with the column. */
.brand-mark-lg {
    width: 125px;
    height: 127px;
    margin: 0 auto var(--space-5);
    display: block;
}
@media (min-width: 768px) {
    .brand-mark-lg {
        width: 225px;
        height: 228px;
        margin-bottom: var(--space-6);
    }
}
.hp-field { position: absolute; left: -9999px; top: -9999px; }

/* ---------- Footer ---------- */
.site-footer { background: var(--color-ink); color: var(--color-fog); padding-block: var(--space-8) var(--space-6); }
.footer-grid { display: grid; gap: var(--space-7); grid-template-columns: 1fr; }
@media (min-width: 780px) { .footer-grid { grid-template-columns: 1.4fr 1fr 1fr 1fr; } }
.footer-grid h4 { color: var(--color-white); margin-bottom: var(--space-4); font-size: 0.85rem; text-transform: uppercase; letter-spacing: 0.08em; }
.footer-grid ul li { margin-bottom: var(--space-2); }
.footer-grid a:hover { color: var(--color-white); }
.footer-social { display: flex; gap: var(--space-3); margin-top: var(--space-5); }
.footer-social a { width: 36px; height: 36px; border: 1px solid rgba(255,255,255,0.2); border-radius: 50%; display: flex; align-items: center; justify-content: center; }
.footer-social svg { width: 16px; height: 16px; }
.footer-bottom { margin-top: var(--space-8); padding-top: var(--space-5); border-top: 1px solid rgba(255,255,255,0.1); display: flex; flex-wrap: wrap; gap: var(--space-4); justify-content: space-between; font-size: 0.82rem; color: var(--color-mist); }

/* ---------- Breadcrumb ---------- */
.breadcrumb { font-size: 0.82rem; color: var(--color-steel); margin-bottom: var(--space-4); }
.breadcrumb a:hover { text-decoration: underline; }
.breadcrumb__sep { margin-inline: 0.4em; color: var(--color-fog); }

/* ---------- Utilities ---------- */
.mt-0 { margin-top: 0; }
.text-center { text-align: center; }
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0; }
.skip-link {
    position: absolute; left: 0; top: -60px; background: var(--color-accent); color: #fff;
    padding: 0.7rem 1.2rem; z-index: 100; transition: top var(--duration-fast);
}
.skip-link:focus { top: 0; }

/* ---------- Reveal-on-scroll (progressive enhancement) ----------
   IMPORTANT: [data-reveal] elements are fully visible by default. Only once JS has
   confirmed it's running (and adds "js-reveal" to <html>) do they start hidden and
   fade in via IntersectionObserver — with a timed fallback in main.js that reveals
   everything regardless, in case an element never scrolls into view. This guarantees
   content is never invisible for no-JS users, slow JS, or automated renderers/crawlers. */
.js-reveal [data-reveal] { opacity: 0; transform: translateY(14px); transition: opacity 500ms var(--ease-standard), transform 500ms var(--ease-standard); }
[data-reveal].is-visible { opacity: 1; transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
    .js-reveal [data-reveal] { opacity: 1; transform: none; }
}

/* ---------- 404 ---------- */
.error-page { min-height: 60vh; display: flex; align-items: center; }
