/* Dune Apps — light SaaS system (Sep 2026).
   Off-white ground, white cards with generous radii, deep teal as the
   primary, lime as the accent, near-black headings on grey body copy.
   Floating pill navbar. */

:root {
  --bg:        #F1F3F5;   /* page ground, very light grey */
  --bg-2:      #EAEDEF;   /* alternate bands */
  --card:      #FFFFFF;   /* cards, nav, panels */
  --text:      #0E1315;   /* headings, near-black */
  --muted:     #59666A;   /* body copy */
  --faint:     #8B979B;   /* meta */
  --line:      #E1E5E8;   /* hairlines */
  --line-2:    #CFD6DA;
  --teal:      #1A4B44;   /* primary dark */
  --teal-2:    #123932;
  --lime:      #C3F04C;   /* accent */
  --lime-2:    #B2E43A;
  --radius:    24px;
  --radius-sm: 16px;
  --sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono: "JetBrains Mono", ui-monospace, "SF Mono", Menlo, monospace;
}

* { margin: 0; padding: 0; box-sizing: border-box; }
html { scroll-behavior: smooth; }

body {
  background: var(--bg);
  color: var(--muted);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

.wrap { width: min(1240px, calc(100% - 48px)); margin-inline: auto; }
h1, h2, h3, h4 { color: var(--text); font-weight: 600; letter-spacing: -.03em; line-height: 1.08; }
a { color: var(--text); }

/* ---------- Floating pill navbar ---------- */
header { position: sticky; top: 0; z-index: 60; padding: 18px 0; }
header .bar {
  display: flex; align-items: center; justify-content: space-between;
  background: var(--card); border-radius: 999px; padding: 12px 12px 12px 26px;
  box-shadow: 0 2px 18px rgba(14,19,21,.06);
  transition: box-shadow .25s ease;
}
header.stuck .bar { box-shadow: 0 8px 30px rgba(14,19,21,.10); }

.brand { display: inline-flex; align-items: center; gap: 12px; text-decoration: none;
  color: var(--text); font-weight: 600; font-size: 1.24rem; letter-spacing: -.03em; }
.brand .mark {
  width: 38px; height: 38px; border-radius: 50%; flex: 0 0 auto;
  background: url("data:image/svg+xml,%3Csvg%20xmlns%3D%27http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%27%20viewBox%3D%270%200%2040%2040%27%3E%3Cdefs%3E%3CclipPath%20id%3D%27d%27%3E%3Ccircle%20cx%3D%2720%27%20cy%3D%2720%27%20r%3D%2719%27%2F%3E%3C%2FclipPath%3E%3C%2Fdefs%3E%3Ccircle%20cx%3D%2720%27%20cy%3D%2720%27%20r%3D%2719%27%20fill%3D%27%23EFF3F1%27%2F%3E%3Cg%20clip-path%3D%27url%28%23d%29%27%3E%3Ccircle%20cx%3D%2713%27%20cy%3D%2713%27%20r%3D%275%27%20fill%3D%27%23C3F04C%27%2F%3E%3Cpath%20d%3D%27M13%2041%20L41%2041%20L41%2025%20C%2034%2025.8%2027.5%2028.8%2022%2033.8%20L13%2041%20Z%27%20fill%3D%27%239DB8B2%27%2F%3E%3Cpath%20d%3D%27M-1%2041%20L-1%2029.4%20C%208%2028.6%2015.2%2025.8%2020.4%2021%20C%2021.6%2019.9%2022.9%2019.9%2024%2021.1%20C%2028%2025.4%2033.4%2029%2041%2030.8%20L41%2041%20Z%27%20fill%3D%27%231A4B44%27%2F%3E%3C%2Fg%3E%3C%2Fsvg%3E") center/cover no-repeat;
}

nav.site-nav { display: flex; align-items: center; gap: 34px; }
nav.site-nav a { color: var(--text); text-decoration: none; font-size: .98rem; font-weight: 450;
  transition: color .18s ease; }
nav.site-nav a:hover { color: var(--teal); }

/* ---------- Buttons: teal pill with a lime dot, per the reference ---------- */
.btn {
  display: inline-flex; align-items: center; gap: 12px;
  font-size: .98rem; font-weight: 500; text-decoration: none;
  padding: 9px 26px 9px 9px; border-radius: 999px; border: 1px solid transparent;
  transition: transform .18s ease, background .18s ease, box-shadow .18s ease;
  white-space: nowrap;
}
.btn::before {
  content: ''; width: 34px; height: 34px; border-radius: 50%; flex: 0 0 auto;
  background: var(--lime);
  background-image: radial-gradient(circle at 50% 50%, var(--teal) 3px, transparent 3.5px);
}
.btn:hover { transform: translateY(-2px); }
/* Lime is the primary call to action and teal the secondary — the
   reference has them this way round. */
.btn-primary { background: var(--lime); color: var(--teal); font-weight: 600;
  box-shadow: 0 6px 18px rgba(195,240,76,.34); }
.btn-primary::before { background: var(--teal);
  background-image: radial-gradient(circle at 50% 50%, var(--lime) 3px, transparent 3.5px); }
.btn-primary:hover { background: var(--lime-2); }
.btn-dark { background: var(--teal); color: #fff; }
.btn-light { background: var(--card); color: var(--text); box-shadow: 0 2px 14px rgba(14,19,21,.07); }
.btn-sm { padding: 6px 20px 6px 6px; font-size: .9rem; }
.btn-sm::before { width: 28px; height: 28px; }
.btn-plain::before { display: none; }
.btn-plain { padding: 13px 26px; }

/* ---------- Eyebrow ---------- */
.eyebrow {
  display: inline-flex; align-items: center; gap: 10px;
  font-size: .82rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--teal); font-weight: 500;
}
.eyebrow::before, .eyebrow::after {
  content: ''; width: 22px; height: 1px; background: var(--line-2);
}

/* ---------- Sections ---------- */
.section { padding: 104px 0; position: relative; }
.section-head { max-width: 720px; }
.section-head h2 { font-size: clamp(2.1rem, 4.4vw, 3.2rem); margin: 20px 0 0; }
.section-head p { margin-top: 18px; font-size: 1.07rem; }
.center { text-align: center; margin-inline: auto; }

/* ---------- Cards ---------- */
.card {
  background: var(--card); border-radius: var(--radius); padding: 32px;
  box-shadow: 0 2px 16px rgba(14,19,21,.05);
  transition: transform .22s ease, box-shadow .22s ease;
}
.card:hover { transform: translateY(-4px); box-shadow: 0 14px 36px rgba(14,19,21,.09); }
.card h3 { font-size: 1.3rem; margin-bottom: 10px; }
.card p { font-size: 1rem; }

.grid { display: grid; gap: 22px; }
.g-2 { grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); }
.g-3 { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }
.g-4 { grid-template-columns: repeat(auto-fit, minmax(215px, 1fr)); }

