@charset "UTF-8";
/* =============================================================================
   מושכות — components.css
   The shared kit: layout, type classes, buttons, surfaces, header, footer,
   device frames, store badges, the accessibility widget, motion primitives.
   Owned by: Foundation. Requires base.css.

   MARKUP CONTRACTS are documented above each block so the landing and inner
   pages can consume the kit without guessing. RTL logical properties only.
   ============================================================================= */

/* =============================================================================
   1. LAYOUT
   ============================================================================= */

/* <div class="container"> … </div> */
.container {
  inline-size: 100%;
  max-inline-size: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}
.container--narrow { max-inline-size: var(--container-narrow); }
.container--wide   { max-inline-size: var(--container-wide); }
.container--flush  { padding-inline: 0; }

/* <section class="section"> … </section>
   A section is a full-width band, so it is also the natural clipping edge.
   [data-reveal="start"] / ="end" displace their element 2rem sideways before it
   resolves; on a full-width child that is 32px past the viewport, and while
   body's `overflow-x: clip` stops it ever becoming a scrollbar, the document
   still reports the overflow. Clipping at the band removes it at the source and
   turns the sideways reveal into a proper masked entrance.
   `clip`, not `hidden`: clip does not create a scroll container, so it neither
   allows programmatic sideways scrolling nor breaks `position: sticky` inside.
   A section that deliberately bleeds opts out with .section--bleed. */
.section {
  position: relative;
  padding-block: var(--section-y);
  overflow-x: clip;
}
.section--bleed { overflow-x: visible; }
.section--lg    { padding-block: var(--section-y-lg); }
.section--tight { padding-block: clamp(2.5rem, 5vw, 4.5rem); }
.section--flush-top    { padding-block-start: 0; }
.section--flush-bottom { padding-block-end: 0; }

.section--warm { background-color: var(--bg-warm); }
.section--deep { background-color: var(--bg-deep); }

/* Section head: eyebrow + headline + lede, start-aligned by default. */
.section__head {
  max-inline-size: var(--measure-wide);
  margin-block-end: clamp(2rem, 4vw, 3.5rem);
}
.section__head--center {
  margin-inline: auto;
  text-align: center;
}
.section__head > * + * { margin-block-start: var(--space-4); }

/* Simple auto-fit grid used all over the site. */
.grid {
  display: grid;
  gap: var(--space-5);
}
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 20rem), 1fr)); }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 17rem), 1fr)); }
.grid--4 { grid-template-columns: repeat(auto-fit, minmax(min(100%, 13.5rem), 1fr)); }

.cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.cluster--lg { gap: var(--space-5); }

.divider {
  block-size: 1px;
  background: linear-gradient(to left, transparent, var(--border) 18%, var(--border) 82%, transparent);
  border: 0;
}

/* Skip link — first focusable element on the page.
   <a class="skip-link" href="#main">דילוג לתוכן</a>  (injected by a11y.js) */
.skip-link {
  position: fixed;
  inset-block-start: var(--space-3);
  inset-inline-start: var(--space-3);
  z-index: var(--z-top);
  padding: var(--space-3) var(--space-5);
  background-color: var(--brand);
  color: var(--on-brand);
  font-size: var(--fs-sm);
  font-weight: 500;
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-lg);
  translate: 0 -200%;
  transition: translate var(--dur-2) var(--ease-brand);
}
.skip-link:focus-visible { translate: 0 0; }

/* =============================================================================
   2. TYPOGRAPHY CLASSES
   Fabs has exactly three weights: 300 (light), 500 (medium), 800 (extra bold).
   ============================================================================= */

/* Kicker above a headline. A short rust rule replaces the usual bullet. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--fs-2xs);
  font-weight: 500;
  line-height: 1;
  letter-spacing: var(--ls-label);
  color: var(--brand-ink);
}
.eyebrow::before {
  content: "";
  inline-size: 1.75rem;
  block-size: 2px;
  border-radius: var(--r-pill);
  background-color: currentColor;
  opacity: 0.75;
}
.eyebrow--plain::before { content: none; }
.eyebrow--muted { color: var(--text-2); }

/* THE APPLIED LADDER. .h1 … .h6 walk consecutive rungs of the scale in
   base.css §2.3, so every neighbouring pair is the same 1.26 apart at 1440 and
   the same 1.15 apart at 360 — no rung is skipped and no step is wider than
   another. Sizes at 360 / 1440 / 2560:

     .display  49 / 108 / 123     hero device, outside the heading ladder
     .h1       37 /  68 /  77     page title
     .h2       32 /  54 /  62     section headline
     .h3       28 /  43 /  49     sub-section
     .h4       24 /  34 /  39     card title, large
     .h5       21 /  27 /  31     card title, default
     .h6       18 /  22 /  25     small heading / label heading

   .display is the ONE deliberate wide step (1.59 over .h1): it is a hero
   treatment, not a heading rank. Everything else is uniform. */
.display,
.h1, .h2, .h3, .h4, .h5, .h6 {
  font-weight: 800;
  letter-spacing: var(--ls-display);
  text-wrap: balance;
}

.display { font-size: var(--fs-7xl); line-height: var(--lh-display); }
.h1      { font-size: var(--fs-5xl); line-height: var(--lh-display); }
.h2      { font-size: var(--fs-4xl); line-height: 1.16; }
.h3      { font-size: var(--fs-3xl); line-height: var(--lh-tight); }
.h4      { font-size: var(--fs-2xl); line-height: var(--lh-tight); }
.h5      { font-size: var(--fs-xl);  line-height: 1.3; }
.h6      { font-size: var(--fs-lg);  line-height: 1.3; }

.h-light { font-weight: 300; letter-spacing: 0; }

/* A rust-tinted run inside a headline. */
.hl { color: var(--brand-ink); }
.hl-ochre { color: var(--accent); }

.lede {
  max-inline-size: var(--measure);
  font-size: var(--fs-lg);
  font-weight: 300;
  line-height: var(--lh-snug);
  color: var(--text-2);
}

.body {
  max-inline-size: var(--measure);
  font-size: var(--fs-md);
  font-weight: 300;
  line-height: var(--lh-body);
  color: var(--text-2);
}
.body-sm {
  max-inline-size: var(--measure);
  font-size: var(--fs-sm);
  font-weight: 300;
  line-height: var(--lh-body);
  color: var(--text-2);
}
.body strong, .body-sm strong, .lede strong { font-weight: 500; color: var(--text); }

.label {
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1.4;
  color: var(--text-3);
}
/* LEGIBILITY FLOOR: Hebrew has no ascenders or descenders to carry a light
   weight at a small size, so nothing on this site sets weight 300 below
   --fs-xs (14px). --fs-2xs (12px) is reserved for weight 500 runs — eyebrows,
   tags, field labels — where the stroke is heavy enough to hold. .caption,
   .store-badges__note, .site-footer__legal and .a11y-panel__foot all used to
   sit at 12px/300 and read as grey texture rather than as words. */
.caption {
  font-size: var(--fs-xs);
  font-weight: 300;
  line-height: 1.6;
  color: var(--text-3);
}

.text-muted { color: var(--text-3); }
.text-soft  { color: var(--text-2); }

/* Prose block for legal / long-form inner pages.
   The ELEMENTS a legal page is actually made of — table, details/summary,
   blockquote, dl, figure — are styled at element level in §16 and need no
   classes here; this block only sets the rhythm and the heading sizes, which
   walk the same consecutive rungs as .h4/.h5/.h6.
   .prose--legal opens the leading to --lh-loose for clause-dense text. */
.prose { max-inline-size: var(--measure-wide); }
.prose > * + *      { margin-block-start: var(--space-4); }
.prose h2           { font-size: var(--fs-2xl); margin-block-start: var(--space-9); }
.prose h3           { font-size: var(--fs-xl);  margin-block-start: var(--space-7); }
.prose h4           { font-size: var(--fs-lg);  margin-block-start: var(--space-6); }
.prose h2 + *, .prose h3 + *, .prose h4 + * { margin-block-start: var(--space-3); }
.prose p, .prose li { font-weight: 300; line-height: var(--lh-body); color: var(--text-2); }
.prose--legal p,
.prose--legal li,
.prose--legal dd    { line-height: var(--lh-loose); }
.prose ul, .prose ol { padding-inline-start: var(--space-5); }
.prose ul li        { list-style: none; position: relative; }
.prose ul li::before {
  content: "";
  position: absolute;
  inset-inline-start: calc(var(--space-5) * -1);
  inset-block-start: 0.75em;
  inline-size: 0.375rem;
  block-size: 0.375rem;
  border-radius: var(--r-full);
  background-color: var(--brand);
}
.prose ol           { list-style: decimal; }
.prose ol li        { padding-inline-start: var(--space-2); }
.prose a            { color: var(--brand-ink); text-decoration: underline; }
.prose a:hover      { color: var(--brand-ink-strong); }

/* =============================================================================
   3. ICONS
   Every icon on this site is an inline SVG on a 24×24 grid with one stroke
   weight. <svg class="icon" viewBox="0 0 24 24" aria-hidden="true">…</svg>
   ============================================================================= */
.icon {
  inline-size: 1.5rem;
  block-size: 1.5rem;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}
.icon--sm { inline-size: 1.125rem; block-size: 1.125rem; stroke-width: 1.7; }
.icon--lg { inline-size: 2rem;     block-size: 2rem;     stroke-width: 1.4; }
.icon--xl { inline-size: 2.75rem;  block-size: 2.75rem;  stroke-width: 1.25; }
.icon--filled { fill: currentColor; stroke: none; }

/* Round icon plate used in feature lists. */
.icon-plate {
  display: inline-grid;
  place-items: center;
  inline-size: 3.5rem;
  block-size: 3.5rem;
  flex: none;
  border-radius: var(--r-lg);
  background-color: var(--rust-a08);
  color: var(--brand-ink);
  box-shadow: var(--ring-hairline);
}
/* Accent plates are solid so the icon keeps a ≥ 4.5:1 contrast without
   inventing a darker tint outside the palette. */
.icon-plate--ochre { background-color: var(--ochre); color: var(--cocoa); box-shadow: none; }
.icon-plate--olive { background-color: var(--olive); color: var(--cream-warm); box-shadow: none; }
.icon-plate--teal  { background-color: var(--teal);  color: var(--cocoa); box-shadow: none; }
.icon-plate--solid { background-color: var(--brand); color: var(--on-brand); box-shadow: var(--shadow-rust); }

/* =============================================================================
   4. BUTTONS
   <a class="btn btn--primary" data-magnetic href="…">
     טקסט <svg class="icon icon--sm">…</svg>
   </a>
   `data-magnetic` is optional; main.js writes --mag-x/--mag-y, and the button
   composes them through the independent `translate` property so hover `scale`
   never fights the magnet.
   ============================================================================= */
