/* Lowered Standards motion layer (FAQ, contact, service area, and service/town pages).
   Effects rebuilt from the VengeanceUI / animate-ui / uiverse references in plain CSS:
   no animation library, transform/opacity only, nothing hidden without JS (the html element
   gets .js-anim from an inline script before paint), all of it off under reduced motion.
   Pointer-only effects (tilt, depth) are wired in ls-motion.js for fine pointers only. */

:root {
  --ls-ease: cubic-bezier(0.16, 1, 0.3, 1);
  --ls-ink: #0f172a;
  --ls-accent: #facc15;
}

/* ---- entrance reveal (same names and timing as pseo_master.html) */
.js-anim .reveal { opacity: 0; transform: translateY(18px);
  transition: opacity .7s var(--ls-ease), transform .7s var(--ls-ease); }
.js-anim .reveal.is-visible { opacity: 1; transform: none; }
.stagger-1 { transition-delay: .05s; }
.stagger-2 { transition-delay: .12s; }
.stagger-3 { transition-delay: .19s; }
.stagger-4 { transition-delay: .26s; }
/* long grids: per-item delay from --i, capped so the last card never waits long */
.js-anim .reveal[style*="--i"] { transition-delay: calc(min(var(--i), 8) * 45ms); }

/* hero copy rises in on load; no opacity change, so the heading paints at once (LCP) */
@keyframes ls-rise { from { transform: translateY(14px); } to { transform: none; } }
.js-anim .ls-rise { animation: ls-rise .7s var(--ls-ease) both; }
.js-anim .ls-rise-2 { animation: ls-rise .7s var(--ls-ease) .1s both; }

/* ---- hero parallax: a faint yellow dot grid that drifts as the page scrolls */
.ls-hero { position: relative; overflow: hidden; isolation: isolate; }
.ls-hero::before { content: ''; position: absolute; inset: -30% -5% 0; z-index: -1; pointer-events: none;
  background: radial-gradient(rgba(250, 204, 21, .22) 1px, transparent 1.6px) 0 0 / 28px 28px;
  -webkit-mask-image: radial-gradient(ellipse 70% 60% at 50% 40%, #000 20%, transparent 75%);
          mask-image: radial-gradient(ellipse 70% 60% at 50% 40%, #000 20%, transparent 75%); }
@supports (animation-timeline: scroll()) {
  @keyframes ls-drift { to { transform: translateY(90px); } }
  .ls-hero::before { animation: ls-drift linear both; animation-timeline: scroll(root); animation-range: 0 700px; }
}

/* ---- 3D tilt card: ls-motion.js sets --rx/--ry/--gx/--gy from the pointer */
.tilt { position: relative; transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg));
  transition: transform .6s var(--ls-ease), box-shadow .3s ease; }
.tilt.is-tilting { transition: transform .12s linear, box-shadow .3s ease;
  box-shadow: 0 18px 40px -22px rgba(15, 23, 42, .35); }
.tilt::after { content: ''; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0;
  background: radial-gradient(420px circle at var(--gx, 50%) var(--gy, 50%), rgba(250, 204, 21, .14), transparent 45%);
  transition: opacity .3s ease; }
.tilt.is-tilting::after { opacity: 1; }
/* a card that is both .reveal and .tilt: once revealed, the tilt owns the transform (the reveal
   rule is more specific and would otherwise pin it flat), with no stagger delay on the pointer */
.js-anim .reveal.is-visible.tilt { transform: perspective(900px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg)); }
.js-anim .reveal.is-visible.tilt.is-tilting { transition: transform .12s linear, box-shadow .3s ease; transition-delay: 0s; }

/* pointer depth: a hero image drifts a few px against the cursor ("translate" composes with
   any running transform animation on the same element) */
[data-depth] { transition: translate .5s var(--ls-ease); }

/* ---- hover + micro-interactions */
.lift { transition: transform .25s var(--ls-ease), border-color .2s ease, box-shadow .25s ease; }
.lift:hover { transform: translateY(-3px); border-color: var(--ls-ink); box-shadow: 0 14px 30px -20px rgba(15, 23, 42, .35); }
.press { transition: transform .15s var(--ls-ease), background-color .2s ease, border-color .2s ease, color .2s ease; }
.press:active { transform: scale(.97); }
.link-draw { text-decoration: none; background: linear-gradient(var(--ls-accent), var(--ls-accent)) 0 100% / 0 2px no-repeat;
  transition: background-size .3s var(--ls-ease), color .2s ease; padding-bottom: 1px; }
