/* ============================================================
   Mandorly — mandorly.id marketing site
   Design tokens derived from the actual product's brand system
   (app/globals.css), not invented fresh for this site: terracotta
   is the real logo color, cream/concrete is the real app background.
   A marketing site for a product should look like it belongs to
   that product, not like a different agency designed it.
   ============================================================ */

:root {
  /* ---- Brand (exact) vs UI-safe tint, same split the app itself
     uses: brand color for large graphic/decorative use, the darker
     tint anywhere text needs to sit on it and clear contrast. ---- */
  --brand: #d06438;
  --terracotta: #ae4e29;
  --terracotta-deep: #6e3419;
  --sage: #536d46;
  --sage-deep: #3c4f33;
  --amber: #d97706;
  --charcoal: #252421;
  --charcoal-70: rgba(37, 36, 33, 0.7);
  --charcoal-50: rgba(37, 36, 33, 0.5);
  --charcoal-30: rgba(37, 36, 33, 0.3);
  --charcoal-12: rgba(37, 36, 33, 0.12);
  --cream: #f5f3ef;
  --cream-deep: #ece7de;
  --paper: #ffffff;
  --line: #e4ddd0;

  --font-display: "Geist", "Inter", system-ui, sans-serif;
  --font-body: "Inter", system-ui, sans-serif;
  --font-mono: "IBM Plex Mono", "SFMono-Regular", ui-monospace, monospace;

  --container: 1120px;
  --radius: 20px;
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; overflow-x: hidden; }
/* overflow-x lives on <html> only, not <body>: setting it on body too
   forces body's own overflow-y to auto-compute (CSS overflow spec),
   which turns <body> into its own scroll container and breaks
   `position: sticky` for .nav (a direct child of body) — it then
   sticks relative to body's scrollport instead of the real viewport. */
body { max-width: 100%; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--charcoal);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.08;
  margin: 0;
  color: var(--charcoal);
}

p { margin: 0; }

.wrap {
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 28px;
}

.eyebrow {
  font-family: var(--font-mono);
  font-size: 12.5px;
  font-weight: 500;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--terracotta-deep);
  display: inline-flex;
  align-items: center;
  gap: 10px;
}
.eyebrow::before {
  content: "";
  width: 18px;
  height: 1px;
  background: var(--terracotta);
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 15px;
  padding: 14px 26px;
  border-radius: 100px;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease, background 0.15s ease;
  white-space: nowrap;
}
.btn-primary {
  background: var(--terracotta);
  color: var(--paper);
  box-shadow: 0 1px 0 rgba(0,0,0,0.05), 0 10px 24px -12px rgba(174,78,41,0.55);
}
.btn-primary:hover { transform: translateY(-1px); box-shadow: 0 14px 28px -12px rgba(174,78,41,0.6); }
.btn-ghost {
  background: transparent;
  color: var(--charcoal);
  border-color: var(--charcoal-12);
}
.btn-ghost:hover { border-color: var(--terracotta); color: var(--terracotta-deep); }
.btn-block { width: 100%; }

/* ---------- Nav ---------- */
.nav {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(245, 243, 239, 0.86);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--line);
}
.nav-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 0;
  min-height: 64px;
}
.brand {
  display: flex;
  align-items: center;
  gap: 9px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 19px;
  color: var(--charcoal);
}
.brand-mark { flex-shrink: 0; transition: transform 0.35s ease; }
.brand-mark rect { fill: var(--terracotta); }
.brand:hover .brand-mark { transform: rotate(-8deg) scale(1.08); }

.nav-links {
  display: flex;
  align-items: center;
  gap: 26px;
  font-size: 14px;
  font-weight: 500;
  color: var(--charcoal-70);
}
.nav-links a { position: relative; padding-bottom: 4px; white-space: nowrap; transition: color 0.15s ease; }
.nav-links a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;
  bottom: 0;
  height: 1.5px;
  background: var(--terracotta);
  transition: right 0.25s ease;
}
.nav-links a:hover { color: var(--terracotta-deep); }
.nav-links a:hover::after { right: 0; }
.nav-cta { display: flex; align-items: center; gap: 14px; }