.btn {
  --btn-bg: transparent;
  --btn-fg: var(--text);
  --btn-bd: transparent;
  --btn-shadow: none;

  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-block-size: 3rem;              /* 48px — comfortably over the 44px target */
  padding-block: 0.75rem;
  padding-inline: 1.75rem;
  font-family: inherit;
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: 1.2;
  text-align: center;
  border: 1px solid var(--btn-bd);
  border-radius: var(--r-pill);
  background-color: var(--btn-bg);
  color: var(--btn-fg);
  box-shadow: var(--btn-shadow);
  cursor: pointer;
  user-select: none;
  translate: var(--mag-x, 0px) var(--mag-y, 0px);
  transition:
    translate var(--dur-5) var(--ease-brand),
    scale var(--dur-3) var(--ease-brand),
    background-color var(--dur-2) ease,
    border-color var(--dur-2) ease,
    color var(--dur-2) ease,
    box-shadow var(--dur-3) var(--ease-brand);
}
/* While the pointer is inside, the magnet tracks quickly; on release it eases
   back over the long duration above. */
.btn[data-mag-active] { transition-duration: 160ms, var(--dur-3), var(--dur-2), var(--dur-2), var(--dur-2), var(--dur-3); }

.btn:hover  { scale: 1.025; }
.btn:active { scale: 0.985; }
.btn:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }

.btn .icon { transition: translate var(--dur-3) var(--ease-brand); }
.btn:hover .icon { translate: -0.2rem 0; }   /* RTL: forward is leftwards */

/* 4.1 Primary — rust. The single action colour. */
.btn--primary {
  --btn-bg: var(--brand);
  --btn-fg: var(--on-brand);
  --btn-bd: var(--brand);
  --btn-shadow: var(--shadow-rust);
}
.btn--primary:hover  { --btn-bg: var(--brand-strong); --btn-bd: var(--brand-strong); }
.btn--primary:active { --btn-bg: var(--brand-deepest); --btn-bd: var(--brand-deepest); }
.btn--primary:focus-visible { outline-color: var(--cocoa); }

/* 4.2 Secondary — warm surface, charcoal text, a border you can actually see.
   The fill (--soft #f6efe5) is only 1.04:1 against the page, so the border is
   the whole control boundary: --line would be 1.20:1 and the button would read
   as floating text. --border-strong is 3.22:1 and clears WCAG 1.4.11. */
.btn--secondary {
  --btn-bg: var(--soft);
  --btn-fg: var(--text);
  --btn-bd: var(--border-strong);
  --btn-shadow: var(--shadow-xs);
}
.btn--secondary:hover  { --btn-bg: var(--white); --btn-bd: var(--brand); --btn-fg: var(--brand-ink); --btn-shadow: var(--shadow-sm); }
.btn--secondary:active { --btn-bg: var(--surface-muted); }

/* 4.3 Ghost — text only. */
.btn--ghost {
  --btn-fg: var(--text);
  padding-inline: var(--space-4);
}
.btn--ghost:hover  { --btn-bg: var(--rust-a08); --btn-fg: var(--brand-ink); }
.btn--ghost:active { --btn-bg: var(--rust-a14); }

/* 4.4 On-photo — frosted, for the hero. Mirrors the login backdrop. */
.btn--frost {
  --btn-bg: rgba(255, 255, 255, 0.72);
  --btn-fg: var(--text);
  --btn-bd: rgba(255, 255, 255, 0.9);
  --btn-shadow: var(--shadow-md);
  -webkit-backdrop-filter: var(--blur-glass);
  backdrop-filter: var(--blur-glass);
}
.btn--frost:hover { --btn-bg: rgba(255, 255, 255, 0.9); --btn-fg: var(--brand-ink); }

/* 4.5 Sizes */
.btn--sm { min-block-size: 2.75rem; padding-block: 0.5rem; padding-inline: 1.25rem; font-size: var(--fs-xs); }
.btn--lg { min-block-size: 3.5rem;  padding-block: 1rem;   padding-inline: 2.25rem; font-size: var(--fs-md); }
.btn--block { display: flex; inline-size: 100%; }

.btn--icon {
  inline-size: 3rem;
  padding-inline: 0;
  border-radius: var(--r-full);
}

.btn[aria-disabled="true"],
.btn:disabled {
  opacity: 0.5;
  pointer-events: none;
  --btn-shadow: none;
}

/* Inline text link with a rust rule that grows from the inline-start (right). */
.link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  position: relative;
  font-weight: 500;
  color: var(--brand-ink);
}
.link::after {
  content: "";
  position: absolute;
  inset-block-end: -0.15em;
  inset-inline: 0;
  block-size: 1px;
  background-color: currentColor;
  transform-origin: 100% 50%;       /* RTL: the inline-start edge */
  scale: 0 1;
  transition: scale var(--dur-3) var(--ease-brand);
}
.link:hover::after { scale: 1 1; }
.link .icon { transition: translate var(--dur-3) var(--ease-brand); }
.link:hover .icon { translate: -0.2rem 0; }

/* =============================================================================
   5. SURFACES
   ============================================================================= */

/* 5.1 Plain card — white, hairline, soft lift.
   White on cream is 1.10:1, so the edge is carried by the shadow plus the ring
   together. Both were strengthened (--ring-hairline 5% → 10% cocoa, --shadow-sm
   14% → 18%) until the card reads as an object at a glance. It deliberately
   stops short of a 3:1 hard border: a card is a container, not a UI component,
   so WCAG 1.4.11 does not bind it, and a hard border would break the login
   screen's soft-card language that BRIEF §2 makes non-negotiable. High contrast
   is where that edge becomes a 2px charcoal ring — see §13. */
.card {
  position: relative;
  padding: clamp(1.5rem, 2.5vw, 2rem);
  background-color: var(--surface);
  border-radius: var(--r-2xl);
  box-shadow: var(--shadow-sm), var(--ring-hairline);
  transition: box-shadow var(--dur-3) var(--ease-brand), translate var(--dur-3) var(--ease-brand);
}
.card--interactive:hover { box-shadow: var(--shadow-lg), var(--ring-hairline); translate: 0 -4px; }

/* 5.2 Frosted glass — the product's `.jc-card`, value for value. Put it over
   `.pwa-surface` or over photography, never over a flat cream field. */
.card-glass {
  position: relative;
  padding: clamp(1.25rem, 2.2vw, 1.75rem);
  background-color: var(--glass-fill);
  border: 1px solid var(--glass-edge);
  border-radius: var(--r-xl);
  box-shadow: 0 12px 32px -14px rgba(70, 45, 33, 0.32);
  -webkit-backdrop-filter: var(--blur-glass);
  backdrop-filter: var(--blur-glass);
}
.card-glass--strong {
  background-color: var(--glass-fill-strong);
  -webkit-backdrop-filter: blur(20px) saturate(112%);
  backdrop-filter: blur(20px) saturate(112%);
}
.card-glass--flat { box-shadow: none; }

/* 5.3 Hero card — the login screen's one big white card. 32px, deep shadow,
   hairline ring, generous inset so the photo breathes on every side. */
.card-hero {
  position: relative;
  overflow: hidden;
  background-color: var(--surface);
  border-radius: var(--r-3xl);
  box-shadow: var(--shadow-xl), var(--ring-hairline);
}

/* 5.4 Frost layer — `bg-white/30 backdrop-blur-[36px]` from the login page.
   Sits between a photograph and its content. */
.frost {
  position: absolute;
  inset: 0;
  background-color: rgba(255, 255, 255, 0.3);
  -webkit-backdrop-filter: var(--blur-heavy);
  backdrop-filter: var(--blur-heavy);
  pointer-events: none;
}
.frost--light { background-color: rgba(255, 255, 255, 0.18); -webkit-backdrop-filter: blur(18px); backdrop-filter: blur(18px); }
.frost--heavy { background-color: rgba(255, 255, 255, 0.46); }

/* 5.5 PWA surface — the app's own background, value for value from `.jc-app-bg`:
   a warm tan→cream gradient with a faint film grain. The grain is baked into
   the background-image stack (not a pseudo-element) so ::before / ::after stay
   free for the device chrome that sits on top of this class. */
.pwa-surface {
  position: relative;
  background-color: var(--tan);
  background-image:
    url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.06'/%3E%3C/svg%3E"),
    radial-gradient(130% 78% at 50% -10%, rgba(131, 67, 49, 0.2), transparent 56%),
    linear-gradient(165deg, #efe1d0 0%, #e7d4bf 52%, #dfcab0 100%);
  background-blend-mode: multiply, normal, normal;
  background-repeat: repeat, no-repeat, no-repeat;
  background-size: 140px 140px, cover, cover;
  background-position: center, center, center;
}

/* =============================================================================
   6. PILLS, TAGS, STATS
   ============================================================================= */
.tag {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding-block: 0.375rem;
  padding-inline: 0.75rem;
  font-size: var(--fs-2xs);
  font-weight: 500;
  line-height: 1.4;
  border-radius: var(--r-pill);
  background-color: var(--surface-muted);
  color: var(--text-2);
  box-shadow: var(--ring-hairline);
}
.tag--rust  { background-color: var(--rust-a08);            color: var(--brand-ink); }
.tag--ochre { background-color: rgba(202, 144, 37, 0.18);   color: var(--cocoa); }
.tag--olive { background-color: rgba(80, 93, 47, 0.14);     color: var(--olive); }
.tag--teal  { background-color: rgba(137, 172, 173, 0.26);  color: var(--cocoa); }
.tag--solid { background-color: var(--brand); color: var(--on-brand); box-shadow: none; }

/* "בקרוב" marker for anything on the roadmap. */
.tag--soon { background-color: rgba(202, 144, 37, 0.18); color: var(--cocoa); }
.tag--soon::before {
  content: "";
  inline-size: 0.4rem;
  block-size: 0.4rem;
  border-radius: var(--r-full);
  background-color: var(--ochre);
}

.stat { display: flex; flex-direction: column; gap: var(--space-1); }
.stat__value {
  font-size: var(--fs-3xl);
  font-weight: 800;
  line-height: 1.05;
  color: var(--brand-ink);
  font-family: var(--font-num);
  font-variant-numeric: tabular-nums;
}
.stat__label { font-size: var(--fs-xs); font-weight: 500; color: var(--text-3); }

/* =============================================================================
   7. SITE HEADER
   Contract:
   <header class="site-header" data-site-header>
     <div class="site-header__inner container">
       <a class="site-header__brand" href="index.html">
         <img class="site-header__logo" src="assets/img/moshchot-logo.svg"
              alt="מושכות" width="1050" height="352">
       </a>
       <nav class="site-nav" id="site-nav" aria-label="ניווט ראשי">
         <ul class="site-nav__list">
           <li><a class="site-nav__link" href="#features">המערכת</a></li>
         </ul>
         <div class="site-nav__actions"> … drawer CTA, .btn--block … </div>
       </nav>
       <!-- Below 900px only the .btn--primary here survives; anything else in
            this box is desktop-only and belongs in .site-nav__actions too. -->
       <div class="site-header__actions"> <a class="btn btn--primary btn--sm">…</a> </div>
       <button class="nav-toggle" type="button" data-nav-toggle
               aria-expanded="false" aria-controls="site-nav">
         <span class="nav-toggle__bars" aria-hidden="true"><i></i><i></i></span>
         <span class="visually-hidden">תפריט</span>
       </button>
     </div>
   </header>
   main.js adds `.is-scrolled` past 24px and toggles `.is-open` + html.nav-open.
   Below 900px the open drawer is a real modal: main.js puts role="dialog" +
   aria-modal on #site-nav, marks every body-level node except the header
   `inert`, and traps Tab inside the header. Escape closes and returns focus to
   the toggle. Nothing in the markup contract changes for that; it is all
   applied and removed at runtime.
   ============================================================================= */
.site-header {
  position: sticky;
  inset-block-start: 0;
  z-index: var(--z-header);
  background-color: transparent;
  border-block-end: 1px solid transparent;
  transition:
    border-color var(--dur-3) var(--ease-brand),
    box-shadow var(--dur-3) var(--ease-brand);
}
/* Frosted background lives on a pseudo-element, NOT on .site-header itself.
   A backdrop-filter on the header makes it the containing block for its
   `position: fixed` descendants (the mobile drawer + its scrim), so after
   scrolling — when `.is-scrolled` applied the filter — the menu anchored to
   the header instead of the viewport and appeared not to open. The ::before
   has no descendants, so its own containing block affects nothing. */
.site-header::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background-color: rgba(248, 244, 237, 0.82);
  -webkit-backdrop-filter: blur(18px) saturate(120%);
  backdrop-filter: blur(18px) saturate(120%);
  opacity: 0;
  transition: opacity var(--dur-3) var(--ease-brand);
  pointer-events: none;
}
.site-header.is-scrolled::before { opacity: 1; }
.site-header.is-scrolled {
  border-block-end-color: var(--border);
  box-shadow: 0 10px 30px -24px rgba(40, 25, 15, 0.5);
}

