/* ══════════════════════════════════════════════════════════════════════════
   Components — the approved design, built on the Organic tokens.

   Ported from the client's HTML prototypes, which were reference material
   rather than shippable code: the geometry and copy are taken from them
   exactly, the structure is this codebase's own. The prototype directory
   is no longer in the repository. Every value below resolves through a
   var(--*) from tokens.css — no raw hex.

   Order: chrome (bar, drawer, sticky bar) → page furniture (hero, section
   heads) → the home page's sections in the order they appear → the pages
   the handoff did not design (service, location, gallery, quote form),
   built from the same parts → footer.

   Mobile-first throughout: unprefixed rules are the < 768px design of
   record, then min-width: 768px (tablet) and min-width: 1024px (desktop).
   ══════════════════════════════════════════════════════════════════════ */

/* ══ buttons ══════════════════════════════════════════════════════════
   tokens.css gives .btn the heading face; the approved design overrides
   it back to the body face at 800, which is what every button here uses.
   Pill radius comes from the token sheet. Only the background transitions
   — the handoff is explicit that nothing else moves.
   ═══════════════════════════════════════════════════════════════════ */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  font-family: var(--font-body);
  font-weight: 800;
  font-size: 15px;
  line-height: 1.2;
  text-align: center;
  padding: 15px var(--space-6);
  border: none;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.btn:hover { text-decoration: none; }

/* Every tap target clears 44px; these two keep that true when a variant's
   border eats into the box. */
.btn--primary { background: var(--color-accent-400); color: var(--color-accent-900); }
.btn--primary:hover { background: var(--color-accent-300); }

.btn--outline-dark {
  border: var(--stroke) solid var(--color-accent-2-700);
  color: var(--color-accent-2-100);
  font-weight: 700;
  padding: 12px var(--space-6);
}
.btn--outline-dark:hover { background: var(--color-accent-2-800); }

.btn--ink { background: var(--color-accent-2-900); color: var(--color-accent-2-100); font-weight: 700; }
.btn--ink:hover { background: var(--color-accent-2-800); }

.btn--outline-ink {
  border: var(--stroke) solid var(--color-accent-2-900);
  color: var(--color-accent-2-900);
  padding: 12px var(--space-6);
}
.btn--outline-ink:hover { background: var(--color-accent-2-200); }

/* Named for the fill, which is brass — the theme reserves clay for marks
   and bullets and never puts a label on it. Text is the brass ink: brass
   is far too light for the ground colour to pass contrast on it. */
.btn--brass { background: var(--color-accent); color: var(--color-accent-900); }
.btn--brass:hover { background: var(--color-accent-300); }

.btn--block { display: flex; width: 100%; }
.btn--grow { flex: 1; }

/* The lead button on the ads hero — the same primary fill, one step up in
   size, so the page has a single obvious action. An ad destination gets
   one chance at the click. */
.btn--lg { font-size: 16.5px; padding: 18px var(--space-8); }

/* On a phone the pair shares the row and both labels wrap to two lines,
   which is fine for "Call now"/"WhatsApp" and poor for the button the
   whole page exists to get tapped. Stacked full width here instead;
   scoped to this hero, so every other page keeps the side-by-side pair. */
.hero--ads .btn-row { flex-direction: column; align-items: stretch; }
@media (min-width: 768px) {
  .hero--ads .btn-row { flex-direction: row; align-items: center; }
}

.btn[disabled] { opacity: .45; cursor: not-allowed; }

.floating-actions {
  position: fixed;
  right: 18px;
  bottom: calc(18px + env(safe-area-inset-bottom, 0px));
  z-index: var(--z-bar);
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.floating-action {
  position: relative;
  display: grid;
  place-items: center;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  box-shadow: 0 12px 24px rgba(27, 32, 57, 0.22);
  transition: transform 0.18s ease, box-shadow 0.18s ease, filter 0.18s ease;
  animation: floating-action 2.8s ease-in-out infinite;
}

.floating-action:hover,
.floating-action:focus-visible {
  transform: translateY(-3px) scale(1.04);
  box-shadow: 0 16px 28px rgba(27, 32, 57, 0.26);
  filter: brightness(1.04);
}

/* This is the one element whose own box-shadow would overwrite the focus
   ring's dark outer edge set in base.css, because the rule above is shared
   with :hover. Keyboard focus therefore restates the lifted drop shadow
   and appends the ring. */
.floating-action:focus-visible {
  box-shadow:
    0 16px 28px rgba(27, 32, 57, 0.26),
    0 0 0 5px var(--color-accent-2-900);
}

.floating-action--call {
  background: var(--color-accent-2-900);
  color: var(--color-accent-2-100);
}

.floating-action--whatsapp {
  background: #25d366;
  color: #ffffff;
  animation-delay: 0.2s;
}

.floating-action__icon {
  width: 22px;
  height: 22px;
}

.floating-action--whatsapp .icon,
.floating-action--whatsapp svg {
  fill: currentColor;
  stroke: none;
}

.floating-action::after {
  content: "";
  position: absolute;
  inset: -6px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.45);
  opacity: 0;
  transform: scale(0.85);
  transition: opacity 0.2s ease, transform 0.2s ease;
}

.floating-action:hover::after,
.floating-action:focus-visible::after {
  opacity: 1;
  transform: scale(1);
}

@keyframes floating-action {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-6px); }
}

/* A row of buttons that share the width on mobile and sit inline above it. */
.btn-row { display: flex; gap: var(--space-2); }
.btn-row > .btn { flex: 1; }

@media (min-width: 768px) {
  .btn { padding: 14px var(--space-6); }
  /* Restated: the generic .btn override above would otherwise undo it. */
  .btn--lg { padding: 18px var(--space-8); }
  .btn--outline-dark, .btn--outline-ink { padding: 11.25px var(--space-6); }
  .btn-row > .btn { flex: 0 0 auto; }
  .btn-row { gap: 12px; padding-top: 6px; }
}

/* ══ icons ════════════════════════════════════════════════════════════
   core/icons.php renders 24×24 stroked SVGs at the system's 2.75 stroke.
   ═══════════════════════════════════════════════════════════════════ */

.icon { width: 20px; height: 20px; flex: none; }
.icon--sm { width: 16px; height: 16px; }

/* ══ fixed top bar ════════════════════════════════════════════════════ */

.bar {
  position: fixed;
  inset: 0 0 auto 0;
  z-index: var(--z-bar);
  background: var(--color-accent-2-900);
  /* iOS notch: the bar's own padding grows, the content does not move. */
  padding-top: env(safe-area-inset-top, 0px);
}

.bar__inner {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-height: var(--bar-height-mobile);
  /* 12px, not 14: the 43px lockup plus 2x14 would be 71px and push the
     bar past --bar-height-mobile, which the hero's top offset is measured
     from — the hero would then tuck 3px under the bar. */
  padding-block: 12px;
}

/* Position only — the lockup's look lives in .brand, in the brand-lockup
   block further down this file. */
.bar__brand { flex: none; margin-right: auto; }

/* Wraps to two lines at 430px without this. */
.bar__tel {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--color-accent-2-200);
  white-space: nowrap;
  flex: none;
}
.bar__tel:hover { color: var(--color-accent-300); text-decoration: none; }

/* Below 360px the number and the brand lockup cannot share the row without
   one being squeezed — the old wide logo was already shrunk to 97px here.
   The floating call button is on every page, so the number stays one tap
   away. */
@media (max-width: 359px) { .bar__tel { display: none; } }

.bar__links { display: none; }

.bar__quote { display: none; }

.burger {
  width: 40px;
  height: 40px;
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 4px;
  padding: 0;
  border: var(--stroke) solid var(--color-accent-2-700);
  border-radius: 999px;
  background: none;
  cursor: pointer;
}
.burger__bar {
  display: block;
  width: 15px;
  height: var(--stroke);
  border-radius: 999px;
  background: var(--color-accent-2-200);
  transition: transform .22s ease;
}
/* Open: the two bars rotate and meet as an X. */
.is-menu-open .burger__bar:first-child { transform: translateY(3.4px) rotate(45deg); }
.is-menu-open .burger__bar:last-child  { transform: translateY(-3.4px) rotate(-45deg); }

@media (min-width: 768px) {
  .bar__inner { min-height: var(--bar-height-tablet); padding-block: 0; gap: 20px; }
  .bar__tel { font-size: 14px; }
  .bar__quote { display: inline-flex; padding: 11px 22px; font-size: 14.5px; }
  .burger { width: 44px; height: 44px; }
  .burger span { width: 17px; }
}

@media (min-width: 1024px) {
  .bar__inner { min-height: var(--bar-height); gap: 40px; }
  /* The link row takes the spacer, so brand sits left and actions right. */
  .bar__brand { margin-right: 0; }
  .bar__links {
    display: flex;
    gap: 28px;
    margin-right: auto;
  }
  .bar__links a {
    font-size: 15px;
    font-weight: 600;
    color: var(--color-accent-2-200);
  }
  .bar__links a:hover,
  .bar__links a[aria-current="page"] { color: var(--color-accent-300); text-decoration: none; }
  .burger { display: none; }
}

/* ══ nav drawer (below 1024px) ════════════════════════════════════════ */

.drawer {
  position: fixed;
  inset: 0;
  z-index: var(--z-drawer);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  background: var(--color-accent-2-900);
  padding: calc(82px + env(safe-area-inset-top, 0px)) var(--gutter-mobile) var(--space-6);
  transform: translateY(-100%);
  visibility: hidden;
  transition:
    transform var(--drawer-duration) var(--drawer-ease),
    visibility 0s linear var(--drawer-duration);
}
.is-menu-open .drawer {
  transform: translateY(0);
  visibility: visible;
  transition:
    transform var(--drawer-duration) var(--drawer-ease),
    visibility 0s;
}

