/* Kivun marketing landing page - design tokens (values verified against
   DESIGN.md, tailwind.config.js and src/components/categoryIcons.tsx -
   do not hand-tweak these without checking those three files agree).
   Visual language deliberately restrained: one confident hero moment
   (big type + one elevated/glowing card), generous space, motion that
   plays once and never loops - not a pile of small floating/pulsing
   effects. This matches the direction the owner's other products
   (DoneRaise in particular) converged on after their own first,
   effect-heavy drafts were rejected the same way this one was. */
:root {
  --bg: #F5F6FB;
  --surface: #FFFFFF;
  --line: #ECEEF6;
  --ink: #181C2B;
  --muted: #5F6578;
  --brand: #285ABC;
  --brand-2: #3B7BFF;
  --brand-3: #173A82;
  --gold: #EFA636;
  --gold-tint: #FDECCB;
  --gold-tint-ink: #8A5A0D;
  --chabad: #5B5EF2;
  --roshchodesh: #3AA6E0;
  --shabbat: #14B8A6;
  --parasha: #7C53D6;
  --user: #FF5D8F;
  --birthday: #F2994A;
  --radius-card: 1.25rem;
  --radius-hero: 1.875rem;
  --radius-btn: 0.75rem;
  --glow-brand: 0 10px 25px rgba(40,90,188,.32);
  --glow-brand-lg: 0 22px 50px rgba(40,90,188,.28);
}

* { box-sizing: border-box; margin: 0; padding: 0; }

/* overflow-x:hidden is a safety net, not a fix for a specific bug - several
   entrance animations (relate-list fly-in, hero card bleed) intentionally
   start elements translated past their own box before they're revealed,
   which can otherwise create a few px of real horizontal scroll on first
   paint. This clips that without touching any animation's actual values. */
html { scroll-behavior: smooth; overflow-x: hidden; }

