/* ============================================================
   ShiftBee landing — shiftbee.co.il
   Espresso bookends · cream canvas · gold accent (single, locked)
   RTL-first: logical properties only. Zero dependencies.
   ============================================================ */

/* ---------- Tokens ----------
   Palette 2.0 — "refined espresso": stays on-brand with the real app
   (espresso + cream) but deeper, richer and higher-contrast than the old
   flat brown, so it reads premium instead of coffee-shop. Honey-amber +
   the honeycomb remain the single signature accent (the bee).
   Variable NAMES are kept stable so the whole page re-skins from here. */
:root {
  /* WhatsApp's double-check glyph, inlined so the mock stays request-free */
  --tick: url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 11"><path fill="black" d="M11.07.65a.5.5 0 0 0-.7.06L5.2 6.8 3.4 4.9a.5.5 0 1 0-.72.7l2.2 2.3a.5.5 0 0 0 .74-.03l5.5-6.5a.5.5 0 0 0-.06-.72z"/><path fill="black" d="M15.07.65a.5.5 0 0 0-.7.06L9.2 6.8l-.6-.63-.68.8.9.95a.5.5 0 0 0 .74-.03l5.5-6.5a.5.5 0 0 0-.06-.72z"/></svg>');
  /* dark (espresso) surfaces — deep dark-roast, warm but nearly black */
  --espresso: #1a120b;
  --espresso-2: #241a10;
  --espresso-3: #332619;
  --on-dark: #f5f0e6;
  --on-dark-muted: #cbbfa7;
  --dark-line: rgba(245, 240, 230, 0.13);

  /* light (cream) surfaces — clean warm off-white */
  --cream: #f6f3ec;
  /* v5: a brighter, near-white PAGE canvas (competitors all run a bright
     canvas + one saturated accent). The body switches from --cream to
     --canvas; --cream is UNCHANGED and stays the tray/shell tone inside the
     surface ladder, so the panels still read as floating on a warm ground.
     v6 §2.1: deepened from #faf9f6. At near-white the WHITE panels sat at
     dL* ~2.1 from the canvas and read as outlined boxes (the --line-strong
     border was the symptom fix); #f7f5f0 gives the ladder a real step back. */
  --canvas: #f7f5f0;
  --white: #ffffff;
  --line: #eeeae0;
  --line-strong: #e1dccf;
  --ink: #221a10;
  --body: #423a2b;
  --muted: #766c54;
  --stone: #5e5340;

  /* the one accent — honey */
  --gold: #f5b724;
  --gold-2: #eaa50f;
  --gold-soft: #f8e8c4;
  --gold-deep: #c88a12;
  /* v6 §2.2/§2.3 correction: the spec put --gold-deep on the h1 accent word and
     the nav wordmark's "Bee" at an assumed ~3.4:1. MEASURED on the new
     #f7f5f0 canvas it is 2.57:1 (2.69:1 under the warm bloom), i.e. it fails AA
     even for large text. This is the same honey one stop darker: 3.4:1 measured,
     so it clears the >=3:1 large-text floor with margin. It is for LARGE gold
     type on the bright fold ONLY - nothing under 18.66px, and never a surface.
     --gold-deep itself is untouched: it also paints fills, borders and the
     a11y focus ring, and darkening it globally would move the whole brand. */
  --gold-fold: #b57a0e;
  --gold-ink: #895907;
  --on-gold: #3d2a04;

  /* product-recreation only (sampled from the real app) */
  --olive: #6f7a3a;
  --olive-bg: #eceedd;
  --olive-line: #d3d8b0;
  --role-server: #4a6c9b;
  --role-bar: #d97706;
  --role-cook: #7c6597;
  --warn: #c88a12;
  --warn-line: #e8d19a;
  --warn-bg: #fbf0d5;

  --radius-sm: 9px;
  --radius: 13px;
  --radius-lg: 20px;
  --radius-xl: 28px;

  /* One card, one spec. Every card the LANDING PAGE owns uses these three —
     the step vignettes, the chat, the vertical photos, the calculator result,
     the demo form. Product recreations (.pframe/.papp/.pgrid) are exempt on
     purpose: they copy the app's own geometry, and matching them to the page
     would make the mock stop looking like the product. */
  --card-radius: 28px;
  /* one label size across the three step vignettes */
  --fs-viz: 0.9rem;
  --card-pad: clamp(20px, 2.6vw, 28px);

  --shadow-card: 0 1px 2px rgba(20, 22, 30, 0.05), 0 8px 28px rgba(20, 22, 30, 0.07);
  --shadow-float: 0 2px 8px rgba(20, 22, 30, 0.12), 0 30px 70px rgba(16, 18, 26, 0.26);
  --shadow-gold: 0 2px 12px rgba(200, 138, 18, 0.34);

  --ease-out: cubic-bezier(0.16, 1, 0.3, 1);
  /* Load-choreography curve. --ease-out is a whip (75% of the travel in the
     first fifth of the duration) - right for 300ms micro-interactions, wrong
     for the page entrance, where five staggered whips read as popping. This
     is ease-out-cubic: calm initial velocity, same soft landing. */
  --ease-enter: cubic-bezier(0.215, 0.61, 0.355, 1);
  --content: 1120px;

  /* ---- v4 (design-refs/landing-v4/ADDENDUM.md) ---- */
  --content-narrow: 760px;   /* the FAQ. Container width IS the hierarchy lever. */
  --r-card: 24px;
  --pad-shell: 8px;                              /* shell -> core inset */
  --r-core: calc(var(--r-card) - var(--pad-shell));  /* concentric: inner radius
                                                        = outer minus the inset,
                                                        so the curves nest */
  --pad-card: 24px;          /* deliberately == --r-card, see ADDENDUM S7.5:
                                content follows the curve instead of colliding
                                with it. Do not "tidy" these apart. */
  --head-lead: 12px;         /* eyebrow -> h2 */
  --head-deck: 16px;         /* h2 -> deck   */
  --head-gap: 32px;          /* head -> body */
  --head-gap-major: 48px;

  --fs-display: clamp(2.75rem, 6.5vw, 5rem);  /* v5: ~80px desktop hero, to match the competitive set */
  --fs-h2: clamp(2rem, 4vw, 3.1rem);          /* v5: section heads scale with the hero */
  --fs-h3: 1.35rem;
  --fs-lead: 1.2rem;                          /* v5: hero sub + decks breathe with the new scale */
  --fs-sm: 0.925rem;
  --fw-mid: 600;
  --fw-display: 700;
  /* v6.2 §C5: 1.25, up from 1.2. This is the .sec-head h2 / .pivot value, i.e.
     every section head on the page - and ~1.2 is the Latin display default N3
     exists to keep off Hebrew. Hebrew floor; never below. */
  --lh-display: 1.25;
  --fs-body: 1.0625rem;      /* 17px */
  --fs-xs: 0.8rem;
  --lh-lead: 1.45;

  /* The mock copies the real app's UI, which has its own (smaller) type scale.
     Five steps, and page chrome never uses them. Before this there were 16
     values in here, nine of which sat inside a 0.06rem band - differences too
     small to read as hierarchy and large enough to read as sloppiness. */
  /* v5: all five up one notch - the enlarged hero frame must read at arm's length */
  --fs-app-lg: 1rem;
  --fs-app-md: 0.92rem;
  --fs-app-sm: 0.84rem;
  --fs-app-xs: 0.76rem;
  --fs-app-xxs: 0.68rem;
}

/* ---------- Base ---------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--canvas);
  color: var(--body);
  font-family: 'Heebo', system-ui, -apple-system, sans-serif;
  font-size: var(--fs-body);
  line-height: 1.65;
  /* Deliberately NO -webkit-font-smoothing: antialiased and NO text-rendering:
     optimizeLegibility. Both were here before the Heebo migration and both are
     banned by the app's typography spec: on macOS they thin and blur the
     lighter half of a single-family weight ladder, which is precisely the half
     this page now leans on for body copy. Do not re-add them. */
}

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

a {
  color: inherit;
}

/* Form controls do not inherit font-family from body - the UA hands them its
   own stack, which on this machine is Arial. Measured after the Heebo
   migration: .calc__range, .a11y-trigger and .a11y-panel__close were all
   painting in Arial, and the last one renders a visible glyph. That is a
   second family on a page whose whole typography rule is that there is one.
   font-family only, not the `font` shorthand: the shorthand would also drag
   body's 17px onto every control that currently sizes itself. */
button,
input,
select,
textarea,
optgroup {
  font-family: inherit;
}

h1,
h2,
h3 {
  font-family: 'Heebo', system-ui, sans-serif;
  color: var(--ink);
  text-wrap: balance;
  margin: 0;
}

p {
  margin: 0;
  text-wrap: pretty;
}

/* Hebrew gets no letter-spacing; the EN page opts in via [lang=en] below. */
:lang(en) h1,
:lang(en) h2 {
  letter-spacing: -0.02em;
}

/* The 450 nudge that used to live here is GONE (Heebo migration, 2026-07-28).
   It compensated for Assistant, whose Hebrew at 400 had no ascenders or
   descenders to carry the word shape and read thin. Heebo's Hebrew was drawn
   as Roboto's companion and holds at 400, which is also what the app ships for
   body copy - so keeping 450 here would have re-opened the handoff seam this
   migration exists to close. Body is 400 on both surfaces now. */

.container {
  max-width: var(--content);
  margin-inline: auto;
  padding-inline: clamp(20px, 4vw, 40px);
}

/* Anchor targets must clear the 68px fixed nav. Without this the nav crops the
   section head on every in-page link; it only appeared to work because the
   panel's own top padding happened to absorb it. */
section[id] {
  scroll-margin-block-start: 84px;
}

.section {
  padding-block: clamp(56px, 7vw, 96px);
}

/* time / numeric runs inside RTL text */
bdi.num,
.num {
  direction: ltr;
  unicode-bidi: isolate;
  font-variant-numeric: tabular-nums;
}

/* A FROM-TO range follows PARAGRAPH direction: start-first in Hebrew (so the
   pair paints `15:00-07:00` and an RTL reader meets 07:00 first), start-left
   in English. Each endpoint stays internally LTR via its own `dir="ltr"` bdi,
   so no clock ever renders as `00:70`.

   This reverses the v6.2 §C1 decision, which forced the pair LTR in both
   languages. That decision read the LTR paint as "sixteen overnight shifts";
   the owner reads the same pixels the other way - end-first - and they are the
   native speaker this page is written for. Restored on their call.

   THE COST, so it is not rediscovered by accident: with start-first ordering a
   day shift `12:00-17:00` and a genuine overnight `17:00->12:00` are pixel-
   identical. That is a real defect - it was measured in the app on 2026-07-31,
   where a 06:00-13:00 morning shift painted as `13:00-06:00`. It is safe HERE
   and only here: the demo grid contains 07:00-15:00 and 15:00-23:00 and no
   overnight shift at all. Add one and this rule has to be reconsidered.

   DELIBERATE DIVERGENCE FROM app/lib/dates.ts, which keeps ranges LTR in both
   languages and prescribes fixing "the reader meets the end first" with a cue
   (an arrow or an "עד" label) rather than by reordering. Do not propagate this
   rule into the app without also moving the 11 remaining `rangeText()` call
   sites onto `timeRange()`, which appends the "+1" overnight marker.

   `bdi.num--range` and not a bare `.num--range`: the element carries BOTH
   classes, and the rule above is written `bdi.num` (0,1,1). A bare class
   selector is (0,1,0) and loses to it no matter how late it appears, so the
   override silently did nothing. Keep the element qualifier. */
bdi.num--range,
.num--range {
  direction: inherit;
}

/* icons */
.ic {
  width: 1.15em;
  height: 1.15em;
  flex: none;
  fill: currentColor;
}

/* directional glyphs mirror under RTL */
:dir(rtl) .ic--dir {
  transform: scaleX(-1);
}

/* ---------- Scroll progress ----------
   Scroll-driven animation, so there is no scroll listener and nothing to
   throttle. Falls back to an invisible scaleX(0) bar where
   animation-timeline is unsupported, and is disabled under reduced motion. */
.progress {
  /* Sits on the nav's own bottom edge, not loose at the top of the viewport.
     Free-floating it read as a stray gold stub in the corner - especially in
     RTL, where it fills from the right and starts life detached in the corner. */
  position: absolute;
  inset-block-end: 0;
  inset-inline-start: 0;
  inline-size: 100%;
  block-size: 3px;
  /* --gold again: v6.1 put this bar back on the espresso nav, where #f5b724 is
     the correct high-contrast fill. (It was --gold-fold only for the bright
     fold.) 3px kept from v6 - 2px read as a rendering artefact. */
  background: var(--gold);
  transform-origin: 0 50%;
  transform: scaleX(0);
  pointer-events: none;
}

:dir(rtl) .progress {
  transform-origin: 100% 50%;
}

@supports (animation-timeline: scroll()) {
  @media (prefers-reduced-motion: no-preference) {
    .progress {
      animation: progress-grow linear both;
      animation-timeline: scroll(root);
    }
  }
}

@keyframes progress-grow {
  from { transform: scaleX(0); }
  to { transform: scaleX(1); }
}

/* ---------- Nav ---------- */
.nav {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 50;
  transition: background-color 0.35s ease, box-shadow 0.35s ease;
}

/* v6.1: the nav sits on the espresso hero again. */
.nav.is-scrolled {
  background: rgba(26, 18, 11, 0.88);
  -webkit-backdrop-filter: blur(14px);
  backdrop-filter: blur(14px);
  /* v6.2 §B1: --dark-line, not --line. --line (#eeeae0) is a light-surface tone
     and painted a near-white 1px rule across the espresso nav. */
  box-shadow: 0 1px 0 var(--dark-line);
}

