/* Nista Projects — futuristic interaction layer (Watermelon UI-inspired, vanilla) */

/* Scroll progress — width is set directly from scrollY on every rAF tick with no CSS
   transition, so it tracks the actual scroll position 1:1 instead of animating toward
   a moving target (which is what read as "laggy"). */
#scroll-progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 0%;
  background: linear-gradient(90deg, var(--teal), var(--teal-dark));
  box-shadow: 0 0 10px rgba(19,180,157,.7);
  z-index: 500;
}

/* Cursor spotlight glow (desktop only) */
.cursor-glow {
  position: fixed; top: 0; left: 0; width: 460px; height: 460px;
  border-radius: 50%; pointer-events: none; z-index: 4; opacity: 0;
  background: radial-gradient(circle, rgba(19,180,157,.14), transparent 70%);
  transform: translate(-50%, -50%); transition: opacity .4s;
}
@media (hover: hover) and (pointer: fine) { .cursor-glow.active { opacity: 1; } }

/* Magnetic buttons */
.btn { position: relative; will-change: transform; }
/* Transform is driven entirely by JS (inline style) during magnetic tracking — this
   override keeps the base .btn transform-transition from fighting the per-frame updates,
   which is what caused the stutter. The hover glow below is a separate box-shadow, not
   transform, so it never fights the JS-driven position. */
.btn-primary, .btn-dark { transition: background .2s, color .2s, box-shadow 1s cubic-bezier(.2,.8,.2,1); }
.btn-primary:hover { box-shadow: 0 0 22px 4px rgba(19,180,157,.55); }
.btn-dark:hover { box-shadow: 0 0 22px 4px rgba(19,180,157,.45); }

/* Spotlight hover cards */
.spot-card { position: relative; isolation: isolate; }
.spot-card::before {
  content: ''; position: absolute; inset: 0; z-index: 0; opacity: 0; transition: opacity .35s;
  background: radial-gradient(320px circle at var(--mx, 50%) var(--my, 50%), rgba(19,180,157,.16), transparent 62%);
  pointer-events: none; border-radius: inherit;
}
.spot-card:hover::before { opacity: 1; }
.spot-card > * { position: relative; z-index: 1; }
.spot-card.on-dark::before { background: radial-gradient(320px circle at var(--mx,50%) var(--my,50%), rgba(19,180,157,.3), transparent 62%); }

/* Stat band */
.stats-band { position: relative; background: #000; color: #fff; overflow: hidden; }
.stats-band .bg-texture {
  position: absolute; inset: 0; background-image: url("../images/generated/hero-texture.jpg");
  background-size: cover; background-position: center; opacity: .3;
}
.stats-band .bg-fade { position: absolute; inset: 0; background: linear-gradient(90deg, rgba(0,0,0,.55), rgba(0,0,0,.85)); }
.stats-band .container { position: relative; z-index: 2; }
.stats-grid { display: grid; grid-template-columns: repeat(3, 1fr); max-width: 620px; margin: 0 auto; gap: 2rem; text-align: center; }
.stat-num {
  font-family: var(--font-display); font-weight: 700; font-size: clamp(2.1rem, 4.6vw, 3rem);
  color: var(--teal); text-shadow: 0 0 26px rgba(19,180,157,.55); line-height: 1;
}
.stat-label { font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: #bbb; margin-top: .6rem; }

/* Marquee ticker — scroll position is driven by JS (see effects.js), not a CSS
   animation. Pausing a CSS animation via animation-play-state has a real
   cross-browser bug where the paused frame can snap to a slightly different
   position than what was on screen, showing as a stutter/jump-back on hover.
   Driving the transform by hand in rAF sidesteps that entirely. */
.ticker { overflow: hidden; white-space: nowrap; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); background: var(--bg-soft); padding: .85rem 0; }
.ticker-track { display: inline-flex; gap: 2.6rem; padding-right: 2.6rem; will-change: transform; }
.ticker-item { font-family: var(--font-display); font-size: .8rem; font-weight: 600; letter-spacing: .1em; text-transform: uppercase; color: var(--grey); display: inline-flex; align-items: center; gap: .6rem; }
.ticker-item .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--teal); flex: none; }