/* ---------- Mobile menu ---------- */
.nav-toggle {
  display: none;
  width: 48px;
  height: 48px;
  align-items: center;
  justify-content: center;
  background: var(--paper);
  border: 1.5px solid var(--charcoal-12);
  border-radius: 12px;
  cursor: pointer;
  flex-shrink: 0;
  color: var(--charcoal);
  box-shadow: 0 2px 6px -2px rgba(37, 36, 33, 0.12);
  transition: transform 0.15s ease, background 0.15s ease, border-color 0.15s ease, color 0.15s ease, box-shadow 0.15s ease;
}
.nav-toggle:hover { border-color: var(--terracotta); box-shadow: 0 4px 12px -4px rgba(174, 78, 41, 0.25); }
.nav-toggle:active { transform: scale(0.9); }
.nav-toggle.is-open { background: var(--terracotta); border-color: var(--terracotta); color: #fff; }
.nav-toggle svg { display: block; }
.nav-toggle .icon-close { display: none; }
.nav-toggle.is-open .icon-menu { display: none; }
.nav-toggle.is-open .icon-close { display: block; }

.mobile-menu {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 0;
  opacity: 0;
  overflow: hidden;
  padding: 0;
  border-top: 0 solid var(--line);
  transition: max-height 0.4s ease, opacity 0.3s ease, padding 0.4s ease, border-top-width 0.4s ease;
}
.mobile-menu a {
  padding: 13px 4px;
  font-size: 15.5px;
  font-weight: 500;
  color: var(--charcoal);
  border-bottom: 1px solid var(--line);
  opacity: 0;
  transform: translateY(-6px);
  transition: color 0.15s ease, padding-left 0.15s ease, opacity 0.3s ease, transform 0.3s ease;
}
.mobile-menu a:active { color: var(--terracotta-deep); padding-left: 8px; }
.mobile-menu .mobile-cta {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding-top: 16px;
  opacity: 0;
  transform: translateY(-6px);
  transition: opacity 0.3s ease 0.3s, transform 0.3s ease 0.3s;
}
.mobile-menu.is-open {
  max-height: 640px;
  opacity: 1;
  padding: 8px 0 20px;
  border-top-width: 1px;
}
.mobile-menu.is-open a { opacity: 1; transform: translateY(0); }
.mobile-menu.is-open a:nth-child(1) { transition-delay: 0.05s; }
.mobile-menu.is-open a:nth-child(2) { transition-delay: 0.1s; }
.mobile-menu.is-open a:nth-child(3) { transition-delay: 0.15s; }
.mobile-menu.is-open a:nth-child(4) { transition-delay: 0.2s; }
.mobile-menu.is-open a:nth-child(5) { transition-delay: 0.25s; }
.mobile-menu.is-open a:nth-child(6) { transition-delay: 0.3s; }
.mobile-menu.is-open a:nth-child(7) { transition-delay: 0.35s; }
.mobile-menu.is-open .mobile-cta { opacity: 1; transform: translateY(0); }

@media (max-width: 860px) {
  .nav-links { display: none; }
  .nav-cta { display: none; }
  .nav-toggle { display: flex; }
  .nav-inner { padding: 20px 0; min-height: 68px; }
}

@media (max-width: 480px) {
  .brand { font-size: 20px; }
  .brand-mark { width: 30px; height: 30px; }
}

/* ---------- Footer ----------
   Deliberately dark (charcoal), not the body's cream — a footer that
   matches the body background reads as an unstyled afterthought and
   gives the page no visual "floor". Dark also lets the terracotta
   brand mark and links pop instead of blending in. */
.footer {
  border-top: 1px solid var(--charcoal);
  padding: 64px 0 32px;
  margin-top: 120px;
  background: var(--charcoal);
  color: rgba(245, 243, 239, 0.7);
}
.footer .brand { color: var(--cream); }
.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1fr;
  gap: 40px;
  padding-bottom: 48px;
}
.footer-brand p {
  color: rgba(245, 243, 239, 0.55);
  font-size: 14.5px;
  margin-top: 14px;
  max-width: 280px;
}
.footer-legal-info {
  margin-top: 18px;
  padding-top: 18px;
  border-top: 1px solid rgba(245, 243, 239, 0.12);
}
.footer-brand .footer-legal-info p {
  font-size: 12.5px;
  color: rgba(245, 243, 239, 0.4);
  line-height: 1.6;
  margin-top: 0;
  margin-bottom: 6px;
  max-width: 320px;
}
.footer-brand .footer-legal-info p:last-child { margin-bottom: 0; }
.footer-col h4 {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: rgba(245, 243, 239, 0.4);
  margin-bottom: 16px;
}
.footer-col a, .footer-col p {
  display: block;
  font-size: 14.5px;
  color: rgba(245, 243, 239, 0.65);
  margin-bottom: 10px;
}
.footer-col a { transition: color 0.15s ease; }
.footer-col a:hover { color: var(--brand); }
.footer-bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding-top: 28px;
  border-top: 1px solid rgba(245, 243, 239, 0.12);
  font-size: 13px;
  color: rgba(245, 243, 239, 0.4);
  flex-wrap: wrap;
  gap: 12px;
}
.footer-legal { display: flex; gap: 18px; }
.footer-legal a { color: rgba(245, 243, 239, 0.55); transition: color 0.15s ease; }
.footer-legal a:hover { color: var(--brand); }

@media (max-width: 760px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
}

/* ---------- Ruler / measurement motif ----------
   The signature device for this site: a thin dashed ruler with tick
   marks, used as a section divider. Ties directly to the product's
   own subject matter — blueprints, measurements, tracked progress —
   rather than a decorative generic line. */