.nav__inner {
  max-width: var(--content);
  margin-inline: auto;
  padding-inline: clamp(20px, 4vw, 40px);
  block-size: 68px;
  display: flex;
  align-items: center;
  gap: 28px;
}

.brand {
  display: flex;
  align-items: center;
  gap: 10px;
  text-decoration: none;
}

.brand__mark {
  inline-size: 34px;
  block-size: 34px;
}

/* wordmark: sized to the logotype, not to the text scale.
   The base colour is the DARK-surface one (the footer wordmark still sits on
   espresso); the nav overrides it below. */
.brand__word {
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 800;
  font-size: 1.25rem;
  line-height: 1.3;
  color: var(--on-dark);
}

/* N2: negative tracking is a Latin-only affordance. The wordmark happens to be
   Latin, but the declaration itself applied on the HE page, so it is gated. */
:lang(en) .brand__word {
  letter-spacing: -0.01em;
}

.brand__word b {
  color: var(--gold);
  font-weight: 800;
}


/* v6.1: nav identity on the espresso fold. Kept .nav-scoped (not global) so the
   FOOTER wordmark, which sits on its own espresso band, is unaffected either way. */
.nav .brand__word {
  color: var(--on-dark);
}

.nav .brand__word b {
  color: var(--gold);
}

.nav__links {
  display: flex;
  align-items: center;
  gap: 24px;
  margin-inline-start: auto;
}

.nav__links a:not(.btn) {
  color: var(--on-dark-muted);
  text-decoration: none;
  font-weight: 600;
  font-size: var(--fs-sm);
  line-height: 1.4;
  transition: color 0.2s ease;
}

.nav__links a:not(.btn):hover {
  color: var(--on-dark);
}

.nav__lang {
  /* v6.2 §B2: --dark-line. --line-strong is a light-surface tone, so on the
     espresso nav the pill's outline out-shouted its own label. */
  border: 1px solid var(--dark-line);
  border-radius: 999px;
  padding: 4px 12px;
  font-size: var(--fs-xs);
}

@media (max-width: 880px) {
  .nav__links a.nav__anchor {
    display: none;
  }
}

/* The language switch is the ONE nav item that must never need discovering: a
   Hebrew speaker landing on /en/ (or the reverse) has to see the way back, not
   hunt for it behind a hamburger. It was hidden from 880px down, which buried
   it on tablets and mid-size windows where it fits perfectly well - reported
   from a real 610px window as "I can't switch to Hebrew on the menu".
   480px is where it actually stops fitting: brand 134 + pill 62 + CTA 132 +
   menu 44 + gaps ~30 = ~402px of content, against (vw - 40) of bar. Below that
   the disclosure sheet carries it, and the sheet is the only place it lives. */
@media (max-width: 480px) {
  .nav__links a.nav__lang {
    display: none;
  }
}

/* v6.2 §D2: at 320px the bar ran out of room and the CTA painted over the
   wordmark while the menu button sat outside the header's viewport. The emblem
   alone carries the brand at that width - it is the same mark as the favicon
   and the app icon, so nothing about the identity is lost. */
@media (max-width: 370px) {
  /* .nav-scoped, not global: the FOOTER wordmark sits in a wrapping flex row
     with room to spare and has no collision to solve, so hiding it there would
     be a regression the fix never asked for. */
  .nav .brand__word {
    display: none;
  }
  .nav__inner {
    gap: 12px;
    padding-inline: 12px;
  }
}

/* ---------- Mobile navigation (v6 §4.2) ----------
   A <details> disclosure, same no-JS pattern the FAQ already proves. The sheet
   is positioned against .nav (which is `fixed`, so it is the containing block)
   rather than against .navmenu, so it can run full-bleed on the inline axis. */
.navmenu {
  display: none;
}

.navmenu > summary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  inline-size: 44px;
  block-size: 44px;
  border-radius: 12px;
  /* v6.1: the nav is espresso again, so the hamburger and its sheet follow it.
     A light sheet under a dark nav read as two unrelated surfaces. */
  color: var(--on-dark);
  line-height: 1;
  cursor: pointer;
  list-style: none;
}

.navmenu > summary::-webkit-details-marker {
  display: none;
}

.navmenu > summary .ic {
  inline-size: 24px;
  block-size: 24px;
}

.navmenu__sheet {
  position: absolute;
  inset-block-start: 68px;   /* == .nav__inner block-size */
  inset-inline: 0;
  background: var(--espresso-2);
  border-block-end: 1px solid var(--dark-line);
  box-shadow: 0 12px 28px rgba(10, 7, 4, 0.45);
  padding-inline: clamp(20px, 4vw, 40px);
  padding-block: 4px 8px;
}

.nav .navmenu__sheet a {
  display: flex;
  align-items: center;
  min-block-size: 48px;
  color: var(--on-dark);
  font-size: var(--fs-body);
  line-height: 1.5;
  font-weight: 600;
  text-decoration: none;
}

.nav .navmenu__sheet a + a {
  border-block-start: 1px solid var(--dark-line);
}

@media (max-width: 880px) {
  .navmenu {
    display: block;
  }
}

/* ---------- Buttons ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  border: 0;
  border-radius: var(--radius);
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  /* v6.2 §C6 (N3): a <button> gets `line-height: normal` from the UA `font`
     shorthand - it does NOT inherit the body's 1.65 the way the anchor variants
     do. That left the page's primary conversion control setting a Hebrew label
     at the ~1.2 Latin display default. Explicit 1.4 for every .btn. */
  line-height: 1.4;
  transition: transform 0.22s var(--ease-out), box-shadow 0.22s var(--ease-out), background-color 0.2s ease;
}

.btn:active {
  transform: scale(0.98);
}

.btn--gold {
  background: linear-gradient(180deg, #f5be3d, var(--gold-2));
  color: var(--on-gold);
  box-shadow: var(--shadow-gold);
}

.btn--gold:hover {
  transform: translateY(-1px) scale(1.02);
  box-shadow: 0 4px 18px rgba(201, 138, 22, 0.45);
}

.btn--lg {
  block-size: 54px;
  padding-inline: 30px;
  font-size: var(--fs-body);
  border-radius: 14px;
}

.btn--md {
  block-size: 42px;
  padding-inline: 20px;
  font-size: var(--fs-sm);
}

/* ---------- Hero ---------- */
/* v6.1: the fold is DARK again (user call, 2026-07-28). The v6 inversion was
   technically correct about WHERE the fix had to land, but the espresso fold is
   the brand's own voice and a bright-hero page is what all five competitors
   already ship. Espresso now bookends BOTH ends of the page; the bright canvas
   (#f7f5f0) keeps the middle, which is where v5 put it and where it works. */
.hero {
  background:
    radial-gradient(1100px 520px at 82% -10%, rgba(240, 180, 41, 0.16), transparent 62%),
    radial-gradient(900px 480px at 8% 112%, rgba(240, 180, 41, 0.07), transparent 60%),
    var(--espresso);
  color: var(--on-dark);
  padding-block-start: clamp(100px, 13vh, 136px);
  padding-block-end: clamp(56px, 6vw, 84px);
  /* overflow-x (not `hidden`) is the ONLY physical-axis property on the page.
     x IS the inline axis in both HE and EN, so it is direction-safe. `clip`
     rather than `hidden` so the paired block axis stays `visible` and the
     product frame can cross the seam below - `hidden` would force it to auto
     and re-clip the very overlap this buys. */
  overflow-x: clip;
}

.hero__grid {
  display: grid;
  /* v5: the type is bigger, so the text column NARROWS (the measure must not
     grow) and the frame column grows to carry the enlarged mock. */
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(36px, 5vw, 64px);
  align-items: center;
}

/* v6.2 §C2/§C5: Hebrew gets its OWN clamp, the way English already has one.
   --fs-display (80px desktop) put 7- and 9-character lines in a 415px column;
   Hebrew has no ascenders or descenders to carry word shape and needs MORE room
   per glyph, not less. Capped at 64px, with the line-height lifted off the ~1.14
   Latin display value that crushes Hebrew. Target wrap: "הסידור נבנה" / "לבד."
   text-wrap: pretty, NOT the `balance` inherited from the global h1/h2/h3 rule.
   MEASURED: at the new cap, balance equalises the two lines into
   "הסידור" / "נבנה לבד." - it splits the verb off its subject and leaves the
   gold accent word buried mid-line instead of standing alone. pretty gives the
   target wrap at 1280/1366/1440/1600/1920 and leaves the single-line render at
   981-1200 and the whole EN page byte-identical. */
.hero h1 {
  color: var(--on-dark);
  font-size: clamp(2.75rem, 4.6vw, 4rem);
  font-weight: 800;
  line-height: 1.2;
  text-wrap: pretty;
}

/* The EN headline ("The schedule builds itself.") runs ~2x the Hebrew measure;
   at the full --fs-display it wraps to four lines in the hero column. Its own
   clamp keeps it at two. Hebrew keeps the full scale - three words carry it. */
:lang(en) .hero h1 {
  font-size: clamp(2.4rem, 4.6vw, 3.6rem);
}

/* v6.1: --gold again. The hero is espresso, so the bright honey is both the
   brand's own accent and the high-contrast choice (~9.9:1 on --espresso).
   --gold-fold exists for the LIGHT surfaces only; putting it here would leave
   the one accent word muddy against the dark fold. */
.hero h1 .gold {
  color: var(--gold);
}

.hero__sub {
  margin-block-start: 24px;
  font-size: var(--fs-lead);
  line-height: 1.75;
  color: var(--on-dark-muted);
  max-width: 30em;
}

.hero__cta {
  margin-block-start: 38px;
  display: flex;
  align-items: center;
  gap: 16px;
  flex-wrap: wrap;
}

.hero__trust {
  margin-block-start: 14px;
  font-size: var(--fs-sm);
  line-height: 1.5;
  color: var(--on-dark-muted);
}

.hero__more {
  color: var(--on-dark-muted);
  font-weight: 600;
  font-size: var(--fs-sm);
  line-height: 1.4;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 7px;
  /* The text box alone measured 21px, under the 24px floor AGENTS.md sets as
     the absolute minimum (WCAG 2.2 SC 2.5.8). The height has to live in the
     element's own box - hitSlop does not exist on the web, and a transparent
     ::before would not enlarge the focus ring. min-block-size + the existing
     centring grows the target without moving the text. */
  min-block-size: 32px;
  transition: color 0.2s ease;
}

.hero__more:hover {
  color: var(--on-dark);
}

@media (max-width: 980px) {
  /* minmax(0, 1fr), NOT 1fr: plain `1fr` is minmax(auto, 1fr), so the mock's
     fixed-width day columns (v6 §4.1) would force the whole column - and with
     it the product frame - past the viewport, and the frame would get cropped
     by .hero's overflow clip instead of the week being cropped inside .pgrid. */
  .hero__grid {
    grid-template-columns: minmax(0, 1fr);
  }
  .hero {
    padding-block-start: 108px;
  }
}

/* ---------- The cropped week reads as a crop, not a bug ----------
   Below 640px the grid deliberately shows two full days and clips the rest, so
   the week visibly continues (v6 §4.1). But a cell chopped dead flat on the
   card's border reads as a rendering fault, not as an invitation - reported as
   "the card not fitting". A soft fade on the overflowing edge is the whole
   difference between "cut off" and "there is more".
   mask-image has no logical form, so the direction is set per :dir(): in RTL
   the row starts at the inline-start (right) and spills LEFT; in LTR it spills
   RIGHT. Purely decorative - it cannot affect layout, hit-testing or a11y. */
/* The fade belongs wherever the row can actually overflow, and nowhere else.
   With the 81px column floor that is everything below ~1240px; above it all six
   days fit and the grid has clean edges that line up with the toolbar and the
   status row above it. Fading a grid that is NOT cropped cuts its leading
   column mid-cell and makes the whole card read as misaligned - which is
   exactly what was reported. */
@media (max-width: 1240px) {
  .pgrid {
    -webkit-mask-image: linear-gradient(to left, #000 calc(100% - 44px), transparent 100%);
    mask-image: linear-gradient(to left, #000 calc(100% - 44px), transparent 100%);
  }
  :dir(ltr) .pgrid {
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 44px), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 44px), transparent 100%);
  }
}

/* ---------- Short viewports: landscape phones ----------
   Every block value in the hero is tuned for a TALL screen. Rotate a phone and
   the viewport becomes wide-but-short (844x390 on an iPhone 14), where the
   108px top padding alone eats 28% of the screen, the hero grows to 1045px
   (2.7 screens), and the product card - the whole point of the fold - starts at
   y=422, entirely below it. Height-based, not width-based: this is about how
   much vertical room exists, and a short desktop window has the same problem.
   Targets: headline, sub, CTA and the trust line all inside the fold, with the
   card's top edge just peeking to invite the scroll. */
@media (max-height: 560px) and (min-width: 600px) {
  .hero {
    /* nav is 68px; 16px of air under it is enough at this height */
    padding-block-start: 84px;
    padding-block-end: 28px;
  }
  .hero h1 {
    /* vh-based so it tracks the constrained axis rather than the free one */
    font-size: clamp(1.75rem, 6.5vh, 2.6rem);
    line-height: 1.2;
  }
  .hero__sub {
    margin-block-start: 12px;
    font-size: var(--fs-body);
    line-height: 1.5;
  }
  .hero__cta { margin-block-start: 20px; }
  .hero__trust { margin-block-start: 10px; }

  /* The sticky CTA duplicates the hero CTA that is now visible, and at this
     height its 75px bar is a much bigger tax than it is in portrait. */
  .mcta { display: none !important; }
}

/* ---------- Product frame (the self-building week) ---------- */
.pframe {
  background: #140d06;
  border: 1px solid rgba(245, 240, 230, 0.1);
  border-radius: var(--radius-lg);
  /* Layered: a tight contact shadow, the existing float, and a 1px inset
     highlight along the top edge so the device chrome catches light instead
     of reading as a flat dark rectangle. */
  box-shadow:
    var(--shadow-float),
    inset 0 1px 0 rgba(245, 240, 230, 0.08);
  overflow: hidden;
}