/* ---------- Assurance row + rating ---------- */
.assurances { display: flex; gap: 26px; justify-content: center; flex-wrap: wrap; margin-top: 26px; }
.assurances span { display: inline-flex; align-items: center; gap: 9px;
  color: var(--muted); font-size: .96rem; }
.assurances span::before { content: ''; width: 7px; height: 7px; border-radius: 50%;
  background: var(--line-2); }
.rating { display: inline-flex; align-items: center; gap: 11px; margin-top: 22px; }
.rating .stars { color: var(--teal); letter-spacing: 2px; font-size: 1.05rem; }
.rating .txt { color: var(--text); font-weight: 500; }

/* ---------- Marquee ---------- */
.marquee-wrap { overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent); }
.marquee { display: flex; gap: 56px; width: max-content; animation: slide 34s linear infinite; }
.marquee span { color: var(--faint); font-size: 1.06rem; white-space: nowrap; }
@keyframes slide { to { transform: translateX(-50%); } }
.marquee-wrap:hover .marquee { animation-play-state: paused; }

/* ---------- Footer ---------- */
footer { background: var(--teal); color: rgba(255,255,255,.72); padding: 70px 0 34px;
  border-radius: 40px 40px 0 0; margin-top: 40px; }
footer h4 { color: #fff; font-size: .78rem; letter-spacing: .12em; text-transform: uppercase;
  margin-bottom: 16px; font-weight: 500; opacity: .6; }
footer a { display: block; color: rgba(255,255,255,.78); text-decoration: none;
  margin-bottom: 10px; font-size: .98rem; }
