/* ============================================================
   ParkZilla marketing landing page (index.php only).
   Loaded via pz_head($title, ['/assets/css/landing.css']) so no
   other surface pays for this file's weight.
   ============================================================ */

:root {
  /* Motion (Emil Kowalski's tested curves, not invented ones) */
  --pz-ease-out: cubic-bezier(0.23, 1, 0.32, 1);       /* entrances/exits */
  --pz-ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);   /* on-screen movement */

  /* Fluid type scale — guide's pt values treated as ~px (see plan notes),
     pushed bolder/bigger per Moses's Apple/Landon-Norris reference */
  --pz-fs-headline: clamp(3rem, 7vw + 1rem, 7rem);        /* 48px -> 112px */
  --pz-fs-heading:  clamp(2.5rem, 5vw + 1rem, 5.5rem);    /* 40px -> 88px */
  --pz-fs-subhead:  clamp(1.375rem, 2vw + 1rem, 2.25rem); /* 22px -> 36px */
  --pz-fs-body:     clamp(1rem, .3vw + .9rem, 1.125rem);  /* 16px -> 18px */
}

.mk-container { max-width: 1180px; margin: 0 auto; padding: 0 6vw; }

/* ---------- One-shot text/button reveal (Apple product-page style: a
   short blur+rise that plays once as an element enters view, staggered
   per element via --d). This is a DIFFERENT mechanism from the
   continuous scroll-scrubbed .mk-beat below — headlines and buttons get
   a fixed-duration entrance (IntersectionObserver-triggered, once),
   while the story's stage visuals stay tied continuously to scroll
   position. Scoped under html.js so a no-JS visitor never has content
   hidden behind a class-triggered transition that never fires. */
html.js .mk-reveal {
  opacity: 0; filter: blur(14px); transform: translateY(28px);
  transition: opacity 700ms var(--pz-ease-out), filter 700ms var(--pz-ease-out), transform 700ms var(--pz-ease-out);
  transition-delay: var(--d, 0ms);
}
html.js .mk-reveal.in-view { opacity: 1; filter: blur(0); transform: translateY(0); }
@media (prefers-reduced-motion: reduce) {
  html.js .mk-reveal { opacity: 1 !important; filter: none !important; transform: none !important; transition: none !important; }
}