.drawer__blob {
  position: absolute;
  bottom: -140px;
  right: -110px;
  width: 340px;
  height: 340px;
  border-radius: 999px;
  background: var(--color-accent-2-800);
}

.drawer__inner {
  position: relative;
  display: flex;
  flex-direction: column;
  height: 100%;
  overflow-y: auto;
}

.drawer__kicker { margin-bottom: var(--space-4); }

.drawer__links { display: flex; flex-direction: column; }
.drawer__links a {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 32px;
  line-height: 1.1;
  color: var(--color-accent-2-100);
  padding: 14px 0;
  border-bottom: 2px solid var(--color-accent-2-800);
}
.drawer__links a:first-child { border-top: 2px solid var(--color-accent-2-800); }
.drawer__links a:hover,
.drawer__links a[aria-current="page"] { color: var(--color-accent-400); text-decoration: none; }

.drawer__foot {
  margin-top: auto;
  padding-top: var(--space-6);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}
.drawer__tel {
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--color-accent-2-400);
  text-align: center;
  padding-top: var(--space-2);
}
.drawer__tel a { color: inherit; }

/* Body scroll lock while the drawer is open. */
.is-menu-open { overflow: hidden; }

@media (min-width: 768px) {
  .drawer { padding-inline: var(--gutter-tablet); }
  .drawer__links a { font-size: 36px; }
}

@media (min-width: 1024px) {
  /* The inline link row replaces it entirely above this width. */
  .drawer { display: none; }
}

/* ══ hero ═════════════════════════════════════════════════════════════
   One component for the home page's hero and for every inner page's
   header band. --hero-blob-* let a page place the decorative circle
   without a second rule.
   ═══════════════════════════════════════════════════════════════════ */

.hero {
  position: relative;
  background: var(--color-accent-2-900);
  color: var(--color-accent-2-100);
  /* Exposed as a variable because the home hero has to subtract it: its
     band is one viewport tall *including* the space under the fixed bar. */
  --hero-offset: calc(var(--bar-height-mobile) + env(safe-area-inset-top, 0px));
  padding-top: var(--hero-offset);
}

/* Clips the blob to the copy band, so it sits behind the heading as
   designed and never reaches the trust strip below it. */
.hero__band { position: relative; overflow: hidden; }

.hero__blob {
  position: absolute;
  bottom: -120px;
  left: -60px;
  width: 280px;
  height: 280px;
  border-radius: 999px;
  background: var(--color-accent-2-800);
}

.hero__inner {
  position: relative;
  padding-top: var(--space-2);
  padding-bottom: var(--space-8);
}

.hero__copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.hero h1 { color: var(--color-accent-2-100); margin: 0; }
.hero h1 .accent { color: var(--color-accent-400); }

/* The Google Ads landing page names all three campaign cities in its H1,
   because the ad group's keywords are "invisible grills in <city>" and the
   heading has to echo them. At the site's normal 42/58/76px that heading
   fills a phone screen on its own and pushes the quote button below the
   fold, which is the one thing an ad destination cannot do. Sized down
   here rather than shortened. */
.hero--ads h1 { font-size: 31px; line-height: 1.05; letter-spacing: -0.01em; }

.hero__sub {
  font-size: 15.5px;
  line-height: 1.5;
  color: var(--color-accent-2-200);
  max-width: 320px;
  text-wrap: pretty;
  margin: 0;
}

.hero__media { display: none; }

/* Inner pages: shorter band, no photo, breadcrumb above the heading. */
.hero--page .hero__inner { padding-bottom: var(--space-8); }
.hero--page .hero__sub { max-width: 52ch; }

@media (min-width: 768px) {
  .hero { --hero-offset: var(--bar-height-tablet); }
  .hero__inner { padding-top: 48px; padding-bottom: 48px; }
  .hero__copy { gap: 22px; }
  .hero__sub { font-size: 19px; max-width: 470px; }
  .hero__blob { top: -80px; bottom: auto; left: auto; right: -200px; width: 460px; height: 460px; }

  .hero__media { display: block; }
  .hero__grid { display: grid; grid-template-columns: 1fr; gap: 36px; align-items: center; }
}

@media (min-width: 1024px) {
  .hero { --hero-offset: var(--bar-height); }
  .hero__inner { padding-top: 72px; padding-bottom: 64px; }
  .hero__grid { grid-template-columns: 7fr 5fr; gap: 56px; }
  .hero__blob { top: 40px; right: -140px; }
}

/* On a hero with no photo there is nothing sitting in front of the circle,
   so the full 460px disc reads as a dominant shape rather than as depth
   behind the image. Pulled smaller and further off-canvas to stay an
   accent. */
@media (min-width: 768px) {
  .hero--page .hero__blob { width: 340px; height: 340px; top: -90px; right: -170px; }
}

/* ══ washed photo treatment ═══════════════════════════════════════════
   .washed in tokens.css is the filter. This is its frame: rounded, clipped
   and (on wide screens) lifted, per the handoff.
   ═══════════════════════════════════════════════════════════════════ */

.frame {
  position: relative;
  border-radius: var(--radius-md);
  overflow: hidden;
}
.frame img { width: 100%; height: 100%; object-fit: cover; }

.frame--lg { border-radius: var(--radius-lg); }

@media (min-width: 768px) {
  .frame--lg { box-shadow: var(--shadow-lg); }
}

/* ══ trust strip ══════════════════════════════════════════════════════ */

.stats {
  display: flex;
  gap: var(--space-2);
  padding-bottom: var(--space-6);
}
.stat {
  flex: 1;
  border-top: var(--stroke) solid var(--color-accent-2-700);
  padding-top: 10px;
}
.stat b {
  display: block;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 21px;
  line-height: 1.1;
  color: var(--color-accent-2-100);
}
.stat span {
  display: block;
  font-size: 11.5px;
  line-height: 1.3;
  color: var(--color-accent-2-400);
}

@media (min-width: 768px) {
  .stats { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; padding-bottom: 44px; }
  .stat { padding-top: 16px; }
  .stat b { font-size: 34px; }
  .stat span { font-size: 14px; }
}

@media (min-width: 1024px) {
  .stats { grid-template-columns: repeat(4, 1fr); gap: 24px; padding-bottom: 56px; }
}

/* ══ section head ═════════════════════════════════════════════════════
   Heading flush left with whitespace kept on the right — the handoff is
   explicit that the asymmetry is the system's direction. The one-line
   note only appears from tablet up, where there is room for it.
   ═══════════════════════════════════════════════════════════════════ */

.sec-head { margin-bottom: var(--space-3); }
.sec-head h2 { margin: 0; }
.sec-head .kicker { display: block; margin-bottom: var(--space-2); }
.sec-head__note { display: none; }

@media (min-width: 768px) {
  .sec-head {
    display: grid;
    grid-template-columns: 1fr;
    gap: 14px;
    align-items: start;
    margin-bottom: 36px;
  }
  .sec-head__note {
    display: block;
    font-size: 16px;
    line-height: 1.5;
    color: var(--color-neutral-700);
    margin: 0;
  }
}

@media (min-width: 1024px) {
  .sec-head { grid-template-columns: 7fr 5fr; gap: 56px; align-items: end; }
}

/* ══ service cards ════════════════════════════════════════════════════
   Photo cover, title, description, three feature highlights and an
   "Explore …" action — the showcase layout the client supplied, in the
   existing card colours: sand ground, neutral-700 for the description.

   A wrapped grid rather than the reference's horizontal scroller: there
   are five cards, not seven, and the section directly below this one is
   already a snap scroller.
   ═══════════════════════════════════════════════════════════════════ */

.svc-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
}

.svc {
  display: flex;
  flex-direction: column;
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
  overflow: hidden;
  transition: box-shadow var(--transition-fast), transform var(--transition-fast);
}
.svc:hover { text-decoration: none; }

/* ── cover ───────────────────────────────────────────────────────────── */

.svc__cover {
  position: relative;
  display: block;
  aspect-ratio: 16 / 10;
  background: var(--color-accent-2-800);
}

/* Absolutely positioned, not just height:100%: against an aspect-ratio
   box that percentage does not resolve, so a portrait source lays out at
   its own ratio and stretches the cover instead of being cropped by it.
   Several of the installation photos are taller than they are wide. */
.svc__cover img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 400ms ease;
}
.svc:hover .svc__cover img { transform: scale(1.04); }

/* ── body ────────────────────────────────────────────────────────────── */

.svc__body {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: var(--space-4);
  flex: 1;
}

.svc__title {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 19px;
  line-height: 1.12;
  margin: 0;
}

.svc__note {
  margin: 0;
  font-size: 13.5px;
  line-height: 1.45;
  color: var(--color-neutral-700);
  text-wrap: pretty;
}

.svc__feats {
  list-style: none;
  margin: 2px 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.svc__feats li {
  position: relative;
  padding-left: 18px;
  font-size: 12.5px;
  font-weight: 600;
  line-height: 1.3;
}

/* A small brand disc rather than a bullet glyph, so the list reads as
   specification rather than as prose. */
.svc__feats li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .34em;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--color-accent) 70%, transparent);
}

.svc__more {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  margin-top: auto;
  padding-top: var(--space-2);
  font-size: 13.5px;
  font-weight: 700;
  color: var(--color-accent-700);
}
.svc__more .icon { transition: transform var(--transition-fast); }
.svc:hover .svc__more .icon { transform: translateX(3px); }

@media (min-width: 600px) {
  .svc-grid { grid-template-columns: repeat(2, 1fr); gap: 20px; }
}

