/* The Squeegee Method — "Material" direction, bespoke layer.
   Loaded after assets/css/base.css (core/layout.php's client_extra_css
   hook) so it can layer Material-specific visual/motion details on top of
   the shared token-driven foundation — everything reusable (stat-row,
   service-swatches, before-after multi-pair, chatbot avatar/subtitle
   options) already lives in the shared component/CSS files; this file is
   only the parts genuinely specific to this direction's own texture and
   motion recipe. See clients/squeegee-method/visual-directions/round1/
   C-material/ for the approved reference and NOTES.md for the full
   rationale behind every choice below. */

/* Accessible text-brass (2026-08-28, pre-launch QA finding, approved by
   Danielle): the approved brand gold #C9A24B measures only 2.40:1 against
   white — WCAG AA needs 4.5:1 at this weight/size (.section-eyebrow is
   12px/700). #141414/#F6F2E9/#C9A24B remain the final approved palette;
   this is a functional accessibility variant of the SAME gold family for
   small text on light surfaces, not a palette change. Same hue (41.4°)
   and saturation (53.8%) as the brand gold, HSL lightness only, darkened
   until it clears AA with real margin: 5.73:1 against white, verified
   both by the WCAG relative-luminance formula and by eye against every
   section background this token actually renders on. Deliberately does
   NOT apply to the hero eyebrow (assets/css/base.css exempts
   .hero-immersive-eyebrow back to the full-strength --cleo-accent) —
   that one sits on dark, scrimmed hero media and already reads clean at
   7.68:1; darkening it further would only mute the cinematic hero
   without fixing anything. */
:root {
    --cleo-accent-text: #7E6226;
}

/* Faint grain overlay — materiality, ~5% opacity, multiply blend. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: 1;
    pointer-events: none;
    opacity: 0.05;
    mix-blend-mode: multiply;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='120'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* main/footer/chatbot need to paint above the fixed grain layer — but NOT
   .site-header, which must keep its own base.css z-index (20, or the
   fixed/transparent-over-hero treatment on Home) untouched. A real bug,
   found 2026-08-28 from Danielle reporting the nav unclickable: this rule
   originally included .site-header with z-index:2, which — being equal to
   and later in source order than <main>'s own z-index:2 — let the home
   hero's content paint OVER the fixed header, visually covering the nav
   links and silently eating their clicks even though the header still
   read as visible underneath. */
main, .site-footer, .cleo-chatbot { position: relative; z-index: 2; }

/* Typography entering with precision — hero eyebrow/heading/lead/CTA settle
   in with a short stagger on load, quiet fade+rise, never a slide/bounce.
   Driven by material.js adding .is-in to each target; CSS-only fallback
   (no JS) leaves everything at its natural opacity:1 — see the base rule
   order below. */
@media (prefers-reduced-motion: no-preference) {
    .hero-immersive-inner > .hero-immersive-eyebrow,
    .hero-immersive-inner > h1,
    .hero-immersive-inner .hero-depth-front {
        opacity: 0;
        transform: translateY(10px);
        transition: opacity .9s cubic-bezier(.2,.6,.2,1), transform .9s cubic-bezier(.2,.6,.2,1);
    }
    html.motion-ready .hero-immersive-inner > .hero-immersive-eyebrow.is-in,
    html.motion-ready .hero-immersive-inner > h1.is-in,
    html.motion-ready .hero-immersive-inner .hero-depth-front.is-in {
        opacity: 1;
        transform: none;
    }
    /* No JS / motion disabled: never leave content invisible. */
    html:not(.motion-ready) .hero-immersive-inner > .hero-immersive-eyebrow,
    html:not(.motion-ready) .hero-immersive-inner > h1,
    html:not(.motion-ready) .hero-immersive-inner .hero-depth-front {
        opacity: 1;
        transform: none;
    }
}
.hero-actions { display: flex; gap: 16px; flex-wrap: wrap; align-items: center; margin-top: 8px; }

/* Material's HOMEPAGE hero is centered and lower-key, not the shared
   component's default left-weighted editorial composition — a deliberate
   distinction from Direction A's asymmetric hero (see visual-directions/
   round1/C-material/NOTES.md, "Differs from A"). Scoped to the home page
   specifically (body[data-page-type="home"], set by core/layout.php) —
   the approved concept was a single homepage-style page; other pages'
   heroes (e.g. Commercial) keep the shared component's own composition
   and padding rather than inheriting the extra bottom space this needed.
   Found and fixed 2026-08-27: an earlier, unscoped version of this rule
   made every hero on the site abnormally tall with a large dead-black
   area — caught by rendering the Commercial page, not from source. */