.ruler {
  height: 22px;
  background-image: repeating-linear-gradient(
    to right,
    var(--charcoal-30) 0, var(--charcoal-30) 1px,
    transparent 1px, transparent 24px
  );
  background-position: bottom;
  background-size: 100% 10px;
  background-repeat: repeat-x;
  position: relative;
  margin: 0 auto;
  max-width: var(--container);
}
.ruler::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: var(--charcoal-30);
}

/* ---------- Section rhythm ---------- */
section { padding: 96px 0; }
section.tight { padding: 64px 0; }

.section-head {
  max-width: 640px;
  margin-bottom: 56px;
}
.section-head h2 { font-size: clamp(28px, 4vw, 40px); margin-top: 16px; }
.section-head p { color: var(--charcoal-70); font-size: 17px; margin-top: 16px; }

/* ---------- Cards ---------- */
.card {
  background: var(--paper);
  border-radius: var(--radius);
  border: 1px solid var(--line);
  padding: 28px;
  transition: transform 0.2s ease, box-shadow 0.2s ease, border-color 0.2s ease;
}
.card:hover {
  transform: translateY(-4px);
  box-shadow: 0 20px 36px -22px var(--charcoal-30);
  border-color: var(--charcoal-12);
}
/* Cards that are structural (a strip, a form, a comparison table wrapper)
   rather than a "pick me" item shouldn't float on hover — the lift only
   reads as interactive on things that are actually browsable options. */
.entity-strip:hover, .form-card:hover, .compare-wrap:hover {
  transform: none;
  box-shadow: none;
}

.tag {
  display: inline-flex;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 500;
  letter-spacing: 0.05em;
  padding: 4px 10px;
  border-radius: 100px;
  background: var(--sage-deep);
  color: #fff;
}
.tag-amber { background: var(--amber); }
.tag-terracotta { background: var(--terracotta); }

@media (max-width: 640px) {
  section { padding: 64px 0; }
  .wrap { padding: 0 20px; }
}

/* ---------- Scroll reveal ----------
   Sections fade/slide in the first time they cross into view (see the
   IntersectionObserver in each page's closing <script>). Targets
   `section` specifically — hero/page-hero blocks sit above the fold
   and stay visible immediately on load, they're never `.reveal`. */
.reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.7s ease, transform 0.7s ease;
}
.reveal.is-visible {
  opacity: 1;
  transform: translateY(0);
}

/* Grid-item stagger: cards inside a revealed section fade in one after
   another instead of as one flat block. Scoped under `.reveal` (never
   a bare rule) so browsers without IntersectionObserver — where JS
   never adds `.reveal` at all — still show these items immediately. */
.reveal .feat-card,
.reveal .persona-card,
.reveal .price-card,
.reveal .step,
.reveal .value-card {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.5s ease, transform 0.5s ease;
}
.reveal.is-visible .feat-card,
.reveal.is-visible .persona-card,
.reveal.is-visible .price-card,
.reveal.is-visible .step,
.reveal.is-visible .value-card {
  opacity: 1;
  transform: translateY(0);
}
.reveal.is-visible .feat-card:nth-child(1),
.reveal.is-visible .persona-card:nth-child(1),
.reveal.is-visible .price-card:nth-child(1),
.reveal.is-visible .step:nth-child(1),
.reveal.is-visible .value-card:nth-child(1) { transition-delay: 0.05s; }
.reveal.is-visible .feat-card:nth-child(2),
.reveal.is-visible .persona-card:nth-child(2),
.reveal.is-visible .price-card:nth-child(2),
.reveal.is-visible .step:nth-child(2),
.reveal.is-visible .value-card:nth-child(2) { transition-delay: 0.1s; }
.reveal.is-visible .feat-card:nth-child(3),
.reveal.is-visible .persona-card:nth-child(3),
.reveal.is-visible .price-card:nth-child(3),
.reveal.is-visible .step:nth-child(3),
.reveal.is-visible .value-card:nth-child(3) { transition-delay: 0.15s; }
.reveal.is-visible .feat-card:nth-child(4),
.reveal.is-visible .persona-card:nth-child(4),
.reveal.is-visible .price-card:nth-child(4),
.reveal.is-visible .step:nth-child(4),
.reveal.is-visible .value-card:nth-child(4) { transition-delay: 0.2s; }
.reveal.is-visible .feat-card:nth-child(5),
.reveal.is-visible .persona-card:nth-child(5),
.reveal.is-visible .price-card:nth-child(5),
.reveal.is-visible .step:nth-child(5),
.reveal.is-visible .value-card:nth-child(5) { transition-delay: 0.25s; }
.reveal.is-visible .feat-card:nth-child(6),
.reveal.is-visible .persona-card:nth-child(6),
.reveal.is-visible .price-card:nth-child(6),
.reveal.is-visible .step:nth-child(6),
.reveal.is-visible .value-card:nth-child(6) { transition-delay: 0.3s; }
.reveal.is-visible .feat-card:nth-child(7) { transition-delay: 0.35s; }

