/* =========================================================
   COMPONENTS — header, footer, buttons, cards, forms, tables,
   accordion, phone mockup, social proof, scroll-reveal
   ========================================================= */

/* =========================
   Background grid (shared hero backdrop motif)
   ========================= */

.bg-grid {
  position: relative;
  overflow: hidden;
  background:
    radial-gradient(
      800px 400px at 50% -100px,
      var(--accent-blue-soft),
      transparent 70%
    ),
    repeating-linear-gradient(
      0deg,
      var(--grid-line) 0,
      var(--grid-line) 1px,
      transparent 1px,
      transparent 72px
    ),
    repeating-linear-gradient(
      90deg,
      var(--grid-line) 0,
      var(--grid-line) 1px,
      transparent 1px,
      transparent 72px
    ),
    var(--bg);
}

/* Ambient drifting glow — sits above the grid pattern, below the content
   (see ".bg-grid > *" below). transform-only animation, very low opacity,
   purely decorative. Effectively frozen under prefers-reduced-motion via
   the global animation-duration override in theme.css. */
.bg-grid::before {
  content: "";
  position: absolute;
  top: -15%;
  left: 15%;
  width: 55%;
  height: 65%;
  background: radial-gradient(
    circle,
    var(--accent-blue) 0%,
    transparent 70%
  );
  opacity: 0.14;
  filter: blur(90px);
  pointer-events: none;
  z-index: 0;
  will-change: transform;
  animation: ambientDrift 24s ease-in-out infinite;
}

@keyframes ambientDrift {
  0%,
  100% {
    transform: translate(0, 0) scale(1);
  }
  50% {
    transform: translate(7%, 5%) scale(1.1);
  }
}

.bg-grid > * {
  position: relative;
  z-index: 1;
}

/* =========================
   Header / Navigation
   ========================= */

.site-header {
  /*
    CONFIRMED ROOT CAUSE (verified empirically, not a guess): this was
    `position: sticky` until it was found to silently stop sticking at all
    once scrolled past its own height — it just sat at its normal in-flow
    document position, invisible except near scrollY 0. Cause: html/body
    both carry `overflow-x: hidden` (added in an earlier round to block a
    real horizontal-overscroll bug — see base.css). Per the CSS Overflow
    spec, giving overflow-x a non-visible value forces the *other* axis
    (overflow-y) to also compute to a non-visible value (auto) instead of
    the visible it was written as, even under `!important`. That makes
    html/body genuine scroll containers instead of transparent pass-through
    to the viewport, and a position:sticky descendant's stuck-offset
    calculation against a root-level scroll container that isn't the true
    viewport doesn't engage — confirmed by forcing overflow-x back to
    visible on both elements, which immediately restored correct sticking.
    Removing overflow-x:hidden isn't an option (re-tested: dropping it from
    either html or body alone reopens the original horizontal-scroll bug).

    Fix: position:fixed instead of sticky. Fixed positioning resolves
    against the initial containing block (the true viewport) regardless of
    an ancestor's overflow value, so it isn't subject to this conflict at
    all. Since fixed elements don't reserve their own space in normal flow
    the way sticky ones do, #app-view carries a matching padding-top below
    (measured header height, mirrored at the same 992px breakpoint used
    elsewhere in this file) so page content no longer starts underneath it.
  */
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  /*
    Higher than .nav-overlay's z-index (1099). A non-auto z-index on a
    positioned element is enough on its own to force this header to form
    its own stacking context, so .primary-nav (a descendant, z-index 1100)
    only ever gets compared against .nav-overlay through the header's own
    rank — not directly. Ranking the header itself above the overlay is
    what makes the slide-out menu (and the header bar that sits above it)
    render crisp instead of getting caught under the blurred backdrop meant
    only for the page content behind it.
  */
  z-index: 1200;
}

/* Full-bleed visual bar + hide/show animation. Kept as a separate element
   from .site-header (rather than putting background/transform directly on
   it) purely so the hide/show transform never lands on the positioned
   element itself — harmless with position:fixed (no known engine bug there,
   unlike the sticky+transform interaction), kept as cheap extra insurance. */
.header-bar {
  background: var(--overlay-fade);
  backdrop-filter: blur(10px);
  border-bottom: 1px solid var(--border);
  transition: transform 0.3s ease;
}

/* Smart hide/show: hidden on scroll-down past a threshold, revealed instantly
   on any scroll-up (see scroll-ui.js). transform only, so it composes
   cleanly and costs nothing layout-wise. */
