/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.95rem;
  padding: 0.8rem 1.4rem;
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  cursor: pointer;
  text-decoration: none;
  transition: background-color 150ms ease, border-color 150ms ease;
  line-height: 1;
  min-height: 44px;
}
.btn-primary { background: var(--kiln); color: var(--ink); }
.btn-primary:hover { background: var(--kiln-deep); }
.btn-secondary { background: transparent; color: var(--text); border-color: var(--text); }
.btn-secondary:hover { background: var(--surface-2); }
.btn-whatsapp { background: var(--whatsapp); color: #ffffff; }
.btn-whatsapp:hover { background: #1fb959; }
.btn-sm { font-size: 0.82rem; padding: 0.55rem 1rem; min-height: auto; }
.btn-row { display: flex; gap: 0.75rem; flex-wrap: wrap; align-items: center; }

/* ---------- Ticker bar (top of the fixed header) ---------- */
/* A slim, always-dark strip regardless of whether the nav row below it is
   transparent or solid — see includes/ticker.php — so it stays legible in
   both states without its own scroll-driven color logic. It's part of the
   same fixed <header>, so it grows the header's total height and the
   existing --header-h measurement (assets/js/main.js) picks that up
   automatically; nothing else needed offsetting content below it. */
/* Collapses smoothly to nothing on scroll-down and expands back on
   scroll-up (see assets/js/main.js) — the header itself never moves or
   hides, only this row's own height animates, so the nav row above rides
   up to fill the freed space and ends up sitting right at the fixed
   header's top edge once the ticker is collapsed. Same 0fr/1fr grid-row
   collapse technique already used for the FAQ accordion elsewhere in this
   project, which handles content of any height without guessing pixels. */
.ticker-bar {
  background: var(--ink-deep);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 320ms ease, border-color 320ms ease;
}
.ticker-bar.is-hidden { grid-template-rows: 0fr; border-bottom-color: transparent; }
.ticker-bar-inner { overflow: hidden; }
.ticker-track {
  display: flex;
  width: max-content;
  align-items: center;
  animation: ticker-scroll 42s linear infinite;
}
.ticker-bar:hover .ticker-track { animation-play-state: paused; }
@keyframes ticker-scroll {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}
.ticker-item {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.4rem 1.1rem;
  color: rgba(255, 255, 255, 0.82);
  font-family: var(--font-body);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  white-space: nowrap;
  flex: 0 0 auto;
}
.ticker-sep { width: 9px; height: 9px; color: var(--kiln); flex-shrink: 0; }
@media (prefers-reduced-motion: reduce) {
  .ticker-track { animation: none; }
}

/* ---------- Header / Navigation ---------- */
/* Fixed + transparent-capable: a page opts in via the `transparent_header`
   $page flag (see includes/header.php), which renders .site-header--transparent.
   assets/js/main.js then adds .is-scrolled once the page's hero has scrolled
   past, switching it to the solid white treatment. Pages without a hero
   render .site-header--solid instead and stay solid the whole time — no JS
   needed there, so there's no flash of the wrong state. */
.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 50;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background-color 280ms ease, border-color 280ms ease, box-shadow 280ms ease;
  --header-fg: #ffffff;
}
.site-header--solid,
.site-header--transparent.is-scrolled {
  background: #ffffff;
  border-bottom-color: var(--border);
  box-shadow: 0 2px 14px rgba(15, 23, 30, 0.08);
  --header-fg: var(--ink);
}
/* Vertical padding only. This was `padding: 1rem 0`, and the shorthand's
   horizontal `0` overrode the `0 var(--space-5)` that .wrap sets on the same
   element — .nav-bar carries both classes. The header therefore ignored the
   page's gutter entirely: the logo and menu button sat 24px outside every
   other block on the page, and on a phone that meant flush against the
   screen edge with nothing to breathe against. Setting only the block axis
   leaves .wrap's inline padding intact, so the header lines up with the
   content beneath it at every width. */
.nav-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding-block: 1rem;
  transition: padding 280ms ease;
}
/* Once the header is solid (scrolled past the hero, or a page that's
   solid from the start), it no longer needs the same tall presence it has
   floating over the hero image — tighten the vertical padding here so the
   overall header gets shorter, not just recolored. */
.site-header--solid .nav-bar,
.site-header--transparent.is-scrolled .nav-bar {
  padding-block: 0.6rem;
}
.brand {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.15rem;
  color: var(--header-fg);
  text-decoration: none;
  transition: color 280ms ease;
  display: inline-flex;
  align-items: center;
  gap: 0.65rem;
}
/* Image logo — see config/site.php's logo_image. Nothing here has any
   effect until a logo file is actually configured (the markup simply
   doesn't render the <img> tags otherwise).
   When a reversed (light) variant is also configured, it's markup-ordered
   right before the primary logo — ".brand-logo-reversed + .brand-logo"
   below matches the primary only in that case, so a single-logo setup
   (no reversed variant) is completely unaffected by these rules. */
/* Width:height ratios below match the logo artwork's own aspect ratio
   (currently 500x400 = 1.25:1) so the circular badge scales evenly instead
   of stretching into an oval — object-fit:contain is a safety net for
   whenever the artwork is next replaced with a different aspect ratio. */
.brand-logo { height: 50px; width: 63px; object-fit: contain; display: block; transition: height 280ms ease, width 280ms ease; }
.brand-logo-reversed { display: none; }
.site-header--transparent:not(.is-scrolled) .brand-logo-reversed { display: block; }
.site-header--transparent:not(.is-scrolled) .brand-logo-reversed + .brand-logo { display: none; }
/* Smaller once the header is solid — keeps the *floating-over-the-hero*
   logo at its full requested size, while letting the header itself get
   noticeably shorter once scrolled (the logo was the tallest thing
   setting that row's height). */
.site-header--solid .brand-logo,
.site-header--transparent.is-scrolled .brand-logo {
  height: 40px;
  width: 50px;
}
/* Title text shown beside the logo icon — colors match the source logo
   artwork: "Leo" stays the same amber/gold in both header states (it
   already reads fine on light and dark), "Invisible Grills" reuses
   --header-fg, the same variable driving every other header text color,
   so it's white over the transparent hero and switches to navy
   automatically the instant the header goes solid — no separate rule
   needed here to keep that in sync. */
.brand-title { font-size: 1.05rem; line-height: 1.15; white-space: nowrap; }
.brand-title-accent { color: var(--kiln); }
.brand-title-name { color: var(--header-fg); transition: color 280ms ease; }
@media (min-width: 861px) {
  .brand-logo { height: 58px; width: 73px; }
  .brand-title { font-size: 1.4rem; }
  .site-header--solid .brand-logo,
  .site-header--transparent.is-scrolled .brand-logo {
    height: 46px;
    width: 58px;
  }
}
.site-nav {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  font-size: 0.92rem;
  font-weight: 500;
}
.site-header .btn-secondary { color: var(--header-fg); border-color: var(--header-fg); transition: color 280ms ease, border-color 280ms ease; }
.site-header--solid .btn-secondary:hover,
.site-header--transparent.is-scrolled .btn-secondary:hover { background: var(--surface-2); }
.site-header--transparent:not(.is-scrolled) .btn-secondary:hover { background: rgba(255, 255, 255, 0.12); }

.nav-toggle {
  display: none;
  flex-direction: column;
  gap: 4px;
  background: none;
  border: none;
  cursor: pointer;
  padding: 8px;
}
.nav-toggle span { width: 22px; height: 2px; background: var(--header-fg); display: block; transition: background-color 280ms ease; }

.nav-services { position: relative; }
.nav-services summary {
  cursor: pointer;
  list-style: none;
  font-weight: 500;
}
.nav-services summary::-webkit-details-marker { display: none; }
.nav-services .dropdown { display: flex; flex-direction: column; }
.nav-services .dropdown a {
  padding: 0.5rem 0.75rem;
  display: block;
  text-decoration: none;
  color: var(--text);
  border-radius: 4px;
  font-size: 0.9rem;
}
.nav-services .dropdown a:hover { background: var(--surface-2); }
/* WhatsApp button in the nav: mobile-menu only — "Get Free Quote" already
   covers desktop, and doubling both CTAs into the slim desktop bar would
   crowd it. */
.nav-whatsapp { display: none; }

@media (min-width: 861px) {
  .site-nav > a, .nav-services summary { text-decoration: none; color: var(--header-fg); transition: color 280ms ease; }
  .nav-services[open] .dropdown {
    position: absolute;
    top: calc(100% + 0.5rem);
    left: 0;
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--radius-md);
    padding: 0.5rem;
    min-width: 230px;
    box-shadow: 0 12px 24px -12px rgba(22, 35, 46, 0.25);
    z-index: 20;
  }
}

@media (max-width: 860px) {
  /* The mobile panel is always its own opaque light surface regardless of
     header state, so its links stay a fixed dark color — never --header-fg. */
  .site-nav > a, .nav-services summary { text-decoration: none; color: var(--text); }
  .nav-toggle { display: flex; }
  .site-nav {
    position: fixed;
    inset: 0;
    top: var(--header-h, 65px);
    background: var(--bg);
    flex-direction: column;
    align-items: flex-start;
    padding: var(--space-6) var(--space-5);
    transform: translateX(100%);
    transition: transform 200ms ease;
    overflow-y: auto;
    gap: var(--space-4);
  }
  .site-nav.is-open { transform: translateX(0); }
  .nav-services { width: 100%; }
  .nav-cta, .nav-whatsapp { align-self: stretch; justify-content: center; }
  .nav-whatsapp { display: inline-flex; }
}

/* ---------- Hero ---------- */
/* Fixed header offset: main content starts padded below the header height,
   except a hero that's the very first thing in <main> — it pulls back up
   to y=0 so its own dark background sits behind the transparent header,
   while re-adding the same padding internally so its *content* still
   clears the header. See assets/js/main.js for how --header-h is measured. */
main#main-content { padding-top: var(--header-h, 72px); }
main#main-content > .hero:first-child,
main#main-content > .home-hero:first-child {
  margin-top: calc(var(--header-h, 72px) * -1);
  padding-top: var(--header-h, 72px);
}

.hero {
  position: relative;
  overflow: hidden;
  padding-bottom: var(--space-7);
  background: linear-gradient(160deg, var(--ink-deep) 0%, var(--ink) 55%, var(--steel) 150%);
}
/* Real installation photo (data/services.php 'hero_image'), layered behind
   the mesh texture and a darkening gradient so the existing white hero
   copy/breadcrumbs stay legible over any photo. */