@media (prefers-reduced-motion: reduce) {
  .reveal {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .reveal .feat-card,
  .reveal .persona-card,
  .reveal .price-card,
  .reveal .step,
  .reveal .value-card {
    opacity: 1;
    transform: none;
    transition: none;
  }
  .mobile-menu, .mobile-menu a, .mobile-menu .mobile-cta {
    transition: none !important;
  }
  .card, .brand-mark, .nav-links a::after {
    transition: none !important;
  }
}

/* ============================================================
   Modernization layer (redesign pass) — motion, depth and a couple
   of small interactive touches layered ON TOP of the system above.
   Deliberately additive/appended rather than rewriting the rules
   above: same brand colors and content everywhere, nothing here
   changes what anything says, only how it moves and feels.
   ============================================================ */

/* ---------- Selection & focus polish ---------- */
::selection { background: var(--terracotta); color: var(--paper); }
a:focus-visible, button:focus-visible, input:focus-visible, textarea:focus-visible, select:focus-visible {
  outline: 2px solid var(--terracotta);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ---------- Top scroll-progress bar ----------
   Zero-markup: driven entirely by a --scroll-pct custom property
   main.js updates on scroll (rAF-throttled). */
body::before {
  content: "";
  position: fixed;
  top: 0; left: 0;
  height: 3px;
  width: calc(var(--scroll-pct, 0) * 1%);
  background: linear-gradient(90deg, var(--terracotta), var(--brand));
  z-index: 1000;
  pointer-events: none;
}

/* ---------- Nav: normal at rest, blurs in once scrolled ----------
   Stays sticky (already set on .nav below) so it's always visible
   while scrolling; the glass-blur effect is specifically a scroll
   reaction, not a permanent state — solid/plain at the very top. */
.nav {
  background: rgba(245, 243, 239, 0.97);
  backdrop-filter: none;
  transition: background 0.3s ease, backdrop-filter 0.3s ease, box-shadow 0.3s ease;
}
.nav.is-scrolled {
  background: rgba(245, 243, 239, 0.86);
  backdrop-filter: blur(14px);
  box-shadow: 0 8px 28px -20px rgba(37, 36, 33, 0.5);
}

/* ---------- Buttons: tactile press + slightly livelier hover ---------- */
.btn {
  transition: transform 0.2s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.2s ease,
    background 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.btn:active { transform: scale(0.96); }
.btn-primary:hover { transform: translateY(-2px) scale(1.015); box-shadow: 0 18px 34px -14px rgba(174, 78, 41, 0.65); }
.btn-ghost:hover { transform: translateY(-1px); }

/* ---------- Cards: a touch more lift + a springier curve ---------- */
.card {
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.4s cubic-bezier(0.22, 1, 0.36, 1), border-color 0.2s ease;
}
.card:hover { transform: translateY(-6px) scale(1.012); box-shadow: 0 28px 48px -22px var(--charcoal-30); }
/* Re-assert (must stay last): structural cards don't float on hover. */
.entity-strip:hover, .form-card:hover, .compare-wrap:hover { transform: none; box-shadow: none; }

/* Feature-card icon-less numbers get a quiet hover nudge so the grid
   doesn't feel static even where there's no bordered .card box. */
.feat-card, .persona-role, .step { transition: transform 0.3s cubic-bezier(0.22, 1, 0.36, 1); }
.feat-card:hover { transform: translateX(2px); }

/* ---------- Reveal stagger: extend to the newer grid types (cost/
   channel/download-benefit cards) using the same pattern as above. ---------- */
.reveal .cost-card, .reveal .channel-card, .reveal .dl-benefit {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity 0.5s cubic-bezier(0.22, 1, 0.36, 1), transform 0.5s cubic-bezier(0.22, 1, 0.36, 1);
}
.reveal.is-visible .cost-card, .reveal.is-visible .channel-card, .reveal.is-visible .dl-benefit {
  opacity: 1;
  transform: translateY(0);
}
.reveal.is-visible .cost-card:nth-child(1), .reveal.is-visible .channel-card:nth-child(1), .reveal.is-visible .dl-benefit:nth-child(1) { transition-delay: 0.05s; }
.reveal.is-visible .cost-card:nth-child(2), .reveal.is-visible .channel-card:nth-child(2), .reveal.is-visible .dl-benefit:nth-child(2) { transition-delay: 0.1s; }
.reveal.is-visible .cost-card:nth-child(3), .reveal.is-visible .channel-card:nth-child(3), .reveal.is-visible .dl-benefit:nth-child(3) { transition-delay: 0.15s; }
.reveal.is-visible .cost-card:nth-child(4), .reveal.is-visible .channel-card:nth-child(4), .reveal.is-visible .dl-benefit:nth-child(4) { transition-delay: 0.2s; }

/* ---------- Aurora background ----------
   A soft, blurred, slow-drifting gradient mesh built only from the
   existing brand palette (terracotta/sage/amber) at low opacity —
   applied to hero-style containers via this one additive class, no
   change to any existing per-page hero CSS or markup content. A
   second layer gives a localized pointer-follow spotlight (JS sets
   --mx/--my in main.js), the same restrained "hero glow" pattern
   used on sites like Linear/Vercel rather than a page-wide gimmick. */
.aurora-bg { position: relative; isolation: isolate; overflow: hidden; }
.aurora-bg::before {
  content: "";
  position: absolute;
  inset: -15%;
  background:
    radial-gradient(38% 42% at 18% 22%, rgba(174, 78, 41, 0.16), transparent 70%),
    radial-gradient(32% 36% at 82% 18%, rgba(83, 109, 70, 0.14), transparent 70%),
    radial-gradient(40% 45% at 65% 88%, rgba(152, 106, 27, 0.10), transparent 70%);
  filter: blur(46px);
  animation: aurora-drift 24s ease-in-out infinite;
  z-index: -1;
  pointer-events: none;
}
.aurora-bg::after {
  content: "";
  position: absolute;
  inset: 0;
  background: radial-gradient(360px circle at var(--mx, 50%) var(--my, 30%), rgba(174, 78, 41, 0.14), transparent 65%);
  opacity: 0;
  transition: opacity 0.4s ease;
  z-index: -1;
  pointer-events: none;
}
.aurora-bg:hover::after { opacity: 1; }
@keyframes aurora-drift {
  0%, 100% { transform: translate(0, 0) scale(1); }
  33% { transform: translate(3%, -4%) scale(1.08); }
  66% { transform: translate(-4%, 3%) scale(0.95); }
}

/* ---------- Hero / page-hero entrance ----------
   Runs once on load, independent of the scroll-reveal system above
   (hero content is already in view on load, so IntersectionObserver
   would fire immediately anyway — this gives it its own deliberate
   staggered fade-up instead). Targets existing selectors only, no
   markup changes needed on any page. */
@keyframes hero-fade-up {
  from { opacity: 0; transform: translateY(22px); }
  to { opacity: 1; transform: translateY(0); }
}
.hero .eyebrow, .hero h1, .hero .hero-sub, .hero .hero-cta, .hero .hero-meta, .hero .mock-wrap {
  animation: hero-fade-up 0.8s cubic-bezier(0.22, 1, 0.36, 1) both;
}
.hero .eyebrow { animation-delay: 0.05s; }
.hero h1 { animation-delay: 0.15s; }
.hero .hero-sub { animation-delay: 0.28s; }
.hero .hero-cta { animation-delay: 0.4s; }
.hero .hero-meta { animation-delay: 0.5s; }
.hero .mock-wrap { animation-delay: 0.35s; }

/* Construction vector motif behind hero content — a line-art building
   drawing, recolored terracotta from the source line drawing, anchored
   bottom-right so it reads as a real presence, not just texture. Each
   page sets its own --hero-vector (a different drawing per page, see
   each file's own <style> block) so headers don't all repeat the same
   image; this shared rule only carries the shape/size/position rules.
   Sits on the inner hero-grid/page-hero box (not aurora-bg itself,
   which is already carrying a blurred glow layer on its own ::before)
   so the crisp lines stay unblurred. */
.hero-grid, .page-hero { position: relative; }
.hero-grid::before, .page-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: var(--hero-vector, url("images/vector-hero-building.png"));
  background-repeat: no-repeat;
  background-size: 640px auto;
  background-position: bottom 24px right 16px;
  opacity: 0.26;
  z-index: -1;
  pointer-events: none;
}
@media (max-width: 700px) {
  .hero-grid::before, .page-hero::before { background-size: 380px auto; background-position: bottom 12px right 8px; }
}

/* Same line-art family, recolored white for the dark trust-band lower
   on the homepage (images/vector-trust-elevation.png — a dimensioned
   building elevation with measurement arrows) — keeps the "not too
   plain" treatment going past the hero instead of only living at the
   very top of the page. */
.trust-band { position: relative; isolation: isolate; overflow: hidden; }
.trust-band::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("images/vector-trust-elevation.png");
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center 30%;
  opacity: 0.14;
  z-index: 0;
  pointer-events: none;
}
.trust-band > * { position: relative; z-index: 1; }

.page-hero > * { animation: hero-fade-up 0.7s cubic-bezier(0.22, 1, 0.36, 1) both; }
.page-hero > *:nth-child(1) { animation-delay: 0.05s; }
.page-hero > *:nth-child(2) { animation-delay: 0.15s; }
.page-hero > *:nth-child(3) { animation-delay: 0.25s; }
.page-hero > *:nth-child(4) { animation-delay: 0.35s; }
.page-hero > *:nth-child(5) { animation-delay: 0.45s; }

/* Gentle continuous float on the hero phone mockup — reads as "alive"
   without being distracting; runs after the entrance animation above
   settles (7s covers entrance + a beat). */
@keyframes mock-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-10px); }
}
.hero .mock-phone { animation: mock-float 6s ease-in-out 1.2s infinite; }