.site-header.is-hidden .header-bar {
  transform: translateY(-100%);
}

/* .site-header is position:fixed (see above) and so no longer reserves its
   own space in document flow — this replaces that reserved space so page
   content doesn't start underneath it. Values are the header's measured
   rendered height at each breakpoint (81px up to 991px, ~84.6px→85px from
   992px, where nav-links appear inline and the row's cross-axis sizing
   shifts very slightly); mirrors the 992px breakpoint used elsewhere in
   this file for the same header layout change. */
#app-view {
  padding-top: 81px;
}

@media (min-width: 992px) {
  #app-view {
    padding-top: 85px;
  }
}

.header-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 20px 24px;
}

.logo {
  display: flex;
  align-items: center;
  flex-shrink: 0;
}

/*
  Sizing and visibility are kept as fully separate rule sets on the same
  .logo-im Go to your house I think the person that live there left here because of space left space of space yeah yeah the man that left build his own duplex so left a picture because a space carrier yes working out perfect checking feet this is working now I'm all defined everything and anything it will be yeah that should be the least that you also like say the turnover sixty five sixty five so today another person has been sixty five so sixty five is five we moved four fifty eight yesterday just after this one if you check what you have online you check what I have offline the offline offline the offline it's okay it's here landing page doesn't have that much and fiber it's not coming from the network it's coming from the offline that this is coming from this one is coming from there a lot of things it checks the local lot of things I hope some something needs to be done for that thing to work if not then it's time it has been done done so it does a lot of check before it turns on but this is one that this also it's going to have like a new object coming right now the thing is okay as it is I'll be putting on next week will be a new launch a lot of things will be changed besides the lot of sense will be changed on the site a lot of features will be added only please also I'm going to work on an app this day ahead of the competition I don't know if it stay like this now I will just do one of the cause people like the strong shell or you know percentage of the market so I want what I teach you to see that we need to do something like directly they don't collect that somewhere just have that our app on their phone and it connects your website connect straight to their FaceTime connect directly to their FaceTime connect directly to your WhatsApp you just enter connect to whatever configuration Facebook PC that kind of scenario like because it's not like that so once something like that something they can use their phone and moving up and down it can be the car driving this I don't know exactly where you are with your with your voice so that I can put on account second one kind of by those it is kind of like him itself because it's trying to see how far just resolve this finish the discussion they went to court some other so they don't face the now as as this money update the update with this let me send you my countryg class (rather than a `.logo img` element-descendant selector),
  so a sizing rule can never outrank the display:none/block visibility
  rules below by specificity — that mismatch was the root cause of both
  logos rendering at once in dark mode.
*/
.logo-img {
  display: block;
  width: 130px;
  height: 28px; /* DO NOT CHANGE THIS VALUE UNTIL SPECIFIED */
}

.logo-img--light {
  display: none;
}

:root[data-theme="light"] .logo-img--dark {
  display: none;
}

:root[data-theme="light"] .logo-img--light {
  display: block;
}

.header-actions {
  display: flex;
  align-items: center;
  gap: 12px;
}

.primary-nav {
  display: flex;
  align-items: center;
  gap: 8px;
}

.nav-links {
  display: flex;
  align-items: center;
  gap: 8px;
}

.nav-links a {
  display: inline-block;
  padding: 10px 14px;
  border-radius: 999px;
  font-size: 0.95rem;
  font-weight: 500;
  color: var(--text-secondary);
  transition:
    color 0.2s ease,
    background-color 0.2s ease;
}

.nav-links a:hover {
  color: var(--text-primary);
  background: var(--surface-2);
}

.nav-links a[aria-current="page"] {
  color: var(--text-primary);
  background: var(--accent-blue-soft);
}

/*
  Leading link icons only exist for the mobile drawer redesign — hidden by
  default so the desktop pill nav is untouched; switched on inside the
  @media (max-width: 900px) block below. Uses the svg.nav-link-icon
  (element+class) form rather than plain .nav-link-icon specifically so it
  can never lose a specificity tie against the later .icon utility rule
  (also a single class, "display: inline-block") purely by file order —
  exactly the kind of mismatch that caused the earlier logo-visibility bug.
*/
svg.nav-link-icon {
  display: none;
}

/* Theme toggle */
.theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--text-primary);
  flex-shrink: 0;
}

.theme-toggle:hover {
  border-color: var(--accent-blue);
}

.theme-toggle svg {
  width: 18px;
  height: 18px;
}