.hero-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
.hero-photo-overlay {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: linear-gradient(160deg, rgba(12, 22, 30, 0.88) 0%, rgba(22, 35, 46, 0.78) 55%, rgba(71, 96, 110, 0.55) 150%);
  pointer-events: none;
}
.hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.05) 0, rgba(255, 255, 255, 0.05) 1.5px, transparent 1.5px, transparent 18px),
    repeating-linear-gradient(-45deg, rgba(255, 255, 255, 0.05) 0, rgba(255, 255, 255, 0.05) 1.5px, transparent 1.5px, transparent 18px);
  pointer-events: none;
}
.hero-inner { position: relative; z-index: 3; max-width: 60ch; padding-top: var(--space-6); }
.hero h1 { font-size: var(--h1); margin: 0 0 var(--space-4); color: #fff; }
.hero-lede { color: rgba(255, 255, 255, 0.8); font-size: 1.1rem; max-width: 52ch; margin: 0 0 var(--space-5); }
.hero .btn-secondary { color: #fff; border-color: rgba(255, 255, 255, 0.75); }
.hero .btn-secondary:hover { background: rgba(255, 255, 255, 0.12); }

/* Breadcrumbs sitting inside the dark hero (service pages) need light-on-
   dark colors instead of the default light-surface ones, plus a hard
   guard against overflow — flex-wrap alone is normally enough, but
   nowrap+scroll is the fallback if a very long service/location name ever
   doesn't fit on a narrow screen, so the trail never breaks the hero's
   layout or clips silently. */
.hero .breadcrumbs { position: relative; z-index: 3; padding: var(--space-4) 0 0; overflow-x: auto; }
.hero .breadcrumbs ol { flex-wrap: nowrap; }
.hero .breadcrumbs a { color: rgba(255, 255, 255, 0.7); }
.hero .breadcrumbs a:hover { color: #fff; }
.hero .breadcrumbs span[aria-current="page"] { color: #fff; }
.hero .breadcrumbs .sep { color: rgba(255, 255, 255, 0.4); }

/* Fallback only: large, low-opacity service icon watermark, used in place
   of .hero-photo for any service that doesn't yet have a real hero_image
   in data/services.php — see templates/service-page.php. */
.hero-bg-icon {
  position: absolute;
  right: -4%;
  bottom: -8%;
  width: min(55%, 560px);
  opacity: 0.07;
  color: #fff;
  pointer-events: none;
  z-index: 0;
}
.hero-bg-icon-svg { width: 100%; height: auto; display: block; }

.hero-feature-badges { display: flex; flex-wrap: wrap; gap: 0.5rem; margin: 0 0 var(--space-5); }
.hero-feature-badge {
  display: inline-flex;
  align-items: center;
  padding: 0.45rem 0.9rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: #fff;
  font-size: 0.82rem;
  font-weight: 600;
}

/* ---------- Homepage hero (full-bleed service carousel) ---------- */
/* Isolated, homepage-only classes (prefixed home-hero-) — deliberately not
   reusing .hero/.hero-copy/.hero-visual, which every other page's hero
   still hand-rolls (see templates/*.php), so none of this touches them. */
.home-hero { background: var(--ink-deep); padding-bottom: var(--space-5); }
.home-hero-eyebrow-row { text-align: center; padding-top: 0; padding-bottom: var(--space-2); }
.home-hero-eyebrow {
  display: block;
  width: 100%;
  box-sizing: border-box;
  margin: 0;
  padding: 0.4rem 1.1rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.22);
  color: rgba(255, 255, 255, 0.85);
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.78rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-align: center;
}
/* Stage height is expressed in vh, not aspect-ratio, so it's sized against
   the viewport that actually needs to fit the title + CTAs below it — an
   aspect-ratio tied to width alone would blow past the viewport on short/
   wide screens. Tuned separately per breakpoint (see media queries below). */
.home-hero-stage {
  position: relative;
  width: 100%;
  height: min(34vh, 320px);
  overflow: hidden;
  background:
    radial-gradient(120% 90% at 15% 0%, rgba(217, 138, 52, 0.16), transparent 60%),
    linear-gradient(160deg, var(--ink-deep) 0%, var(--ink) 55%, var(--steel) 150%);
}
/* Blends the bottom of the stage into the dark section beneath it. Reduced
   from 40% to 24% of the stage height: stacked on top of the overlay's own
   bottom band, 40% meant the lower half of every hero photo was being
   darkened twice over. 24% still lands the blend cleanly. */
.home-hero-stage::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 24%;
  background: linear-gradient(to bottom, transparent, var(--ink-deep));
  pointer-events: none;
}
/* display:none as the base state (not just the [hidden] attribute) — a
   competing author `display` rule at equal specificity would otherwise
   beat the UA stylesheet's [hidden]{display:none} and defeat it. */
.home-hero-slide { position: absolute; inset: 0; display: none; align-items: center; justify-content: center; }
.home-hero-slide.is-active { display: flex; }
.home-hero-art { position: relative; width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; }
.home-hero-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; z-index: 0; }
/* Edge shading only — the middle of the photo is left completely clear.
   This used to be a full-cover diagonal wash (inset:0, ~55% black at the top
   corner fading to ~22%), which dimmed every hero photo across its whole
   area. Nothing is written on top of the photo — the h1 sits above the stage
   and the service name and buttons sit below it — so darkening the middle
   bought no legibility, it only made the photography look flat and murky.
   What genuinely does need shading is the two edges: the top, where the
   transparent header's white text crosses the image, and the bottom, behind
   the carousel controls and blending into the section below. So each edge
   gets its own band and they do not meet. */
.home-hero-photo-overlay {
  position: absolute;
  inset: 0;
  z-index: 1;
  background:
    linear-gradient(to bottom, rgba(12, 22, 30, 0.60), rgba(12, 22, 30, 0.26) 45%, transparent) top / 100% 20% no-repeat,
    linear-gradient(to top, rgba(12, 22, 30, 0.62), rgba(12, 22, 30, 0.26) 45%, transparent) bottom / 100% 24% no-repeat;
  pointer-events: none;
}
.home-hero-mesh {
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.06) 0, rgba(255, 255, 255, 0.06) 1.5px, transparent 1.5px, transparent 18px),
    repeating-linear-gradient(-45deg, rgba(255, 255, 255, 0.06) 0, rgba(255, 255, 255, 0.06) 1.5px, transparent 1.5px, transparent 18px);
}
.home-hero-icon-badge {
  position: relative;
  width: min(40vw, 26vh, 170px);
  height: min(40vw, 26vh, 170px);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: radial-gradient(circle at 32% 28%, rgba(255, 255, 255, 0.18), rgba(255, 255, 255, 0.05) 60%, transparent 78%);
  border: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow: 0 20px 45px -16px rgba(0, 0, 0, 0.55), inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
.home-hero-icon { width: 46%; height: 46%; color: rgba(255, 255, 255, 0.95); filter: drop-shadow(0 8px 16px rgba(0, 0, 0, 0.3)); }

/* Sized down on mobile (small stage heights mean this badge otherwise eats
   a big share of the visible photo) and pulled closer to the bottom edge;
   restored to its original, larger size from the tablet breakpoint up —
   see the min-width:600px override below. */
.home-hero-controls {
  position: absolute;
  left: var(--space-4);
  bottom: 0.55rem;
  display: flex;
  align-items: center;
  gap: 0.45rem;
  background: rgba(12, 22, 30, 0.55);
  backdrop-filter: blur(6px);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 999px;
  padding: 0.3rem 0.5rem;
}
.home-hero-play {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 1.6rem;
  height: 1.6rem;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.35);
  background: transparent;
  color: #fff;
  cursor: pointer;
  flex: 0 0 auto;
}
/* Author display:flex above sits at equal specificity to (and, being an
   author rule, outranks) the UA [hidden]{display:none} default — without
   this override, the play and pause buttons would both render at once
   whichever one currently carries the `hidden` attribute (see the same
   fix already applied to .home-hero-slide for the identical reason). */
.home-hero-play[hidden] { display: none; }
.home-hero-play:hover { background: rgba(255, 255, 255, 0.12); }
.home-hero-play svg { width: 0.8rem; height: 0.8rem; fill: currentColor; }
.home-hero-indicators { display: flex; align-items: center; gap: 0.35rem; }
.home-hero-indicator {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  border: none;
  background: rgba(255, 255, 255, 0.4);
  cursor: pointer;
  padding: 0;
  transition: width 200ms ease, background-color 200ms ease;
}
.home-hero-indicator.is-active { width: 20px; background: #fff; }

.home-hero-copy-wrap { padding-top: var(--space-4); text-align: center; }
.home-hero-copy h2 { font-size: var(--h1); margin: 0 0 var(--space-3); color: #fff; }
.home-hero-btn-row { justify-content: center; }
.btn-hero-outline { background: transparent; color: #fff; border-color: rgba(255, 255, 255, 0.75); border-radius: 999px; }
.btn-hero-outline:hover { background: rgba(255, 255, 255, 0.12); border-color: #fff; }
.btn-hero-solid { background: var(--kiln); color: var(--ink); border-radius: 999px; }
.btn-hero-solid:hover { background: var(--kiln-deep); }

/* Tablet */
@media (min-width: 600px) {
  .home-hero-stage { height: min(40vh, 400px); }
  .home-hero-icon-badge { width: min(30vw, 30vh, 190px); height: min(30vw, 30vh, 190px); }
  .home-hero-controls {
    left: var(--space-5);
    bottom: var(--space-5);
    gap: var(--space-3);
    padding: 0.5rem 0.7rem;
  }
  .home-hero-play { width: 2.1rem; height: 2.1rem; }
  .home-hero-play svg { width: 1rem; height: 1rem; }
  .home-hero-indicators { gap: 0.4rem; }
  .home-hero-indicator { width: 8px; height: 8px; }
  .home-hero-indicator.is-active { width: 26px; }
  /* Shrink-to-fit instead of stretching the full row width, from tablet up,
     so the badge reads as a compact pill sized to its own text, centered
     by the .home-hero-eyebrow-row wrapper's text-align:center — mobile
     keeps the full-width block (needed so long text can wrap centered on a
     narrow screen; see the home-hero-eyebrow-row rule above). */
  .home-hero-eyebrow { display: inline-block; width: auto; }
}
/* Desktop — the image div gets noticeably taller here (not just the
   proportional step tablet already got), while the controls badge above
   stays exactly the tablet size fixed just above — it must never shrink
   again on top of that. */
@media (min-width: 1024px) {
  .home-hero-stage { height: min(58vh, 600px); }
  .home-hero-icon-badge { width: min(16vw, 30vh, 190px); height: min(16vw, 30vh, 190px); }
}

/* ---------- Sections ---------- */
.section { padding: var(--space-8) 0; }
.section.alt { background: var(--surface); }
/* Tighter vertical rhythm for a few specific back-to-back stretches on
   service pages (Installation Video + Hyderabad Overview; Safety/FAQ/
   Service-Areas — see templates/service-page.php) — not a global .section
   change, so nothing elsewhere on the site is affected. */
.section-tight { padding: var(--space-6) 0; }
.section#testimonials + .section#faqs { padding-top: var(--space-5); }
.section h2 { font-size: var(--h2); margin-bottom: var(--space-3); }
.section-lede { color: var(--text-muted); max-width: 60ch; margin-bottom: var(--space-6); }

/* ---------- Homepage introduction ---------- */
.home-intro {
  padding: var(--space-7) 0 var(--space-6);
  background: linear-gradient(180deg, var(--ink-deep) 0, var(--ink-deep) 18%, var(--bg) 76%);
}
.home-intro-card {
  position: relative;
  overflow: hidden;
  display: grid;
  grid-template-columns: minmax(230px, 0.8fr) minmax(0, 1.35fr);
  gap: var(--space-6) var(--space-7);
  padding: clamp(var(--space-5), 4vw, var(--space-7));
  background:
    linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(244, 242, 236, 0.98)),
    var(--surface);
  border: 1px solid rgba(255, 255, 255, 0.72);
  border-radius: var(--radius-md);
  box-shadow: 0 18px 38px -24px rgba(12, 22, 30, 0.7), 0 2px 0 rgba(255, 255, 255, 0.7) inset;
}
.home-intro-card::after {
  content: "";
  position: absolute;
  width: 18rem;
  height: 18rem;
  right: -8rem;
  top: -10rem;
  border: 1px solid rgba(71, 96, 110, 0.12);
  border-radius: 50%;
  box-shadow: 0 0 0 1.5rem rgba(71, 96, 110, 0.04), 0 0 0 3rem rgba(71, 96, 110, 0.03);
  pointer-events: none;
}
.home-intro-heading,
.home-intro-copy,
.home-intro-details { position: relative; z-index: 1; }
.home-intro-heading { border-left: 3px solid var(--kiln); padding-left: var(--space-4); }
.home-intro-kicker {
  color: var(--steel);
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  line-height: 1.3;
  margin-bottom: var(--space-3);
  text-transform: uppercase;
}
.home-intro h2 { font-size: var(--h2); margin: 0; }
.home-intro-copy { align-self: center; }
.home-intro-copy p { color: var(--text-muted); margin-bottom: var(--space-4); }
.home-intro-copy p:last-child { margin-bottom: 0; }
.home-intro-details {
  grid-column: 1 / -1;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-5);
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
  color: var(--ink);
  font-family: var(--font-display);
  font-size: 0.92rem;
  font-weight: 700;
}
.home-intro-details span { display: inline-flex; align-items: center; gap: var(--space-2); }
.home-intro-details span::before {
  content: "";
  width: 0.45rem;
  height: 0.45rem;
  border-radius: 50%;
  background: var(--kiln);
  box-shadow: 0 0 0 3px rgba(217, 138, 52, 0.15);
}
@media (max-width: 700px) {
  .home-intro { padding-top: var(--space-6); }
  .home-intro-card { grid-template-columns: 1fr; gap: var(--space-5); }
  .home-intro-details { grid-column: auto; display: grid; gap: var(--space-3); }
}

/* ---------- Homepage showcase ---------- */
.home-showcase {
  padding: var(--space-8) 0;
  background: var(--bg);
}
.home-showcase-inner { text-align: center; }
.home-showcase-kicker {
  color: var(--kiln-deep);
  font-family: var(--font-display);
  font-size: 0.8rem;
  font-weight: 800;
  letter-spacing: 0.1em;
  margin-bottom: var(--space-3);
  text-transform: uppercase;
}
.home-showcase h2 {
  max-width: 20ch;
  margin: 0 auto var(--space-4);
  font-size: clamp(2rem, 1.5rem + 2.2vw, 3.25rem);
}
.home-showcase-lede {
  max-width: 58ch;
  margin: 0 auto var(--space-7);
  color: var(--text-muted);
  font-size: 1.08rem;
}
.home-showcase-media {
  position: relative;
  width: min(100%, 920px);
  aspect-ratio: 16 / 10;
  margin: 0 auto;
  overflow: visible;
  border: 1px solid rgba(71, 96, 110, 0.34);
  border-radius: var(--radius-md);
  background:
    linear-gradient(135deg, rgba(12, 22, 30, 0.97), rgba(71, 96, 110, 0.88)),
    var(--ink);
  box-shadow: 0 20px 40px -25px rgba(12, 22, 30, 0.7), 0 0 0 8px rgba(217, 138, 52, 0.08);
}
.home-showcase-thumbnail {
  position: absolute;
  inset: 0;
  overflow: hidden;
  border-radius: inherit;
  background:
    linear-gradient(90deg, rgba(12, 22, 30, 0.86) 0%, rgba(12, 22, 30, 0.25) 42%, rgba(217, 138, 52, 0.18) 100%),
    linear-gradient(155deg, transparent 0 36%, rgba(255, 255, 255, 0.15) 36.2% 36.6%, transparent 36.8% 100%),
    repeating-linear-gradient(90deg, rgba(255, 255, 255, 0.25) 0 2px, transparent 2px 38px),
    linear-gradient(135deg, #314754 0%, #8ca0a5 52%, #d8c7a6 100%);
}
.home-showcase-thumbnail::before,
.home-showcase-thumbnail::after {
  content: "";
  position: absolute;
  pointer-events: none;
}
.home-showcase-thumbnail::before {
  inset: 8% 11% 0 8%;
  border: 1px solid rgba(255, 255, 255, 0.28);
  border-bottom: 0;
  transform: skewY(-5deg);
}
.home-showcase-thumbnail::after {
  width: 34%;
  height: 50%;
  right: 11%;
  bottom: 0;
  border-left: 1px solid rgba(255, 255, 255, 0.32);
  border-right: 1px solid rgba(255, 255, 255, 0.32);
  background: repeating-linear-gradient(90deg, transparent 0 18px, rgba(255, 255, 255, 0.28) 18px 20px);
}
.home-showcase-thumbnail-label {
  position: absolute;
  left: clamp(1.25rem, 5vw, 3.5rem);
  bottom: clamp(1.25rem, 5vw, 3rem);
  z-index: 1;
  color: rgba(255, 255, 255, 0.88);
  font-family: var(--font-display);
  font-size: clamp(1rem, 1.5vw, 1.35rem);
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}
.home-showcase-play {
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 50%;
  width: 5.5rem;
  height: 5.5rem;
  border: 1px solid rgba(255, 255, 255, 0.8);
  border-radius: 50%;
  background: rgba(251, 250, 247, 0.94);
  box-shadow: 0 10px 25px -14px rgba(12, 22, 30, 0.9);
  transform: translate(-50%, -50%);
}
.home-showcase-play::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 54%;
  width: 0;
  height: 0;
  border-top: 0.8rem solid transparent;
  border-bottom: 0.8rem solid transparent;
  border-left: 1.2rem solid var(--kiln);
  transform: translate(-50%, -50%);
}
.home-showcase-media::before,
.home-showcase-media::after {
  content: "";
  position: absolute;
  pointer-events: none;
}
.home-showcase-media::before {
  inset: 0;
  border-radius: inherit;
  background:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.055) 0, rgba(255, 255, 255, 0.055) 1px, transparent 1px, transparent 22px),
    repeating-linear-gradient(-45deg, rgba(255, 255, 255, 0.04) 0, rgba(255, 255, 255, 0.04) 1px, transparent 1px, transparent 22px);
}
.home-showcase-media::after {
  width: 45%;
  height: 1px;
  top: 50%;
  left: 27.5%;
  background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.22), transparent);
}
/* Real installation video — a portrait phone recording, so it gets its
   own frame sized to that aspect ratio (matches the source file exactly:
   480x864) rather than being force-cropped into the wide abstract
   placeholder box above. */