body[data-page-type="home"] .hero-immersive-inner {
    text-align: center;
    display: flex;
    flex-direction: column;
    align-items: center;
    padding-bottom: calc(var(--cleo-section-space, 64px) * 1.6);
}
body[data-page-type="home"] .hero-immersive-inner h1 { max-width: 16ch; }
body[data-page-type="home"] .hero-immersive .lead { text-align: center; margin-left: auto; margin-right: auto; }
body[data-page-type="home"] .hero-actions { justify-content: center; }

/* A soft gathering of shadow behind the hero text — not a card, reads as
   atmosphere/depth. Guarantees legibility over the brightest part of a
   photo (found during the Visual Art Direction Gate: the headline sat
   almost exactly over a window's glass and was close to illegible,
   especially on mobile — see NOTES.md's "Rendered-QA finding"). */
.hero-immersive-inner {
    position: relative;
    text-shadow: 0 1px 3px rgba(0,0,0,.75), 0 6px 22px rgba(10,8,4,.6);
}
.hero-immersive-inner::before {
    content: "";
    position: absolute;
    z-index: -1;
    left: 50%; top: 50%;
    transform: translate(-50%, -50%);
    width: 135%; height: 145%;
    background: radial-gradient(ellipse at center, rgba(18,14,8,.55) 0%, rgba(18,14,8,.32) 48%, rgba(18,14,8,0) 78%);
}

/* Restrained hero parallax (material.js) — the hero photo drifts a few px
   slower than the page, capped, disabled under reduced motion. */
.hero-immersive .hero-immersive-media img,
.hero-immersive .hero-immersive-media video { will-change: transform; }

/* Homepage hero — "almost subconscious" cinematic life (2026-08-28).
   Two effects, both one-time (never loop, never draw attention back to
   themselves after they finish), both layered on top of the existing
   scroll parallax above rather than replacing it:

   1. A very slow push-in on the photo itself (~24s, ease-out, holds at
      its final scale). Driven entirely by material.js, NOT a CSS
      `animation` — a competing `animation` on the same `transform`
      property the scroll-parallax JS already writes inline would win the
      cascade for the animation's whole (`both`-filled, effectively
      permanent) duration and silently cancel the parallax. material.js
      computes one combined scale+translateY string per frame instead.
   2. A single, faint diagonal light sweep — glass/water catching light —
      timed to cross the frame just after the text has finished settling
      in, at low enough opacity that it reads as atmosphere, not an
      effect. Never repeats. A separate pseudo-element, so no transform
      conflict with the photo itself.

   Both respect prefers-reduced-motion via the same guard as the rest of
   this file's motion (material.js checks matchMedia before doing
   anything, and the sheen below only ever applies under
   prefers-reduced-motion: no-preference). */
@media (prefers-reduced-motion: no-preference) {
    body[data-page-type="home"] .hero-immersive-media::before {
        content: "";
        position: absolute;
        inset: -20% -60%;
        z-index: 1;
        pointer-events: none;
        background: linear-gradient(115deg, transparent 42%, rgba(255,255,255,.09) 50%, transparent 58%);
        transform: translateX(-60%);
        animation: cleo-material-hero-sheen 4.5s ease-in-out 1.4s 1 both;
    }
}
@keyframes cleo-material-hero-sheen {
    from { transform: translateX(-60%); opacity: 0; }
    15%  { opacity: 1; }
    85%  { opacity: 1; }
    to   { transform: translateX(60%); opacity: 0; }
}

/* Service swatches — brass corner ticks on each tile, echoing the proof
   panel's own framed-object language below. */
.service-swatch { position: relative; }
.service-swatch::before,
.service-swatch::after {
    content: "";
    position: absolute;
    width: 14px; height: 14px;
    border-color: var(--cleo-accent);
    pointer-events: none;
    z-index: 2;
}
.service-swatch::before { top: 0; left: 0; border-top: 2px solid; border-left: 2px solid; }
.service-swatch::after { bottom: 0; right: 0; border-bottom: 2px solid; border-right: 2px solid; }

/* Proof gallery (before-after) — framed like a finished object: an inset
   brass hairline just inside the frame's own edge. */
.cleo-before-after .before-after-frame { box-shadow: 0 30px 80px rgba(0,0,0,.35); }
.cleo-before-after .before-after-frame::after {
    content: "";
    position: absolute;
    inset: 10px;
    border: 1px solid rgba(201, 162, 75, .35);
    pointer-events: none;
    z-index: 2;
}

/* Chatbot panel — framed like the proof panel, for the same "material
   object" continuity (see chatbot.css's gradient-avatar option, enabled
   for this client via manifest.json's chatbot.avatar_style). */
.cleo-chatbot-panel { position: relative; }
.cleo-chatbot-panel::before {
    content: "";
    position: absolute;
    inset: 8px;
    border: 1px solid rgba(201, 162, 75, .3);
    pointer-events: none;
    z-index: 1;
}