@media (min-width: 768px) {
  .svc { border-radius: var(--radius-lg); }
  .svc:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
  .svc__body { padding: var(--space-6); gap: 11px; }
  .svc__title { font-size: 22px; }
  .svc__note { font-size: 14.5px; }
  .svc__feats li { font-size: 13px; }
  .svc__more { font-size: 14px; }
}

@media (min-width: 1024px) {
  .svc-grid { grid-template-columns: repeat(3, 1fr); gap: 24px; }
}

@media (prefers-reduced-motion: reduce) {
  .svc__cover img,
  .svc__more .icon { transition: none; }
  .svc:hover .svc__cover img { transform: none; }
}

/* ══ gallery: mobile scroller, wide grid ══════════════════════════════ */

/* Bleeds off the right edge on mobile, per the handoff. The negative
   margin is the container gutter, so it lines up whatever that is. */
.scroller {
  display: flex;
  gap: var(--space-2);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: var(--space-2);
  margin-right: calc(var(--gutter-mobile) * -1);
  padding-right: var(--gutter-mobile);
  scrollbar-width: none;
}
.scroller::-webkit-scrollbar { display: none; }
.scroller > * { scroll-snap-align: start; flex: none; width: 250px; }

.shot { display: flex; flex-direction: column; gap: var(--space-2); }
.shot .frame { height: 170px; }
.shot figcaption {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.4;
  color: var(--color-neutral-700);
  margin: 0;
}

/* The last cell of the row: a tile through to the full gallery rather
   than a link underneath, since on mobile the scroller is the thing a
   thumb is already moving through and a link below it would be missed. */
.shot--all { text-decoration: none; }

.shot__all {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 6px;
  height: 170px;
  padding: var(--space-4);
  background: var(--color-accent-2-900);
  color: var(--color-accent-2-100);
  transition: background var(--transition-fast);
}
.shot--all:hover .shot__all { background: var(--color-accent-2-800); }

.shot__allicon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  margin-bottom: auto;
  border-radius: 999px;
  background: var(--color-accent-400);
  color: var(--color-accent-2-900);
  transition: transform var(--transition-fast);
}
.shot--all:hover .shot__allicon { transform: translateX(4px); }

.shot__alltitle {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 17px;
  line-height: 1.1;
}

.shot__allnote {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.4;
  color: var(--color-accent-2-300);
}

@media (prefers-reduced-motion: reduce) {
  .shot__allicon { transition: none; }
  .shot--all:hover .shot__allicon { transform: none; }
}

@media (min-width: 768px) {
  .scroller {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    overflow: visible;
    margin-right: 0;
    padding-right: 0;
  }
  .scroller > * { width: auto; }
  .shot .frame { height: 260px; border-radius: var(--radius-lg); }
  .shot figcaption { font-size: 12px; }
  .shot__all { border-radius: var(--radius-lg); }
  .shot__alltitle { font-size: 19px; }
}

/* ══ process steps ════════════════════════════════════════════════════
   Mobile is a vertical timeline with a connector; wide screens drop the
   connector and let three columns carry the sequence.
   ═══════════════════════════════════════════════════════════════════ */

.steps { display: flex; flex-direction: column; list-style: none; margin: 0; padding: 0; }

.step { display: flex; gap: 14px; }

.step__rail { display: flex; flex-direction: column; align-items: center; flex: none; }

.step__num {
  width: 38px;
  height: 38px;
  flex: none;
  display: grid;
  place-items: center;
  border-radius: 999px;
  background: var(--color-accent-2-900);
  color: var(--color-accent-2-100);
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 16px;
  line-height: 1;
}
.step:last-child .step__num { background: var(--color-accent-400); color: var(--color-accent-900); }

.step__line { width: var(--stroke); flex: 1; background: var(--color-neutral-300); }
.step:last-child .step__line { display: none; }

.step__body { padding-bottom: var(--space-4); }
.step:last-child .step__body { padding-bottom: 0; }
.step__body b { display: block; font-size: 16px; font-weight: 800; }
.step__body span { font-size: 13.5px; line-height: 1.45; color: var(--color-neutral-700); }

@media (min-width: 768px) {
  .steps { display: grid; grid-template-columns: repeat(2, 1fr); gap: 32px; }
  .step { flex-direction: column; gap: 14px; }
  .step__rail { flex-direction: row; }
  .step__line { display: none; }
  .step__num { width: 52px; height: 52px; font-size: 22px; }
  .step__body { padding-bottom: 0; }
  .step__body b { font-size: 19px; }
  .step__body span { font-size: 15px; line-height: 1.5; }
}

@media (min-width: 1024px) {
  .steps { grid-template-columns: repeat(3, 1fr); }
}

/* ══ why us ═══════════════════════════════════════════════════════════ */

.why-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-3); }

.why-item { display: flex; flex-direction: column; gap: 6px; }
/* Clay, then brass — the theme's two mark colours, alternating. Clay is
   only ever used like this: a mark, never a fill behind a label. */
.why-item__dot {
  width: 11px;
  height: 11px;
  border-radius: 999px;
  background: var(--color-signal);
}
.why-item__dot--alt { background: var(--color-accent-2); }
.why-item b { display: block; font-size: 14.5px; font-weight: 800; }
.why-item span { font-size: 12.5px; line-height: 1.4; color: var(--color-neutral-700); }

@media (min-width: 768px) {
  .why-grid { grid-template-columns: repeat(2, 1fr); gap: 32px; }
  .why-item { gap: 0; }
  .why-item__dot { width: 14px; height: 14px; margin-bottom: 14px; }
  .why-item b { font-size: 17px; margin-bottom: 6px; }
  .why-item span { font-size: 14.5px; line-height: 1.5; }
}

@media (min-width: 1024px) {
  .why-grid { grid-template-columns: repeat(4, 1fr); }
}

/* ══ testimonial + area chips ═════════════════════════════════════════ */

.review {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-6);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}
.review blockquote { margin: 0; font-size: 18px; line-height: 1.45; text-wrap: pretty; }
.review__by { display: flex; align-items: center; gap: 10px; }
.review__avatar {
  width: 34px;
  height: 34px;
  flex: none;
  border-radius: 999px;
  /* Brass-soft. The second of the theme's two hand splits: this ramp step
     is muted copy on indigo everywhere else on the site. */
  background: var(--color-accent-200);
  overflow: hidden;
}
.review__by b { display: block; font-size: 14px; font-weight: 700; }
.review__by span { font-size: 12.5px; color: var(--color-neutral-700); }

.chips { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; margin: 0; padding: 0; }
/* Brass-soft, not shell-soft. The theme puts area pills on the brass
   tint with the brass soft-ink on top; the shell step this used to read
   is still doing its other job as body copy on indigo, which is why the
   theme flags this pair as a hand split rather than a find-replace. */
.chip {
  display: inline-flex;
  align-items: center;
  background: var(--color-accent-200);
  color: var(--color-accent-700);
  padding: 9px 15px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 600;
}
a.chip:hover { background: var(--color-accent-300); text-decoration: none; }

/* The "All of Bangalore" chip that opens every area row. It leads to the
   city hub, which is the parent of the twelve area pages, so it reads as
   the first item rather than one of the twelve. It carries the solid
   brass fill because the plain chips above now take the brass tint, and a
   tint against a tint would not separate them. */
.chip--city { background: var(--color-accent-400); color: var(--color-accent-900); }
a.chip--city:hover { background: var(--color-accent-300); }

@media (min-width: 768px) {
  .review { padding: 40px; gap: 20px; border-radius: calc(var(--radius-lg) * 1.15); }
  .review blockquote { font-size: 22px; line-height: 1.35; }
  .review__avatar { width: 46px; height: 46px; }
  .review__by { gap: 14px; }
  .review__by b { font-size: 15.5px; }
  .review__by span { font-size: 13.5px; }
  .chips { gap: 10px; }
  .chip { padding: 11px 18px; font-size: 15px; }
}

@media (min-width: 1024px) {
  .review blockquote { font-size: 26px; }
}

/* ══ testimonial slider ═══════════════════════════════════════════════
   One review at a time, advancing on a timer (assets/js/testimonial-
   slider.js). Every review is in the DOM; the inactive ones are hidden
   with visibility rather than display, so they still occupy the grid cell
   and the stage stays as tall as the longest quote instead of jumping as
   it advances.

   No stars anywhere: the quotes are sample copy until real ones replace
   them, and a rating would present them as counted. See the warning at
   the top of data/testimonials.php.
   ═══════════════════════════════════════════════════════════════════ */

.tslider { display: flex; flex-direction: column; gap: var(--space-4); }

/* Every slide in one grid cell, so the stack is as tall as the tallest. */
.tslider__stage { display: grid; }

.tslide {
  grid-area: 1 / 1;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-6);
  border-radius: calc(var(--radius-lg) * 1.15);
  background: var(--color-surface);
  box-shadow: var(--shadow-sm);
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity .45s ease, transform .45s ease, visibility 0s linear .45s;
}
.tslide.is-active {
  opacity: 1;
  visibility: visible;
  transform: none;
  transition: opacity .45s ease, transform .45s ease, visibility 0s;
}

.tslide__mark {
  font-family: var(--font-heading);
  font-size: 54px;
  line-height: .55;
  height: 26px;
  color: var(--color-accent-400);
}
.tslide__quote {
  margin: 0;
  font-size: 17px;
  line-height: 1.5;
  text-wrap: pretty;
}
.tslide__by { display: flex; align-items: center; gap: 12px; }
.tslide__avatar {
  flex: none;
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  border-radius: 999px;
  background: var(--color-accent-200);
  color: var(--color-accent-700);
  font-family: var(--font-brand);
  font-weight: 800;
  font-size: 17px;
}
.tslide__who b { display: block; font-size: 14.5px; font-weight: 700; }
.tslide__who span { font-size: 12.5px; color: var(--color-neutral-700); }