.pframe__bar {
  display: flex;
  align-items: center;
  gap: 12px;
  padding: 10px 16px;
  border-block-end: 1px solid rgba(243, 239, 230, 0.08);
}

.pframe__dots {
  display: flex;
  gap: 6px;
}

.pframe__dots i {
  inline-size: 10px;
  block-size: 10px;
  border-radius: 50%;
  background: rgba(243, 239, 230, 0.16);
}

.pframe__url {
  margin-inline: auto;
  direction: ltr;
  unicode-bidi: isolate;
  font-size: var(--fs-app-sm);
  color: rgba(243, 239, 230, 0.55);
  background: rgba(243, 239, 230, 0.07);
  border-radius: 999px;
  padding: 3px 14px;
}

.papp {
  background: var(--cream);
  padding: 16px;  /* v5: the enlarged frame gets a touch more interior */
}

/* mini toolbar */
.papp__bar {
  display: flex;
  align-items: center;
  gap: 8px;
  margin-block-end: 12px;
}

.pchip-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  block-size: 30px;
  padding-inline: 12px;
  border-radius: 10px;
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-app-xs);
}

.pchip-btn--dark {
  background: var(--espresso-2);
  color: var(--on-dark);
}

.pchip-btn--gold {
  background: linear-gradient(180deg, #f5be3d, var(--gold-2));
  color: var(--on-gold);
  position: relative;
}

/* The week label holds the inline-START edge (the right, in Hebrew) and pushes
   the action pair to the far side - which is where the real app puts it.
   NB: this was `margin-inline-start: auto` here PLUS `margin-inline-end: auto`
   in a later override. Different properties, so neither overrode the other -
   auto on both sides centres a flex item, which parked the label in the middle
   of the toolbar. One margin only. */
.papp__week {
  margin-inline-end: auto;
  font-size: var(--fs-app-sm);
  font-weight: 600;
  color: var(--muted);
}

/* AI button PRESS (phase 1): a quick push-down-and-release, then one ring.
   The story is "someone tapped it and the week filled" - so it must look like
   a tap (scale dip), not a glow. Phase 2 follows ~350ms later in main.js;
   keep the dip inside that window so the fill reads as the press's effect. */
@keyframes ai-pulse {
  0%,
  100% {
    box-shadow: 0 0 0 0 rgba(240, 180, 41, 0.55);
  }
  60% {
    box-shadow: 0 0 0 9px rgba(240, 180, 41, 0);
  }
}

@keyframes ai-press {
  0%,
  100% {
    transform: scale(1);
  }
  35% {
    transform: scale(0.92);
  }
}

.pf[data-phase='1'] .pchip-btn--gold {
  animation:
    ai-press 0.32s var(--ease-out),
    ai-pulse 0.8s var(--ease-out) 0.18s 1;
}

/* status strip */
.papp__status {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-block-end: 10px;
  min-block-size: 28px;
}

.ppub {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  block-size: 26px;
  padding-inline: 11px;
  border-radius: 999px;
  background: var(--olive-bg);
  border: 1px solid var(--olive-line);
  /* v6.2 §E1: NOT --olive. At 13.44px bold this is body text (large text starts
     at 18.66px bold), so it owes 4.5:1 - --olive measures 3.95:1 on its own pill
     fill. #616b2c is 4.89:1 on --olive-bg and 5.20:1 on --cream. --olive keeps
     every 18px+ use (.vres__rules .ic, .pstat-chip .ic, .vres-chip .ic). */
  color: #616b2c;
  font-weight: 700;
  font-size: var(--fs-app-sm);
  margin-inline-start: auto;
  opacity: 0;
  transform: scale(0.85);
  transition: opacity 0.4s var(--ease-out), transform 0.5s var(--ease-out);
}

.pf[data-phase='4'] .ppub {
  opacity: 1;
  transform: scale(1);
}

/* toolbar-style stat readout (mirrors the real app's stats cluster) */
.pstats {
  display: inline-flex;
  align-items: center;
  /* wrap: below ~430px the three chips cannot share one line. Wrapping moves a
     WHOLE chip down; without it the flex line just overflows and the labels
     break mid-phrase instead (see the nowrap rule below). */
  flex-wrap: wrap;
  gap: 14px;
  font-size: var(--fs-app-sm);
  font-weight: 700;
  color: var(--stone);
}

/* Each status label is ONE phrase and must never break inside itself. The
   comment below has claimed this since v6, but no rule ever implemented it:
   .lbl has no declaration anywhere, so at 360-420px and again at 570-580px
   "כל המשמרות מכוסות" split across two lines and the status bar grew to 78px.
   Measured across 360-620px: with this rule, zero mid-phrase breaks and zero
   overflow. .ppub is a fixed 26px pill, so a second line would overflow it. */
.pstats__open .lbl,
.pstat-chip .lbl,
.ppub {
  white-space: nowrap;
}

.pstats__num {
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 800;
  color: var(--ink);
  min-inline-size: 2ch;
  text-align: end;
}

/* Same .lbl treatment as .vres-chip - "0 פתוחות" is one phrase. */
.pstats__open {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  opacity: 0;
  transition: opacity 0.4s var(--ease-out) 0.7s;
}

.pstats__open .ic {
  color: var(--olive);
}

/* v6 §3: the rest-protected proof, on the CARD's own baseline. It replaces the
   two floating glass "proof pills", which covered the .ptoast (the animation's
   own payoff), sat at permanently opposite float phases so they could never
   share a baseline, restated claims the card already makes, and were
   display:none below 980px - desktop-only decoration on a mobile-first product.
   Three documented failed homes; do not re-add them. Same size, icon colour and
   phase gate as .pstats__open, and NO hide rule at any width. */
.pstat-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-size: var(--fs-app-sm);
  line-height: 1.4;
  color: var(--stone);
  opacity: 0;
  transition: opacity 0.4s var(--ease-out) 0.7s;
}

.pstat-chip .ic {
  color: var(--olive);
}

.pf[data-phase='3'] .pstats__open,
.pf[data-phase='4'] .pstats__open,
.pf[data-phase='3'] .pstat-chip,
.pf[data-phase='4'] .pstat-chip {
  opacity: 1;
}

/* mini grid */
.pgrid {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  /* The grid is the hero of the manager screen — it should sit ON the cream
     app canvas, not be flush with it. A 1px border alone left the table and
     its background reading as one flat plane. */
  box-shadow:
    0 1px 2px rgba(35, 26, 18, 0.04),
    0 6px 16px -6px rgba(35, 26, 18, 0.1);
}

.pgrid__row {
  display: grid;
  /* minmax(0,1fr), not 1fr: the time chips are nowrap, and 1fr is
     minmax(auto,1fr), so a chip wider than its share pushes its own track
     out and starves the others - the day columns then stop lining up with
     the day headers, worst at phone widths. */
  /* SIX day tracks at a fixed width, not four flexible ones. The Israeli work
     week is Sun-Fri, so 4 staff x 6 days = the 24 the status bar claims - the
     badge is now a number a visitor can literally count, instead of asserting
     24 over a grid that only contained 16. The tracks are FIXED so the row is
     always wider than the frame: the week visibly continues past the edge
     (masked below), which is what a real app looks like and what stops anyone
     reading the crop as the whole week. */
  /* minmax(81px, 1fr), not minmax(0, 1fr). 81px is the measured width the
     "07:00-15:00" range needs inside its chip; below that the text clips, which
     is strictly worse than the row overflowing. So the columns have a FLOOR:
     where there is room they share it, and where there is not (981-1024px is
     the tightest band - the hero has just gone two-column but .pf's bleed has
     not started, leaving the grid ~496px against the ~594px six days need) the
     row overflows and crops behind the fade instead of squeezing. */
  /* 116px, not 108. At 108 the name box came to 56px while "מאיה פרץ" needs 57,
     so it ellipsized at every width — and the other three sat at exactly 0px of
     slack (נועה כהן 50/50, עומר דהן 52/52), i.e. one font-rendering difference
     from clipping too. Renaming the person would have hidden that. Measured at
     900/1024/1280/1440: 116 clears all four, and the day columns still land at
     81-113px, never under the 81px floor the range chip needs. */
  grid-template-columns: 116px repeat(6, minmax(81px, 1fr));
  border-block-start: 1px solid var(--line);
}

.pgrid__row:first-child {
  border-block-start: 0;
  background: var(--cream);
}

.pgrid__head {
  padding: 8px 6px;
  text-align: center;
  font-size: var(--fs-app-xs);
  font-weight: 700;
  color: var(--muted);
}

.pgrid__head .num {
  display: block;
  font-family: 'Heebo', system-ui, sans-serif;
  font-size: var(--fs-app-md);
  color: var(--ink);
}

.pgrid__who {
  padding: 9px 10px;
  border-inline-end: 1px solid var(--line);
  display: flex;
  flex-direction: column;
  justify-content: center;
  gap: 2px;
  min-inline-size: 0;
  overflow: hidden;
}

.pgrid__name {
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-app-sm);
  color: var(--ink);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-inline-size: 100%;
}

.pgrid__role {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-inline-size: 100%;
}

.pgrid__role {
  font-size: var(--fs-app-xxs);
  font-weight: 600;
  display: inline-flex;
  align-items: center;
  gap: 4px;
  color: var(--muted);
}

.pgrid__role i {
  /* v6.2 §D3: flex:none. As a shrinkable flex item the role dot collapsed to
     zero width the moment the who-column tightened (561-640px), so 3 of the 4
     rows lost their colour code entirely. */
  flex: none;
  inline-size: 6px;
  block-size: 6px;
  border-radius: 50%;
  background: var(--rc, var(--muted));
}

.pgrid__cell {
  /* 6px -> 3px: six day columns need every pixel the four never did, and the
     gutter is cheaper to give up than the chip's own type. The tightest desktop
     band is 981-1280px, where the frame's bleed has not yet ramped up and the
     grid is only ~607px - that width, not the widest one, is what these numbers
     are tuned against. */
  padding: 3px;
  min-block-size: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
}

/* Shift chip — faithful to the app's ShiftCard.
   The role cap sits on the INLINE-START edge (right in RTL, left in LTR):
   the "handle". This mirrors the documented product decision in
   app/components/ShiftCard.tsx — a colour cap wider than a hairline would
   normally read as a decorative side-stripe, but here it encodes ROLE, the
   way calendar apps mark event categories. It was inline-END here, i.e. the
   opposite edge from the real product. */
.pshift {
  inline-size: 100%;
  background: var(--white);
  border: 1px solid var(--line-strong);
  border-inline-start: 3px solid var(--rc, var(--muted));
  border-radius: 9px;
  /* 3px inline, not 5px: six day columns leave ~85px per cell, and the time
     range needs 67px of it - the chip's own gutter was the last few pixels
     available without shrinking the type. */
  padding: 4px 2px;
  text-align: center;
  box-shadow: 0 1px 2px rgba(35, 26, 18, 0.06);
  opacity: 0;
  transform: translateY(7px) scale(0.9);
}

.pshift .num {
  display: block;
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-app-xs);
  white-space: nowrap;
  color: var(--ink);
}

/* The full FROM-TO range, at EVERY width (v6 §4.1).
   Re-measured at 11.52px Heebo 700 (was 78.2px under Rubik): "07:00 - 15:00"
   needs 69.7px of chip interior; rendered as "07:00-15:00" (hyphen, NO spaces,
   per SPEC S4.3) it needs 63.9px. Heebo's digits are narrower than Rubik's, so
   the 104px column below has MORE headroom than it was sized for, not less.
   Below 640px the four day columns used to be squeezed to 36-63px, which is why
   the separator, the range end AND the role label were all hidden - 16 chips
   that read only "07:00" on the surface that matters most. The fix is FEWER
   DAYS, not less information: the columns go to a fixed 104px (chip content box
   ~86px, so the range fits with headroom) and the week is CLIPPED by .pgrid's
   existing overflow:hidden. A partly visible third column is the "the week
   continues" signal. Re-measure against the chip content box, not against the
   other chips, before touching either side of this. */

/* keep mixed-direction tokens (e.g. "ה-AI") on one line */
.nb {
  white-space: nowrap;
}

/* v6.2 §D4: the English staff names ("Omer Dahan", "Maya Peretz") ellipsized at
   every width including 1440px - the 128px who-track is tuned to the shorter
   Hebrew names. EN gets 136px. This must sit BEFORE the 640px block, and that
   block must name :lang(en) too: (0,2,0) beats the plain (0,1,0) rule and a
   media query adds no specificity, so otherwise EN would keep 136px + 1fr day
   columns on a phone. */
:lang(en) .pgrid__row {
  /* 128px team track - English names ("Maya Peretz") run longer than the
     Hebrew ones and clipped at the 112px Hebrew width. Same six day tracks:
     the row must carry all 24 chips in both languages, or the status bar's
     "24 shifts" is only true on one of them. */
  grid-template-columns: 128px repeat(6, minmax(81px, 1fr));
}

/* v6 §4.1: fewer days, fully legible. The day columns take a FIXED width so the
   chips keep their full range plus role label; the row overflows .pgrid and is
   clipped there (.pgrid already carries overflow:hidden), which is what turns
   the 4th column into an edge crop instead of a squeeze. Keep this at 640px so
   it matches the .proof stacking breakpoint. */