/* The header shares ONE column edge with every .section on the page. It used to
   ride .container--wide (1440) while sections ride .container (1240), which put
   the logo 100px outboard of the content it sits above at every desktop width.
   The max-inline-size below wins over .container--wide by source order, so the
   alignment holds even if a page still carries the old class. */
.site-header__inner {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  min-block-size: var(--header-h);
  max-inline-size: var(--container);
}

.site-header__brand {
  display: inline-flex;
  align-items: center;
  flex: none;
  border-radius: var(--r-sm);
}
.site-header__logo {
  inline-size: auto;
  block-size: 1.75rem;
  transition: scale var(--dur-3) var(--ease-brand);
}
.site-header__brand:hover .site-header__logo { scale: 1.03; }
@media (min-width: 900px) {
  .site-header__logo { block-size: 2.125rem; }
}

.site-nav { margin-inline-end: auto; }
.site-nav__list {
  display: flex;
  align-items: center;
  gap: clamp(0.25rem, 1.2vw, 1rem);
}
.site-nav__link {
  position: relative;
  display: inline-flex;
  align-items: center;
  min-block-size: 2.75rem;
  padding-inline: var(--space-3);
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--text);
  border-radius: var(--r-sm);
  transition: color var(--dur-2) ease;
}
.site-nav__link::after {
  content: "";
  position: absolute;
  inset-block-end: 0.55rem;
  inset-inline: var(--space-3);
  block-size: 2px;
  border-radius: var(--r-pill);
  background-color: var(--brand);
  transform-origin: 100% 50%;        /* RTL: grows from the right */
  scale: 0 1;
  transition: scale var(--dur-3) var(--ease-brand);
}
.site-nav__link:hover,
.site-nav__link[aria-current="page"] { color: var(--brand-ink); }
.site-nav__link:hover::after,
.site-nav__link[aria-current="page"]::after { scale: 1 1; }

.site-header__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex: none;
}
.site-nav__actions { display: none; }

/* Hamburger */
.nav-toggle {
  display: none;
  place-items: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  flex: none;
  border-radius: var(--r-md);
  color: var(--text);
  transition: background-color var(--dur-2) ease;
}
.nav-toggle:hover { background-color: var(--rust-a08); }
.nav-toggle__bars { display: block; inline-size: 1.25rem; block-size: 0.75rem; position: relative; }
.nav-toggle__bars i {
  position: absolute;
  inset-inline: 0;
  block-size: 2px;
  border-radius: var(--r-pill);
  background-color: currentColor;
  transition: translate var(--dur-3) var(--ease-brand), rotate var(--dur-3) var(--ease-brand);
}
.nav-toggle__bars i:first-child { inset-block-start: 0; }
.nav-toggle__bars i:last-child  { inset-block-end: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:first-child { translate: 0 0.3125rem; rotate: 45deg; }
.nav-toggle[aria-expanded="true"] .nav-toggle__bars i:last-child  { translate: 0 -0.3125rem; rotate: -45deg; }

/* --- Mobile / tablet: the nav becomes a sheet that drops from the header ---
   The primary CTA STAYS in the bar. Most farm owners will land here on a
   phone, and a CTA that only exists inside a closed drawer is one tap out of
   sight. Only the primary button survives the squeeze; any secondary action in
   .site-header__actions drops out and lives on in the drawer's
   .site-nav__actions. The brand takes the auto margin (rather than the toggle)
   so the CTA and the hamburger stay grouped at the inline-end edge whether or
   not a page ships a header CTA at all. */
@media (max-width: 899px) {
  /* Logo on the LEFT, hamburger on the RIGHT (standard mobile layout). In RTL,
     space-between puts the first-ordered item at the inline-start (right) and
     the last at the inline-end (left): toggle → right, brand → left. */
  .site-header__inner { gap: var(--space-3); justify-content: space-between; }
  .nav-toggle { display: grid; order: 0; }
  .site-header__actions { gap: var(--space-2); order: 1; }
  .site-header__brand { order: 2; margin-inline: 0; }
  .site-header__actions > :not(.btn--primary) { display: none; }
  .site-header__actions .btn {
    min-block-size: 2.75rem;       /* 44px — still a full touch target */
    padding-block: 0.5rem;
    padding-inline: 1.125rem;
    font-size: var(--fs-xs);
  }
  .site-nav {
    position: fixed;
    inset-block-start: var(--header-h);
    inset-inline: 0;
    margin-inline-end: 0;
    padding: var(--space-5) var(--gutter) var(--space-8);
    max-block-size: calc(100dvh - var(--header-h));
    overflow-y: auto;
    overscroll-behavior: contain;
    background-color: rgba(248, 244, 237, 0.96);
    border-block-end: 1px solid var(--border);
    box-shadow: var(--shadow-lg);
    -webkit-backdrop-filter: blur(20px) saturate(120%);
    backdrop-filter: blur(20px) saturate(120%);
    opacity: 0;
    visibility: hidden;
    translate: 0 -0.75rem;
    transition:
      opacity var(--dur-3) var(--ease-brand),
      translate var(--dur-3) var(--ease-brand),
      visibility 0s linear var(--dur-3);
  }
  .site-nav.is-open {
    opacity: 1;
    visibility: visible;
    translate: 0 0;
    transition-delay: 0s, 0s, 0s;
  }
  .site-nav__list { flex-direction: column; align-items: stretch; gap: 0; }
  .site-nav__link {
    /* The <a> is inline-flex, so without this the row divider under it only
       spans the width of the word and the drawer reads as ragged. */
    inline-size: 100%;
    min-block-size: 3.25rem;
    padding-inline: 0;
    font-size: var(--fs-lg);
    border-block-end: 1px solid var(--border);
    border-radius: 0;
  }
  .site-nav__link::after { inset-inline: 0; inset-block-end: -1px; }
  .site-nav__actions {
    display: flex;
    flex-direction: column;
    gap: var(--space-3);
    margin-block-start: var(--space-6);
  }
  html.nav-open, html.nav-open body { overflow: hidden; }

  /* The scroll-lock above (overflow:hidden) removes the scroll container, which
     breaks the header's `position: sticky` — it drops back to its in-flow spot
     at the document top and scrolls off-screen, taking the logo + close (X)
     with it. Pin the bar to the viewport while the menu is open, and force its
     frosted background on so it reads as a solid bar sitting above the drawer. */
  html.nav-open .site-header {
    position: fixed;
    inset-block-start: 0;
    inset-inline: 0;
  }
  html.nav-open .site-header::before { opacity: 1; }

  /* Scrim under the open drawer, for the same reason the a11y panel has one:
     main.js marks the whole page behind it `inert`, so a sighted user has to
     SEE that it has stopped taking input. Left lit, the page looked live while
     it was in fact frozen.
     It is a pseudo-element of the header rather than an element of its own, so
     no page has to ship markup for it. `z-index: -1` keeps it under the header
     bar and under the fixed drawer, both of which are its own descendants,
     while the header's stacking context keeps it over <main>. A click on it
     targets .site-header itself, which is how main.js closes on outside click.
     visibility:hidden while closed takes it out of hit testing entirely. */
  .site-header::after {
    content: "";
    position: fixed;
    z-index: -1;
    inset-block: var(--header-h) 0;
    inset-inline: 0;
    background-color: var(--scrim);
    opacity: 0;
    visibility: hidden;
    transition:
      opacity var(--dur-3) var(--ease-brand),
      visibility 0s linear var(--dur-3);
  }
  html.nav-open .site-header::after {
    opacity: 1;
    visibility: visible;
    transition-delay: 0s, 0s;
  }
}

/* =============================================================================
   8. SITE FOOTER
   Contract (same column edge as the header and every .section):
   <footer class="site-footer">
     <div class="container site-footer__inner">
       <div class="site-footer__brand"> logo + line + contact </div>
       <nav class="site-footer__nav" aria-label="…"> .site-footer__col … </nav>
     </div>
     <div class="site-footer__bar"><div class="container"> … </div></div>
   </footer>
   ============================================================================= */
.site-footer {
  position: relative;
  background-color: var(--bg-warm);
  border-block-start: 1px solid var(--border);
}
.site-footer__inner {
  display: grid;
  gap: clamp(2.5rem, 5vw, 4rem);
  padding-block: clamp(3rem, 6vw, 5rem);
  grid-template-columns: 1fr;
  max-inline-size: var(--container);
}
@media (min-width: 760px) {
  .site-footer__inner { grid-template-columns: minmax(16rem, 22rem) 1fr; }
}

.site-footer__logo { inline-size: auto; block-size: 2.25rem; }
.site-footer__brand > * + * { margin-block-start: var(--space-4); }
.site-footer__tagline {
  max-inline-size: 30ch;
  font-size: var(--fs-sm);
  font-weight: 300;
  line-height: var(--lh-body);
  color: var(--text-2);
}

/* Parent-brand attribution. מושכות is a product of TripleIL, and the footer is
   where a visitor checks who is actually behind the software, so this sits
   above the contact line and carries a touch more weight than the tagline. */
.site-footer__maker {
  max-inline-size: 40ch;
  margin-block-start: var(--space-3);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: var(--lh-body);
  color: var(--text);
}
.site-footer__maker .link { font-weight: 800; }

.site-footer__nav {
  display: grid;
  gap: var(--space-6) var(--space-5);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 10rem), 1fr));
}
.site-footer__col > * + * { margin-block-start: var(--space-3); }
.site-footer__title {
  font-size: var(--fs-2xs);
  font-weight: 500;
  letter-spacing: var(--ls-label);
  color: var(--text-3);
}
.site-footer__list { display: flex; flex-direction: column; gap: var(--space-1); }
.site-footer__link {
  display: inline-flex;
  align-items: center;
  min-block-size: 2.25rem;
  font-size: var(--fs-sm);
  font-weight: 300;
  color: var(--text);
  transition: color var(--dur-2) ease, translate var(--dur-2) var(--ease-brand);
}
.site-footer__link:hover { color: var(--brand-ink); translate: -0.2rem 0; }