body {
  background: var(--bg);
  color: var(--ink);
  font-family: "Assistant", system-ui, sans-serif;
  font-size: 16px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3 { font-family: "Frank Ruhl Libre", Georgia, serif; font-weight: 800; line-height: 1.2; }

img { max-width: 100%; display: block; }

.wrap { max-width: 68rem; margin: 0 auto; padding: 0 1.25rem; }

/* unicode-range keeps the Hebrew and Latin subsets of each family from
   fighting over the same characters now that both are loaded (index.html
   uses the Hebrew ones, index.en.html uses the Latin ones, but the CSS file
   is shared) - without it, an @font-face with no unicode-range matches every
   codepoint, and which of two same-family/weight rules "wins" for a given
   character is undefined. Values copied verbatim from @fontsource's own
   combined stylesheets (node_modules/@fontsource/assistant/400.css and
   .../frank-ruhl-libre/800.css), not invented. */
@font-face {
  font-family: "Assistant";
  src: url("fonts/assistant-hebrew-400-normal.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0307-0308,U+0590-05FF,U+200C-2010,U+20AA,U+25CC,U+FB1D-FB4F;
}
@font-face {
  font-family: "Assistant";
  src: url("fonts/assistant-hebrew-600-normal.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
  unicode-range: U+0307-0308,U+0590-05FF,U+200C-2010,U+20AA,U+25CC,U+FB1D-FB4F;
}
@font-face {
  font-family: "Assistant";
  src: url("fonts/assistant-hebrew-700-normal.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
  unicode-range: U+0307-0308,U+0590-05FF,U+200C-2010,U+20AA,U+25CC,U+FB1D-FB4F;
}
@font-face {
  font-family: "Assistant";
  src: url("fonts/assistant-latin-400-normal.woff2") format("woff2");
  font-weight: 400; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Assistant";
  src: url("fonts/assistant-latin-600-normal.woff2") format("woff2");
  font-weight: 600; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Assistant";
  src: url("fonts/assistant-latin-700-normal.woff2") format("woff2");
  font-weight: 700; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face {
  font-family: "Frank Ruhl Libre";
  src: url("fonts/frank-ruhl-libre-hebrew-800-normal.woff2") format("woff2");
  font-weight: 800; font-style: normal; font-display: swap;
  unicode-range: U+0307-0308,U+0590-05FF,U+200C-2010,U+20AA,U+25CC,U+FB1D-FB4F;
}
@font-face {
  font-family: "Frank Ruhl Libre";
  src: url("fonts/frank-ruhl-libre-latin-800-normal.woff2") format("woff2");
  font-weight: 800; font-style: normal; font-display: swap;
  unicode-range: U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
/* Poppins ExtraBold is the real wordmark font (DESIGN.md: "הכיתוב 'Kivun'
   בגופן Poppins ExtraBold") - loaded here purely for this one header word.
   It's deliberately NOT bundled into the app itself (the app's own
   wordmark is a pre-rendered PNG, see src/assets/logo.png), so this is the
   one place on the whole site that self-hosts it, sourced the same way as
   the other two fonts (copied from @fontsource, not a CDN). */
@font-face {
  font-family: "Poppins";
  src: url("fonts/poppins-latin-800-normal.woff2") format("woff2");
  font-weight: 800; font-style: normal; font-display: swap;
}

/* header - dark glass, sits over the dark hero at page-load and stays
   consistent (as a permanent premium chrome) as the page scrolls into
   lighter sections below. */
.site-header { position: sticky; top: 0; z-index: 20; background: rgba(24,28,43,.82); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); border-bottom: 1px solid rgba(255,255,255,.08); }
.header-row { display: flex; align-items: center; justify-content: space-between; padding: .75rem 1.25rem; }
.brand { display: flex; align-items: center; gap: .5rem; text-decoration: none; color: #fff; }
.brand-name { font-family: "Poppins", sans-serif; font-weight: 800; font-size: 1.2rem; letter-spacing: -.02em; }
.header-actions { display: flex; align-items: center; gap: .75rem; }
/* A small bordered pill, not plain text - without its own shape the language
   link read as a stray, disconnected word wedged between the CTA button and
   the brand wordmark (Pessi's direct feedback on the live site). The pill
   echoes the existing hero .badge treatment, so it reads as an intentional,
   tappable control instead of dim leftover text. */
.lang-switch {
  display: inline-flex; align-items: center;
  color: rgba(255,255,255,.85); font-size: .8rem; font-weight: 600;
  text-decoration: none; border: 1px solid rgba(255,255,255,.3);
  border-radius: 999px; padding: .3rem .75rem;
  transition: background .2s ease, border-color .2s ease;
}
.lang-switch:hover { background: rgba(255,255,255,.08); border-color: rgba(255,255,255,.45); }

/* buttons */
.btn { display: inline-flex; align-items: center; justify-content: center; border-radius: var(--radius-btn); font-weight: 700; text-decoration: none; padding: .7rem 1.3rem; font-size: .95rem; transition: transform .18s ease, box-shadow .25s ease, background .2s ease; }
.btn-primary { background: var(--brand); color: #fff; box-shadow: var(--glow-brand); }
.btn-primary:hover { background: var(--brand-2); box-shadow: var(--glow-brand-lg); transform: translateY(-2px); }
.btn-primary:active { transform: translateY(0) scale(.97); }
.btn-sm { padding: .5rem 1rem; font-size: .85rem; }

.store-row { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.6rem; }
.btn-store {
  display: inline-flex; align-items: center; justify-content: center; gap: .55rem;
  background: var(--brand); color: #fff; border-radius: var(--radius-btn);
  padding: .8rem 1.6rem; font-weight: 700; text-decoration: none; font-size: .95rem;
  box-shadow: var(--glow-brand);
  transition: transform .18s ease, box-shadow .25s ease, background .2s ease;
}
.btn-store:hover { background: var(--brand-2); box-shadow: var(--glow-brand-lg); transform: translateY(-3px); }
.btn-store:active { transform: translateY(-1px) scale(.97); }
/* icon inherits the button's text color via currentColor, so it needs no
   separate override between the dark brand-blue buttons and the white
   .pricing-card variant below - one icon, both backgrounds. */
.btn-store .store-icon { width: 19px; height: 19px; flex: none; }

/* reveal-on-scroll (progressive enhancement, see script.js) */
/* Custom curve, not plain `ease` - this is the entrance motion for every
   section on the page (how-cards, FAQ, steps, trust, story), so its feel
   sets the page's whole signature; `ease` reads flat next to it. Reuses
   the same cubic-bezier already used for the hero's word-in/card-in
   entrances, so the page has one consistent "arrival" feel, not several. */
.js [data-reveal] { opacity: 0; transform: translateY(16px); transition: opacity .6s cubic-bezier(.16,1,.3,1), transform .6s cubic-bezier(.16,1,.3,1); }
.js [data-reveal].is-revealed { opacity: 1; transform: translateY(0); }

@media (prefers-reduced-motion: reduce) {
  .js [data-reveal] { opacity: 1 !important; transform: none !important; transition: none !important; }
  html { scroll-behavior: auto; }
}

section { padding: 3rem 0; }
.section-title { font-size: 1.6rem; margin-bottom: 1.75rem; text-align: center; }
.section-sub { text-align: center; color: var(--muted); font-size: 1rem; margin-top: -1.25rem; margin-bottom: 1.75rem; }

/* Section-level color rhythm: between the dark hero and the dark
   pricing/final-cta bookends, the middle sections used to sit on one flat
   --bg gray for five sections in a row - correct call to avoid a loud AI-slop
   gradient everywhere, but it read as flat/quiet next to the old page's
   sustained color. Each middle section now carries a soft wash of a real
   category color already meaningful elsewhere on this page (never an
   invented hue), alternating with plain --bg so it reads as rhythm, not
   noise. .story stays plain on purpose - one quiet beat, not six loud ones. */
.relate { background: color-mix(in srgb, #C6433F 6%, var(--bg)); transition: background .5s ease; }
.relate.is-after { background: color-mix(in srgb, #16A34A 7%, var(--bg)); }
.how { background: color-mix(in srgb, var(--gold) 7%, var(--bg)); }
.steps { background: color-mix(in srgb, var(--brand) 6%, var(--bg)); }

/* hero - a real dark "atmosphere" moment (not just a light page with a
   grid texture): deep navy field, two soft color glows, big light type,
   one elevated white card that reads as a genuine floating screenshot
   against the dark field. Entrance plays once and never loops. */
.hero {
  padding: 2rem 0 2rem;
  position: relative;
  background-color: var(--ink);
  background-image:
    linear-gradient(160deg, #232841 0%, var(--ink) 55%, #12141F 100%),
    linear-gradient(rgba(255,255,255,.035) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255,255,255,.035) 1px, transparent 1px);
  background-size: 100% 100%, 72px 72px, 72px 72px;
}
.hero::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(circle at 85% 8%, rgba(59,123,255,.32), transparent 52%),
    radial-gradient(circle at 6% 88%, rgba(139,142,245,.24), transparent 48%),
    radial-gradient(circle at 92% 95%, rgba(239,166,54,.1), transparent 38%);
}
/* the flowing route line + pulsing location dot are the same visual
   signature the real app's own "Today" hero uses (DESIGN.md: "קווי מסלול
   זורמים ברקע ונקודת מיקום פועמת") - porting it here is showing the
   product's own DNA, not inventing new decoration. The line DRAWS itself
   once (stroke-dashoffset, same technique as the route-progress rail
   further down the page), and the dot pulses a *finite* 3 times before
   settling - a real "ping", not one more infinite loop, which the rest of
   this file deliberately avoids (see the top-of-file comment). */
.hero-route { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; z-index: 0; opacity: .55; }
.hero-route-line {
  fill: none; stroke: #6EA0FF; stroke-width: 1.5; stroke-linecap: round;
  stroke-dasharray: 7 11; stroke-dashoffset: 760;
  animation: heroRouteDraw 2.4s cubic-bezier(.16,1,.3,1) .4s forwards;
}
@keyframes heroRouteDraw { to { stroke-dashoffset: 0; } }
.hero-route-dot {
  position: absolute; top: 83%; left: 5%; width: .55rem; height: .55rem;
  border-radius: 50%; background: var(--brand-2); z-index: 0; opacity: 0;
  animation: heroDotIn .4s ease 2.3s forwards, heroDotPulse 1.3s ease-out 2.5s 3 forwards;
}
@keyframes heroDotIn { to { opacity: 1; } }
@keyframes heroDotPulse {
  0% { box-shadow: 0 0 0 0 rgba(59,123,255,.55); }
  70% { box-shadow: 0 0 0 15px rgba(59,123,255,0); }
  100% { box-shadow: 0 0 0 0 rgba(59,123,255,0); }
}

.hero-row { position: relative; display: flex; flex-direction: column; gap: 1.75rem; }

@media (min-width: 760px) {
  .hero-row { gap: 2.75rem; }
}

/* Tighter vertical rhythm below the row breakpoint only - reclaims room
   so the demo card is visible sooner on short phone screens, without
   touching the entrance animation's translateY (that offset is the
   card's deliberate bleed past the hero's dark background, tuned and
   verified separately - see the heroCardIn keyframe below). Desktop
   already has headroom to spare, so it's left untouched. */
@media (max-width: 759px) {
  .hero { padding: 1.5rem 0 2rem; }
  .badge { margin-bottom: .75rem; }
  .hero h1 { margin-bottom: .75rem; }
  .hero-copy .store-row { margin-top: 1.1rem; }
}

.badge {
  display: inline-flex; align-items: center; gap: .35rem; background: var(--surface);
  color: var(--gold-tint-ink); border: 1px solid var(--gold-tint); font-size: .75rem;
  font-weight: 700; padding: .3rem .75rem; border-radius: 999px; margin-bottom: 1rem;
  box-shadow: 0 8px 18px rgba(138,90,13,.14);
  opacity: 0; animation: heroPop .5s cubic-bezier(.34,1.56,.64,1) .1s forwards;
}

.hero h1 { font-size: 2.75rem; letter-spacing: -.01em; line-height: 1.08; margin-bottom: 1rem; overflow: hidden; color: #fff; }
.hero-word { display: inline-block; opacity: 0; filter: blur(6px); transform: translateY(14px); animation: heroWordIn .6s cubic-bezier(.16,1,.3,1) forwards; }
.hero-word-1 { animation-delay: .28s; }
.hero-word-2 {
  animation-delay: .44s;
  background: linear-gradient(90deg, #6EA0FF 0%, #ADAFF7 100%);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}

.hero-sub {
  color: #B7C1E3; font-size: 1.1rem; max-width: 26rem;
  opacity: 0; filter: blur(4px); transform: translateY(14px);
  animation: heroWordIn .6s cubic-bezier(.16,1,.3,1) .62s forwards;
}
.hero-copy .store-row {
  opacity: 0; transform: translateY(14px);
  animation: heroUp .55s ease .78s forwards;
}

/* Entrance animation lives on the WRAPPER (.hero-demo), not on .demo-card
   itself - a finished CSS animation's fill:forwards value permanently
   wins the cascade for that property on that element, which would make
   a later `.demo-card:hover { transform: ... }` rule silently do nothing.
   The card's own rest tilt + hover un-tilt use the standalone `rotate`/
   `translate` properties instead, which are independent of `transform`
   and unaffected by the wrapper's animation. */
.hero-demo { position: relative; }
.hero-demo::before {
  content: ""; position: absolute; inset: 8% 4% -4% 4%; z-index: 0;
  background: var(--brand-2); opacity: .22; filter: blur(48px); border-radius: var(--radius-hero);
}
.hero-demo {
  opacity: 0; transform: translateY(18px) scale(.97); filter: blur(3px);
  animation: heroCardIn .75s cubic-bezier(.16,1,.3,1) .9s forwards;
}

@keyframes heroPop {
  0% { opacity: 0; transform: scale(.85); }
  60% { opacity: 1; transform: scale(1.08); }
  80% { transform: scale(.97); }
  100% { opacity: 1; transform: scale(1); }
}
@keyframes heroWordIn { to { opacity: 1; filter: blur(0); transform: translateY(0); } }
@keyframes heroUp { to { opacity: 1; transform: translateY(0); } }
@keyframes heroCardIn { to { opacity: 1; transform: translateY(48px) scale(1); filter: blur(0); } }
/* Desktop: align-self:flex-end pins .hero-demo's bottom to the row's
   bottom line instead of letting align-items:center float it based on
   the (variable, line-wrap-dependent) height of .hero-copy next to it -
   that variability is what made a fixed transform offset land short at
   some widths and not others. Once the card's baseline position no
   longer depends on the copy column's height, a fixed offset behaves
   the same at every desktop width. */
@media (min-width: 760px) {
  .hero-demo { align-self: flex-end; animation-name: heroCardInDesktop; }
}
@keyframes heroCardInDesktop { to { opacity: 1; transform: translateY(56px) scale(1); filter: blur(0); } }

.demo-card {
  background: var(--surface); border-radius: var(--radius-card);
  box-shadow: 0 34px 60px -18px rgba(21,30,60,.32), 0 0 0 1px rgba(40,90,188,.05);
  overflow: hidden; max-width: 26rem; position: relative; z-index: 1;
  rotate: -1.4deg;
  transition: rotate .35s ease, translate .35s ease, box-shadow .35s ease;
}
.demo-card:hover, .demo-card:active { rotate: 0deg; translate: 0 -6px; box-shadow: 0 40px 74px -16px rgba(21,30,60,.38), 0 0 0 1px rgba(40,90,188,.05); }
.demo-head { display: flex; justify-content: space-between; padding: .9rem 1.1rem; font-size: .75rem; color: var(--muted); border-bottom: 1px solid var(--line); }
.demo-body { padding: .3rem; }
.demo-item { display: flex; align-items: center; gap: .7rem; padding: .7rem 1rem; opacity: 0; animation: kvIn .5s ease forwards; width: 100%; }
.demo-dot { width: 1.9rem; height: 1.9rem; min-width: 1.9rem; border-radius: 50%; display: flex; align-items: center; justify-content: center; transition: background .25s ease, transform .25s ease; }
.demo-text { display: flex; flex-direction: column; font-size: .85rem; text-align: start; }
.demo-text b { font-weight: 700; color: var(--ink); transition: color .25s ease; }
.demo-text span:last-child { font-size: .75rem; color: var(--muted); }

/* the two task rows are real toggle buttons - a small, genuine "try it"
   interaction, not another passive animation. one click, no loop. */
.demo-task { background: none; border: 1px dashed var(--line); font: inherit; cursor: pointer; border-radius: .75rem; margin: 0 .3rem; transition: background .2s ease, border-color .2s ease; }
.demo-task:hover { background: var(--bg); }
.demo-task:focus-visible { outline: 2px solid var(--brand); outline-offset: -2px; }
.demo-task[aria-pressed="true"] { border-color: #16A34A; }
.demo-task[aria-pressed="true"] .demo-dot { background: #16A34A !important; transform: scale(1.08); }
.demo-task[aria-pressed="true"] .demo-text b { color: var(--muted); text-decoration: line-through; }

/* the interactivity hint used to sit below the card, where it's easy to
   scroll past before ever noticing the two task rows are real buttons.
   Moved above the card and turned into a small tag instead of plain text -
   same pink as the task dots it's pointing at, so the connection reads
   instantly. One-time pop-in (shares heroPop with the free-trial badge),
   not a repeating attention-grabber. */
.demo-tip {
  display: inline-flex; align-items: center; gap: .3rem;
  background: var(--user); color: #fff; font-size: .78rem; font-weight: 700;
  padding: .35rem .85rem; border-radius: 999px; margin-bottom: .6rem;
  box-shadow: 0 8px 18px rgba(255,93,143,.35);
  rotate: -3deg;
  opacity: 0; animation: heroPop .5s cubic-bezier(.34,1.56,.64,1) 1.05s forwards;
}

@keyframes kvIn { from { opacity: 0; transform: translateY(6px); } to { opacity: 1; transform: translateY(0); } }

@media (prefers-reduced-motion: reduce) {
  .demo-item { animation: none !important; opacity: 1 !important; }
  .badge, .hero-word, .hero-sub, .hero-copy .store-row, .hero-demo, .demo-tip {
    animation: none !important; opacity: 1 !important; filter: none !important; transform: none !important;
  }
  .demo-card, .demo-card:hover, .demo-card:active { rotate: 0deg !important; translate: none !important; transition: none !important; }
  .step:not(:last-child)::after { transition: none !important; }
  .hero-route-line { animation: none !important; stroke-dashoffset: 0 !important; }
  .hero-route-dot { animation: none !important; opacity: 1 !important; box-shadow: none !important; }
}

@media (min-width: 760px) {
  .hero-row { flex-direction: row; align-items: center; }
  .hero-copy, .hero-demo { flex: 1; }
  .hero h1 { font-size: 3.6rem; }
}

/* relate - a short "does this sound like you" bridge between the hero
   promise and the feature list, in the reader's own language. */

/* before/after toggle - lets a visitor literally flip the pain list from
   chaos to "with Kivun" instead of only reading about the contrast. A
   direct-manipulation click response (like .demo-task elsewhere), not a
   scroll/timer-driven animation, so it isn't gated by prefers-reduced-motion.
   script.js toggles .is-after on the parent <section class="relate">. */
.relate-toggle {
  display: flex; align-items: center; gap: .6rem; margin: 0 auto 1.75rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: 999px;
  padding: .4rem .5rem; font: inherit; cursor: pointer; box-shadow: 0 6px 16px rgba(30,42,68,.06);
  transition: box-shadow .2s ease;
}
.relate-toggle:hover, .relate-toggle:active { box-shadow: 0 10px 22px rgba(30,42,68,.12); }
.relate-toggle:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }
.relate-toggle-label { font-size: .85rem; font-weight: 700; color: var(--muted); padding: 0 .3rem; transition: color .25s ease; }
.relate-toggle[aria-pressed="false"] .relate-toggle-label--before { color: var(--ink); }
.relate-toggle[aria-pressed="true"] .relate-toggle-label--after { color: #16A34A; }
.relate-toggle-track { position: relative; width: 2.6rem; height: 1.5rem; border-radius: 999px; background: var(--line); transition: background .25s ease; flex-shrink: 0; }
.relate-toggle[aria-pressed="true"] .relate-toggle-track { background: #BBF7D0; }
.relate-toggle-thumb {
  position: absolute; top: .15rem; right: .15rem; width: 1.2rem; height: 1.2rem;
  border-radius: 50%; background: var(--surface); box-shadow: 0 2px 6px rgba(0,0,0,.2);
  transition: transform .25s cubic-bezier(.34,1.56,.64,1), background .25s ease;
}
.relate-toggle[aria-pressed="true"] .relate-toggle-thumb { transform: translateX(-1.1rem); background: #16A34A; }
/* Mirrored for LTR (index.en.html) - the rule above is tuned for RTL's
   off=right/on=left motion; without this, the thumb would rest on the wrong
   side and slide backwards (end-to-start) instead of forwards (start-to-end)
   when toggled on under dir="ltr". */
[dir="ltr"] .relate-toggle-thumb { right: auto; left: .15rem; }
[dir="ltr"] .relate-toggle[aria-pressed="true"] .relate-toggle-thumb { transform: translateX(1.1rem); }

/* the list rows themselves: each swaps its before/after text when the
   section carries .is-after (CSS-only). The mark's own ✕/✓ glyph is swapped
   by script.js setting textContent directly, not via a ::before trick -
   .relate-x already carries a real, later, equal-specificity color/background
   rule further down this file, so an earlier ::before-based override here
   would silently lose that cascade fight and double up the glyph. Doing the
   swap in the one place (JS) that already runs on click sidesteps that. */
.relate-after { display: none; }
.relate.is-after .relate-before { display: none; }
.relate.is-after .relate-after { display: inline; }
.relate.is-after .relate-x { background: #DCFCE7; color: #16A34A; }

/* overflow-x:hidden here (not just the existing html-level one) is load-
   bearing, confirmed on a real Android device profile: rows below the fold
   sit in their pre-reveal translateX(±40px) position (correct - they
   haven't scrolled into view yet), and on Chrome's mobile viewport-sizing
   pass that off-screen paint area alone was enough to make the browser
   decide the page needs to be wider than the screen, rendering the ENTIRE
   page zoomed out to fit it - even though html's own overflow-x:hidden
   already existed. Containing it right at the source, not just at the
   document root, is what actually fixed it. */
.relate-list {
  list-style: none; max-width: 34rem; margin: 0 auto; display: flex;
  flex-direction: column; gap: .85rem;
  overflow-x: hidden;
}
.relate-list li {
  display: flex; align-items: center; gap: .75rem;
  background: var(--surface); border: 1px solid var(--line); border-radius: 1rem;
  padding: .85rem 1.1rem; font-size: .98rem; color: var(--ink);
  box-shadow: 0 4px 14px rgba(30,42,68,.05);
  /* `translate`, not `transform` - these items also carry [data-reveal],
     whose one-time entrance uses `transform` (see below); keeping the
     interactive hover/active lift on the standalone property avoids the
     same collision already fixed for .how-card/.faq-item. */
  transition: translate .2s ease, box-shadow .2s ease, border-color .2s ease;
}
.relate-list li:hover, .relate-list li:active {
  translate: 0 -3px; box-shadow: 0 14px 28px rgba(30,42,68,.1); border-color: rgba(198,67,63,.25);
}
.relate-x {
  display: flex; align-items: center; justify-content: center; flex-shrink: 0;
  width: 1.6rem; height: 1.6rem; border-radius: 50%;
  background: #FDEBEB; color: #C6433F; font-weight: 800; font-size: .85rem;
  transition: transform .2s ease, background .2s ease, color .2s ease;
}
.relate-list li:hover .relate-x, .relate-list li:active .relate-x {
  transform: scale(1.15); background: #C6433F; color: #fff;
}
/* Each pain point flies in from alternating sides as it's scrolled into
   view (right/left/right/left), staggered, instead of the whole list
   fading up as one block - a single scroll-triggered entrance, not a
   loop. The :not(.is-revealed) guard keeps this scoped to the pre-reveal
   state only, so it can't out-specificity the shared .is-revealed rule
   that actually plays the entrance (same trick as the .step stagger). */
.js .relate-list li[data-reveal] {
  transition: opacity .55s cubic-bezier(.16,1,.3,1), transform .55s cubic-bezier(.16,1,.3,1),
    translate .2s ease, box-shadow .2s ease, border-color .2s ease;
  transition-delay: 0s;
}
.js .relate-list li[data-reveal]:not(.is-revealed) { transform: translateX(40px); }
.js .relate-list li[data-reveal]:nth-child(even):not(.is-revealed) { transform: translateX(-40px); }
.js .relate-list li[data-reveal]:nth-child(2) { transition-delay: .1s; }
.js .relate-list li[data-reveal]:nth-child(3) { transition-delay: .2s; }
.js .relate-list li[data-reveal]:nth-child(4) { transition-delay: .3s; }

/* start steps - numbered, connected, meant to feel like real momentum
   (download -> calendar builds itself -> start planning), not a wall
   of feature description. */
.steps-row { display: flex; flex-direction: column; gap: 2rem; max-width: 22rem; margin: 0 auto; position: relative; }
.step { position: relative; padding-inline-start: 3.75rem; text-align: start; }
/* each station reveals on its own as you scroll past it, not the whole
   row at once - transition-delay is staggered per station so even when
   all three cross the viewport threshold close together (desktop row
   layout), they still visibly arrive one at a time, like passing stops. */
.js .step[data-reveal] { transition-delay: 0s; }
.js .step[data-reveal]:nth-child(2) { transition-delay: .15s; }
.js .step[data-reveal]:nth-child(3) { transition-delay: .3s; }
.step-num {
  position: absolute; inset-inline-start: 0; top: 0;
  width: 2.75rem; height: 2.75rem; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--brand) 55%, white), var(--brand) 78%);
  color: #fff; font-family: "Frank Ruhl Libre", serif; font-weight: 800; font-size: 1.15rem;
  box-shadow: 0 10px 20px rgba(40,90,188,.35); z-index: 1;
}
.step:not(:last-child)::after {
  content: ""; position: absolute; inset-inline-start: 1.35rem; top: 2.75rem;
  width: 2px; height: calc(100% + 2rem - 2.75rem);
  background: linear-gradient(var(--brand), var(--chabad));
  opacity: .35;
  transform: scaleY(1); transform-origin: top; transition: transform .2s linear;
}
/* Without JS the rail stays exactly as drawn above (scaleY(1) = no visual
   change). With JS, script.js sets --route-progress on .steps-row as the
   visitor scrolls through this section (0 to 2, one unit per gap between
   stations) - each gap's own --seg (set inline per .step, 0 then 1) picks
   its slice out of that shared value, so the line fills in one station at
   a time, tied to scroll position, not to a timer. script.js skips this
   entirely under prefers-reduced-motion, so var(--route-progress, 2)
   keeps falling back to a fully-drawn, static rail in that case too -
   the fallback is 2 (not 1) because it must clear both segments' --seg
   (0 and 1), not just the first one. */
.js .step:not(:last-child)::after {
  transform: scaleY(clamp(0, calc(var(--route-progress, 2) - var(--seg, 0)), 1));
}
.step h3 { font-size: 1.05rem; margin-bottom: .35rem; }
.step p { color: var(--muted); font-size: .92rem; }

@media (min-width: 760px) {
  .steps-row { flex-direction: row; max-width: none; gap: 1.5rem; }
  .step { padding-inline-start: 0; padding-top: 3.75rem; text-align: center; flex: 1; }
  .step-num { inset-inline-start: 50%; transform: translateX(50%); }
  .step:not(:last-child)::after {
    inset-inline-start: calc(50% + 1.9rem); top: 1.35rem;
    width: calc(100% - 1.9rem); height: 2px;
    background: linear-gradient(90deg, var(--brand), var(--chabad));
    transform: scaleX(1); transform-origin: right;
  }
  .js .step:not(:last-child)::after {
    transform: scaleX(clamp(0, calc(var(--route-progress, 2) - var(--seg, 0)), 1));
  }
}

/* how it works */
.how-grid { display: grid; gap: 1.25rem; grid-template-columns: 1fr; }
.how-card {
  background: var(--surface); border-radius: var(--radius-card); padding: 1.5rem;
  border: 1px solid var(--line); box-shadow: 0 2px 10px rgba(30,42,68,.04);
  transition: translate .25s ease, box-shadow .25s ease;
}
/* Lift uses the standalone `translate` property, not `transform` - this
   card also carries [data-reveal], whose .is-revealed state sets
   `transform: translateY(0)` at higher specificity once scrolled into
   view, which would silently cancel a `transform`-based hover/active lift
   for every visitor (the reveal has already fired by the time anyone can
   hover or tap it). Same fix already used for .demo-card above. */
.how-card:hover, .how-card:active { translate: 0 -6px; box-shadow: 0 22px 40px rgba(30,42,68,.14); }
/* each card reveals on its own as it crosses into view, not as one block -
   the two-column desktop grid pairs cards row by row, so a small stagger
   between them still reads as "arriving one at a time" like the steps. */
.js .how-card[data-reveal] { transition-delay: 0s; }
.js .how-card[data-reveal]:nth-child(2n) { transition-delay: .12s; }
.how-card:nth-child(1) { border-top: 3px solid var(--brand); }
.how-card:nth-child(2) { border-top: 3px solid var(--gold); }
.how-card:nth-child(3) { border-top: 3px solid var(--user); }
.how-card:nth-child(4) { border-top: 3px solid var(--chabad); }
.how-card:nth-child(5) { border-top: 3px solid var(--parasha); }
.how-card:nth-child(6) { border-top: 3px solid var(--roshchodesh); }
.how-card:nth-child(7) { border-top: 3px solid var(--birthday); }
.how-card:nth-child(8) { border-top: 3px solid var(--shabbat); }
.how-icon { width: 2.75rem; height: 2.75rem; border-radius: 50%; display: flex; align-items: center; justify-content: center; margin-bottom: 1rem; box-shadow: 0 10px 20px rgba(30,42,68,.2); }
.how-icon--gold { background: radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--gold) 55%, white), var(--gold) 78%); box-shadow: 0 10px 20px rgba(239,166,54,.35); }
.how-icon--brand { background: radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--brand) 55%, white), var(--brand) 78%); box-shadow: 0 10px 20px rgba(40,90,188,.35); }
.how-icon--chabad { background: radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--chabad) 55%, white), var(--chabad) 78%); box-shadow: 0 10px 20px rgba(91,94,242,.35); }
.how-icon--roshchodesh { background: radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--roshchodesh) 55%, white), var(--roshchodesh) 78%); box-shadow: 0 10px 20px rgba(58,166,224,.35); }
.how-icon--user { background: radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--user) 55%, white), var(--user) 78%); box-shadow: 0 10px 20px rgba(255,93,143,.35); }
.how-icon--parasha { background: radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--parasha) 55%, white), var(--parasha) 78%); box-shadow: 0 10px 20px rgba(124,83,214,.35); }
.how-icon--birthday { background: radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--birthday) 55%, white), var(--birthday) 78%); box-shadow: 0 10px 20px rgba(242,153,74,.35); }
.how-icon--widget { background: radial-gradient(circle at 32% 28%, color-mix(in srgb, var(--shabbat) 55%, white), var(--shabbat) 78%); box-shadow: 0 10px 20px rgba(20,184,166,.35); }
.how-card h3 { font-size: 1.05rem; margin-bottom: .4rem; }
.how-card p { color: var(--muted); font-size: .9rem; }