/* Testimonial marquee rows */
.marquee-row { overflow: hidden; padding: 10px 0; -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent); }
.marquee-row + .marquee-row { margin-top: .6rem; }
.marquee-track { display: flex; gap: 1.4rem; width: max-content; animation: marquee-x 46s linear infinite; }
.marquee-row.reverse .marquee-track { animation-direction: reverse; }
.marquee-row:hover .marquee-track { animation-play-state: paused; }
@keyframes marquee-x { from { transform: translateX(0); } to { transform: translateX(-50%); } }
.marquee-card {
  flex: none; width: 340px; background: var(--white); border: 1px solid var(--line); border-radius: var(--radius);
  padding: 1.6rem; display: flex; flex-direction: column; gap: .8rem;
}
.marquee-card .stars { color: #f5a623; letter-spacing: 2px; font-size: .9rem; }
.marquee-card p { font-size: .92rem; color: var(--ink); }
.marquee-card .who { font-family: var(--font-display); font-weight: 600; font-size: .82rem; color: var(--grey); }

/* Filter chips */
.filter-bar { display: flex; gap: .6rem; flex-wrap: wrap; margin-bottom: 2.2rem; }
.chip {
  font-family: var(--font-display); font-size: .78rem; font-weight: 600; letter-spacing: .06em; text-transform: uppercase;
  padding: .6rem 1.15rem; border-radius: 999px; border: 1.5px solid var(--line); background: var(--white);
  cursor: pointer; transition: border-color .25s, color .25s, background .25s, transform .2s;
}
.chip:hover { transform: translateY(-2px); }
.chip.active { border-color: var(--teal); color: var(--teal); background: rgba(19,180,157,.08); }
.project-card { transition: opacity .35s ease, transform .35s ease; }
.project-card.filtered-out { display: none; }

/* Tab switcher */
.tab-bar { display: flex; gap: .3rem; margin-bottom: 2.4rem; border-bottom: 1px solid var(--line); flex-wrap: wrap; position: relative; }
.tab-btn {
  font-family: var(--font-display); font-size: .84rem; font-weight: 600; letter-spacing: .05em; text-transform: uppercase;
  padding: .95rem 1.2rem; background: none; border: none; cursor: pointer; color: var(--grey);
  position: relative; transition: color .25s;
}
.tab-btn.active, .tab-btn:hover { color: var(--black); }
.tab-underline { position: absolute; bottom: -1px; height: 2px; background: var(--teal); box-shadow: 0 0 8px rgba(19,180,157,.6); transition: transform .4s cubic-bezier(.65,0,.35,1), width .4s cubic-bezier(.65,0,.35,1); left: 0; width: 0; }
.tab-panel { display: none; }
.tab-panel.active { display: grid; animation: tab-fade-up .5s ease; }
@keyframes tab-fade-up { from { opacity: 0; transform: translateY(14px); } to { opacity: 1; transform: none; } }

/* Portfolio progress carousel (Addendum 6) — filterable grid of project cards, each
   card stepping through that project's photos lowest-number-first via arrows/dots/swipe.
   Reuses .filter-bar/.chip for the category pills and .project-card's filtered-out
   pattern for hide/show, for visual + behavioral consistency with the rest of the site. */
.pf-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1.8rem; }
.pf-card {
  background: var(--white); border: 1px solid var(--line); border-radius: var(--radius);
  overflow: hidden; transition: opacity .35s ease, transform .35s ease;
}
.pf-card.filtered-out { opacity: 0; transform: scale(.92); pointer-events: none; height: 0; margin: 0; border: 0; overflow: hidden; }
.pf-carousel { position: relative; aspect-ratio: 4 / 3; background: #000; overflow: hidden; touch-action: pan-y; }
.pf-carousel img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: 1; transition: opacity .3s ease; }
.pf-arrow {
  position: absolute; top: 50%; transform: translateY(-50%); width: 36px; height: 36px;
  border-radius: 50%; background: rgba(0,0,0,.55); color: #fff; border: none;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  opacity: 0; transition: background .2s, opacity .2s; z-index: 2;
}
.pf-carousel:hover .pf-arrow, .pf-arrow:focus-visible { opacity: 1; }
.pf-arrow:hover { background: var(--teal); }
.pf-arrow svg { width: 18px; height: 18px; }
.pf-prev { left: 10px; }
.pf-next { right: 10px; }
.pf-dots { position: absolute; bottom: 12px; left: 50%; transform: translateX(-50%); display: flex; gap: 5px; z-index: 2; }
.pf-dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(255,255,255,.5); transition: background .2s, transform .2s; padding: 0; border: none; cursor: pointer; }
.pf-dot.active { background: #fff; transform: scale(1.35); }
.pf-counter {
  position: absolute; top: 10px; right: 10px; background: rgba(0,0,0,.55); color: #fff;
  font-size: .7rem; font-family: var(--font-display); font-weight: 600; letter-spacing: .04em;
  padding: .25rem .55rem; border-radius: 999px; z-index: 2;
}
.pf-card-info { padding: 1.1rem 1.3rem 1.3rem; }
.pf-card-info h3 { font-size: 1.05rem; margin-bottom: .55rem; }
.pf-tags { display: flex; flex-wrap: wrap; gap: .4rem; }
.pf-tag {
  font-family: var(--font-display); font-size: .66rem; font-weight: 700; letter-spacing: .05em; text-transform: uppercase;
  color: var(--teal); background: rgba(19,180,157,.08); border: 1px solid rgba(19,180,157,.25);
  padding: .28rem .6rem; border-radius: 999px;
}
@media (max-width: 960px) { .pf-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .pf-grid { grid-template-columns: 1fr; } }

/* Accordion (FAQ) */
.accordion-item { border-bottom: 1px solid var(--line); }
.accordion-trigger {
  width: 100%; display: flex; justify-content: space-between; align-items: center; gap: 1rem;
  padding: 1.4rem 0; background: none; border: none; cursor: pointer; text-align: left;
  font-family: var(--font-display); font-weight: 600; font-size: 1.02rem; color: var(--black);
}
.accordion-trigger:hover { color: var(--teal); }
.accordion-trigger .plus { width: 22px; height: 22px; position: relative; flex: none; }
.accordion-trigger .plus::before, .accordion-trigger .plus::after { content: ''; position: absolute; background: var(--teal); transition: transform .3s; }
.accordion-trigger .plus::before { width: 100%; height: 2px; top: 50%; left: 0; transform: translateY(-50%); }
.accordion-trigger .plus::after { width: 2px; height: 100%; left: 50%; top: 0; transform: translateX(-50%); }
.accordion-item.open .plus::after { transform: translateX(-50%) rotate(90deg); opacity: 0; }
.accordion-panel { max-height: 0; overflow: hidden; transition: max-height .4s ease; }
.accordion-panel p { padding-bottom: 1.4rem; color: var(--grey); font-size: .95rem; max-width: 640px; }

/* Full-bleed landscape hero with scroll-dissolve */
.hero-landscape {
  position: relative; width: 100%; min-height: 92vh; height: 92vh;
  display: flex; align-items: center; justify-content: center;
  overflow: hidden; background: #000;
}
/* Single static hero photo (current) — see .hero-shuffle below for the ambient
   multi-photo version this replaced; left in place unused in case that comes back. */
.hero-bg-img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  object-position: center 35%;
}
/* Ambient hero photo shuffle (Addendum 4 + follow-up revisions) — replaces the old
   static .hero-bg-img. Big, heavily-overlapping tiles fade in, hold with a slow
   Ken-Burns drift, then fade out — each cycle landing on a fresh random position and a
   fresh random photo, orchestrated by js/hero-shuffle.js (not CSS @keyframes, since
   which photo goes where has to be decided against what's currently on screen so the
   same photo never shows in two places at once — a static keyframe loop can't do that).
   JS sets --top/--left/--w/--rot plus opacity/transform directly per cycle; only
   opacity and transform are ever touched (compositor-only, no layout thrashing — see
   the sl-line fix elsewhere in this file for why that matters), so this stays smooth
   despite being JS-driven. */