/* ---------- Nav ---------- */
.mk-nav {
  display: flex; align-items: center; gap: 22px; padding: 18px 6vw;
  background: transparent; position: fixed; top: 0; left: 0; right: 0; z-index: 50;
  transition: background 200ms var(--pz-ease-out), border-color 200ms var(--pz-ease-out);
  border-bottom: 1px solid transparent;
}
.mk-nav .brand { color: #fff; font-weight: 800; font-size: 20px; display: flex; gap: 8px; align-items: center; transition: color 200ms var(--pz-ease-out); }
.mk-nav .links { margin-left: auto; display: flex; gap: 20px; align-items: center; }
.mk-nav .links a:not(.pz-btn) { color: #d9e5f7; font-size: 14px; font-weight: 600; transition: color 200ms var(--pz-ease-out); }
.mk-nav.scrolled {
  background: rgba(255, 255, 255, .6);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid rgba(19, 30, 70, .08);
}
.mk-nav.scrolled .brand { color: var(--pz-navy); }
/* On scroll the plain text links go brand blue; :not(.pz-btn) leaves the
   CTA button alone so it keeps its blue fill + white label (the link rule
   was previously greying the button's text and making it unreadable). */
.mk-nav.scrolled .links a:not(.pz-btn) { color: var(--pz-blue-deep); }

/* Below ~640px the brand + two text links + CTA button no longer fit on
   one line (TODO.md has flagged this nav-overflow issue since before this
   rebuild). Drop the plain-text links — both destinations are also one
   tap away from the hero and footer — and keep brand + the single CTA. */
@media (max-width: 640px) {
  .mk-nav .links a:not(.pz-btn) { display: none; }
}

/* ---------- Hero ---------- */
.mk-hero {
  background:
    linear-gradient(160deg, rgba(19,30,70,.92) 0%, rgba(18,60,122,.88) 55%, rgba(33,102,204,.85) 100%),
    url('../img/landing/hero-bg.png') center/cover;
  color: #fff; padding: clamp(120px, 22vw, 170px) 6vw 90px; position: relative; overflow: hidden;
}
.mk-hero .eyebrow { font-size: 13px; font-weight: 700; letter-spacing: .04em; text-transform: uppercase; color: var(--pz-teal); margin-bottom: 10px; }
.mk-hero h1 { font-size: var(--pz-fs-headline); max-width: 14ch; line-height: 1.05; letter-spacing: -0.02em; text-wrap: balance; }
.mk-hero p.lead { font-size: var(--pz-fs-body); color: #c9d8ef; max-width: 520px; margin-bottom: 28px; }
.mk-hero .hero-ctas { display: flex; gap: 12px; flex-wrap: wrap; margin-top: 8px; }
.mk-stats { display: flex; gap: 40px; margin-top: 48px; flex-wrap: wrap; }
.mk-stats .num { font-size: 30px; font-weight: 800; font-family: var(--pz-font-heading); font-variant-numeric: tabular-nums; }
.mk-stats .lbl { font-size: 13px; color: #a9bedd; }

/* ---------- Generic section rhythm ---------- */
.mk-section { padding: clamp(80px, 12vw, 160px) 6vw; }
.mk-section h2 { font-size: var(--pz-fs-heading); margin-bottom: 24px; letter-spacing: -0.01em; text-wrap: balance; }
.mk-section.tint { background: #f4fbfb; }

/* ============================================================
   The 3-act scroll-driven story — full-bleed photography per act
   (Landon-Norris/Apple style: real photo fills the screen, copy floats
   in a glass panel over it) instead of a boxed-in illustration.
   ============================================================ */
.mk-story { position: relative; background: #131e46; }
.mk-act { position: relative; height: 260vh; }
.mk-act-pin { position: sticky; top: 0; height: 100vh; overflow: hidden; }
/* The containing block for the route overlay + glass cards below — they
   must be nested INSIDE .mk-act-photo in the markup (not siblings of it),
   so their position:absolute anchors to the photo's own box. On desktop
   that box fills the pin (inset:0); on mobile it's a normal-flow box with
   an explicit height (see the media query) — either way, cards land on
   the photo, not on some taller ancestor. */
.mk-act-photo {
  position: absolute; inset: 0; background-size: cover; background-position: center;
}

.mk-act-copy-panel {
  /* max-width capped under half the viewport so it never crosses the
     midline into the phone / comparison rows on the opposite side. */
  position: absolute; top: 50%; left: 6vw; transform: translateY(-50%);
  max-width: min(44vw, 560px); padding: clamp(28px, 4vw, 44px); border-radius: 22px;
  background: rgba(19,30,70,.4); backdrop-filter: blur(20px) saturate(160%); -webkit-backdrop-filter: blur(20px) saturate(160%);
  border: 1px solid rgba(255,255,255,.14); color: #fff;
}
.mk-act-copy-panel h2 { font-size: var(--pz-fs-heading); margin-bottom: 14px; text-wrap: balance; color: #fff; }
.mk-act-copy-panel p { font-size: var(--pz-fs-body); color: #dce6f5; max-width: 38ch; }

/* Act 2 floats its copy panel on the right instead of the left, so the
   eye doesn't track the same composition three times in a row. */
#act-event .mk-act-copy-panel { left: auto; right: 6vw; }

/* ---------- Phone frame carrying the real app UI (Acts 1 & 3) ----------
   Borrows the bezel/notch look of the app's own .pz-phone but is
   self-contained and sized for the story stage, and reuses the app's
   real component classes inside (.pz-btn, .pz-badge, .pz-map-fallback,
   .pz-row) so the mock genuinely matches the product rather than being
   invented fake UI. Sits opposite the copy panel. */
.mk-phone {
  position: absolute; top: 50%; right: 7vw; transform: translateY(-50%);
  width: clamp(258px, 25vw, 320px); aspect-ratio: 320 / 652;
  background: #0b1220; border-radius: 42px; padding: 13px;
  box-shadow: 0 34px 90px rgba(0,0,0,.5); border: 1px solid rgba(255,255,255,.1); z-index: 2;
}
.mk-phone::before { /* notch */
  content: ""; position: absolute; top: 21px; left: 50%; transform: translateX(-50%);
  width: 92px; height: 20px; background: #0b1220; border-radius: 999px; z-index: 3;
}
.mk-phone-screen {
  position: relative; width: 100%; height: 100%; overflow: hidden;
  background: var(--pz-bg); border-radius: 30px; display: flex; flex-direction: column;
}
.mk-ui-head {
  display: flex; align-items: center; gap: 8px; padding: 34px 16px 12px;
  font-family: var(--pz-font-heading); font-weight: 800; font-size: 14px; color: var(--pz-navy);
  background: #fff; border-bottom: 1px solid var(--pz-line);
}
.mk-ui-head img { height: 20px; }
.mk-ui-body { flex: 1; padding: 14px; display: flex; flex-direction: column; gap: 11px; position: relative; }
.mk-ui-card { background: #fff; border: 1px solid var(--pz-line); border-radius: 14px; padding: 11px 13px; box-shadow: var(--pz-shadow); }
.mk-ui-thumb { width: 100%; height: 92px; border-radius: 10px; background-size: cover; background-position: center; margin-bottom: 8px; }
.mk-ui-label { font-size: 10.5px; color: var(--pz-ink-soft); font-weight: 600; text-transform: uppercase; letter-spacing: .04em; }
.mk-ui-value { font-size: 15px; font-weight: 700; color: var(--pz-navy); font-family: var(--pz-font-heading); }
.mk-ui-value.price { color: var(--pz-teal); }
.mk-ui-success { display: flex; align-items: center; gap: 8px; background: #e5f8ec; color: #14713c; border-radius: 12px; padding: 11px 13px; font-weight: 700; font-size: 13px; }
.mk-ui-body .pz-btn { width: 100%; }
/* In-phone map (Act 3). The map-bg.png is a flat neutral street grid; the
   ::after layer tints it toward the brand (cool teal→blue wash) and adds a
   soft vignette so it reads as a designed map surface rather than raw gray,
   and unifies with the rest of the phone/brand palette. */
.mk-ui-map {
  position: absolute; inset: 0;
  background: url('../img/landing/map-bg.png') center 32% / cover, var(--pz-bg);
}
.mk-ui-map::after {
  content: ""; position: absolute; inset: 0;
  background:
    radial-gradient(135% 90% at 50% 38%, transparent 42%, rgba(19,30,70,.24)),
    linear-gradient(180deg, rgba(81,196,216,.14), rgba(33,102,204,.10));
}
/* Pin + location halo. Wrapped in .mk-ui-loc so the .mk-beat entrance
   (which drives `transform`) can't fight the centering: the wrapper is
   centered via the standalone `translate` property, which composes with
   the beat's `transform` instead of overriding it. The halo is the
   wrapper's own radial background — the translucent accuracy circle real
   map apps show around your position. */
.mk-ui-loc {
  position: absolute; top: 38%; left: 50%; translate: -50% -50%; z-index: 2;
  width: 82px; height: 82px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle, rgba(81,196,216,.42), rgba(81,196,216,0) 70%);
}
/* The pin IS the ParkZilla logo mark (a map pin by design) — the actual
   brand asset, not a stand-in shape. translate lifts it so its point sits
   at the halo center (the located spot). */
.mk-ui-pin { width: 36px; height: auto; translate: 0 -18px; filter: drop-shadow(0 6px 8px rgba(19,30,70,.45)); }
.mk-ui-sheet {
  position: absolute; left: 10px; right: 10px; bottom: 10px; z-index: 4;
  background: #fff; border-radius: 16px; padding: 13px 14px; box-shadow: var(--pz-shadow-lg);
}
.mk-ui-sheet .name { font-family: var(--pz-font-heading); font-weight: 700; font-size: 14.5px; color: var(--pz-navy); }
.mk-ui-sheet .meta { font-size: 12px; color: var(--pz-ink-soft); margin: 3px 0 10px; }

/* ---------- Act 2 comparison rows (floating over the photo, no phone) ---------- */
.mk-compare { position: absolute; top: 50%; left: 6vw; transform: translateY(-50%); width: min(430px, 42vw); display: flex; flex-direction: column; gap: 18px; z-index: 2; }
.mk-compare-row {
  display: flex; align-items: center; gap: 14px; position: relative;
  background: rgba(255,255,255,.86); backdrop-filter: blur(18px) saturate(160%); -webkit-backdrop-filter: blur(18px) saturate(160%);
  border: 1px solid rgba(255,255,255,.6); border-radius: 18px; padding: 18px 20px; box-shadow: 0 12px 38px rgba(19,30,70,.34);
  transition: opacity 400ms var(--pz-ease-out);
}
.mk-compare-row .lot { flex: 1; min-width: 0; }
.mk-compare-row .lot .name { font-family: var(--pz-font-heading); font-weight: 700; font-size: 16px; color: var(--pz-navy); }
.mk-compare-row .lot .meta { font-size: 12.5px; color: var(--pz-ink-soft); margin-top: 2px; }
.mk-compare-row .price { position: relative; font-family: var(--pz-font-heading); font-weight: 700; font-size: clamp(1.5rem, 2.6vw, 2.25rem); color: var(--pz-navy); line-height: 1; }
.mk-compare-row .price.host { color: var(--pz-teal); }
.mk-compare-row .mark { position: absolute; top: -10px; right: -10px; width: 34px; height: 34px; }
/* The rejected (stadium) row: --e3 (0→1 over --rfrom..--rto, the same
   window the corner X draws over) both dims the row and grows a red
   strike line across the price left-to-right, so the strike, the X, and
   the dim all happen together on scroll. Row opacity multiplies the beat
   entrance (--e) by the reject dim so it still fades in on arrival. */
.mk-compare-row.reject {
  --e3: clamp(0, calc((var(--p) - var(--rfrom, .5)) / (var(--rto, .7) - var(--rfrom, .5))), 1);
  opacity: calc(var(--e, 1) * (1 - var(--e3) * 0.4));
}
.mk-compare-row.reject .price::after {
  content: ""; position: absolute; left: -3px; right: -3px; top: 50%; height: 3px;
  background: var(--pz-red); border-radius: 2px;
  translate: 0 -50%; scale: var(--e3, 0) 1; transform-origin: left center;
}

/* Scroll-scrubbed reveal utility for the STAGE (photo/glass-card/pin
   elements) — continuous, tied to scroll position via --p, distinct from
   the one-shot .mk-reveal used for headline/button text. --from/--to are
   set per element via an inline style attribute (unitless progress 0-1);
   --p is set on .mk-act-pin every frame by landing.js. When --p is never
   set (JS failed, or the mobile/reduced-motion media query below wins),
   the calc() is invalid at computed-value time and opacity/transform/
   filter fall back to their initial values — content is visible by
   default, motion only enhances it. */
.mk-beat {
  --e: clamp(0, calc((var(--p) - var(--from, 0)) / (var(--to, 1) - var(--from, 0))), 1);
  opacity: var(--e);
  transform: translateY(calc((1 - var(--e)) * var(--rise, 22px)));
  filter: blur(calc((1 - var(--e)) * 6px));
}
.mk-beat.scale {
  transform: translateY(calc((1 - var(--e)) * var(--rise, 12px))) scale(calc(0.92 + var(--e) * 0.08));
}
.mk-checkmark, .mk-draw {
  --e: clamp(0, calc((var(--p) - var(--from, 0)) / (var(--to, 1) - var(--from, 0))), 1);
  stroke-dasharray: 1; stroke-dashoffset: calc(1 - var(--e));
}

/* Act titles are plain copy — no "01/02/03" numbering, no eyebrow labels
   above every act (see plan Part 6): the pinned sequence already makes
   the order obvious. */

/* ---------- Mobile layout: collapse the pinned full-bleed stage ----------
   Desktop floats the phone / comparison rows absolutely inside the photo
   box (which fills the sticky pin). On mobile there's no pin to fill, so
   the photo becomes a normal-flow rounded banner that grows to fit its
   contents (the phone/rows sit centered on top of it via flex), and the
   copy stacks below. Layout only — motion is handled in the two blocks
   below. Scoped to width alone (not reduced-motion) so a desktop user
   with reduced-motion keeps the desktop layout, just without scrubbing. */
@media (max-width: 767px) {
  .mk-act { height: auto; }
  .mk-act-pin { position: static; height: auto; padding: 40px 0; }
  .mk-act-photo {
    position: relative; inset: auto; height: auto; min-height: 40vh;
    border-radius: 18px; margin: 0 6vw; width: calc(100% - 12vw);
    padding: 26px 0; display: flex; flex-direction: column; align-items: center; gap: 20px;
  }
  .mk-phone { position: static; transform: none; width: min(300px, 76vw); }
  .mk-compare { position: static; transform: none; width: 100%; padding: 0 16px; }
  .mk-act-copy-panel {
    /* .mk-story's background stays navy on mobile too (no seam between
       acts) so this keeps its light-on-dark text, it just drops the
       glass/blur/border treatment since it's no longer floating over a
       photo — it's normal-flow content on the navy section background. */
    position: static; transform: none; max-width: none; margin: 22px 6vw 0;
    background: none; backdrop-filter: none; -webkit-backdrop-filter: none; border: 0; padding: 0;
  }
  #act-event .mk-act-copy-panel { left: auto; right: auto; margin: 22px 6vw 0; }
}

/* ---------- Mobile motion: one-shot reveal on scroll ----------
   Pinning/scroll-jacking feels janky on phones, so instead of the desktop
   --p scrub, each story beat does a single fade+rise as it scrolls into
   view — landing.js adds .in-view via IntersectionObserver (same idea as
   the headline .mk-reveal). transition-delay keyed off each beat's own
   --from preserves the 1-2-3 sequence even when a group enters together.
   The checkmarks/X draw and the Act 2 strike grow on entry too. Gated to
   no-preference so reduced-motion phones fall through to the static block. */
@media (max-width: 767px) and (prefers-reduced-motion: no-preference) {
  /* Durations run ~30% longer than desktop so the reveals feel smoother
     under a finger-scroll; the stagger delay is keyed off each beat's own
     --from so the 1-2-3 order holds. */
  #story .mk-beat {
    opacity: 0; transform: translateY(20px); filter: none;
    transition: opacity .8s var(--pz-ease-out), transform .8s var(--pz-ease-out);
    transition-delay: calc(var(--from, 0) * 460ms);
  }
  #story .mk-beat.in-view { opacity: 1; transform: none; }
  #story .mk-checkmark, #story .mk-draw {
    stroke-dashoffset: 1;
    transition: stroke-dashoffset .72s var(--pz-ease-out);
    transition-delay: calc(var(--from, 0) * 460ms);
  }
  #story .in-view .mk-checkmark, #story .in-view .mk-draw { stroke-dashoffset: 0; }
  .mk-compare-row.reject .price::after {
    scale: 0 1; transition: scale .65s var(--pz-ease-out); transition-delay: .4s;
  }
  .mk-compare-row.reject.in-view .price::after { scale: 1 1; }
}

/* ---------- Reduced motion (any width): everything visible, nothing moves ---------- */
@media (prefers-reduced-motion: reduce) {
  .mk-nav { transition: none; }
  .mk-beat, .mk-beat.scale, .mk-checkmark, .mk-draw {
    opacity: 1 !important; transform: none !important; filter: none !important; stroke-dashoffset: 0 !important;
  }
  .mk-compare-row.reject .price::after { scale: 1 1 !important; }
}

/* ============================================================
   Secondary audience strip (Cities + Events) — deliberately NOT a
   third/fourth equal card matching Host/Seeker; a light inline strip
   so the story + dual CTA stay the page's visual center of gravity.
   ============================================================ */
.mk-audience-strip {
  display: flex; gap: 6vw; flex-wrap: wrap; padding-top: 28px; margin-top: 28px;
  border-top: 1px solid var(--pz-line);
}
.mk-audience-strip .item { flex: 1 1 260px; }
.mk-audience-strip .item h3 { font-size: 17px; margin-bottom: 6px; font-family: var(--pz-font-heading); }
.mk-audience-strip .item p { font-size: 14px; color: var(--pz-ink-soft); margin: 0 0 8px; max-width: 40ch; }
.mk-audience-strip .item a { font-size: 14px; font-weight: 600; }

/* ---------- Closing dual CTA ---------- */
.mk-cta { display: grid; grid-template-columns: 1fr 1fr; }
.mk-cta .panel {
  padding: clamp(56px, 10vw, 96px) 6vw; color: #fff; position: relative;
  min-height: 340px; display: flex; flex-direction: column; justify-content: flex-end;
}
.mk-cta .panel h3 { font-size: var(--pz-fs-heading); margin-bottom: 10px; }
.mk-cta .panel p { font-size: var(--pz-fs-body); color: #dce6f5; max-width: 34ch; margin-bottom: 22px; }
.mk-cta .panel.host {
  background: linear-gradient(160deg, rgba(19,30,70,.86), rgba(33,102,204,.72)), url('../img/landing/audience-host.png') center/cover; /* placeholder — valet photo doesn't quite match the product, revisit per TODO.md */
}
.mk-cta .panel.seeker {
  background: linear-gradient(160deg, rgba(19,30,70,.86), rgba(81,196,216,.55)), url('../img/landing/audience-seeker.png') center/cover;
}
@media (max-width: 767px) {
  .mk-cta { grid-template-columns: 1fr; }
}

/* ---------- Footer ---------- */
.mk-foot {
  background: linear-gradient(160deg, rgba(19,30,70,.94), rgba(19,30,70,.88)), url('../img/landing/footer-texture.png') center/cover;
  color: #a9bedd; padding: 30px 6vw; font-size: 13px; display: flex; gap: 20px; flex-wrap: wrap;
}
.mk-foot a { color: #d9e5f7; }