/* The framed video player, shared by the homepage showcase and the
   installation video on the Invisible Grills and Balcony Safety Nets service
   pages. It lives under one neutral name because those pages must look
   identical: same 420px cap, same 480x864 portrait ratio (the footage is
   phone-shot, so a 16:9 box would crop most of the frame away), same corner
   radius, shadow and gold ring. The service pages previously used a separate
   `.install-video` rule with the rounding but no frame, which read as flatter
   and shorter than the homepage player right next to it in the same visit. */
.video-frame {
  width: min(100%, 420px);
  margin: 0 auto;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--ink);
  box-shadow: 0 20px 40px -25px rgba(12, 22, 30, 0.7), 0 0 0 8px rgba(217, 138, 52, 0.08);
}
.video-frame-media { display: block; width: 100%; height: auto; aspect-ratio: 480 / 864; object-fit: cover; }

/* ---------- Value-prop chips ---------- */
.chip-row { display: flex; gap: var(--space-3); flex-wrap: wrap; }
.chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 0.55rem 1rem;
  font-size: 0.85rem;
  font-weight: 500;
  color: var(--text);
  text-decoration: none;
}
a.chip:hover { border-color: var(--steel); color: var(--ink); }

@media (max-width: 700px) {
  .home-showcase { padding: var(--space-7) 0; }
  .home-showcase-lede { font-size: 1rem; margin-bottom: var(--space-6); }
  .home-showcase-media { width: calc(100% - 0.5rem); }
  .home-showcase-play { width: 4.5rem; height: 4.5rem; }
}

/* ---------- Service cards ---------- */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--space-4);
}
.service-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  transition: transform 150ms ease, box-shadow 150ms ease, border-color 150ms ease;
}
.service-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 8px 20px -12px rgba(22, 35, 46, 0.35);
  border-color: var(--steel);
}
.service-card h3 { font-size: 1.15rem; margin-bottom: var(--space-2); }
.service-card p { color: var(--text-muted); font-size: 0.92rem; margin-bottom: var(--space-3); }
.service-card a { font-weight: 600; color: var(--steel); text-decoration: none; font-size: 0.88rem; }
.service-card a:hover { color: var(--ink); text-decoration: underline; }

/* ---------- Small reusable pill label above a section heading ---------- */
.eyebrow-pill {
  display: inline-block;
  margin-bottom: var(--space-3);
  padding: 0.4rem 0.9rem;
  border-radius: 999px;
  background: rgba(217, 138, 52, 0.12);
  color: var(--kiln-deep);
  font-size: 0.82rem;
  font-weight: 700;
  letter-spacing: 0.02em;
}

/* ---------- Section head: badge + title (+ optional lede), centered ---------- */
/* The one consistent pattern for every top-of-section intro sitewide — see
   index.php and the equivalent sections in templates/*.php. Content below
   a section head (lists, cards, steps) keeps its own natural left-aligned
   reading flow; only the intro block itself centers. */
.section-head { max-width: 640px; margin: 0 auto var(--space-6); text-align: center; }
.section-head h2 { margin-bottom: var(--space-3); }
.section-head .section-lede { margin-left: auto; margin-right: auto; margin-bottom: 0; }

/* ---------- Testimonials carousel ---------- */
.testimonial-shell { position: relative; max-width: 640px; margin: 0 auto; }
.testimonial-card {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-7) var(--space-6);
  box-shadow: 0 20px 40px -28px rgba(22, 35, 46, 0.35);
  overflow: hidden;
}
.testimonial-slide { display: none; text-align: left; padding-left: var(--space-2); }
.testimonial-slide.is-active { display: block; }
.testimonial-stars { display: flex; gap: 0.3rem; margin-bottom: var(--space-4); }
.testimonial-stars svg { width: 1.4rem; height: 1.4rem; }
.star-filled { fill: var(--kiln); stroke: var(--kiln); }
.star-empty { fill: none; stroke: var(--border); stroke-width: 1.5; }
.testimonial-quote { font-style: italic; font-size: 1.15rem; line-height: 1.5; color: var(--text); max-width: none; margin: 0 0 var(--space-5); }
.testimonial-name { font-weight: 700; font-size: 1.05rem; margin: 0 0 0.25rem; }
.testimonial-role { color: var(--kiln-deep); font-weight: 600; font-size: 0.92rem; margin: 0; }

.testimonial-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  z-index: 2;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  box-shadow: 0 10px 22px -12px rgba(22, 35, 46, 0.3);
}
.testimonial-nav:hover { border-color: var(--kiln-deep); color: var(--kiln-deep); }
.testimonial-nav svg { width: 1.2rem; height: 1.2rem; }
.testimonial-nav.prev { left: -1.375rem; }
.testimonial-nav.next { right: -1.375rem; }

.testimonial-controls { display: flex; flex-direction: column; align-items: center; gap: var(--space-4); margin-top: var(--space-6); padding: var(--space-5) var(--space-2) 0; border-top: 1px solid var(--border); }
.testimonial-indicators { display: flex; align-items: center; gap: 0.4rem; }
.testimonial-indicator {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  border: none;
  background: var(--border);
  cursor: pointer;
  padding: 0;
  transition: width 200ms ease, background-color 200ms ease;
}
.testimonial-indicator.is-active { width: 26px; background: var(--kiln); }
.testimonial-play {
  padding: 0.6rem 1.4rem;
  border-radius: 999px;
  border: none;
  background: rgba(217, 138, 52, 0.14);
  color: var(--kiln-deep);
  font-weight: 700;
  font-size: 0.9rem;
  cursor: pointer;
  transition: background-color 180ms ease;
}
.testimonial-play:hover { background: rgba(217, 138, 52, 0.22); }

/* ---------- Installation video placeholder (2 service pages only) ---------- */
.video-placeholder {
  max-width: 720px;
  margin: 0 auto;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  background: linear-gradient(160deg, var(--ink-deep) 0%, var(--ink) 55%, var(--steel) 150%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-4);
  color: rgba(255, 255, 255, 0.75);
}
.video-placeholder-play {
  width: 4.5rem;
  height: 4.5rem;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.3);
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
}
.video-placeholder-play svg { width: 1.8rem; height: 1.8rem; }
/* (The service-page installation video now uses the shared .video-frame /
   .video-frame-media pair defined above, so it matches the homepage player
   exactly. The old standalone .install-video rule was removed rather than
   left behind as dead CSS.) */

/* ---------- Recent projects carousel ---------- */
/* One slide visible at a time (matching the pattern used by the homepage
   hero and testimonials carousels), dot indicators below, auto-advancing
   and touch-swipeable on mobile — see the projectGallery block in
   assets/js/main.js. */
.project-carousel { max-width: 640px; margin: 0 auto; }
.project-carousel-stage {
  position: relative;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--surface-2);
  touch-action: pan-y;
}
.project-carousel-slide { position: absolute; inset: 0; display: none; }
.project-carousel-slide.is-active { display: block; }
.project-carousel-slide img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* display:none stays the base for this modifier too (not just the shared
   .project-carousel-slide rule) — a flex/block display declared here
   unconditionally would outrank display:none at equal specificity and
   defeat both the [hidden] attribute and .is-active regardless of state. */