footer a:hover { color: var(--lime); }
footer .brand { color: #fff; }
footer .cols { display: grid; gap: 36px; grid-template-columns: 1.7fr 1fr 1fr 1fr; }
footer .disclosure { color: rgba(255,255,255,.5); font-size: .88rem; margin-top: 40px;
  padding-top: 26px; border-top: 1px solid rgba(255,255,255,.14); }
@media (max-width: 760px) { footer .cols { grid-template-columns: 1fr 1fr; } }

/* ---------- Prose ---------- */
.post { max-width: 730px; margin: 60px auto 96px; }
.post h1 { font-size: clamp(2.1rem, 4.6vw, 3.1rem); }
.post h2 { font-size: 1.55rem; margin: 46px 0 14px; }
.post p { margin-bottom: 22px; font-size: 1.1rem; line-height: 1.75; }
.post .byline { font-size: .92rem; color: var(--faint); margin: 16px 0 36px; }
.post blockquote { border-left: 3px solid var(--lime); padding-left: 22px; margin: 32px 0;
  color: var(--text); font-size: 1.14rem; }
.post code { font-family: var(--mono); font-size: .9em; background: var(--card);
  border: 1px solid var(--line); border-radius: 6px; padding: 2px 6px; color: var(--teal); }
.post a { color: var(--teal); }
.back { display: inline-block; margin-top: 40px; color: var(--muted); text-decoration: none; }
.back:hover { color: var(--teal); }

/* ---------- Reveals ---------- */
.js .reveal { opacity: 0; transform: translateY(18px); transition: opacity .6s ease, transform .6s ease; }
.js .reveal.in { opacity: 1; transform: none; }

.skip { position: absolute; left: -9999px; top: 0; background: var(--lime); color: var(--teal);
  padding: 12px 18px; border-radius: 0 0 10px 0; z-index: 100; font-weight: 600; text-decoration: none; }
.skip:focus { left: 0; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal { opacity: 1; transform: none; transition: none; }
  .marquee { animation: none; }
  .btn:hover, .card:hover { transform: none; }
}

/* The nav had no responsive rule at all: on a phone the brand wrapped to two
   lines and the call to action was clipped off the right edge. Most App Store
   traffic is a phone, so that was the header nearly every visitor saw.
   Below 760px the text links collapse and the one button survives. */
@media (max-width: 760px) {
  nav.site-nav { gap: 12px; }
  nav.site-nav a:not(.btn) { display: none; }
  .bar { gap: 12px; }
  .brand span:last-child { white-space: nowrap; }
}

/* ---- Mobile hero: the reason the site was cut off on a phone ----
   .phones is a flex row of three 205px images: 3*205 + 2*18 = 651px of hard
   minimum width. Neither flex nor grid items shrink below their content, so
   that minimum propagated up through the 1fr hero column and pinned the whole
   layout at 702px on a 390px screen. body{overflow-x:hidden} then clipped the
   headline mid-word rather than letting anything reflow — and because it also
   makes scrollWidth equal clientWidth, no overflow check could find it. It had
   to be measured inside a real 390px viewport.

   Specificity is raised one step on purpose: every page's inline <style> is
   emitted after this file, so an equal-specificity rule here would lose. */
@media (max-width: 980px) {
  .hero .split > * { min-width: 0; }
}
@media (max-width: 700px) {
  .hero .visual { min-height: 0; }
  .hero .phones { gap: 0; padding: 14px 0; min-width: 0; }
  /* One phone reads at this size; three become thumbnails. Applies to the
     product pages, which still use the three-phone row; the homepage hero is
     a single device carousel and sizes itself. */
  .hero .phones img { width: min(62vw, 250px); }
  .hero .phones img:first-child,
  .hero .phones img:last-child { display: none; }
  .hero .stage { min-width: 0; }
  .hero .bubble { width: 430px; height: 430px; right: -36%; }
}

/* The comparison table ran 429px wide on a 390px phone: 20px/24px cell padding
   across three columns is ~144px of the width spent on air. Trimming it fits
   the table without making it scroll sideways, which is worse to read on the
   one page whose whole job is a side-by-side. `body` prefix only to outrank
   the page's own inline <style>, which loads after this file. */
@media (max-width: 700px) {
  body table.cmp th,
  body table.cmp td { padding: 12px 10px; font-size: .93rem; }
  body table.cmp thead th { font-size: .68rem; letter-spacing: .04em; }
}


/* ==========================================================================
   Craft layer — motion, depth, focus. Added 12 Sep 2026.
   Tokens live here so every page inherits one rhythm instead of each page
   inventing its own durations. Guidance from ui-ux-pro-max: reveal offsets
   stay 8-16px so the motion reads as a fade rather than a slide, per-item
   stagger stays 30-60ms, and exits are shorter than entrances.
   ========================================================================== */
:root {
  /* Deceleration on arrival, which is what almost every entrance wants. */
  --ease-out:    cubic-bezier(.22,.61,.36,1);
  --ease-spring: cubic-bezier(.34,1.32,.64,1);
  --t-fast: .16s;
  --t-mid:  .28s;
  --t-slow: .42s;
  /* One elevation ladder, so a card and a header cannot disagree about depth. */
  --e1: 0 1px 2px rgba(14,19,21,.04), 0 2px 8px rgba(14,19,21,.05);
  --e2: 0 2px 6px rgba(14,19,21,.05), 0 12px 28px rgba(14,19,21,.07);
  --e3: 0 10px 22px rgba(14,19,21,.08), 0 30px 64px rgba(14,19,21,.10);
}

/* Anchor links landed under the floating header; reserve its height. */
:where(section, h2, h3)[id] { scroll-margin-top: 104px; }

/* Short headings look broken when one word drops alone onto the last line.
   Progressive: browsers without it just wrap normally. */
h1, h2, .stage-cap { text-wrap: balance; }

/* --- Reveal ---------------------------------------------------------------
   18px read as a slide. 12px reads as the content settling. */
.js .reveal {
  opacity: 0;
  transform: translateY(12px);
  transition: opacity var(--t-slow) var(--ease-out),
              transform var(--t-slow) var(--ease-out);
}
.js .reveal.in { opacity: 1; transform: none; }

/* Row stagger with no markup change: cards are already individually .reveal,
   so a sibling delay inside a grid turns a simultaneous pop into a sweep. */
.js .grid > .reveal:nth-child(2),
.js .cols > .reveal:nth-child(2) { transition-delay: 60ms; }
.js .grid > .reveal:nth-child(3),
.js .cols > .reveal:nth-child(3) { transition-delay: 120ms; }
.js .grid > .reveal:nth-child(4) { transition-delay: 180ms; }
.js .grid > .reveal:nth-child(5) { transition-delay: 220ms; }
.js .grid > .reveal:nth-child(6) { transition-delay: 260ms; }

/* --- Interaction ---------------------------------------------------------- */
.btn {
  transition: transform var(--t-fast) var(--ease-spring),
              background var(--t-fast) ease,
              box-shadow var(--t-fast) ease;
}
/* nav.site-nav a (0,1,2) outranks .btn (0,1,0), so the header's own button
   was the one control on the page with no press feedback. */
nav.site-nav a.btn {
  transition: transform var(--t-fast) var(--ease-spring),
              background var(--t-fast) ease,
              box-shadow var(--t-fast) ease;
}
.btn:hover { transform: translateY(-2px); box-shadow: var(--e2); }
/* Press must return to rest, not overshoot — it is a confirmation, not a bounce. */
.btn:active { transform: translateY(0) scale(.985); transition-duration: 80ms; }

.card { transition: transform var(--t-mid) var(--ease-out),
                    box-shadow var(--t-mid) var(--ease-out); }
.card:hover { transform: translateY(-4px); box-shadow: var(--e3); }

/* --- Focus ----------------------------------------------------------------
   There were no focus styles on anything but the skip link, so a keyboard
   user had no idea where they were. :focus-visible keeps it off mouse clicks. */
:where(a, button, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--teal);
  outline-offset: 3px;
  border-radius: 6px;
}
.btn:focus-visible { outline-offset: 4px; }

@media (prefers-reduced-motion: reduce) {
  .js .reveal,
  .js .grid > .reveal,
  .js .cols > .reveal { opacity: 1; transform: none; transition: none; transition-delay: 0s; }
  .btn:hover, .btn:active, .card:hover { transform: none; }
}