.theme-toggle .icon-moon {
  display: none;
}

:root[data-theme="light"] .theme-toggle .icon-sun {
  display: none;
}

:root[data-theme="light"] .theme-toggle .icon-moon {
  display: block;
}

/* Mobile menu toggle (hamburger) */
.menu-toggle {
  display: none;
  width: 40px;
  height: 40px;
  position: relative;
  flex-shrink: 0;
}

.menu-toggle span {
  position: absolute;
  left: 8px;
  right: 8px;
  height: 2px;
  background: var(--text-primary);
  border-radius: 2px;
  transition: all 0.3s ease;
}

.menu-toggle span:nth-child(1) {
  top: 14px;
}
.menu-toggle span:nth-child(2) {
  top: 19px;
}
.menu-toggle span:nth-child(3) {
  top: 24px;
}

.menu-toggle[aria-expanded="true"] span:nth-child(1) {
  top: 19px;
  transform: rotate(45deg);
}
.menu-toggle[aria-expanded="true"] span:nth-child(2) {
  opacity: 0;
}
.menu-toggle[aria-expanded="true"] span:nth-child(3) {
  top: 19px;
  transform: rotate(-45deg);
}

.nav-overlay {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
  opacity: 0;
  visibility: hidden;
  transition: all 0.3s ease;
  z-index: 1099;
}

.nav-overlay.active {
  opacity: 1;
  visibility: visible;
}

@media (max-width: 900px) {
  .menu-toggle {
    display: block;
  }

  .primary-nav {
    position: fixed;
    top: 0;
    right: 0;
    width: min(85%, 380px);
    /*
      100vh on real mobile browsers is the viewport with the address bar
      hidden — the actually-visible area is smaller whenever the address bar
      is showing (most of the time), leaving the drawer's bottom content
      (CTA + social row) below the fold. dvh tracks the real visible
      viewport; the 100vh line is a fallback for browsers that don't
      understand dvh and simply ignore that declaration, keeping this one.
    */
    height: 100vh;
    height: 100dvh;
    flex-direction: column;
    align-items: stretch;
    background: var(--surface);
    border-left: 1px solid var(--border);
    padding: 24px;
    gap: 24px;
    /*
      transform instead of animating `right`: a fixed element positioned via
      a large negative `right` offset expands the document's scrollable
      width dramatically (confirmed: ~2.8x viewport width) even while
      off-screen. Switching to translateX cuts that down a lot, but a
      position:fixed element's post-transform painted box still counts
      toward scrollable overflow in Chromium/WebKit even when transformed
      fully off-screen (confirmed: still ~1.85x). visibility:hidden is what
      actually removes it from the scrollable area — the transition-delay
      keeps it visible throughout the closing slide so it doesn't just pop
      away mid-animation, only going hidden once fully off-screen. This also
      takes the closed menu's links out of the keyboard tab order, which
      they otherwise stayed in despite being invisible.
    */
    transform: translateX(100%);
    visibility: hidden;
    transition:
      transform 0.35s ease,
      visibility 0s linear 0.35s;
    z-index: 1100;
    /*
      The panel itself does NOT scroll — .nav-links (below) owns its own
      internal scroll instead, so the logo row and CTA/social footer stay
      pinned in place as a defensive measure (e.g. a very short screen,
      larger accessibility text, or more links added later) rather than the
      whole drawer scrolling and carrying the footer out of view with it.
    */
    overflow-y: hidden;
  }

  .primary-nav.active {
    transform: translateX(0);
    visibility: visible;
    transition:
      transform 0.35s ease,
      visibility 0s linear 0s;
  }

  .nav-panel-top {
    display: flex;
    align-items: center;
    justify-content: space-between;
  }

  .nav-panel-close {
    width: 36px;
    height: 36px;
    border-radius: 8px;
    background: var(--surface-2);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.3rem;
  }

  .nav-links {
    flex-direction: column;
    align-items: stretch;
    gap: 4px;
    width: 100%;
    /*
      Owns the drawer's internal scroll (see .primary-nav's overflow-y:hidden
      above). flex:1 lets it consume the space left over between the pinned
      logo row and CTA/footer; min-height:0 overrides the flex-item default
      of min-height:auto, which otherwise refuses to shrink below content
      size and silently defeats overflow-y here.
    */
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
  }

  .nav-links a {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 14px 16px;
    border-radius: 10px;
    border-left: 3px solid transparent;
  }

  svg.nav-link-icon {
    display: inline-flex;
    width: 18px;
    height: 18px;
    color: var(--text-secondary);
    flex-shrink: 0;
  }

  /*
    Mobile-only active state: the desktop .nav-links a[aria-current="page"]
    rule (var(--accent-blue-soft), a 14%-opacity tint) is barely visible
    against the drawer's solid --surface background — this rule wins on
    mobile via the media query, cascade-correct, no specificity hacks. A
    literal rgba() rather than --accent-blue-soft on purpose, so the shared
    variable (used in 9+ other places) stays untouched.
  */
  .nav-links a[aria-current="page"] {
    background: rgba(74, 124, 255, 0.18);
    border-left-color: var(--accent-blue);
  }

  .nav-links a[aria-current="page"] svg.nav-link-icon {
    color: var(--accent-blue);
  }

  .header-actions .get-app-btn {
    display: none;
  }

  /* Anchors the CTA + social row to the bottom of the drawer via flex
     auto-margin, instead of it trailing right after the (short) nav-links
     list with a dead void beneath it. */
  .nav-panel-bottom {
    margin-top: auto;
    border-top: 1px solid var(--border);
    padding-top: 16px;
    display: flex;
    flex-direction: column;
    gap: 16px;
  }

  .nav-panel-social {
    display: flex;
    justify-content: center;
    gap: 16px;
  }

  .nav-panel-social img {
    opacity: 0.6;
    transition: opacity 0.2s ease;
  }

  .nav-panel-social a:hover img {
    opacity: 1;
  }

  .primary-nav .get-app-btn {
    display: flex;
    justify-content: center;
    width: 100%;
  }
}