.link-draw:hover, .link-draw:focus-visible { background-size: 100% 2px; }
.nudge svg { transition: transform .25s var(--ls-ease); }
.nudge:hover svg { transform: translateX(3px); }
:where(a, button, summary):focus-visible { outline: 2px solid var(--ls-accent); outline-offset: 3px; border-radius: 6px; }

/* copy-to-clipboard button (contact page) */
.copy-btn { display: inline-flex; align-items: center; justify-content: center; gap: .4rem; min-height: 44px; padding: 0 .9rem;
  border-radius: .75rem; border: 1px solid #cbd5e1; background: #fff; color: var(--ls-ink); font-size: .875rem; font-weight: 700; cursor: pointer; }
.copy-btn:hover { border-color: var(--ls-ink); }
.copy-btn svg { width: 1rem; height: 1rem; }
.copy-btn .copy-btn__idle { display: inline-flex; align-items: center; gap: .4rem; }
.copy-btn .copy-btn__done { display: none; }
.copy-btn.is-done .copy-btn__idle { display: none; }
.copy-btn.is-done .copy-btn__done { display: inline-flex; align-items: center; gap: .4rem; animation: ls-pop .35s var(--ls-ease); }
@keyframes ls-pop { from { transform: scale(.85); opacity: 0; } to { transform: none; opacity: 1; } }

/* FAQ accordion (faq.html, [data-ls-accordion]): grid-rows height animation; without JS every
   answer simply stays open */
.js-anim [data-ls-accordion] .faq-answer { display: grid; grid-template-rows: 0fr; padding-bottom: 0;
  transition: grid-template-rows .35s var(--ls-ease); }
.js-anim [data-ls-accordion] .faq-answer > .faq-inner { overflow: hidden; min-height: 0; }
.js-anim [data-ls-accordion] .faq-answer > .faq-inner > div { padding-bottom: 1rem; }
.js-anim [data-ls-accordion] .faq-item[aria-expanded="true"] .faq-answer { grid-template-rows: 1fr; }
[data-ls-accordion] .faq-item { transition: border-color .2s ease, background-color .2s ease; }
[data-ls-accordion] .faq-item[aria-expanded="true"] { border-color: var(--ls-ink); background: #fff; }
.faq-item[aria-expanded="false"] .faq-icon-minus, .faq-item[aria-expanded="true"] .faq-icon-plus { display: none; }
[data-ls-accordion] .faq-item[aria-expanded="true"] .faq-icon-minus { animation: ls-turn .3s var(--ls-ease); }
@keyframes ls-turn { from { transform: rotate(-90deg); } to { transform: none; } }

/* ---- smooth loading: top progress bar on internal navigation, map skeleton, page fade */
.ls-progress { position: fixed; inset: 0 0 auto 0; height: 3px; z-index: 100; pointer-events: none;
  background: var(--ls-accent); transform-origin: 0 50%; transform: scaleX(0); opacity: 0; }
.ls-progress.is-loading { opacity: 1; transform: scaleX(.85); transition: transform 6s cubic-bezier(.1, .7, .2, 1), opacity .2s ease; }
.map-skel { position: relative; }
.js-anim .map-skel:not(.is-loaded) { background: linear-gradient(100deg, #f1f5f9 30%, #e2e8f0 50%, #f1f5f9 70%) 0 0 / 200% 100%;
  animation: ls-skel 1.4s linear infinite; }
.js-anim .map-skel iframe { opacity: 0; transition: opacity .5s ease; }
.js-anim .map-skel.is-loaded iframe { opacity: 1; }
@keyframes ls-skel { to { background-position: -200% 0; } }
/* No cross-document @view-transition: tested 2026-10, it made Chrome paint the incoming page
   before its stylesheets applied, a full-viewport layout shift (CLS 1.0) on navigation. */

/* ---- reduced motion: everything static and fully visible */
@media (prefers-reduced-motion: reduce) {
  .js-anim .reveal { opacity: 1 !important; transform: none !important; transition: none !important; }
  .js-anim .ls-rise, .js-anim .ls-rise-2, .ls-hero::before, .js-anim .map-skel:not(.is-loaded),
  [data-ls-accordion] .faq-item[aria-expanded="true"] .faq-icon-minus, .copy-btn.is-done .copy-btn__done { animation: none !important; }
  .tilt, [data-depth], .lift, .press, .link-draw, .nudge svg, .js-anim [data-ls-accordion] .faq-answer,
  .js-anim .map-skel iframe, .ls-progress { transition: none !important; }
  .tilt { transform: none !important; }
  .lift:hover { transform: none; }
  .ls-progress { display: none; }
}