.tslider__controls { display: flex; align-items: center; gap: var(--space-3); }
.tslider__dots { display: flex; align-items: center; gap: 8px; }
.tdot {
  width: 8px;
  height: 8px;
  padding: 0;
  border: 0;
  border-radius: 999px;
  background: var(--color-neutral-400);
  cursor: pointer;
  transition: width var(--transition-fast), background var(--transition-fast);
}
.tdot:hover { background: var(--color-accent-500); }
.tdot.is-active { width: 26px; background: var(--color-accent-400); }

.tslider__pause {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 15px;
  border: 1px solid var(--color-divider);
  border-radius: 999px;
  background: none;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: 11.5px;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--color-neutral-700);
}
.tslider__pause:hover { color: var(--color-text); border-color: var(--color-neutral-400); }
/* Two bars while running, one triangle once paused. */
.tslider__pause-icon {
  width: 9px;
  height: 10px;
  border-left: 3px solid currentColor;
  border-right: 3px solid currentColor;
}
.tslider__pause.is-paused .tslider__pause-icon {
  width: 0;
  height: 0;
  border-left: 8px solid currentColor;
  border-right: 0;
  border-top: 5px solid transparent;
  border-bottom: 5px solid transparent;
}

@media (min-width: 768px) {
  .tslide { padding: 40px; gap: 20px; }
  .tslide__quote { font-size: 19px; }
  .tslide__mark { font-size: 64px; height: 30px; }
  .tslide__avatar { width: 46px; height: 46px; font-size: 19px; }
  .tslide__who b { font-size: 15.5px; }
  .tslide__who span { font-size: 13.5px; }
}

@media (min-width: 1024px) {
  /* The quote is the content here, so it takes the measure a long line
     wants rather than the full container width. */
  .tslide__quote { font-size: 21px; max-width: 62ch; }
}

@media (prefers-reduced-motion: reduce) {
  .tslide { transition: none; }
}

/* ══ FAQ ══════════════════════════════════════════════════════════════
   Collapsible, with every answer left in the DOM — open or closed, the
   text is crawlable, which is what the handoff asks for.
   ═══════════════════════════════════════════════════════════════════ */

.faq-list { display: flex; flex-direction: column; gap: var(--space-2); }

.faq {
  background: var(--color-surface);
  border-radius: var(--radius-md);
  padding: 15px;
}
.faq > summary {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: 15px;
  font-weight: 800;
  line-height: 1.3;
  cursor: pointer;
  list-style: none;
}
.faq > summary::-webkit-details-marker { display: none; }
.faq > summary::after {
  content: "";
  flex: none;
  width: 11px;
  height: 11px;
  margin-top: 5px;
  border-right: var(--stroke) solid var(--color-neutral-600);
  border-bottom: var(--stroke) solid var(--color-neutral-600);
  transform: rotate(45deg);
  transition: transform var(--transition-fast);
}
.faq[open] > summary::after { transform: rotate(-135deg); }
.faq p {
  font-size: 13px;
  line-height: 1.45;
  color: var(--color-neutral-700);
  padding-top: var(--space-2);
  margin: 0;
}

@media (min-width: 768px) {
  .faq-list { display: grid; grid-template-columns: 1fr 1fr; gap: 20px 40px; }
  .faq {
    background: none;
    border-radius: 0;
    padding: 18px 0 0;
    border-top: 2px solid var(--color-divider);
  }
  .faq > summary { font-size: 18px; }
  .faq p { font-size: 15px; line-height: 1.5; padding-top: 6px; }
}

/* ══ closing CTA band ═════════════════════════════════════════════════ */

.close-cta { background: var(--color-accent-2-900); color: var(--color-accent-2-100); }
.close-cta__inner {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding-block: var(--space-8);
}
.close-cta h2 { color: var(--color-accent-2-100); margin: 0; }
.close-cta p { font-size: 15px; line-height: 1.5; color: var(--color-accent-2-200); margin: 0; }

/* The pair only gained a gap from 768px up, so on a narrow phone the call
   button wrapped flush against the quote button. */
.close-cta__actions { display: flex; flex-wrap: wrap; gap: 12px; }

@media (min-width: 768px) {
  .close-cta__inner {
    display: grid;
    grid-template-columns: 1fr;
    gap: 32px;
    align-items: center;
    padding-block: var(--band-pad-tablet);
  }
  .close-cta p { font-size: 18px; margin-top: 16px; max-width: 480px; }
  .close-cta__actions { display: flex; flex-direction: column; gap: 12px; }
  .close-cta__actions .btn { width: 100%; }
}

@media (min-width: 1024px) {
  .close-cta__inner { grid-template-columns: 7fr 5fr; gap: 56px; padding-block: var(--band-pad); }
}

/* ══ footer ═══════════════════════════════════════════════════════════ */

.foot {
  background: var(--color-accent-2-900);
  color: var(--color-accent-2-200);
  border-top: 2px solid var(--color-accent-2-800);
  padding-block: var(--space-8);
  font-size: 14.5px;
  line-height: 1.7;
}
.foot__grid { display: grid; grid-template-columns: 1fr; gap: var(--space-6); }
.foot__group b {
  display: block;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 19px;
  color: var(--color-accent-2-100);
  margin-bottom: var(--space-2);
}
.foot__group ul { list-style: none; margin: 0; padding: 0; }
.foot a { color: var(--color-accent-2-200); }
.foot a:hover { color: var(--color-accent-300); }
.foot__group ul a { display: block; }
.foot__legal {
  border-top: 2px solid var(--color-accent-2-800);
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-accent-2-400);
}

@media (min-width: 768px) {
  .foot { padding-block: 44px; }
  .foot__grid { grid-template-columns: 1fr 1fr; gap: 40px; }
  .foot__group--about { grid-column: 1 / -1; }
}

@media (min-width: 1024px) {
  .foot__grid { grid-template-columns: 2fr 1fr 1fr 1fr; }
  .foot__group--about { grid-column: auto; }
}

/* ══ breadcrumbs ══════════════════════════════════════════════════════ */

.breadcrumbs { margin-bottom: var(--space-3); }
.breadcrumbs ol {
  display: flex;
  flex-wrap: wrap;
  gap: 6px var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--color-accent-2-400);
}
.breadcrumbs li + li::before { content: "/ "; color: var(--color-accent-2-700); }
.breadcrumbs a { color: var(--color-accent-2-300); }
.breadcrumbs a:hover { color: var(--color-accent-300); }
.breadcrumbs [aria-current] { color: var(--color-accent-2-200); }

/* ══ long-form page content ═══════════════════════════════════════════
   The service, service-location, location and about pages carry real
   copy. These are the reading styles for it — one measure, one rhythm,
   consistent with the cards around them.
   ═══════════════════════════════════════════════════════════════════ */

.prose { max-width: 68ch; }
.prose p { font-size: 15px; line-height: 1.6; color: var(--color-neutral-800); }
.prose p + p { margin-top: var(--space-3); }
.prose strong { font-weight: 700; color: var(--color-text); }
.prose h3 { margin: var(--space-6) 0 var(--space-2); }
.prose a { color: var(--color-accent-700); text-decoration: underline; }

@media (min-width: 768px) {
  .prose p { font-size: 16.5px; line-height: 1.65; }
}

/* Two-column split: copy left, a sand panel right. */
.split { display: grid; grid-template-columns: 1fr; gap: var(--space-6); align-items: start; }
@media (min-width: 1024px) {
  .split { grid-template-columns: 7fr 5fr; gap: 56px; }
  /* A section head already inside a split column must not split again —
     nesting the 7fr/5fr twice squeezes the heading into a third of the
     width and wraps it to three lines. */
  .split .sec-head { grid-template-columns: 1fr; gap: 14px; align-items: start; }
}

.panel {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}
.panel h3 { margin-top: 0; }
.panel p { font-size: 14.5px; line-height: 1.6; color: var(--color-neutral-800); margin: 0; }
/* Every other panel on the site holds a single paragraph, so the margin
   reset above was enough. The ads landing page's guarantee panel runs to
   three, which ran them together as one block. Scoped to the sibling so
   the single-paragraph panels are untouched. */
.panel p + p { margin-top: var(--space-3); }
/* .panel and .band--sand are both --color-surface, so a panel dropped into
   a sand band disappears into it. Lift it to the page ground instead: the
   card still reads as a card and the palette stays the same two tones.
   No existing page puts a panel on sand, so this only affects the ads
   landing page's guarantee card. */
.band--sand .panel { background: var(--color-bg); }

@media (min-width: 768px) { .panel { padding: 32px; } }

/* Checked list — used for "where it's used" and coverage lists. */
.checklist { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-3); }
.checklist li {
  display: flex;
  gap: var(--space-3);
  font-size: 14.5px;
  line-height: 1.5;
  color: var(--color-neutral-800);
}
.checklist li::before {
  content: "";
  flex: none;
  width: 9px;
  height: 9px;
  margin-top: 8px;
  border-radius: 999px;
  background: var(--color-signal);
}
.checklist li:nth-child(even)::before { background: var(--color-accent-2); }

@media (min-width: 768px) {
  .checklist { grid-template-columns: 1fr 1fr; gap: var(--space-4) var(--space-6); }
  .split .checklist { grid-template-columns: 1fr; }
}

/* A dense grid of onward links — the city × service matrix. */
.link-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}
.link-grid a {
  display: block;
  padding: 13px 15px;
  border-radius: var(--radius-md);
  background: var(--color-surface);
  color: var(--color-text);
  font-size: 14.5px;
  font-weight: 600;
  transition: background var(--transition-fast);
}
.link-grid a:hover { background: var(--color-accent-200); text-decoration: none; }