.hero-shuffle { position: absolute; inset: 0; overflow: hidden; }
.hero-photo-tile {
  position: absolute;
  top: var(--top); left: var(--left); width: var(--w);
  aspect-ratio: 4 / 3; border-radius: 10px; overflow: hidden;
  background: linear-gradient(135deg, #1c2022, #282d2f);
  box-shadow: 0 20px 45px rgba(0,0,0,.45);
  opacity: 0; transform: rotate(var(--rot)) scale(1) translate(0, 0);
  will-change: opacity, transform;
}
.hero-photo-tile img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Hero triptych — three full-height panels, each holding two stacked imgs that
   js/hero-shuffle.js cross-fades between. Slow opacity-only transitions
   (compositor-friendly, same rationale as everywhere else in this file). */
.hero-triptych { position: absolute; inset: 0; display: grid; grid-template-columns: repeat(3, 1fr); }
.hero-panel { position: relative; overflow: hidden; background: #101314; }
.hero-panel + .hero-panel { border-left: 2px solid rgba(0,0,0,.55); }
.hero-panel img {
  position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover;
  opacity: 0; transition: opacity 2.5s ease; will-change: opacity;
}

/* Lighter than the first pass on purpose — feedback was that the dark layer buried the
   photos. The radial dose stays a bit stronger than the surrounding wash specifically
   behind the headline/CTA (centered ellipse) so that text stays legible regardless of
   which photos land behind it, while the rest of the canvas reads much more vividly. */
.hero-overlay {
  position: absolute; inset: 0; z-index: 2;
  background:
    radial-gradient(ellipse 62% 52% at 50% 48%, rgba(0,0,0,.46) 0%, rgba(0,0,0,.16) 55%, transparent 75%),
    linear-gradient(180deg, rgba(0,0,0,.36) 0%, rgba(0,0,0,.18) 42%, rgba(0,0,0,.44) 100%);
}
.hero-center {
  position: relative; z-index: 4; text-align: center; color: #fff;
  max-width: 720px; padding: 0 1.5rem; will-change: transform, opacity, filter;
}
.hero-center .rating {
  background: rgba(255,255,255,.12); border: 1px solid rgba(255,255,255,.25); color: #fff;
  backdrop-filter: blur(4px);
}
.hero-center h1 { color: #fff; }
.hero-center h1 em { color: var(--teal); font-style: normal; }
.hero-center .lede { color: rgba(255,255,255,.85); max-width: 560px; margin-left: auto; margin-right: auto; }
.hero-tagline { color: var(--teal); font-family: var(--font-display); font-size: 1.15rem; font-weight: 600; margin-top: .9rem; }
.hero-center .hero-actions { justify-content: center; }
.hero-ghost { color: #fff; border-color: rgba(255,255,255,.7); }
.hero-ghost:hover { background: #fff; color: #111; }
.hero-landscape .scroll-cue { color: rgba(255,255,255,.75); }

/* Whole-heading fade/blur entrance (used where the heading has nested markup like <em>) */
.hero-fade-in { animation: hero-fade-up 1s cubic-bezier(.2,.8,.2,1) both; }
@keyframes hero-fade-up { from { opacity: 0; transform: translateY(22px); filter: blur(6px); } to { opacity: 1; transform: none; filter: blur(0); } }

/* Word-by-word hero headline reveal */
.word-reveal .word { display: inline-block; overflow: hidden; vertical-align: top; }
.word-reveal .word span { display: inline-block; opacity: 0; transform: translateY(110%) rotate(3deg); animation: word-in .8s cubic-bezier(.2,.8,.2,1) forwards; }

@keyframes word-in { to { opacity: 1; transform: none; } }

/* Section-heading fade + rise on scroll — same quiet entrance as
   .hero-fade-in above, applied via IntersectionObserver in effects.js.
   Replaced a glyph-scramble/decode effect per feedback that it read as
   "gamey" rather than professional. */
.heading-reveal { opacity: 0; transform: translateY(18px); filter: blur(4px); transition: opacity .7s ease, transform .7s ease, filter .7s ease; }
.heading-reveal.heading-in { opacity: 1; transform: none; filter: blur(0); }

/* Scroll cue */
.scroll-cue {
  position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: .45rem;
  font-family: var(--font-display); font-size: .64rem; letter-spacing: .14em; text-transform: uppercase;
  color: var(--grey); opacity: .75; z-index: 6;
}
.scroll-cue .line { width: 1px; height: 28px; background: linear-gradient(var(--teal), transparent); animation: cue-pulse 1.8s ease-in-out infinite; }
@keyframes cue-pulse { 0%, 100% { opacity: .2; } 50% { opacity: 1; } }

/* Generated service icon badges — background is a fixed white (not a theme variable) because
   the generated icon images have a white canvas baked in; on a dark bg-soft that would show
   as a visible white square instead of blending in. */
.icon-badge {
  width: 56px; height: 56px; border-radius: var(--radius); overflow: hidden;
  background: #fff; display: flex; align-items: center; justify-content: center;
  margin-bottom: 1rem; transition: transform .3s, box-shadow .3s;
}
.icon-badge img { width: 72%; height: 72%; object-fit: contain; }
.service-card:hover .icon-badge { transform: scale(1.08) rotate(-4deg); box-shadow: 0 10px 24px rgba(19,180,157,.25); }

/* Chatbot FAQ widget — rule-based quick answers, not a live AI. Mounted into
   #chatbot-widget-placeholder (position:fixed, 60x60, bottom-right) by js/chatbot.js. */
.chat-fab {
  width: 60px; height: 60px; border-radius: 50%; border: none; cursor: pointer;
  background: var(--teal); color: #fff; display: flex; align-items: center; justify-content: center;
  box-shadow: 0 10px 28px rgba(19,180,157,.45);
  transition: transform .25s, background .2s;
}
.chat-fab:hover { transform: scale(1.06); background: var(--teal-dark); }
.chat-fab svg { width: 25px; height: 25px; }
.chat-fab .icon-close { display: none; }
#chatbot-widget-placeholder.open .chat-fab .icon-chat { display: none; }
#chatbot-widget-placeholder.open .chat-fab .icon-close { display: block; }

.chat-panel {
  position: absolute; bottom: 76px; right: 0; width: 340px; max-width: calc(100vw - 48px);
  max-height: min(480px, 70vh); background: var(--white); border: 1px solid var(--line);
  border-radius: 14px; box-shadow: 0 24px 60px rgba(0,0,0,.28);
  display: flex; flex-direction: column; overflow: hidden;
  opacity: 0; transform: translateY(16px) scale(.96); pointer-events: none;
  transition: opacity .25s, transform .25s; transform-origin: bottom right;
}
#chatbot-widget-placeholder.open .chat-panel { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }

.chat-header {
  background: #000; color: #fff; padding: .9rem 1.1rem;
  display: flex; align-items: center; justify-content: space-between;
  font-family: var(--font-display); font-weight: 700; font-size: .92rem; flex: none;
}
.chat-close {
  background: none; border: none; color: #fff; font-size: 1.3rem; line-height: 1;
  cursor: pointer; padding: 0 .2rem; opacity: .8;
}
.chat-close:hover { opacity: 1; }

.chat-body { flex: 1; overflow-y: auto; padding: 1rem 1.1rem; display: flex; flex-direction: column; gap: .7rem; }
.chat-msg { max-width: 92%; padding: .65rem .85rem; border-radius: 12px; font-size: .86rem; line-height: 1.45; }
.chat-msg.bot { background: var(--bg-soft); color: var(--ink); align-self: flex-start; border-bottom-left-radius: 3px; }
.chat-msg.user { background: var(--teal); color: #fff; align-self: flex-end; border-bottom-right-radius: 3px; font-weight: 600; }

.chat-actions { display: flex; flex-wrap: wrap; gap: .4rem; margin-top: .55rem; }
.chat-action-btn {
  font-family: var(--font-display); font-size: .7rem; font-weight: 700; letter-spacing: .03em;
  padding: .45rem .8rem; border-radius: 999px; border: 1.5px solid var(--teal); color: var(--teal);
  background: transparent; cursor: pointer; text-decoration: none; display: inline-block;
  transition: background .2s, color .2s;
}
.chat-action-btn:hover { background: var(--teal); color: #fff; }

.chat-quick { display: flex; flex-direction: column; gap: .4rem; }
.chat-quick-btn {
  text-align: left; font-family: var(--font-body); font-size: .84rem;
  padding: .6rem .75rem; border-radius: 10px; border: 1px solid var(--line);
  background: var(--white); cursor: pointer; color: var(--ink);
  transition: border-color .2s, background .2s;
}
.chat-quick-btn:hover { border-color: var(--teal); background: var(--bg-soft); }

.chat-footer {
  padding: .65rem 1.1rem; border-top: 1px solid var(--line);
  font-size: .74rem; color: var(--grey); text-align: center; flex: none;
}
.chat-footer a { color: var(--teal); font-weight: 600; }

/* Exit-intent quote popup — desktop only, once per browser session.
   Trigger logic lives in js/exit-intent.js; this is purely presentational. */
.exit-modal-overlay {
  position: fixed; inset: 0; z-index: 600;
  background: rgba(0,0,0,.6);
  display: flex; align-items: center; justify-content: center; padding: 1.5rem;
  opacity: 0; pointer-events: none; transition: opacity .35s;
}
.exit-modal-overlay.open { opacity: 1; pointer-events: auto; }
.exit-modal {
  position: relative; width: min(420px, 100%);
  background: var(--white); border-radius: 14px; padding: 2.4rem 2.2rem 2.2rem;
  box-shadow: 0 30px 80px rgba(0,0,0,.35);
  transform: translateY(18px) scale(.97);
  transition: transform .35s cubic-bezier(.2,.8,.2,1);
}
.exit-modal-overlay.open .exit-modal { transform: translateY(0) scale(1); }
.exit-modal .eyebrow { font-size: 1.05rem; font-weight: 800; letter-spacing: .04em; }
.exit-modal h3 { font-size: 1.5rem; margin: .3rem 0 .6rem; }
.exit-modal > p { color: var(--grey); font-size: .93rem; margin-bottom: 1.4rem; }
.exit-modal .quote-form { gap: .9rem; }
.exit-modal .quote-form .btn { width: 100%; text-align: center; margin-top: .2rem; }
.exit-modal-close {
  position: absolute; top: 1rem; right: 1rem; width: 32px; height: 32px; border-radius: 50%;
  border: none; background: var(--bg-soft); color: var(--ink); font-size: 1.3rem; line-height: 1;
  cursor: pointer; display: flex; align-items: center; justify-content: center; transition: background .2s;
}
.exit-modal-close:hover { background: var(--line); }
.exit-modal-skip { display: block; text-align: center; margin-top: 1.1rem; font-size: .85rem; color: var(--grey); }
.exit-modal-skip:hover { color: var(--teal); }

/* Trust badge row — neutral/outline styling on purpose: these are unconfirmed
   placeholders (see README), not verified claims, so they shouldn't read as bold
   teal "verified" badges like the rest of the site's accent-colored trust cues. */
.trust-strip { display: flex; flex-wrap: wrap; gap: .7rem; margin-top: 2rem; }
.trust-badge {
  display: inline-flex; align-items: center; gap: .55rem;
  padding: .55rem .95rem; border-radius: 999px; border: 1px solid var(--line);
  font-size: .8rem; color: var(--grey); background: transparent;
}
.trust-badge svg { width: 16px; height: 16px; flex: none; }
.trust-badge.prominent {
  font-weight: 700; font-size: .9rem; color: var(--teal);
  border-color: var(--teal); background: rgba(19,180,157,.08); padding: .7rem 1.15rem;
}
.trust-badge.prominent svg { width: 19px; height: 19px; }
.trust-note { font-size: .78rem; color: var(--grey); margin-top: .7rem; max-width: 480px; }
.site-footer .trust-strip { margin-top: 2.6rem; padding-top: 2rem; border-top: 1px solid #222; }
.site-footer .trust-badge { border-color: #333; color: #999; }
.site-footer .trust-badge.prominent { color: var(--teal); border-color: var(--teal); background: rgba(19,180,157,.12); }
.site-footer .trust-note { color: #777; }

/* Process steps (index.html "how it works") */
.process-track { position: relative; display: grid; grid-template-columns: repeat(4, 1fr); gap: 2rem; }
.process-track::before {
  content: ''; position: absolute; top: 23px; left: 12.5%; right: 12.5%; height: 2px;
  background: linear-gradient(90deg, var(--teal), rgba(19,180,157,.15), var(--teal));
  z-index: 0;
}
.process-step { position: relative; z-index: 1; text-align: center; }
.process-num {
  display: flex; align-items: center; justify-content: center;
  width: 46px; height: 46px; margin: 0 auto 1.2rem; border-radius: 50%;
  border: 2px solid var(--teal); background: var(--white);
  font-family: var(--font-display); font-weight: 700; font-size: .95rem; color: var(--teal);
}
.process-step h3 { margin-bottom: .5rem; }
.process-step p { color: var(--grey); font-size: .92rem; max-width: 240px; margin: 0 auto; }

@media (prefers-color-scheme: dark) {
  .process-num { background: var(--white); }
}

@media (max-width: 960px) {
  .stats-grid { gap: 1.4rem; }
  .process-track { grid-template-columns: repeat(2, 1fr); row-gap: 2.6rem; }
  .process-track::before { display: none; }
}
@media (max-width: 640px) {
  .cursor-glow { display: none; }
  .hero-landscape { height: 86vh; min-height: 520px; }
  .chat-panel { bottom: 72px; }
  .process-track { grid-template-columns: 1fr; }
  /* Mobile gets the sticky "Get a Quote" bar instead — no reliable exit-intent
     signal on touch devices (see js/exit-intent.js, which also gates on hover capability). */
  .exit-modal-overlay { display: none !important; }
}

/* ============================================================
   Visual polish pass — 10 effects (2026-07-14)
   Revert: git revert / checkout the "Snapshot before visual
   effects pass" commit in this folder's git repo.
   ============================================================ */

/* 1) Animated film-grain on dark bands — premium matte feel */
.stats-band::after, .cta-band::after {
  content: ''; position: absolute; inset: -100%;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
  opacity: .055; pointer-events: none; z-index: 1;
  animation: grain-shift 8s steps(10) infinite;
}
.cta-band { position: relative; overflow: hidden; }
.cta-band .container { position: relative; z-index: 2; }
@keyframes grain-shift {
  0%, 100% { transform: translate(0, 0); }
  10% { transform: translate(-4%, -6%); }
  20% { transform: translate(3%, -2%); }
  30% { transform: translate(-2%, 4%); }
  40% { transform: translate(5%, 6%); }
  50% { transform: translate(-5%, 2%); }
  60% { transform: translate(2%, -5%); }
  70% { transform: translate(6%, 1%); }
  80% { transform: translate(-3%, 6%); }
  90% { transform: translate(4%, -4%); }
}

/* 3) 3D tilt on hover cards (transform driven by JS, like magnetic buttons) */
.tilt-card { will-change: transform; }

/* 4) SVG stroke line-draw on scroll (dash values set by JS) */
.draw-svg path, .draw-svg line, .draw-svg circle, .draw-svg rect {
  transition: stroke-dashoffset .9s cubic-bezier(.4, 0, .2, 1);
}

/* 8) Drifting gradient blobs behind the CTA band + inner-page heros */
.cta-band::before {
  content: ''; position: absolute; inset: -20%;
  background:
    radial-gradient(340px 340px at 22% 30%, rgba(19,180,157,.32), transparent 68%),
    radial-gradient(420px 420px at 78% 72%, rgba(14,148,131,.22), transparent 70%);
  filter: blur(46px);
  animation: blob-drift 16s ease-in-out infinite alternate;
  pointer-events: none;
}
.page-hero { position: relative; overflow: hidden; }
.page-hero .container { position: relative; z-index: 2; }
.page-hero::before {
  content: ''; position: absolute; inset: -20%;
  background:
    radial-gradient(300px 300px at 80% 20%, rgba(19,180,157,.12), transparent 68%),
    radial-gradient(380px 380px at 15% 85%, rgba(19,180,157,.08), transparent 70%);
  filter: blur(40px);
  animation: blob-drift 18s ease-in-out infinite alternate;
  pointer-events: none;
}
@keyframes blob-drift {
  0%   { transform: translate(0, 0) scale(1); }
  50%  { transform: translate(4%, -3%) scale(1.08); }
  100% { transform: translate(-4%, 3%) scale(1.02); }
}

/* Accessibility: honor the visitor's reduced-motion setting for the new
   always-running animations. (JS-driven effects check this in effects.js.) */
@media (prefers-reduced-motion: reduce) {
  .stats-band::after, .cta-band::after,
  .cta-band::before, .page-hero::before { animation: none; }
}

/* Page-entry loading screen (scanning laser line) — plays once per browser
   session on first page view (js/loading-screen.js decides via sessionStorage
   and prefers-reduced-motion, then removes this element from the DOM). Sits
   at the very top of <body> so it covers everything by z-index alone,
   regardless of DOM position.

   Reused as a cross-page transition too: this is a static multi-page site
   (no client-side router), so a real page navigation is a full document
   unload/reload — there's no single animation that can span both documents.
   js/loading-screen.js fakes it in two halves instead: clicking an internal
   link plays the "covering" half on the page you're leaving (fade+sweep to
   fully opaque) before the browser navigates, then the arriving page starts
   already covered (set synchronously, before first paint, via inline script
   right after this markup) and plays the "revealing" half to fade it back
   out. The .on/slFade/slSweep animation below is only for the standalone
   first-visit entrance, which has no "leaving" page to hand off from. */
.sl-overlay { position: fixed; inset: 0; background: #0A0A0A; z-index: 9999; opacity: 0; pointer-events: none; overflow: hidden; }
/* pointer-events is released by the slFade/slRevealFade keyframes themselves
   (see below) rather than only by the static rule here — a JS timer/
   animationend callback is what normally removes the "on"/"revealing" class
   and its pointer-events:auto, but if that callback is ever delayed or never
   fires (main thread busy on a slower machine, a background/unfocused tab
   throttling timers, an unrelated script error earlier in the page), this
   invisible-but-still-"auto" overlay would silently swallow every click
   across the whole page — which reads exactly like the site "not responding"
   to clicks. Baking the release into the animation makes it self-healing:
   pointer-events goes back to none the instant the fade-out visually
   finishes, with or without JS. */
.sl-overlay.on { opacity: 1; pointer-events: auto; animation: slFade 1.6s ease forwards; }
.sl-overlay.on .sl-line { animation: slSweep 1.3s cubic-bezier(.6,0,.25,1) forwards; }
.sl-overlay.on .sl-word { animation: slWordIn .25s ease .55s forwards, slWordOut .25s ease 1.1s forwards; }

.sl-overlay.covering { opacity: 1; pointer-events: auto; animation: slCoverFade .45s ease forwards; }
.sl-overlay.covering .sl-line { animation: slCoverSweep .45s cubic-bezier(.6,0,.25,1) forwards; }
.sl-overlay.covering .sl-word { animation: slWordIn .2s ease .18s forwards; }

.sl-overlay.revealing { opacity: 1; pointer-events: auto; animation: slRevealFade .65s ease forwards; }
.sl-overlay.revealing .sl-line { transform: translateY(50vh); animation: slRevealSweep .65s cubic-bezier(.6,0,.25,1) forwards; }
.sl-overlay.revealing .sl-word { opacity: 1; animation: slWordOut .2s ease .12s forwards; }

/* Static "already covered" state — set synchronously on the arriving page,
   before first paint, so the black overlay is there from frame one instead
   of flashing the new page's content before .revealing takes over. */
.sl-overlay.covered { opacity: 1; pointer-events: auto; }
.sl-overlay.covered .sl-line { transform: translateY(50vh); }
.sl-overlay.covered .sl-word { opacity: 1; }

/* Moves via `transform: translateY()` rather than `top` — `top` is a layout
   property, so animating it forces a full-viewport-width layout+repaint of
   this element's heavily blurred box-shadow on every frame, which is what
   caused the reported stutter/jank during the transition. `transform` is
   compositor-only, so the browser can animate it on the GPU without
   re-running layout each frame. will-change hints the browser to promote
   this to its own layer up front rather than mid-animation. Percentages are
   expressed in vh instead of % because translateY() percentages resolve
   against the element's own (3px-tall) box, not the containing block, so vh
   is needed to preserve the original viewport-relative travel distance. */
.sl-line { position: absolute; left: 0; right: 0; height: 3px; top: 0; transform: translateY(-5vh); background: var(--teal); box-shadow: 0 0 30px 8px rgba(19,180,157,.85); will-change: transform; }
.sl-word { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; color: #fff; font-family: var(--font-display); font-weight: 700; letter-spacing: .14em; font-size: 1.1rem; opacity: 0; }
.sl-word em { font-style: normal; color: var(--teal); }

@keyframes slSweep { to { transform: translateY(105vh); } }
@keyframes slFade { 0% { opacity: 0; pointer-events: auto; } 10% { opacity: 1; } 85% { opacity: 1; } 100% { opacity: 0; pointer-events: none; } }
@keyframes slWordIn { from { opacity: 0; } to { opacity: 1; } }
@keyframes slWordOut { from { opacity: 1; } to { opacity: 0; } }
@keyframes slCoverFade { from { opacity: 0; } to { opacity: 1; } }
@keyframes slCoverSweep { from { transform: translateY(-5vh); } to { transform: translateY(50vh); } }
@keyframes slRevealFade { 0% { opacity: 1; pointer-events: auto; } 65% { opacity: 1; } 100% { opacity: 0; pointer-events: none; } }
@keyframes slRevealSweep { from { transform: translateY(50vh); } to { transform: translateY(105vh); } }

/* Service-card photo carousel — replaces the flat icon badge where real photos exist
   (js/service-photos.js reads data-photos on each card). Collapsed: icon-badge-sized
   thumbnail. On card hover: expands to a wide browsable strip with prev/next arrows.
   Falls back to the plain .icon-badge when a card has no data-photos. */
.svc-photo-box {
  position: relative; width: 56px; height: 56px; border-radius: var(--radius);
  overflow: hidden; margin-bottom: 1rem; background: #1c2022;
  transition: width .35s ease, height .35s ease;
}
.svc-photo-box img { width: 100%; height: 100%; object-fit: cover; display: block; transition: opacity .25s ease; }
.service-card:hover .svc-photo-box { width: 100%; height: 190px; }
.svc-photo-nav {
  position: absolute; top: 50%; transform: translateY(-50%); width: 30px; height: 30px;
  border-radius: 50%; border: none; background: rgba(0,0,0,.55); color: #fff;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  opacity: 0; transition: opacity .2s, background .2s; z-index: 2; padding: 0;
}
.svc-photo-nav:hover { background: var(--teal); }
.service-card:hover .svc-photo-nav { opacity: 1; }
.svc-photo-nav.prev { left: 8px; }
.svc-photo-nav.next { right: 8px; }
.svc-photo-nav svg { width: 15px; height: 15px; }
.svc-photo-count {
  position: absolute; bottom: 8px; right: 10px; background: rgba(0,0,0,.55); color: #fff;
  font-family: var(--font-display); font-size: .64rem; font-weight: 600;
  padding: .15rem .5rem; border-radius: 999px; opacity: 0; transition: opacity .2s; z-index: 2;
}
.service-card:hover .svc-photo-count { opacity: 1; }
.svc-photo-expand {
  position: absolute; top: 8px; right: 8px; width: 28px; height: 28px;
  border-radius: 50%; border: none; background: rgba(0,0,0,.55); color: #fff;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  opacity: 0; transition: opacity .2s, background .2s; z-index: 3; padding: 0;
}
.svc-photo-expand:hover { background: var(--teal); }
.service-card:hover .svc-photo-expand { opacity: 1; }
.svc-photo-expand svg { width: 14px; height: 14px; }

/* Photo lightbox — opened from the expand button above. Sized to the site's own
   container width/height, not the full browser viewport, per explicit feedback:
   "not like full full screen, only the amount of screen the website has." */
.svc-lightbox-overlay {
  position: fixed; inset: 0; z-index: 700;
  background: rgba(0,0,0,.75);
  display: flex; align-items: center; justify-content: center; padding: 2rem;
  opacity: 0; pointer-events: none; transition: opacity .3s;
}
.svc-lightbox-overlay.open { opacity: 1; pointer-events: auto; }
.svc-lightbox {
  position: relative; width: min(1140px, 92%); height: min(80vh, 760px);
  display: flex; align-items: center; justify-content: center;
  background: #101314; border-radius: var(--radius); overflow: hidden;
  transform: scale(.96); transition: transform .3s;
}
.svc-lightbox-overlay.open .svc-lightbox { transform: scale(1); }
.svc-lightbox-img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; }
.svc-lightbox-close {
  position: absolute; top: 14px; right: 14px; width: 38px; height: 38px;
  border-radius: 50%; border: none; background: rgba(255,255,255,.12); color: #fff;
  font-size: 1.6rem; line-height: 1; cursor: pointer; z-index: 2;
  display: flex; align-items: center; justify-content: center;
  transition: background .2s;
}
.svc-lightbox-close:hover { background: var(--teal); }
.svc-lightbox-nav {
  position: absolute; top: 50%; transform: translateY(-50%); width: 46px; height: 46px;
  border-radius: 50%; border: none; background: rgba(255,255,255,.12); color: #fff;
  display: flex; align-items: center; justify-content: center; cursor: pointer;
  transition: background .2s; z-index: 2; padding: 0;
}
.svc-lightbox-nav:hover { background: var(--teal); }
.svc-lightbox-nav.prev { left: 14px; }
.svc-lightbox-nav.next { right: 14px; }
.svc-lightbox-nav svg { width: 22px; height: 22px; }
.svc-lightbox-count {
  position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%);
  background: rgba(0,0,0,.55); color: #fff; font-family: var(--font-display);
  font-size: .78rem; font-weight: 600; padding: .3rem .8rem; border-radius: 999px;
}
@media (max-width: 640px) {
  .svc-lightbox-overlay { padding: 0; }
  .svc-lightbox { width: 100%; height: 100%; border-radius: 0; }
  .svc-lightbox-nav { width: 40px; height: 40px; }
}