/* ---------- CTA band (shared across all 6 pages) ----------
   Gradient instead of flat brand color, white/cream accents instead of
   charcoal, and a low-opacity line-art streetscape (images/vector-cta-
   street.png, recolored white — a row of building elevations with
   dimension ticks) so the band reads as more than a plain color block.
   Single definition here so every page stays in sync instead of 6
   copies drifting apart. */
.cta-band {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: linear-gradient(135deg, var(--brand) 0%, var(--terracotta-deep) 100%);
  border-radius: 28px;
  padding: 64px;
  text-align: center;
  color: var(--cream);
}
.cta-band::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("images/vector-cta-street.png");
  background-repeat: no-repeat;
  background-size: cover;
  background-position: center 75%;
  opacity: 0.16;
  z-index: 0;
  pointer-events: none;
}
.cta-band > * { position: relative; z-index: 1; }
.cta-band h2 { color: var(--cream); font-size: clamp(28px, 4vw, 38px); }
.cta-band p { color: rgba(245,243,239,0.82); margin-top: 14px; font-size: 16px; }
.cta-band .hero-cta { justify-content: center; margin-top: 30px; }
.cta-band .eyebrow { color: rgba(245,243,239,0.85); }
.cta-band .eyebrow::before { background: var(--cream); }
.cta-band .btn-ghost:hover { border-color: var(--cream); color: var(--cream); background: rgba(245,243,239,0.12); }
@media (max-width: 640px) { .cta-band { padding: 44px 24px; } }