/* The secondary line inside a link-grid entry — the side of the city an
   area sits on, on the Bangalore hub. Block-level so it drops under the
   area name rather than running on from it. */
.link-grid__note {
  display: block;
  margin-top: 2px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--color-neutral-700);
}

@media (min-width: 768px) { .link-grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 1024px) { .link-grid { grid-template-columns: repeat(3, 1fr); } }

/* ══ gallery page ═════════════════════════════════════════════════════ */

.gallery-grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); }
.gallery-grid__item { display: flex; flex-direction: column; gap: var(--space-2); }
.gallery-grid__item[hidden] { display: none; }
.gallery-grid__zoom {
  display: block;
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  border-radius: var(--radius-md);
  overflow: hidden;
}
.gallery-grid__zoom img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; }
.gallery-grid figcaption {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--color-neutral-700);
  margin: 0;
}

@media (min-width: 768px) {
  .gallery-grid { grid-template-columns: repeat(3, 1fr); gap: 20px; }
  .gallery-grid__zoom { border-radius: var(--radius-lg); }
}

.lightbox {
  border: 0;
  padding: 0;
  max-width: min(1100px, 92vw);
  max-height: 92vh;
  background: var(--color-neutral-100);
  border-radius: var(--radius-lg);
  overflow: hidden;
}
.lightbox::backdrop { background: color-mix(in srgb, var(--color-neutral-900) 72%, transparent); }
.lightbox__figure { margin: 0; }
.lightbox__figure img { width: 100%; max-height: 80vh; object-fit: contain; }
.lightbox__figure figcaption {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-neutral-700);
  padding: var(--space-3) var(--space-4);
  margin: 0;
}
.lightbox__close,
.lightbox__nav {
  position: absolute;
  top: var(--space-3);
  right: var(--space-3);
  width: 40px;
  height: 40px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 999px;
  background: var(--color-accent-2-900);
  color: var(--color-accent-2-100);
  cursor: pointer;
}
.lightbox__nav { top: 50%; transform: translateY(-50%); }
.lightbox__nav--prev { left: var(--space-3); right: auto; }
.lightbox__nav--next { right: var(--space-3); }

/* ══ forms ════════════════════════════════════════════════════════════
   The quote form. tokens.css supplies .field/.input; these are the three
   touch overrides the handoff specifies — 52px min height, 15px text and
   a 2px divider border — plus the pill service picker and photo drop.
   ═══════════════════════════════════════════════════════════════════ */

.qform { display: flex; flex-direction: column; gap: var(--space-4); }

.field > label,
.field > legend {
  display: block;
  font-size: 13px;
  font-weight: 700;
  color: var(--color-neutral-800);
  margin-bottom: 6px;
  padding: 0;
}
.field__hint { font-size: 12.5px; color: var(--color-neutral-600); margin: 5px 0 0; }

.input {
  min-height: 52px;
  font-size: 15px;
  background: var(--color-neutral-100);
  border: 2px solid var(--color-divider);
}
.input:hover { border-color: var(--color-neutral-400); }
.input:focus-visible { border-color: var(--color-accent); }
textarea.input { min-height: 96px; border-radius: var(--radius-lg); padding-block: 14px; }
select.input { appearance: none; padding-right: 40px; }

.input[aria-invalid="true"] { border-color: var(--color-accent-700); }
.field__error {
  font-size: 12.5px;
  font-weight: 600;
  color: var(--color-accent-700);
  margin: 5px 0 0;
}

/* Pill checkboxes for the service picker. */
.pick { display: flex; flex-wrap: wrap; gap: var(--space-2); border: 0; padding: 0; margin: 0; }
.pick__opt {
  display: inline-flex;
  align-items: center;
  padding: 11px 16px;
  border: 2px solid transparent;
  border-radius: 999px;
  background: var(--color-surface);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.pick__opt:hover { border-color: var(--color-accent-300); }
.pick__opt input { position: absolute; opacity: 0; width: 0; height: 0; }
.pick__opt:has(input:checked) { background: var(--color-accent-200); border-color: var(--color-accent); }
.pick__opt:has(input:focus-visible) { outline: 2px solid var(--color-accent); outline-offset: 2px; }

.drop {
  display: block;
  text-align: center;
  padding: var(--space-6);
  border: var(--stroke) dashed var(--color-neutral-400);
  border-radius: var(--radius-lg);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast);
}
.drop:hover { border-color: var(--color-accent); background: var(--color-accent-100); }
.drop b { display: block; font-size: 15px; font-weight: 800; }
.drop span { font-size: 13px; color: var(--color-neutral-700); }
.drop input { position: absolute; width: 1px; height: 1px; opacity: 0; }

.consent { display: flex; align-items: flex-start; gap: var(--space-2); font-size: 14px; }
.consent input { width: 20px; height: 20px; margin-top: 2px; accent-color: var(--color-accent); }

/* rule / "or" / rule */
.or {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-neutral-600);
}
.or::before, .or::after {
  content: "";
  flex: 1;
  height: 2px;
  background: var(--color-divider);
}

.honeypot { position: absolute; left: -9999px; width: 1px; height: 1px; overflow: hidden; }

.status-banner {
  padding: var(--space-4) var(--space-6);
  border-radius: var(--radius-md);
  font-size: 15px;
  font-weight: 600;
  margin-bottom: var(--space-6);
}
.status-banner--success { background: var(--color-accent-2-200); color: var(--color-accent-2-800); }
.status-banner--error { background: var(--color-signal-soft); color: var(--color-text); }
.status-banner a { color: inherit; }

/* Reassurance chips under the quote intro. Fill is the design's, plus a
   hairline edge: the chip and the hero's decorative circle are both
   accent-2-800, so where they overlap the pill would otherwise vanish. */
.assure { display: flex; flex-wrap: wrap; gap: var(--space-2); list-style: none; margin: 0; padding: 0; }
.assure li {
  background: var(--color-accent-2-800);
  border: 1px solid var(--color-accent-2-700);
  color: var(--color-accent-2-100);
  font-size: 13px;
  font-weight: 600;
  padding: 8px 14px;
  border-radius: 999px;
}

.qform-layout { display: grid; grid-template-columns: 1fr; gap: var(--space-8); align-items: start; }

@media (min-width: 1024px) {
  .qform-layout { grid-template-columns: 5fr 7fr; gap: 56px; }
  .qform-card {
    background: var(--color-surface);
    border-radius: calc(var(--radius-lg) * 1.15);
    padding: var(--space-8);
  }
  .qform-card .input { background: var(--color-neutral-100); }
  .qform-card .pick__opt { background: var(--color-neutral-100); }
  .qform-submit { min-width: 260px; }
}

/* ══ home hero slideshow ══════════════════════════════════════════════
   Full-bleed service photography behind the hero copy, one slide per
   service. Layered back to front:

     .hero__slides   the photos
     .hero__scrim    a gradient wash — its top is solid accent-2-900, the
                     bar's own colour, so the fixed header and the hero
                     still read as one continuous dark ground
     .hero__blob     the design's decorative circle, kept but softened
                     since it now sits over photography rather than flat
     .hero__inner    the copy, inside .wrap like every other section

   The band is capped at the viewport height so the whole hero is visible
   without scrolling on any device, and every type size below is clamped
   so the copy shrinks to fit rather than overflowing on a short phone.
   ═══════════════════════════════════════════════════════════════════ */

.hero--home .hero__band {
  /* svh, not vh: on mobile browsers vh counts the area behind the
     retracting address bar, which would push the controls off-screen. */
  min-height: clamp(500px, calc(100svh - var(--hero-offset)), 900px);
  display: flex;
  align-items: center;
}

.hero__slides { position: absolute; inset: 0; }

.hslide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity .9s ease-in-out;
}
.hslide.is-active { opacity: 1; }

.hslide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* The slow push in is what makes a still photograph read as footage.
   Applied only to the active slide so it restarts on every change. */
.hslide.is-active img { animation: hero-kenburns 8s ease-out both; }

@keyframes hero-kenburns {
  from { transform: scale(1.02); }
  to   { transform: scale(1.11); }
}

.hero__scrim {
  position: absolute;
  inset: 0;
  /* Solid at the very top so the fixed bar and the hero are one colour,
     lightest through the middle where the photograph has to be legible,
     and solid again at the very bottom so it meets the trust strip with
     no seam. Kept to a single gradient on mobile: stacking a second one
     multiplies the darkness and buries the photo. */
  background: linear-gradient(
    180deg,
    var(--color-accent-2-900) 0%,
    color-mix(in srgb, var(--color-accent-2-900) 74%, transparent) 13%,
    color-mix(in srgb, var(--color-accent-2-900) 52%, transparent) 40%,
    color-mix(in srgb, var(--color-accent-2-900) 56%, transparent) 68%,
    color-mix(in srgb, var(--color-accent-2-900) 86%, transparent) 94%,
    var(--color-accent-2-900) 100%
  );
}

/* From tablet up the copy is a left-hand column, so the right side of the
   frame can carry much less wash and show the installation properly. */
@media (min-width: 768px) {
  .hero__scrim {
    background:
      linear-gradient(
        90deg,
        color-mix(in srgb, var(--color-accent-2-900) 55%, transparent) 0%,
        color-mix(in srgb, var(--color-accent-2-900) 22%, transparent) 55%,
        transparent 100%
      ),
      linear-gradient(
        180deg,
        var(--color-accent-2-900) 0%,
        color-mix(in srgb, var(--color-accent-2-900) 62%, transparent) 14%,
        color-mix(in srgb, var(--color-accent-2-900) 38%, transparent) 42%,
        color-mix(in srgb, var(--color-accent-2-900) 44%, transparent) 70%,
        color-mix(in srgb, var(--color-accent-2-900) 84%, transparent) 94%,
        var(--color-accent-2-900) 100%
      );
  }
}

