/* Website UI kit — surface layout helpers.
   Components rely on tokens in ../../colors_and_type.css. */

* { box-sizing: border-box; }
body { margin: 0; }

/* Guard against horizontal scroll from decorative glow bleeds (e.g. the
   radial halos behind quote cards use negative insets that spill past the
   viewport edge on narrow screens). `clip` on the full-page wrapper contains
   the sideways bleed without establishing a scroll container, so the sticky
   sidebars (.svc-aside / .q-side) keep working. */
.surface { background: var(--ink-0); min-height: 100vh; overflow-x: clip; }
.container { max-width: 1280px; margin: 0 auto; padding: 0 48px; }

@media (max-width: 768px) {
  .container { padding: 0 24px; }
}

/* Aurora hero glow */
.aurora {
  position: absolute; inset: 0; pointer-events: none;
  background: radial-gradient(60% 50% at 50% 0%, rgba(32, 91, 242, 0.5), transparent 70%);
}
.grid-bg {
  position: absolute; inset: 0; pointer-events: none;
  background-image:
    linear-gradient(rgba(255,255,255,0.04) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,0.04) 1px, transparent 1px);
  background-size: 56px 56px;
  mask-image: radial-gradient(70% 50% at 50% 30%, #000 40%, transparent 100%);
  -webkit-mask-image: radial-gradient(70% 50% at 50% 30%, #000 40%, transparent 100%);
}

/* ---- Common buttons used across the kit -----------------------------------
   Every button on the site carries the same brand-blue halo: a hairline ring on
   the edge plus a wide, soft bloom behind it — the treatment the blog CTA panel
   uses (BlogPost.jsx `.blog-cta`), scaled down to button size. Primary buttons
   glow at full strength; secondary and ghost buttons take a dimmer version, so a
   row of mixed buttons still reads as one family instead of one lit button beside
   a dead one. Hover lifts both.

   The four values are tokens rather than literals because they are spent in six
   places (three .btn variants, the header call icon, the mobile-menu call button,
   the pulse keyframes) and the whole site should retune from one edit.

   box-shadow is the mechanism on purpose. It costs no layout, needs no
   pseudo-element on buttons that are already flex containers, and cannot push a
   horizontal scrollbar the way an absolutely-positioned blurred halo can — the
   failure `.surface { overflow-x: clip }` above exists to contain. */
:root {
  --btn-glow:            0 0 0 1px rgba(79,124,255,0.35), 0 0 20px -4px rgba(32,91,242,0.65), 0 0 46px -12px rgba(32,91,242,0.55);
  --btn-glow-hover:      0 0 0 1px rgba(79,124,255,0.60), 0 0 28px -2px rgba(79,124,255,0.85), 0 0 64px -10px rgba(32,91,242,0.70);
  --btn-glow-soft:       0 0 18px -6px rgba(32,91,242,0.45), 0 0 42px -14px rgba(32,91,242,0.38);
  --btn-glow-soft-hover: 0 0 26px -4px rgba(32,91,242,0.65), 0 0 56px -12px rgba(32,91,242,0.50);
}
.btn {
  font-family: var(--font-body); font-weight: 600; font-size: 14px;
  padding: 12px 20px; border-radius: 12px; border: 1px solid transparent;
  cursor: pointer; display: inline-flex; gap: 8px; align-items: center;
  transition: all 160ms cubic-bezier(.22,1,.36,1);
  white-space: nowrap;
}
.btn.primary { background: var(--brand-blue); color: #fff;
  box-shadow: var(--btn-glow); }
.btn.primary:hover { background: var(--brand-blue-bright); box-shadow: var(--btn-glow-hover); }
.btn.primary:active { background: var(--brand-blue-deep); transform: scale(0.98); }
.btn.secondary { background: var(--ink-2); color: var(--fg); border-color: var(--ink-4);
  box-shadow: var(--btn-glow-soft); }
.btn.secondary:hover { background: var(--ink-3); border-color: rgba(32,91,242,0.5); box-shadow: var(--btn-glow-soft-hover); }
.btn.ghost { background: transparent; color: var(--fg); border-color: var(--ink-4);
  box-shadow: var(--btn-glow-soft); }
.btn.ghost:hover { border-color: var(--ink-5); box-shadow: var(--btn-glow-soft-hover); }
/* A button the form has switched off is dimmed to 0.5 opacity inline; kill the
   halo too, so a control that cannot be pressed stops advertising itself. */
.btn:disabled, .btn[disabled] { box-shadow: none; }
.btn:focus-visible { outline: 2px solid var(--brand-blue-bright); outline-offset: 2px; }
.btn.lg { padding: 15px 24px; font-size: 15px; }
.btn.pill { border-radius: 999px; }
.btn .arrow { width: 14px; height: 14px; stroke: currentColor; stroke-width: 2; fill: none; }

/* Header call icon — the one pulsing control in the bar. It only exists below
   900px, where Header.jsx drops the phone number from the row, so on a phone it
   is the whole "call now" affordance; the pulse is what finds it against a dark
   hero photo. Same 2.8s cadence as the floating call button (FloatingPhone.jsx)
   so the two read as one heartbeat rather than two competing blinks.
   Declared here, not in Header.jsx, because this file is a <link> — the header's
   styles are inlined into 200+ prerendered pages and would need a full
   re-prerender to change. */
.gds-header__phone-icon { animation: gds-call-pulse 2.8s ease-in-out infinite; }
@keyframes gds-call-pulse {
  0%, 100% { box-shadow: 0 0 0 1px rgba(32,91,242,0.25), 0 0 14px -5px rgba(32,91,242,0.50), 0 0 34px -12px rgba(32,91,242,0.40); }
  50%      { box-shadow: 0 0 0 1px rgba(79,124,255,0.55), 0 0 26px -2px rgba(79,124,255,0.80), 0 0 58px -8px rgba(32,91,242,0.60); }
}
@media (prefers-reduced-motion: reduce) {
  /* Hold the halo at its bright half rather than dropping it: the glow is the
     affordance, the movement is the part that has to go. */
  .gds-header__phone-icon { animation: none; box-shadow: 0 0 0 1px rgba(79,124,255,0.45), 0 0 22px -4px rgba(32,91,242,0.65); }
}

/* Mobile-menu call button — a bare pill in Header.jsx, so it takes the same soft
   halo the ghost buttons do and stops reading as a hole beside the lit CTA. */
.gds-mnav__phone { box-shadow: var(--btn-glow-soft); transition: box-shadow 160ms cubic-bezier(.22,1,.36,1); }
.gds-mnav__phone:hover, .gds-mnav__phone:active { box-shadow: var(--btn-glow-soft-hover); }

/* In-article CTA buttons sit on a saturated coloured panel, so they take a white
   halo — a blue one would sink into the exact background it has to lift off.
   Selector is doubled up to outrank BlogIndex.jsx's own `.blog-cta__btn` rule,
   which is inlined after this stylesheet and would otherwise drop the
   box-shadow transition. */
.blog-cta .blog-cta__btn {
  box-shadow: 0 0 18px -6px rgba(255,255,255,0.55), 0 0 46px -14px rgba(255,255,255,0.32);
  transition: transform 150ms, box-shadow 160ms cubic-bezier(.22,1,.36,1);
}
.blog-cta .blog-cta__btn:hover { box-shadow: 0 0 26px -4px rgba(255,255,255,0.75), 0 0 60px -12px rgba(255,255,255,0.45); }

/* Eyebrow */
.eyebrow {
  font-size: 12px; font-weight: 600; text-transform: uppercase;
  letter-spacing: 0.18em; color: var(--brand-blue-bright);
  display: inline-flex; gap: 10px; align-items: center;
}
.eyebrow .dot { width: 6px; height: 6px; border-radius: 50%; background: currentColor; }

/* Generic card */
.gds-card {
  background: var(--ink-1);
  border: 1px solid var(--hairline);
  border-radius: 16px;
  padding: 24px;
  box-shadow: 0 4px 16px -4px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.06);
  transition: all 240ms cubic-bezier(.22,1,.36,1);
}
.gds-card:hover {
  background: var(--ink-2);
  border-color: rgba(32, 91, 242, 0.35);
  transform: translateY(-2px);
}