/* ---------- Phone mockup with cycling real screenshots (shared — used
   by index.html's hero and fitur.html's "Tur Singkat") ----------
   Real cropped screenshots of the actual Mandorly app (from
   images/app-shot-*.png) cross-fade inside a phone bezel. main.js
   drives this generically off `.mock-frame` + `.mock-dot`/`.mock-pause`
   wherever they appear, so this is markup + this CSS only, no
   page-specific JS. */
.mock-phone {
  width: 320px;
  margin: 0 auto;
  background: var(--charcoal);
  border-radius: 40px;
  padding: 12px;
  box-shadow: 0 40px 80px -30px rgba(37,36,33,0.45);
  position: relative;
}
.mock-screen {
  background: var(--cream);
  border-radius: 30px;
  overflow: hidden;
  position: relative;
  aspect-ratio: 513 / 1056;
}
.mock-frame {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 0.45s ease;
  pointer-events: none;
}
.mock-frame.is-active { opacity: 1; z-index: 1; pointer-events: auto; }
.mock-frame img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mock-dots { display: flex; align-items: center; justify-content: center; gap: 8px; margin-top: 12px; padding-bottom: 2px; }
.mock-dot { width: 7px; height: 7px; border-radius: 50%; background: rgba(245,243,239,0.25); border: none; padding: 0; cursor: pointer; transition: background 0.2s ease, transform 0.2s ease; }
.mock-dot.is-active { background: var(--brand); transform: scale(1.35); }
.mock-pause {
  width: 20px; height: 20px; border-radius: 50%; margin-left: 4px;
  border: 1px solid rgba(245,243,239,0.2); background: transparent;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; color: rgba(245,243,239,0.55); font-size: 7px; line-height: 1;
  transition: border-color 0.15s ease, color 0.15s ease;
}
.mock-pause:hover { border-color: rgba(245,243,239,0.5); color: var(--cream); }
@media (max-width: 860px) { .mock-phone { width: 260px; } }

/* ---------- Interactive stepper (shared — used by index.html's "Cara
   Kerja" and fitur.html's "Tur Singkat") ----------
   A vertical numbered list with a connecting line whose fill height
   tracks the active step. main.js drives it generically off any
   `.step[data-step]` elements it finds inside a `.steps` container, so
   this single definition (and its JS counterpart) works on any page
   without page-specific code. */
.steps { display: flex; flex-direction: column; gap: 32px; position: relative; }
.steps::before {
  content: ""; position: absolute; left: 15px; top: 16px; bottom: 16px; width: 2px; background: var(--charcoal-12);
}
.steps-fill {
  position: absolute; left: 15px; top: 16px; width: 2px; background: var(--terracotta);
  height: 0%; transition: height 0.5s ease;
}
.step { position: relative; padding-left: 46px; cursor: pointer; }
.step-num {
  position: absolute; left: 0; top: 0; width: 32px; height: 32px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center; z-index: 1;
  font-family: var(--font-mono); font-size: 13px; font-weight: 600;
  border: 2px solid var(--charcoal-12); color: var(--charcoal-50); background: var(--cream);
  transition: border-color 0.3s ease, color 0.3s ease, background 0.3s ease, transform 0.3s ease;
}
.step h3 { font-size: 18px; margin-bottom: 8px; color: var(--charcoal-50); transition: color 0.3s ease; }
.step p { color: var(--charcoal-50); font-size: 14.5px; transition: color 0.3s ease; }
.step.is-active .step-num { border-color: var(--terracotta); color: #fff; background: var(--terracotta); transform: scale(1.08); }
.step.is-active h3 { color: var(--charcoal); }
.step.is-active p { color: var(--charcoal-70); }

/* ---------- Back-to-top button (created by main.js) ----------
   Sits stacked above the WhatsApp button below, right-aligned. */
.back-to-top {
  position: fixed;
  right: 24px;
  bottom: 92px;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--charcoal);
  color: var(--cream);
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
  box-shadow: 0 14px 30px -12px rgba(37, 36, 33, 0.5);
  opacity: 0;
  transform: translateY(12px) scale(0.9);
  pointer-events: none;
  transition: opacity 0.3s ease, transform 0.3s cubic-bezier(0.22, 1, 0.36, 1), background 0.15s ease;
  z-index: 60;
}
.back-to-top.is-visible { opacity: 1; transform: translateY(0) scale(1); pointer-events: auto; }
.back-to-top:hover { background: var(--terracotta); }
.back-to-top:active { transform: scale(0.9); }
@media (max-width: 640px) {
  .back-to-top { right: 16px; bottom: 78px; width: 42px; height: 42px; }
}