.project-carousel-slide--empty {
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.6rem;
  border: 1.5px dashed var(--border);
  color: var(--text-muted);
  font-size: 0.85rem;
  box-sizing: border-box;
}
.project-carousel-slide--empty.is-active { display: flex; }
.project-carousel-slide--empty svg { width: 2rem; height: 2rem; opacity: 0.6; }
.project-carousel-indicators { display: flex; align-items: center; justify-content: center; gap: 0.4rem; margin-top: var(--space-4); }
.project-carousel-indicator {
  width: 8px;
  height: 8px;
  border-radius: 999px;
  border: none;
  background: var(--border);
  cursor: pointer;
  padding: 0;
  transition: width 200ms ease, background-color 200ms ease;
}
.project-carousel-indicator.is-active { width: 26px; background: var(--kiln); }

/* ---------- Technical specifications card ---------- */
.spec-card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-2) var(--space-5);
}
.spec-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) 0;
  border-bottom: 1px solid var(--border);
}
.spec-row:last-child { border-bottom: none; }
.spec-label { color: var(--text-muted); font-size: 0.92rem; }
.spec-value { font-weight: 700; text-align: right; }
.spec-value--pending { font-weight: 500; font-style: italic; color: var(--text-muted); }
.spec-check {
  width: 1.5rem;
  height: 1.5rem;
  border-radius: 50%;
  background: rgba(37, 211, 102, 0.15);
  color: var(--whatsapp);
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
}
.spec-check svg { width: 0.9rem; height: 0.9rem; }

/* ---------- Service page mid CTA (parallax) ---------- */
/* background-attachment:fixed gives the background a genuine parallax
   feel — it stays put while the page scrolls past it. Two stacked
   background-image layers: a dark gradient (painted on top, for text
   legibility) over --service-cta-photo (the service's real hero photo,
   set inline per-page by includes/service-cta.php). The var() defaults to
   "none" so a service without a photo yet just shows the gradient alone. */
.service-cta {
  position: relative;
  padding: var(--space-8) 0;
  text-align: center;
  overflow: hidden;
  background-image: linear-gradient(160deg, rgba(12, 22, 30, 0.88) 0%, rgba(22, 35, 46, 0.82) 55%, rgba(71, 96, 110, 0.7) 150%), var(--service-cta-photo, none);
  background-size: cover, cover;
  background-position: center, center;
  background-repeat: no-repeat, no-repeat;
  background-attachment: fixed, fixed;
}
.service-cta::before {
  content: "";
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.05) 0, rgba(255, 255, 255, 0.05) 1.5px, transparent 1.5px, transparent 18px),
    repeating-linear-gradient(-45deg, rgba(255, 255, 255, 0.05) 0, rgba(255, 255, 255, 0.05) 1.5px, transparent 1.5px, transparent 18px);
  pointer-events: none;
}
.service-cta-inner { position: relative; z-index: 1; max-width: 520px; margin: 0 auto; }
.service-cta h2 { color: #fff; font-size: var(--h1); margin: 0 0 var(--space-3); }
.service-cta-inner > p { color: rgba(255, 255, 255, 0.8); margin: 0 0 var(--space-6); }
.service-cta-btns { display: flex; flex-direction: column; gap: var(--space-3); }
.service-cta-btn { width: 100%; justify-content: center; }
.service-cta-btn svg { width: 1.1rem; height: 1.1rem; }
.service-cta .btn-secondary { color: #fff; border-color: rgba(255, 255, 255, 0.35); background: rgba(255, 255, 255, 0.06); }
.service-cta .btn-secondary:hover { background: rgba(255, 255, 255, 0.14); }
.service-cta-btn-consult {
  width: 100%;
  justify-content: center;
  background: linear-gradient(135deg, var(--kiln) 0%, var(--kiln-deep) 100%);
  color: var(--ink);
  font-weight: 700;
}
.service-cta-btn-consult:hover { filter: brightness(1.06); }
.service-cta-btn-consult svg { width: 1.1rem; height: 1.1rem; }
@media (min-width: 600px) {
  .service-cta-btns { flex-direction: row; justify-content: center; }
  .service-cta-btn, .service-cta-btn-consult { width: auto; }
}

/* ---------- Highlight callout panel ---------- */
.highlight-panel {
  margin-top: var(--space-6);
  padding: var(--space-4) var(--space-5);
  border-radius: var(--radius-md);
  background: rgba(217, 138, 52, 0.1);
  border: 1px solid rgba(217, 138, 52, 0.3);
  text-align: center;
}
.highlight-panel p { margin: 0; color: var(--text); font-size: 0.95rem; }
.highlight-panel a { color: var(--kiln-deep); font-weight: 700; text-decoration: underline; }

/* ---------- Service areas section ---------- */
.service-areas-chips .chip-row { justify-content: center; }
.explore-links .chip-row { flex-direction: column; align-items: stretch; }

/* Explore Further chips (service-location pages) read as plain tags by
   default — scoped here (not a change to the shared .chip rules used
   elsewhere, e.g. service-areas or About's coverage list) to make these
   specifically look like clickable destinations: a warm gradient fill and
   an arrow that shifts on hover, matching the site's navy/amber palette. */
.explore-links .chip {
  width: 100%;
  box-sizing: border-box;
  background: linear-gradient(135deg, rgba(217, 138, 52, 0.12) 0%, rgba(22, 35, 46, 0.06) 150%);
  border-color: rgba(217, 138, 52, 0.35);
  font-weight: 600;
  padding-right: 2.1rem;
  position: relative;
  transition: transform 160ms ease, box-shadow 160ms ease, border-color 160ms ease, background-color 160ms ease;
}
.explore-links .chip::after {
  content: "\2192";
  position: absolute;
  right: 0.9rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--kiln-deep);
  font-weight: 700;
  transition: transform 160ms ease;
}
.explore-links .chip:hover {
  background: linear-gradient(135deg, rgba(217, 138, 52, 0.2) 0%, rgba(22, 35, 46, 0.1) 150%);
  border-color: var(--kiln-deep);
  color: var(--ink);
  transform: translateY(-2px);
  box-shadow: 0 12px 22px -14px rgba(22, 35, 46, 0.4);
}
.explore-links .chip:hover::after { transform: translateY(-50%) translateX(3px); }
.service-areas-more { text-align: center; margin-top: var(--space-5); }

/* ---------- Services showcase: category tabs ---------- */
.service-tabs {
  display: flex;
  gap: 0.5rem;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scrollbar-width: none;
  padding-bottom: 2px;
  margin-top: var(--space-5);
}
.service-tabs::-webkit-scrollbar { display: none; }
.service-tab {
  flex: 0 0 auto;
  padding: 0.55rem 1.1rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  font-size: 0.86rem;
  font-weight: 600;
  cursor: pointer;
  white-space: nowrap;
  transition: background-color 180ms ease, border-color 180ms ease, color 180ms ease, box-shadow 180ms ease;
}
.service-tab:hover { border-color: var(--steel); }
.service-tab.is-active {
  background: linear-gradient(135deg, var(--ink) 0%, var(--kiln-deep) 160%);
  border-color: transparent;
  color: #fff;
  box-shadow: 0 8px 18px -10px rgba(22, 35, 46, 0.5);
}

/* ---------- Services showcase: horizontal scroller ---------- */
/* Lives inside the same .wrap as the rest of the page (see
   includes/service-card.php / index.php) so the first card's left edge
   lines up with every other section's text — not a viewport-edge bleed.
   The next card still peeks in at the row's right edge once the cards'
   total width exceeds the wrap, which is the "there's more" cue.
   overscroll-behavior-x keeps a horizontal swipe that reaches either end
   of the row from chaining into a page-level horizontal scroll. */
.service-scroller-wrap { position: relative; margin-top: var(--space-6); }
.service-scroller {
  display: flex;
  gap: var(--space-4);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  padding: 0.25rem 0 var(--space-3);
  /* Trims a little off the leading gutter (and widens by the same amount,
     so only the left edge moves) — the next card's peek is more visible
     without pulling the whole row far from the heading above it. */
  margin-left: -0.75rem;
  width: calc(100% + 0.75rem);
}
.service-scroller::-webkit-scrollbar { display: none; }
.service-card-item {
  flex: 0 0 auto;
  width: 78vw;
  max-width: 320px;
  scroll-snap-align: start;
}
.service-card-item[hidden] { display: none; }
.scroller-nav {
  display: none;
  position: absolute;
  top: 40%;
  transform: translateY(-50%);
  z-index: 5;
  width: 2.75rem;
  height: 2.75rem;
  border-radius: 50%;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  box-shadow: 0 10px 24px -10px rgba(22, 35, 46, 0.35);
}
.scroller-nav svg { width: 1.2rem; height: 1.2rem; }
.scroller-nav:hover { border-color: var(--steel); background: var(--surface-2); }
.scroller-nav.prev { left: var(--space-4); }
.scroller-nav.next { right: var(--space-4); }
@media (min-width: 860px) {
  .scroller-nav { display: flex; }
  .service-card-item { width: 340px; }
}
/* Author display:flex above sits at equal specificity to (and, being an
   author rule, outranks) the UA [hidden]{display:none} default — without
   this, the prev/next buttons would stay visible even when JS hides them
   for a single-card category (see the same fix already applied to
   .home-hero-play for the identical reason). */
.scroller-nav[hidden] { display: none; }

/* A category with exactly one matching service (see updateSingleCardState
   in main.js): the lone card expands to fill the row instead of sitting
   at its normal fixed "peek" width with dead space beside it. Resets the
   scroller's own peek-margin trick too (see .service-scroller-wrap above),
   since there's no next card left to tease. */
.service-scroller.is-single { margin-left: 0; width: 100%; }
.service-scroller.is-single .service-card-item {
  flex: 1 1 auto;
  width: 100%;
  max-width: none;
}

/* ---------- Services showcase: card ---------- */
.service-showcase-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  text-decoration: none;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  transition: transform 200ms ease, box-shadow 200ms ease, border-color 200ms ease;
}
.service-showcase-card:hover {
  transform: translateY(-5px);
  box-shadow: 0 18px 34px -16px rgba(22, 35, 46, 0.4);
  border-color: var(--kiln-deep);
}
.service-card-cover {
  position: relative;
  height: 170px;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.service-card-cover-texture {
  position: absolute;
  inset: 0;
  background:
    repeating-linear-gradient(45deg, rgba(255, 255, 255, 0.07) 0, rgba(255, 255, 255, 0.07) 1.5px, transparent 1.5px, transparent 16px),
    repeating-linear-gradient(-45deg, rgba(255, 255, 255, 0.07) 0, rgba(255, 255, 255, 0.07) 1.5px, transparent 1.5px, transparent 16px),
    radial-gradient(120% 100% at 15% 0%, rgba(255, 255, 255, 0.16), transparent 60%);
}
.service-card-photo { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; transition: transform 200ms ease; }
.service-showcase-card:hover .service-card-photo { transform: scale(1.05); }
.service-card-cover-fade {
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(12, 22, 30, 0.05) 0%, rgba(12, 22, 30, 0.4) 100%);
  pointer-events: none;
}
.service-card-icon {
  position: relative;
  width: 3.5rem;
  height: 3.5rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: 0 10px 22px -10px rgba(0, 0, 0, 0.45);
}
.service-card-icon-svg { width: 1.9rem; height: 1.9rem; color: #fff; }
.service-showcase-card:hover .service-card-icon { transform: scale(1.08); transition: transform 200ms ease; }

/* One distinct 2-tone gradient per service, all drawn from the same brand
   palette (ink / ink-deep / steel / kiln / kiln-deep) — never the flat
   single-accent color the reference design used. */
.sc-grad-invisible-grills { background: linear-gradient(135deg, var(--ink-deep) 0%, var(--steel) 130%); }
.sc-grad-balcony-safety-nets { background: linear-gradient(150deg, var(--ink) 0%, var(--kiln-deep) 150%); }
.sc-grad-children-pet-safety-nets { background: linear-gradient(120deg, var(--steel) 0%, var(--ink) 130%); }
.sc-grad-pigeon-bird-netting { background: linear-gradient(160deg, var(--ink-deep) 0%, var(--ink) 55%, var(--steel) 150%); }
.sc-grad-duct-area-nets { background: linear-gradient(140deg, var(--ink) 0%, var(--steel) 70%, var(--ink-deep) 150%); }
.sc-grad-sports-nets { background: linear-gradient(130deg, var(--kiln-deep) 0%, var(--ink-deep) 140%); }
.sc-grad-ceiling-cloth-hangers { background: linear-gradient(145deg, var(--steel) 0%, var(--kiln-deep) 150%); }

.service-card-body { display: flex; flex-direction: column; flex: 1; padding: var(--space-5); }
.service-card-body h3 { font-size: 1.1rem; margin-bottom: var(--space-2); }
.service-card-body > p { color: var(--text-muted); font-size: 0.9rem; margin-bottom: var(--space-3); }
.service-card-features { list-style: none; margin: 0 0 var(--space-4); padding: 0; display: grid; gap: 0.4rem; }
.service-card-features li {
  display: flex;
  align-items: flex-start;
  gap: 0.5rem;
  font-size: 0.82rem;
  color: var(--text-muted);
}
.service-card-features li::before {
  content: "";
  flex: 0 0 auto;
  width: 6px;
  height: 6px;
  margin-top: 0.4em;
  border-radius: 50%;
  background: var(--kiln);
}
.service-card-cta {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--kiln-deep);
}
.service-card-cta svg { width: 1rem; height: 1rem; transition: transform 200ms ease; }
.service-showcase-card:hover .service-card-cta svg { transform: translateX(3px); }