@media (max-width: 640px) {
  /* 6 tracks here too - the row must carry the same 24 chips at every width,
     only narrower, so the countable 4x6 holds on a phone as well. */
  .pgrid__row,
  :lang(en) .pgrid__row {
    /* 92px, not 88: at 88 the name box came up exactly 1px short of "Maya
       Peretz" through this whole band, so EN ellipsized from 320 to 560 while
       HE fit. The row already overflows .pgrid by ~400px here and crops behind
       the fade, so the extra 4px costs nothing visible — it comes out of the
       part of the week that is deliberately cut off. */
    grid-template-columns: 92px repeat(6, 104px);
  }
  /* v6.2 §D3: the compact who/cell padding moved UP from 560px so it lands
     together with the 88px fixed track. At 561-640px the wide padding inside a
     newly-narrow column squeezed the Hebrew team names into a ~36px box and
     ellipsized every one of them. */
  .pgrid__who {
    padding: 8px 6px;
  }
  .pgrid__cell {
    padding: 4px 3px;
    min-block-size: 44px;
  }
}

/* v6.2 §D3, second half. The padding move alone does NOT meet the fix's own
   acceptance criteria - MEASURED at 561/600/640 the names were still
   ellipsized and the crop signal was still gone. Cause: at 561-640px the hex
   avatar is still shown (it hides at <=560), so of the 88px who-column only
   88 - 12 padding - 1 border - 24 avatar - 7 gap = 44px reached the name, and
   the longest names need 56px (HE) / 82px (EN). Separately, 88 + 4x104 = 504px
   is NARROWER than the grid in this band (482 / 518 / 555), so the row stopped
   overflowing .pgrid and the "week continues" edge crop disappeared, leaving a
   dead strip instead.
   152px fixes both at once: the name box becomes 108px, and the row becomes
   568px, which overflows the grid by 86 / 50 / 13px at 561 / 600 / 640.
   Scoped with min-width so the <=560 phone layout - where the avatar is hidden
   and 88px is correct - is untouched. */
/* SIX day tracks, not four. A row has 7 children (who + 6 days); declaring 5
   tracks does NOT drop the last two days, it auto-places them into an implicit
   SECOND row - the day headers visibly wrapped to a second line at 561-640px
   and the grid read as broken. The overflow-and-crop this block wants comes
   from .pgrid's overflow:hidden, never from under-declaring tracks. Keep the
   track count at 6 in every band; only the widths change. */
@media (min-width: 561px) and (max-width: 640px) {
  .pgrid__row,
  :lang(en) .pgrid__row {
    grid-template-columns: 152px repeat(6, 104px);
  }
}

/* Compact product frame on phones: tighter columns and cells */
@media (max-width: 560px) {
  .papp {
    padding: 9px;
  }
  .pgrid__name {
    font-size: var(--fs-app-sm);
  }
  .pgrid__role {
    font-size: var(--fs-app-xxs);
  }
  .pshift {
    padding: 4px 3px;
    border-radius: 7px;
  }
  .papp__week {
    display: none;
  }
  .pchip-btn {
    font-size: var(--fs-app-xs);
    padding-inline: 10px;
  }
  /* Four items (three stats + the published pill) do not fit one phone line, and
     unwrapped they broke "סידור פורסם" across two lines INSIDE its pill. The
     stats take the whole first line; the pill drops to its own, still on the
     inline-end edge, which is where the real app puts it. */
  .papp__status {
    flex-wrap: wrap;
    row-gap: 8px;
  }
  .pstats {
    flex: 1 0 100%;
    gap: 10px;
  }
}

.pshift small {
  font-size: var(--fs-app-xxs);
  font-weight: 600;
  color: var(--muted);
}

/* The build cascade. The phase 1->2 flip changes background, border, shadow
   and the chip's text - opacity and transform are IDENTICAL on both sides of
   it (the waiting slot is already opacity:1/no-offset). The transition must
   therefore cover the paint properties, or the whole week pops in on one
   frame and the --d stagger is dead code. Declared on the SHOWN state only,
   so the load-time rewind (markup ships phase 4, main.js resets to 0 before
   first paint) stays an instant snap instead of a visible un-build. */
.pf[data-phase='2'] .pshift,
.pf[data-phase='3'] .pshift,
.pf[data-phase='4'] .pshift {
  opacity: 1;
  transform: translateY(0) scale(1);
  transition:
    opacity 0.42s var(--ease-out),
    transform 0.5s var(--ease-out),
    background-color 0.42s var(--ease-out),
    border-color 0.42s var(--ease-out),
    box-shadow 0.42s var(--ease-out);
  transition-delay: var(--d, 0s);
}

/* chip text rises into its cell (--d inherits from the cell's inline style) */
.pf[data-phase='2'] .pshift > *,
.pf[data-phase='3'] .pshift > *,
.pf[data-phase='4'] .pshift > * {
  opacity: 1;
  translate: 0 0;
  transition: opacity 0.42s var(--ease-out), translate 0.45s var(--ease-out);
  transition-delay: calc(var(--d, 0s) + 0.06s);
}

/* Phases 0-1: the whole week is waiting slots. The empty grid is the
   "before" that motivates the button press in phase 1 - it is on screen for
   under a second before the press fills it (timing in main.js). */
.pf[data-phase='0'] .pshift,
.pf[data-phase='1'] .pshift {
  opacity: 1;
  transform: none;
  background: var(--cream);
  border-color: transparent;
  border-inline-start-color: transparent;
  box-shadow: none;
}

.pf[data-phase='0'] .pshift > *,
.pf[data-phase='1'] .pshift > * {
  opacity: 0;        /* opacity, not visibility: the shown state fades it in */
  translate: 0 5px;  /* content rises INTO the slot when the AI places it */
}

/* toast */
.ptoast {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-block-start: 12px;
  background: var(--espresso-2);
  color: var(--on-dark);
  border-radius: var(--radius);
  padding: 10px 14px;
  font-size: var(--fs-app-md);
  font-weight: 600;
  box-shadow: var(--shadow-card);
  opacity: 0;
  transform: translateY(8px);
  transition: opacity 0.45s var(--ease-out) 0.5s, transform 0.55s var(--ease-out) 0.5s;
}

.ptoast img {
  inline-size: 22px;
  block-size: 22px;
}

.ptoast .ic {
  color: #8fbe6e;
}

.pf[data-phase='4'] .ptoast {
  opacity: 1;
  transform: translateY(0);
}

/* reduced motion: land on the finished state, no theatrics */
@media (prefers-reduced-motion: reduce) {
  .pshift,
  .pshift > *,
  .ppub,
  .ptoast {
    opacity: 1 !important;
    transform: none !important;
    translate: none !important;
    transition: none !important;
  }
  .pf .pchip-btn--gold {
    animation: none !important;
  }
}

/* ---------- Fact strip (directly under the hero) ---------- */

/* ---------- Reveal-on-scroll (hidden states only when JS is present) ----------
   NOTE: the hidden state uses :where() so it carries zero extra specificity and
   the .is-in reveal always wins. */
html.js :where(.rv) {
  opacity: 0;
  transform: translateY(16px);
}

.rv.is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.6s var(--ease-out), transform 0.65s var(--ease-out);
  transition-delay: var(--rd, 0s);
}

@media (prefers-reduced-motion: reduce) {
  html.js :where(.rv) {
    opacity: 1;
    transform: none;
  }
}

/* Failsafe: main.js did not boot within 3s, so nothing is going to add .is-in.
   Without this the whole page below the hero - demo form included - stays
   invisible. Armed by the inline <head> script, cancelled by main.js. */
html.rv-failsafe :where(.rv) {
  opacity: 1;
  transform: none;
}

/* Print never scrolls, so unrevealed sections would come out blank. */
@media print {
  html.js :where(.rv) {
    opacity: 1;
    transform: none;
  }
}

/* Section banding lives in ONE place: .section--cream / .section--white.
   The legacy .problem / section#faq / .steps banding rules that used to sit
   here were overridden for background but NOT for border, so they kept
   drawing full-width hairlines nobody had asked for. */

/* ---------- Scroll-choreography details ---------- */
/* ---------- Hero load choreography (pure CSS, one-time, no JS dependency) ---------- */
@keyframes hero-rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
}

/* One gentle rise for the COPY only, on the calm curve (--ease-enter).
   The product card gets NO entrance animation - deliberately. It is 60% of
   the hero; fading it in meant the page's dominant object arrived LAST, into
   a large dark void (filmstrip-verified), and every later story beat queued
   behind it. A card that is simply present at first paint is not a "pop" -
   the initial paint is one accepted frame. Its only motion is the story
   itself: the AI pulse, the staggered build, the pills, the toast. */
html.js .hero h1 { animation: hero-rise 0.9s var(--ease-enter) both; }
html.js .hero .hero__sub { animation: hero-rise 0.9s var(--ease-enter) 0.1s both; }
html.js .hero .hero__cta { animation: hero-rise 0.9s var(--ease-enter) 0.18s both; }
html.js .hero .hero__trust { animation: hero-rise 0.9s var(--ease-enter) 0.26s both; }

/* gentle drift as the hero frame scrolls away (supporting browsers only) */
@media (prefers-reduced-motion: no-preference) {
  @supports (animation-timeline: view()) {
    .hero .pframe {
      animation: frame-drift linear both;
      animation-timeline: view();
      animation-range: exit 0% exit 100%;
    }
  }
}

@keyframes frame-drift {
  to {
    transform: translateY(-16px);
  }
}

/* The bubbles' staggered arrival lives with the rest of the chat styles and is
   driven by an explicit --i index, NOT by :nth-of-type. The version that used
   to live here counted `@keyframes bump {
  30% {
    transform: scale(1.07);
  }
}

@media (prefers-reduced-motion: reduce) {
  
}

@media (max-width: 820px) {
  
}

/* ---------- Sticky mobile CTA ---------- */
.mcta {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 55;
  padding: 10px clamp(16px, 4vw, 24px) calc(10px + env(safe-area-inset-bottom, 0px));
  background: rgba(26, 18, 11, 0.92);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-block-start: 1px solid var(--dark-line);
  display: none;
}

.mcta .btn {
  inline-size: 100%;
}

/* v6 §5: suppressed once #demo is on screen. It permanently covered
   .dform__micro and its privacy.html consent link, and it is a decoy anyway -
   it targets #demo while the reader is already there. */
@media (max-width: 880px) {
  html.js body.past-hero:not(.at-demo) .mcta {
    display: block;
    animation: mcta-rise 0.45s var(--ease-out);
  }
}

@keyframes mcta-rise {
  from {
    transform: translateY(100%);
  }
  to {
    transform: translateY(0);
  }
}

@media (prefers-reduced-motion: reduce) {
  .mcta {
    animation: none !important;
  }
  html.js .hero h1,
  html.js .hero .hero__sub,
  html.js .hero .hero__cta,
  html.js .hero .hero__trust,
  html.js .chat .bubble {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    animation: none !important;
  }
  .hero .pframe {
    animation: none !important;
  }
}

/* availability days tap themselves in when step 2 enters */
.vavail__day.on {
  background: transparent;
  border-color: var(--line-strong);
  color: var(--muted);
  transition: background-color 0.35s ease, border-color 0.35s ease, color 0.35s ease;
  transition-delay: var(--d, 0s);
}

.vavail__day .ic {
  visibility: visible;
  opacity: 0;
  transform: scale(0.4);
  transition: opacity 0.3s var(--ease-out), transform 0.4s var(--ease-out);
  transition-delay: var(--d, 0s);
}

.vavail__day:not(.on) .ic {
  visibility: hidden;
}

.rv.is-in .vavail__day.on {
  background: var(--gold-soft);
  border-color: var(--gold-deep);
  color: var(--gold-ink);
}

.rv.is-in .vavail__day.on .ic {
  opacity: 1;
  transform: scale(1);
}

/* applied-rule chips confirm one after another */
html.js .vrules__applied .vres-chip {
  opacity: 0;
  transform: translateY(8px);
}

.rv.is-in .vrules__applied .vres-chip {
  opacity: 1;
  transform: none;
  transition: opacity 0.45s var(--ease-out), transform 0.5s var(--ease-out);
}

.rv.is-in .vrules__applied .vres-chip:nth-child(1) { transition-delay: 0.25s; }
.rv.is-in .vrules__applied .vres-chip:nth-child(2) { transition-delay: 0.45s; }
.rv.is-in .vrules__applied .vres-chip:nth-child(3) { transition-delay: 0.65s; }

/* quiet hover lift on tactile surfaces (hover devices only) */
@media (hover: hover) {
  .step__viz,
  .chat {
    transition: transform 0.3s var(--ease-out), box-shadow 0.3s var(--ease-out);
  }
  .step__viz:hover,
  .chat:hover {
    transform: translateY(-3px);
    box-shadow: 0 8px 30px rgba(35, 26, 18, 0.1);
  }
}