/* ---------- WhatsApp floating button (created by main.js) ----------
   Always visible (not scroll-gated) at the conventional bottom-right
   spot; a soft repeating pulse ring draws the eye without being
   obnoxious. Uses the existing sage token (already this site's
   "positive action" color, e.g. checkmarks) rather than importing
   WhatsApp's own brand green. */
.wa-float {
  position: fixed;
  right: 24px;
  bottom: 24px;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  background: var(--sage-deep);
  color: #fff;
  display: flex;
  align-items: center;
  justify-content: center;
  border: none;
  cursor: pointer;
  box-shadow: 0 16px 34px -12px rgba(60, 79, 51, 0.6);
  z-index: 61;
  transition: transform 0.25s cubic-bezier(0.22, 1, 0.36, 1), box-shadow 0.25s ease, background 0.15s ease;
}
.wa-float::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--sage-deep);
  opacity: 0.55;
  animation: wa-pulse 2.4s cubic-bezier(0.22, 1, 0.36, 1) infinite;
  z-index: -1;
}
@keyframes wa-pulse {
  0% { transform: scale(1); opacity: 0.45; }
  100% { transform: scale(1.9); opacity: 0; }
}
.wa-float:hover { transform: scale(1.08); background: var(--sage); }
.wa-float:active { transform: scale(0.94); }
@media (max-width: 640px) {
  .wa-float { right: 16px; bottom: 16px; width: 50px; height: 50px; }
}
@media (prefers-reduced-motion: reduce) {
  .wa-float::before { animation: none; opacity: 0; }
}

/* ---------- Feature deep-dive rows — shared across fitur.html (hub)
   and the 8 per-module pages under fitur/, so a single visual language
   (copy left, mini mockup right) carries through the whole Fitur section. ---------- */
.feature-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 64px;
  align-items: center;
  padding: 72px 0;
}
.feature-row.reverse .fr-visual { order: 2; }
.fr-copy h2 { font-size: clamp(26px, 3.4vw, 34px); margin-top: 14px; }
.fr-copy p { color: var(--charcoal-70); font-size: 15.5px; margin-top: 16px; line-height: 1.7; }
.fr-list { margin-top: 22px; padding: 0; display: flex; flex-direction: column; gap: 12px; }
.fr-list li { list-style: none; display: flex; gap: 10px; font-size: 14.5px; color: var(--charcoal); }
.fr-list li b { font-weight: 600; }
.fr-check { width: 18px; height: 18px; border-radius: 50%; background: var(--sage); flex-shrink: 0; margin-top: 2px; position: relative; }
.fr-check::after { content: ""; position: absolute; left: 5px; top: 3px; width: 5px; height: 9px; border-right: 2px solid #fff; border-bottom: 2px solid #fff; transform: rotate(40deg); }
.fr-visual { background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); padding: 26px; position: relative; }
@media (max-width: 860px) {
  .feature-row, .feature-row.reverse { grid-template-columns: 1fr; }
  .feature-row.reverse .fr-visual { order: 0; }
  .feature-row { padding: 48px 0; }
}