.site-footer__bar {
  border-block-start: 1px solid var(--border);
  background-color: var(--bg);
}
.site-footer__bar > .container {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  padding-block: var(--space-5);
  max-inline-size: var(--container);
}
.site-footer__legal {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-5);
  font-size: var(--fs-xs);      /* legibility floor — see .caption */
  color: var(--text-3);
}
.site-footer__legal a { transition: color var(--dur-2) ease; }
.site-footer__legal a:hover { color: var(--brand-ink); }

/* =============================================================================
   9. DEVICE FRAMES
   9.1 Phone — iPhone-class proportions taken from the product's own
       `.jc-device-frame`: 393x852 screen, 52px outer radius, 125x37 island,
       home indicator.

   Everything inside the frame is sized in `cqi` — 1cqi is 1% of the frame's
   RENDERED width. That matters because --phone-w is a request, not a promise:
   `max-inline-size: 100%` can shrink the frame inside a narrow column, and the
   old `calc(var(--phone-w) * k)` internals kept computing off the unclamped
   number. At a 320px viewport a --phone-w:320px frame renders ~280px wide and
   the dynamic island came out 33% of the screen instead of 30.3%, with the
   corner radius and the side buttons stranded outside the bezel. cqi tracks the
   real box, so the phone stays a phone at every width.

   The bezel is an `inset` on the screen rather than padding on the frame, so
   the frame's content box and border box are the same and 100cqi is the true
   outer width. The frame's own radius is a percentage pair (13.2% of the width
   over the same length expressed as a share of the height) because the frame
   cannot query itself.

   Do not declare `container-type` on anything between .device-phone and its
   screen contents; it would re-anchor every unit below.

   <div class="device-phone" style="--phone-w: 320px">
     <div class="device-phone__screen pwa-surface">
       <div class="device-phone__statusbar" dir="ltr"><span>9:41</span><span>…</span></div>
       <div class="device-phone__app"> … real PWA markup … </div>
     </div>
   </div>
   ============================================================================= */
.device-phone {
  /* The real device is 393px wide. At the old flat 300px default every ported
     screen rendered at 76% of life size, which put the FloatingNav label at
     9.9px and the status bar at 12.6px — legible, but at the floor for a
     marketing screenshot, and 13px bold Fabs is one of the details that makes
     the port recognisable at a glance.
     The default is now "as large as the column allows, up to 360px" — 92% of
     life size, label 11.9px — and it degrades by column rather than by a fixed
     number: 350px inside a 390px phone (label 11.6px), 320px at 360px. In rem,
     so it grows with the accessibility widget's text scale like everything
     else. A caller that needs a specific size still sets --phone-w itself. */
  --phone-w: min(100%, 22.5rem);

  position: relative;
  container-type: inline-size;
  inline-size: var(--phone-w);
  max-inline-size: 100%;
  aspect-ratio: 413 / 872;
  flex: none;
  /* 13.2% of the width; 6.2516% of the height is the same length at 413/872. */
  border-radius: 13.2% / 6.2516%;
  background: linear-gradient(155deg, var(--bezel-edge) 0%, var(--bezel) 24%, var(--bezel) 66%, var(--bezel-edge) 100%);
  box-shadow:
    0 0 0 1px rgba(255, 255, 255, 0.14),
    inset 0 0 2px rgba(255, 255, 255, 0.22),
    var(--shadow-xl);
}
/* Volume pair + silence switch on one edge, side button on the other.
   They have to PROTRUDE to read as buttons: the part sitting on top of the
   bezel is the same grey as the bezel and is invisible by definition, so only
   the overhang is ever seen. 1cqi of overhang is what a real iPhone has
   (~0.7mm on a 71.5mm body) and is ~3px on the default 300px frame, which is
   the smallest nub that still reads at a glance. The earlier 0.5cqi overhang
   on a 0.9cqi button showed 1.5px and the phone read as a plain slab. */
.device-phone::before {
  content: "";
  position: absolute;
  z-index: 2;
  inset-inline-end: -1cqi;
  inset-block-start: 25%;
  inline-size: 2cqi;
  block-size: 7.2cqi;
  border-radius: var(--r-pill);
  background-color: var(--bezel-edge);
  box-shadow:
    0 9.3cqi 0 var(--bezel-edge),
    0 -12cqi 0 var(--bezel-edge);
}
/* Side button on the opposite edge. */
.device-phone::after {
  content: "";
  position: absolute;
  z-index: 2;
  inset-inline-start: -1cqi;
  inset-block-start: 30%;
  inline-size: 2cqi;
  block-size: 11.5cqi;
  border-radius: var(--r-pill);
  background-color: var(--bezel-edge);
}

.device-phone__screen {
  position: absolute;
  inset: 2.42cqi;                       /* the bezel */
  overflow: hidden;
  border-radius: 10.78cqi;              /* outer radius minus the bezel */
  background-color: var(--cream-warm);
}
/* Dynamic island. Centred with auto inline margins rather than a translate,
   because `translate` is physical and would drift in an RTL document. */
.device-phone__screen::before {
  content: "";
  position: absolute;
  z-index: 5;
  inset-block-start: 2.7cqi;
  inset-inline: 0;
  margin-inline: auto;
  inline-size: 30.3cqi;
  block-size: 9cqi;
  border-radius: var(--r-pill);
  background-color: var(--bezel);
}
/* Home indicator */
.device-phone__screen::after {
  content: "";
  position: absolute;
  z-index: 5;
  inset-block-end: 2.4cqi;
  inset-inline: 0;
  margin-inline: auto;
  inline-size: 32cqi;
  block-size: 1.4cqi;
  min-block-size: 3px;
  border-radius: var(--r-pill);
  background-color: var(--cocoa);
  opacity: 0.55;
}
.device-phone--bare::before,
.device-phone--bare::after,
.device-phone--bare .device-phone__screen::before,
.device-phone--bare .device-phone__screen::after { content: none; }

.device-phone__statusbar {
  position: relative;
  z-index: 4;
  display: flex;
  align-items: center;
  justify-content: space-between;
  block-size: 12.8cqi;
  padding-inline: 6.5cqi;
  padding-block-start: 1.2cqi;
  font-family: var(--font-num);
  font-size: 4.2cqi;
  font-weight: 500;
  color: var(--cocoa);
  direction: ltr;
  pointer-events: none;
}
.device-phone__statusbar .icon { inline-size: 1em; block-size: 1em; stroke-width: 2; }

/* The scrolling app area. Keep screen content inside this. */
.device-phone__app {
  position: relative;
  z-index: 1;
  block-size: 100%;
  inline-size: 100%;
  overflow: hidden;
}
.device-phone__statusbar + .device-phone__app { block-size: calc(100% - 12.8cqi); }

/* Floating pill bottom nav — a value-for-value port of FloatingNav in
   app/src/features/student-pwa/StudentPwaShell.tsx (the instructor shell uses
   the same one). The structure matters as much as the colours:

     nav   .pwa-nav       `absolute inset-x-0 bottom-3 flex justify-center px-4`
                          a full-width CENTRING wrapper, not the bar itself
     ul    .pwa-nav__list `flex items-center gap-1 … p-1.5` — the pill, sized by
                          its contents, so 4 tabs make a short pill and 5 a
                          longer one. It never stretches edge to edge.
     a     .pwa-nav__item icon only …
     a[aria-current]      … except the active tab, which alone carries a label
                          and expands into a solid rust pill.

   Every cqi below is the real Tailwind pixel value over the real 393px screen
   (gap-1 = 4px = 1.02cqi, p-1.5 = 6px = 1.53cqi, and so on).

   <nav class="pwa-nav" aria-label="ניווט">
     <ul class="pwa-nav__list">
       <li><a class="pwa-nav__item" aria-current="page" href="#">
             <svg class="icon">…</svg><span class="pwa-nav__label">בית</span></a></li>
       <li><a class="pwa-nav__item" href="#"><svg class="icon">…</svg>
             <span class="pwa-nav__label">לוח זמנים</span></a></li>
     </ul>
   </nav>
   The label is written for every tab and hidden on the inactive ones by CSS, so
   the accessible name of each tab is a real word and not an icon. */
.pwa-nav {
  position: absolute;
  inset-block-end: 4.2cqi;      /* bottom-3, lifted clear of the home indicator */
  inset-inline: 0;
  z-index: 3;
  display: flex;
  justify-content: center;
  padding-inline: 4cqi;         /* px-4 */
}
.pwa-nav__list {
  display: flex;
  align-items: center;
  gap: 1cqi;                    /* gap-1 */
  padding: 1.5cqi;              /* p-1.5 */
  border-radius: var(--r-pill);
  background-color: rgba(255, 250, 244, 0.62);
  border: 1px solid var(--glass-edge);
  box-shadow: 0 10px 30px -10px rgba(131, 67, 49, 0.4);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
}
.pwa-nav__item {
  display: inline-flex;
  align-items: center;
  gap: 2cqi;                    /* gap-2 */
  padding: 2.5cqi;              /* px-2.5 py-2.5 */
  border-radius: var(--r-pill);
  color: var(--ink-soft);
}
.pwa-nav__item .icon {
  inline-size: 5.1cqi;          /* lucide size={20} */
  block-size: 5.1cqi;
  stroke-width: 1.75;
}
.pwa-nav__label {
  font-size: 3.3cqi;            /* text-[13px] */
  font-weight: 800;             /* font-bold — Fabs has no 700, 800 is the face */
  line-height: 1;
  white-space: nowrap;
}
/* Only the active tab is labelled, exactly as in the shell. */
.pwa-nav__item:not([aria-current]) .pwa-nav__label { display: none; }
.pwa-nav__item[aria-current] {
  padding-inline: 4.1cqi;       /* px-4 */
  background-color: var(--rust-deep);
  color: var(--cream-warm);
  box-shadow: 0 4px 14px -4px rgba(131, 67, 49, 0.6);
}
.pwa-nav__item[aria-current] .icon { stroke-width: 2.25; }