/* ---------- Why-choose list / generic checklist ---------- */
.why-list, .checklist { list-style: none; padding: 0; margin: 0; display: grid; gap: var(--space-3); max-width: 60ch; }
.why-list li, .checklist li { padding-left: 1.75rem; position: relative; }
.why-list li::before, .checklist li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 0.35em;
  width: 0.9rem;
  height: 0.9rem;
  border: 2px solid var(--kiln);
  border-radius: 2px;
}

/* ---------- Why Choose Us: card grid ---------- */
.why-cards {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--space-4);
  margin-top: var(--space-6);
}
.why-card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  transition: transform 180ms ease, box-shadow 180ms ease, border-color 180ms ease;
}
.why-card:hover {
  transform: translateY(-4px);
  box-shadow: 0 16px 30px -18px rgba(22, 35, 46, 0.35);
  border-color: var(--kiln-deep);
}
.why-card-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 3rem;
  height: 3rem;
  border-radius: var(--radius-md);
  margin-bottom: var(--space-4);
  color: #fff;
}
.why-card-icon svg { width: 1.5rem; height: 1.5rem; }
.why-card-icon-ink { background: linear-gradient(135deg, var(--ink) 0%, var(--ink-deep) 130%); }
.why-card-icon-kiln { background: linear-gradient(135deg, var(--kiln) 0%, var(--kiln-deep) 130%); }
.why-card h3 { font-size: 1.05rem; margin-bottom: var(--space-2); }
.why-card p { color: var(--text-muted); font-size: 0.9rem; margin: 0; }

/* ---------- Breadcrumbs ---------- */
.breadcrumbs { padding: var(--space-4) 0 0; }
.breadcrumbs ol {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  padding: 0;
  margin: 0;
  font-size: 0.82rem;
}
.breadcrumbs li { display: flex; align-items: center; gap: 0.4rem; }
.breadcrumbs a { color: var(--steel); text-decoration: none; }
.breadcrumbs a:hover { text-decoration: underline; }
.breadcrumbs span[aria-current="page"] { color: var(--text-muted); }
.breadcrumbs .sep { color: var(--text-muted); }

/* ---------- Info panel (safety / maintenance notes) ---------- */
.info-panel {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-5);
  margin-bottom: var(--space-4);
  max-width: 70ch;
}
.info-panel:last-child { margin-bottom: 0; }
/* The #safety section's heading is centered (.section-head); without this
   its info-panel(s) would hug the left edge of the much wider .wrap below
   it instead of sitting centered under that heading like everywhere else
   this pattern is used. Scoped to #safety only — .contact-grid's info-panel
   is a sidebar column in a 2-up grid and must stay left-aligned there. */
#safety .info-panel { margin-left: auto; margin-right: auto; }
.info-panel h3 { font-size: 1.05rem; margin-bottom: var(--space-2); }
.info-panel p { margin: 0; color: var(--text-muted); font-size: 0.94rem; }

/* Anchor targets should clear the sticky header. */
.section[id], .hero[id] { scroll-margin-top: 5rem; }

/* ---------- Hyderabad hub: area-by-area coverage blocks ---------- */
.area-block { padding: var(--space-5) 0; border-top: 1px solid var(--border); scroll-margin-top: 5rem; }
.area-block:first-of-type { border-top: none; padding-top: 0; }
.area-block h3 { margin-bottom: var(--space-2); }
.area-block > p { color: var(--text-muted); font-size: 0.94rem; margin-bottom: var(--space-3); max-width: 70ch; }

/* ---------- Process steps ---------- */
/* Each step draws its own connector segment from the bottom of its own
   circle down to the top of the *next* circle (:not(:last-child), so
   nothing draws past the final step). A single container-spanning line
   can't do this correctly since steps have different text heights — the
   container's total height isn't circle-center to circle-center, it's
   however tall the last step's text happens to make it. Per-item, sized
   with 100% of that item's own (auto) height, is exact regardless. */
/* Centered under .section-head above it, same width as that heading —
   without this, the list stretches the full (much wider) .wrap on large
   screens while the heading above stays narrow-and-centered, reading as
   visually off-balance. */
.process-steps { list-style: none; padding: 0; margin: 0 auto; max-width: 640px; display: grid; gap: var(--space-5); text-align: left; }
.process-steps li { position: relative; display: flex; gap: var(--space-4); align-items: flex-start; }
.process-steps li:not(:last-child)::before {
  content: "";
  position: absolute;
  z-index: 0;
  left: 1.125rem;
  top: 2.25rem;
  width: 2px;
  height: calc(100% - 2.25rem + var(--space-5));
  background: linear-gradient(to bottom, var(--kiln), var(--steel));
}
.step-num {
  position: relative;
  z-index: 1;
  flex: 0 0 auto;
  width: 2.25rem;
  height: 2.25rem;
  border-radius: 50%;
  background: var(--ink);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 700;
}
.process-steps h3 { font-size: 1.05rem; margin: 0 0 0.25rem; }
.process-steps p { margin: 0; color: var(--text-muted); font-size: 0.92rem; }