@media (min-width: 901px) {
  .nav-panel-top,
  .nav-panel-close,
  .nav-panel-bottom {
    display: none;
  }
  .primary-nav .get-app-btn {
    display: none;
  }
}

/* =========================
   Floating scroll cluster (back-to-top + theme toggle)
   ========================= */

/*
  z-index 900: above normal page content, but well below .nav-overlay(1099)/
  .primary-nav(1100)/.site-header(1200) — so when the mobile drawer opens,
  the dimmed backdrop correctly covers this cluster instead of it poking
  through on top of the overlay. Visibility (scroll threshold) and the
  back-to-top click handler both live in scroll-ui.js.
*/
.scroll-fab-cluster {
  position: fixed;
  right: 20px;
  bottom: 20px;
  z-index: 900;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  opacity: 0;
  transform: translateY(12px) scale(0.9);
  pointer-events: none;
  transition:
    opacity 0.3s ease,
    transform 0.3s ease;
}

.scroll-fab-cluster.is-visible {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

.scroll-fab {
  width: 48px;
  height: 48px;
  border-radius: 50%;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  box-shadow: 0 8px 24px var(--shadow-color);
}

.scroll-fab.theme-toggle {
  width: 48px;
  height: 48px;
}

.back-to-top-btn {
  background: var(--accent-blue);
  color: #fff;
  border: 1px solid transparent;
  transition:
    background-color 0.2s ease,
    transform 0.15s ease;
}

.back-to-top-btn:hover {
  background: var(--accent-blue-strong);
}

.back-to-top-btn:active {
  transform: scale(0.94);
}

.back-to-top-btn svg {
  width: 20px;
  height: 20px;
}

/* =========================
   Icon sizing utilities (SVG <use> icons from the sprite)
   ========================= */

.icon {
  display: inline-block;
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

.icon-sm {
  width: 16px;
  height: 16px;
}

.icon-lg {
  width: 28px;
  height: 28px;
}

.cell-yes svg {
  color: var(--accent-teal);
}

.cell-no svg {
  color: var(--text-muted);
}

.compare-table td.cell-center {
  text-align: center;
}

/* =========================
   Buttons
   ========================= */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 13px 26px;
  border-radius: 999px;
  font-weight: 600;
  font-size: 1rem;
  border: 1px solid transparent;
  transition:
    transform 0.15s cubic-bezier(0.4, 0, 0.2, 1),
    background-color 0.2s ease,
    border-color 0.2s ease,
    color 0.2s ease,
    box-shadow 0.2s ease;
  white-space: nowrap;
}

.btn i,
.btn svg {
  transition: transform 0.25s ease;
}

.btn:hover i,
.btn:hover svg {
  transform: translateX(3px);
}

/* Tactile press feedback, every variant, touch included. Matched in
   specificity + source order against each variant's :hover rule below so
   the press-down scale always wins over the hover-lift while clicking. */
.btn:active {
  transform: scale(0.97);
}

.btn--primary {
  background: var(--accent-blue);
  color: #fff;
  box-shadow: 0 4px 20px var(--accent-blue-soft);
}

.btn--primary:hover {
  background: var(--accent-blue-strong);
  transform: translateY(-2px);
}

.btn--primary:active {
  transform: scale(0.97);
}

.btn--outline {
  background: transparent;
  border-color: var(--border);
  color: var(--text-primary);
}

.btn--outline:hover {
  border-color: var(--accent-blue);
  color: var(--accent-blue);
}

.btn--outline:active {
  transform: scale(0.97);
}

.btn--gold {
  background: var(--accent-gold);
  color: #241a04;
}
.btn--teal {
  background: var(--accent-teal);
  color: #04211d;
}
.btn--purple {
  background: var(--accent-purple);
  color: #fff;
}

.btn--sm {
  padding: 9px 18px;
  font-size: 0.9rem;
}

.btn--block {
  width: 100%;
}

.header-actions .btn,
.primary-nav .btn {
  padding: 10px 20px;
  font-size: 0.9rem;
}

/* =========================
   Badges / pills
   ========================= */

.badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: 999px;
  font-size: 0.8rem;
  font-weight: 600;
  background: var(--surface-2);
  border: 1px solid var(--border);
  color: var(--text-secondary);
}