/* 9.2 Desktop / browser frame
   <div class="device-desktop">
     <div class="device-desktop__bar"><span class="device-desktop__dots"></span>
       <span class="device-desktop__url" dir="ltr">moshchot.biz/schedule</span></div>
     <div class="device-desktop__screen"> … office UI … </div>
   </div>
   -------------------------------------------------------------------------- */
.device-desktop {
  position: relative;
  inline-size: 100%;
  overflow: hidden;
  border-radius: var(--r-xl);
  background-color: var(--surface);
  box-shadow: var(--shadow-xl), var(--ring-hairline);
}
.device-desktop__bar {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  block-size: 2.75rem;
  padding-inline: var(--space-4);
  background-color: var(--surface-muted);
  border-block-end: 1px solid var(--border);
  direction: ltr;
}
.device-desktop__dots {
  position: relative;
  inline-size: 2.75rem;
  block-size: 0.625rem;
  flex: none;
}
.device-desktop__dots::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline-start: 0;   /* the bar is dir="ltr", so this is its left edge */
  inline-size: 0.625rem;
  block-size: 0.625rem;
  border-radius: var(--r-full);
  background-color: rgba(46, 29, 20, 0.16);
  box-shadow:
    1rem 0 0 rgba(46, 29, 20, 0.16),
    2rem 0 0 rgba(46, 29, 20, 0.16);
}
.device-desktop__url {
  flex: 1;
  max-inline-size: 22rem;
  margin-inline: auto;
  padding-block: 0.25rem;
  padding-inline: var(--space-4);
  border-radius: var(--r-pill);
  background-color: var(--white);
  box-shadow: var(--ring-hairline);
  /* Browser chrome showing a Latin URL: not brand voice, so not the brand face. */
  font-family: var(--font-ltr);
  font-size: var(--fs-3xs);
  font-weight: 500;
  color: var(--text-3);
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.device-desktop__screen {
  position: relative;
  overflow: hidden;
  aspect-ratio: 16 / 10;
  background-color: var(--bg);
}
.device-desktop--tall .device-desktop__screen { aspect-ratio: 4 / 3; }
.device-desktop--wide .device-desktop__screen { aspect-ratio: 16 / 9; }

/* =============================================================================
   10. APP STORE BADGES
   main.js hydrates <div class="store-badges" data-store-badges></div> with two
   hand-built inline SVG badges. The apps are not published yet, so each anchor
   is href="#", data-status="pending", and its accessible name says בקרוב.
   Markup produced:
     <a class="store-badge" href="#" data-store="apple" data-status="pending"
        aria-label="…" dir="ltr"><svg …>…</svg></a>
   ============================================================================= */
.store-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}
.store-badge {
  display: inline-flex;
  block-size: 3.25rem;
  border-radius: 0.625rem;
  background-color: var(--cocoa);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
  transition:
    translate var(--dur-3) var(--ease-brand),
    box-shadow var(--dur-3) var(--ease-brand),
    background-color var(--dur-2) ease;
}
.store-badge svg { block-size: 100%; inline-size: auto; display: block; }
/* "App Store" and "Google Play" are Latin trademarks: they must not render in
   the Hebrew brand face. Weight stays on the SVG's own presentation attributes. */
.store-badge svg text { font-family: var(--font-ltr); }
.store-badge:hover { translate: 0 -2px; background-color: var(--chocolate); box-shadow: var(--shadow-lg); }
.store-badge:active { translate: 0 0; }
.store-badge:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.store-badge--sm { block-size: 2.75rem; }

.store-badges__note {
  flex-basis: 100%;
  font-size: var(--fs-xs);      /* legibility floor — see .caption */
  font-weight: 300;
  color: var(--text-3);
}

/* =============================================================================
   11. ACCESSIBILITY WIDGET
   Injected in full by a11y.js, as the FIRST nodes in <body> after the skip
   link, so the controls are the second stop in the tab order rather than the
   last. All three nodes are position:fixed, so DOM order costs nothing
   visually. Anchored to the inline-start edge, which is the right-hand side in
   RTL. Panel is a real dialog: focus-trapped, aria-modal, the rest of the page
   inert, Esc closes.
   ============================================================================= */
.a11y-fab {
  position: fixed;
  inset-block-end: clamp(1rem, 3vw, 1.5rem);
  inset-inline-start: clamp(1rem, 3vw, 1.5rem);
  z-index: var(--z-a11y);
  display: grid;
  place-items: center;
  inline-size: 3.25rem;
  block-size: 3.25rem;
  border-radius: var(--r-full);
  background-color: var(--brand);
  color: var(--on-brand);
  box-shadow: var(--shadow-lg), var(--ring-hairline);
  transition: background-color var(--dur-2) ease, scale var(--dur-3) var(--ease-brand);
}
.a11y-fab:hover  { background-color: var(--brand-strong); scale: 1.05; }
.a11y-fab:active { scale: 0.96; }
.a11y-fab:focus-visible { outline: 3px solid var(--cocoa); outline-offset: 3px; }
.a11y-fab .icon { inline-size: 1.625rem; block-size: 1.625rem; stroke-width: 1.7; }

/* Scrim. The panel is a real modal — role=dialog, aria-modal, and every other
   child of <body> genuinely `inert` while it is open — so a sighted user must
   see that the page behind it has stopped taking input. Without this the page
   stayed fully lit and looked interactive while it was in fact frozen.
   It sits one layer under the fab so the fab stays clickable to close, and it
   is a real element rather than a pseudo-element so that a click on it has its
   own event target and a11y.js's outside-click handler fires. */
.a11y-scrim {
  position: fixed;
  inset: 0;
  z-index: calc(var(--z-a11y) - 1);
  background-color: var(--scrim);
  -webkit-backdrop-filter: blur(2px);
  backdrop-filter: blur(2px);
  opacity: 0;
  visibility: hidden;
  transition:
    opacity var(--dur-3) var(--ease-brand),
    visibility 0s linear var(--dur-3);
}
.a11y-scrim.is-open {
  opacity: 1;
  visibility: visible;
  transition-delay: 0s, 0s;
}

.a11y-panel {
  position: fixed;
  inset-block-end: calc(clamp(1rem, 3vw, 1.5rem) + 4rem);
  inset-inline-start: clamp(1rem, 3vw, 1.5rem);
  z-index: var(--z-a11y);
  inline-size: min(21rem, calc(100vw - 2rem));
  max-block-size: min(37rem, calc(100dvh - 6.5rem));
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: var(--space-5);
  background-color: var(--white);
  border-radius: var(--r-2xl);
  box-shadow: var(--shadow-xl), var(--ring-hairline);
  opacity: 0;
  visibility: hidden;
  translate: 0 0.75rem;
  scale: 0.98;
  transform-origin: 100% 100%;
  /* visibility flips instantly on open and only after the fade on close, so a
     control is always focusable the moment the panel is marked open. */
  transition:
    opacity var(--dur-3) var(--ease-brand),
    translate var(--dur-3) var(--ease-brand),
    scale var(--dur-3) var(--ease-brand),
    visibility 0s linear var(--dur-3);
}
.a11y-panel.is-open {
  opacity: 1;
  visibility: visible;
  translate: 0 0;
  scale: 1;
  transition-delay: 0s, 0s, 0s, 0s;
}

.a11y-panel__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-block-end: var(--space-5);
}
.a11y-panel__title {
  font-size: var(--fs-lg);
  font-weight: 800;
  line-height: 1.2;
  color: var(--text);
}
.a11y-panel__close {
  display: grid;
  place-items: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  margin-inline-end: -0.5rem;
  border-radius: var(--r-full);
  color: var(--text-3);
  transition: background-color var(--dur-2) ease, color var(--dur-2) ease;
}
.a11y-panel__close:hover { background-color: var(--surface-muted); color: var(--text); }

.a11y-group + .a11y-group { margin-block-start: var(--space-5); }
.a11y-group__label {
  display: block;
  margin-block-end: var(--space-3);
  font-size: var(--fs-2xs);
  font-weight: 500;
  letter-spacing: var(--ls-label);
  color: var(--text-3);
}

/* Font-size stepper */
.a11y-stepper {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-1);
  border-radius: var(--r-pill);
  background-color: var(--soft);
  box-shadow: var(--ring-hairline);
}
.a11y-stepper__btn {
  display: grid;
  place-items: center;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  flex: none;
  border-radius: var(--r-full);
  background-color: var(--white);
  color: var(--text);
  box-shadow: var(--shadow-xs);
  transition: background-color var(--dur-2) ease, color var(--dur-2) ease, scale var(--dur-2) var(--ease-brand);
}
.a11y-stepper__btn:hover:not(:disabled) { background-color: var(--rust); color: var(--on-rust); }
.a11y-stepper__btn:active:not(:disabled) { scale: 0.94; }
.a11y-stepper__btn:disabled { opacity: 0.4; cursor: not-allowed; }
.a11y-stepper__value {
  flex: 1;
  text-align: center;
  font-family: var(--font-num);
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

/* Toggle rows */
.a11y-list { display: flex; flex-direction: column; gap: var(--space-2); }
.a11y-toggle {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  inline-size: 100%;
  min-block-size: 3rem;
  padding-block: var(--space-2);
  padding-inline: var(--space-3);
  border-radius: var(--r-md);
  text-align: start;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--text);
  transition: background-color var(--dur-2) ease, color var(--dur-2) ease;
}
.a11y-toggle:hover { background-color: var(--soft); }
/* Set only on "עצירת אנימציות" while the OS asks for reduced motion: the state
   is real and locked, so the row shows as unavailable but stays focusable, and
   its title says why. */
.a11y-toggle[aria-disabled="true"] { opacity: 0.72; cursor: not-allowed; }
.a11y-toggle[aria-disabled="true"]:hover { background-color: transparent; }
.a11y-toggle__icon { color: var(--text-3); transition: color var(--dur-2) ease; }
.a11y-toggle__text { flex: 1; }
/* The switch is a UI component, so WCAG 1.4.11 wants 3:1 on both the track and
   the knob. --line (#e7e0d5) gave 1.31:1 on the white panel and a white knob on
   an #f1ece3 track gave 1.18:1: the off state rendered as a blank capsule with
   no visible knob. Both edges now use --text-2 ink (7.04:1), so off/on is told
   by knob POSITION and not by colour alone. */