/* ---------- CTA banner ---------- */
.cta-section { background: var(--ink); color: #fff; padding: var(--space-7) 0; }
.cta-inner { text-align: center; display: flex; flex-direction: column; align-items: center; gap: var(--space-5); }
.cta-inner h2 { color: #fff; font-size: var(--h2); max-width: 24ch; margin: 0; }
.cta-inner .btn-row { justify-content: center; }
.cta-section .btn-secondary { color: #fff; border-color: #fff; }
.cta-section .btn-secondary:hover { background: rgba(255, 255, 255, 0.1); }

/* ---------- FAQ ---------- */
.faq-list { max-width: 70ch; margin: 0 auto; display: grid; gap: var(--space-3); }
.faq-item {
  background: linear-gradient(160deg, var(--ink) 0%, var(--ink-deep) 130%);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-md);
  overflow: hidden;
}
.faq-item h3 { margin: 0; }
.faq-q {
  width: 100%;
  text-align: left;
  background: none;
  border: none;
  padding: var(--space-4) var(--space-5);
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4);
  font-family: var(--font-body);
  font-size: 1rem;
  font-weight: 600;
  color: #fff;
  cursor: pointer;
}
.faq-chevron { width: 1.1rem; height: 1.1rem; color: rgba(255, 255, 255, 0.65); transition: transform 220ms ease, color 220ms ease; flex-shrink: 0; }
.faq-item[data-open="true"] .faq-chevron { transform: rotate(180deg); color: var(--kiln); }
.faq-a-wrap { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 220ms ease; }
.faq-item[data-open="true"] .faq-a-wrap { grid-template-rows: 1fr; }
.faq-a-inner { overflow: hidden; }
.faq-a-inner p { padding: 0 var(--space-5) var(--space-4); color: rgba(255, 255, 255, 0.7); font-size: 0.92rem; margin: 0; }

/* ---------- Footer ---------- */
.site-footer { background: var(--ink); color: #c9d2d8; padding: var(--space-7) 0 var(--space-5); }
.footer-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: var(--space-6); }
.footer-grid h2 {
  color: #fbfaf7;
  font-family: var(--font-body);
  font-size: 0.75rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  margin: 0 0 var(--space-3);
  font-weight: 600;
}
.footer-name { font-family: var(--font-display); font-weight: 700; color: #fbfaf7; font-size: 1.05rem; margin: 0; }
.footer-brand { display: flex; align-items: center; gap: 0.6rem; margin-bottom: var(--space-2); }
.footer-logo { height: 40px; width: auto; display: block; }
.footer-brand-accent { color: var(--kiln); }
.footer-minimal-inner .footer-brand { justify-content: center; }
.footer-grid p { color: #c9d2d8; font-size: 0.9rem; max-width: 30ch; }
/* .footer-grid p (class+tag) otherwise outranks the plain .footer-name
   class on specificity alone regardless of source order, silently
   overriding its intended bright white back to the muted body-text gray
   — this pins it back with a same-tier-beating selector instead. */
.footer-grid p.footer-name, .footer-minimal-inner p.footer-name { color: #fbfaf7; }
.footer-grid a { display: block; color: #c9d2d8; text-decoration: none; font-size: 0.9rem; margin-bottom: var(--space-2); }
.footer-grid a:hover { color: var(--kiln); }
/* An icon (phone/email/pin) before each contact line — .footer-grid
   a.footer-contact-item (class+tag+class) beats the plain .footer-grid a
   above on specificity, same reasoning as the .footer-name fix above it:
   without the extra weight, that rule's display:block would silently win
   regardless of source order and break the icon+text flex row. */
.footer-grid a.footer-contact-item,
.footer-grid div.footer-contact-item {
  display: flex;
  align-items: center;
  gap: 0.55rem;
}
.footer-contact-item svg { width: 1.05rem; height: 1.05rem; flex: 0 0 auto; color: var(--kiln); }
/* WhatsApp button, styled like the sitewide .btn-whatsapp (same green,
   same pill shape) rather than a plain footer text link — same
   specificity reasoning as .footer-contact-item above. */
.footer-grid a.footer-whatsapp-btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  margin-top: var(--space-2);
  padding: 0.6rem 1.25rem;
  border-radius: 999px;
  background: var(--whatsapp);
  color: #fff;
  font-weight: 700;
}
.footer-grid a.footer-whatsapp-btn:hover { background: #1fb959; color: #fff; }
.footer-whatsapp-btn svg { width: 1.1rem; height: 1.1rem; }
.footer-legal {
  border-top: 1px solid rgba(255, 255, 255, 0.12);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  font-size: 0.78rem;
  display: flex;
  gap: var(--space-5);
  flex-wrap: wrap;
  color: #8fa3af;
}
.footer-legal a { color: #8fa3af; text-decoration: none; }
.footer-legal a:hover { color: var(--kiln); }
/* On a narrow screen the three items wrap unevenly — typically copyright and
   "Privacy Policy" on one line with "Terms & Conditions" stranded alone
   underneath, which reads as a mistake. Forcing the copyright to a full-width
   row of its own puts it centred on the first line and lets the two links sit
   together on the second, side by side, wrapping only if the device is
   genuinely too narrow for both. No markup change: the copyright is the only
   <span> among the children. */
@media (max-width: 640px) {
  .footer-legal {
    justify-content: center;
    text-align: center;
    gap: var(--space-2) var(--space-4);
  }
  .footer-legal > span { flex: 0 0 100%; }
}

/* ---------- Minimal chrome (Google Ads landing pages) ---------- */
.site-header--minimal .nav-bar--minimal { justify-content: space-between; }
.site-footer--minimal { padding: var(--space-6) 0; }
.footer-minimal-inner { text-align: center; }
.footer-minimal-inner .footer-name { color: #fbfaf7; }
.footer-minimal-inner > p { color: #c9d2d8; max-width: none; }
.footer-legal--minimal {
  justify-content: center;
  border-top: none;
  margin-top: var(--space-3);
  padding-top: 0;
}

/* ---------- Form fields ---------- */
.field { display: flex; flex-direction: column; gap: var(--space-2); margin-bottom: var(--space-4); }
.field label { font-size: 0.85rem; font-weight: 600; }
.field-optional { font-weight: 400; color: var(--text-muted); }
.field input,
.field select,
.field textarea {
  font-family: var(--font-body);
  font-size: 0.95rem;
  padding: 0.7rem 0.85rem;
  border-radius: var(--radius-sm);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text);
  min-height: 44px;
}
.field select { appearance: auto; }
.field textarea { min-height: auto; resize: vertical; }
.field input[aria-invalid="true"],
.field select[aria-invalid="true"],
.field textarea[aria-invalid="true"] {
  border-color: var(--error);
}
.field-error {
  display: block;
  color: var(--error);
  font-size: 0.8rem;
  margin-top: var(--space-1);
}

/* Honeypot: off-screen rather than display:none, which some bots skip specifically. */
.hp-field { position: absolute; left: -9999px; top: -9999px; }

.lead-form { max-width: 420px; }

.contact-grid {
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: var(--space-7);
  align-items: start;
}
.contact-grid .info-panel { margin-top: 2.7rem; }
@media (max-width: 780px) {
  .contact-grid { grid-template-columns: 1fr; }
  .contact-grid .info-panel { margin-top: 0; }
}
.form-error-banner {
  background: var(--surface-2);
  border: 1px solid var(--error);
  color: var(--error);
  border-radius: var(--radius-sm);
  padding: var(--space-3) var(--space-4);
  font-size: 0.9rem;
  max-width: 420px;
}

/* ---------- WhatsApp popup CTA ---------- */
/* Bottom-anchored bar, rounded top corners only (flush against the
   viewport edges it touches on mobile; still flush against the bottom
   edge on desktop so the same "rounded top, square bottom" silhouette
   holds at every size). Hidden via the `hidden` attribute until
   assets/js/main.js's delayed-show timer removes it and triggers the
   slide-up transition — see the whatsappPopup block there for the
   show-once-per-cooldown-window logic that keeps this from nagging on
   every page visit. */
.whatsapp-popup {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 60;
  background: var(--surface);
  border: 1px solid var(--border);
  border-bottom: none;
  border-radius: 18px 18px 0 0;
  box-shadow: 0 -14px 34px -14px rgba(22, 35, 46, 0.35);
  transform: translateY(110%);
  transition: transform 320ms cubic-bezier(0.22, 1, 0.36, 1);
}
.whatsapp-popup.is-visible { transform: translateY(0); }
.whatsapp-popup-close {
  position: absolute;
  top: 0.55rem;
  right: 0.55rem;
  width: 1.7rem;
  height: 1.7rem;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-muted);
  cursor: pointer;
  padding: 0;
}
.whatsapp-popup-close:hover { background: var(--border); color: var(--text); }
.whatsapp-popup-close svg { width: 0.9rem; height: 0.9rem; }
.whatsapp-popup-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-4) var(--space-5);
}
.whatsapp-popup-text { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.whatsapp-popup-title { font-family: var(--font-display); font-weight: 700; font-size: 0.95rem; color: var(--ink); }
.whatsapp-popup-sub { font-size: 0.82rem; color: var(--text-muted); }
.whatsapp-popup-cta { flex: 0 0 auto; white-space: nowrap; }
.whatsapp-popup-cta svg { width: 1.1rem; height: 1.1rem; }
@media (min-width: 640px) {
  .whatsapp-popup { left: auto; width: 380px; right: var(--space-6); }
}
/* Same end state either way (visible, at rest) — this only removes the
   slide-in motion itself for prefers-reduced-motion users. */
@media (prefers-reduced-motion: reduce) {
  .whatsapp-popup { transition: none; }
}

/* ---------- Gallery page ---------- */
.gallery-video-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
  gap: var(--space-5);
  max-width: 920px;
  margin: 0 auto;
}
.gallery-video-card { display: flex; flex-direction: column; gap: var(--space-3); }
/* Same frame treatment as .video-frame (homepage + service pages)
   (rounded corners, shadow, gold ring accent) — just narrower, since three
   sit side by side here instead of one. */
.gallery-video-frame {
  width: min(100%, 320px);
  margin: 0 auto;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--ink-deep);
  box-shadow: 0 20px 40px -25px rgba(12, 22, 30, 0.7), 0 0 0 8px rgba(217, 138, 52, 0.08);
}
.gallery-video { display: block; width: 100%; aspect-ratio: 480 / 864; object-fit: cover; }
.gallery-video-caption { text-align: center; font-weight: 600; font-size: 0.92rem; color: var(--text-muted); margin: 0; }

.gallery-service-group { padding: var(--space-6) 0; border-top: 1px solid var(--border); }
.gallery-service-group:first-of-type { padding-top: 0; border-top: none; }
.gallery-service-group-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}
.gallery-service-group-head h3 { margin: 0; }
.gallery-service-link {
  flex: 0 0 auto;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-weight: 700;
  font-size: 0.9rem;
  color: var(--kiln-deep);
  text-decoration: none;
  white-space: nowrap;
}
.gallery-service-link svg { width: 1rem; height: 1rem; transition: transform 200ms ease; }
.gallery-service-link:hover svg { transform: translateX(3px); }
.gallery-image-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-3);
}
.gallery-image-item {
  display: block;
  aspect-ratio: 4 / 3;
  border-radius: var(--radius-md);
  overflow: hidden;
}
.gallery-image-item img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 200ms ease; }
.gallery-image-item:hover img { transform: scale(1.05); }

/* The footer address wraps onto two or three lines, so its icon has to align
   to the first line rather than the block's vertical centre — with the shared
   `align-items: center` above, a long address pushes the pin down to the
   middle of the block and it stops reading as a label for the first line. */
.footer-grid a.footer-contact-item-block,
.footer-grid div.footer-contact-item-block {
  align-items: flex-start;
}
.footer-contact-item-block svg { margin-top: 0.2em; }

/* Minimal (landing-page) footer NAP line — phone and address on one centred
   row, wrapping to separate lines on narrow screens rather than letting the
   long address squeeze the phone number onto its own overflowing line. */
.footer-minimal-contact {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: 0.25rem 0.5rem;
}
.footer-minimal-sep { color: #6d7a83; }

/* ==========================================================================
   Invisible Grills Hyderabad ads landing page (/lp/invisible-grills-hyderabad/)
   Uses the existing tokens and component vocabulary throughout — the only
   new pieces here are the two grids the page needs that nothing else has:
   the four invisible-grill variant cards, and the compact "other services"
   row beneath them.
   ========================================================================== */

/* Lede under the hero's H1 pill. Only the ads page passes one, so the
   homepage hero is untouched. */
.home-hero-lede {
  max-width: 54ch;
  margin: var(--space-3) auto 0;
  text-align: center;
  color: #c9d2d8;
  font-size: 0.98rem;
  line-height: 1.55;
}

/* ---------- The four invisible-grill variants ---------- */
/* auto-fit rather than a fixed column count: four cards sit 4-up on a wide
   screen, 2-up on a tablet and 1-up on a phone without a breakpoint each. */
.ig-type-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-5);
}
.ig-type-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  overflow: hidden;
  transition: transform 200ms ease, box-shadow 200ms ease;
}
.ig-type-card:hover {
  transform: translateY(-3px);
  box-shadow: 0 18px 32px -22px rgba(22, 35, 46, 0.45);
}
/* Fixed 4:3 window so all four line up even though one source photo is
   portrait — the images are pre-cropped to 4:3, this just holds the box. */
.ig-type-media {
  aspect-ratio: 4 / 3;
  background: var(--ink);
  overflow: hidden;
}
.ig-type-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
.ig-type-body { display: flex; flex-direction: column; flex: 1; padding: var(--space-5); }
.ig-type-body h3 { font-size: 1.05rem; margin-bottom: var(--space-2); }
.ig-type-body > p { color: var(--text-muted); font-size: 0.9rem; margin-bottom: var(--space-3); }
/* Pushes the link to the bottom so all four cards' CTAs line up on a row
   regardless of how long the copy above them runs. Styled as a text link with
   a chevron rather than a filled button, matching the homepage service cards —
   these lead to a page, they are not the page's primary action. */
.ig-type-cta {
  margin-top: auto;
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.88rem;
  color: var(--kiln-deep);
  text-decoration: none;
  transition: gap 180ms ease, color 180ms ease;
}
.ig-type-cta:hover { gap: 0.6rem; color: var(--ink); }
.ig-type-cta svg { width: 0.9rem; height: 0.9rem; }

/* ---------- Feature grid beside the showcase video ---------- */
.ig-feature-grid {
  list-style: none;
  margin: var(--space-7) auto 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: var(--space-4);
  text-align: left;
  max-width: 62rem;
}
.ig-feature {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  padding: var(--space-4);
}
.ig-feature-icon {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.4rem;
  height: 2.4rem;
  border-radius: 50%;
  background: rgba(217, 138, 52, 0.12);
  color: var(--kiln-deep);
}
.ig-feature-icon svg { width: 1.25rem; height: 1.25rem; }
.ig-feature-text { display: flex; flex-direction: column; gap: 0.25rem; min-width: 0; }
.ig-feature-text strong { font-family: var(--font-display); font-size: 0.95rem; color: var(--ink); }
.ig-feature-text span { font-size: 0.85rem; line-height: 1.5; color: var(--text-muted); }

/* ---------- Quote form block ---------- */
.ig-form-wrap { max-width: 42rem; }
.ig-form-alt { margin-top: var(--space-4); font-size: 0.9rem; color: var(--text-muted); }
.ig-form-alt a { color: var(--steel); font-weight: 600; }

/* ---------- Explainer ---------- */
.ig-explainer { max-width: 70ch; }
.ig-explainer-lead { margin-bottom: var(--space-5); }
.ig-benefits { margin-top: var(--space-4); }

/* ---------- "We also provide" ---------- */
/* Six cards, so the column count is pinned rather than left to auto-fit:
   auto-fit produced five across on a wide screen and left a single orphan
   card alone on the second row. Three across divides 6 into two even rows,
   two across does the same on a tablet. */
.ig-other-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: var(--space-4);
}
@media (min-width: 640px) {
  .ig-other-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (min-width: 900px) {
  .ig-other-grid { grid-template-columns: repeat(3, 1fr); }
}
/* These are the homepage's own .service-showcase-card, reused so the two pages
   look identical. Its wrapper .service-card-item is sized for the homepage's
   horizontal scroller (fixed 78vw width, scroll snapping), none of which
   applies in a grid — so the wrapper is unpinned here and the card inside is
   left exactly as it is. */
.ig-other-grid .service-card-item {
  flex: initial;
  width: auto;
  max-width: none;
  scroll-snap-align: none;
}

/* ---------- Service area list ---------- */
.ig-area-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-3);
  justify-content: center;
}
.ig-area-list li {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 0.45rem 0.95rem;
  font-size: 0.85rem;
  color: var(--text-muted);
}
.ig-areas .section-head { text-align: center; }

/* ==========================================================================
   Floating Call / WhatsApp actions (every page)
   ========================================================================== */
.float-actions {
  position: fixed;
  right: var(--space-5);
  bottom: var(--space-5);
  z-index: 55;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  /* Lifted out of the way of the WhatsApp popup when that is on screen — see
     the sibling rule below. JS writes the popup's measured height here so the
     gap is exact rather than a guess that breaks when the copy wraps. */
  transform: translateY(calc(var(--float-lift, 0px) * -1));
  transition: transform 320ms cubic-bezier(0.22, 1, 0.36, 1);
}
/* The popup anchors to the same corner, so while it is visible the stack
   moves above it. Depends on .float-actions coming after .whatsapp-popup in
   the DOM (see includes/footer.php). */