.badge--live {
  color: var(--text-primary);
}

.badge--live .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--accent-teal);
  animation: pulseDot 2s ease-in-out infinite;
}

@keyframes pulseDot {
  0%,
  100% {
    opacity: 0.6;
    transform: scale(0.9);
  }
  50% {
    opacity: 1;
    transform: scale(1.15);
  }
}

/* =========================
   Accent helpers (meaning-based color system)
   ========================= */

[data-accent="blue"] {
  --accent: var(--accent-blue);
  --accent-soft: var(--accent-blue-soft);
}
[data-accent="gold"] {
  --accent: var(--accent-gold);
  --accent-soft: var(--accent-gold-soft);
}
[data-accent="teal"] {
  --accent: var(--accent-teal);
  --accent-soft: var(--accent-teal-soft);
}
[data-accent="purple"] {
  --accent: var(--accent-purple);
  --accent-soft: var(--accent-purple-soft);
}

.icon-wrap {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 52px;
  height: 52px;
  border-radius: 16px;
  background: var(--accent-soft, var(--accent-blue-soft));
  color: var(--accent, var(--accent-blue));
  flex-shrink: 0;
}

.icon-wrap svg {
  width: 26px;
  height: 26px;
}

/* =========================
   Cards
   ========================= */

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
  gap: 24px;
}

.pillar-card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 20px;
  padding: 32px;
  display: flex;
  flex-direction: column;
  gap: 16px;
  transition:
    transform 0.3s cubic-bezier(0.16, 1, 0.3, 1),
    border-color 0.25s ease,
    box-shadow 0.3s ease;
}

.pillar-card:hover {
  transform: translateY(-6px);
  border-color: var(--accent, var(--accent-blue));
  box-shadow: 0 20px 40px -24px var(--shadow-color);
}

.pillar-card h3 {
  color: var(--text-primary);
}

.pillar-card p {
  flex: 1;
}

.pillar-card .card-link {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  color: var(--accent, var(--accent-blue));
}

.pillar-card .card-link i,
.pillar-card .card-link svg {
  transition: transform 0.25s ease;
}

.pillar-card:hover .card-link i,
.pillar-card:hover .card-link svg {
  transform: translateX(4px);
}

/* =========================
   Phone mockup + placeholder screenshots
   ========================= */

.phone-frame {
  position: relative;
  width: 100%;
  max-width: 260px;
  /* Prevents flex/grid containers (e.g. .home-phones, three of these in a
     row) from shrinking each frame down to near-nothing while resolving
     width:100% against the full row — max-width above still caps the size. */
  flex-shrink: 0;
  aspect-ratio: 1080 / 2239; /* matches the real screenshots (source files are 2160x4472-4498, ~0.48 ratio) */
  border-radius: 34px;
  overflow: hidden;
  background: var(--surface);
  border: 1px solid var(--border);
  box-shadow: 0 30px 60px -20px var(--shadow-color);
  /*
    --tilt-base-rotate/--tilt-base-y hold each frame's static fanned-out
    offset (set per nth-child on the Home hero, see pages.css); --tilt-x/
    --tilt-y are written by motion.js's pointer-driven hero tilt and default
    to 0 everywhere else, so this composes safely on every page.
  */
  transform: perspective(900px) rotate(var(--tilt-base-rotate, 0deg))
    translateY(var(--tilt-base-y, 0px)) rotateX(var(--tilt-x, 0deg))
    rotateY(var(--tilt-y, 0deg));
  transition: transform 0.4s cubic-bezier(0.16, 1, 0.3, 1);
}

