/* The H Clinic — CI theme (STAGE 1): rose-gold brand palette + Anuphan */
:root {
    --color-primary: #AB7E69;
    --color-primary-2: #B78E78;
    --color-beige: #E4C8B3;
    --color-beige-2: #E8CDBA;
    --color-cream: #F2EBE5;
    --color-ink: #3E2B23;
}

* { box-sizing: border-box; }
@media (prefers-reduced-motion: no-preference) {
    html { scroll-behavior: smooth; }
}
body { margin: 0; font-family: 'Anuphan', system-ui, -apple-system, "Segoe UI", sans-serif; color: var(--color-ink); background: var(--color-cream); line-height: 1.5; }
h1, h2, h3, h4, h5, h6 { font-family: 'Anuphan', system-ui, -apple-system, "Segoe UI", sans-serif; }
.container { max-width: 1100px; margin: 0 auto; padding: 0 16px; }
a { color: inherit; }

.site-header { border-bottom: 1px solid var(--color-beige); position: sticky; top: 0; background: #fff; z-index: 10; transition: box-shadow .25s ease; }
.site-header.is-scrolled { box-shadow: 0 2px 12px rgba(62, 43, 35, 0.10); border-bottom-color: transparent; }
.header-inner { display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; gap: 16px; transition: padding .25s ease; }
.site-header.is-scrolled .header-inner { padding: 8px 16px; }
.logo { font-weight: 700; text-decoration: none; display: flex; align-items: center; }
.logo img { height: 40px; width: auto; display: block; transition: height .25s ease; }
.site-header.is-scrolled .logo img { height: 32px; }
.main-nav { display: flex; gap: 12px; flex-wrap: wrap; font-size: 14px; }
.main-nav a { text-decoration: none; position: relative; padding-bottom: 2px; }
/* STAGE 7 Group E — underline expands from the left on hover/focus. */
.main-nav a::after {
    content: '';
    position: absolute; left: 0; bottom: -2px;
    width: 0; height: 2px;
    background: var(--color-primary);
    transition: width .25s ease;
}
.main-nav a:hover::after, .main-nav a:focus-visible::after { width: 100%; }
.header-cta { display: flex; gap: 8px; }

/* P1-1 — mobile hamburger toggle + off-canvas drawer. .main-nav's inline
   link list hides below ~900px (matching the breakpoint the sticky-bar/
   floating-line swap already uses everywhere else in this file) and this
   button takes over; .header-cta stays visible at every width regardless. */
.nav-toggle {
    display: none;
    flex-direction: column; justify-content: center; align-items: center; gap: 5px;
    width: 36px; height: 36px; padding: 6px;
    border: 0; background: transparent; cursor: pointer;
}
.nav-toggle-bar { display: block; width: 100%; height: 2px; background: var(--color-ink); border-radius: 2px; }

.nav-drawer { display: none; position: fixed; inset: 0; z-index: 40; }
.nav-drawer.is-open { display: block; }
.nav-drawer-backdrop {
    position: absolute; inset: 0; background: rgba(62, 43, 35, .5);
    opacity: 0; transition: opacity .3s ease;
}
.nav-drawer.is-visible .nav-drawer-backdrop { opacity: 1; }
.nav-drawer-panel {
    position: absolute; top: 0; right: 0; bottom: 0; width: min(280px, 80vw);
    background: #fff; padding: 20px; display: flex; flex-direction: column; gap: 2px;
    transform: translateX(100%); transition: transform .3s ease;
    box-shadow: -8px 0 24px rgba(62, 43, 35, .18);
    overflow-y: auto;
}
.nav-drawer.is-visible .nav-drawer-panel { transform: translateX(0); }
.nav-drawer-panel a {
    padding: 12px 8px; text-decoration: none; color: var(--color-ink);
    border-bottom: 1px solid var(--color-beige); font-size: 15px;
}
.nav-drawer-close {
    align-self: flex-end; background: transparent; border: 0;
    font-size: 30px; line-height: 1; cursor: pointer; padding: 4px 8px; color: var(--color-ink);
}
.nav-drawer-cta { display: flex; gap: 8px; margin-top: 16px; }
.nav-drawer-cta .btn { flex: 1; text-align: center; }

@media (max-width: 899px) {
    .main-nav { display: none; }
    .nav-toggle { display: inline-flex; }
}
@media (min-width: 900px) {
    .nav-toggle, .nav-drawer { display: none !important; }
}

.btn { display: inline-block; padding: 8px 16px; border-radius: 6px; text-decoration: none; font-size: 14px; transition: transform .2s ease, box-shadow .2s ease, background-color .2s ease; }
.btn:hover { transform: translateY(-2px); box-shadow: 0 4px 12px rgba(62, 43, 35, 0.15); }
.btn-call, .btn-line { background: var(--color-beige-2); color: var(--color-ink); }
/* Touch-target fix: 8px vertical padding alone worked out to ~37px tall,
   short of the ~44px minimum recommended for a comfortable tap target.
   Scoped to mobile (not desktop, where a mouse pointer doesn't need it)
   via inline-flex centering so the label stays centered at the taller
   height rather than just top-aligned within extra padding. */
@media (max-width: 899px) {
    .btn { min-height: 44px; display: inline-flex; align-items: center; justify-content: center; }
}
.btn-primary { background: var(--color-primary); color: #fff; }

main { min-height: 60vh; padding: 24px 16px; }
.hero { text-align: center; padding: 48px 16px; position: relative; overflow: hidden; }
.hero-image-only { padding: 0 16px; position: relative; overflow: hidden; }
.hero-banner-img { display: block; width: 100%; max-width: 1100px; height: auto; margin: 0 auto; border-radius: 12px; }

/* P1-1 — unified hero: media + a gradient-scrimmed text overlay sitting on
   top of it, on both desktop and mobile. Supersedes the STAGE 7 Group B
   .hero-video-bg scaffolding below as the swap-in mechanism for a future
   video — that block is now inert/superseded, left in place rather than
   ripped out mid-phase.
   .hero-media-wrap is the shared positioning context for the media +
   overlay (rather than positioning the overlay against the outer
   .hero-feature section) so the gradient always lines up with the actual
   image box, not the section's full-bleed padding area. */
.hero-feature { padding: 16px; }
.hero-media-wrap { position: relative; max-width: 1100px; margin: 0 auto; border-radius: 12px; overflow: hidden; }
.hero-media { display: block; width: 100%; object-fit: cover; }
.hero-overlay {
    position: absolute; inset: 0; display: flex; align-items: flex-end;
    background: linear-gradient(180deg, rgba(62, 43, 35, .05) 0%, rgba(62, 43, 35, .55) 55%, rgba(62, 43, 35, .85) 100%);
}
.hero-overlay-inner { width: 100%; padding: 24px 20px; text-align: center; color: #fff; box-sizing: border-box; }
.hero-headline { margin: 0 0 8px; font-size: 26px; line-height: 1.3; color: #fff; }
.hero-tagline { margin: 0 0 16px; font-size: 15px; color: #fff; opacity: .9; }
.hero-trust-points {
    list-style: none; display: flex; flex-wrap: wrap; justify-content: center; gap: 14px 20px;
    padding: 0; margin: 0 0 20px; font-size: 13px; font-weight: 600; color: #fff;
}
.hero-trust-points li { display: flex; align-items: center; gap: 6px; }
.hero-trust-points svg { width: 18px; height: 18px; flex-shrink: 0; color: #fff; }
.hero-overlay-inner .hero-cta-bar { max-width: none; margin: 0; padding: 0; }

/* Below ~900px the 16:9 lock (from x-placeholder's ratio prop) is too
   short to hold headline + tagline + trust points + 3 CTA buttons
   legibly, so this overrides it with a fixed height instead — still a
   static value known before the image loads, so no CLS. Two classes
   (.hero-feature .hero-media) rather than just `.hero-media` so this
   reliably beats the P1-0 `.placeholder-media { height: 100% }` rule
   regardless of source order — same specificity would otherwise let
   whichever rule comes later in the file win. */
@media (max-width: 899px) {
    .hero-feature .hero-media { height: 480px; }
}

@media (min-width: 900px) {
    .hero-overlay {
        align-items: center;
        background: linear-gradient(90deg, rgba(62, 43, 35, .65) 0%, rgba(62, 43, 35, .3) 55%, transparent 100%);
    }
    .hero-overlay-inner { max-width: 460px; padding: 0 48px; text-align: left; }
    .hero-overlay .hero-trust-points { justify-content: flex-start; }
    .hero-overlay-inner .hero-cta-bar { justify-content: flex-start; }
}

/* STAGE 7 Group B — hero entrance (fade + slide-up, staggered by JS via
   inline transition-delay). Load-triggered, not scroll-triggered, since
   the hero is always above the fold — see the reduced-motion kill-switch
   above for how this gets neutralized when the user asks for no motion. */
.hero-enter {
    opacity: 0;
    transform: translateY(20px);
    transition: opacity .6s ease-out, transform .6s ease-out;
}
.hero-enter.hero-enter-visible { opacity: 1; transform: translateY(0); }

/* Hero video, prepared ahead of the clinic supplying real (text-free)
   footage — see STAGE7-design-polish-spec.md Group B. Inert until a
   `.hero-video-bg` container + <video> is actually added to the markup;
   the crossfade-from-poster and reduced-motion behavior are ready now so
   wiring in the real <video> later is a template-only change. */
.hero-video-bg { position: absolute; inset: 0; z-index: 0; }
.hero-video-bg video {
    width: 100%; height: 100%; object-fit: cover;
    opacity: 0; transition: opacity .8s ease;
}
.hero-video-bg video.is-ready { opacity: 1; }
.hero-image-only.has-video-bg .hero-banner-img { position: relative; z-index: 0; }
@media (prefers-reduced-motion: reduce) {
    /* A silently autoplaying background video is itself a motion
       preference — keep the static poster/banner image instead. */
    .hero-video-bg { display: none; }
}

/* Subtle drifting accent (sol-style) — a soft blurred brand-color blob,
   pure CSS (::before), no markup needed. Very low-contrast on purpose so
   it reads as ambient texture, not a distraction. */
.hero::before, .hero-image-only::before {
    content: '';
    position: absolute;
    top: -60px; right: -60px;
    width: 220px; height: 220px;
    border-radius: 50%;
    background: radial-gradient(circle, var(--color-beige-2) 0%, transparent 70%);
    opacity: .5;
    filter: blur(4px);
    z-index: -1;
    animation: hero-accent-float 10s ease-in-out infinite;
}
@keyframes hero-accent-float {
    0%, 100% { transform: translate(0, 0); }
    50% { transform: translate(-16px, 16px); }
}

.site-footer { background: var(--color-ink); color: var(--color-beige-2); margin-top: 48px; }
.footer-inner { display: flex; flex-wrap: wrap; gap: 24px; padding: 32px 16px; }
.footer-col { flex: 1 1 200px; }
.footer-col a { color: var(--color-beige-2); }
.footer-bottom { padding: 12px 16px; border-top: 1px solid rgba(255, 255, 255, 0.15); font-size: 13px; }

.sticky-bar { position: fixed; bottom: 0; left: 0; right: 0; display: flex; background: #fff; border-top: 1px solid var(--color-beige); z-index: 20; }
.sticky-item { flex: 1; text-align: center; padding: 12px 0; text-decoration: none; font-size: 14px; color: var(--color-ink); }
.sticky-item-primary { background: var(--color-primary); color: #fff; }
@media (min-width: 900px) { .sticky-bar { display: none; } }

/* Desktop-only (mobile's equivalent quick actions already live in
   .sticky-bar at the bottom of the screen) — a call button stacked above
   the existing LINE button, same fixed corner position as before. */
.floating-widget {
    position: fixed; right: 20px; bottom: 80px; z-index: 20;
    display: none; flex-direction: column; align-items: flex-end; gap: 10px;
}
@media (min-width: 900px) { .floating-widget { display: flex; } }
.floating-btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 6px;
    min-width: 44px; min-height: 44px; padding: 12px 18px;
    border-radius: 50px; text-decoration: none; color: #fff;
    box-shadow: 0 4px 14px rgba(62, 43, 35, .22);
}
.floating-btn svg { width: 18px; height: 18px; flex-shrink: 0; }
.floating-call { background: var(--color-primary); }
.floating-line { background: #06c755; animation: floating-line-pulse 2.6s ease-out infinite; }
/* STAGE 7 Group E — slow outward ring pulse, just the LINE button (not
   the whole widget) to stay non-intrusive; kill-switch in the
   reduced-motion block below already collapses this via the global
   `*, *::before, *::after` rule. */
@keyframes floating-line-pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(6, 199, 85, .45); }
    50% { box-shadow: 0 0 0 10px rgba(6, 199, 85, 0); }
}

.cookie-banner { position: fixed; bottom: 0; left: 0; right: 0; background: var(--color-ink); color: #fff; padding: 12px 16px; display: flex; justify-content: space-between; align-items: center; gap: 12px; z-index: 30; }
.cookie-banner button { background: var(--color-primary); color: #fff; border: none; padding: 8px 16px; border-radius: 6px; }

.error-404 { text-align: center; padding: 80px 16px; }

/* Home sections + shared frontend components (Phase 3) */
main section { max-width: 1100px; margin: 0 auto 56px; padding: 0 16px; }
.section-head { display: flex; justify-content: space-between; align-items: center; gap: 16px; margin-bottom: 16px; }
.hero-cta { display: flex; gap: 12px; justify-content: center; margin-top: 16px; }
.hero-cta-bar { display: flex; gap: 12px; justify-content: center; flex-wrap: wrap; max-width: 1100px; margin: 20px auto 40px; padding: 0 16px; }

/* STAGE 7 Group C — section label pill + heading + accent underline.
   The underline's draw-in is pure CSS: it just watches for the ancestor
   <section>'s existing Group A .reveal.is-visible state, no new JS. */
.section-heading { margin-bottom: 4px; }
.section-heading h2 { margin: 0; }
.section-label {
    display: inline-block;
    font-size: 12px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase;
    color: var(--color-primary); background: var(--color-beige-2);
    padding: 4px 14px; border-radius: 999px; margin-bottom: 10px;
}
.section-accent {
    display: block;
    width: 44px; height: 3px; margin-top: 10px;
    background: var(--color-primary); border-radius: 2px;
    transform: scaleX(0); transform-origin: left;
    transition: transform .6s ease .15s;
}
section.reveal.is-visible .section-accent { transform: scaleX(1); }
.home-why, .home-faq { text-align: center; }
.home-why .section-accent, .home-faq .section-accent {
    margin-left: auto; margin-right: auto;
}

/* P1-2 — Why Us icon cards (was a plain 4-item flex list). 3 columns
   desktop, 2 tablet, 1 narrow mobile. */
.why-us-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 20px; }
@media (max-width: 900px) { .why-us-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .why-us-grid { grid-template-columns: 1fr; } }
.why-us-card {
    background: #fff; border: 1px solid var(--color-beige); border-radius: 12px;
    padding: 28px 20px; text-align: center;
    transition: transform .2s ease, box-shadow .2s ease;
}
.why-us-card:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(62, 43, 35, 0.10); }
.why-us-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 56px; height: 56px; border-radius: 50%;
    background: var(--color-beige-2); color: var(--color-primary);
    margin-bottom: 14px;
}
.why-us-icon svg { width: 30px; height: 30px; }
.why-us-card h3 { margin: 0 0 8px; font-size: 16px; }
.why-us-card p { margin: 0; font-size: 13px; color: var(--color-ink); opacity: .8; line-height: 1.6; }

.card-grid, .ba-grid, .review-grid { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; }
.card, .review-card { background: #fff; border: 1px solid var(--color-beige); border-radius: 10px; padding: 16px; overflow: hidden; transition: transform .2s ease, box-shadow .2s ease; }
.card:hover, .review-card:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(62, 43, 35, 0.10); }
.card img { width: 100%; height: 160px; object-fit: cover; border-radius: 6px; margin-bottom: 8px; transition: transform .3s ease; }
.card:hover img { transform: scale(1.05); }
.card .price { color: var(--color-primary); font-weight: 600; }

/* P1-3 — 5 homepage/`/services` display-group cards. The icon badge
   overlaps the bottom edge of the placeholder/photo (negative margin) —
   stays clipped to the card's own rounded corners via the card's own
   overflow:hidden, doesn't bleed outside it.
   Flexbox (not grid) + justify-content:center + flex-grow:0 on purpose:
   with exactly 5 cards, a fixed column count leaves an odd one out on the
   last row (e.g. 4+1) sitting alone at the left edge — centering the
   whole row via flexbox fixes that at every breakpoint automatically,
   including the in-between widths a media-query-only fix would miss. */
.service-group-grid {
    list-style: none; padding: 0; margin: 0;
    display: flex; flex-wrap: wrap; justify-content: center; gap: 20px;
}
.service-group-card {
    flex: 0 1 100%;
    background: #fff; border: 1px solid var(--color-beige); border-radius: 12px;
    overflow: hidden; text-align: center;
    transition: transform .2s ease, box-shadow .2s ease;
}
/* Mobile-first ramp: 1 col -> 2 -> 3 (5 cards = balanced 3+2) -> 5 (single
   row, no leftover at all). Declared after the base rule above so each
   breakpoint's flex-basis actually overrides it, per the project's
   established mobile-first CSS convention. */
@media (min-width: 560px) {
    .service-group-card { flex-basis: calc(50% - 10px); }
}
@media (min-width: 900px) {
    .service-group-card { flex-basis: calc(33.333% - 13.333px); }
}
@media (min-width: 1300px) {
    .service-group-card { flex-basis: calc(20% - 16px); }
}
.service-group-card:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(62, 43, 35, 0.10); }
.service-group-card-media { display: block; }
.service-group-card-icon {
    display: inline-flex; align-items: center; justify-content: center;
    width: 48px; height: 48px; border-radius: 50%;
    background: #fff; color: var(--color-primary);
    margin-top: -24px; box-shadow: 0 2px 8px rgba(62, 43, 35, .15);
    position: relative; z-index: 1;
}
.service-group-card-icon svg { width: 26px; height: 26px; }
.service-group-card h3 { margin: 12px 16px 6px; font-size: 16px; }
.service-group-card p { margin: 0 16px 16px; font-size: 13px; color: var(--color-ink); opacity: .8; line-height: 1.6; }
.service-group-card > a { display: inline-block; margin: 0 0 20px; font-size: 14px; font-weight: 600; color: var(--color-primary); text-decoration: none; }
.service-group-card > a:hover { text-decoration: underline; }

/* STAGE 7 Group E — rounded-arch portrait frame for doctor photos, with a
   soft bottom gradient for a touch of depth. Wraps the <img> so the
   gradient (an ::after) has somewhere to sit — generated content doesn't
   render on replaced elements like <img> itself. */
.portrait-frame {
    position: relative;
    overflow: hidden;
    border-radius: 40px 40px 8px 8px;
    margin-bottom: 8px;
}
.portrait-frame img { display: block; margin-bottom: 0; border-radius: 0; }
.portrait-frame::after {
    content: '';
    position: absolute; left: 0; right: 0; bottom: 0;
    height: 45%;
    background: linear-gradient(to top, rgba(62, 43, 35, .28), transparent);
    pointer-events: none;
}

/* P1-5 — big-photo/bio "Team" layout (home condensed + /doctors full),
   40/60 desktop split, stacks under ~800px matching the existing
   .contact-grid breakpoint convention. .team-feature-reverse (used on
   even rows on /doctors when there's more than one doctor) flips which
   side the photo sits on via CSS order, no markup duplication needed. */
/* gap tightened (was 32px) and align-items:start (was center) so the text
   column begins level with the top of the photo instead of being
   vertically centered against it — with the photo now capped at 400px
   tall (see .team-feature-photo below) and a much shorter text block,
   center-alignment left visible empty space above/below the text, making
   the two columns read as disconnected rather than one balanced unit. */
.team-feature { display: grid; grid-template-columns: 2fr 3fr; gap: 20px; align-items: start; margin-bottom: 32px; }
/* Capped so the photo can't tower over a short text block (was stretching
   to the full 2fr column width, which at 4:5 made for a very tall crop on
   wide screens) — max-width/max-height are set to the same 4:5 ratio
   (320:400) so whichever one is the binding constraint gives the same
   result either way. justify-self:center keeps it centered within its
   grid track instead of stretching (the grid default). */
.team-feature-photo {
    margin-bottom: 0;
    width: 100%;
    max-width: 320px;
    max-height: 400px;
    justify-self: center;
}
.team-feature-photo img { display: block; width: 100%; height: 100%; aspect-ratio: 4 / 5; object-fit: cover; }
.team-feature-body h2, .team-feature-body h3 { margin: 0 0 8px; font-size: 22px; }
.team-feature-license { color: var(--color-primary); font-weight: 600; font-size: 14px; margin: 0 0 12px; }
.team-feature-body p { line-height: 1.8; margin: 0 0 16px; }
@media (max-width: 800px) {
    .team-feature { grid-template-columns: 1fr; }
    .team-feature-reverse .team-feature-photo { order: 0; }
}
@media (min-width: 801px) {
    .team-feature-reverse { grid-template-columns: 3fr 2fr; }
    .team-feature-reverse .team-feature-photo { order: 2; }
    .team-feature-reverse .team-feature-body { order: 1; }
}

.trust-strip {
    display: flex; flex-wrap: wrap; justify-content: center; gap: 12px 24px;
    padding: 20px; background: var(--color-beige-2); border-radius: 12px;
    margin-top: 12px; font-size: 13px; font-weight: 600; color: var(--color-ink);
}

/* STAGE 7 Group C — hover lift to match .card, plus a subtle image zoom
   (clipped by this element's own overflow:hidden so it never bleeds past
   the rounded corners). */
.ba-pair { display: flex; flex-wrap: wrap; gap: 4px; background: #fff; border-radius: 10px; overflow: hidden; border: 1px solid var(--color-beige); transition: transform .2s ease, box-shadow .2s ease; }
.ba-pair:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(62, 43, 35, 0.10); }
.ba-pair img { width: 50%; height: 160px; object-fit: cover; transition: transform .3s ease; }
.ba-pair:hover img { transform: scale(1.04); }
.ba-pair p { width: 100%; padding: 8px; font-size: 13px; }
.ba-pair.ba-composite { display: block; }
.ba-pair.ba-composite img { display: block; width: 100%; aspect-ratio: 4 / 5; object-fit: cover; cursor: zoom-in; }
.ba-pair img.js-lightbox { cursor: zoom-in; }

.ba-load-more-wrap { text-align: center; margin-top: 20px; }

/* P1-4 — "Our Results" portfolio grid (home + /reviews): explicit 4
   columns desktop / 2 mobile (not auto-fill like .ba-grid, per spec's
   precise 4x3), bigger tiles with a bottom-gradient procedure-name
   caption baked onto the photo itself. */
.results-grid { list-style: none; padding: 0; margin: 0; display: grid; grid-template-columns: repeat(4, 1fr); gap: 12px; }
@media (max-width: 900px) { .results-grid { grid-template-columns: repeat(2, 1fr); gap: 10px; } }
.result-tile { position: relative; border-radius: 10px; overflow: hidden; aspect-ratio: 4 / 5; cursor: zoom-in; }
.result-tile img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform .3s ease; }
.result-tile:hover img { transform: scale(1.05); }
.result-tile-caption {
    position: absolute; left: 0; right: 0; bottom: 0;
    padding: 20px 12px 10px;
    background: linear-gradient(to top, rgba(62, 43, 35, .8), transparent);
    color: #fff; font-size: 12px; font-weight: 600; line-height: 1.3;
    pointer-events: none;
}

/* P1-4 — closing CTA band before Contact ("Are you ready" style). */
.cta-band {
    background: var(--color-primary); color: #fff;
    border-radius: 16px; padding: 40px 24px; text-align: center;
}
.cta-band h2 { margin: 0 0 8px; color: #fff; }
.cta-band p { margin: 0 0 20px; opacity: .92; }
.cta-band .btn-primary { background: #fff; color: var(--color-primary); }

/*
 * Hidden by default. NOTE: the `hidden` HTML attribute alone is not
 * reliable here — the UA stylesheet's `[hidden] { display: none }` has the
 * same specificity as an author `.lightbox-overlay { display: ... }` rule,
 * and author CSS always wins that tie regardless of source order, so a
 * flex/block display declared directly on this class would silently
 * cancel `hidden`. Visibility is driven entirely by the `.is-open` class
 * (toggled in main.js), kept in sync with the `hidden` attribute for
 * accessibility (screen readers).
 */
.lightbox-overlay {
    display: none;
    position: fixed; inset: 0; background: rgba(0, 0, 0, 0.85);
    align-items: center; justify-content: center;
    padding: 24px; z-index: 50; cursor: zoom-out;
    pointer-events: none;
    opacity: 0;
    transition: opacity .25s ease;
}
.lightbox-overlay.is-open { display: flex; pointer-events: auto; }
/* .is-visible is added one frame after .is-open (see main.js) so the
   opacity/scale transition actually has a "from" state to animate out of,
   same double-rAF trick as the Group B hero entrance. */
.lightbox-overlay.is-visible { opacity: 1; }
.lightbox-overlay img {
    max-width: 100%; max-height: 100%; border-radius: 8px; cursor: default;
    opacity: 0; transform: scale(.94);
    transition: opacity .3s ease, transform .25s ease;
}
.lightbox-overlay.is-visible img.is-loaded { opacity: 1; transform: scale(1); }
.lightbox-close {
    position: absolute; top: 16px; right: 20px; background: transparent; border: 0;
    color: #fff; font-size: 32px; line-height: 1; cursor: pointer; padding: 8px;
}

/* Shown while the medium-size image is loading (its `src` was just set),
   hidden once the browser fires `load` and main.js adds `.is-loaded`. */
.lightbox-spinner {
    position: absolute;
    width: 40px; height: 40px;
    border: 3px solid rgba(255, 255, 255, .25);
    border-top-color: #fff;
    border-radius: 50%;
    opacity: 0;
    transition: opacity .2s ease;
    animation: lightbox-spin .8s linear infinite;
    pointer-events: none;
}
.lightbox-overlay.is-loading .lightbox-spinner { opacity: 1; }
@keyframes lightbox-spin {
    to { transform: rotate(360deg); }
}

.review-stars { color: var(--color-primary-2); }
.review-author { display: block; margin-top: 8px; font-size: 13px; color: #777; }

.faq-list { display: flex; flex-direction: column; gap: 8px; }
.faq-item { background: var(--color-beige-2); border-radius: 8px; padding: 12px 16px; }
.faq-item summary { cursor: pointer; font-weight: 600; }

.booking-form { max-width: 480px; margin: 0 auto; background: #fff; border: 1px solid var(--color-beige); border-radius: 10px; padding: 24px; }
.booking-form label { display: block; margin-bottom: 12px; font-size: 14px; }
.booking-form input, .booking-form select, .booking-form textarea {
    width: 100%; padding: 8px; margin-top: 4px; border: 1px solid #ccc; border-radius: 4px; font-family: inherit;
}
.booking-form-row { display: flex; gap: 12px; }
.booking-form-row label { flex: 1; }
.booking-form .checkbox-label { display: flex; align-items: flex-start; gap: 8px; font-size: 13px; }
.booking-form .checkbox-label input { width: auto; margin-top: 3px; }
.booking-form button { width: 100%; margin-top: 8px; }
.form-flash { padding: 10px; border-radius: 6px; font-size: 14px; }
.form-flash-success { background: #dcfce7; color: #166534; }
.form-flash-error { background: #fee2e2; color: #991b1b; }

/* About page — 3 pillars */
.static-page { max-width: 1000px; margin: 0 auto; padding: 0 16px; }
.about-pillars { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 28px; margin-top: 40px; }
.pillar-card {
    background: #fff;
    border-top: 3px solid var(--color-primary);
    border-radius: 12px;
    padding: 32px 24px;
    text-align: center;
    box-shadow: 0 4px 16px rgba(62, 43, 35, 0.08);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.pillar-card:hover { transform: translateY(-4px); box-shadow: 0 8px 24px rgba(62, 43, 35, 0.14); }
.pillar-card h2 { font-size: 15px; letter-spacing: 0.06em; color: var(--color-primary); margin: 0 0 14px; text-transform: uppercase; font-weight: 700; }
.pillar-card p { font-size: 14px; line-height: 1.8; margin: 0; color: var(--color-ink); }

/* Service detail template (spec §5) */
.service-detail-section { margin-bottom: 32px; }
.service-detail-section h2 { font-size: 18px; border-bottom: 2px solid var(--color-primary); display: inline-block; padding-bottom: 4px; }
.service-price-box { background: var(--color-beige-2); border: 1px solid var(--color-beige); border-radius: 8px; padding: 16px; }
.breadcrumb { font-size: 13px; color: #777; margin-bottom: 16px; }
.breadcrumb a { text-decoration: none; }

/* Article detail */
.article-detail .article-meta { color: #777; font-size: 13px; margin-bottom: 16px; }
.article-detail .article-cover { width: 100%; max-height: 400px; object-fit: cover; border-radius: 8px; margin-bottom: 16px; }
.article-detail .article-body { line-height: 1.8; }
.article-detail iframe { width: 100%; aspect-ratio: 16/9; border: 0; border-radius: 8px; margin: 16px 0; }

.contact-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 32px; }
/* aspect-ratio instead of a fixed pixel height (was 260px regardless of
   width) so it scales proportionally at any column/viewport width — same
   technique already used for .article-detail iframe below. max-height is
   a belt-and-suspenders cap on top of that (the real fix for the
   distortion on wide screens was giving /contact's whole page a
   max-width container — see contact.blade.php — since the map's own
   column was never the actual problem, an unconstrained page was). */
.contact-info iframe { width: 100%; aspect-ratio: 4 / 3; height: auto; max-height: 400px; border: 0; border-radius: 8px; margin-top: 16px; }
@media (max-width: 800px) { .contact-grid { grid-template-columns: 1fr; } }

/* STAGE 7 Group A — scroll-reveal foundation.
   `.reveal` only ever touches opacity/transform (never box size), so it
   can never introduce layout shift regardless of when the observer fires.
   Elements are tagged + observed by main.js, not hand-added in Blade. */
.reveal {
    opacity: 0;
    transform: translateY(16px);
    transition: opacity .5s ease-out, transform .5s ease-out;
}
.reveal.is-visible { opacity: 1; transform: translateY(0); }

/* STAGE 7 Group E — fade-in once a lazy-loaded image's bytes actually
   arrive (`.img-loaded`, toggled in main.js off the `load` event / an
   already-`.complete` check for cached images). Scoped to
   `img[loading="lazy"]` only — the before/after gallery thumbnails, not a
   blanket rule over every image on the site (hero/logo/etc. render
   immediately, no fade needed, and starting them hidden would risk a
   flash-of-nothing if JS is slow to attach). Opacity-only, so it can't
   shift layout. */
img[loading="lazy"] { opacity: 0; transition: opacity .35s ease; }
img[loading="lazy"].img-loaded { opacity: 1; }

/* P1-0 — <x-placeholder> "materials needed" box. Meant to look intentional
   (client-meeting-ready), not like a broken image: dashed CI-rose-gold
   border, tinted cream fill, centered line-icon + label. aspect-ratio is
   set inline per-instance (see the component), so the box is always the
   exact real ratio the eventual asset will be, no CLS when it's swapped
   in later. */
.placeholder-box {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 10px;
    width: 100%;
    border: 2px dashed var(--color-primary);
    border-radius: 12px;
    background: var(--color-beige-2);
    color: var(--color-primary);
    padding: 16px;
    text-align: center;
    box-sizing: border-box;
}
.placeholder-icon svg { width: 40px; height: 40px; color: var(--color-primary); opacity: .8; }
.placeholder-text { font-size: 13px; font-weight: 600; line-height: 1.5; max-width: 90%; }
.placeholder-media { display: block; width: 100%; height: 100%; object-fit: cover; }

/* Motion kill-switch: one place that turns everything off, rather than
   wrapping every rule above in its own reduced-motion guard. */
@media (prefers-reduced-motion: reduce) {
    /* Bare `*` does not match generated content — `::before`/`::after`
       need their own entry, otherwise pseudo-element animations (e.g. the
       hero accent float) keep running under reduced-motion. Confirmed via
       a real headless-Chrome check during STAGE 7 Group B. */
    *, *::before, *::after {
        animation-duration: .001ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: .001ms !important;
        scroll-behavior: auto !important;
    }
    .reveal { opacity: 1 !important; transform: none !important; }
}