.whatsapp-popup.is-visible ~ .float-actions {
  --float-lift: var(--float-popup-height, 104px);
}

.float-action {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 0;
  height: 3.25rem;
  padding: 0;
  border-radius: 999px;
  text-decoration: none;
  color: #fff;
  box-shadow: 0 10px 24px -8px rgba(12, 22, 30, 0.45);
  /* Entrance: each button rises into place, the second a beat after the
     first, so the pair reads as one deliberate movement rather than two
     things appearing at once. */
  animation: float-action-in 480ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
  transition: transform 200ms ease, box-shadow 200ms ease, background-color 200ms ease;
}
.float-action--whatsapp { background: var(--whatsapp); animation-delay: 260ms; }
.float-action--whatsapp:hover { background: #1fb959; }
.float-action--call { background: var(--kiln); animation-delay: 400ms; }
.float-action--call:hover { background: var(--kiln-deep); }
.float-action:hover { transform: translateY(-2px); box-shadow: 0 14px 28px -8px rgba(12, 22, 30, 0.55); }
.float-action:active { transform: translateY(0); }

.float-action-icon {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 3.25rem;
  height: 3.25rem;
  flex: 0 0 auto;
}
.float-action-icon svg { width: 1.5rem; height: 1.5rem; }

/* The label is collapsed to zero width and expands on hover/focus, so the
   resting state stays two clean circles and the meaning is still one
   interaction away on desktop. Width, not display, so it can animate. */
.float-action-label {
  max-width: 0;
  overflow: hidden;
  white-space: nowrap;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.9rem;
  opacity: 0;
  transition: max-width 260ms cubic-bezier(0.22, 1, 0.36, 1), opacity 200ms ease, padding 260ms ease;
}
.float-action:hover .float-action-label,
.float-action:focus-visible .float-action-label {
  max-width: 7rem;
  opacity: 1;
  padding-left: var(--space-4);
}

/* A slow outward ring on WhatsApp only — enough to catch the eye once in a
   while without the restlessness of two competing animations. */
.float-action--whatsapp::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: inherit;
  border: 2px solid var(--whatsapp);
  animation: float-action-ring 2.8s ease-out infinite;
  animation-delay: 1.4s;
  pointer-events: none;
}

@keyframes float-action-in {
  from { opacity: 0; transform: translateY(14px) scale(0.85); }
  to   { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes float-action-ring {
  0%        { opacity: 0.55; transform: scale(1); }
  70%, 100% { opacity: 0;    transform: scale(1.45); }
}

@media (max-width: 640px) {
  .float-actions { right: var(--space-4); bottom: var(--space-4); gap: var(--space-2); }
  .float-action, .float-action-icon { height: 3rem; width: 3rem; }
  /* No hover on touch, so the label would never open — and a permanently
     collapsed label is just dead weight in the accessibility tree's way. */
  .float-action-label { display: none; }
}

/* Motion here is decoration, not information: with reduced motion the buttons
   are simply present, in place, with no entrance, ring or lift. */
@media (prefers-reduced-motion: reduce) {
  .float-action { animation: none; transition: background-color 200ms ease; }
  .float-action:hover { transform: none; }
  .float-action--whatsapp::before { animation: none; opacity: 0; }
  .float-actions { transition: none; }
  .float-action-label { transition: none; }
}

/* Printed pages have no use for a tap-to-call button. */
@media print {
  .float-actions { display: none; }
}

/* ==========================================================================
   Before / after comparison slider
   ========================================================================== */
.ba {
  position: relative;
  width: min(100%, 52rem);
  margin: 0 auto;
  aspect-ratio: var(--ba-ratio, 4 / 3);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--ink);
  box-shadow: 0 20px 40px -25px rgba(12, 22, 30, 0.7), 0 0 0 8px rgba(217, 138, 52, 0.08);
  touch-action: pan-y;
  cursor: ew-resize;
  user-select: none;
}
.ba-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}
/* Clipping this wrapper — with the image inside held at the frame's full
   width — is what keeps the visible half from squashing as the divider moves.
   Clipping the <img> itself would resize it instead. */
.ba-clip {
  position: absolute;
  inset: 0;
  width: var(--ba-pos, 50%);
  overflow: hidden;
}
.ba-img--before { width: var(--ba-frame-w, 100%); }

.ba-divider {
  position: absolute;
  top: 0;
  bottom: 0;
  left: var(--ba-pos, 50%);
  width: 2px;
  margin-left: -1px;
  background: rgba(255, 255, 255, 0.9);
  pointer-events: none;
}
.ba-handle {
  position: absolute;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  width: 2.6rem;
  height: 2.6rem;
  border-radius: 50%;
  background: var(--kiln);
  color: var(--ink);
  display: flex;
  align-items: center;
  justify-content: center;
  box-shadow: 0 6px 18px -6px rgba(12, 22, 30, 0.7);
}
.ba-handle svg { width: 1.1rem; height: 1.1rem; }

.ba-tag {
  position: absolute;
  bottom: var(--space-4);
  padding: 0.3rem 0.75rem;
  border-radius: 999px;
  background: rgba(12, 22, 30, 0.72);
  color: #fff;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  pointer-events: none;
}
.ba-tag--before { left: var(--space-4); }
.ba-tag--after { right: var(--space-4); }

/* The real control: a range input stretched over the frame, visually hidden
   but not display:none, so it keeps keyboard focus and screen-reader
   semantics. Its focus ring is drawn on the handle instead. */
.ba-range {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  margin: 0;
  opacity: 0;
  cursor: ew-resize;
  -webkit-appearance: none;
  appearance: none;
  background: transparent;
}
.ba-range:focus-visible ~ .ba-divider .ba-handle {
  outline: 3px solid var(--focus-ring);
  outline-offset: 3px;
}

@media (max-width: 640px) {
  .ba-handle { width: 2.2rem; height: 2.2rem; }
  .ba-tag { bottom: var(--space-3); font-size: 0.66rem; }
  .ba-tag--before { left: var(--space-3); }
  .ba-tag--after { right: var(--space-3); }
}

/* ==========================================================================
   Mobile nav drawer (below 860px)
   ========================================================================== */
/* Below the breakpoint the bar's inline nav is replaced wholesale by the
   drawer, so the old .site-nav mobile panel rules no longer apply there. */
@media (max-width: 860px) {
  .site-nav { display: none; }
}
@media (min-width: 861px) {
  .drawer, .drawer-scrim, .nav-toggle { display: none; }
}

.drawer-scrim {
  position: fixed;
  inset: 0;
  overscroll-behavior: contain;
  touch-action: none;
  z-index: 58;
  background: rgba(12, 22, 30, 0.5);
  opacity: 0;
  transition: opacity 260ms ease;
}
.drawer-scrim.is-open { opacity: 1; }

.drawer {
  position: fixed;
  top: 0;
  right: 0;
  /* Height rather than bottom:0. A phone's address bar collapsing changes the
     viewport a bottom-anchored panel is measured against, so the panel
     resizes mid-gesture; dvh tracks that deliberately instead, and the vh
     line before it is the fallback where dvh is unsupported. */
  height: 100vh;
  height: 100dvh;
  z-index: 59;
  width: min(88vw, 24rem);
  background: var(--bg);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transform: translateX(100%);
  transition: transform 320ms cubic-bezier(0.22, 1, 0.36, 1);
  box-shadow: -18px 0 42px -20px rgba(12, 22, 30, 0.55);
}
.drawer.is-open { transform: translateX(0); }

/* A soft brand-coloured wash behind the panel's top corner, so the drawer
   reads as a designed surface rather than a plain white sheet. Purely
   decorative and behind everything else in the panel. */
.drawer-blob {
  position: absolute;
  top: -6rem;
  right: -6rem;
  width: 18rem;
  height: 18rem;
  border-radius: 50%;
  background: radial-gradient(circle at 30% 30%, rgba(217, 138, 52, 0.28), rgba(217, 138, 52, 0) 68%);
  pointer-events: none;
}

.drawer-inner {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow-y: auto;
  /* A scroll that reaches the end of this panel must stop there rather than
     handing the remaining momentum to the page behind it. */
  overscroll-behavior: contain;
  padding: calc(var(--space-7) + 0.5rem) var(--space-5) var(--space-5);
  -webkit-overflow-scrolling: touch;
}

.drawer-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
}
.drawer-kicker {
  font-family: var(--font-display);
  font-size: 0.72rem;
  font-weight: 800;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--kiln-deep);
  margin: 0;
}
.drawer-close {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  flex: 0 0 auto;
  margin: -0.5rem -0.4rem -0.5rem 0;
  border: 1px solid var(--border);
  border-radius: 50%;
  background: var(--surface);
  color: var(--ink);
  cursor: pointer;
  transition: transform 220ms cubic-bezier(0.22, 1, 0.36, 1), background-color 180ms ease, border-color 180ms ease;
}
.drawer-close:hover { background: var(--surface-2); border-color: var(--kiln); transform: rotate(90deg); }
.drawer-close:active { transform: rotate(90deg) scale(0.94); }
.drawer-close svg { width: 1.05rem; height: 1.05rem; }

.drawer-links { display: flex; flex-direction: column; }
/* Top-level destinations, sized to be read and tapped at arm's length. */
.drawer-links > a,
.drawer-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  width: 100%;
  padding: 0.85rem 0;
  border: 0;
  border-bottom: 1px solid var(--border);
  background: none;
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 700;
  color: var(--ink);
  text-decoration: none;
  text-align: left;
  cursor: pointer;
}
.drawer-links > a:hover,
.drawer-toggle:hover { color: var(--kiln-deep); }
.drawer-links > a[aria-current="page"] { color: var(--kiln-deep); }

.drawer-caret {
  display: flex;
  color: var(--steel);
  transition: transform 240ms cubic-bezier(0.22, 1, 0.36, 1);
}
.drawer-caret svg { width: 1rem; height: 1rem; }
/* Points right when closed, down when open. */
.drawer-toggle[aria-expanded="true"] .drawer-caret { transform: rotate(90deg); }

/* The open state is the CSS default so the panels are readable with the
   script blocked; the script closes them on load. Collapsed with a 0fr/1fr
   grid row rather than max-height, so the animation is to the panel's real
   height whatever its content. */
.drawer-panel {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 280ms cubic-bezier(0.22, 1, 0.36, 1);
}
.drawer-toggle[aria-expanded="false"] + .drawer-panel { grid-template-rows: 0fr; }
/* One wrapper, not the links directly: 0fr collapses the first grid row only,
   so with each link its own row every link after the first stayed visible. */
.drawer-panel-inner { overflow: hidden; min-height: 0; }
/* The divider belongs to the open panel — on a collapsed one it would stack
   against the next toggle's own top border and read as a double rule. */
.drawer-toggle[aria-expanded="true"] + .drawer-panel { border-bottom: 1px solid var(--border); }
.drawer-panel a {
  display: block;
  padding: 0.55rem 0 0.55rem var(--space-4);
  font-size: 0.95rem;
  color: var(--text-muted);
  text-decoration: none;
  border-left: 2px solid var(--border);
  margin-left: 0.15rem;
}
.drawer-panel a:first-child { padding-top: var(--space-3); }
.drawer-panel a:last-child { padding-bottom: var(--space-3); }
.drawer-panel a:hover,
.drawer-panel a[aria-current="page"] { color: var(--kiln-deep); border-left-color: var(--kiln); }

/* Pinned below the links, with margin-top:auto so it sits at the foot of a
   short menu and directly after the links on a long one. */