/* reduced motion: everything above lands in its final state instantly */
@media (prefers-reduced-motion: reduce) {
  .vrules__applied .vres-chip {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
  .vres__ring .fill {
    stroke-dashoffset: 0 !important;
    transition: none !important;
  }
  .vavail__day.on {
    background: var(--gold-soft) !important;
    border-color: var(--gold-deep) !important;
    color: var(--gold-ink) !important;
    transition: none !important;
  }
  .vavail__day.on .ic {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* ---------- Section headings ---------- */
/* ============================================================
   v4 - SECTION HEAD SYSTEM (ADDENDUM S4)
   Four states, three levers: deck colour, head->body drop, container width.
   Hierarchy is NEVER expressed as a new type size or a deviant section
   padding - that is what made every section read as dimensionally identical.
   Zero gold spent. Zero new visual devices.
   Measured: --stone on cream 6.80:1 / on white 7.53:1
             --muted on cream 4.69:1 (FAQ deck only, a deliberate demotion)
   ============================================================ */
.sec-head {
  margin-block-end: var(--head-gap);
}

.sec-head--major { margin-block-end: var(--head-gap-major); }

/* The eyebrow is always a <p>, never a heading: the h1->h2->h3 outline has to
   stay legal and the HE/EN parity check counts heading elements.
   No letter-spacing, no uppercase, no italics - Hebrew has none of them. There
   is also no second family to reach for since the Heebo migration, so the
   eyebrow's whole voice is size + weight + colour. That is a shorter lever than
   it used to be: do not try to win it back by adding a family. */
.sec-head__eyebrow {
  display: block;
  margin: 0 0 var(--head-lead);
  font-family: 'Heebo', system-ui, sans-serif;
  font-size: var(--fs-sm);   /* FLOOR. Never --fs-xs: 12.8px Hebrew loses word
                                shape entirely - no ascenders or descenders. */
  font-weight: var(--fw-mid);
  line-height: var(--lh-lead);
  color: var(--stone);
}

.sec-head h2 {
  margin: 0;
  font-size: var(--fs-h2);
  font-weight: var(--fw-display);   /* 700, never 800: 800 is the hero's, and
                                       Heebo Hebrew at 800 slabs just as Rubik did */
  line-height: var(--lh-display);
  color: var(--ink);
  /* 24ch, up from the 20ch tuned against Rubik. `ch` measures the ZERO glyph,
     and Heebo's is 0.562em against Rubik's 0.679em - so the Heebo migration
     silently tightened EVERY ch measure on this page by 17% and pushed two
     section heads onto a second line. All the ch measures below are scaled by
     the same 1.209 to hold the RENDERED width the copy was hand-fitted to.
     The two ch values NOT scaled are .pstats__num and .calc__hours-out: those
     guard digit strings, which is exactly what ch measures. */
  max-inline-size: 24ch;
  text-wrap: balance;
}

.sec-head--major h2 { max-inline-size: 29ch; }

.sec-head__deck {
  margin: var(--head-deck) 0 0;
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: var(--body);
  max-inline-size: min(34em, 48ch);
  text-wrap: pretty;
}

/* lever: deck colour. Spent once on the engine, once on the FAQ. */
.sec-head--major .sec-head__deck { color: var(--ink); }
.sec-head--minor .sec-head__deck { color: var(--muted); }

/* the page's ONE centred head. `center` is direction-neutral, so it is legal
   under the logical-properties rule where left/right are not. */
.sec-head--close { text-align: center; }
.sec-head--close .sec-head__eyebrow { color: var(--on-dark-muted); }
.sec-head--close h2 { color: var(--on-dark); max-inline-size: 27ch; margin-inline: auto; }
.sec-head--close .sec-head__deck { color: var(--on-dark-muted); margin-inline: auto; }

/* The .num family switch that used to live here is gone. It existed because
   only Rubik of the old pair carried tabular figures. Heebo exposes no `tnum`
   feature at all - it does not need one: every digit 0-9 is 1151 units wide by
   default, so figures already align in a column. Nothing to declare. */

/* English measures run ~35% longer than the tuned Hebrew ones */
:lang(en) .sec-head h2 { max-inline-size: 31ch; }
:lang(en) .sec-head--major h2 { max-inline-size: 36ch; }
:lang(en) .sec-head--close h2 { max-inline-size: 34ch; }
:lang(en) .sec-head__deck { max-inline-size: min(34em, 63ch); }

@media (max-width: 560px) {
  :root { --head-gap: 24px; --head-gap-major: 40px; }
  .sec-head h2,
  .sec-head--major h2,
  .sec-head--close h2,
  .sec-head__deck,
  :lang(en) .sec-head__deck,
  .pivot,
  :lang(en) .pivot { max-inline-size: none; }
  /* centred Hebrew display type at 390px is ragged on both edges and looks
     worse than left-aligned. A phone has no room for a poster. */
  .sec-head--close { text-align: start; }
  .sec-head--close h2,
  .sec-head--close .sec-head__deck { margin-inline: 0; }
  .pivot { font-size: var(--fs-lead); }
}

/* ---- THE PIVOT (ADDENDUM S6). A display-weight line that is ALWAYS the last
   element of a section and ALWAYS redirects the reader into the next h2.
   Two binding refusals: a pivot never follows a CTA (it would license an exit
   at the moment of the ask), and two seams stay bare so the device does not
   become wallpaper. Type, not a graphic - costs nothing from the device budget. */
.pivot {
  margin-block: clamp(24px, 3.5vw, 40px) 0;
  max-inline-size: 36ch;
  font-family: 'Heebo', system-ui, sans-serif;
  font-size: var(--fs-h3);
  font-weight: var(--fw-display);
  line-height: var(--lh-display);
  color: var(--ink);
}

/* the reader's own voice, so it steps back from the page's */
.pivot--ask { font-weight: var(--fw-mid); color: var(--stone); }

:lang(en) .pivot { max-inline-size: 46ch; }

/* ---- the mid-page CTA is a composed block, not a naked button (ADDENDUM S7.9).
   A gold button dropped into flow with margin around it is the loudest amateur
   tell on a SaaS page; a rule plus a de-risking line beside it reads as an
   end-of-argument move - and it is what makes the gold famine pay off. ---- */
.ctablock {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 16px;
  margin-block-start: clamp(40px, 5vw, 56px);
  padding-block-start: clamp(24px, 3.5vw, 32px);
  border-block-start: 1px solid var(--dark-line);
}

/* ONE flex item: a sentence left as a bare text node would let the gap open
   mid-phrase (see README editing rules). */
.ctablock__micro {
  margin: 0;
  font-size: var(--fs-sm);
  color: var(--muted);
  max-inline-size: 31ch;
}

@media (max-width: 640px) {
  .ctablock { display: block; }
  .ctablock .btn { display: flex; justify-content: center; inline-size: 100%; min-block-size: 52px; }
  .ctablock__micro { margin-block-start: 12px; max-inline-size: none; }
}

/* ---------- Problem section ---------- */
.problem {
  background: var(--cream);
}

.problem__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(32px, 5vw, 60px);
  align-items: center;
}

.pains {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: 18px;
}

.pains li {
  display: flex;
  gap: 14px;
  align-items: flex-start;
  font-size: var(--fs-body);
  line-height: 1.6;
}

.pains .ic {
  color: var(--gold-deep);
  margin-block-start: 5px;
}

/* WhatsApp chaos vignette */
.bubble {
  position: relative;
  display: flow-root;   /* contain the floated time+receipt inside the bubble */
  max-inline-size: 82%;
  inline-size: fit-content;
  border-radius: 8px;
  padding: 6px 9px 8px;
  font-size: var(--fs-app-md);
  line-height: 1.45;
  margin-block-end: 8px;
  box-shadow: 0 1px 0.5px rgba(11, 20, 26, 0.13);
}

/* the tail: a small triangle at the top corner, the way WhatsApp draws it */
.bubble::after {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inline-size: 0;
  block-size: 0;
  border-block-start: 9px solid transparent;
}

.bubble--in {
  background: #ffffff;
  border-start-start-radius: 0;
}

.bubble--in::after {
  inset-inline-start: -8px;
  border-inline-end: 9px solid #ffffff;
}

.bubble--out {
  background: #d9fdd3;
  margin-inline-start: auto;
  border-start-end-radius: 0;
}

.bubble--out::after {
  inset-inline-end: -8px;
  border-inline-start: 9px solid #d9fdd3;
}

/* time + read receipt, tucked to the bubble's end like the real client.
   v6.2 §B4: a second .bubble time block used to sit ~42 lines below this one and
   silently override display / colour / text-align, leaving only the float from
   here - so the authored rule was half dead code. The duplicate is gone and its
   one wanted declaration, `color: var(--muted)` (4.69:1), is folded in here. */
.bubble time {
  display: inline-flex;
  align-items: center;
  gap: 3px;
  float: inline-end;
  margin-inline-start: 10px;
  margin-block-start: 4px;
  font-size: var(--fs-app-xxs);
  color: var(--muted);
}

.bubble--out time::after {
  content: "";
  display: inline-block;   /* an inline box ignores inline-size/block-size */
  inline-size: 15px;
  block-size: 11px;
  background: #53bdeb;   /* the blue double-check */
  -webkit-mask: var(--tick) center / contain no-repeat;
  mask: var(--tick) center / contain no-repeat;
}

/* Messages land one after another instead of all at once - a chat that
   appears fully-formed reads as a screenshot, not as a conversation. */
.chat .bubble {
  opacity: 0;
  transform: translateY(8px);
}

.chat.is-in .bubble {
  animation: bubble-in 0.34s var(--ease-out) forwards;
  animation-delay: calc(var(--i) * 0.55s + 0.35s);
}

@keyframes bubble-in {
  to { opacity: 1; transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .chat .bubble { opacity: 1; transform: none; }
  .chat.is-in .bubble { animation: none; }
}

/* ---------- Steps ---------- */
.steps {
  /* banding: see .section--white */
}

.steps__rail {
  position: relative;
  display: grid;
  gap: clamp(28px, 3.5vw, 44px);
  padding-inline-start: 54px;
}

.steps__line {
  position: absolute;
  inset-inline-start: 19px;
  inset-block: 8px;
  inline-size: 2px;
  background: var(--line-strong);
  overflow: hidden;
}

.steps__line i {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  background: var(--gold-deep);
  transform: scaleY(0);
  transform-origin: top;
  transition: transform 1.1s var(--ease-out);
}

.steps__rail.is-in .steps__line i {
  transform: scaleY(1);
}

.step {
  position: relative;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(24px, 4vw, 48px);
  /* Headings align with the top of their vignette, not its centre — the cards
     vary in height, and centring made each step's copy float at a different
     offset from its own numbered dot. */
  align-items: start;
}

.step__dot {
  position: absolute;
  inset-inline-start: -54px;
  inset-block-start: 4px;
  inline-size: 40px;
  block-size: 40px;
  border-radius: 50%;
  background: var(--white);
  border: 2px solid var(--gold-deep);
  color: var(--gold-ink);
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 800;
  font-size: var(--fs-body);
  display: flex;
  align-items: center;
  justify-content: center;
}

.step h3 {
  font-size: var(--fs-h3);
  font-weight: 700;
}

.step p {
  margin-block-start: 10px;
  color: var(--body);
}

/* All three vignettes are one set, so they get one height — otherwise the
   staffing rows, the day pills and the comb make three cards of wildly
   different size stacked down a single rail. Content centres in the extra
   room rather than stretching to fill it. */
.step__viz {
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--card-radius);
  box-shadow: var(--shadow-card);
  padding: var(--card-pad);
  display: grid;
  align-content: center;
}

@media (max-width: 880px) {
  .step {
    grid-template-columns: 1fr;
  }
  .problem__grid {
    grid-template-columns: 1fr;
  }
}

/* staffing vignette */
.vstaff {
  display: grid;
  gap: 10px;
}

/* Grid, not flex, and deliberately so. The count badge used to be pinned with
   `margin-inline-start: auto` on a flex row - but `.count` also carries `.num`,
   which sets `direction: ltr`, and that flips the element's OWN logical
   properties. So inline-start resolved to margin-LEFT, which is the correct
   side in the LTR page and the wrong one in RTL: the badges drifted with the
   width of each role name (measured 279 / 281 / 285px in Hebrew) while English
   looked fine. This is the same trap that once pushed the step dots off-screen.
   A three-column grid pins the badge to its own track and never consults
   direction at all, so the flip cannot reach it. Do not "simplify" this back
   to flex + auto margin. */
.vstaff__row {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 10px;
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 9px 14px;
  font-weight: 600;
  font-size: var(--fs-app-sm);
  color: var(--ink);
}

.vstaff__row i {
  inline-size: 9px;
  block-size: 9px;
  border-radius: 50%;
  background: var(--rc);
}

.vstaff__row .count {
  /* no auto margin: the grid's third track already pins it (see above) */
  justify-self: end;
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 800;
  color: var(--gold-ink);
  background: var(--gold-soft);
  border-radius: 8px;
  padding: 1px 10px;
}

/* availability vignette */
.vavail {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  justify-content: center;
}

.vavail__day {
  inline-size: 46px;
  block-size: 56px;
  border-radius: 12px;
  border: 1.5px solid var(--line-strong);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  font-weight: 700;
  color: var(--muted);
  font-size: var(--fs-app-sm);
}

.vavail__day.on {
  background: var(--gold-soft);
  border-color: var(--gold-deep);
  color: var(--gold-ink);
}

.vavail__day .ic {
  width: 0.95em;
  height: 0.95em;
  color: var(--gold-deep);
  visibility: hidden;
}

.vavail__day.on .ic {
  visibility: visible;
}

/* publish vignette */
/* ---------- Hive: the AI-generating moment ----------
   A port of the product's HiveProgress (app/components/HiveProgress.tsx) —
   the same 19-cell 3-4-5-4-3 comb, the same 250×192 stage, the same fill
   order (clockwise perimeter → inner ring → centre last) and the same three
   rotating golds. Step 3 previously showed a PUBLISH button, which described
   the wrong moment: the step is "the AI builds the week". The filling comb
   IS the progress display in the app, so it is here too — no percentage. */

/* .hive .hive__cap, not .hive__cap: `.step p` sets a 10px top margin and beats
   a single class — that margin pushed step 3 past the shared card height. */

/* The chip, not a sparkle: the app marks "the AI is working" with the compute
   chip from onboarding (app/components/AIChipMark.tsx) precisely so it reads as
   OUR AI rather than generic magic. Same die, same gold pins, same bolt — the
   core breathes and the bolt flickers while the comb fills. */

@media (prefers-reduced-motion: no-preference) {
  
  
}

@media (prefers-reduced-motion: no-preference) {
  
}
.rv.is-in .hive__fill {
  opacity: 1;
  transform: scale(1);
}
/* Cells filling is DATA (how much of the week is built), not decoration —
   so with reduced motion they still end up filled, just without the stagger.
   Mirrors the same decision in the product component. */
@media (prefers-reduced-motion: reduce) {
  
}

/* The bee — the same worker that hops cell-to-cell in the product while the
   schedule is generated. It follows the identical fill ORDER, at the identical
   0.085s cadence, so the comb and the bee stay in step. Parked on the centre
   cell at the end, exactly where the product leaves it. */

.rv.is-in .hive__bee {
  animation: hive-bee 1.53s var(--ease-out) forwards;
}

@media (prefers-reduced-motion: no-preference) {
  
  
}

/* The bee delivers the last cell and leaves — it lifts off and fades, so the
   finished comb is left clean and the caption flips to the product's done
   state. 1.53s of travel + a beat on the centre cell = 2.1s. */
.rv.is-in .hive__bee-art {
  animation: hive-bee-out 0.55s ease-in 2.1s forwards;
}
.rv.is-in .hive__cap-a {
  animation: hive-cap-out 0.35s ease 2.15s forwards;
}
.rv.is-in .hive__cap-b {
  animation: hive-cap-in 0.35s ease 2.35s forwards;
}

/* Reduced motion: the comb arrives already full, so it arrives already DONE —
   no bee to fly off, and the caption starts at the done state. */
@media (prefers-reduced-motion: reduce) {
  .rv.is-in .hive__bee,
  .rv.is-in .hive__bee-art,
  .rv.is-in .hive__cap-a,
  .rv.is-in .hive__cap-b {
    animation: none;
  }
  /* `.hive__cap > span` sets display, so hiding the working caption needs to
     outweigh it — at one class it lost, and both captions rendered on top of
     each other in the same grid cell. */
  
  
}

/* ---------- Why / features ---------- */
.feature {
  display: grid;
  grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: clamp(30px, 5vw, 64px);
  align-items: center;
}

.feature + .feature {
  margin-block-start: clamp(44px, 5.5vw, 72px);
}

.feature--flip .feature__copy {
  order: 2;
}

.feature h3 {
  font-size: var(--fs-h3);
  font-weight: 800;
  line-height: 1.25;
}

.feature p {
  margin-block-start: 14px;
  font-size: var(--fs-body);
}

/* Feature vignettes — same visual system as the hero product frame */
/* A mini panel is a CARD, not a third fake browser window. SPEC S5.7 allows
   exactly one desktop chrome on the page (the hero); repeating the dots-and-URL
   bar twice more made the page read as a stack of screenshots and was the
   single biggest source of "too many cards". These two keep the app's real
   interior and drop the costume. */
.pframe--mini {
  max-inline-size: 480px;
  margin-inline: auto;
  background: var(--white);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
  overflow: hidden;
}

.section--white .pframe--mini {
  background: var(--cream);
  box-shadow: none;
}

.pframe--mini .papp {
  padding: var(--pad-card);
  background: transparent;
}

/* results vignette: the "safe to approve" moment */
.vres__hero {
  display: flex;
  align-items: center;
  /* v6.2 §D1: the 74px comb plus the "100% / fully staffed" stack could not fit
     one line inside the step card at 320px, and the row - the last unwrappable
     object on the page - pushed documentElement.scrollWidth to 333px, i.e. 13px
     of horizontal page scroll (WCAG 1.4.10 reflow). Wrapping takes it to 320. */
  flex-wrap: wrap;
  gap: 18px;
  padding-block-end: 18px;
  border-block-end: 1px solid var(--line);
}

/* The coverage readout IS the brand mark (SPEC S5.7). This retires the circular
   ring - drawn in a teal that existed nowhere else on the site - and makes the
   honeycomb carry information instead of decorating it. A full comb is a fully
   staffed week: the page's whole argument in one 74px object. */
.vcomb {
  inline-size: 74px;
  block-size: 74px;
  flex: none;
}

.vcomb polygon {
  fill: var(--gold);
}

/* One entrance, then silence: the comb fills cell by cell as step 3 reveals. */
.rv.is-in .vcomb polygon {
  animation: comb-fill 0.42s var(--ease-out) backwards;
  animation-delay: calc(var(--i) * 0.055s + 0.12s);
}

@keyframes comb-fill {
  from { opacity: 0; }
  to { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .rv.is-in .vcomb polygon { animation: none; }
}

/* the panel's hero stat - deliberately the one outsized numeral in the mock */
.vres__pct {
  display: block;
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 800;
  font-size: 1.9rem;
  line-height: 1.1;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

.vres__sub {
  font-weight: 700;
  color: var(--ink);
  font-size: var(--fs-app-lg);
}

.vres__stats {
  margin-block-start: 4px;
  font-size: var(--fs-app-md);
  font-weight: 600;
  color: var(--muted);
}

.vres__rules {
  list-style: none;
  margin: 0;
  padding: 16px 0 0;
  display: grid;
  gap: 11px;
}

.vres__rules li {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  font-size: var(--fs-app-md);
  font-weight: 600;
  color: var(--ink);
}

.vres__rules .ic {
  color: var(--olive);
  margin-block-start: 2px;
}

.vres__cta {
  margin-block-start: 18px;
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.vres__hint {
  font-size: var(--fs-app-sm);
  color: var(--muted);
  font-weight: 600;
}

/* rules vignette: plain-language rules in, applied rules out */
.vrules__label {
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-app-lg);
  color: var(--ink);
  margin-block-end: 10px;
}

.vrules__box {
  background: var(--cream);
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius);
  padding: 14px 16px;
  font-size: var(--fs-app-lg);
  line-height: 1.75;
  color: var(--body);
}

.vrules__box i {
  font-style: normal;
  display: block;
}

.vrules__caret {
  display: inline-block;
  inline-size: 2px;
  block-size: 1.05em;
  background: var(--gold-deep);
  /* text-bottom drops the bar to the DESCENDER line, which in Hebrew - where
     no glyph has a descender - parks it visibly below the letters it is
     supposed to sit beside. Align to the middle of the line box instead and
     let the 1.05em height cover the x-height. */
  vertical-align: middle;
  margin-inline-start: 2px;
  position: relative;
  inset-block-start: -0.06em;
}

@media (prefers-reduced-motion: no-preference) {
  .vrules__caret {
    animation: caret-blink 1.1s steps(1) infinite;
  }
}

@keyframes caret-blink {
  50% {
    opacity: 0;
  }
}

.vrules__applied {
  margin-block-start: 16px;
  display: grid;
  gap: 9px;
}

.vres-chip {
  display: inline-flex;
  align-items: center;
  /* The label is wrapped in .lbl so the whole sentence is ONE flex item.
     Left as bare text nodes, an inline <bdi> inside it became its own item and
     the gap opened on both sides of the number ("על | 28 | שעות"); setting
     gap:0 instead collapsed the real word spaces, because flex trims
     whitespace-only text at an item boundary. Wrapping fixes both. */
  gap: 8px;
  justify-self: start;
  background: var(--olive-bg);
  border: 1px solid var(--olive-line);
  color: #55603c;
  border-radius: 999px;
  padding: 7px 14px;
  font-weight: 700;
  font-size: var(--fs-app-md);
}

.vres-chip .ic {
  color: var(--olive);
}

@media (max-width: 880px) {
  .feature {
    grid-template-columns: 1fr;
  }
  .feature--flip .feature__copy {
    order: 0;
  }
}

/* ---------- Pillars: consolidated "why trust it" grid ----------
   Absorbs the old trio + mechanism sections into one calm 2×2. Cards
   lean on background + spacing, not a heavy border-and-shadow box. */
/* Two claims, no boxes. This was four identical bordered cards — icon +
   heading + text, x4 — which is the template look, and two of the four
   simply restated the feature blocks above and the FAQ below. What is left
   is the differentiator and the safety promise, divided by a hairline
   instead of wrapped in cards. */

@media (max-width: 720px) {
  
  
  
}

/* ---------- FAQ ---------- */
.faq {
  max-width: 780px;
  margin-inline: auto;
}

.faq {
  border-radius: var(--r-card);
  /* `hidden` clipped the 3px focus ring on all six summaries to just its top and
     bottom bars - the start/end sides never painted. `clip` + a clip-margin lets
     the ring (3px wide at 3px offset = 6px) escape while the fill is still
     clipped to the rounded corners. `overflow: hidden` stays as the fallback for
     engines without overflow-clip-margin; there the ring clips as before. */
  overflow: hidden;
  overflow: clip;
  overflow-clip-margin: 8px;
}

/* dividers BETWEEN rows only - a trailing rule under the last row makes the
   group look like six loose strips instead of one object */
.faq details + details {
  border-block-start: 1px solid var(--line);
}

.faq summary {
  list-style: none;
  cursor: pointer;
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 20px var(--pad-card);
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-lead);
  color: var(--ink);
  transition: background-color 0.18s ease;
}

.faq summary:hover {
  background: var(--cream);
}

.faq details[open] summary {
  padding-block-end: 12px;
}

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

/* The question is ONE flex item. Left as bare text nodes, any inline span in a
   question (e.g. the .nb wrapper around "ה-AI") became its own flex item and
   the summary's 16px gap opened up mid-sentence. */
.faq__q {
  flex: 1;
}

.faq summary .ic {
  margin-inline-start: auto;
  color: var(--muted);
  transition: transform 0.3s var(--ease-out);
}

.faq details[open] summary .ic {
  transform: rotate(180deg);
}

.faq .faq__a {
  overflow: hidden;
}

/* The answer must hang on the SAME inline edge as its own question. It carried
   no inline padding while `.faq summary` carries `var(--pad-card)` (24px), so
   the answer ran flush into the card's border while the question above it sat
   24px in - the text read as clipped by the card rather than set inside it.
   `--pad-card` (not a literal) so it can never drift from the summary again. */
.faq .faq__a p {
  padding-inline: var(--pad-card);
  padding-block-end: 22px;
  /* 62ch on a 619px card never bound the line; the measure came from the card.
     66ch is the real cap for the two long answers, and it now measures from
     inside the padding. */
  max-width: 80ch;
}

/* ---------- Final CTA + footer ---------- */
.outro {
  background:
    radial-gradient(900px 460px at 50% -20%, rgba(240, 180, 41, 0.14), transparent 62%),
    var(--espresso);
  color: var(--on-dark);
  text-align: center;
}

.outro h2 {
  color: var(--on-dark);
  font-weight: 800;
  line-height: 1.25;
}

/* What the 10 minutes actually contains. Sells the call, not the product. */
.agenda {
  margin: 30px auto 0;
  padding: 0;
  list-style: none;
  max-width: 30em;
  display: grid;
  gap: 10px;
  text-align: start;
}

.agenda li {
  display: flex;
  align-items: baseline;
  gap: 12px;
  color: var(--on-dark-muted);
  font-size: var(--fs-body);
}

.agenda__t {
  flex: none;
  min-inline-size: 4.2em;
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-xs);
  color: var(--gold);
}

.outro__cta {
  margin-block-start: 34px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 13px;
}

/* v6 §5: moved INSIDE .dform, directly under the submit button - it is the
   strongest trust line on the page and belongs at the moment of commitment, not
   after it. So it is now on the white card, not on espresso. The sentence is one
   flex item (README: a bare text node in a gap container opens the gap
   mid-phrase). */
.outro__risk {
  display: flex;
  align-items: flex-start;
  gap: 8px;
  color: var(--stone);
  font-size: var(--fs-sm);
  line-height: 1.5;
  text-align: start;
}

.outro__risk .ic {
  flex: none;
  inline-size: 17px;
  block-size: 17px;
  margin-block-start: 3px;
  color: var(--olive);
}

.outro__emblem {
  inline-size: 56px;
  block-size: 56px;
  margin-inline: auto;
  margin-block-end: 22px;
}

/* The footer is a sibling of <main>, not a child of .outro, so that it exposes a
   real contentinfo landmark (the accessibility statement has to be reachable by
   landmark navigation). That means it can no longer inherit .outro's espresso
   band - it has to paint its own, or its --on-dark-muted links land on cream. */
.footer {
  background: var(--espresso);
  color: var(--on-dark);
  border-block-start: 1px solid var(--dark-line);
  padding-block: 30px;
}

.footer > .container {
  padding-block: 0;
}

.footer__inner {
  display: flex;
  align-items: center;
  gap: 22px;
  flex-wrap: wrap;
}

.footer__inner .brand__word {
  font-size: var(--fs-body);
}

.footer a {
  color: var(--on-dark-muted);
  text-decoration: none;
  font-size: var(--fs-sm);
  font-weight: 600;
}

.footer a:hover {
  color: var(--on-dark);
}

.footer__spacer {
  margin-inline-start: auto;
}

.footer__copy {
  color: rgba(201, 191, 169, 0.7);
  font-size: var(--fs-xs);
}

@media (max-width: 640px) {
  .footer__inner {
    justify-content: center;
    text-align: center;
  }
  .footer__spacer {
    display: none;
  }
}

/* ============================================================
   Brand geometry — the hive layer
   Honeycomb lattice on espresso surfaces, hexagons as product
   language (the app's avatars are hexagonal). Calm, not neon.
   ============================================================ */
:root {
  --hex-pattern: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='49.6' viewBox='0 0 28 49.6'%3E%3Cpath fill='%23F0B429' fill-rule='evenodd' d='M13.99 9.25l13 7.5v15l-13 7.5-13-7.5v-15l13-7.5zM3 17.45v12.6l10.99 6.34 11.01-6.35v-12.6L13.99 11.1 3 17.45z'/%3E%3C/svg%3E");
  --hex-clip: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%);
}