/* the two strongest cards (planning + calendar) are visually promoted -
   bigger, horizontal, full-width on desktop - so the section reads as
   "here are the two big things, plus four more", not six identical tiles.
   This is the fix for the literal "icons in identical circles" pattern
   DESIGN.md's hard rules call out by name. */
.how-card--featured { padding: 2rem; }
.how-card--featured .how-icon { width: 3.5rem; height: 3.5rem; margin-bottom: 1.25rem; }
.how-card--featured h3 { font-size: 1.25rem; }
.how-card--featured p { font-size: .98rem; }
@media (min-width: 760px) {
  .how-card--featured {
    grid-column: 1 / -1; display: flex; align-items: center; gap: 2rem;
    padding: 2.25rem 2.5rem;
  }
  .how-card--featured .how-icon { margin-bottom: 0; flex-shrink: 0; }
  .how-card-text { flex: 1; }
}
.how-help { text-align: center; color: var(--muted); font-size: .92rem; margin-top: 1.75rem; max-width: 30rem; margin-inline: auto; }
.how-shots { margin-top: 2.5rem; display: flex; flex-direction: column; align-items: center; gap: 2rem; }
.how-shot { text-align: center; }

/* a custom "dealt like cards" entrance for the three real screenshots,
   instead of sharing the generic fade-up every other [data-reveal] on
   this page uses - these are the proof images, they earn a distinct
   arrival. Reveal transform is on the <figure>, the cursor-tilt transform
   (above) is on the <img> inside it, so the two never collide. */