/* mini mockups used inside .fr-visual */
.mk-label { font-family: var(--font-mono); font-size: 10.5px; color: var(--charcoal-50); letter-spacing: 0.06em; text-transform: uppercase; margin-bottom: 14px; }
.mk-row { display: flex; justify-content: space-between; font-size: 13px; padding: 8px 0; border-bottom: 1px solid var(--line); color: var(--charcoal-70); }
.mk-row:last-child { border-bottom: none; }
.mk-row b { color: var(--charcoal); }
.mk-badge { display: inline-flex; align-items: center; gap: 6px; font-size: 11.5px; font-weight: 600; padding: 5px 10px; border-radius: 100px; }
.mk-badge.sage { color: var(--sage-deep); background: rgba(83,109,70,0.12); }
.mk-badge.amber { color: var(--amber); background: rgba(217,119,6,0.12); }
.mk-badge.terracotta { color: var(--terracotta-deep); background: rgba(174,78,41,0.12); }
.mk-bar-track { height: 8px; background: var(--line); border-radius: 5px; overflow: hidden; margin: 6px 0 14px; }
.mk-bar-fill { height: 100%; background: var(--terracotta); border-radius: 5px; }
.mk-sig { border-top: 1px solid var(--charcoal); width: 130px; margin-top: 34px; padding-top: 6px; font-size: 11px; color: var(--charcoal-70); }
.mk-sig-mark { font-family: var(--font-display); font-style: italic; font-size: 22px; color: var(--terracotta-deep); }
.mk-chat { background: var(--cream); border-radius: 12px; padding: 14px; font-size: 13px; }
.mk-chat .from-ai { color: var(--charcoal-70); }
.mk-chat .from-ai::before { content: "AI · "; font-family: var(--font-mono); font-size: 10px; color: var(--terracotta-deep); }

/* Recording frame — wraps a real screen-recording GIF on each module page,
   a plain "browser window" chrome (not the phone-shaped .mock-phone, since
   these recordings are desktop app captures) so the GIF reads as a real
   window rather than floating bare on the page. */
.rec-frame { background: var(--paper); border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; box-shadow: 0 24px 48px -28px var(--charcoal-30); }
.rec-frame-bar { display: flex; align-items: center; gap: 6px; padding: 12px 14px; border-bottom: 1px solid var(--line); }
.rec-frame-dot { width: 9px; height: 9px; border-radius: 50%; background: var(--charcoal-30); }
.rec-frame img { display: block; width: 100%; height: auto; }

/* FAQ accordion-style list — shared (fitur hub + module pages) */
.faq { max-width: 760px; margin: 0 auto; }
.faq-item { border-bottom: 1px solid var(--line); padding: 24px 0; }
.faq-item h3 { font-size: 17px; font-weight: 600; font-family: var(--font-body); }
.faq-item p { margin-top: 10px; color: var(--charcoal-70); font-size: 14.5px; line-height: 1.7; }

.topup-strip {
  padding: 22px 28px; border-radius: 16px;
  background: var(--cream-deep); border: 1px dashed var(--charcoal-30);
  display: flex; align-items: center; justify-content: space-between; gap: 20px; flex-wrap: wrap;
}
.topup-strip span { font-size: 14px; color: var(--charcoal-70); }

/* Module grid — fitur.html hub's 8 module cards, and reused as the
   feature-breakdown list style (.fc-list) on each module deep-dive page. */
.fc-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; margin-top: 40px; }
.fc-category {
  padding: 30px;
  transform: perspective(700px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg));
  transition: transform 0.25s ease, box-shadow 0.25s ease; will-change: transform;
}
/* .card:hover (above) has higher specificity than a bare .fc-category
   rule and would silently replace this transform with its lift effect —
   override it explicitly so the tilt wins on hover instead. */
.card.fc-category:hover { transform: perspective(700px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)); }
.fc-category-head { display: flex; align-items: center; gap: 12px; margin-bottom: 20px; }
.fc-category-num {
  font-family: var(--font-mono); font-size: 12px; color: var(--terracotta-deep);
  background: rgba(174,78,41,0.1); width: 34px; height: 34px; border-radius: 10px;
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
}
.fc-category h3 { font-size: 18px; }
.fc-category p.fc-desc { color: var(--charcoal-70); font-size: 13.5px; line-height: 1.6; margin-top: -6px; margin-bottom: 4px; }
.fc-list { display: flex; flex-direction: column; gap: 14px; }
.fc-list li { list-style: none; display: flex; gap: 10px; font-size: 13.5px; color: var(--charcoal-70); line-height: 1.55; }
.fc-list li b { color: var(--charcoal); font-weight: 600; }
@media (max-width: 860px) { .fc-grid { grid-template-columns: 1fr; } }

/* Breadcrumb — used on the 8 per-module fitur/ pages (Beranda / Fitur / {Modul}) */
.breadcrumb { font-size: 13px; color: var(--charcoal-50); margin-bottom: 14px; }
.breadcrumb a { color: var(--charcoal-50); text-decoration: none; }
.breadcrumb a:hover { color: var(--terracotta-deep); }
.breadcrumb span { margin: 0 6px; }

@media (prefers-reduced-motion: reduce) {
  body::before { transition: none; }
  .aurora-bg::before { animation: none; }
  .aurora-bg::after { transition: none; }
  .hero .eyebrow, .hero h1, .hero .hero-sub, .hero .hero-cta, .hero .hero-meta, .hero .mock-wrap,
  .page-hero > * {
    animation: none;
    opacity: 1;
    transform: none;
  }
  .hero .mock-phone { animation: none; }
  .card:hover, .btn:active, .btn-primary:hover, .feat-card:hover { transform: none; }
  .back-to-top { transition: opacity 0.2s ease; }
}