/* lattice over the espresso bookends, fading toward the copy */
.hero {
  position: relative;
}

.outro {
  position: relative;
  overflow: hidden;
}

/* v6 §2.2: the `:dir(rtl) .hero::before` hive mask is gone with the espresso
   hero - there is no dark texture left for it to fade. */

.hero > *,
.outro > * {
  position: relative;
}

/* the hive breathes: one-tile drift, seamless 60s loop */
@media (prefers-reduced-motion: no-preference) {
  
}

/* hexagonal staff avatars in the hero demo (mirrors the real app) */
.pgrid__who {
  flex-direction: row;
  align-items: center;
  gap: 7px;
}

.pgrid__stack {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.pgrid__ava {
  flex: none;
  inline-size: 24px;
  block-size: 26px;
  clip-path: var(--hex-clip);
  /* Flat fallback first: color-mix() is Safari 16.2+, and without this the whole
     background declaration is dropped on older iOS, leaving the hex untinted. */
  background: var(--gold-soft);
  background: color-mix(in srgb, var(--rc, var(--gold-deep)) 16%, #fff);
  color: var(--ink);
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-app-xxs);
  display: flex;
  align-items: center;
  justify-content: center;
}

@media (max-width: 560px) {
  .pgrid__ava {
    display: none;
  }
}

/* step markers become hive cells */
.step__dot {
  border-radius: 0;
  border: 0;
  clip-path: var(--hex-clip);
  background: linear-gradient(180deg, #f5be3d, var(--gold-2));
  color: var(--on-gold);
  inline-size: 42px;
  block-size: 46px;
  inset-block-start: 0;
}

html.js .step__dot {
  opacity: 0;
  transform: scale(0.55);
}

.step.rv.is-in .step__dot {
  opacity: 1;
  transform: none;
  transition: opacity 0.5s var(--ease-out) 0.15s, transform 0.6s var(--ease-out) 0.15s;
}

@media (prefers-reduced-motion: reduce) {
  
  html.js .step__dot {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
  }
}

/* ============================================================
   Demo request form (outro) — "we'll call you back"
   ============================================================ */
.dform {
  inline-size: min(460px, 100%);
  margin-inline: auto;
  background: var(--white);
  border: 1px solid var(--line);
  border-radius: var(--card-radius);
  /* the one card that floats: it is the conversion point, and the lift is the
     page's only elevation cue. Everything else sits at --shadow-card. */
  box-shadow: var(--shadow-float);
  padding: var(--card-pad);
  text-align: start;
}

.dform__grid {
  display: grid;
  gap: 16px;
}

.dform label {
  display: block;
  font-weight: 700;
  font-size: var(--fs-sm);
  color: var(--ink);
  margin-block-end: 6px;
}

.dform label small {
  font-weight: 600;
  color: var(--muted);
}

/* v6 §5: the fields fill with --cream, not white. On a white card a white input
   is a border floating in nothing; a tinted well reads as somewhere to type. */
.dform input {
  inline-size: 100%;
  block-size: 48px;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--radius);
  background: var(--cream);
  color: var(--ink);
  font-family: 'Heebo', system-ui, sans-serif;
  font-size: var(--fs-body);
  line-height: 1.5;
  padding-inline: 14px;
  transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

/* #8a8171 measured 3.85:1 on white and failed AA outright. Re-verified against
   the NEW --cream fill, not against white. */
.dform input::placeholder {
  color: #6f6858;
  opacity: 1;   /* Firefox dims placeholders to 0.54 by default */
}

/* v6.2 §A2: `outline: none` used to leave the field with only a border and a
   soft shadow at 1.17:1 - i.e. the demo form, the page's one conversion path,
   had no conforming focus indicator (WCAG 2.4.7 / 1.4.11 want 3:1). The ring is
   pinned to --gold-fold because .dform is a WHITE card: --gold is 1.65:1 there.
   The box-shadow stays as the inner enhancement. */
.dform input:focus-visible {
  outline: 3px solid var(--gold-fold);
  outline-offset: 3px;
  border-color: var(--gold-deep);
  box-shadow: 0 0 0 3px rgba(240, 180, 41, 0.25);
}

/* v6.2 §C3: the phone field was the only left-aligned object in the Hebrew form.
   The authored `direction: ltr` is dropped, but MEASURED that is not enough on
   its own: HTML's own directionality rule pins `direction: ltr` on an
   `input[type=tel]` regardless of the page, and `text-align: start` resolves
   against the ELEMENT's direction, not the paragraph's - so `start` still lands
   on the left. (Verified in Chromium: a bare tel input under `dir=rtl` computes
   `direction: ltr`; a text input beside it computes `rtl`.) The UA behaviour is
   RIGHT - a phone number is an LTR value - so the fix re-anchors only the BOX,
   below. `plaintext` keeps that true per line even if the value ever starts
   with a strong RTL character. */
.dform input[type='tel'] {
  unicode-bidi: plaintext;
  font-variant-numeric: tabular-nums;
}

/* Logical value, direction-scoped: in Hebrew the field's own `end` is the right
   edge, which is where its three siblings sit. `:dir()` (already used for
   .ic--dir, .progress and .chat__back) rather than a physical `right`. */
:dir(rtl) .dform input[type='tel'] {
  text-align: end;
}

.dform .btn {
  inline-size: 100%;
}

.dform__micro {
  font-size: var(--fs-xs);
  color: var(--muted);
  text-align: center;
}

/* Padding on an INLINE element does not change the line box, but it does
   enlarge the hit area - which is what this needs: 18px tall inside a centred
   sentence, right under the submit button. inline-block would break the
   sentence flow; this does not. */
.dform__micro a {
  padding-block: 4px;
  color: var(--gold-ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.dform__err {
  display: none;
  background: var(--warn-bg);
  border: 1px solid var(--warn-line);
  color: #7e5606;
  border-radius: var(--radius);
  padding: 10px 14px;
  font-size: var(--fs-sm);
  font-weight: 600;
}

.dform.has-error .dform__err {
  display: block;
}

.dform__err a {
  font-weight: 700;
}

/* honeypot — visually gone, present for bots */
.dform .hp {
  position: absolute;
  inset-inline-start: -9999px;
  inline-size: 1px;
  block-size: 1px;
  overflow: hidden;
}

/* success state */
.dform__done {
  display: none;
  text-align: center;
  padding-block: 14px;
}

.dform.is-done form {
  display: none;
}

.dform.is-done .dform__done {
  display: block;
}

.dform__done img {
  inline-size: 52px;
  block-size: 52px;
  margin-inline: auto;
  margin-block-end: 14px;
}

.dform__done h3 {
  font-size: var(--fs-h3);
  font-weight: 800;
}

.dform__done p {
  margin-block-start: 8px;
  color: var(--body);
}

@media (prefers-reduced-motion: no-preference) {
  .dform.is-done .dform__done {
    animation: hero-rise 0.6s var(--ease-out) both;
  }
}

/* ============================================================
   Hive personality: lit cells, the resident bee, the comb edge
   ============================================================ */

/* the bee that built the schedule, perched on the frame */
.pf {
  position: relative;
}

@media (prefers-reduced-motion: no-preference) {
  
}

@keyframes bee-bob {
  0%, 100% { transform: rotate(-8deg) translateY(0); }
  50% { transform: rotate(-6deg) translateY(-4px); }
}

/* the hero ends in a comb edge, not a straight line */

/* ============ TRUST STRIP — the slot competitors fill with logos ============
   Replaced the three-photo "built for businesses like yours" band: stock
   photography of non-Israeli cafes cost 245KB and said less than one line of
   text. This says who it is for AND what is true about the product, in a strip
   instead of a section, so it costs ~120px of scroll instead of ~620px. */
/* v6.1: the strip is the hero's dark apron again - it continues the espresso
   fold under the frame's bleed. The tall block padding at >=981px stays: it
   still has to clear that bleed. */
.tstrip {
  background: var(--espresso);
  border-block-start: 1px solid var(--dark-line);
  color: var(--on-dark);
}

.tstrip__inner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 12px 28px;
  padding-block: 18px;
}

/* v5: the enlarged frame descends 96px into the strip (A3). A thin strip put
   two of the three proof cells UNDER the frame, unreadable. Clearing the bleed
   with block padding turns the strip into the hero's dark apron: the frame
   rests on it, the hairline still passes behind, and the stats sit below the
   frame's bottom edge at full width. */
/* 981px: must match the .pf bleed breakpoint exactly - the padding exists only
   to clear that bleed, so a strip padded where the frame does not descend is
   122px of empty space. */
@media (min-width: 981px) {
  .tstrip__inner {
    padding-block: 122px 26px;
  }
}

.tstrip__for {
  font-weight: 700;
  color: var(--on-dark);
  font-size: var(--fs-sm);
  line-height: 1.5;
}

.tstrip__list {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 22px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.tstrip__list li {
  display: flex;
  align-items: center;
  gap: 7px;
  font-size: var(--fs-sm);
  color: var(--on-dark-muted);
}

/* Not gold: the fact bar is supporting information, and 4 decorative gold
   checkmarks here would spend a third of the 12-element gold budget on
   punctuation - and blunt the famine that makes the mid-page CTA land. */
.tstrip__list .ic {
  color: var(--on-dark-muted);
  flex: none;
}

/* v5 A5: the proof bar - three stat cells replace the four check-items.
   v6 §2.4: with the strip on the bright canvas the v5 note is void - A5's
   original --ink / --muted pair is now the correct one and is restored. */
.proof {
  flex: 1;
  min-inline-size: 0;
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  /* gap 0 ON PURPOSE. The divider is a border on the CELL, so a grid `gap`
     puts the whole gutter on one side of it: the owning cell's text sat 1px
     from the rule while its neighbour sat 29px away, which reads as crooked
     lines and unaligned text. With gap:0 the clearance comes from symmetric
     cell padding, so every rule has the same air on both sides. */
  gap: 0;
}

.proof li {
  display: grid;
  gap: 2px;
  align-content: start;
  min-inline-size: 0;
  /* the air around each divider; halved on each side of the rule */
  padding-inline: clamp(14px, 2.2vw, 26px);
}

/* The outer two cells stay flush with the container so the strip's own edges
   line up with every other section on the page. */
.proof li:first-child { padding-inline-start: 0; }
.proof li:last-child { padding-inline-end: 0; }

/* hairline dividers BETWEEN cells - border-inline-start is direction-safe.
   The grid `gap` carries the spacing; the border sits in the gutter, so no
   extra padding (that would double the space). */
.proof li + li {
  border-inline-start: 1px solid var(--dark-line);
}

.proof__fig {
  display: block;
  font-family: 'Heebo', system-ui, sans-serif;
  font-size: 1.5rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--on-dark);
}

.proof li span {
  font-size: var(--fs-sm);
  line-height: 1.4;
  color: var(--on-dark-muted);
}

@media (max-width: 760px) {
  .tstrip__inner {
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 16px;
  }
}

/* <=640px: cells stack vertically, dividers become border-block-start.
   Same rule as the desktop case - the gutter has to sit on BOTH sides of the
   rule, so it comes from padding, not from `gap`. Inline padding goes to zero
   here: one column means no vertical rules to clear, and the cells should hang
   on the container's own edge. */
@media (max-width: 640px) {
  .proof {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .proof li {
    padding-inline: 0;
    padding-block: 12px;
  }
  .proof li:first-child { padding-block-start: 0; }
  .proof li:last-child { padding-block-end: 0; }
  .proof li + li {
    border-inline-start: 0;
    border-block-start: 1px solid var(--dark-line);
  }
}

/* ============ THE ENGINE (SPEC S4.7) ============
   Promoted out of the old "why" section: this is the differentiator, so it gets
   its own band instead of being the 4th item in the 4th section. */
.guard {
  display: flex;
  gap: 16px;
  align-items: flex-start;
  margin-block-start: 32px;
  padding: 24px;
  border: 1px solid var(--line);
  border-radius: var(--card-radius);
  background: var(--white);
}

.guard > .ic {
  flex: none;
  inline-size: 22px;
  block-size: 22px;
  margin-block-start: 2px;
  color: var(--stone);
}

.guard h3 {
  margin: 0 0 6px;
  font-size: var(--fs-h3);
  line-height: 1.3;
  color: var(--ink);
}

.guard p {
  margin: 0;
  color: var(--body);
}

.engine__cta {
  display: flex;
  flex-wrap: wrap;
  gap: 12px 18px;
  align-items: center;
  margin-block-start: 32px;
}

/* One flex item per sentence - a bare text node here would let the gap open
   mid-phrase (see README "flex container with gap"). */
.engine__micro {
  color: var(--muted);
  font-size: var(--fs-sm);
}

@media (max-width: 720px) {
  .guard { padding: 20px; }
  .engine__cta { flex-direction: column; align-items: stretch; }
  .engine__cta .btn { justify-content: center; }
  .engine__micro { text-align: center; }
}

/* ============================================================
   v4 - SURFACE RHYTHM AND SEAMS (ADDENDUM S7.2 / S7.3 / S7.4)
   ============================================================ */
/* Each light section is a PANEL on the cream canvas, not a full-bleed band.
   Two earlier attempts failed for opposite reasons: alternating cream/white
   flipped the background on every scroll (a hard switch), and a single flat
   canvas left every section head floating on nothing, so a section read as
   loose headers. A panel gives the head a body to sit in, marks the boundary
   without ever changing the background colour, and keeps the whole middle of
   the page one temperature. */
.section--cream,
.section--white {
  background: var(--white);
  /* v5 §2 washout guard: with the canvas near-white, --line lost the dL step
     the panels relied on. Compensate ONCE, at panel level, with --line-strong
     (keep the existing shadow); do NOT darken the canvas to fix it. */
  border: 1px solid var(--line-strong);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-card);
  /* a gutter at EVERY width: with margin-inline:auto alone the panel runs
     edge-to-edge between 720px and 1216px and its rounded corners get clipped
     by the viewport */
  inline-size: calc(100% - 32px);
  max-inline-size: calc(var(--content) + 96px);
  margin-inline: auto;
  margin-block-end: clamp(16px, 2vw, 24px);
  padding-block: clamp(48px, 5.5vw, 72px);
}

/* the first panel clears the espresso band, the last clears the outro */
main > .section--cream:first-of-type { margin-block-start: clamp(24px, 3vw, 40px); }
main > .section--cream:last-of-type { margin-block-end: clamp(24px, 3vw, 40px); }

@media (max-width: 720px) {
  .section--cream,
  .section--white {
    inline-size: calc(100% - 24px);
  }
  /* radii step DOWN inside the panel, never up */
  :root { --r-card: 20px; --pad-shell: 6px; }
}

/* NO hairline between light bands. It was tried and removed: at 1.24:1 on cream
   it is barely visible on its own, but stacked with the pivot mark above it and
   the eyebrow mark below it, a section opening showed three horizontal rules
   inside ~200px and read as clutter rather than structure. The cream->white
   step is dL* 4.11 and marks the boundary by itself; the only rules left on the
   page are the short marks that mean something. */

.container--narrow { max-inline-size: var(--content-narrow); }

/* SURFACE LADDER. Every level alternates tone, so each one is legible against
   its parent: white panel -> cream shell -> white core -> cream inner block.
   The version this replaces put cream inside cream inside cream, which has no
   figure/ground at all and is why the panels read as washed out.
   Radii shrink inward (--r-core = --r-card - --pad-shell); a child with a
   LARGER radius than its parent reads as a mistake. */
.faq,
.guard,
.calc__result,
.pframe--mini {
  background: var(--cream);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-card);
  box-shadow: none;
}

/* the shell/core pair: cream tray, white plate */
.pframe--mini {
  padding: var(--pad-shell);
}

.pframe--mini .papp {
  background: var(--white);
  border-radius: var(--r-core);
  padding: clamp(16px, 2.4vw, 22px);
  /* a 1px top highlight so the plate catches light instead of reading flat */
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.9), 0 1px 2px rgba(35, 26, 18, 0.04);
}

/* blocks INSIDE the white core go back to cream - the ladder alternates */
.vrules__box {
  background: var(--cream);
  border: 1px solid var(--line);
  border-radius: calc(var(--r-core) - 6px);
}

.faq { max-width: none; }

/* ============================================================
   v4 - THE HERO FRAME CROSSES THE SEAM (ADDENDUM S7.1, corrected)
   A cropped window with a hairline disappearing behind it is depth built from
   geometry - no gradient, no glow, no coloured shadow. It also buys ~88px of
   grid width, which is what makes the mock's type legible at 1120px.
   The addendum shipped this as an inline-axis bleed only; with no block-axis
   overlap the z-index stack had nothing to occlude. Both are needed.
   ============================================================ */
/* v6: 981px, NOT 881px. The bleed only makes sense while .hero__grid is still
   TWO columns, and that breaks at 980px. In the old 881-980 band the frame was
   ~936px wide inside an ~828px single column, so .hero's overflow-x:clip sliced
   ~72px off its toolbar. The bug predates v6 - the inversion only made it
   visible, because a dark frame cropped against a dark hero read as nothing.
   These two breakpoints and .hero__grid's are ONE decision: move them together. */
@media (min-width: 981px) {
  .hero__grid { align-items: center; }

  /* the fact bar's hairline runs UNDER the frame */
  .tstrip { position: relative; z-index: 1; }

  .hero { padding-block-end: 24px; }

  .pf {
    position: relative;
    z-index: 2;
    /* v5: bleed grows with the enlarged frame. The tstrip's top hairline still
       runs under it (frame bottom must exceed .tstrip top at >=981px).
       v6.2 §D5: the 72px was UNCONDITIONAL, but the margin that absorbs it only
       exists once .container stops growing at 1120px - so from 981px to ~1262px
       the viewport sliced ~72px off the frame's toolbar, which is the exact crop
       the 981px move was meant to end. The second term caps the bleed at the
       room actually available: 0 at <=1200px, ramping to the full 72px at
       1344px. The 1200px basis (not 1120px) is deliberate headroom - 100vw
       counts the classic scrollbar that the container's own width does not. */
    margin-inline-end: calc(
      -1 * clamp(20px, 4vw, 40px) - min(72px, max(0px, (100vw - 1200px) / 2))
    );
    margin-block-end: -96px;
  }

  /* .pframe already carries --shadow-float PLUS a 1px inset top highlight.
     Do not re-declare box-shadow here: a flat override drops the highlight
     and the frame reads as a soft, blurred dark rectangle. */
}

@media (max-width: 980px) {
  .pf { margin-inline-end: 0; margin-block-end: 0; }
}

/* ---------- The bee on the frame corner ----------
   Sits on the hero frame's top corner and bobs gently. It is the brand mark
   doing the one thing a static logo cannot: making the mock feel alive. */
/* v6.1: the overhang is back - it only washed out on the bright canvas, and the
   hero is espresso again, so the light-bodied emblem reads for its whole
   silhouette. If the fold ever goes bright again, tuck this to +6px. */
.pf__bee {
  position: absolute;
  inset-block-start: -21px;
  inset-inline-end: 30px;
  inline-size: 46px;
  block-size: 46px;
  z-index: 3;
  transform: rotate(-8deg);
  filter: drop-shadow(0 5px 12px rgba(0, 0, 0, 0.4));
}

@media (prefers-reduced-motion: no-preference) {
  .pf__bee { animation: bee-bob 3.6s ease-in-out infinite; }
}

@keyframes bee-bob {
  0%, 100% { transform: rotate(-8deg) translateY(0); }
  50% { transform: rotate(-6deg) translateY(-4px); }
}

/* The engine section carries ONE artifact, centred, with nothing competing.
   It used to run head -> deck -> orphan lead -> h3 -> paragraph -> card, i.e.
   four prose blocks restating each other before the reader reached the proof.
   Everything the cut copy claimed (availability, roles, rest) is already shown
   as rule lines inside step 3's approve panel. */
/* v5 A7: the engine is the page's ONE dark mid-panel (a deliberate Deputy-style
   feature block). The content stacks: head, then a two-column feature (copy +
   rule box side by side), then the CTA. The old half-empty feature--flip (a
   vignette alone in a 2-col grid) and the standalone .guard card are gone -
   their content now lives in the .guardlist inside .feature__copy. */
.engine .container { display: block; }

.engine .feature { align-items: start; }

.engine .feature .pframe--mini {
  max-inline-size: none;
  margin-inline: 0;
}

/* ---------- section--dark: the engine's espresso centerpiece (v5 A7) ----------
   Gold is native on espresso here, the way it is on the hero/outro bookends -
   so the guardlist's gold marks read as brand, not as a break in the light-page
   gold famine (N6, which governs the light middle bands). */
.section--dark {
  background: linear-gradient(180deg, var(--espresso-2), var(--espresso));
  border-color: transparent;
}

/* Recolour only the engine's OWN copy - never descendants of .pframe--mini,
   which keeps its light shell and its dark-on-light interior text. */
.section--dark .sec-head h2,
.section--dark .feature__copy h3 {
  color: var(--on-dark);
}

.section--dark .sec-head__deck,
.section--dark .feature__copy > p {
  color: var(--on-dark-muted);
}

.section--dark .ctablock {
  border-block-start-color: var(--dark-line);
}

.section--dark .ctablock__micro {
  color: var(--on-dark-muted);
}

/* the guardrail list: what the engine catches, moved out of the old .guard card */
.guardlist {
  list-style: none;
  margin: 20px 0 0;
  padding: 0;
  display: grid;
  gap: 14px;   /* rows separated by 14px, no hairlines (9.F per-row-rule ban) */
}

.guardlist li {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  font-size: var(--fs-body);
  line-height: 1.5;
  color: var(--on-dark);
}

.guardlist li .ic {
  flex: none;
  inline-size: 18px;
  block-size: 18px;
  margin-block-start: 3px;
  color: var(--gold);
}

.guardlist__cap {
  margin-block-start: 14px;
  font-size: var(--fs-sm);
  color: var(--on-dark-muted);
}

/* ============ COST CALCULATOR ============
   Restored deliberately: it is the one place the reader supplies their own
   number and watches it turn into a figure they did not want to see. Leaner
   than the original - one headline figure instead of three stacked result
   rows, because the hook is the number, not the arithmetic. */
.calc__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 0.85fr);
  gap: clamp(28px, 4.5vw, 56px);
  align-items: center;
  max-inline-size: 940px;
}