.phone-frame img.phone-shell {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/*
  Dark/light screenshot swap — same specificity-safe pattern as .logo-img:
  visibility lives only on the plain .phone-shell--dark/--light classes, never
  compounded with an element or size selector, so a sizing/positioning rule
  can never outrank it (that mismatch was the root cause of the logo bug).
*/
.phone-shell--light {
  display: none;
}

:root[data-theme="light"] .phone-shell--dark {
  display: none;
}

:root[data-theme="light"] .phone-shell--light {
  display: block;
}

.phone-placeholder {
  position: absolute;
  inset: 6%;
  border-radius: 24px;
  background: linear-gradient(
    160deg,
    var(--surface-2),
    var(--accent-blue-soft)
  );
  border: 1px dashed var(--border);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
  text-align: center;
  padding: 20px;
}

.phone-placeholder svg {
  width: 36px;
  height: 36px;
  color: var(--accent-blue);
}

.phone-placeholder span {
  font-size: 0.8rem;
  font-weight: 600;
  color: var(--text-secondary);
}

/* =========================
   Social proof strip
   ========================= */

.social-proof {
  display: inline-flex;
  flex-wrap: nowrap; /* a pill shape should never wrap mid-content */
  align-items: center;
  gap: 12px;
  padding: 10px 18px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
}

/*
  Rather than chase an exact "wraps at Npx" breakpoint (font-loading and
  text-size settings shift where content stops fitting), drop the label at
  a deliberately generous width where avatars/stars alone are guaranteed to
  fit regardless of font. The label reappearing above this point is the
  only thing that needs to track real content width.
*/
@media (max-width: 480px) {
  .proof-label {
    display: none;
  }
}

/*
  .home-proof-section's copy ("Joined by people who'd rather discuss than
  scroll") is much longer than the other .social-proof instances ("Our
  happy users", "Loved by our early users") — measured, it re-wraps onto a
  second line internally (not caught by flex-wrap:nowrap, which only stops
  the avatar-row/label from separating, not text wrapping within the label
  itself) from ~481px up to ~520px, before there's enough room. Using the
  same generous-buffer approach as the 480px cutoff above (safety margin
  over the measured wrap-resolves point, not the point itself, so font-load
  differences don't reopen this), this instance keeps its label hidden a
  good deal further before it's confident there's room.
*/
@media (max-width: 640px) {
  .home-proof-section .proof-label {
    display: none;
  }
}

.avatar-row {
  display: flex;
  align-items: center;
}

.avatar-row .avatar {
  width: 32px;
  height: 32px;
  border-radius: 50%;
  border: 2px solid var(--bg);
  margin-left: -10px;
  overflow: hidden;
  background: var(--surface);
}

.avatar-row .avatar:first-child {
  margin-left: 0;
}

.avatar-row .avatar img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.rating-stars {
  display: inline-flex;
  gap: 2px;
  color: var(--accent-gold);
}

.rating-stars svg {
  width: 16px;
  height: 16px;
}

/* =========================
   Comparison tables
   ========================= */

.table-scroll {
  overflow-x: auto;
  border-radius: 18px;
  border: 1px solid var(--border);
}

.compare-table {
  width: 100%;
  border-collapse: collapse;
  min-width: 480px;
  background: var(--surface);
}

.compare-table th,
.compare-table td {
  text-align: left;
  padding: 16px 20px;
  border-bottom: 1px solid var(--border);
  font-size: 0.95rem;
}

.compare-table thead th {
  color: var(--text-primary);
  font-size: 1rem;
  background: var(--surface-2);
}

.compare-table tbody th {
  color: var(--text-primary);
  font-weight: 600;
  white-space: nowrap;
}

.compare-table td {
  color: var(--text-secondary);
}

.compare-table tbody tr:last-child th,
.compare-table tbody tr:last-child td {
  border-bottom: none;
}

/* =========================
   Steps list (e.g. Aware Circle)
   ========================= */

.step-list {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.step-item {
  display: flex;
  gap: 20px;
  align-items: flex-start;
}

.step-number {
  flex-shrink: 0;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-weight: 700;
  background: var(--accent-soft, var(--accent-blue-soft));
  color: var(--accent, var(--accent-blue));
}

.step-item h3 {
  margin-bottom: 4px;
  color: var(--text-primary);
}

/* =========================
   Accordion / FAQ (native details/summary)
   ========================= */

.faq-list {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.faq-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 14px;
  padding: 4px 20px;
}

.faq-item summary {
  cursor: pointer;
  list-style: none;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 18px 0;
  font-weight: 600;
  color: var(--text-primary);
}

.faq-item summary::-webkit-details-marker {
  display: none;
}

.faq-item summary .chevron {
  flex-shrink: 0;
  width: 18px;
  height: 18px;
  transition: transform 0.25s ease;
  color: var(--text-secondary);
}

.faq-item[open] summary .chevron {
  transform: rotate(180deg);
}

.faq-item .faq-answer {
  padding: 0 0 20px;
  color: var(--text-secondary);
  line-height: 1.6;
}

/* =========================
   Forms
   ========================= */

.form-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.form-field label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-secondary);
}