.a11y-toggle__switch {
  position: relative;
  flex: none;
  inline-size: 2.5rem;
  block-size: 1.5rem;
  border-radius: var(--r-pill);
  background-color: var(--surface-muted);
  box-shadow: inset 0 0 0 1.5px var(--text-2);
  transition: background-color var(--dur-2) ease, box-shadow var(--dur-2) ease;
}
.a11y-toggle__switch::after {
  content: "";
  position: absolute;
  inset-block-start: 0.1875rem;
  inset-inline-start: 0.1875rem;
  inline-size: 1.125rem;
  block-size: 1.125rem;
  border-radius: var(--r-full);
  background-color: var(--white);
  box-shadow: var(--shadow-xs), inset 0 0 0 1.5px var(--text-2);
  transition: translate var(--dur-2) var(--ease-brand), box-shadow var(--dur-2) ease;
}
.a11y-toggle[aria-pressed="true"] { color: var(--brand-ink); }
.a11y-toggle[aria-pressed="true"] .a11y-toggle__icon { color: var(--brand-ink); }
.a11y-toggle[aria-pressed="true"] .a11y-toggle__switch {
  background-color: var(--brand);          /* 4.82:1 against the white panel */
  box-shadow: inset 0 0 0 1.5px var(--brand-ink);
}
.a11y-toggle[aria-pressed="true"] .a11y-toggle__switch::after {
  box-shadow: var(--shadow-xs), inset 0 0 0 1.5px var(--brand-ink);
}
/* RTL: the knob travels toward the inline-end edge, which is physically left. */
.a11y-toggle[aria-pressed="true"] .a11y-toggle__switch::after { translate: -1rem 0; }

.a11y-panel__reset {
  inline-size: 100%;
  margin-block-start: var(--space-5);
}
.a11y-panel__foot {
  margin-block-start: var(--space-4);
  font-size: var(--fs-xs);      /* legibility floor — see .caption */
  line-height: 1.6;
  color: var(--text-2);
}

/* =============================================================================
   12. MOTION PRIMITIVES
   Elements opt in with data-reveal. They stay visible when JS is unavailable:
   the hidden state only applies once main.js has set html.js.
   ============================================================================= */
html.js [data-reveal] {
  opacity: 0;
  will-change: opacity, translate;
  transition:
    opacity var(--dur-4) var(--ease-brand),
    translate var(--dur-4) var(--ease-brand),
    scale var(--dur-4) var(--ease-brand);
  transition-delay: var(--reveal-delay, 0ms);
}
html.js [data-reveal="up"],
html.js [data-reveal=""]        { translate: 0 1.75rem; }
html.js [data-reveal="down"]    { translate: 0 -1.25rem; }
html.js [data-reveal="start"]   { translate: 2rem 0; }
html.js [data-reveal="end"]     { translate: -2rem 0; }
html.js [data-reveal="scale"]   { scale: 0.94; }
html.js [data-reveal="fade"]    { translate: 0 0; }

html.js [data-reveal].is-revealed {
  opacity: 1;
  translate: 0 0;
  scale: 1;
  will-change: auto;
}

/* When motion is off, the reveal still happens, just without displacement. */
html.js[data-a11y-motion="off"] [data-reveal] { translate: 0 0 !important; scale: 1 !important; }

@media (prefers-reduced-motion: reduce) {
  html.js [data-reveal] { translate: 0 0 !important; scale: 1 !important; }
}

/* A masked wordmark / headline reveal: wrap each line in .reveal-line > span. */
.reveal-line { display: block; overflow: hidden; }
html.js .reveal-line > * {
  display: block;
  translate: 0 105%;
  transition: translate var(--dur-5) var(--ease-brand);
  transition-delay: var(--reveal-delay, 0ms);
}
html.js .reveal-line.is-revealed > * { translate: 0 0; }
@media (prefers-reduced-motion: reduce) {
  html.js .reveal-line > * { translate: 0 0; }
}

/* Parallax layers.
   <img data-parallax="0.18" …>  — the number is the total travel as a fraction
   of the element's own block size; omit it for the 0.12 default.
   main.js §initParallax drives --par-y from a scrubbed ScrollTrigger (or a
   passive rAF fallback when GSAP is absent), writing nothing but this one
   custom property, so the paint stays on the compositor. The element must be
   over-sized by at least its travel, or its container must clip, or the layer
   will show its own edge at one end of the scroll.
   Motion off (OS or widget) tears the triggers down and resets --par-y to 0. */
[data-parallax] { will-change: transform; translate: 0 var(--par-y, 0px); }
html[data-a11y-motion="off"] [data-parallax] { translate: 0 0 !important; }
@media (prefers-reduced-motion: reduce) {
  [data-parallax] { translate: 0 0 !important; will-change: auto; }
}

/* =============================================================================
   13. HIGH-CONTRAST OVERRIDES
   base.css §7.2 retunes the tokens: every surface goes white and --ring-hairline
   becomes a 2px charcoal ring, so anything composing `var(--shadow-*),
   var(--ring-hairline)` (.card, .card-hero, .device-desktop, .a11y-fab,
   .a11y-panel, .tag, .icon-plate, .a11y-stepper) gains a hard edge for free.

   Listed below are the parts that DON'T compose that ring: they carry their own
   translucency, their own tint, or a shadow-only boundary that goes transparent
   in this mode. Every one of them needs an explicit border of its own, or it
   would dissolve into the white page.

   The form controls (§15.8) and the long-form elements (§16.6) carry their own
   high-contrast overrides next to their own rules rather than here, because
   they are element-level and there are enough of them to be worth reading in
   one place with the thing they override.
   ============================================================================= */
html[data-a11y-contrast="on"] .site-header.is-scrolled,
html[data-a11y-contrast="on"] .site-nav {
  background-color: var(--white);
  box-shadow: none;
  border-block-end-color: var(--charcoal);
}

/* Shadow-only surfaces. */
html[data-a11y-contrast="on"] .card-glass,
html[data-a11y-contrast="on"] .card-glass--flat {
  background-color: var(--white);
  border-color: var(--charcoal);
  border-width: 2px;
  box-shadow: none;
}
html[data-a11y-contrast="on"] .device-desktop__url,
html[data-a11y-contrast="on"] .a11y-stepper__btn,
html[data-a11y-contrast="on"] .store-badge {
  box-shadow: inset 0 0 0 2px var(--charcoal);
}
/* The traffic-light dots are painted with a cocoa alpha, which all but vanishes
   on white; they are the only cue that the frame is a browser window. */
html[data-a11y-contrast="on"] .device-desktop__dots::before {
  background-color: var(--charcoal);
  box-shadow: 1rem 0 0 var(--charcoal), 2rem 0 0 var(--charcoal);
}
html[data-a11y-contrast="on"] .skip-link { box-shadow: inset 0 0 0 2px var(--white); }

/* The phone frame paints its own bezel, so it survives; the screen inside it
   needs the seam between bezel and app drawn explicitly. */
html[data-a11y-contrast="on"] .device-phone__screen {
  box-shadow: inset 0 0 0 2px var(--charcoal);
}

/* Switches: charcoal track edge and charcoal knob edge in both states, so the
   knob is still locatable once every fill is white. */
html[data-a11y-contrast="on"] .a11y-toggle__switch,
html[data-a11y-contrast="on"] .a11y-toggle__switch::after {
  box-shadow: inset 0 0 0 2px var(--charcoal);
}
html[data-a11y-contrast="on"] .a11y-toggle[aria-pressed="true"] .a11y-toggle__switch {
  background-color: var(--brand);
}
html[data-a11y-contrast="on"] .a11y-toggle[aria-pressed="true"] .a11y-toggle__switch::after {
  background-color: var(--white);
}
html[data-a11y-contrast="on"] .tag,
html[data-a11y-contrast="on"] .icon-plate {
  background-color: var(--white);
  color: var(--cocoa);
  box-shadow: inset 0 0 0 1.5px var(--charcoal);
}
html[data-a11y-contrast="on"] .tag--solid,
html[data-a11y-contrast="on"] .icon-plate--solid {
  background-color: var(--brand);
  color: var(--white);
  box-shadow: none;
}
html[data-a11y-contrast="on"] .btn--frost {
  --btn-bg: var(--white);
  --btn-bd: var(--charcoal);
}
html[data-a11y-contrast="on"] .frost { background-color: rgba(255, 255, 255, 0.92); }
html[data-a11y-contrast="on"] .pwa-nav__list {
  background-color: var(--white);
  border-color: var(--charcoal);
  box-shadow: none;
}
/* The single stray tint left in this mode: the ochre dot on a "בקרוב" pill,
   2.15:1 on the white page. It is decoration, so it takes the ink colour. */
html[data-a11y-contrast="on"] .tag--soon::before { background-color: var(--cocoa); }
/* Ghost buttons are the one variant with no fill and no border of their own.
   In a mode whose whole job is to give every control a visible edge, that
   dissolves them into the page. */
html[data-a11y-contrast="on"] .btn--ghost {
  --btn-bg: var(--white);
  --btn-bd: var(--charcoal);
  --btn-fg: var(--cocoa);
}
html[data-a11y-contrast="on"] .store-badge { background-color: var(--chocolate); }

/* =============================================================================
   14. RESPONSIVE SAFETY
   ============================================================================= */
@media (max-width: 420px) {
  .btn { padding-inline: 1.375rem; }
  .btn--lg { padding-inline: 1.625rem; }
  .a11y-fab { inline-size: 3rem; block-size: 3rem; }
  /* 360px budget: logo 83 + CTA ~86 + hamburger 44 + two 12px gaps = 237 of the
     320px available inside the gutter. */
  .site-header__actions .btn { padding-inline: 0.875rem; }
}

/* Very wide screens: stop the layout from stretching, keep the air. */
@media (min-width: 1900px) {
  :root { --container: 1360px; --container-wide: 1560px; }
}

/* =============================================================================
   15. FORM CONTROLS
   The site's only action is a demo request, so the form IS the conversion path
   and it gets the same care as the hero. Everything here is styled at ELEMENT
   level, not by class: a page author writing plain `<label> + <input>` gets the
   finished control without knowing a class name, and no browser default is ever
   left visible. The class layer on top (§15.7) is layout only.

   Language: the same one the login card speaks. Soft 18px radii, white fill, a
   real 3:1 edge, a rust focus ring, the product's own easing. A square-cornered
   1px grey Chrome input next to a rust pill button is the sharpest possible
   break in that language, which is exactly why this section exists.

   Contract:
     <form class="form" novalidate>
       <div class="field">
         <label for="farm">שם החווה <span class="req" aria-hidden="true">*</span></label>
         <input id="farm" name="farm" type="text" required>
         <p class="field__hint" id="farm-hint">כפי שהוא מופיע ללקוחות</p>
       </div>
       <div class="form__row form__row--2"> … two .field … </div>
       <label class="check"><input type="checkbox" name="ok"> <span>…</span></label>
       <div class="form__actions"><button class="btn btn--primary" type="submit">…</button></div>
       <p class="form__status" role="status" aria-live="polite"></p>
     </form>
   ============================================================================= */

/* 15.1 Labels. Block by default so a label can never collide with its field,
   and a real 8px gap to whatever control follows it. */
label {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1.4;
  color: var(--text);
}
.req { color: var(--brand-ink); font-weight: 500; }