.calc__controls { display: grid; gap: 26px; }

.calc__label {
  display: block;
  margin-block-end: 10px;
  font-weight: 700;
  color: var(--ink);
  font-size: var(--fs-sm);
}

.calc__hours-row { display: flex; align-items: center; gap: 16px; }

input[type='range'].calc__range {
  flex: 1;
  accent-color: var(--gold-deep);
  block-size: 28px;
  /* Paints no glyph, but the UA leaves line-height unset on form controls and
     the typography spec wants every style to state one. */
  line-height: 1;
}

.calc__hours-out {
  min-inline-size: 4.4ch;
  padding: 4px 10px;
  border-radius: var(--r-sm, 10px);
  background: var(--gold-soft);
  color: var(--gold-ink);
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-lead);
  text-align: center;
}

.calc__wages { display: flex; flex-wrap: wrap; gap: 8px; }

.calc__wage {
  padding: 8px 16px;
  min-block-size: 40px;
  border: 1.5px solid var(--line-strong);
  border-radius: var(--r-pill, 999px);
  background: var(--cream);
  color: var(--stone);
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-sm);
  /* v6.2 §C6 (N3): a <button> takes `line-height: normal` from the UA `font`
     shorthand instead of inheriting the body value. */
  line-height: 1.4;
  cursor: pointer;
  transition: background-color 0.2s ease, border-color 0.2s ease, color 0.2s ease;
}