/* Over photography the flat circle would read as a smudge, so it becomes
   a soft radial in the same colour instead of a hard-edged disc. */
.hero--home .hero__blob {
  bottom: -180px;
  left: -120px;
  width: 420px;
  height: 420px;
  background: radial-gradient(
    circle,
    color-mix(in srgb, var(--color-accent-2-800) 70%, transparent) 0%,
    transparent 68%
  );
}

.hero--home .hero__inner {
  /* svh-scaled: the band is one viewport tall, so the padding inside it
     has to give way on a short screen rather than overflow. */
  padding-top: clamp(10px, 1.8svh, 32px);
  padding-bottom: clamp(10px, 1.8svh, 32px);
  width: 100%;
}

.hero--home .hero__copy { gap: clamp(7px, 1.2svh, 18px); }

.hero--home h1 {
  font-size: clamp(26px, min(8.6vw, 5.6svh), 44px);
  line-height: 1.02;
  letter-spacing: -.015em;
}


.hero--home .hero__sub {
  max-width: 42ch;
  font-size: clamp(13px, min(3.9vw, 2.3svh), 16px);
}

/* ── the rotating service panel ─────────────────────────────────────
   All five panels occupy the same grid cell, so the block is as tall as
   the tallest one and nothing below it moves when the slide changes.
   ─────────────────────────────────────────────────────────────────── */

.hero__rotator {
  display: grid;
  margin-top: var(--space-2);
  border-left: 2px solid var(--color-accent-400);
  padding: clamp(7px, 1.2svh, 16px) var(--space-4);
  border-radius: 0 var(--radius-md) var(--radius-md) 0;
  /* Its own wash, rather than a heavier scrim over the whole frame. Two
     of the five photographs are bright enough that panel text drops under
     4.5:1 against them; this holds every slide well clear of that without
     darkening the photography everywhere else. */
  background: linear-gradient(
    90deg,
    color-mix(in srgb, var(--color-accent-2-900) 82%, transparent) 0%,
    color-mix(in srgb, var(--color-accent-2-900) 66%, transparent) 65%,
    color-mix(in srgb, var(--color-accent-2-900) 40%, transparent) 100%
  );
  backdrop-filter: blur(3px);
}

.hpanel {
  grid-area: 1 / 1;
  opacity: 0;
  visibility: hidden;
  transform: translateY(10px);
  transition: opacity .5s ease, transform .5s ease, visibility .5s;
}
.hpanel.is-active { opacity: 1; visibility: visible; transform: none; }

.hpanel__title {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: clamp(19px, 5.2vw, 26px);
  line-height: 1.1;
  margin: 0;
  color: var(--color-accent-2-100);
}
.hpanel__title a { color: inherit; text-decoration: none; }
.hpanel__title a:hover { color: var(--color-accent-400); }

.hpanel__blurb {
  margin: 6px 0 0;
  font-size: clamp(13px, 3.6vw, 15px);
  line-height: 1.5;
  color: var(--color-accent-2-200);
  max-width: 46ch;
  text-wrap: pretty;
}

.hpanel__feats {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  list-style: none;
  margin: var(--space-3) 0 0;
  padding: 0;
}

.hpanel__feats li {
  font-size: clamp(10.5px, 2.9vw, 12px);
  font-weight: 600;
  color: var(--color-accent-2-100);
  background: color-mix(in srgb, var(--color-accent-2-800) 60%, transparent);
  border: 1px solid color-mix(in srgb, var(--color-accent-2-100) 28%, transparent);
  border-radius: 999px;
  padding: 5px 11px;
}

/* Per-slide link through to that service. Sized as a compact pill so it
   reads as a button without costing the band much height — the hero has
   one viewport to work in. */
.hpanel__more {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: clamp(6px, 1.1svh, 14px);
  padding: 8px 16px;
  border-radius: 999px;
  border: 1.5px solid var(--color-accent-400);
  background: color-mix(in srgb, var(--color-accent-2-900) 45%, transparent);
  color: var(--color-accent-400);
  font-size: clamp(12px, 3.3vw, 13.5px);
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  transition: background .2s ease, color .2s ease;
}
.hpanel__more:hover,
.hpanel__more:focus-visible {
  background: var(--color-accent-400);
  color: var(--color-accent-2-900);
}
.hpanel__arrow { transition: transform .2s ease; }
.hpanel__more:hover .hpanel__arrow { transform: translateX(3px); }

/* ── dots and the pause control ─────────────────────────────────────── */

.hero__controls {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-top: var(--space-2);
  flex-wrap: wrap;
}

.hero__dots { display: flex; gap: 8px; }

.hdot {
  width: 30px;
  height: 4px;
  padding: 10px 0;               /* keeps the tap target ~24px tall */
  background: none;
  border: 0;
  cursor: pointer;
  box-sizing: content-box;
}

.hdot__fill {
  display: block;
  height: 4px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--color-accent-2-100) 30%, transparent);
  transition: background .3s ease;
}
.hdot.is-active .hdot__fill { background: var(--color-accent-400); }
.hdot:hover .hdot__fill { background: color-mix(in srgb, var(--color-accent-2-100) 55%, transparent); }

.hpause {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  background: none;
  border: 0;
  padding: 6px 2px;
  cursor: pointer;
  color: var(--color-accent-2-300);
  font-family: var(--font-mono);
  font-size: 10.5px;
  letter-spacing: .08em;
  text-transform: uppercase;
}
.hpause:hover { color: var(--color-accent-2-100); }

/* Two bars for "pause"; the script swaps the class for a play triangle. */
.hpause__icon {
  width: 9px;
  height: 10px;
  border-left: 3px solid currentColor;
  border-right: 3px solid currentColor;
}
.hpause.is-paused .hpause__icon {
  width: 0;
  height: 0;
  border: 5px solid transparent;
  border-left: 8px solid currentColor;
  border-right: 0;
}

@media (min-width: 768px) {
  .hero--home .hero__inner { padding-top: var(--space-8); padding-bottom: var(--space-8); }
  .hero--home .hero__copy { gap: var(--space-4); max-width: 660px; }
  .hero--home h1 { font-size: clamp(44px, 5.6vw, 62px); }
  .hero--ads h1 { font-size: clamp(38px, 4.4vw, 48px); }
  .hero--home .hero__sub { font-size: 17px; }
  .hero__rotator { padding: var(--space-4) calc(var(--space-4) * 1.25); }
  .hpanel__title { font-size: 28px; }
  .hpanel__blurb { font-size: 16px; }
  .hpanel__feats li { font-size: 12.5px; }
}

@media (min-width: 1024px) {
  .hero--home .hero__copy { max-width: 620px; }
  .hero--home h1 { font-size: 64px; }
  .hero--ads h1 { font-size: 54px; }
}

/* Reduced motion: no push-in, no crossfade, no auto-advance (the script
   also stops advancing). The slideshow becomes a plain switcher. */
@media (prefers-reduced-motion: reduce) {
  .hslide,
  .hpanel,
  .hpanel__more,
  .hpanel__arrow { transition: none; }
  .hslide.is-active img { animation: none; }
}

/* ══ "who we are" intro band ══════════════════════════════════════════
   Sits between the hero and the services grid. Carries the company's
   credentials with as little running text as possible: the years figure
   as an oversized numeral bled off the bottom-right corner, four marked
   credentials, and an index rail of services and cities that is both the
   keyword coverage and the page's first set of internal links.
   ═══════════════════════════════════════════════════════════════════ */

.intro {
  position: relative;
  overflow: hidden;
  padding-bottom: var(--space-8);
}

/* ── the years badge ─────────────────────────────────────────────────
   Shares the kicker's row rather than taking one of its own, so nothing
   in the layout moves to accommodate it. The figure is set in the display
   face against a solid accent chip; the words that follow sit outside the
   chip in mono, so the pair reads as a stamp on the section masthead
   rather than as a button.
   ─────────────────────────────────────────────────────────────────── */

.intro__eyebrow {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-4);
  margin: 0;
}

.intro__since {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--color-neutral-700);
}

.intro__since b {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 19px;
  line-height: 1;
  letter-spacing: -.02em;
  color: var(--color-accent-2-900);
  background: var(--color-accent-400);
  border-radius: 999px;
  padding: 5px 11px 6px;
}

.intro__inner { position: relative; }
/* ── copy ────────────────────────────────────────────────────────────── */

.intro__copy {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  max-width: 62ch;
}

.intro__head {
  font-size: clamp(25px, 6.6vw, 34px);
  line-height: 1.06;
  margin: 0;
  text-wrap: balance;
}
.intro__head .accent { color: var(--color-accent-600); }

.intro__lede {
  margin: 0;
  font-size: clamp(14.5px, 3.9vw, 16px);
  line-height: 1.55;
  color: var(--color-neutral-700);
  text-wrap: pretty;
}
.intro__lede strong { color: var(--color-text); font-weight: 700; }

/* Marked rather than bulleted: the discs pick up the service cards' dots
   and alternate the two brand accents down the list. */