.drawer-foot {
  margin-top: auto;
  padding-top: var(--space-5);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.drawer-foot .btn { justify-content: center; width: 100%; }
.drawer-tel {
  margin: var(--space-1) 0 0;
  text-align: center;
  font-size: 0.85rem;
  color: var(--text-muted);
}
.drawer-tel a { color: var(--ink); font-weight: 700; text-decoration: none; }
.drawer-tel a:hover { color: var(--kiln-deep); }
.drawer-tel-sep { color: var(--border); }

/* Scroll lock for the page behind the open drawer.
   position:fixed, not just overflow:hidden — the latter was measured not to
   hold: with it applied, window.scrollTo(0,400) still moved the page. Taking
   the body out of flow does hold, on iOS and Android alike. JS supplies the
   negative `top` so the page stays visually where it was, and restores the
   scroll position on close (see the drawer block in assets/js/main.js). */
body.is-menu-open {
  position: fixed;
  left: 0;
  right: 0;
  width: 100%;
  overflow: hidden;
}

/* The burger crossing into an X. */
.nav-toggle-bar {
  width: 22px;
  height: 2px;
  background: var(--header-fg);
  display: block;
  border-radius: 2px;
  transition: transform 260ms cubic-bezier(0.22, 1, 0.36, 1), opacity 160ms ease, background-color 280ms ease;
}
.nav-toggle[aria-expanded="true"] .nav-toggle-bar { background: var(--ink); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bar:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* Entrance choreography. The panel itself slides in; its contents follow in a
   short cascade a beat behind, which is what makes the drawer read as
   assembling rather than simply appearing. Keyed off .is-open so it replays
   on every open, and only ever on opening — closing is the panel sliding out
   as one piece, which is quicker and less busy than reversing the cascade. */
@keyframes drawer-item-in {
  from { opacity: 0; transform: translateX(14px); }
  to   { opacity: 1; transform: translateX(0); }
}
.drawer.is-open .drawer-top,
.drawer.is-open .drawer-links > *,
.drawer.is-open .drawer-foot > * {
  animation: drawer-item-in 420ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
  animation-delay: calc(var(--i, 0) * 38ms + 140ms);
}
/* The top row leads, before the first link. */
.drawer.is-open .drawer-top { animation-delay: 90ms; }

/* The decorative wash grows in behind everything, slowest of all, so the
   panel has depth by the time the links have settled. */
@keyframes drawer-blob-in {
  from { opacity: 0; transform: scale(0.72); }
  to   { opacity: 1; transform: scale(1); }
}
.drawer.is-open .drawer-blob {
  animation: drawer-blob-in 720ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
}

@media (prefers-reduced-motion: reduce) {
  .drawer, .drawer-scrim, .drawer-panel, .drawer-caret, .nav-toggle-bar, .drawer-close { transition: none; }
  /* The cascade is decoration; without it the panel simply is where it is. */
  .drawer.is-open .drawer-top,
  .drawer.is-open .drawer-links > *,
  .drawer.is-open .drawer-foot > *,
  .drawer.is-open .drawer-blob { animation: none; }
  .drawer-close:hover { transform: none; }
}

/* ==========================================================================
   Brand lockup — header and footer
   ==========================================================================
   "Leo" and "Invisible Grills" were one inline string at a single size, which
   reads as a sentence rather than a mark. Stacked instead: the name carries
   the weight, the descriptor sits under it small and letter-spaced. Same
   treatment in both places so the two never look like different brands.
   The markup already had both words in their own spans (see includes/navbar.php
   and includes/footer-brand.php), so this is styling only. */
.brand-title,
.footer-name {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  /* The two lines are set tight against each other; the descriptor's own
     letter-spacing is what separates them optically. */
  line-height: 1;
  gap: 0.16em;
}

.brand-title-accent,
.footer-brand-accent {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 1.45em;
  letter-spacing: -0.02em;
  color: var(--kiln);
  /* Cut the extra space a display face leaves above and below the glyphs, so
     the two lines sit as one block rather than a paragraph. */
  line-height: 0.95;
}

.brand-title-name,
.footer-brand-rest {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 0.62em;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  white-space: nowrap;
  line-height: 1;
}

/* ---------- Motion ----------
   Restrained on purpose: a logo that performs on every page load stops
   reading as a mark and starts reading as an advert. The lockup settles in
   once, quickly, in the order you would read it — mark, name, descriptor —
   and thereafter only answers to a pointer.

   animation-fill-mode is `backwards`, not `both`: with `both` the finished
   keyframe keeps ownership of `transform`, and an animated value outranks a
   normal declaration, so the hover transform below would silently never
   apply. `backwards` hands the property back when the animation ends. */
@keyframes brand-settle {
  from { opacity: 0; transform: translateY(-5px); }
  to   { opacity: 1; transform: translateY(0); }
}

.brand .brand-logo        { animation: brand-settle 520ms cubic-bezier(0.22, 1, 0.36, 1) 60ms backwards; }
.brand .brand-title-accent { animation: brand-settle 520ms cubic-bezier(0.22, 1, 0.36, 1) 150ms backwards; }
.brand .brand-title-name   { animation: brand-settle 520ms cubic-bezier(0.22, 1, 0.36, 1) 230ms backwards; }

/* The header mark already transitions height/width as the header shrinks on
   scroll; transform is added to that list rather than replacing it, or the
   shrink would snap. */
.brand-logo {
  transition: height 280ms ease, width 280ms ease, transform 320ms cubic-bezier(0.22, 1, 0.36, 1);
  transform-origin: center;
}
.brand:hover .brand-logo,
.brand:focus-visible .brand-logo { transform: scale(1.06) rotate(-2deg); }

/* The descriptor opens up a fraction on hover — the smallest gesture that
   still registers, and it pulls the eye along the word rather than at it. */
.brand-title-name { transition: letter-spacing 320ms cubic-bezier(0.22, 1, 0.36, 1), color 280ms ease; }
.brand:hover .brand-title-name,
.brand:focus-visible .brand-title-name { letter-spacing: 0.22em; }

.brand-title-accent { transition: color 280ms ease; }
.brand:hover .brand-title-accent,
.brand:focus-visible .brand-title-accent { color: var(--kiln-deep); }

/* Footer: the same mark, but it is not a link, so there is nothing to answer
   a pointer with. It gets the lockup and a settle on the logo only — and no
   entrance cascade, because the footer is below the fold and an entrance
   keyed to page load would finish long before anyone scrolled to see it. */
.footer-logo { transition: transform 320ms cubic-bezier(0.22, 1, 0.36, 1); }
.footer-brand:hover .footer-logo { transform: scale(1.05) rotate(-2deg); }

@media (prefers-reduced-motion: reduce) {
  .brand .brand-logo,
  .brand .brand-title-accent,
  .brand .brand-title-name { animation: none; }
  .brand:hover .brand-logo,
  .brand:focus-visible .brand-logo,
  .footer-brand:hover .footer-logo { transform: none; }
  .brand:hover .brand-title-name,
  .brand:focus-visible .brand-title-name { letter-spacing: 0.16em; }
}

/* The footer lockup is sized from its own base, not the body-copy size.
   `.footer-grid p` (class+tag) outranks `.footer-name` and was pinning the
   base to 0.9rem, which pushed the descriptor down to ~9px — legible in a
   mockup, not on a phone. Beaten here with the same class+tag weight the
   colour fix above already needed. */
.footer-grid p.footer-name,
.footer-minimal-inner p.footer-name {
  font-size: 1.2rem;
}
/* A floor under the descriptor in both places, so it can never be rendered
   smaller than it can be read at, whatever the base around it ends up as. */
.brand-title-name,
.footer-brand-rest {
  font-size: max(0.62em, 0.7rem);
}

/* ==========================================================================
   Split hero — desktop only
   ==========================================================================
   Stacked, the hero on a wide screen was three horizontal bands: a small pill
   and a line of text, a letterbox photo spanning the full width, then the
   title and buttons underneath. The photo got most of the width and very
   little of the height, and the copy was split in two with the image between
   its halves — you read the pill, then the picture, then what it was about.

   Split, the copy is one column you read top to bottom — pill, lede, the
   current slide's name, the two buttons — and the photo sits beside it as a
   framed image with real height, closer to the 4:3 the photos were taken at.

   Opt-in via render_home_hero()'s 'layout' => 'split', and desktop only.
   Below 1024px this class does nothing, so phones and tablets keep the
   stacked layout that already works for a narrow screen, and the preserved
   render_services_hero() — which does not ask for it — is unaffected at any
   width. */
@media (min-width: 1024px) {
  .home-hero--split {
    display: grid;
    /* Copy a little narrower than the image: the photo is the evidence, the
       copy only has to name it. minmax(0, …) lets either column shrink below
       its content's intrinsic width instead of forcing a horizontal scroll. */
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
    /* Equal 1fr spacers above and below the two text rows, so the copy
       column sits centred against the photo. With a single spacer on top and
       the copy row absorbing the rest, the text slid into the lower half and
       left an empty block above the pill. */
    grid-template-rows: 1fr auto auto 1fr;
    grid-template-areas:
      ".     stage"
      "intro stage"
      "copy  stage"
      ".     stage";
    column-gap: clamp(2.5rem, 4.5vw, 5rem);
    /* The section stays full-bleed so its dark ground runs edge to edge; the
       content is held to the site container by padding instead. padding-inline
       only — padding-top is set by the header-offset rule on
       main > .home-hero:first-child and must not be overridden here. */
    padding-inline: max(var(--space-5), calc((100% - var(--container)) / 2 + var(--space-5)));
    padding-bottom: var(--space-8);
  }

  /* The two text blocks were each wrapped in .wrap for the stacked layout.
     Inside the grid the section provides the gutters, so .wrap's own max
     width, centring and padding would double them. */
  .home-hero--split > .wrap {
    max-width: none;
    margin: 0;
    padding: 0;
  }

  .home-hero--split > .home-hero-eyebrow-row {
    grid-area: intro;
    text-align: left;
    padding: 0;
  }
  .home-hero--split > .home-hero-copy-wrap {
    grid-area: copy;
    align-self: start;
    text-align: left;
    padding-top: var(--space-5);
  }

  .home-hero--split .home-hero-eyebrow {
    display: inline-block;
    width: auto;
  }
  /* With a whole column to itself the lede can be read at a real size rather
     than as a caption under a pill. */
  .home-hero--split .home-hero-lede {
    margin: var(--space-5) 0 0;
    max-width: 38ch;
    text-align: left;
    font-size: 1.15rem;
    line-height: 1.6;
    color: #d4dce1;
  }
  .home-hero--split .home-hero-copy h2 {
    font-size: clamp(2.3rem, 1.4rem + 1.9vw, 3.4rem);
    line-height: 1.05;
    letter-spacing: -0.015em;
    margin-bottom: var(--space-5);
  }
  .home-hero--split .home-hero-btn-row { justify-content: flex-start; }

  /* The photo becomes a framed image rather than a full-bleed band. Height
     is capped against the viewport so the whole hero — copy included —
     still fits above the fold on a laptop screen. */
  .home-hero--split > .home-hero-stage {
    grid-area: stage;
    align-self: center;
    height: min(66vh, 580px);
    border-radius: 18px;
    box-shadow:
      0 30px 60px -30px rgba(0, 0, 0, 0.75),
      0 0 0 1px rgba(255, 255, 255, 0.06);
  }
  /* The bottom fade existed to melt a full-bleed band into the section below
     it. On a framed card it would just make the lower edge look unfinished. */
  .home-hero--split > .home-hero-stage::after { display: none; }
  /* Likewise the top band was there for the transparent header's text to sit
     on. Nothing crosses this card's top edge, so it is dropped; the bottom
     band stays, because the carousel controls sit on it. */
  .home-hero--split .home-hero-photo-overlay {
    background: linear-gradient(to top, rgba(12, 22, 30, 0.6), rgba(12, 22, 30, 0.2) 45%, transparent) bottom / 100% 26% no-repeat;
  }
}

/* The slide title is the one line in the column that changes as the carousel
   turns. A short fade as it changes keeps the column from visibly snapping
   between names. Scoped to the split layout, so the preserved stacked hero
   behaves exactly as before. */
@media (min-width: 1024px) {
  .home-hero--split .home-hero-copy.is-active {
    animation: hero-copy-in 420ms cubic-bezier(0.22, 1, 0.36, 1) backwards;
  }
}
@keyframes hero-copy-in {
  from { opacity: 0; transform: translateY(8px); }
  to   { opacity: 1; transform: translateY(0); }
}
@media (prefers-reduced-motion: reduce) {
  .home-hero--split .home-hero-copy.is-active { animation: none; }
}