.js .how-shots [data-reveal]:not(.is-revealed) { transform: translateY(28px) rotate(0deg); }
.js .how-shots .how-shot:first-child[data-reveal]:not(.is-revealed) { transform: translateY(34px) rotate(-7deg); }
.js .how-shots .how-shot--mid[data-reveal]:not(.is-revealed) { transform: translateY(44px) scale(.9); }
.js .how-shots .how-shot:last-child[data-reveal]:not(.is-revealed) { transform: translateY(34px) rotate(7deg); }
.js .how-shots [data-reveal] { transition-delay: 0s; }
.js .how-shots .how-shot--mid[data-reveal] { transition-delay: .1s; }
.js .how-shots .how-shot:last-child[data-reveal] { transition-delay: .2s; }
.js .how-shots [data-reveal].is-revealed { transform: translateY(0) rotate(0deg) scale(1); }
/* the img's own transform is composed from custom properties so a JS-driven
   cursor tilt (script.js, desktop/fine-pointer only) and the CSS :hover lift
   below can both contribute without one overwriting the other via inline
   `style.transform` - see the .demo-card comment above for why that
   collision matters. */
.how-shot img {
  max-width: 190px; height: auto; margin: 0 auto; border-radius: 1.75rem;
  border: 6px solid var(--ink); box-shadow: 0 24px 50px rgba(30,42,68,.2);
  transform: perspective(900px) rotateX(var(--tilt-x, 0deg)) rotateY(var(--tilt-y, 0deg)) translateY(var(--lift-y, 0px));
  transition: transform .12s ease, box-shadow .3s ease;
}
.how-shot:hover img, .how-shot:active img { --lift-y: -6px; box-shadow: 0 32px 60px rgba(30,42,68,.28); }
.how-shot figcaption { margin-top: .75rem; font-size: .85rem; font-weight: 700; color: var(--muted); }
.how-shot--mid img { max-width: 210px; border-color: var(--brand); }