.intro__creds {
  list-style: none;
  margin: var(--space-2) 0 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.intro__creds li {
  position: relative;
  padding-left: 26px;
  font-size: clamp(13.5px, 3.6vw, 15px);
  font-weight: 600;
  line-height: 1.35;
}

.intro__creds li::before {
  content: "";
  position: absolute;
  left: 0;
  top: .18em;
  width: 13px;
  height: 13px;
  border-radius: 999px;
  background: var(--color-signal);
}
.intro__creds li:nth-child(even)::before { background: var(--color-accent-2); }

/* ── the service / city index rail ───────────────────────────────────── */

.intro__rail {
  margin-top: calc(var(--space-8) * 1.4);
  border-top: 2px solid var(--color-divider);
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding-top: calc(var(--space-6) * 1.1);
}

.intro__row { display: grid; grid-template-columns: 1fr; gap: 10px; }

/* neutral-700 rather than the kicker's usual tint: these labels sit on
   the cream ground, where the lighter tints fall under 4.5:1. */
.intro__rowlabel {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--color-neutral-700);
}

.intro__links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 10px;
}

.intro__links a {
  display: inline-block;
  font-size: clamp(13px, 3.5vw, 14.5px);
  font-weight: 700;
  color: var(--color-text);
  text-decoration: none;
  padding-bottom: 2px;
  border-bottom: 2px solid var(--color-accent-400);
  transition: color .18s ease, border-color .18s ease;
}
.intro__links a:hover,
.intro__links a:focus-visible {
  color: var(--color-accent-600);
  border-bottom-color: var(--color-accent-600);
}

/* Separator dots between links, so the row reads as one list rather than
   as a set of loose buttons. Trailing rather than leading: with ::before
   a wrapped row opens with a stray dot. */
.intro__links li { display: flex; align-items: baseline; gap: 10px; }
.intro__links li:not(:last-child)::after {
  content: "·";
  color: color-mix(in srgb, var(--color-text) 45%, transparent);
}

@media (min-width: 768px) {
  .intro__copy { gap: var(--space-4); }
  .intro__creds { flex-direction: row; flex-wrap: wrap; gap: var(--space-3) var(--space-6); }
  .intro__row { grid-template-columns: 90px 1fr; gap: var(--space-4); align-items: baseline; }
  .intro__rowlabel { text-align: right; }
}

@media (min-width: 1024px) {
  .intro__head { font-size: 38px; }
}

/* ══ gallery page: jump nav and per-service footers ═══════════════════
   The gallery is grouped by service rather than filtered, so these are
   plain anchors down the page rather than a JavaScript control.
   ═══════════════════════════════════════════════════════════════════ */

.gal-jump {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* The count rides inside the chip as a lighter counter, so the nav says
   how much work is under each heading before you jump to it. */
.gal-jump .chip span {
  margin-left: 8px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  color: color-mix(in srgb, var(--color-accent-2-800) 65%, transparent);
}

.gal-more { margin: var(--space-4) 0 0; }

.gal-more a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-size: 14px;
  font-weight: 700;
  color: var(--color-accent-700);
  text-decoration: none;
}
.gal-more a:hover { color: var(--color-accent-800); }
.gal-more .icon { transition: transform var(--transition-fast); }
.gal-more a:hover .icon { transform: translateX(3px); }

/* Each service block gets its own heading and its own grid, so the gaps
   between them do more work than the gaps inside one. */
#work-invisible-grills { padding-top: var(--space-6); }

@media (prefers-reduced-motion: reduce) {
  .gal-more .icon { transition: none; }
  .gal-more a:hover .icon { transform: none; }
}

/* ══ service page: photo scroller ═════════════════════════════════════
   The service pages show their photos as one horizontal row at every
   width. Cells are filled edge to edge — object-fit: cover, no
   letterboxing — and sized generously enough that the crop stays gentle
   and the installation is still what you see.
   ═══════════════════════════════════════════════════════════════════ */

.gallery-grid--scroll {
  display: flex;
  gap: var(--space-3);
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: var(--space-3);
  /* Bleeds off the right gutter so the next photo peeks in as a cue. */
  margin-right: calc(var(--gutter-mobile) * -1);
  padding-right: var(--gutter-mobile);
  scrollbar-width: thin;
}
.gallery-grid--scroll > * {
  scroll-snap-align: start;
  flex: none;
  width: min(80vw, 320px);
}

.gallery-grid--scroll .gallery-grid__zoom {
  display: block;
  width: 100%;
  height: 260px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-surface);
  cursor: zoom-in;
}

.gallery-grid--scroll .gallery-grid__zoom img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* The closing cell, matching the home page's work row. */
.gallery-grid__all {
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: 6px;
  height: 260px;
  padding: var(--space-4);
  border-radius: var(--radius-md);
  background: var(--color-accent-2-900);
  color: var(--color-accent-2-100);
  text-decoration: none;
  transition: background var(--transition-fast);
}
.gallery-grid__all:hover { background: var(--color-accent-2-800); text-decoration: none; }

.gallery-grid__allicon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 38px;
  height: 38px;
  margin-bottom: auto;
  border-radius: 999px;
  background: var(--color-accent-400);
  color: var(--color-accent-2-900);
  transition: transform var(--transition-fast);
}
.gallery-grid__all:hover .gallery-grid__allicon { transform: translateX(4px); }

.gallery-grid__alltitle {
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 17px;
  line-height: 1.1;
}

.gallery-grid__allnote {
  font-family: var(--font-mono);
  font-size: 11px;
  line-height: 1.4;
  color: var(--color-accent-2-300);
}

@media (min-width: 768px) {
  .gallery-grid--scroll { margin-right: 0; padding-right: 0; gap: var(--space-4); }
  .gallery-grid--scroll > * { width: 380px; }
  .gallery-grid--scroll .gallery-grid__zoom,
  .gallery-grid__all { height: 330px; }
  .gallery-grid__alltitle { font-size: 19px; }
}

/* ══ technical specification card ═════════════════════════════════════
   The materials paragraph as label/value rows. A definition list, because
   that is exactly what it is — and it gives a screen reader the pairing
   for free, which a two-column div grid would not.
   ═══════════════════════════════════════════════════════════════════ */

/* The spec card was designed for the 5fr column of a split. On the
   service-location pages it now stands alone, so its width is capped —
   label-above-value rows read badly at the full 1160px container. */
.spec-solo { max-width: 640px; }

.spec {
  background: var(--color-surface);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}

.spec__head { margin-bottom: var(--space-4); }
.spec__head h3 {
  margin: 6px 0 0;
  font-size: 21px;
  line-height: 1.12;
}

.spec__rows { margin: 0; }

.spec__row {
  display: grid;
  grid-template-columns: 1fr;
  gap: 2px;
  padding: var(--space-3) 0;
  border-top: 1px solid color-mix(in srgb, var(--color-text) 14%, transparent);
}
.spec__row:first-child { border-top: 0; padding-top: 0; }
.spec__row:last-child { padding-bottom: 0; }

.spec__row dt {
  font-family: var(--font-mono);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--color-neutral-700);
}

.spec__row dd {
  margin: 0;
  font-size: 14.5px;
  font-weight: 600;
  line-height: 1.4;
  color: var(--color-text);
  text-wrap: pretty;
}

@media (min-width: 480px) {
  /* Label and value side by side once there is room for both without the
     value wrapping to two words a line. */
  .spec__row {
    grid-template-columns: 116px 1fr;
    gap: var(--space-4);
    align-items: baseline;
  }
}

@media (min-width: 768px) {
  .spec { padding: var(--space-8); }
  .spec__head h3 { font-size: 24px; }
  .spec__row { grid-template-columns: 132px 1fr; padding: var(--space-4) 0; }
  .spec__row dd { font-size: 15.5px; }
}

/* The one assurance badge that is a link. Given the accent outline the
   home hero's "Explore …" button uses, so the interactive chip in a row of
   static ones is obvious — and so its text clears 4.5:1 against the chip,
   which the inherited link colour did not. */
/* .assure li out-specifies a bare .assure__link, so the chip fill and
   border have to be reset at matching specificity or the linked badge
   ends up with two borders. */
.assure li.assure__link { padding: 0; background: none; border: 0; }

.assure__link a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 15px;
  border-radius: 999px;
  border: 1.5px solid var(--color-accent-400);
  background: color-mix(in srgb, var(--color-accent-2-900) 45%, transparent);
  color: var(--color-accent-400);
  font-size: 13px;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  transition: background var(--transition-fast), color var(--transition-fast);
}
.assure__link a:hover,
.assure__link a:focus-visible {
  background: var(--color-accent-400);
  color: var(--color-accent-2-900);
  text-decoration: none;
}

/* ══ service-location: the photo block ════════════════════════════════
   Below 1024px the hero drops its photo, so the page would open on text
   alone. This puts one image of the service back, at a size worth looking
   at, with the link on to the rest of that service's set.
   ═══════════════════════════════════════════════════════════════════ */

.loc-shot-wrap { display: block; }
.loc-shot-wrap .wrap { padding-block: 11px; }

/* The "designed border": a double edge in the two brand accents rather
   than a plain rule — the outer ring is offset so the frame reads as part
   of the design instead of a box drawn round a photo.

   No overflow:hidden here, or it would clip the very ring it is meant to
   show; the image is rounded on its own instead. */
.loc-shot {
  margin: 0;
  position: relative;
  border: 3px solid var(--color-accent-400);
  border-radius: var(--radius-lg);
  background: var(--color-surface);
}

.loc-shot::after {
  content: "";
  position: absolute;
  inset: -11px;
  border: 2px solid color-mix(in srgb, var(--color-accent-2-500) 55%, transparent);
  border-radius: calc(var(--radius-lg) + 8px);
  pointer-events: none;
}

.loc-shot img {
  display: block;
  width: 100%;
  height: clamp(240px, 58vw, 380px);
  object-fit: cover;
  border-radius: calc(var(--radius-lg) - 3px);
}