.form-field input,
.form-field textarea {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 13px 16px;
  color: var(--text-primary);
  transition: border-color 0.2s ease;
}

.form-field input:focus,
.form-field textarea:focus {
  border-color: var(--accent-blue);
}

.form-field textarea {
  resize: vertical;
  min-height: 110px;
}

.form-field.invalid input,
.form-field.invalid textarea {
  border-color: #ef4444;
}

.form-status {
  font-size: 0.9rem;
  font-weight: 600;
  min-height: 1.2em;
}

.form-status[data-state="success"] {
  color: var(--accent-teal);
}

.form-status[data-state="error"] {
  color: #ef4444;
}

/* Inline newsletter form */
.newsletter-form form {
  display: flex;
  gap: 10px;
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 6px;
}

.newsletter-form input {
  flex: 1;
  background: transparent;
  border: none;
  padding: 10px 16px;
  color: var(--text-primary);
  min-width: 0;
}

.newsletter-form input:focus-visible {
  outline: none;
}

.newsletter-form button {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--accent-blue);
  color: #fff;
  padding: 11px 20px;
  border-radius: 999px;
  font-weight: 600;
  flex-shrink: 0;
}

.newsletter-form button:hover {
  background: var(--accent-blue-strong);
}

.newsletter-form .form-status {
  margin-top: 10px;
}

@media (max-width: 480px) {
  .newsletter-form form {
    flex-direction: column;
    border-radius: 16px;
  }
  .newsletter-form button {
    justify-content: center;
  }
}

/* =========================
   Footer
   ========================= */

.site-footer {
  background: var(--bg-alt);
  border-top: 1px solid var(--border);
  padding: 72px 0 32px;
}

.footer-grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr 1.3fr;
  gap: 40px;
  padding-bottom: 48px;
  border-bottom: 1px solid var(--border);
}

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

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

.footer-logo .logo-img {
  width: 190px;
  height: 31px; /* DO NOT CHANGE THIS VALUE AGAIN */
  margin-bottom: 16px;
}

.footer-desc {
  max-width: 320px;
  margin-bottom: 20px;
}

.footer-social {
  display: flex;
  gap: 12px;
}

.footer-social a {
  width: 38px;
  height: 38px;
  border-radius: 50%;
  background: var(--surface-2);
  border: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: all 0.2s ease;
}

.footer-social a:hover {
  border-color: var(--accent-blue);
  transform: translateY(-2px);
}

.footer-social img {
  width: 16px;
  height: 16px;
}

.footer-col-title {
  font-weight: 700;
  color: var(--text-primary);
  margin-bottom: 16px;
  font-size: 0.95rem;
}

.footer-links {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.footer-links a {
  color: var(--text-secondary);
  transition: color 0.2s ease;
}

.footer-links a:hover {
  color: var(--text-primary);
}

.footer-newsletter-desc {
  margin-bottom: 16px;
}

.footer-bottom {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  padding-top: 32px;
}

.footer-copy {
  color: var(--text-muted);
  font-size: 0.85rem;
}

.footer-download {
  display: flex;
  align-items: center;
  gap: 16px;
}

.footer-download-label {
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--text-secondary);
}

.footer-download-badges {
  display: flex;
  gap: 12px;
}