label + input,
label + textarea,
label + select,
label + .input,
label + .field__control { margin-block-start: var(--space-2); }

/* 15.2 The control surface. One look for every text-ish control, the textarea
   and the select. --border-strong (3.22:1 on cream, 3.53:1 on white) is the
   boundary WCAG 1.4.11 asks for; --border alone is a 1.20:1 hairline and the
   field would read as floating text. */
.input,
.textarea,
.select,
input[type="text"],
input[type="email"],
input[type="tel"],
input[type="url"],
input[type="search"],
input[type="number"],
input[type="password"],
input[type="date"],
input[type="time"],
input[type="datetime-local"],
input[type="month"],
input[type="week"],
input:not([type]),
textarea,
select {
  inline-size: 100%;
  min-block-size: 3rem;                /* 48px — over the 44px touch target */
  padding-block: 0.6875rem;
  padding-inline: var(--space-4);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 300;
  line-height: 1.5;
  color: var(--text);
  background-color: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-lg);
  box-shadow: var(--shadow-xs);
  -webkit-appearance: none;
  appearance: none;
  transition:
    border-color var(--dur-2) ease,
    background-color var(--dur-2) ease,
    box-shadow var(--dur-2) ease;
}

.input:hover,
input[type="text"]:hover,
input[type="email"]:hover,
input[type="tel"]:hover,
input[type="url"]:hover,
input[type="search"]:hover,
input[type="number"]:hover,
input[type="password"]:hover,
input[type="date"]:hover,
input:not([type]):hover,
textarea:hover,
select:hover { border-color: var(--brand); }

.input:focus-visible,
input:focus-visible,
textarea:focus-visible,
select:focus-visible {
  outline: 3px solid var(--focus);
  outline-offset: 2px;
  border-color: var(--brand);
  box-shadow: var(--shadow-sm);
}

::placeholder { color: var(--text-3); opacity: 1; }

/* `resize: vertical` keeps the grip, deliberately. It is the one native
   affordance worth keeping: a farm owner writing a long "what should we see"
   note needs to be able to open the box, and `resize: none` takes that away for
   a cosmetic gain. Horizontal resizing is off — it would break the RTL column. */
textarea {
  min-block-size: 8.5rem;
  padding-block: var(--space-3);
  line-height: var(--lh-body);
  resize: vertical;
}

/* Chrome and Safari paint their own decorations inside these; they are the
   "raw browser styling" the quality bar forbids. */
input[type="search"]::-webkit-search-decoration,
input[type="search"]::-webkit-search-cancel-button { -webkit-appearance: none; }
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
input[type="number"] { -moz-appearance: textfield; appearance: textfield; }
input[type="date"]::-webkit-calendar-picker-indicator { opacity: 0.55; cursor: pointer; }
input[type="date"]::-webkit-calendar-picker-indicator:hover { opacity: 1; }

/* Autofill repaints the field in Chrome's own pale blue. The inset shadow is
   the only way back to the brand surface. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
select:-webkit-autofill {
  -webkit-text-fill-color: var(--text);
  caret-color: var(--text);
  box-shadow: inset 0 0 0 100px var(--surface), var(--shadow-xs);
  transition: background-color 9999s ease-out;
}

/* 15.3 Select. `appearance: none` kills the native chevron; this one is the
   site's own icon at the site's own stroke weight, in --ink-soft.
   The document is RTL, so the inline-end edge is physically LEFT. */
select:not([multiple]):not([size]) {
  padding-inline-end: 2.75rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236b5446' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: left var(--space-4) center;
  background-size: 1.125rem 1.125rem;
  cursor: pointer;
}
[dir="ltr"] select:not([multiple]):not([size]) { background-position: right var(--space-4) center; }
select[multiple],
select[size] { padding-inline-end: var(--space-4); background-image: none; min-block-size: auto; }
select option { color: var(--text); background-color: var(--surface); }

/* 15.4 Checkbox and radio. Custom boxes: the native controls are the single
   most obviously un-branded thing a page can render. */
input[type="checkbox"],
input[type="radio"] {
  display: inline-grid;
  place-content: center;
  inline-size: 1.375rem;
  block-size: 1.375rem;
  flex: none;
  margin: 0;
  padding: 0;
  background-color: var(--surface);
  border: 1.5px solid var(--border-strong);
  border-radius: var(--r-xs);
  box-shadow: var(--shadow-xs);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
  transition:
    background-color var(--dur-2) ease,
    border-color var(--dur-2) ease,
    box-shadow var(--dur-2) ease;
}
input[type="radio"] { border-radius: var(--r-full); }
input[type="checkbox"]:hover,
input[type="radio"]:hover { border-color: var(--brand); }

input[type="checkbox"]::before,
input[type="radio"]::before {
  content: "";
  inline-size: 0.8125rem;
  block-size: 0.8125rem;
  background-color: var(--on-brand);
  scale: 0;
  transition: scale var(--dur-2) var(--ease-brand);
}
/* A drawn tick, not a glyph: no font dependency, no emoji. */
input[type="checkbox"]::before {
  clip-path: polygon(14% 44%, 0 65%, 50% 100%, 100% 16%, 80% 0%, 43% 62%);
}
input[type="radio"]::before {
  inline-size: 0.625rem;
  block-size: 0.625rem;
  border-radius: var(--r-full);
}
input[type="checkbox"]:checked,
input[type="radio"]:checked,
input[type="checkbox"]:indeterminate {
  background-color: var(--brand);
  border-color: var(--brand);
}
input[type="checkbox"]:checked::before,
input[type="radio"]:checked::before { scale: 1; }
input[type="checkbox"]:indeterminate::before {
  clip-path: inset(44% 6% 44% 6%);
  scale: 1;
}

/* The box itself is 22px, so the ROW carries the touch target. `:has` gives
   plain <label><input type=checkbox> … </label> markup the same treatment as
   the explicit .check class. */
.check,
.radio,
label:has(> input[type="checkbox"]),
label:has(> input[type="radio"]) {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  min-block-size: 2.75rem;
  font-size: var(--fs-sm);
  font-weight: 300;
  line-height: var(--lh-snug);
  color: var(--text-2);
  cursor: pointer;
}
.check + .check,
.radio + .radio { margin-block-start: var(--space-1); }

/* 15.5 File input. The native button is the last raw control left. */
input[type="file"] {
  inline-size: 100%;
  padding: var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 300;
  color: var(--text-2);
  background-color: var(--surface);
  border: 1px dashed var(--border-strong);
  border-radius: var(--r-lg);
  cursor: pointer;
}
input[type="file"]::file-selector-button {
  margin-inline-end: var(--space-3);
  padding: 0.5rem 1.125rem;
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--text);
  background-color: var(--soft);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-pill);
  cursor: pointer;
  transition: background-color var(--dur-2) ease, color var(--dur-2) ease;
}
input[type="file"]::file-selector-button:hover { background-color: var(--brand); color: var(--on-brand); border-color: var(--brand); }

/* 15.6 Fieldset, legend, states.
   There is no red in this palette and inventing one is a palette-discipline
   failure, so the error ink is --brand-ink-strong (deep rust #5e2e21, 9.6:1 on
   cream). Error state is never carried by colour alone: the border thickens and
   the message under the field says what is wrong. */
fieldset {
  min-inline-size: 0;
  padding: var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
}
legend {
  padding-inline: var(--space-2);
  font-size: var(--fs-2xs);
  font-weight: 500;
  letter-spacing: var(--ls-label);
  color: var(--text-3);
}

input:disabled,
textarea:disabled,
select:disabled,
.input[aria-disabled="true"] {
  background-color: var(--surface-muted);
  color: var(--text-3);
  border-color: var(--border);
  box-shadow: none;
  cursor: not-allowed;
}
input:disabled::placeholder, textarea:disabled::placeholder { color: var(--text-3); }
input[readonly], textarea[readonly] { background-color: var(--bg-warm); }

input[aria-invalid="true"],
textarea[aria-invalid="true"],
select[aria-invalid="true"] {
  border-color: var(--brand-ink-strong);
  border-width: 2px;
}

/* Submit/reset written as <input> rather than <button class="btn">. Prefer the
   button; this is the safety net so it can never render as a grey OS chrome. */
input[type="submit"],
input[type="reset"],
input[type="button"] {
  inline-size: auto;
  min-block-size: 3rem;
  padding-block: 0.75rem;
  padding-inline: 1.75rem;
  font-size: var(--fs-sm);
  font-weight: 500;
  color: var(--on-brand);
  background-color: var(--brand);
  border: 1px solid var(--brand);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-rust);
  cursor: pointer;
  -webkit-appearance: none;
  appearance: none;
}
input[type="reset"], input[type="button"] {
  color: var(--text);
  background-color: var(--soft);
  border-color: var(--border-strong);
  box-shadow: var(--shadow-xs);
}

/* 15.7 Layout classes. Spacing lives on margins rather than a flex gap so the
   `label + control` rule above can never double up with a container gap. */
/* 34rem is the readable width for a stack of single-line fields. Inside a
   .form-card or a .card the container already sets the measure, so the form
   fills it rather than leaving a column of dead space beside itself. */
.form { max-inline-size: 34rem; }
.form--wide,
.form-card > .form,
.card > .form { max-inline-size: none; }
.form__row { display: grid; gap: var(--space-4); }
@media (min-width: 620px) {
  .form__row--2 { grid-template-columns: 1fr 1fr; }
  .form__row--3 { grid-template-columns: repeat(3, 1fr); }
}
.field { display: block; }
.field + .field,
.field + .form__row,
.form__row + .field,
.form__row + .form__row,
.field + .check,
.form__row + .check,
.field + fieldset,
fieldset + .field { margin-block-start: var(--space-4); }

.field__hint {
  margin-block-start: var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 300;
  line-height: 1.5;
  color: var(--text-3);
}
.field__error {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-block-start: var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1.5;
  color: var(--brand-ink-strong);
}
.field__error .icon { inline-size: 1.05rem; block-size: 1.05rem; margin-block-start: 0.1rem; }

.form__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-5);
  margin-block-start: var(--space-6);
}
/* A live region that starts empty: it must not reserve a padded, tinted box on
   the page before there is anything to announce. */
.form__status {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  margin-block-start: var(--space-4);
  padding: var(--space-3) var(--space-4);
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: var(--lh-snug);
  color: var(--brand-ink);
  background-color: var(--rust-a08);
  border-radius: var(--r-md);
  box-shadow: var(--ring-hairline);
}
.form__status:empty { display: none; }

/* A form sitting on the page rather than inside a .card. */
.form-card {
  padding: clamp(1.5rem, 3vw, 2.5rem);
  background-color: var(--surface);
  border-radius: var(--r-3xl);
  box-shadow: var(--shadow-lg), var(--ring-hairline);
}

/* 15.8 High contrast. The tokens in base.css §7.2 already flip every fill to
   white and every ink to cocoa; what a control needs on top of that is a hard
   2px edge, because a 1px --border-strong becomes charcoal but still reads thin
   next to 2px-ringed cards. */