@media (min-width: 640px) {
  .how-shots { flex-direction: row; align-items: flex-end; justify-content: center; gap: 1.5rem; }
}

@media (min-width: 760px) {
  .how-grid { grid-template-columns: repeat(2, 1fr); }
}

/* story - a short, real founder note (not a testimonial, not a sales
   pitch) - genuine specific credibility is its own kind of proof. */
.story-card {
  background: var(--surface); border: 1px solid var(--line); border-radius: var(--radius-card);
  padding: 2rem 1.75rem; max-width: 38rem; margin: 0 auto; text-align: center;
  box-shadow: 0 18px 40px rgba(40,90,188,.08);
}
.story-quote {
  display: block; font-family: "Frank Ruhl Libre", serif; font-weight: 800;
  font-size: 3.5rem; line-height: 1; color: var(--brand); opacity: .22; margin-bottom: -.5rem;
}
.story-card p { color: var(--muted); font-size: 1rem; line-height: 1.75; }
.story-card p + p { margin-top: .9rem; }

/* pricing - dark pivot section, mirrors the "hard contrast band" both
   reference products (DonTrack, DoneDocs) use right before their closing CTA */
.pricing { position: relative; overflow: hidden; background: linear-gradient(180deg, var(--bg) 0%, #E7EAF6 100%); }
.pricing .wrap { position: relative; z-index: 1; }
.pricing::before {
  content: ""; position: absolute; inset: -10%; pointer-events: none; z-index: 0;
  background:
    radial-gradient(circle at 28% 20%, rgba(59,123,255,.24), transparent 42%),
    radial-gradient(circle at 78% 78%, rgba(91,94,242,.18), transparent 40%);
  filter: blur(10px);
}
.pricing-card {
  background: linear-gradient(160deg, #202538 0%, var(--ink) 55%, #141726 100%);
  color: #fff; border-radius: var(--radius-hero);
  padding: 2.5rem 1.5rem; text-align: center; max-width: 30rem; margin: 0 auto;
  box-shadow: 0 30px 70px rgba(15,18,30,.4), 0 0 60px rgba(59,123,255,.15), 0 0 0 1px rgba(255,255,255,.06) inset;
  position: relative;
}
.pricing-card .price { font-family: "Assistant"; font-weight: 800; font-size: 2.4rem; margin: .5rem 0; }
.pricing-card .price small { font-size: 1rem; font-weight: 600; }
.pricing-card p { color: #C7CCDC; margin-bottom: 1.5rem; }
.pricing-card .store-row { justify-content: center; }
.pricing-card .pricing-note { color: #8792B8; font-size: .8rem; margin: 1rem 0 0; }
.pricing-card .btn-store { background: #fff; color: var(--ink); box-shadow: 0 10px 25px rgba(0,0,0,.25); animation: none; }
.pricing-card .btn-store:hover { background: #fff; box-shadow: 0 16px 34px rgba(0,0,0,.32); }

/* faq */
.faq-list { max-width: 40rem; margin: 0 auto; display: flex; flex-direction: column; gap: .75rem; }
.faq-item {
  background: var(--surface); border: 1px solid var(--line); border-radius: 1rem;
  padding: .25rem 1.1rem; transition: box-shadow .25s ease, translate .25s ease, border-color .25s ease;
}
/* `translate`, not `transform` - same [data-reveal]/is-revealed collision
   as .how-card above. */
.faq-item:hover, .faq-item:active { box-shadow: 0 14px 28px rgba(30,42,68,.1); translate: 0 -2px; border-color: rgba(40,90,188,.2); }
/* five items, single column - they mostly enter view close together, so a
   short per-row stagger keeps the "arriving one at a time" feel intact
   instead of every question popping in as one flat block. */
.js .faq-item[data-reveal] { transition-delay: 0s; }
.js .faq-item[data-reveal]:nth-child(2) { transition-delay: .08s; }
.js .faq-item[data-reveal]:nth-child(3) { transition-delay: .16s; }
.js .faq-item[data-reveal]:nth-child(4) { transition-delay: .24s; }
.js .faq-item[data-reveal]:nth-child(5) { transition-delay: .32s; }
.faq-item summary { cursor: pointer; font-weight: 700; padding: .9rem 0; list-style: none; }
.faq-item summary::-webkit-details-marker { display: none; }
.faq-item summary::after { content: "+" / ""; float: left; font-size: 1.2rem; color: var(--brand); }
.faq-item[open] summary::after { content: "-" / ""; }
.faq-item p { color: var(--muted); padding: 0 0 1rem; font-size: .92rem; }

/* final cta - mirrors the hero's dark treatment so the page closes the
   loop it opened with, instead of ending on a flat light band. */
.final-cta {
  text-align: center; position: relative; overflow: hidden;
  background-color: var(--ink);
  background-image: linear-gradient(160deg, #232841 0%, var(--ink) 55%, #12141F 100%);
  padding: 4rem 0;
}
.final-cta::before {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background:
    radial-gradient(circle at 18% 15%, rgba(59,123,255,.26), transparent 50%),
    radial-gradient(circle at 85% 85%, rgba(139,142,245,.2), transparent 48%);
}
.final-cta .wrap { position: relative; z-index: 1; }
.final-cta .section-title { color: #fff; }
.final-cta .store-row { justify-content: center; }

/* footer */
.site-footer { border-top: 1px solid var(--line); padding: 2.5rem 0; }
.footer-row { display: flex; flex-direction: column; align-items: center; gap: 1rem; text-align: center; }
.footer-logo { width: 140px; height: auto; }
.footer-contact { font-size: .9rem; color: var(--muted); }
.footer-contact a { color: var(--brand); text-decoration: none; }
.footer-links { display: flex; gap: 1rem; font-size: .85rem; }
.footer-links a { color: var(--muted); text-decoration: none; }
.footer-copyright { color: var(--muted); font-size: .8rem; margin-top: .5rem; }