/*
  Real HTML (icon + text) instead of pre-styled store badge images, so both
  themes are handled by the site's own color tokens with no second asset to
  source per theme. Shared by .footer-download-badges (all pages) and
  .download-badges (download.html hero) — each container only sets its own
  layout (gap/wrap/margin), this is the actual badge itself. Height/padding
  are tuned to land at the ~40px total height the old image badges had, so
  neither container's row height shifted when this replaced them.
*/
.store-badge {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 8px 16px;
  border-radius: 10px;
  border: 1px solid var(--border);
  background: var(--surface-2);
  transition:
    border-color 0.2s ease,
    transform 0.15s ease;
}

.store-badge:hover {
  border-color: var(--accent-blue);
}

.store-badge:active {
  transform: scale(0.97);
}

.store-badge-icon {
  width: 22px;
  height: 22px;
  object-fit: contain;
  flex-shrink: 0;
  /*
    Source icons (assets/images/google-playstore-icon.png,
    apple-appstore-icon.png) are solid black on a transparent background —
    confirmed by pixel inspection (single RGB value among all non-fully-
    transparent pixels in both files, anti-aliased edges only, no gradient/
    multi-color content) before relying on this filter trick. Default (dark
    theme) inverts pure black to pure white; light theme keeps the original
    black.
  */
  filter: brightness(0) invert(1);
}

:root[data-theme="light"] .store-badge-icon {
  filter: none;
}

.store-badge-text {
  display: flex;
  flex-direction: column;
  line-height: 1.15;
}

.store-badge-eyebrow {
  font-size: 0.6rem;
  font-weight: 500;
  color: var(--text-secondary);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

.store-badge-name {
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--text-primary);
}

/* =========================
   Scroll reveal
   ========================= */

/*
  Hidden-until-revealed state is scoped under html.js (set by a synchronous
  inline script in <head>, alongside the theme bootstrap) so content is
  visible by default when JavaScript never runs — the reveal animation is a
  progressive enhancement, not a requirement for content to appear.
*/
/*
  A `transition` shorthand match always replaces another rule's shorthand
  outright rather than merging with it (same-specificity + later in the
  file, so this always wins over e.g. .pillar-card's own transition) — so
  this list has to carry every property anything tagged [data-reveal] might
  need to transition (hover box-shadow/border-color, theme color cross-fade
  from theme.css), not just the reveal-animation's own opacity/transform.
*/
[data-reveal] {
  transition:
    opacity 0.7s ease,
    transform 0.7s ease,
    background-color 0.25s ease,
    border-color 0.25s ease,
    color 0.25s ease,
    box-shadow 0.3s ease;
}

html.js [data-reveal]:not(.is-visible) {
  opacity: 0;
  transform: translateY(28px);
}

[data-reveal].is-visible {
  opacity: 1;
  transform: none;
}

/*
  Group children use the separate `translate` property (not `transform`)
  for their slide-in offset. translate/rotate/scale compose independently
  from transform, so a child that needs its own transform for something
  else (e.g. .phone-frame's fanned rotation + pointer tilt on the Home
  hero) never gets clobbered by this rule stomping "transform: none" over
  it — which is exactly what happened before this was split out.
*/
[data-reveal-group] > * {
  transition:
    opacity 0.7s ease,
    translate 0.7s ease,
    background-color 0.25s ease,
    border-color 0.25s ease,
    color 0.25s ease,
    box-shadow 0.3s ease;
}

html.js [data-reveal-group]:not(.is-visible) > * {
  opacity: 0;
  translate: 0 20px;
}

[data-reveal-group].is-visible > * {
  opacity: 1;
  translate: 0 0;
  /* per-child transition-delay is computed and set inline by
     animations.js (60-90ms apart, capped so large groups still finish
     within ~500ms) — see revealGroup() there. */
}

/* =========================
   Page transition (nav content-swap)
   ========================= */

/*
  Two-phase, asymmetric transition: a quick ease-in fade+shift out
  (.is-leaving), then the swapped-in content settles back with a slower,
  spring-flavoured ease-out — reads as one continuous motion rather than
  two separate steps. See nav.js's swapContent().
*/
#app-view {
  transition:
    opacity 0.32s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.32s cubic-bezier(0.16, 1, 0.3, 1);
}

#app-view.is-leaving {
  transition:
    opacity 0.16s cubic-bezier(0.4, 0, 1, 1),
    transform 0.16s cubic-bezier(0.4, 0, 1, 1);
  opacity: 0;
  transform: translateY(10px);
}

#app-view.is-entering {
  opacity: 0;
  transform: translateY(10px);
}