html[data-a11y-contrast="on"] input,
html[data-a11y-contrast="on"] textarea,
html[data-a11y-contrast="on"] select,
html[data-a11y-contrast="on"] .input,
html[data-a11y-contrast="on"] fieldset {
  border-color: var(--charcoal);
  border-width: 2px;
  background-color: var(--white);
  color: var(--cocoa);
  box-shadow: none;
}
html[data-a11y-contrast="on"] select:not([multiple]):not([size]) {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23383c3f' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5l6 6 6-6'/%3E%3C/svg%3E");
}
html[data-a11y-contrast="on"] input[type="checkbox"]:checked,
html[data-a11y-contrast="on"] input[type="radio"]:checked,
html[data-a11y-contrast="on"] input[type="checkbox"]:indeterminate {
  background-color: var(--brand);
  border-color: var(--charcoal);
}
html[data-a11y-contrast="on"] input[type="checkbox"]::before,
html[data-a11y-contrast="on"] input[type="radio"]::before { background-color: var(--white); }
html[data-a11y-contrast="on"] input:disabled,
html[data-a11y-contrast="on"] textarea:disabled,
html[data-a11y-contrast="on"] select:disabled { background-color: var(--white); color: var(--cocoa); opacity: 0.65; }
/* Every edge is charcoal in this mode, so the invalid field's own 2px would be
   indistinguishable from a valid one. It goes to 3px, and the message under the
   field still carries the meaning in words. */
html[data-a11y-contrast="on"] input[aria-invalid="true"],
html[data-a11y-contrast="on"] textarea[aria-invalid="true"],
html[data-a11y-contrast="on"] select[aria-invalid="true"] { border-width: 3px; }
html[data-a11y-contrast="on"] .form__status,
html[data-a11y-contrast="on"] .form-card {
  background-color: var(--white);
  color: var(--cocoa);
  box-shadow: inset 0 0 0 2px var(--charcoal);
}
html[data-a11y-contrast="on"] input[type="submit"] { border-color: var(--charcoal); }

/* =============================================================================
   16. LONG-FORM ELEMENTS
   Tables, disclosure lists and quoted clauses: exactly what pages/privacy.html
   and pages/terms.html are made of, plus the odd figure or definition list.
   Element level again, so a legal page written in plain HTML comes out finished.
   ============================================================================= */

/* 16.1 Tables.
   main.js wraps every un-wrapped table in a .table-wrap scroller and gives it
   role="region" + tabindex="0", so a wide table scrolls inside its own box on a
   360px screen instead of pushing the page sideways, and a keyboard user can
   reach that scroll area. Authors may write the wrapper themselves:
     <div class="table-wrap"><table> … </table></div> */
/* A real border rather than --ring-hairline: the ring is an INSET shadow, and
   the row backgrounds inside the wrap paint straight over it, so the table's
   outer edge survived only where a cell happened not to cover it. */
.table-wrap {
  overflow-x: auto;
  overscroll-behavior-x: contain;
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  background-color: var(--surface);
  box-shadow: var(--shadow-xs);
  -webkit-overflow-scrolling: touch;
}
.table-wrap:focus-visible { outline: 3px solid var(--focus); outline-offset: 3px; }
.table-wrap > table { min-inline-size: 32rem; }
/* On a phone a 3-column legal table should WRAP rather than scroll; the floor
   only exists to stop a genuinely wide table being squeezed into columns one
   word across, and it is the point past which the scroller takes over. */
@media (max-width: 560px) { .table-wrap > table { min-inline-size: 20rem; } }

/* The caption shares the header row's field, so the top of the table card reads
   as one header block instead of an empty white band above the column names. */
caption {
  caption-side: block-start;
  padding: var(--space-3) var(--space-4) var(--space-2);
  font-size: var(--fs-xs);
  font-weight: 500;
  line-height: 1.5;
  text-align: start;
  color: var(--text-3);
  background-color: var(--bg-warm);
}

th, td {
  padding: var(--space-3) var(--space-4);
  text-align: start;
  vertical-align: top;
  border-block-end: 1px solid var(--border);
  overflow-wrap: break-word;
}
thead th {
  font-size: var(--fs-2xs);
  font-weight: 500;
  letter-spacing: var(--ls-label);
  line-height: 1.4;
  color: var(--text-3);
  background-color: var(--bg-warm);
  border-block-end: 1px solid var(--border-strong);
  white-space: nowrap;
}
tbody th { font-weight: 500; color: var(--text); }
tbody td {
  font-size: var(--fs-sm);
  font-weight: 300;
  line-height: var(--lh-body);
  color: var(--text-2);
}
tbody tr:last-child > th,
tbody tr:last-child > td { border-block-end: 0; }
tbody tr:nth-child(even) { background-color: var(--bg-warm); }
tfoot td, tfoot th {
  font-size: var(--fs-xs);
  font-weight: 500;
  color: var(--text);
  border-block-start: 1px solid var(--border-strong);
}
@media (max-width: 560px) {
  th, td { padding: var(--space-2) var(--space-3); }
}

/* 16.2 Disclosure. `list-style: none` removes the marker in Chrome and Firefox,
   the ::-webkit-details-marker rule finishes the job in Safari, and the chevron
   below is the site's own icon at the site's own stroke weight. */
details {
  background-color: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-xl);
  box-shadow: var(--shadow-xs);
  overflow: hidden;
  transition: box-shadow var(--dur-3) var(--ease-brand), border-color var(--dur-2) ease;
}
details:hover { border-color: var(--border-strong); }
details[open] { box-shadow: var(--shadow-sm); }
details + details { margin-block-start: var(--space-3); }

summary {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  min-block-size: 3.5rem;
  padding: var(--space-4) var(--space-5);
  font-size: var(--fs-md);
  font-weight: 500;
  line-height: var(--lh-snug);
  color: var(--text);
  cursor: pointer;
  list-style: none;
  transition: color var(--dur-2) ease, background-color var(--dur-2) ease;
}
summary::-webkit-details-marker { display: none; }
summary::marker { content: ""; }
summary:hover { color: var(--brand-ink); background-color: var(--rust-a08); }
summary:focus-visible { outline: 3px solid var(--focus); outline-offset: -3px; border-radius: var(--r-xl); }
summary::after {
  content: "";
  flex: none;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  margin-inline-start: auto;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23834331' stroke-width='1.7' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5l6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-size: contain;
  transition: rotate var(--dur-3) var(--ease-brand);
}
details[open] > summary::after { rotate: 180deg; }
details > :not(summary) {
  padding-inline: var(--space-5);
  padding-block-end: var(--space-5);
  font-size: var(--fs-sm);
  font-weight: 300;
  line-height: var(--lh-body);
  color: var(--text-2);
}
details > summary + * { padding-block-start: 0; }

/* Optional wrapper when a page shows a run of them as one FAQ block. */
.faq { display: flex; flex-direction: column; gap: var(--space-3); }
.faq > details + details { margin-block-start: 0; }

/* 16.3 Quotes. A rust rule on the reading edge (the RIGHT edge in RTL). */
blockquote {
  padding-inline-start: var(--space-5);
  border-inline-start: 3px solid var(--brand);
  font-size: var(--fs-lg);
  font-weight: 300;
  line-height: var(--lh-snug);
  color: var(--text);
}
blockquote p { font-size: inherit; color: inherit; }
blockquote > * + * { margin-block-start: var(--space-3); }
blockquote cite,
blockquote footer {
  display: block;
  font-size: var(--fs-xs);
  font-weight: 500;
  font-style: normal;
  line-height: 1.5;
  color: var(--text-3);
}
q { quotes: "\201D" "\201C" "\2019" "\2018"; }   /* RTL-correct curly pair */

/* 16.4 Definition lists — how a legal page states "term: meaning". */
dl { display: block; }
dt {
  font-size: var(--fs-sm);
  font-weight: 500;
  line-height: var(--lh-snug);
  color: var(--text);
}
dd {
  margin-inline-start: 0;
  font-size: var(--fs-sm);
  font-weight: 300;
  line-height: var(--lh-body);
  color: var(--text-2);
}
dt + dd { margin-block-start: var(--space-1); }
dd + dt { margin-block-start: var(--space-4); }

/* 16.5 The rest of the long-form set, so nothing falls back to a UA default. */
figure { display: block; }
figure > img, figure > picture { border-radius: var(--r-lg); }
figcaption {
  margin-block-start: var(--space-3);
  font-size: var(--fs-xs);
  font-weight: 300;
  line-height: 1.5;
  color: var(--text-3);
}
address { font-style: normal; }
small { font-size: var(--fs-xs); }
sup, sub { font-size: 0.7em; line-height: 0; }
mark {
  padding-inline: 0.2em;
  border-radius: var(--r-xs);
  background-color: rgba(202, 144, 37, 0.28);
  color: var(--cocoa);
}
abbr[title] {
  text-decoration: underline dotted;
  text-underline-offset: 0.2em;
  cursor: help;
}
code, kbd, samp {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.9em;
  padding: 0.12em 0.4em;
  border-radius: var(--r-xs);
  background-color: var(--surface-muted);
  color: var(--text);
  direction: ltr;
  unicode-bidi: isolate;
}
pre {
  overflow-x: auto;
  padding: var(--space-4);
  border-radius: var(--r-md);
  background-color: var(--surface-muted);
  direction: ltr;
}
pre code { padding: 0; background: none; }

/* 16.6 High contrast for the long-form set. */
html[data-a11y-contrast="on"] .table-wrap {
  border-color: var(--charcoal);
  border-width: 2px;
  box-shadow: none;
}
html[data-a11y-contrast="on"] caption { background-color: var(--white); color: var(--cocoa); }
html[data-a11y-contrast="on"] th,
html[data-a11y-contrast="on"] td { border-color: var(--charcoal); }
html[data-a11y-contrast="on"] thead th {
  background-color: var(--white);
  color: var(--cocoa);
  border-block-end-width: 2px;
}
html[data-a11y-contrast="on"] tbody tr:nth-child(even) { background-color: var(--white); }
html[data-a11y-contrast="on"] details {
  border-color: var(--charcoal);
  border-width: 2px;
  box-shadow: none;
}
html[data-a11y-contrast="on"] summary::after {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23383c3f' stroke-width='2.2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9.5l6 6 6-6'/%3E%3C/svg%3E");
}
html[data-a11y-contrast="on"] blockquote {
  border-inline-start-color: var(--charcoal);
  border-inline-start-width: 4px;
}
html[data-a11y-contrast="on"] mark,
html[data-a11y-contrast="on"] code,
html[data-a11y-contrast="on"] kbd,
html[data-a11y-contrast="on"] samp,
html[data-a11y-contrast="on"] pre {
  background-color: var(--white);
  color: var(--cocoa);
  box-shadow: inset 0 0 0 1.5px var(--charcoal);
}