.loc-shot__all {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-top: var(--space-6);
  padding: 11px 20px;
  border-radius: 999px;
  background: var(--color-accent-2-900);
  color: var(--color-accent-2-100);
  font-size: 14px;
  font-weight: 700;
  line-height: 1;
  text-decoration: none;
  transition: background var(--transition-fast);
}
.loc-shot__all:hover,
.loc-shot__all:focus-visible {
  background: var(--color-accent-2-800);
  color: var(--color-accent-2-100);
  text-decoration: none;
}
.loc-shot__all .icon { transition: transform var(--transition-fast); }
.loc-shot__all:hover .icon { transform: translateX(3px); }

@media (min-width: 1024px) {
  /* The hero carries the photo again from here up. */
  .loc-shot-wrap { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  .loc-shot__all .icon { transition: none; }
  .loc-shot__all:hover .icon { transform: none; }
}

/* ══ drawer accordions ════════════════════════════════════════════════
   Services and Areas expand in place instead of jumping to a strip on the
   home page. Open is the CSS default so the drawer degrades to a plain
   list of every destination with the script blocked; assets/js/nav.js
   closes them on load and keeps one open at a time.
   ═══════════════════════════════════════════════════════════════════ */

.drawer__group { border-bottom: 2px solid var(--color-accent-2-800); }

.drawer__toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  width: 100%;
  padding: 14px 0;
  background: none;
  border: 0;
  cursor: pointer;
  text-align: left;
  font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  font-size: 32px;
  line-height: 1.05;
  color: var(--color-accent-2-100);
}
.drawer__toggle:hover { color: var(--color-accent-400); }

.drawer__caret {
  display: inline-flex;
  flex: none;
  color: var(--color-accent-400);
  transition: transform var(--transition-fast);
}
.drawer__group.is-open .drawer__caret { transform: rotate(90deg); }

.drawer__panel {
  overflow: hidden;
  transition: height .28s ease;
}

/* .drawer__links a also matches these, at the same specificity, so the
   display face and the bottom rule it sets have to be turned off here
   explicitly — a sub-link is body text, not a 32px heading. */
.drawer__panel a {
  display: block;
  padding: 9px 0 9px var(--space-4);
  border-bottom: 0;
  border-left: 2px solid var(--color-accent-2-700);
  font-family: var(--font-body);
  font-size: 16px;
  font-weight: 600;
  line-height: 1.3;
  color: var(--color-accent-2-200);
  text-decoration: none;
}
.drawer__panel a:first-child { padding-top: 2px; }
.drawer__panel a:last-child { padding-bottom: var(--space-4); }
.drawer__panel a:hover,
.drawer__panel a[aria-current="page"] { color: var(--color-accent-400); }

@media (prefers-reduced-motion: reduce) {
  .drawer__panel { transition: none; }
  .drawer__caret { transition: none; }
}

/* ══ brand lockup ═════════════════════════════════════════════════════
   The JS monogram on a porcelain tile, beside the "Invisible Grills"
   title, together in one glass pill (partials/brand.php). Header and
   footer share the markup; only the size steps differ.

   Why the tile: the monogram's blues measure 1.3-3.6:1 against the indigo
   bar, so on the bar itself the "JS" disappears and only the orange is
   left. On porcelain the same blues read at 5.6-11.4:1. The favicon and
   app icons carry the mark on the same tile, so it looks alike everywhere.

   Why the pill: glassmorphism on a flat ground. A translucent white fill,
   a hairline light border, a lit top edge and a soft diagonal reflection
   carry the effect; backdrop-filter is declared for anything that passes
   behind the bar, which on the flat indigo is nothing.

   Title colours, all measured against the bar (#1b2039):
     "Invisible"  steel sheen  #ffffff -> #b9bcd4          16.0 -> 8.54:1
     "GRILLS"     brass into the logo's orange
                  #f7e7c6 -> #ff9a1a -> #d9a03c             13.1 -> 6.89:1
   A highlight band sweeps across both words every 7s. It is dropped under
   prefers-reduced-motion, and a browser without background-clip:text gets
   solid porcelain and brass instead of invisible text.

   Sizes are bounded by what each bar can hold, measured in Chrome: 137px
   beside the phone number at 360px (the number hides below 360), ~191px
   at 1024px where the nav links arrive. The pill's height matches its bar:
   44px inside the 68px phone bar's 12px padding, 48px and 52px above.
   ═══════════════════════════════════════════════════════════════════ */

.brand {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  height: 44px;
  padding: 4px 12px 4px 4px;
  border-radius: 14px;
  color: inherit;
  text-decoration: none;
  background: linear-gradient(135deg,
    rgba(255, 255, 255, .16) 0%,
    rgba(255, 255, 255, .05) 55%,
    rgba(255, 255, 255, .10) 100%);
  border: 1px solid rgba(255, 255, 255, .18);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .28),
    inset 0 -1px 0 rgba(0, 0, 0, .22),
    0 8px 22px rgba(10, 13, 30, .35);
  -webkit-backdrop-filter: blur(12px) saturate(140%);
  backdrop-filter: blur(12px) saturate(140%);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}
/* The glass reflection: soft light across the top-left, fading out. */
.brand::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background: linear-gradient(118deg, rgba(255, 255, 255, .20) 0%, rgba(255, 255, 255, 0) 42%);
}
a.brand:hover {
  text-decoration: none;
  border-color: rgba(255, 255, 255, .30);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, .36),
    inset 0 -1px 0 rgba(0, 0, 0, .22),
    0 10px 26px rgba(10, 13, 30, .42);
}

.brand__tile {
  flex: none;
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: 10px;
  background: linear-gradient(160deg, #ffffff 0%, var(--color-neutral-100) 55%, var(--color-neutral-200) 100%);
  box-shadow:
    inset 0 0 0 1px rgba(255, 255, 255, .75),
    0 2px 6px rgba(10, 13, 30, .30);
}
.brand__mark { display: block; width: 30px; height: auto; }

.brand__title {
  display: flex;
  flex-direction: column;
  font-family: var(--font-brand);
  line-height: 1;
  white-space: nowrap;
  /* Lifts the metal off the glass; follows the clipped glyph shapes. */
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, .35));
}
.brand__word { display: block; }
.brand__word--main {
  font-size: 16px;
  font-weight: 800;
  letter-spacing: -.01em;
  color: var(--color-accent-2-100);
}
.brand__word--sub {
  margin-top: 3px;
  font-size: 9.5px;
  font-weight: 700;
  letter-spacing: .36em;
  text-transform: uppercase;
  color: var(--color-accent-300);
}

@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .brand__word {
    color: transparent;
    -webkit-background-clip: text;
    background-clip: text;
    background-repeat: no-repeat;
    /* Layer 1 is the shine band, 2.6x the word's width and parked just off
       its left edge; layer 2 is the metal itself. */
    background-size: 260% 100%, 100% 100%;
    background-position: 100% 0, 0 0;
  }
  .brand__word--main {
    background-image:
      linear-gradient(100deg, transparent 44%, rgba(255, 255, 255, .95) 50%, transparent 56%),
      linear-gradient(180deg, #ffffff 0%, #e6e7f0 42%, #b9bcd4 68%, #f2f1f6 100%);
  }
  .brand__word--sub {
    background-image:
      linear-gradient(100deg, transparent 44%, rgba(255, 255, 255, .9) 50%, transparent 56%),
      linear-gradient(180deg, #f7e7c6 0%, #ecba5e 38%, #ff9a1a 72%, #d9a03c 100%);
  }
}

/* The sweep: left to right in the first quarter of a 7s cycle, then off
   the right edge until the loop restarts off the left — never a visible
   jump. The second word trails the first by a beat. */
@media (prefers-reduced-motion: no-preference) {
  .brand__word { animation: brand-shine 7s cubic-bezier(.4, 0, .2, 1) 1.2s infinite; }
  .brand__word--sub { animation-delay: 1.32s; }
}
@keyframes brand-shine {
  0%        { background-position: 100% 0, 0 0; }
  24%, 100% { background-position: 0% 0, 0 0; }
}

@media (min-width: 768px) {
  .brand { height: 48px; gap: 10px; padding-right: 14px; border-radius: 15px; }
  .brand__tile { width: 40px; height: 40px; border-radius: 11px; }
  .brand__mark { width: 33px; }
  .brand__word--main { font-size: 18px; }
  .brand__word--sub { margin-top: 4px; font-size: 10.5px; }
}

@media (min-width: 1024px) {
  .brand { height: 52px; }
  .brand__tile { width: 44px; height: 44px; border-radius: 12px; }
  .brand__mark { width: 36px; }
  .brand__word--main { font-size: 19px; }
  .brand__word--sub { font-size: 11px; }
}

/* From 1280px the bar has ~300px spare beside the nav, so the lockup takes
   one more step. Between 1024 and 1279 the ~191px limit holds it at the
   size above. */
@media (min-width: 1280px) {
  .brand { height: 56px; gap: 11px; padding-right: 16px; border-radius: 16px; }
  .brand__tile { width: 48px; height: 48px; border-radius: 13px; }
  .brand__mark { width: 40px; }
  .brand__word--main { font-size: 21px; }
  .brand__word--sub { margin-top: 5px; font-size: 12px; }
}

/* Footer: the same lockup a size up, with room below it. Declared after
   the breakpoint steps so it holds at every width. */
.brand--foot { height: 58px; gap: 12px; padding-right: 18px; border-radius: 16px; margin-bottom: var(--space-4); }
.brand--foot .brand__tile { width: 50px; height: 50px; border-radius: 13px; }
.brand--foot .brand__mark { width: 41px; }
.brand--foot .brand__word--main { font-size: 22px; }
.brand--foot .brand__word--sub { margin-top: 5px; font-size: 12px; }
/* The address block under the footer logo. */
.foot__address { margin-top: var(--space-3); }
.foot__address strong { color: var(--color-accent-2-100); font-weight: 700; }