.calc__wage[aria-pressed='true'] {
  background: var(--espresso-2);
  border-color: var(--espresso-2);
  color: var(--on-dark);
}

.calc__result {
  display: grid;
  justify-items: start;
  gap: 4px;
  padding: var(--pad-card);
  border: 1px solid var(--line-strong);
  border-radius: var(--r-card);
  background: var(--cream);
}

.calc__big {
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: clamp(2rem, 3.6vw, 2.8rem);
  line-height: 1.1;
  color: var(--ink);
}

.calc__sub { color: var(--body); }

.calc__days {
  margin-block-start: 6px;
  color: var(--muted);
  font-size: var(--fs-sm);
}


.calc__big.bump { animation: calc-bump 0.34s var(--ease-out); }

@keyframes calc-bump {
  0% { transform: none; }
  40% { transform: translateY(-3px) scale(1.03); }
  100% { transform: none; }
}

@media (prefers-reduced-motion: reduce) {
  .calc__big.bump { animation: none; }
}

@media (max-width: 820px) {
  .calc__grid { grid-template-columns: minmax(0, 1fr); }
}

/* ============ The WhatsApp screen ============
   A real client screen, not a card with bubbles in it: green header with the
   group identity, the beige chat canvas, and a composer at the foot. The whole
   argument of the Problem section is "this is where your schedule lives today",
   so the mock has to be recognisable at a glance. */
.chat {
  max-inline-size: 430px;
  margin-inline: auto;
  border-radius: var(--r-card);
  overflow: hidden;
  border: 1px solid var(--line);
  box-shadow: var(--shadow-card);
  background: #efeae2;
}

.chat__bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 12px 14px;
  background: #075e54;          /* WhatsApp header green */
  color: #ffffff;
}

.chat__back {
  inline-size: 18px;
  block-size: 18px;
  opacity: 0.9;
  transform: rotate(90deg);     /* chevron-down -> a back arrow */
}

:dir(rtl) .chat__back {
  transform: rotate(-90deg);
}

.chat__ava {
  display: grid;
  place-items: center;
  inline-size: 34px;
  block-size: 34px;
  flex: none;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.22);
}

.chat__ava .ic {
  inline-size: 19px;
  block-size: 19px;
  color: #ffffff;
}

.chat__id {
  display: grid;
  min-inline-size: 0;
  line-height: 1.25;
}

.chat__name {
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-app-sm);
  color: #ffffff;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

.chat__members {
  font-size: var(--fs-app-xxs);
  color: rgba(255, 255, 255, 0.72);
}

.chat__unread {
  margin-inline-start: auto;
  flex: none;
  padding: 3px 9px;
  border-radius: var(--r-pill, 999px);
  background: #25d366;
  color: #05372f;
  font-family: 'Heebo', system-ui, sans-serif;
  font-weight: 700;
  font-size: var(--fs-app-xxs);
}

.chat__body {
  padding: 16px 14px 10px;
  /* the faint doodle wash the real client puts behind messages */
  background-image:
    radial-gradient(circle at 20% 30%, rgba(180, 168, 148, 0.10) 0 2px, transparent 3px),
    radial-gradient(circle at 70% 65%, rgba(180, 168, 148, 0.10) 0 2px, transparent 3px);
  background-size: 90px 90px, 130px 130px;
}

.chat__input {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 9px 12px;
  background: #f0f2f5;
  border-block-start: 1px solid rgba(11, 20, 26, 0.08);
}

.chat__field {
  flex: 1;
  padding: 8px 14px;
  border-radius: var(--r-pill, 999px);
  background: #ffffff;
  /* 0.62, not WhatsApp's own 0.45: at 0.45 this composites to 2.9:1, and while
     the whole mock is role="img" (so this is arguably an incidental-text
     exemption), a 2.9:1 string is not worth defending on a technicality. 0.62
     composites to 4.90:1 and still reads as a washed-out placeholder. */
  color: rgba(17, 27, 33, 0.62);
  font-size: var(--fs-app-sm);
}

.chat__send {
  display: grid;
  place-items: center;
  inline-size: 32px;
  block-size: 32px;
  flex: none;
  border-radius: 50%;
  background: #00a884;
}

.chat__send .ic {
  inline-size: 16px;
  block-size: 16px;
  color: #ffffff;
}