/* Icon slot */
.icon-slot {
  width: 40px; height: 40px; border-radius: 10px;
  background: rgba(32,91,242,0.15);
  border: 1px solid rgba(32,91,242,0.3);
  display: flex; align-items: center; justify-content: center;
  color: var(--brand-blue-bright);
}
.icon-slot svg { width: 20px; height: 20px; stroke: currentColor; stroke-width: 1.5; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.icon-slot.flame { background: rgba(254,132,21,0.12); border-color: rgba(254,132,21,0.3); color: #FE8415; }

/* Section */
section { position: relative; }
/* Native #hash jumps land below the sticky header (76px tall when scrolled) */
[id] { scroll-margin-top: 84px; }
.section-pad { padding: 96px 0; }
.section-pad-sm { padding: 64px 0; }
.section-divider { border-top: 1px solid var(--hairline); }
.section-alt { background: var(--ink-1); }

/* ===== Shared detail-page layout primitives (service + area pages) ===== */
.svc-crumb { display: flex; gap: 10px; align-items: center; font-size: 13px; color: var(--ink-6); margin-bottom: 22px; flex-wrap: wrap; }
.svc-crumb a { color: var(--ink-7); text-decoration: none; }
.svc-crumb a:hover { color: var(--ink-9); }
.svc-crumb em { color: var(--ink-9); font-style: normal; }
.svc-hero__actions { display: flex; flex-wrap: wrap; gap: 14px; margin-top: 30px; }
.svc-body { display: grid; grid-template-columns: 1fr 380px; gap: 56px; align-items: start; }
.svc-h2 { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.01em; font-size: clamp(26px, 3vw, 36px); color: var(--ink-9); margin: 12px 0 28px; }
.svc-h3 { font-family: var(--font-display); font-weight: 600; font-size: 20px; color: var(--ink-9); margin: 0 0 16px; }
.svc-aside { position: sticky; top: 96px; }
.svc-quote { display: flex; flex-direction: column; gap: 14px; }
.svc-quote__price { font-family: var(--font-mono); font-size: 22px; font-weight: 600; color: var(--ink-9); margin-top: 4px; }
.svc-quote__price span { color: var(--ink-6); font-size: 14px; font-weight: 400; }
.svc-quote__copy { color: var(--ink-7); font-size: 14px; line-height: 1.55; margin: 0; }
.svc-quote__cta { width: 100%; justify-content: center; }
.svc-quote__meta { display: flex; flex-direction: column; gap: 8px; margin-top: 6px; padding-top: 16px; border-top: 1px solid var(--hairline); }
.svc-quote__meta span { display: inline-flex; gap: 8px; align-items: center; color: var(--ink-7); font-size: 13px; }
.svc-quote__meta svg { color: var(--brand-blue-bright); }
.svc-others { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.svc-other { display: flex; flex-direction: column; gap: 8px; text-decoration: none; }
.svc-other__title { font-family: var(--font-display); font-size: 19px; font-weight: 600; color: var(--ink-9); margin: 14px 0 0; }
.svc-other__copy { color: var(--ink-7); font-size: 14px; line-height: 1.5; margin: 0; }
.svc-other__foot { margin-top: auto; padding-top: 14px; display: flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 13px; font-weight: 600; color: var(--brand-blue-bright); }
@media (max-width: 920px) {
  .svc-body { grid-template-columns: 1fr; gap: 36px; }
  .svc-aside { position: static; }
  .svc-others { grid-template-columns: 1fr; }
}

/* ===== Area / city + combo shared styles (used by AreaPage, LocalServicePage combos, LocalHub).
   Global so combo pages get them even though AreaPage isn't mounted there. ===== */
.area-hero { position: relative; overflow: hidden; padding: 72px 0 60px; min-height: 460px; display: flex; align-items: center; }
.area-hero__media { position: absolute; inset: 0; background-size: cover; background-repeat: no-repeat; filter: contrast(1.05) saturate(0.95); }
.area-hero__veil { position: absolute; inset: 0; background:
  linear-gradient(90deg, var(--ink-0) 0%, rgba(10,10,12,0.85) 44%, rgba(10,10,12,0.34) 100%),
  linear-gradient(0deg, var(--ink-0) 2%, transparent 40%); }
.area-hero__inner { position: relative; max-width: 760px; }
.area-hero__title { font-family: var(--font-display); font-weight: 700; letter-spacing: -0.02em; font-size: clamp(32px, 4.6vw, 56px); line-height: 1.05; color: var(--ink-9); margin: 14px 0 0; }
.area-hero__lead { color: var(--ink-7); font-size: 18px; line-height: 1.6; margin: 18px 0 0; max-width: 640px; }
.area-hero__meta { display: flex; flex-wrap: wrap; gap: 18px; margin-top: 22px; }
.area-hero__meta span { display: inline-flex; align-items: center; gap: 7px; color: var(--ink-7); font-family: var(--font-mono); font-size: 13px; }
.area-hero__meta svg { color: var(--brand-blue-bright); }

.area-body { color: var(--ink-8); font-size: 16.5px; line-height: 1.7; margin: 0 0 28px; }
.area-ilink { color: var(--info, #5EA8FF); text-decoration: none; font-weight: 500; background-image: linear-gradient(var(--info, #5EA8FF), var(--info, #5EA8FF)); background-size: 100% 1px; background-position: 0 1.15em; background-repeat: no-repeat; transition: color 140ms, background-size 140ms; }
.area-ilink:hover { color: #9CC7FF; background-size: 100% 2px; }
.area-ilink:focus-visible { outline: 2px solid var(--info, #5EA8FF); outline-offset: 2px; }
.area-landmark { display: flex; gap: 16px; align-items: flex-start; padding: 20px; border-radius: 16px;
  background: rgba(32,91,242,0.07); border: 1px solid rgba(32,91,242,0.22); }
.area-landmark__ico { flex: none; width: 42px; height: 42px; border-radius: 11px; display: flex; align-items: center; justify-content: center;
  background: rgba(32,91,242,0.16); border: 1px solid rgba(32,91,242,0.32); color: var(--brand-blue-bright); }
.area-landmark__name { font-family: var(--font-display); font-size: 18px; font-weight: 600; color: var(--ink-9); }
.area-landmark__blurb { color: var(--ink-7); font-size: 14.5px; line-height: 1.55; margin: 6px 0 0; }
.area-landmark__meta { display: flex; flex-wrap: wrap; align-items: center; gap: 6px 16px; margin-top: 8px; }
.area-landmark__meta span { display: inline-flex; align-items: center; gap: 6px; font-family: var(--font-mono); font-size: 12.5px; color: var(--ink-6); }

/* Landmark card + its Google Map, joined into one block. */
.area-place .area-landmark { border-radius: 16px 16px 0 0; border-bottom-color: transparent; }
.area-map { border: 1px solid rgba(32,91,242,0.22); border-top: 0; border-radius: 0 0 16px 16px;
  background: rgba(32,91,242,0.07); overflow: hidden; }
.area-map__frame { display: block; width: 100%; height: 300px; border: 0; }
.area-map__link { display: inline-flex; align-items: center; gap: 7px; padding: 12px 20px;
  font-family: var(--font-mono); font-size: 12.5px; color: var(--ink-7); text-decoration: none;
  border-top: 1px solid rgba(32,91,242,0.18); width: 100%; }
.area-map__link:hover { color: var(--brand-blue-bright); }
.area-map__link svg { flex: none; color: var(--brand-blue-bright); }
@media (max-width: 640px) { .area-map__frame { height: 230px; } }

.area-hoods { margin-top: 40px; }
.area-hoodsub { color: var(--ink-7); font-size: 14.5px; line-height: 1.55; margin: -6px 0 20px; }
.area-hoodgroup { margin-bottom: 18px; }
.area-hoodgroup__dir { font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: var(--ink-6); margin-bottom: 9px; }
.area-group__items { display: flex; flex-wrap: wrap; gap: 8px; }
.area-chip { font-size: 13.5px; color: var(--ink-7); padding: 7px 13px; border-radius: 999px; background: var(--ink-2); border: 1px solid var(--hairline); }
a.area-chip.is-linked { color: var(--ink-9); text-decoration: none; display: inline-flex; align-items: center; gap: 6px; transition: all 150ms; }
a.area-chip.is-linked:hover { border-color: rgba(32,91,242,0.5); color: var(--brand-blue-bright); }
a.area-chip.is-linked svg { color: var(--brand-blue-bright); }

.area-svcgrid { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.area-svc { display: flex; align-items: center; gap: 12px; padding: 13px 15px; border-radius: 12px; text-decoration: none;
  background: var(--ink-1); border: 1px solid var(--hairline); transition: all 160ms; }
.area-svc:hover { background: var(--ink-2); border-color: rgba(32,91,242,0.35); }
.area-svc__ico { flex: none; width: 34px; height: 34px; border-radius: 9px; display: flex; align-items: center; justify-content: center;
  background: rgba(32,91,242,0.13); border: 1px solid rgba(32,91,242,0.28); color: var(--brand-blue-bright); }
.area-svc__ico svg { width: 17px; height: 17px; stroke: currentColor; stroke-width: 1.5; fill: none; stroke-linecap: round; stroke-linejoin: round; }
.area-svc__txt { display: flex; flex-direction: column; min-width: 0; flex: 1; }
.area-svc__title { color: var(--ink-9); font-size: 14.5px; font-weight: 600; }
.area-svc__price { color: var(--ink-6); font-family: var(--font-mono); font-size: 12px; }
.area-svc > svg { color: var(--ink-5); flex: none; }

.area-faq { margin-top: 44px; }
.area-faq__item { border-top: 1px solid var(--hairline); padding: 4px 0; }
.area-faq__item summary { cursor: pointer; list-style: none; padding: 16px 28px 16px 0; position: relative;
  font-size: 16px; font-weight: 600; color: var(--ink-9); }
.area-faq__item summary::-webkit-details-marker { display: none; }
.area-faq__item summary::after { content: "+"; position: absolute; right: 4px; top: 14px; font-size: 22px; font-weight: 400; color: var(--brand-blue-bright); transition: transform 200ms; }
.area-faq__item[open] summary::after { content: "−"; }
.area-faq__item p { color: var(--ink-7); font-size: 15px; line-height: 1.6; margin: 0 0 16px; max-width: 60ch; }

/* "Recent job in {area}" micro-gallery. */
.area-jobs { margin-top: 40px; }
.area-jobs__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; margin-top: 16px; }
.area-jobs__grid.is-single { grid-template-columns: 1fr; max-width: 420px; }
.area-jobs__item { margin: 0; border-radius: 14px; overflow: hidden; border: 1px solid var(--hairline); background: var(--ink-1); }
.area-jobs__item img { display: block; width: 100%; aspect-ratio: 4 / 3; object-fit: cover; filter: grayscale(0.05) contrast(1.05) saturate(0.95); }
.area-jobs__item figcaption { padding: 10px 14px; font-family: var(--font-mono); font-size: 12px; color: var(--ink-6); }

/* Per-area local reviews grid — mirrors the home-page Reviews.jsx card look
   so genuine, location-tagged reviews read consistently site-wide. */
.area-reviews__grid { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
.area-reviews__grid .review { display: flex; flex-direction: column; gap: 12px; }
.area-reviews__grid .review-stars { display: flex; gap: 2px; }
.area-reviews__grid .review-text { font-size: 15px; color: var(--ink-8); line-height: 1.55; margin: 0; }
.area-reviews__grid .review-foot { display: flex; justify-content: space-between; align-items: center; padding-top: 8px; border-top: 1px solid var(--hairline); }
.area-reviews__grid .review-foot__name { font-weight: 600; color: var(--ink-9); font-size: 14px; }
.area-reviews__grid .review-foot__meta { display: flex; gap: 8px; font-family: var(--font-mono); font-size: 11px; color: var(--ink-6); }

/* Fallback (no local review on file) — the live Trustindex badge, reined in
   from its standalone-page padding so it reads as one tight card under the
   heading instead of a small badge lost in a tall empty band. */
.area-reviews-fallback .ti-reviews { padding: 20px 0 0; }
.area-reviews-fallback .ti-widget { display: flex; justify-content: center; min-height: 0; }

.area-quote { position: relative; border-color: rgba(32,91,242,0.34) !important;
  box-shadow: 0 0 0 1px rgba(32,91,242,0.16), 0 26px 70px -20px rgba(32,91,242,0.55), 0 10px 34px -14px rgba(0,0,0,0.65), inset 0 1px 0 rgba(255,255,255,0.06); }
.area-quote::before { content:""; position:absolute; inset:-2px; border-radius:18px; padding:1px; pointer-events:none; z-index:0;
  background: linear-gradient(135deg, rgba(79,124,255,0.6), rgba(32,91,242,0.05) 45%, transparent 70%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0); -webkit-mask-composite: xor; mask-composite: exclude; }
.area-quote::after { content:""; position:absolute; inset:-44px; border-radius:50%; pointer-events:none; z-index:-1;
  background: radial-gradient(58% 48% at 50% 28%, rgba(32,91,242,0.32), transparent 70%); filter: blur(36px); }
.area-quote > * { position: relative; z-index: 1; }
.area-quote__badge { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: #54d68a; }
.area-quote__badge .dot { width: 7px; height: 7px; border-radius: 50%; background: #54d68a; box-shadow: 0 0 8px #54d68a; }

.area-groups { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.area-group__dir { display: flex; align-items: center; gap: 9px; font-family: var(--font-display); font-size: 16px; font-weight: 600; color: var(--ink-9); margin: 0 0 16px; }
.area-group__dir svg { color: var(--brand-blue-bright); }
.area-note { color: var(--ink-7); font-size: 14.5px; margin-top: 28px; }
.area-note a { color: var(--brand-blue-bright); text-decoration: none; font-weight: 600; }

@media (max-width: 920px) {
  .area-groups { grid-template-columns: 1fr; }
  .area-svcgrid { grid-template-columns: 1fr; }
  .area-reviews__grid { grid-template-columns: 1fr; }
}
@media (max-width: 640px) {
  .area-jobs__grid { grid-template-columns: 1fr; }
}
