/* ═══════════════════════════════════════════════════════════════════════════
   המבריק הדרומי — עיצוב האתר
   Mobile-first, RTL, light theme committed (no dark variant by design —
   a local service business reads more trustworthy with one consistent look).
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Tokens ───────────────────────────────────────────────────────────────── */
:root {
  /* Brand: teal reads "clean water", not "medical". */
  --brand-900: #05363a;
  --brand-800: #07494f;
  --brand-700: #0a6a72;
  --brand-600: #0d8b96;
  --brand-500: #14a8b4;
  --brand-100: #d5f2f5;
  --brand-50:  #eefafb;

  /* Accessible accent — #e8890a was 2.62:1 with white text. */
  --accent-600: #9a5a00;
  --accent-500: #f5a524;
  --accent-100: #fef2dd;

  /* WhatsApp brand green is 1.98:1 with white text and cannot be used for a
     button. This is the nearest accessible green (5.39:1); the bright brand
     green survives only as a decorative icon fill on light backgrounds. */
  --wa: #0b7a4a;
  --wa-dark: #095f3a;
  --wa-bright: #25d366;

  --ink-900: #0a1b1d;
  --ink-700: #2b4448;
  --ink-500: #5b7377;
  --ink-300: #9bb0b3;

  --surface: #ffffff;
  --surface-alt: #f4fafb;
  --surface-sunk: #e8f4f6;
  /* Decorative edges only. Interactive controls use --line-strong, which
     clears 3:1 against both white and --surface-alt. */
  --line: #dbe9eb;
  --line-strong: #6b9297;

  --ok: #0b7f46;
  --warn-bg: #fff6e5;
  --warn-line: #f5d48a;
  --warn-ink: #7a4f00;

  /* ── Spacing ─────────────────────────────────────────────────────────
     A scale, so that "a bit more room" is a step rather than a new number.
     Colours, radii and shadows were already tokens; spacing was the half
     that was missing, and the half that gets hard-coded most.            */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;
  --space-7: 48px;
  --space-8: 64px;

  /* ── Status, semantically ────────────────────────────────────────────
     Every pair measured against its own background before being written
     here — the lowest is 6.5:1. Status is never carried by colour alone;
     these always accompany a word or an icon.                           */
  --ok-bg:     #e7f6ee;  --ok-ink:     #0a5c34;  --ok-line:     #b6e0c9;
  --warn-bg2:  #fff6e5;  --warn-ink2:  #7a4f00;  --warn-line2:  #f5d48a;
  --danger-bg: #fdeceb;  --danger-ink: #8c2020;  --danger-line: #f3c4c1;
  --muted-bg:  #eef2f3;  --muted-ink:  #48595c;  --muted-line:  #d6dfe1;
  --info-bg:   #eefafb;  --info-ink:   #07494f;  --info-line:   #d5f2f5;

  /* Avatar tints. White text on each clears AA; the lowest is 5.81:1, and
     a free hash into HSL would have produced the yellows that do not. */
  --av-1: #0a6a72; --av-2: #7a3e8f; --av-3: #8c2020; --av-4: #0b5c3a;
  --av-5: #8a5c00; --av-6: #1f4f8f; --av-7: #8f3a5e; --av-8: #3d5a1f;

  --radius: 14px;
  --radius-lg: 22px;
  --radius-pill: 999px;

  --shadow-sm: 0 1px 2px rgba(6, 50, 54, .06), 0 2px 8px rgba(6, 50, 54, .05);
  --shadow-md: 0 4px 12px rgba(6, 50, 54, .08), 0 12px 32px rgba(6, 50, 54, .07);
  --shadow-lg: 0 12px 28px rgba(6, 50, 54, .12), 0 28px 64px rgba(6, 50, 54, .10);

  --wrap: 1120px;
  /* ⚠️  Read by scroll-padding-top, the calculator's sticky tab strip, the
         basket sidebar's max-height and the accessibility panel. It is the
         variable that moves on scroll — never .site-header's height on its
         own, or anchors land under a header that is no longer that tall. */
  --header-h: 56px;
  /* Where the nav stops being a bar and becomes a drawer.
     ⚠️  A media query cannot read a custom property, so the two @media rules
         below still spell the number out — but assets/app.js reads THIS, and
         site/nav-check.mjs fails if the three ever disagree. The JS and the
         CSS switching at different widths is a menu that is either invisible
         or un-closable in the gap between them. */
  --nav-bp: 1000px;

  --font: 'Rubik', 'Heebo', -apple-system, 'Segoe UI', Arial, sans-serif;

  /* ── Type ────────────────────────────────────────────────────────────
     The last hard-coded half. Sizes were written inline as 13.5, 14, 15,
     15.5, 16.5, 17, 18, 19, 21 — nine sizes where six carry every screen,
     and "a bit smaller" kept inventing a tenth.

     ⚠️  --text-xs is for metadata beside a larger label, never for a
         sentence someone has to read. 12px Hebrew at arm's length on a
         phone is already at the edge.                                   */
  --text-xs: 12px;
  --text-sm: 14px;
  --text-md: 16px;
  --text-lg: 20px;
  --text-xl: 24px;
  --text-2xl: 32px;

  --leading-tight: 1.25;   /* headings, stat numbers */
  --leading-snug: 1.45;    /* labels, table cells */
  --leading-normal: 1.65;  /* prose */

  --weight-normal: 400;
  --weight-medium: 500;
  --weight-semi: 600;
  --weight-bold: 700;
  --weight-black: 800;
}

/* ── Reset ────────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; scroll-padding-top: calc(var(--header-h) + 12px); }
body {
  margin: 0;
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.65;
  color: var(--ink-900);
  background: var(--surface);
  overflow-x: hidden;
}

/* ── Selection and the long-press menu ───────────────────────────────────
 *
 *  Owner's decision: the public pages do not hand their text over to a
 *  casual copy.
 *
 *  ⚠️  THIS DOES NOT PREVENT COPYING, AND MUST NOT BE READ AS IF IT DID.
 *
 *      View-source, devtools, curl and Safari's Reader on the owner's own
 *      iPhone all walk straight past it. It raises the effort for a
 *      passer-by and nothing more. Written here so nobody later builds on
 *      it as though the text were protected.
 *
 *  ⚠️  body:not(.admin), AND THAT SCOPE IS LOAD-BEARING.
 *
 *      admin/lib/view.php:247 loads THIS stylesheet so the CRM inherits
 *      the site's tokens and its RTL. A bare `body { user-select: none }`
 *      would have reached every admin screen — no copying a customer's
 *      phone number into a dialler, no job reference into a message, no
 *      Morning receipt link into WhatsApp. The admin's body carries
 *      `class="admin"` (view.php:256) and the public one does not, so the
 *      hook was already there and needed no new markup.
 *
 *  ⚠️  AND THE EXEMPTIONS ARE NOT POLITENESS.
 *
 *      Form controls must stay selectable or the quote form stops being
 *      usable — no correcting a mistyped phone number, no editing a
 *      coupon code. The contact details are a statutory requirement on
 *      the legal pages (see legal.mjs), and a phone number a customer
 *      cannot copy is a call that does not happen, which is the opposite
 *      of what this site is for.
 */
body:not(.admin) {
  -webkit-user-select: none;
  user-select: none;
  /* Suppresses the iOS long-press callout over images and links. */
  -webkit-touch-callout: none;
}

body:not(.admin) :is(
  input, textarea, select, [contenteditable],
  .contact-list,
  [data-tel-link], [data-phone-display],
  [data-wa-link],
  [data-email-link], [data-email],
  /* The printed quote is a document the customer is meant to use. */
  #quote-doc, #quote-doc *
) {
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
}
img, svg { max-width: 100%; display: block; }
button, input, select, textarea { font: inherit; color: inherit; }
button { cursor: pointer; border: none; background: none; }
a { color: var(--brand-700); text-decoration: none; }
a:hover { text-decoration: underline; }
h1, h2, h3, h4 { line-height: 1.2; margin: 0 0 .5em; font-weight: 700; letter-spacing: -.01em; }
p { margin: 0 0 1em; }
:focus-visible { outline: 3px solid var(--brand-500); outline-offset: 2px; border-radius: 6px; }

/* ── Layout ───────────────────────────────────────────────────────────────── */
.wrap { width: min(100% - 32px, var(--wrap)); margin-inline: auto; }
section { padding: 40px 0; }
.section-head { text-align: center; max-width: 620px; margin: 0 auto 28px; }
.section-head h2 { font-size: clamp(26px, 5vw, 38px); margin-bottom: .3em; }
.section-head p { color: var(--ink-500); font-size: 17px; margin: 0; }
.eyebrow {
  display: inline-block; font-size: 13px; font-weight: 600; letter-spacing: .06em;
  color: var(--brand-800); background: var(--brand-50);
  padding: 5px 14px; border-radius: var(--radius-pill); margin-bottom: 14px;
}
.alt { background: var(--surface-alt); }

/* ── Buttons ──────────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  padding: 14px 26px; border-radius: var(--radius-pill);
  font-weight: 600; font-size: 17px; text-decoration: none;
  transition: transform .15s ease, box-shadow .15s ease, background-color .15s ease;
  white-space: nowrap;
}
.btn:hover { text-decoration: none; transform: translateY(-2px); }
.btn:active { transform: translateY(0); }
.btn svg { width: 20px; height: 20px; flex-shrink: 0; }

.btn-primary { background: var(--brand-700); color: #fff; box-shadow: var(--shadow-md); }
.btn-primary:hover { background: var(--brand-800); }
.btn-wa { background: var(--wa); color: #fff; box-shadow: var(--shadow-md); }
.btn-wa:hover { background: var(--wa-dark); }
.btn-ghost { background: #fff; color: var(--brand-800); border: 2px solid var(--line-strong); }
.btn-ghost:hover { border-color: var(--brand-500); background: var(--brand-50); }
.btn-sm { padding: 10px 18px; font-size: 15px; }
.btn-block { width: 100%; }

/* ── Header ───────────────────────────────────────────────────────────────── */
/* The sentinel app.js inserts above the header. Zero-height, so it leaves
   the page alone; the observer watching it is what flips --header-h. */
.header-sentinel { block-size: 0; }
html.is-scrolled { --header-h: 48px; }

.site-header {
  position: sticky; top: 0; z-index: 50;
  height: var(--header-h);
  transition: height .18s ease;
  background: rgba(255, 255, 255, .92);
  border-bottom: 1px solid var(--line);
}

/* ⚠️  backdrop-filter ONLY above the breakpoint, and the reason is not taste.
       A non-none backdrop-filter makes the element a containing block for
       `position: fixed` DESCENDANTS. The drawer lives inside this header —
       one nav element serving both shapes — so with the filter applied it
       resolved its `inset-block: 0` against the 63px header instead of the
       viewport and rendered as a 63px sliver pinned inside the bar.
       Above the breakpoint there is no drawer, so the frosting is free. */
@media (min-width: 1000px) { /* nav-bp: the bar */
  .site-header { backdrop-filter: saturate(160%) blur(12px); }
}
/* Opaque below it, since there is no blur to keep text off the content. */
@media (max-width: 999px) { /* nav-bp: the drawer */
  .site-header { background: #fff; }
}
.site-header .wrap { height: 100%; display: flex; align-items: center; gap: 16px; }
.logo { display: flex; align-items: center; gap: 10px; font-weight: 800; font-size: 19px; color: var(--brand-900); }
.logo:hover { text-decoration: none; }
.logo-mark {
  width: 34px; height: 34px; border-radius: 10px; flex-shrink: 0;
  background: linear-gradient(145deg, var(--brand-500), var(--brand-700));
  display: grid; place-items: center; color: #fff;
}
.logo-mark svg { width: 19px; height: 19px; }

/* ⚠️  THE MACHINE ONLY, NOT THE WHOLE LOGO — AND THE REASON WAS MEASURED.
       The full artwork is 1.26:1 and carries a machine, a water splash,
       two lines of Hebrew and a subtitle bar. Rendered at 40px it is a
       smudge; at 56px, the header's own height, still a smudge. It first
       becomes readable at about 110px, which is twice this header.
       So the header takes the mark and the name stays live text. */
.logo-mark-img { block-size: 34px; inline-size: auto; display: block; flex-shrink: 0; }

/* ── The logo, at a legible size ──────────────────────────────────────
   ⚠️  280px wide, because the artwork needs roughly 110px of HEIGHT
       before the subtitle bar can be read — measured against the real
       file rather than chosen. Capped so it never dominates the page it
       sits under. */
.brand-strip { padding-block: 26px 6px; }
.brand-logo {
  display: block; margin-inline: auto;
  inline-size: min(280px, 72vw); block-size: auto;
}
.nav { display: none; margin-inline-start: auto; }
/**
 * ⚠️  `> ul` — THE BAR'S OWN LIST, AND NOTHING ELSE INSIDE .nav.
 *
 *     This was `.nav ul`, which also matched the <ul> inside the dropdown
 *     panels — and at (0,1,1) it BEAT `.nav-topics` at (0,1,0) no matter
 *     which came later. So the guides dropdown was a horizontal flex row
 *     with 24px gaps: six labels laid side by side, 769px wide, running
 *     off the left edge of the viewport with its last item cut in half.
 *
 *     That is the whole of the reported «מדריכים overflows the screen».
 *     Clamping the panel's width and shortening its contents both made
 *     the symptom smaller and neither touched this; with the panel bounded
 *     to 360px the same row simply squeezed five titles into 69px tracks
 *     and wrapped them one letter per line, which looked worse and passed
 *     a test that only asked whether anything had left the viewport.
 */
.nav > ul { display: flex; gap: 24px; list-style: none; margin: 0; padding: 0; }
.nav > ul > li > a { color: var(--ink-700); font-weight: 500; font-size: 16px; }
.nav a:hover, .nav a[aria-current="page"] { color: var(--brand-800); text-decoration: underline; }
.header-cta { margin-inline-start: auto; gap: 7px; }
/* ⚠️  Below 1024 the bar is already logo + burger + CTA. The number is the
       first thing to go, not the CTA — somebody on a phone can tap the
       WhatsApp dock or the contact page, and the price calculator is the
       one thing this header exists to reach. */
.header-tel { display: none; }
@media (min-width: 1024px) {
  .header-tel {
    display: inline-flex; align-items: center; gap: 7px;
    margin-inline-start: 12px; padding: 8px 2px;
    font-size: 15px; font-weight: 600; color: var(--ink-900);
    font-variant-numeric: tabular-nums; white-space: nowrap;
  }
  .header-tel:hover { color: var(--brand-800); }
  .header-tel svg { inline-size: 17px; block-size: 17px; color: var(--brand-700); flex: none; }
  .header-tel ~ .header-cta { margin-inline-start: 10px; }
}

/* ⚠️  1024 IS WHERE THE BAR IS TIGHTEST, AND THE NUMBER LANDS EXACTLY THERE.
       Adding ~130px of phone number at the width the bar first appears
       pushed the labels to two lines — «צור / קשר» — and wrapped the logo
       with them, turning a 56px header into a 112px one. The number was
       asked for from 1024, so the room comes out of the spacing rather
       than out of the number.

       Nothing in the BAR may wrap: a nav label broken across two lines is
       what makes the whole bar grow, and there is no width at which that
       is right.

       ⚠️  `> ul > li >`, not `.nav a`. The dropdown panels live inside
           .nav, so the loose selector also pinned the guide titles — five
           full sentences that then could not wrap, each one wider than the
           360px panel, overflowing it to the left off the edge of the
           screen. It fit on this machine with Rubik and did not on the CI
           runner, where the Hebrew fallback is wider: the panel was
           reported at −572..−294. The links that must not wrap are the six
           one-word labels in the bar itself. */
.nav > ul > li > a, .logo, .header-cta { white-space: nowrap; }
@media (min-width: 1024px) and (max-width: 1199px) {
  .nav ul { gap: 15px; }
  .nav a { font-size: 15px; }
  .logo { font-size: 17px; gap: 8px; }
  .logo-mark { width: 30px; height: 30px; }
  .header-tel { font-size: 14px; margin-inline-start: 8px; }
  .header-cta { padding: 9px 14px; font-size: 14.5px; }
}
.header-cta svg { width: 17px; height: 17px; flex-shrink: 0; }
/* `~`, not `+`: the cart button sits between the nav and the CTA when the shop
   is on, and the old adjacent selector silently stopped matching. */
.nav ~ .header-cta { margin-inline-start: 0; }
.nav ~ .cart-btn { margin-inline-start: auto; }

@media (min-width: 1000px) { /* nav-bp: the bar */
  .nav { display: block; }
  /* `.site-header` prefix on purpose: the base `.nav-toggle { display: grid }`
     sits further down the file with equal specificity and used to win here,
     so the hamburger showed on desktop beside the full nav. */
  .site-header .nav-toggle { display: none; }
}

/* ── Hero ─────────────────────────────────────────────────────────────────── */
.hero {
  position: relative; overflow: hidden;
  background: linear-gradient(170deg, var(--brand-50) 0%, #fff 62%);
  padding: 36px 0 44px;
}
.hero::before,
.hero::after {
  content: ''; position: absolute; border-radius: 50%; pointer-events: none;
}
.hero::before {
  width: 420px; height: 420px; top: -180px; inset-inline-start: -140px;
  background: radial-gradient(circle, rgba(20, 168, 180, .16), transparent 68%);
}
.hero::after {
  width: 340px; height: 340px; bottom: -160px; inset-inline-end: -110px;
  background: radial-gradient(circle, rgba(245, 165, 36, .14), transparent 68%);
}
.hero .wrap { position: relative; z-index: 1; }
.hero h1 { font-size: clamp(31px, 7.2vw, 54px); margin-bottom: .35em; }
.hero h1 .hl { color: var(--brand-800); }
.hero-sub { font-size: clamp(16.5px, 2.4vw, 19px); color: var(--ink-700); max-width: 540px; margin-bottom: 22px; }
.hero-cta { display: flex; flex-wrap: wrap; gap: 11px; margin-bottom: 26px; }

/* ⚠️  auto-fit, not repeat(4, 1fr).
       Four fixed tracks inside the hero's 1.15fr column left every track
       about 140px, and "ניקוי ריחות וכתמי מים" does not fit in 140px — a
       1fr track will not shrink past its content, so the last item ran off
       the inline edge and the first was clipped mid-word. The row now takes
       as many columns as the text actually fits in. */
.trust {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
  gap: 10px 16px; padding: 0; margin: 0; list-style: none;
}
.trust li { display: flex; align-items: flex-start; gap: 8px; font-size: 15px; color: var(--ink-700); font-weight: 500; min-width: 0; }
.trust li span { overflow-wrap: anywhere; }
.trust svg { width: 19px; height: 19px; color: var(--ok); flex-shrink: 0; margin-top: 2px; }

@media (max-width: 560px) {
  /* Stacked CTAs look ragged when each sizes to its own label, but letting
     them span a whole phone width reads as a wall of button. Cap them. */
  .hero-cta { flex-direction: column; align-items: stretch; }
  .hero-cta .btn { width: 100%; max-width: 360px; }
  .section-head .hero-cta, .cta-band .hero-cta, .err-page .hero-cta { align-items: center; }
  /* ⚠️  The label STAYS.
         This used to hide it, leaving an icon-only circle beside the
         hamburger — two round glyphs, neither of which says what it does,
         at the exact moment a first-time visitor is deciding whether this
         site can give them a price. The icon is what gives way instead. */
  .header-cta svg { display: none; }
  .header-cta { padding: 8px 12px; font-size: 14px; }
}

@media (min-width: 760px) {
  section { padding: 64px 0; }
  .hero { padding: 68px 0 72px; }
}

/* ── Calculator ───────────────────────────────────────────────────────────── */
/* No `overflow: hidden` here, deliberately. It was clipping the gradient
   header's corners — and silently killing `position: sticky` on the category
   tabs inside, because an ancestor with a clipping overflow becomes the
   sticky element's scroll container. The header clips its own corners now. */
.calc-card {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); max-width: 760px; margin-inline: auto;
}
.calc-head {
  background: linear-gradient(140deg, var(--brand-700), var(--brand-900));
  color: #fff; padding: 22px 24px;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.calc-head h3 { margin: 0 0 4px; font-size: 21px; color: #fff; }
.calc-head p { margin: 0; font-size: 15px; opacity: .85; }
.calc-body { padding: 24px; }

/* "ממשיכים כ-אדי · לא אתה?" — the shared-device escape. Quiet, because it
   is for the rare visitor, but present, because for them it is the whole
   difference between their enquiry and somebody else's. */
.calc-whoami {
  margin: 10px 0 0; font-size: 14px; color: #fff; opacity: .9;
  display: flex; flex-wrap: wrap; gap: 4px; align-items: baseline;
}
.calc-whoami-x {
  background: none; border: 0; padding: 0; font: inherit; color: #fff;
  text-decoration: underline; cursor: pointer; min-height: 0;
}
.calc-whoami-x:hover, .calc-whoami-x:focus-visible { opacity: .8; }

/* ── מסך האישור ──────────────────────────────────────────────────────────
   מה שמחליף את ההעברה לוואטסאפ: הבקשה נשלחה לשרת, השרת אישר, וזה מה
   שהלקוח רואה.

   ⚠️  האנימציה היא קישוט. הכותרת אומרת את אותו הדבר במילים, ה-svg הוא
       aria-hidden, וההודעה נמסרת גם דרך אזור ה-live — כדי שמי שלא רואה
       אנימציות לא יפספס את התשובה.                                      */
.sent-ok { display: grid; justify-items: center; text-align: center; padding: 18px 4px 6px; }

.sent-tick { inline-size: 76px; block-size: 76px; margin-block-end: 14px; }
.sent-tick-ring {
  stroke: var(--ok-ink); stroke-width: 2.5;
  stroke-dasharray: 152; stroke-dashoffset: 152;
  animation: sent-ring .42s ease-out forwards;
}
.sent-tick-path {
  stroke: var(--ok-ink); stroke-width: 4;
  stroke-linecap: round; stroke-linejoin: round;
  stroke-dasharray: 36; stroke-dashoffset: 36;
  animation: sent-path .28s .34s ease-out forwards;
}
@keyframes sent-ring { to { stroke-dashoffset: 0; } }
@keyframes sent-path { to { stroke-dashoffset: 0; } }

/* ⚠️  Reduced motion gets the finished mark, not a shorter animation —
       the tick is information, so it has to be there either way. */
@media (prefers-reduced-motion: reduce) {
  .sent-tick-ring, .sent-tick-path { animation: none; stroke-dashoffset: 0; }
}

.sent-h { margin: 0 0 6px; font-size: 21px; }
.sent-sub { margin: 0 0 14px; font-size: 15px; color: var(--ink-700); max-width: 34ch; }
.sent-ref {
  margin: 0 0 18px; font-size: 15px; color: var(--ink-700);
  background: var(--surface-alt); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 8px 16px;
}
.sent-ref-n { font-weight: 800; color: var(--brand-800); letter-spacing: .04em; }

.sent-warn {
  inline-size: 100%; text-align: start; margin-block-end: 14px;
  background: var(--warn-bg2); border: 1px solid var(--warn-line2);
  border-inline-start: 4px solid var(--warn-ink2);
  border-radius: var(--radius); padding: 12px 14px; color: var(--warn-ink2);
}
.sent-warn strong { display: block; font-size: 15px; margin-block-end: 5px; }
.sent-warn p { margin: 0; font-size: 14px; line-height: 1.5; }
.sent-warn-ack { margin-block-start: 8px !important; font-weight: 600; }

.sent-photo { margin-block-start: 4px; }
.sent-note { margin: 8px 0 0; font-size: 13.5px; color: var(--ink-500); }

/* A send that did not go through. The customer cannot see a retry queue. */
.send-failed {
  background: var(--danger-bg); border: 1px solid var(--danger-line);
  border-radius: var(--radius); padding: 12px 14px; margin-block-end: 12px;
  color: var(--danger-ink);
}
.send-failed strong { display: block; font-size: 15px; margin-block-end: 4px; }
.send-failed p { margin: 0 0 10px; font-size: 14px; line-height: 1.5; }

/* ── שער הלכידה ──────────────────────────────────────────────────────────
   assets/config.js → quote.gate_mode. calculator.js puts `.gate-up` on
   <html> while the gate is standing.

   ⚠️  The hiding rules are on the ROOT, not on .calc-layout, because
       .calc-bar lives outside that wrapper — it is fixed to the viewport.
       One ancestor that contains everything, one rule block.

   ⚠️  `.gate-up .calc-bar` and not `[hidden]`. .calc-bar sets display:flex,
       which beats the [hidden] attribute — a collision this stylesheet has
       now been bitten by four times. Class-on-class wins on specificity
       without an !important.                                            */
.gate-up .calc-tabs,
.gate-up .calc-body,
.gate-up .calc-side,
.gate-up .calc-bar { display: none; }

/* ⚠️  And the column it left behind goes with it.
       .calc-side was hidden but .calc-layout kept its two tracks, so at
       1280 the gate sat in a 756px column with 340px of nothing beside it —
       a form pushed off-centre next to an empty half-screen, waiting for a
       basket that cannot exist until the form is answered. One column, and
       the card is the width of the card. */
.gate-up .calc-layout { display: block; }
.gate-up .calc-layout > .calc-card { max-inline-size: 720px; margin-inline: auto; }

.calc-gate { padding: 24px; }
.gate-head { margin-bottom: 18px; }
.gate-head h2 { margin: 0 0 6px; font-size: 20px; }
.gate-sub { margin: 0; font-size: 15px; color: var(--ink-500); max-width: 52ch; }

/* Same two-column behaviour as the quote form, at the same breakpoint, so
   the two screens do not disagree about where a field belongs. */
@media (min-width: 560px) {
  /* ⚠️  align-items: start, or the fields are different heights.
         Grid items stretch by default. The phone cell is taller than the
         name cell because it carries a .field-hint under the input, so the
         name input was stretched to 71px against the phone's 50px — two
         boxes of different heights whose tops did not line up either.
         Reported twice. Each field is now its own height, and the inputs
         share a row start. */
  .gate-form { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; align-items: start; }
  .gate-head, .gate-foot, .lead-field-wide { grid-column: 1 / -1; }
}

/* ⚠️  Four steps, and no longer gate-only.
       It was built inside renderGate() and died with it, so the one screen
       that showed progress was the first — see journeySteps() in
       calculator.js. The class name stays because the styling is the
       same and renaming it would touch nothing that matters. */
.gate-steps {
  display: flex; flex-wrap: wrap; gap: 6px 14px;
  margin: 12px 0 0; padding: 0; list-style: none;
  font-size: 13.5px; color: var(--ink-500);
}
.gate-steps li { display: flex; align-items: center; gap: 6px; }
.gate-step-n,
.gate-step-i {
  display: grid; place-items: center;
  inline-size: 20px; block-size: 20px; border-radius: 50%;
  background: var(--surface-sunk); color: var(--ink-500);
  font-size: 12px; font-weight: 700;
}
.gate-step-i { padding: 3px; stroke: currentColor; fill: none; }
.gate-steps .is-now { color: var(--brand-800); font-weight: 600; }
.gate-steps .is-now .gate-step-n,
.gate-steps .is-now .gate-step-i { background: var(--brand-700); color: #fff; }
.gate-steps .is-done .gate-step-i { background: var(--brand-100, #d6f0f3); color: var(--brand-800); }

/* ── «מה מנקים?» — the screen between the gate and the prices ─────────────
   Big targets, one decision each. A checkbox inside a tile would be two
   hit areas for one choice; these are toggle buttons that say their own
   state. See renderFocus() in assets/calculator.js.
   ───────────────────────────────────────────────────────────────────── */
.calc-focus { padding: 26px 20px 24px; }
.calc-focus[hidden] { display: none; }
.focus-head h2 { margin: 0; font-size: clamp(20px, 3.4vw, 26px); }
.focus-sub { margin: 6px 0 0; color: var(--ink-500); font-size: 15px; }

/* ⚠️  170, not 150. At 150 the card fits four columns, so five tiles are
       4 + 1 and the fifth sits alone beside an empty three-quarters of a
       row — the same half-empty row that was reported on the catalogue.
       Three columns makes five into 3 + 2. */
.focus-grid {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr));
  gap: 10px; margin-block-start: 20px;
}
.focus-tile {
  display: grid; justify-items: center; gap: 2px; text-align: center;
  padding: 18px 12px; min-block-size: 124px;
  border: 1.5px solid var(--line-strong); border-radius: var(--radius-lg);
  background: #fff; cursor: pointer; color: var(--ink-900);
  transition: border-color .15s ease, background .15s ease;
}
.focus-tile:hover { border-color: var(--brand-500); background: var(--brand-50); }
.focus-tile-art { inline-size: 44px; block-size: 44px; color: var(--brand-700); margin-block-end: 4px; }
.focus-tile-name { font-size: 16.5px; font-weight: 700; }
.focus-tile-hint { font-size: 13px; color: var(--ink-500); }
/* ⚠️  A tick as well as the colour. Colour alone is not a state somebody
       with low vision or a monochrome screen can read. */
.focus-tile[aria-pressed="true"] {
  border-color: var(--brand-700); background: var(--brand-50);
  box-shadow: inset 0 0 0 1px var(--brand-700);
}
.focus-tile[aria-pressed="true"] .focus-tile-name::after {
  content: ' ✓'; color: var(--ok);
}
.focus-tile[aria-pressed="true"] .focus-tile-art { color: var(--brand-900); }

.focus-foot { display: flex; flex-wrap: wrap; gap: 10px; margin-block-start: 20px; align-items: center; }
.focus-go { flex: 1 1 14rem; }
.focus-go[aria-disabled="true"] { opacity: .55; }
/* ⚠️  A disabled button says why, beside itself — the rule this project
       already applies to the gate's CTA. Grey and silent is the version
       somebody stares at. */
.focus-need { flex: 1 1 100%; margin: 0; font-size: 14px; color: var(--ink-500); }

/* While it is up, the catalogue behind it is not — one question at a time. */
.focus-up .calc-tabs,
.focus-up .calc-body,
.focus-up .calc-side,
.focus-up .calc-bar { display: none; }
.focus-up .calc-layout { display: block; }
.focus-up .calc-layout > .calc-card { max-inline-size: 720px; margin-inline: auto; }

.tab-all { font-weight: 700; }

/* ── The minimum meter ────────────────────────────────────────────────────
   ⚠️  It does not disappear when the minimum is met. A message that only
       shows while something is wrong reads as a telling-off, and it goes
       away at the exact moment the customer wants to be told they are past
       it. See minimumMeter() in assets/calculator.js.
   ───────────────────────────────────────────────────────────────────── */
.cart-min { margin-block-start: 12px; }
.cart-min-bar {
  block-size: 6px; border-radius: 99px; overflow: hidden;
  background: var(--surface-sunk, #eef2f1);
}
.cart-min-fill {
  display: block; block-size: 100%; inline-size: 0;
  background: var(--brand-500); border-radius: 99px;
  transition: inline-size .25s ease;
}
@media (prefers-reduced-motion: reduce) { .cart-min-fill { transition: none; } }
.cart-min.is-met .cart-min-fill { background: var(--ok); }
.cart-min-t {
  margin: 7px 0 0; font-size: 13.5px; line-height: 1.55; color: var(--ink-500);
  display: flex; align-items: flex-start; gap: 6px;
}
.cart-min.is-met .cart-min-t { color: var(--ok-ink); font-weight: 600; }
.cart-min.is-met .icon { color: var(--ok); margin-block-start: .18em; }

/**
 * «ההזמנה היא עבור» — the same tile as «מה מנקים», one size down.
 *
 * ⚠️  THREE COLUMNS, FOR THE REASON .focus-grid IS 170px: five tiles in
 *     four columns is 4 + 1, and the fifth sits alone beside an empty
 *     three-quarters of a row. 3 + 2 is the shape that reads as a set.
 *     This grid is inside a form, not a full screen, so the floor is
 *     lower and the tiles are shorter than the focus step's.
 */
.seg-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
/**
 * ⚠️  THE FIFTH TILE, WHICH OTHERWISE SITS ALONE.
 *
 *     Five into two columns is 2 + 2 + 1, and the one is «אירוח» stranded
 *     beside an empty half-row — the same stranded tile .focus-grid's own
 *     comment was written about. It spans the row instead.
 *
 *     `:nth-child(odd):last-child`, not `:last-child`: the span is only
 *     right for an ODD number of tiles. A sixth segment would make the
 *     last one even, and it must then take its normal half-row rather
 *     than stretch across a row that is already full.
 */
.seg-grid > :nth-child(odd):last-child { grid-column: 1 / -1; }
/* Wide enough for three: five becomes 3 + 2 and nothing is stranded. */
@media (min-width: 34rem) {
  .seg-grid { grid-template-columns: repeat(3, 1fr); }
  .seg-grid > :nth-child(odd):last-child { grid-column: auto; }
}
.seg-tile { padding: 14px 10px; min-block-size: 104px; }
.seg-tile .focus-tile-art { inline-size: 32px; block-size: 32px; margin-block-end: 2px; }
.seg-tile .focus-tile-name { font-size: 15.5px; }
.seg-tile .focus-tile-hint { font-size: 12.5px; line-height: 1.35; }

.gate-seg .opt-chips { gap: 8px; }
.gate-seg .opt-chip-2 { flex: 1 1 8.5rem; }

/* Checkbox and label on one line, the box pinned to the first line of text
   rather than floating in the middle of a label that wraps to three. */
.gate-check {
  display: flex; align-items: start; gap: 10px;
  margin-block: 2px 12px;
}
.gate-check input {
  inline-size: 20px; block-size: 20px; margin: 1px 0 0; flex: none;
  accent-color: var(--brand-700);
}
.gate-check > label { font-size: 14.5px; font-weight: 400; color: var(--ink-700); line-height: 1.5; }
.gate-check a { text-decoration: underline; }

.gate-foot { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; margin-top: 6px; }
.gate-go { flex: 1 1 14rem; }
.gate-go[aria-disabled='true'] { opacity: .55; }
/* ── The biological-stain notice ─────────────────────────────────────────
   ⚠️  It has to LOOK like a warning, not like more form copy.

       Shipped unstyled: the heading and four lines of body text flowed in
       with the questions around them, so the one notice on the page that
       a customer must read and tick a box for read as small print. A
       warning nobody notices is a warning that does not exist, and this
       one is the basis for a conversation on the doorstep about a stain
       that did not fully come out.

   ⚠️  The colour is not the signal — the heading says «כתם ביולוגי» and
       the box is bordered. Colour alone never carries a state here.      */
.stain-note {
  margin-block-start: 10px;
  padding: 12px 14px;
  background: var(--warn-bg2);
  border: 1px solid var(--warn-line2);
  border-inline-start: 4px solid var(--warn-ink2);
  border-radius: var(--radius);
  color: var(--warn-ink2);
}
.stain-note > strong { display: block; font-size: 15.5px; margin-block-end: 6px; }
.stain-note > p { margin: 0; font-size: 14px; line-height: 1.55; }

/* The acknowledgement sits inside the notice, separated from the text it
   is about — it is a different act from reading. */
.stain-note .stain-ack {
  margin-block: 12px 0;
  padding-block-start: 10px;
  border-block-start: 1px solid var(--warn-line2);
}
.stain-note .stain-ack > label { color: var(--warn-ink2); font-weight: 600; }
.stain-note .stain-ack input { accent-color: var(--warn-ink2); }

/* A segment we do not publish a price for. Words where the number was. */
.calc-on-request {
  background: var(--info-bg); border: 1px solid var(--info-line);
  border-radius: var(--radius); padding: 12px 14px; color: var(--info-ink);
}
.calc-on-request strong { display: block; font-size: 16px; margin-block-end: 4px; }
.calc-on-request p { margin: 0; font-size: 14px; line-height: 1.5; }

.gate-err {
  flex: 1 1 100%; margin: 0; font-size: 14px; font-weight: 600; color: var(--danger-ink);
}

/* ⚠️  What is still missing, beside the button, before it is pressed.
       The CTA was aria-disabled with nothing next to it, and the reason
       only appeared after a click that could never work. Quieter than
       .gate-err on purpose: nothing has gone wrong yet, the form is simply
       not finished. */
.gate-need {
  flex: 1 1 100%; margin: 0; font-size: 14px; font-weight: 500; color: var(--ink-500);
}

.field { margin-bottom: 22px; }
.field > label,
.field-label { display: block; font-weight: 600; font-size: 16px; margin-bottom: 10px; }
.field-hint { font-size: 14px; color: var(--ink-500); font-weight: 400; margin-inline-start: 6px; }

/* ── the discount code's answer ──────────────────────────────────────────
   ⚠️  THREE STATES, NOT TWO. Green when something actually came off, red
       when the code is dead, and the ordinary grey hint for a code that is
       perfectly valid and simply lost to a bigger discount — that last one
       is not a failure and must not be painted as one, and it is not a
       success either.
   ⚠️  And never colour alone: the sentence says which it is, because
       «הקוד כבר נוצל» and «ההנחה שכבר יש לך גדולה יותר» are different
       instructions and red tells neither of them apart. */
/* ── the coupon row ──────────────────────────────────────────────────────
   ⚠️  The input and «החל» on one line, and the input takes whatever is
       left. A button that wraps under the field on a narrow phone reads
       as belonging to the next field, which is the opposite of the
       problem it was added to solve. */
.coupon-row { display: flex; gap: 8px; align-items: stretch; }
.coupon-row > input { flex: 1 1 auto; min-width: 0; }

/* Styled off .btn-ghost rather than from scratch, so it inherits the
   site's border, radius and brand colours instead of growing a private
   palette that drifts from them. */
.coupon-apply {
  flex: 0 0 auto;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 10px 18px; font: inherit; font-weight: 600; font-size: 15px;
  border-radius: var(--radius-pill);
  background: #fff; color: var(--brand-800);
  border: 2px solid var(--line-strong);
  cursor: pointer; white-space: nowrap;
  /* ⚠️  44px is the tap target this site holds itself to, and this control
         is reached with a thumb while the keyboard is open. */
  min-height: 44px;
  transition: border-color .15s ease, background-color .15s ease;
}
.coupon-apply:hover:not(:disabled) { border-color: var(--brand-500); background: var(--brand-50); }
/* Busy is shown by the control going quiet, not by the label changing — a
   button that changes width mid-tap moves under the thumb still on it. */
.coupon-apply:disabled { opacity: .55; cursor: default; }

.field-hint.coupon-ok { color: var(--ok-ink); font-weight: 600; }
.field-hint.coupon-no { color: var(--danger-ink); }
.coupon-amt { font-weight: 700; }

.chips { display: flex; flex-wrap: wrap; gap: 9px; }
.chip {
  padding: 10px 17px; border-radius: var(--radius-pill);
  border: 2px solid var(--line-strong); background: #fff;
  font-size: 15.5px; font-weight: 500; color: var(--ink-700);
  transition: all .14s ease;
}
.chip:hover { border-color: var(--brand-500); color: var(--brand-700); }
.chip[aria-pressed="true"],
.chip.is-on {
  background: var(--brand-700); border-color: var(--brand-700); color: #fff;
}

.num-row { display: flex; align-items: center; gap: 12px; }
.stepper { display: flex; align-items: center; gap: 4px; border: 2px solid var(--line-strong); border-radius: var(--radius-pill); padding: 3px; }
.stepper button {
  width: 36px; height: 36px; border-radius: 50%; font-size: 21px; line-height: 1;
  color: var(--brand-800); background: var(--brand-50); font-weight: 600;
}
.stepper button:hover { background: var(--brand-100); }
.stepper button:disabled { opacity: .35; cursor: not-allowed; }
.stepper output { min-width: 42px; text-align: center; font-weight: 700; font-size: 18px; }

/* Every text-like input, not just the three the site happened to use first.
   A `tel` or `password` field left off this list renders as a bare browser
   default next to styled siblings — which is what the admin login did. */
input[type="number"], input[type="text"], input[type="email"], input[type="tel"],
input[type="password"], input[type="search"], input[type="date"], input[type="url"],
textarea, select {
  width: 100%; padding: 12px 15px; border: 2px solid var(--line-strong);
  border-radius: var(--radius); background: #fff; font-size: 16px;
}
input:focus, select:focus { border-color: var(--brand-500); outline: none; }
.input-narrow { max-width: 170px; }

.calc-total {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 18px 20px; background: var(--brand-50);
  border: 2px solid var(--brand-100); border-radius: var(--radius); margin-bottom: 16px;
}
.calc-total .lbl { font-weight: 600; font-size: 17px; }
.calc-total .amt { font-weight: 800; font-size: 30px; color: var(--brand-800); }
.calc-total .amt small { font-size: 18px; font-weight: 600; }

.notice {
  padding: 15px 17px; border-radius: var(--radius); font-size: 15.5px;
  border: 1px solid; margin-bottom: 16px;
}
.notice-warn { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn-ink); }
.notice-info { background: var(--brand-50); border-color: var(--brand-100); color: var(--brand-800); }
.notice strong { display: block; margin-bottom: 3px; }

.calc-notes { list-style: none; padding: 0; margin: 16px 0 0; }
.calc-notes li {
  display: flex; gap: 8px; font-size: 14.5px; color: var(--ink-500);
  margin-bottom: 7px; line-height: 1.5;
}
.calc-notes svg { width: 17px; height: 17px; color: var(--brand-700); flex-shrink: 0; margin-top: 3px; }


/* ── Service cards ────────────────────────────────────────────────────────── */
.grid { display: grid; gap: 16px; grid-template-columns: 1fr; }
@media (min-width: 620px) { .grid-2 { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 900px) {
  .grid-3 { grid-template-columns: repeat(3, 1fr); }
  .grid-4 { grid-template-columns: repeat(4, 1fr); }
}

.card {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-lg);
  padding: 22px; box-shadow: var(--shadow-sm);
  transition: transform .18s ease, box-shadow .18s ease;
}
.card:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--brand-100); }
.card h3 { font-size: 19px; margin-bottom: 8px; }
.card p { color: var(--ink-500); font-size: 15.5px; margin: 0; }
.card-icon {
  width: 46px; height: 46px; border-radius: 13px; margin-bottom: 14px;
  background: var(--brand-50); color: var(--brand-800);
  display: grid; place-items: center;
}
.card-icon svg { width: 24px; height: 24px; }
.card-price {
  display: block; margin-top: 14px; padding-top: 14px;
  border-top: 1px dashed var(--line);
  font-size: 22px; font-weight: 800; color: var(--brand-800);
}
.card-price small { font-size: 14px; font-weight: 500; color: var(--ink-500); }

/* ── Steps ────────────────────────────────────────────────────────────────── */
.steps { counter-reset: step; display: grid; gap: 20px; grid-template-columns: 1fr; }
@media (min-width: 760px) { .steps { grid-template-columns: repeat(3, 1fr); } }
.step { position: relative; padding-top: 8px; }
.step-num {
  counter-increment: step; width: 46px; height: 46px; border-radius: 50%;
  background: var(--brand-700); color: #fff; display: grid; place-items: center;
  font-weight: 800; font-size: 20px; margin-bottom: 14px;
}
.step-num::before { content: counter(step); }
.step h3 { font-size: 19px; margin-bottom: 6px; }
.step p { color: var(--ink-500); font-size: 15.5px; margin: 0; }

/* ── Areas ────────────────────────────────────────────────────────────────── */
.areas { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.area-chip {
  padding: 9px 18px; border-radius: var(--radius-pill);
  background: #fff; border: 1px solid var(--line);
  font-weight: 500; font-size: 15.5px; color: var(--ink-700);
}

/* ── FAQ ──────────────────────────────────────────────────────────────────── */
.faq { max-width: 760px; margin-inline: auto; }
.faq details {
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius);
  margin-bottom: 10px; overflow: hidden;
}
.faq details[open] { border-color: var(--brand-100); box-shadow: var(--shadow-sm); }
.faq summary {
  padding: 17px 20px; font-weight: 600; font-size: 16.5px; cursor: pointer;
  list-style: none; display: flex; align-items: center; justify-content: space-between; gap: 12px;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: '+'; font-size: 24px; font-weight: 400; color: var(--brand-800);
  line-height: 1; flex-shrink: 0; transition: transform .2s ease;
}
.faq details[open] summary::after { transform: rotate(45deg); }
.faq .faq-body { padding: 0 20px 18px; color: var(--ink-700); font-size: 16px; }
.faq .faq-body p:last-child { margin: 0; }

/* ── CTA band ─────────────────────────────────────────────────────────────── */
.cta-band {
  background: linear-gradient(140deg, var(--brand-800), var(--brand-900));
  color: #fff; text-align: center; border-radius: var(--radius-lg);
  padding: 44px 24px; box-shadow: var(--shadow-lg);
}
.cta-band h2 { color: #fff; font-size: clamp(24px, 4.6vw, 34px); }
.cta-band p { color: rgba(255, 255, 255, .8); max-width: 480px; margin-inline: auto; margin-bottom: 24px; }
.cta-band .hero-cta { justify-content: center; margin-bottom: 0; }

/* ── Footer ───────────────────────────────────────────────────────────────── */
.site-footer { background: var(--brand-900); color: rgba(255, 255, 255, .72); padding: 44px 0 90px; font-size: 15.5px; }
.site-footer a { color: #fff; }
.site-footer h4 { color: #fff; font-size: 16px; margin-bottom: 12px; }
.footer-grid { display: grid; gap: 30px; grid-template-columns: 1fr; }
@media (min-width: 760px) { .footer-grid { grid-template-columns: 1.4fr 1fr 1fr; } }
.footer-grid ul { list-style: none; padding: 0; margin: 0; }
.footer-grid li { margin-bottom: 7px; }
.hours-row { display: flex; justify-content: space-between; gap: 14px; max-width: 250px; }
/* Scoped to the footer. Unscoped, this painted the time white on the white
   /contact/ card too — the values were there in the DOM and invisible on the
   page, which is why nobody reported it. */
.site-footer .hours-row .v { color: #fff; font-weight: 500; }
.site-footer .hours-kind { color: #cfeef1; opacity: 1; }
.footer-bottom {
  margin-top: 32px; padding-top: 20px; border-top: 1px solid rgba(255, 255, 255, .12);
  font-size: 14px; display: flex; flex-wrap: wrap; gap: 8px; justify-content: space-between;
}
.site-footer .logo { color: #fff; margin-bottom: 12px; }

@media (min-width: 760px) { .site-footer { padding-bottom: 44px; } }

/* ── Floating WhatsApp ────────────────────────────────────────────────────── */
/* ── The floating dock ──────────────────────────────────────────────────────
   One pill, two segments, one tap to either. overflow:hidden plus a pill
   radius is what joins them; when chat.js has not revealed the chat segment
   the dock is a lone 58px square, and a pill radius on a square is the same
   circle that used to be there. */
.fab-dock {
  position: fixed; inset-inline-end: 16px; bottom: 16px; z-index: 60;
  display: inline-flex; align-items: stretch;
  border-radius: var(--radius-pill); overflow: hidden;
  box-shadow: 0 6px 20px rgba(11, 122, 74, .38);
}
.fab-chat {
  display: none; align-items: center; gap: 9px;
  padding: 0 20px; border: 0; cursor: pointer;
  background: var(--brand-700); color: #fff;
  font-weight: 600; font-size: 15.5px; font-family: inherit;
  transition: filter .18s ease;
}
.fab-chat.is-available { display: inline-flex; }
.fab-chat svg { width: 21px; height: 21px; }
.fab-wa {
  flex: none; width: 58px; height: 58px;
  display: grid; place-items: center;
  background: var(--wa); color: #fff;
  transition: filter .18s ease;
}
.fab-wa svg { width: 30px; height: 30px; }
.fab-dock a:hover, .fab-dock button:hover { filter: brightness(1.12); text-decoration: none; }
/* Inset, and white: the outline sits inside overflow:hidden, and white is
   the only colour legible on both the teal and the green segment. */
.fab-dock :focus-visible { outline: 3px solid #fff; outline-offset: -4px; }

/* ── Chat widget ──────────────────────────────────────────────────────────── */

/*
 * The panel used to be sized with `min(calc(100vh - 32px), 580px)`, and on a
 * phone 100vh is the viewport height WITH THE ADDRESS BAR HIDDEN — taller
 * than what you can actually see. The result was a long empty gap and an
 * input field pushed below the fold, shifting every time the browser showed
 * or hid its chrome.
 *
 * dvh is the height that tracks the visible area, so the panel follows the
 * address bar and the keyboard instead of ignoring them. The vh line stays
 * first as the fallback for browsers without dvh — the same two-line pattern
 * .sheet already uses.
 */
.chat-panel {
  position: fixed; inset-inline-end: 16px; bottom: 16px; z-index: 70;
  width: min(calc(100vw - 32px), 390px);
  height: min(calc(100vh - 32px), 580px);
  height: min(calc(100dvh - 32px), 580px);
  background: #fff; border-radius: var(--radius-lg); box-shadow: var(--shadow-lg);
  display: none; flex-direction: column; overflow: hidden;
  border: 1px solid var(--line);
}
.chat-panel.is-open { display: flex; }

/*
 * On a phone it takes the whole screen, like every other chat widget. That
 * is not only more room: a floating card inset from all four edges of a
 * 375px viewport spends most of its height on the gap, and every mobile
 * viewport quirk lands on the inset rather than on the content.
 *
 * chat.js locks the page scroll at this same breakpoint.
 */
@media (max-width: 559px) {
  .chat-panel {
    inset: 0; width: 100%;
    height: 100vh; height: 100dvh;
    border-radius: 0; border: none;
    max-height: none;
  }
  .chat-header { padding-top: calc(14px + env(safe-area-inset-top)); }
  .chat-form { padding-bottom: calc(12px + env(safe-area-inset-bottom)); }
}
.chat-header {
  background: linear-gradient(140deg, var(--brand-700), var(--brand-900));
  color: #fff; padding: 14px 16px; display: flex; align-items: center; gap: 11px;
}
.chat-header .avatar {
  width: 38px; height: 38px; border-radius: 50%; background: rgba(255, 255, 255, .18);
  display: grid; place-items: center; font-weight: 700; flex-shrink: 0;
}
.chat-header .meta { flex: 1; min-width: 0; }
.chat-header .nm { font-weight: 700; font-size: 15.5px; }
.chat-header .st { font-size: 12.5px; opacity: .8; display: flex; align-items: center; gap: 5px; }
.chat-header .st::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%; background: #4ade80;
}
.chat-close { color: #fff; width: 32px; height: 32px; border-radius: 50%; font-size: 22px; line-height: 1; opacity: .8; }
.chat-close:hover { background: rgba(255, 255, 255, .15); opacity: 1; }

/* overscroll-behavior stops a scroll that reaches the end of the log from
   continuing into the page underneath — the other half of "it all jumps". */
.chat-log {
  flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain;
  padding: 16px; background: var(--surface-alt); -webkit-overflow-scrolling: touch;
  /* Messages sit at the bottom, as in every messaging app. Full-screen on a
     phone, a short conversation pinned to the top left most of the panel
     empty and made it read as broken. */
  display: flex; flex-direction: column; align-items: flex-start;
}
/* `margin-top: auto` on the first bubble pushes the stack down when there is
   spare room, and collapses harmlessly once the log overflows — unlike
   justify-content: flex-end, which clips the oldest messages out of reach. */
.chat-log > :first-child { margin-top: auto; }
.msg { max-width: 82%; padding: 11px 15px; border-radius: 16px; margin-bottom: 10px; font-size: 15.5px; line-height: 1.55; white-space: pre-wrap; word-wrap: break-word; }
.msg-bot { background: #fff; border: 1px solid var(--line); border-start-start-radius: 4px; }
.msg-user { background: var(--brand-700); color: #fff; align-self: flex-end; border-end-end-radius: 4px; }
.msg-err { background: var(--warn-bg); border: 1px solid var(--warn-line); color: var(--warn-ink); max-width: 100%; align-self: stretch; }
.typing { display: inline-flex; gap: 4px; padding: 14px 16px; }
.typing i { width: 7px; height: 7px; border-radius: 50%; background: var(--ink-300); animation: blink 1.3s infinite; }
.typing i:nth-child(2) { animation-delay: .18s; }
.typing i:nth-child(3) { animation-delay: .36s; }
@keyframes blink { 0%, 60%, 100% { opacity: .25; } 30% { opacity: 1; } }

.chat-form { display: flex; gap: 8px; padding: 12px; border-top: 1px solid var(--line); background: #fff; }
.chat-form input { flex: 1; border-radius: var(--radius-pill); padding: 11px 17px; }
.chat-form button {
  width: 44px; height: 44px; border-radius: 50%; background: var(--brand-700); color: #fff;
  display: grid; place-items: center; flex-shrink: 0;
}
.chat-form button:hover { background: var(--brand-700); }
.chat-form button:disabled { opacity: .45; cursor: not-allowed; }
.chat-form svg { width: 19px; height: 19px; }

/* ── שער הצ'אט ───────────────────────────────────────────────────────
   ⚠️  display:flex BEATS [hidden] — the third time this stylesheet has
       met that collision, after .calc-bar and .calc-print. The gate and
       the conversation swap places by the attribute, so without this
       both would be on screen at once. */
.chat-gate { display: flex; flex-direction: column; gap: 8px; padding: 14px; overflow-y: auto; }
.chat-gate[hidden], .chat-log[hidden], .chat-form[hidden] { display: none; }

.chat-gate-t { margin: 0 0 2px; font-size: 0.9rem; color: var(--ink-700); }
.chat-gate label[for] { font-size: 0.8rem; font-weight: 600; margin-block-end: -4px; }
.chat-gate input[type="text"], .chat-gate input[type="tel"] {
  border-radius: var(--radius-pill); padding: 10px 15px; font: inherit;
  border: 1px solid var(--line);
}

/* ⚠️  44px of tappable label, not a 13px box. A consent people mis-tap
       is a consent nobody can rely on having been given. */
.chat-gate-chk {
  display: flex; align-items: flex-start; gap: 9px;
  font-size: 0.82rem; line-height: 1.45; min-block-size: 44px;
  padding-block: 4px; cursor: pointer;
}
.chat-gate-chk input { inline-size: 20px; block-size: 20px; flex: none; margin-block-start: 2px; }

.chat-gate-err { margin: 0; font-size: 0.82rem; font-weight: 600; color: var(--danger-ink); }
.chat-gate-err[hidden] { display: none; }

.chat-gate button {
  min-block-size: 44px; border-radius: var(--radius-pill);
  background: var(--brand-700); color: #fff; font: inherit; font-weight: 600;
  border: 0; cursor: pointer;
}

/* ⚠️  Quieter than the button on purpose. It is a real route for a real
       complaint, not a second call to action competing with the one the
       visitor came for. */
.chat-gate-complaint {
  margin: 2px 0 0; font-size: 0.78rem; line-height: 1.5; color: var(--ink-500);
  border-top: 1px solid var(--line); padding-top: 10px;
}
.chat-gate-complaint a { font-weight: 600; }

/* ── 404 ──────────────────────────────────────────────────────────────────── */
.err-page { min-height: 72vh; display: grid; place-items: center; text-align: center; padding: 40px 0; }
.err-code { font-size: clamp(76px, 17vw, 140px); font-weight: 800; color: var(--brand-100); line-height: 1; margin-bottom: 8px; }

/* ── Utilities ────────────────────────────────────────────────────────────── */
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;
}
.hidden { display: none !important; }
.text-center { text-align: center; }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: .01ms !important; transition-duration: .01ms !important; }
  html { scroll-behavior: auto; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   Components added with the multi-page build
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Skip link — first stop for a keyboard user ───────────────────────────── */
.skip-link {
  /* fixed, not absolute: a keyboard user who tabs here after scrolling must
     still see it, without relying on the browser scrolling it into view. */
  position: fixed; top: 0; inset-inline-start: 50%; transform: translate(50%, -120%);
  z-index: 200; background: var(--brand-800); color: #fff;
  padding: 12px 22px; border-radius: 0 0 var(--radius) var(--radius);
  font-weight: 600; transition: transform .16s ease;
}
.skip-link:focus { transform: translate(50%, 0); text-decoration: none; }

/* ── Mobile nav ───────────────────────────────────────────────────────────── */
.nav-toggle {
  margin-inline-start: auto; width: 44px; height: 44px; border-radius: 12px;
  display: grid; place-items: center; border: 2px solid var(--line-strong); background: #fff;
}
.nav-toggle-bars { display: grid; gap: 4px; }
.nav-toggle-bars span { display: block; width: 19px; height: 2px; background: var(--ink-900); border-radius: 2px; }

@media (max-width: 460px) {
  /* Keep the brand on one line so the header stays at its fixed height. */
  .logo { font-size: 16.5px; white-space: nowrap; }
  .logo-mark { width: 30px; height: 30px; border-radius: 9px; }
  .logo-mark svg { width: 17px; height: 17px; }
  .header-cta { padding: 9px 13px; font-size: 14.5px; }
  .nav-toggle { width: 40px; height: 40px; }
  .site-header .wrap { gap: 12px; }
}

@media (max-width: 999px) { /* nav-bp: the drawer */
  .header-cta { margin-inline-start: 10px; }
  /* Below the breakpoint the bar is display:none, so it can't be the flex
     spacer. Push the whole action group to the end off the toggle instead. */
  .nav-toggle { margin-inline-start: auto; }
  .nav ~ .cart-btn { margin-inline-start: 0; }
}

/* ── Desktop menus ──────────────────────────────────────────────────────────
   Services and guides open a panel on wide screens. The label is a real
   link and the caret beside it is the only thing that opens the panel, so
   with JavaScript off the header is exactly the bar it has always been and
   nothing is unreachable — /services/ and /guides/ both list everything the
   panel shows. */
.nav li.has-menu { position: relative; display: flex; align-items: center; gap: 2px; }
.nav-caret {
  display: none; align-items: center; justify-content: center;
  inline-size: 24px; block-size: 24px; padding: 0;
  border: 0; background: none; color: var(--ink-500); cursor: pointer;
  border-radius: 6px;
}
.nav-caret svg { inline-size: 15px; block-size: 15px; transition: transform .18s ease; }
.nav-caret[aria-expanded="true"] svg { transform: rotate(180deg); }
.nav-caret:hover, .nav-caret:focus-visible { color: var(--brand-700); background: var(--brand-50); }

/* ⚠️  THE CLAMP IS THE FIX, NOT THE ANCHOR.
       The panel hangs from the trigger's inline-start edge and grows
       toward the page — which in RTL means leftward — and that is right
       for both triggers. What it had no answer for was WIDTH: the guides
       panel listed six categories with no max, grew as wide as its
       longest label, and ran off the left edge of the viewport with its
       last row cut in half.

       Flipping the anchor was the obvious fix and it is wrong: it sends
       the 760px services panel off the RIGHT edge instead. A bound on
       how wide the thing may get is what keeps both on screen. */
.nav-menu {
  position: absolute; inset-block-start: calc(100% + 10px); inset-inline-start: 0;
  max-inline-size: min(360px, calc(100vw - 32px));
  z-index: 55;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-lg);
  box-shadow: 0 14px 44px rgba(10, 27, 29, .14);
  /* 320, not 260: the guides panel lists five real titles now, and at
     260 every one of them wrapped to two lines. The max above still caps
     it, so the two bounds meet in a band rather than fighting. */
  padding: 14px; min-inline-size: 320px;
  animation: nav-menu-in .16s ease both;
}
/* ⚠️  Fifth time: a display rule beats [hidden]. */
.nav-menu[hidden] { display: none; }
.nav-menu-wide { inline-size: min(760px, calc(100vw - 48px)); max-inline-size: calc(100vw - 32px); }
/* ⚠️  Five items in two fixed tracks is 2-2-1: a lopsided block with a
       half-empty last row, which is what was reported. auto-fit takes as
       many columns as fit and the fifth card is never orphaned. */
.nav-cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(185px, 1fr)); gap: 6px; }
.nav-card-art {
  inline-size: 40px; block-size: 40px; border-radius: 10px;
  background: var(--brand-50); padding: 2px; margin-block-end: 2px;
}
.nav-card {
  display: grid; gap: 2px; padding: 11px 13px; border-radius: var(--radius);
  color: var(--ink-900);
}
.nav-card:hover, .nav-card:focus-visible { background: var(--brand-50); text-decoration: none; }
.nav-card-name { font-weight: 700; font-size: 15.5px; }
.nav-card-price { font-size: 14px; color: var(--brand-800); font-weight: 600; }
.nav-card-price small { color: var(--ink-500); font-weight: 400; }
.nav-card-desc { font-size: 13.5px; color: var(--ink-500); line-height: 1.5; }

.nav-topics { list-style: none; margin: 0; padding: 0; display: grid; gap: 2px; }
.nav-topics a {
  display: flex; justify-content: space-between; align-items: center; gap: 14px;
  padding: 9px 12px; border-radius: var(--radius); color: var(--ink-900); font-size: 15px;
}
.nav-topics a:hover, .nav-topics a:focus-visible { background: var(--brand-50); text-decoration: none; }
.nav-n {
  font-size: 12.5px; color: var(--ink-500); font-variant-numeric: tabular-nums;
  background: var(--surface-sunk); border-radius: 999px; padding: 1px 8px;
}
.nav-menu-foot {
  display: flex; flex-wrap: wrap; gap: 4px 18px; align-items: center;
  margin-block-start: 4px; padding-block-start: 10px;
  border-block-start: 1px solid var(--line);
}
/* The rule and the spacing belong to .nav-menu-foot now — there are two
   of these links under the services panel, and a border on each drew a
   line between them. */
.nav-all { font-size: 14.5px; font-weight: 600; color: var(--brand-700); }
@keyframes nav-menu-in {
  from { opacity: 0; transform: translateY(-5px); }
  to   { opacity: 1; transform: translateY(0); }
}

@media (min-width: 1000px) { /* nav-bp: the bar */
  .nav-caret { display: inline-flex; }
  /* The current page, said in the bar itself rather than only in the
     breadcrumb. Underline rather than a background, so it reads as "you are
     here" and not as a hover state you cannot dismiss. */
  .nav a[aria-current="page"] {
    color: var(--brand-800); font-weight: 600;
    text-decoration: underline; text-decoration-thickness: 2px;
    text-underline-offset: 7px; text-decoration-color: var(--brand-700);
  }
}
/* No panels below the breakpoint — the drawer lists the same links flat. */
@media (max-width: 999px) { /* nav-bp: the drawer */
  .nav-menu, .nav-caret { display: none; }
}

/* ── The drawer ─────────────────────────────────────────────────────────────
   A sibling of the header, not a child of it — see the comment on the
   element in site/layout.mjs for why that is load-bearing rather than tidy.

   It slides from the inline-end edge because that is where the toggle is: at
   375px the logo sits at the start and the hamburger at the end, and a panel
   that appears at the opposite edge from the button that opened it reads as
   a different control entirely. */
/* ⚠️  inset-inline-START, and the distinction is the whole bug.
       In RTL, `inset-inline-end: 0` is the LEFT edge — so the drawer slid
       in from the left, away from the thumb that opened it and away from
       the side every other Hebrew app opens from. It also stopped at
       340px, leaving a strip of live page beside a modal.

       Full width and full height: on a phone this is the page, not a
       panel over it. The scrim, the scroll lock and the focus trap all
       come from assets/sheet.js and were already correct. */
.nav-drawer {
  position: fixed; inset-block: 0; inset-inline-start: 0; z-index: 96;
  inline-size: 100%;
  display: flex; flex-direction: column;
  background: #fff;
  overflow-y: auto; overscroll-behavior: contain;
  animation: nav-in .24s cubic-bezier(.2, .7, .3, 1) both;
  padding-block-end: env(safe-area-inset-bottom);
}
/* ⚠️  display:flex beats [hidden]'s display:none, and sheet.js toggles this
       element with [hidden]. Without this line the drawer ships open on
       every page and can never close. Fourth time in this codebase. */
.nav-drawer[hidden] { display: none; }
/* Above the breakpoint it does not exist at all, open or not. */
@media (min-width: 1000px) { /* nav-bp: the bar */
  .nav-drawer, .nav-drawer[hidden] { display: none; }
}

.nav-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-block-end: 1px solid var(--line);
  position: sticky; inset-block-start: 0; background: #fff; z-index: 1;
}
.nav-title { font-weight: 700; font-size: 16px; color: var(--ink-900); }
.nav-x {
  inline-size: 40px; block-size: 40px; display: grid; place-items: center;
  border: 1px solid var(--line-strong); border-radius: 50%;
  background: #fff; color: var(--ink-700); cursor: pointer;
}
.nav-x svg { inline-size: 18px; block-size: 18px; }
/* ── the drawer's five services ───────────────────────────────────────────
   ⚠️  The prices come from the engine via site/nav.mjs, and the drawings
       are the calculator's own sprite — the same picture for the same
       service, or the menu and the price list are describing two products.
   ──────────────────────────────────────────────────────────────────────── */
.nav-svc { padding: 8px 12px 4px; }
.nav-svc-h {
  margin: 0 0 4px; padding-inline: 8px;
  font-size: 12.5px; font-weight: 700; letter-spacing: .06em;
  text-transform: uppercase; color: var(--ink-500);
}
.nav-svc-row {
  display: flex; align-items: center; gap: 12px;
  padding: 10px 8px; border-radius: var(--radius); min-block-size: 56px;
}
.nav-svc-row:hover, .nav-svc-row:focus-visible { background: var(--brand-50); text-decoration: none; }
.nav-svc-art {
  inline-size: 44px; block-size: 44px; flex: none;
  border-radius: 12px; background: var(--brand-50); padding: 3px;
}
.nav-svc-text { display: grid; gap: 1px; min-inline-size: 0; }
.nav-svc-name { font-size: 16px; font-weight: 600; color: var(--ink-900); }
.nav-svc-price { font-size: 14px; color: var(--brand-800); font-weight: 600; }
.nav-svc-price small { color: var(--ink-500); font-weight: 400; }

/* Today's deal, hung on the service it covers by app.js. Names its
   threshold for the same reason the calculator's cards do: a bare
   percentage beside an unchanged price reads as a broken strikethrough. */

.nav-drawer ul { list-style: none; margin: 0; padding: 6px 0; display: flex; flex-direction: column; }
.nav-drawer ul a {
  display: flex; align-items: center; gap: 12px;
  padding: 13px 20px; font-size: 17px; color: var(--ink-900); min-block-size: 50px;
}
.nav-drawer a:hover, .nav-drawer a:focus-visible { background: var(--brand-50); text-decoration: none; }
.nav-icon { inline-size: 21px; block-size: 21px; flex: none; color: var(--ink-500); }
/* ⚠️  A page you are already on has to be obvious at a glance, not a
       slightly different shade of the same white. The rail is what makes
       it survive high-contrast mode, where a tinted background does not. */
.nav-drawer a[aria-current="page"] {
  background: var(--brand-50); font-weight: 700; color: var(--brand-900);
  /* border-inline-start, not `box-shadow: inset 3px`. box-shadow offsets
     are physical: +3px is the LEFT edge whatever the direction, which in
     RTL puts the marker on the far side of the row from where it belongs. */
  border-inline-start: 3px solid var(--brand-600);
  padding-inline-start: 17px;
}
.nav-drawer a[aria-current="page"] .nav-icon { color: var(--brand-700); }
.nav-foot {
  margin-block-start: auto; display: grid; gap: 10px;
  padding: 16px 18px calc(18px + env(safe-area-inset-bottom, 0px));
  border-block-start: 1px solid var(--line);
}
/* ⚠️  inline-flex, or the icon takes a line of its own.
       .btn is display:block here, so ${WA_ICON} — an <svg> — became a block
       above its own label and the WhatsApp button was two lines tall with
       the text pushed to the inline-start. justify-content on a block does
       nothing, which is why the old line looked like it was handling this. */
.nav-foot-btns { display: grid; gap: 8px; }
.nav-foot .btn {
  display: inline-flex; align-items: center; justify-content: center;
  gap: 8px; white-space: nowrap; min-block-size: 48px; text-align: center;
}
.nav-foot .btn svg { inline-size: 19px; block-size: 19px; flex: none; }
.nav-tel { font-variant-numeric: tabular-nums; }
.nav-hours {
  margin: 10px 0 0; font-size: 13.5px; color: var(--ink-500);
  line-height: 1.6; text-align: center;
}
.nav-hours strong { color: var(--ink-700); font-weight: 600; }
/* ⚠️  A range may not break across lines.
       «08:00–13:00» wrapped after the dash, so the line ended «08:00–»
       and the next began «13:00» — the isolation holds the direction but
       cannot hold the two halves together, and a split range reads as two
       separate times. */
.nav-hours bdi { white-space: nowrap; }

/* ⚠️  translateX is PHYSICAL, not logical — it does not flip in RTL. The
       drawer is pinned with inset-inline-end, which in this document's RTL
       is the LEFT edge, so -100% carries it off-screen and back. An LTR
       build of this site would need +100%; every page here is dir="rtl". */
/* Enters from the edge it is anchored to. The sign follows the anchor —
   it slid in from the wrong side for as long as the anchor was wrong. */
@keyframes nav-in {
  from { opacity: .4; transform: translateX(100%); }
  to   { opacity: 1; transform: translateX(0); }
}

/* Hamburger morphs into an X so the control reads as a toggle, not a button
   that did nothing (which is how it behaved until the rule above). */
.nav-toggle-bars span { transition: transform .22s ease, opacity .18s ease; transform-origin: center; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(2) { opacity: 0; }
.nav-toggle[aria-expanded="true"] .nav-toggle-bars span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }
.nav-toggle[aria-expanded="true"] { border-color: var(--brand-700); background: var(--brand-50); }

/* ── Breadcrumbs ──────────────────────────────────────────────────────────── */
/* ── /areas/ — coverage, grouped the way people describe the area ─────────
   ⚠️  The markup for this shipped once with no CSS at all and rendered as
       a bare bullet list. Same shape as the .stain-note miss: a template
       lands, the stylesheet does not, and nothing fails — the page is
       simply ugly in a way only a person looking at it can see.
   ───────────────────────────────────────────────────────────────────── */
.areas-count {
  text-align: center; color: var(--ink-500); font-size: 15px;
  margin: 0 0 26px; font-variant-numeric: tabular-nums;
}
/* ⚠️  padding: 0 — this is a <section>, and the global `section` rule sets
       64px block padding. Nested inside the page's own section it opened a
       gap the size of a screen between two councils. */
.area-group { margin-block-end: 26px; padding: 0; }
.area-group-h {
  font-size: 15px; font-weight: 700; color: var(--brand-800);
  margin: 0 0 10px; padding-block-end: 8px;
  border-block-end: 1px solid var(--line);
}
.area-list {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); gap: 6px;
}
.area-item {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  padding: 10px 14px; border-radius: var(--radius);
  background: var(--surface-alt); border: 1px solid var(--line);
  min-inline-size: 0;
}
.area-name { font-weight: 600; color: var(--ink-900); overflow-wrap: anywhere; }
.area-drive {
  flex: none; font-size: 13.5px; color: var(--ink-500);
  font-variant-numeric: tabular-nums; white-space: nowrap;
}

/* /join/ — the same grouping, around the checkboxes a new cleaner ticks. */
.join-council { margin-block-end: 18px; }
.join-council-h {
  font-size: 14px; font-weight: 700; color: var(--brand-800);
  margin: 0 0 8px; padding-block-end: 6px; border-block-end: 1px solid var(--line);
}

.breadcrumbs { background: var(--surface-alt); border-bottom: 1px solid var(--line); padding: 10px 0; font-size: 14.5px; }
/* ⚠️  Gone on a phone, by the owner's call. It cost a full row above the
       fold to repeat what the page title says next. The BreadcrumbList
       JSON-LD is emitted separately in site/layout.mjs and is untouched,
       so Google still sees the trail. */
@media (max-width: 767px) { .breadcrumbs { display: none; } }
.breadcrumbs ol { display: flex; flex-wrap: wrap; gap: 6px; list-style: none; margin: 0; padding: 0; }
.breadcrumbs li + li::before { content: '‹'; margin-inline-end: 6px; color: var(--ink-500); }
.breadcrumbs a { color: var(--ink-700); }
.breadcrumbs [aria-current] { color: var(--ink-900); font-weight: 600; }
@media (max-width: 640px) {
  /* A long guide title used to push this to four lines. One line, truncated. */
  .breadcrumbs ol { flex-wrap: nowrap; }
  .breadcrumbs li { white-space: nowrap; }
  .breadcrumbs li:last-child { overflow: hidden; text-overflow: ellipsis; min-width: 0; }
}

/* ── Narrow reading column ────────────────────────────────────────────────── */
.wrap.narrow { width: min(100% - 32px, 648px); }

/* The hero illustration and the contents list may run a little wider than the
   text column — it reads as an editorial layout rather than a misalignment. */
@media (min-width: 760px) {
  .article-hero, .toc { width: calc(100% + 56px); margin-inline: -28px; }
  .article-hero .illus { border-radius: var(--radius-lg); }
}

/* ── Tables ───────────────────────────────────────────────────────────────── */
.table-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.price-table { width: 100%; border-collapse: collapse; font-size: 16px; }
.price-table caption { text-align: start; }
.price-table th, .price-table td { padding: 12px 14px; text-align: start; border-bottom: 1px solid var(--line); }
.price-table th { background: var(--brand-50); font-weight: 700; color: var(--brand-900); }
.price-table td:last-child { font-weight: 700; color: var(--brand-800); white-space: nowrap; }
.price-table tbody tr:last-child td { border-bottom: none; }

/* ── Tick lists ───────────────────────────────────────────────────────────── */
.ticks { list-style: none; padding: 0; margin: 0; }
.ticks li { display: flex; gap: 9px; align-items: flex-start; margin-bottom: 10px; font-size: 15.5px; }
.ticks svg { width: 19px; height: 19px; color: var(--ok); flex-shrink: 0; margin-top: 3px; }

.contact-list { list-style: none; padding: 0; margin: 0; }
.contact-list li { display: flex; gap: 10px; align-items: center; margin-bottom: 11px; font-size: 16px; }
.contact-list svg { width: 20px; height: 20px; color: var(--brand-700); flex-shrink: 0; }

.hours-plain { list-style: none; padding: 0; margin: 0; }
.hours-plain li { margin-bottom: 8px; }
.hours-plain .hours-row { display: flex; justify-content: space-between; max-width: 260px; gap: 14px; }
.hours-plain .v { font-weight: 600; }

.muted { color: var(--ink-500); font-size: 15px; }

/* ── Guides ───────────────────────────────────────────────────────────────── */
.guide-group {
  font-size: 22px; margin: 38px 0 16px; padding-bottom: 10px;
  border-bottom: 2px solid var(--brand-100);
}
.guide-group:first-of-type { margin-top: 0; }

.article { padding: 36px 0 16px; }
.article h1 { font-size: clamp(27px, 5vw, 38px); margin-bottom: .4em; }
.article-cat { font-size: 14.5px; color: var(--ink-500); margin-bottom: 8px; }
.article-cat a { font-weight: 600; }
.article-lead { font-size: 19px; color: var(--ink-700); line-height: 1.6; margin-bottom: 14px; }
.article-body h2 { font-size: 24px; margin-top: 44px; margin-bottom: .5em; scroll-margin-top: 86px; }
.article-body h3 { font-size: 19.5px; margin-top: 30px; margin-bottom: .4em; }
.article-body h2 + p, .article-body h3 + p { margin-top: 0; }
.article-body p, .article-body li { font-size: 17.5px; line-height: 1.78; }
.article-body p { margin-bottom: 1.15em; }
.article-body ul, .article-body ol { padding-inline-start: 20px; margin: 0 0 1.3em; }
.article-body li { margin-bottom: 10px; padding-inline-start: 4px; }
.article-body li::marker { color: var(--brand-600); }
.article a { font-weight: 500; text-decoration: underline; text-underline-offset: 3px; }

.article-cta {
  margin-top: 44px; padding: 26px; border-radius: var(--radius-lg);
  background: var(--brand-50); border: 1px solid var(--brand-100);
}
.article-cta h2 { margin-top: 0; font-size: 21px; }
.article-cta p { margin-bottom: 18px; }
.article-cta .hero-cta { margin-bottom: 0; }

/* ── Footer additions ─────────────────────────────────────────────────────── */
.footer-heading { color: #fff; font-size: 16px; margin-bottom: 12px; font-weight: 700; }
.footer-grid { grid-template-columns: 1fr; }
.footer-brand p { font-size: 15px; }
.footer-contact { list-style: none; padding: 0; margin: 14px 0 0; }
.footer-contact li { margin-bottom: 7px; }
@media (min-width: 700px) { .footer-grid { grid-template-columns: repeat(2, 1fr); } }
@media (min-width: 1000px) { .footer-grid { grid-template-columns: 1.6fr 1fr 1fr 1fr 1fr; } }

/* ── Accessibility panel ──────────────────────────────────────────────────── */
.a11y-fab {
  position: fixed; inset-inline-start: 16px; bottom: 16px; z-index: 65;
  width: 52px; height: 52px; border-radius: 50%;
  background: var(--brand-800); color: #fff; display: grid; place-items: center;
  box-shadow: var(--shadow-md);
}
.a11y-fab svg { width: 26px; height: 26px; }
.a11y-fab:hover { background: var(--brand-900); }

.a11y-panel {
  position: fixed; inset-inline-start: 16px; bottom: 78px; z-index: 75;
  width: min(calc(100vw - 32px), 300px);
  background: #fff; border: 1px solid var(--line-strong); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg); padding: 16px;
}
.a11y-panel[hidden] { display: none; }
.a11y-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 12px; }
.a11y-head h2 { font-size: 17px; margin: 0; }
.a11y-close { width: 32px; height: 32px; border-radius: 50%; font-size: 22px; line-height: 1; color: var(--ink-700); }
.a11y-close:hover { background: var(--surface-alt); }
.a11y-list { list-style: none; padding: 0; margin: 0 0 12px; display: grid; gap: 6px; }
.a11y-list button {
  width: 100%; display: flex; align-items: center; gap: 10px;
  padding: 10px 12px; border-radius: var(--radius); font-size: 15px;
  border: 2px solid var(--line); background: #fff; text-align: start;
}
.a11y-list button:hover { border-color: var(--brand-500); background: var(--brand-50); }
.a11y-list button[aria-pressed="true"] { background: var(--brand-700); border-color: var(--brand-700); color: #fff; }
.a11y-glyph { width: 26px; text-align: center; font-weight: 700; flex-shrink: 0; }
.a11y-foot { margin: 10px 0 0; font-size: 14px; text-align: center; }

/* ── Consent banner ───────────────────────────────────────────────────────── */
.consent {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 90;
  background: var(--brand-900); color: rgba(255,255,255,.92);
  border-top: 3px solid var(--brand-600); box-shadow: 0 -6px 28px rgba(5,54,58,.28);
}
.consent[hidden] { display: none; }
.consent-inner {
  width: min(100% - 32px, var(--wrap)); margin-inline: auto;
  padding: 16px 0; display: flex; flex-wrap: wrap; gap: 14px;
  align-items: center; justify-content: space-between;
}
.consent p { margin: 0; font-size: 15px; max-width: 640px; }
.consent a { color: #fff; text-decoration: underline; }
.consent-actions { display: flex; gap: 9px; flex-shrink: 0; }
.consent .btn-ghost { background: transparent; color: #fff; border-color: rgba(255,255,255,.5); }
.consent .btn-ghost:hover { background: rgba(255,255,255,.12); border-color: #fff; }
/* Three buttons need room to wrap on a phone without becoming a column of
   full-width blocks that hides the text above them. */
@media (max-width: 560px) {
  .consent-inner { padding: 14px 0; gap: 12px; }
  .consent p { font-size: 14px; }
  .consent-actions { width: 100%; }
  .consent-actions .btn { flex: 1; padding-inline: 8px; }
}

/* ── The consent settings sheet ───────────────────────────────────────────── */
.sheet-narrow .sheet-scroll { padding-bottom: 8px; }

.cc-row {
  padding: 14px 0; border-bottom: 1px solid var(--line);
}
.cc-row:last-child { border-bottom: none; }
.cc-head { display: flex; align-items: center; justify-content: space-between; gap: 12px; min-height: 32px; }
.cc-label { font-weight: 700; font-size: 16px; color: var(--ink-900); cursor: pointer; }
.cc-row input:disabled + *, .cc-row .cc-label { cursor: default; }

/* A real checkbox, scaled up to a comfortable target rather than replaced by
   a div — it keeps the native keyboard behaviour and the forced-colors
   rendering that a hand-built switch throws away. */
.cc-toggle {
  flex: none; width: 26px; height: 26px; accent-color: var(--brand-700); cursor: pointer;
}
.cc-toggle:disabled { cursor: not-allowed; opacity: .55; }

.cc-locked { margin: 4px 0 0; font-size: 13px; color: var(--ink-500); font-weight: 600; }
.cc-what { margin: 6px 0 0; font-size: 15px; color: var(--ink-900); }
.cc-why { margin: 4px 0 0; font-size: 14px; color: var(--ink-500); line-height: 1.5; }
/* The label stays Hebrew and right-aligned; only the identifiers are LTR.
   Setting direction on the whole line threw the Hebrew prefix to the wrong
   end and pushed the list off the edge. */
.cc-keys { margin: 8px 0 0; font-size: 12px; color: var(--ink-500); }
.cc-keys code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 11.5px; direction: ltr; unicode-bidi: isolate;
  background: var(--surface-alt); border-radius: 4px; padding: 1px 5px;
  display: inline-block; margin: 2px 0 0; word-break: break-all;
}

.site-footer .footer-bottom a { color: rgba(255,255,255,.82); text-decoration: underline; }
.site-footer .footer-bottom a:hover { color: #fff; }

html[data-a11y-contrast="on"] .cc-row { border-color: #333; }

/* ── The post-job page ────────────────────────────────────────────────────── */
.care-list { display: grid; gap: 12px; }
.care-list li { font-size: 16px; line-height: 1.55; }

.review { max-width: 560px; margin-inline: auto; }

/*
 * Star rating, radios only.
 *
 * The inputs are in the DOM from 5 down to 1 so that `input:checked ~ label`
 * can fill the checked star and every lower one — a sibling combinator can
 * only look forwards. row-reverse then puts 1 at the right-hand (start) end
 * in RTL, which is the order people expect to read them in.
 *
 * They stay real radios: keyboard arrow keys, the required grouping and
 * forced-colors rendering all come free, and every one of them is work to
 * rebuild badly on top of divs.
 */
.stars {
  display: flex; flex-direction: row-reverse; justify-content: flex-end;
  gap: 4px; border: none; margin: 0 0 18px; padding: 0;
}
.stars input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.stars label { cursor: pointer; padding: 4px; line-height: 0; border-radius: 8px; }
.stars svg { width: 38px; height: 38px; fill: var(--line-strong); transition: fill .12s ease; }

.stars input:checked ~ label svg { fill: var(--accent-500); }
@media (hover: hover) {
  .stars label:hover svg,
  .stars label:hover ~ label svg { fill: var(--accent-500); }
}
/* The focus ring has to be visible on the label, since the input is hidden. */
.stars input:focus-visible + label { outline: 3px solid var(--brand-700); outline-offset: 1px; }

.ref-code { margin: 12px 0 0; font-size: 15px; }
.ref-code code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 16px; font-weight: 700; letter-spacing: .06em;
  background: var(--brand-50); color: var(--brand-800);
  border-radius: 6px; padding: 3px 9px; direction: ltr; unicode-bidi: isolate;
}

.review-link code {
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 12px; direction: ltr; unicode-bidi: isolate;
  word-break: break-all; display: inline-block;
}

html[data-a11y-contrast="on"] .stars svg { fill: #666; }
html[data-a11y-contrast="on"] .stars input:checked ~ label svg { fill: #000; }

/* Keep the floating buttons clear of the banner while it is showing. */
body.has-consent .fab-dock { bottom: 104px; }
body.has-consent .a11y-fab { bottom: 104px; }
body.has-consent .a11y-panel { bottom: 166px; }
/**
 * ⚠️  AND THE CART BAR, WHICH WAS MISSED.
 *
 *     Three things already stood aside for the consent banner and the
 *     sticky cart bar did not. At 375 the banner (z-index 90) sat squarely
 *     on top of it (z-index 70), so a visitor who had not yet answered the
 *     cookie question could build a basket and then not open it — the only
 *     way into the cart on a phone was underneath the banner. A browser
 *     test found it by timing out on a click: "consent-reject intercepts
 *     pointer events".
 *
 *     Measured from the element, not guessed: the banner is two or three
 *     lines of Hebrew plus three buttons, and a hard-coded 104px was going
 *     to be wrong at some width. consent.js writes --consent-h.
 */
body.has-consent .calc-bar { bottom: var(--consent-h, 140px); }

/* ── Calculator: multi-item ───────────────────────────────────────────────── */
fieldset { border: none; margin: 0 0 22px; padding: 0; }
legend { padding: 0; }

.calc-item {
  border: 1px solid var(--line-strong); border-radius: var(--radius-lg);
  padding: 18px; margin-bottom: 14px; background: #fff;
}
.calc-item-head { display: flex; align-items: center; gap: 12px; margin-bottom: 14px; }
.calc-item-head h3 { margin: 0; font-size: 18px; flex: 1; }
.calc-item-price { font-weight: 800; font-size: 19px; color: var(--brand-800); white-space: nowrap; }
.calc-item-remove {
  width: 34px; height: 34px; border-radius: 50%; color: var(--ink-700);
  font-size: 20px; line-height: 1; flex-shrink: 0; border: 2px solid var(--line-strong);
}
.calc-item-remove:hover { background: #fde8e8; border-color: #c0392b; color: #a33226; }
.calc-item .field { margin-bottom: 16px; }
.calc-item .field:last-of-type { margin-bottom: 0; }
.calc-item-dup { margin-top: 14px; font-size: 14.5px; }



/* ═══════════════════════════════════════════════════════════════════════════
   Accessibility preference modes — toggled by the widget on <html>
   ═══════════════════════════════════════════════════════════════════════════ */

html[data-a11y-font="1"] body { font-size: 18.5px; }
html[data-a11y-font="2"] body { font-size: 20.5px; }
html[data-a11y-font="3"] body { font-size: 23px; }
html[data-a11y-font="-1"] body { font-size: 15.5px; }

html[data-a11y-contrast="on"] {
  --ink-900: #000; --ink-700: #111; --ink-500: #1c2b2d;
  --line: #333; --line-strong: #222;
  --surface-alt: #fff; --brand-50: #fff; --brand-100: #999;
}
html[data-a11y-contrast="on"] body { background: #fff; }
html[data-a11y-contrast="on"] .card,
html[data-a11y-contrast="on"] .calc-item { border-color: #333; }
html[data-a11y-contrast="on"] .hero::before,
html[data-a11y-contrast="on"] .hero::after { display: none; }
html[data-a11y-contrast="on"] .hero { background: #fff; }

html[data-a11y-invert="on"] { filter: invert(1) hue-rotate(180deg); }
html[data-a11y-invert="on"] img { filter: invert(1) hue-rotate(180deg); }

html[data-a11y-links="on"] a { text-decoration: underline !important; text-underline-offset: 3px; }

html[data-a11y-readable="on"] body,
html[data-a11y-readable="on"] button,
html[data-a11y-readable="on"] input {
  font-family: Arial, 'Segoe UI', sans-serif !important;
  letter-spacing: .02em; word-spacing: .08em; line-height: 1.85;
}

html[data-a11y-no-motion="on"] *,
html[data-a11y-no-motion="on"] *::before,
html[data-a11y-no-motion="on"] *::after {
  animation: none !important; transition: none !important; scroll-behavior: auto !important;
}

html[data-a11y-big-cursor="on"], html[data-a11y-big-cursor="on"] * {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='44' height='44' viewBox='0 0 44 44'%3E%3Cpath d='M8 4l26 15-11 3-4 12z' fill='%23fff' stroke='%23000' stroke-width='2.5'/%3E%3C/svg%3E") 6 4, auto;
}

/* Focus must stay visible in every mode. */
html[data-a11y-contrast="on"] :focus-visible { outline: 3px solid #000; outline-offset: 3px; }


/* ═══════════════════════════════════════════════════════════════════════════
   Quote calculator v3 — a delivery-app menu
   Sticky category tabs, one row per service with a thumbnail, and a cart bar
   pinned to the bottom. Choosing seats or fabric happens in a bottom sheet:
   the previous version expanded the row in place, which pushed everything
   below it down the screen while the customer was still deciding.
   ═══════════════════════════════════════════════════════════════════════════ */

/* ── Sticky category tabs ─────────────────────────────────────────────────── */
.calc-tabs {
  position: sticky; top: var(--header-h); z-index: 20;
  background: #fff; border-bottom: 1px solid var(--line);
}
.tabs-strip {
  display: flex; gap: 4px; padding: 8px 12px;
  overflow-x: auto; -webkit-overflow-scrolling: touch;
  scrollbar-width: none; scroll-snap-type: x proximity;
}
.tabs-strip::-webkit-scrollbar { display: none; }
.tab {
  flex: none; scroll-snap-align: start;
  padding: 9px 15px; border-radius: var(--radius-pill);
  font-size: 15px; font-weight: 600; color: var(--ink-700);
  white-space: nowrap; border: 1.5px solid transparent;
}
.tab:hover { background: var(--brand-50); color: var(--brand-800); text-decoration: none; }
.tab.is-on { background: var(--brand-800); color: #fff; }

/* ── Menu sections ────────────────────────────────────────────────────────── */
.calc-body { padding: 18px 16px 8px; }
/* A <section> for the semantics, without the global 40/64px page padding
   that element carries — these are menu groups, not page sections. */
.menu-sec { padding: 0; scroll-margin-top: calc(var(--header-h) + 58px); }
.menu-sec + .menu-sec { margin-top: 26px; }
.menu-sec-h {
  margin: 0 0 12px; font-size: 19px; font-weight: 800; color: var(--brand-900);
}
/* The call-out minimum, under every category heading. Quiet on purpose:
   it is a condition of the price list, not a price. */
.menu-sec-min { margin: -2px 0 10px; font-size: 13px; color: var(--ink-500); }
.dish-list { display: grid; gap: 10px; }

/* ── One card ─────────────────────────────────────────────────────────────
   Two controls, so the card cannot be one <button>: a stepper has to live
   inside it and buttons do not nest. The art-and-text region opens the
   sheet; the action sits beside it, inside the card. It used to float over
   the corner of the illustration — covering the drawing of the thing it was
   offering to add.
   ───────────────────────────────────────────────────────────────────────── */
.dish {
  display: flex; align-items: center; gap: var(--space-3);
  padding: 10px 12px;
  background: #fff; border: 1.5px solid var(--line);
  border-radius: var(--radius-lg);
  transition: border-color .15s ease, box-shadow .15s ease;
}
.dish:hover { border-color: var(--brand-500); box-shadow: var(--shadow-sm); }
.dish:focus-within { border-color: var(--brand-600); }
.dish.is-in { border-color: var(--brand-600); background: var(--brand-50); }

.dish-open {
  flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 12px;
  padding: 0; background: none; border: 0; text-align: start; cursor: pointer;
}
.dish-art {
  inline-size: 56px; block-size: 56px; flex: none; display: block;
  border-radius: var(--radius); background: var(--brand-50);
}
.dish.is-in .dish-art { background: #fff; }

.dish-text { min-width: 0; display: grid; gap: 2px; }
.dish-name {
  font-size: 16px; font-weight: 700; color: var(--ink-900);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* One line. The old card printed the hint and then the price underneath it,
   and the hint was itself a price — the same number twice. */
/* ⚠️  wrap, not nowrap — but only the badge is allowed to drop.
       The badge now carries its condition («15% הנחה מ-200 ₪») and that
       does not fit beside the price on a card in a two-column grid: it ran
       out under the «הוספה» button and was cut mid-word. The price itself
       still never wraps (.dish-amt / .dish-from / .dish-was are nowrap and
       flex:none), so the line that mattered is unchanged and only the
       badge moves to a second row when it has to. */
.dish-price {
  font-size: 14px; color: var(--brand-800); font-weight: 700;
  display: flex; align-items: baseline; flex-wrap: wrap; row-gap: 3px; min-width: 0;
}
.dish-from, .dish-note { font-weight: 500; color: var(--ink-500); }
/* Held to one line and never shrunk: as a shrinkable flex item " · מ-" was
   squeezed to 16px and broke across two lines, taking the card with it. */
.dish-from { white-space: nowrap; flex: none; }
/* The blurb gives way first. The price never wraps to a second line —
   that second line was the whole height the compact card was meant to save. */
/* ⚠️  Was one clipped line, so "ספה + 2 כורסאות" read "ספה + 2 כור…" on a
       phone — the card told you what it was and then cut off the half that
       said what was in it. Two lines, clamped. */
.dish-note {
  min-width: 0; display: -webkit-box; -webkit-box-orient: vertical;
  -webkit-line-clamp: 2; line-clamp: 2; overflow: hidden;
}
/* The unit qualifier — «למ"ר», «למושב», «ליחידה».
   ⚠️  ITS OWN ROW, ON EVERY CARD, AND THAT IS THE POINT.
       Inline beside the price it fits on some cards and not others: the
       text column is 69-127px at both widths, so «49 ₪ למ"ר» sat on one
       line while «מ-240 ₪ לפי מספר מושבים» took two — and a grid where
       four cards are 79px and three are 101px reads as breakage rather
       than as design. flex-basis:100% gives every card the same two
       lines and the same height. Clipped, never wrapped, so a long unit
       costs an ellipsis and not a third row. */
.dish-unit {
  flex-basis: 100%; font-size: 12.5px; font-weight: 500; color: var(--ink-500);
  min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.dish-amt, .dish-now, .dish-was { white-space: nowrap; }
.dish-was { color: var(--ink-500); font-weight: 500; text-decoration-thickness: 1.5px; margin-inline-end: 5px; }
.dish-now { color: var(--ok-ink); }
/* Says the discount exists and what unlocks it. It cannot print a
   struck-through price here, because below the deal minimum that price is
   not one the customer can actually get — so it names the threshold
   instead. See dealBadge() in assets/calculator.js. */
.dish-deal {
  font-size: 11.5px; font-weight: 700; padding: 1px 7px;
  border-radius: var(--radius-pill);
  background: var(--ok-bg); color: var(--ok-ink);
  margin-inline-start: 6px; white-space: nowrap; flex: none;
}
/* In the sheet there is room for it on the same line as the unit price. */
.sheet-hint .dish-deal { margin-inline-start: 8px; }

.dish-act { flex: none; }
.dish-add {
  min-block-size: 44px; min-inline-size: 44px; padding: 0 15px;
  border-radius: var(--radius-pill);
  background: var(--brand-50); border: 1.5px solid var(--brand-500);
  color: var(--brand-800); font-size: 15px; font-weight: 700; cursor: pointer;
}
.dish-add:hover { background: var(--brand-700); border-color: var(--brand-700); color: #fff; }
.dish-add[hidden], .dish-step[hidden] { display: none; }

/* `dish-` prefixed, not `.stepper`. That class already exists for the shop's
   quantity control at 36px — the same collision `.hero` and `.stars` caused
   in the agent area, and it silently shrank these below the touch minimum. */
.dish-step {
  display: flex; align-items: center;
  border: 1.5px solid var(--brand-700); border-radius: var(--radius-pill);
  background: #fff; overflow: hidden;
}
.dish-step-btn {
  inline-size: 44px; block-size: 44px; flex: none;
  background: none; border: 0; cursor: pointer;
  color: var(--brand-800); font-size: 21px; font-weight: 700; line-height: 1;
}
.dish-step-btn:hover { background: var(--brand-50); }
.dish-step-n {
  min-inline-size: 26px; text-align: center;
  font-size: 16px; font-weight: 800; color: var(--brand-900);
  font-variant-numeric: tabular-nums;
}


/* ── Two columns from 1024px ──────────────────────────────────────────────
   The catalogue keeps its sticky tabs on the right; the basket stays on
   screen on the left instead of living behind a button. Below this width
   there is no room for a second column, so the bottom bar and the quote
   sheet carry the same job.
   ───────────────────────────────────────────────────────────────────────── */
.calc-side { display: none; }

@media (min-width: 1024px) {
  .calc-layout {
    display: grid; grid-template-columns: minmax(300px, 340px) 1fr;
    align-items: start; gap: 24px;
  }
  /* Right in RTL: the catalogue is the second grid column. */
  .calc-layout > .calc-card { grid-column: 2; }
  /* ⚠️  align-self:stretch is load-bearing. .calc-layout sets
         align-items:start, which collapsed this column to its own content
         height — so the sticky box inside it had exactly zero room to
         travel and scrolled away with the page. Stretching the column to
         the grid row gives sticky something to stick within. */
  .calc-side { display: block; grid-column: 1; grid-row: 1; align-self: stretch; }
  /* ⚠️  The title and the total must not scroll away.
         This box used to be one overflow-y:auto region containing the
         heading, the items, the total and the CTA — so on a long basket the
         customer scrolled the one number they came for out of sight, inside
         a column that was already sticky. Three rows now: heading, the item
         list (the only thing that scrolls), and the total with its button
         pinned to the bottom. */
  .calc-side-inner {
    position: sticky; top: calc(var(--header-h) + 16px);
    background: #fff; border: 1.5px solid var(--line);
    border-radius: var(--radius-lg); padding: 18px;
    max-block-size: calc(100dvh - var(--header-h) - 40px);
    display: flex; flex-direction: column; min-block-size: 0;
  }
  #calc-summary { display: flex; flex-direction: column; min-block-size: 0; flex: 1; }
  .calc-side-scroll { overflow-y: auto; min-block-size: 0; flex: 1; overscroll-behavior: contain; }
  .calc-side-foot {
    flex: none; padding-block-start: 12px; margin-block-start: 12px;
    border-block-start: 1px solid var(--line);
  }

  /* ⚠️  Name and price shared one flex row, so "מזרן זוגי — צד אחד" broke
         to one word per line beside the badge, the price, "שינוי" and the ×.
         Two rows in the narrow column: what it is, then what it costs. */
  .calc-side .cart-line { display: grid; grid-template-columns: auto 1fr; gap: 6px 10px; align-items: start; }
  .calc-side .cart-line-art { grid-row: 1 / span 2; }
  .calc-side .cart-line-text { grid-column: 2; }
  .calc-side .cart-line-name { white-space: normal; overflow-wrap: anywhere; }
  .calc-side .cart-line-side { grid-column: 2; justify-content: flex-start; flex-wrap: wrap; }
  .calc-side-h { margin: 0 0 12px; font-size: 18px; font-weight: 800; color: var(--brand-900); }
  .calc-side-empty { margin: 0; font-size: 14.5px; color: var(--ink-500); line-height: 1.55; }
  .calc-side-cta {
    inline-size: 100%; min-block-size: 48px; margin-top: 14px;
    border: 0; border-radius: var(--radius-pill); cursor: pointer;
    background: var(--brand-800); color: #fff; font-size: 16px; font-weight: 700;
  }
  .calc-side-cta:hover { background: var(--brand-900); }
  .calc-side .calc-clear { display: block; margin: 10px auto 0; }
  .calc-side .cart-line-art { inline-size: 40px; block-size: 40px; }
  .calc-side .calc-total .amt { font-size: 26px; }

  /* Two cards per row, now that each is short enough for two to be read
     at a glance rather than scrolled past. */
  /* ⚠️  auto-fit, so a category with one item fills its row.
         Two fixed tracks meant מזרן and שטיח — the only members of their
         categories — each sat in half a row with an empty half beside them,
         reading as a card that failed to load. auto-fit collapses the empty
         track, so one item spans the width and two still sit side by side. */
  .dish-list { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); }

  /* The bottom bar is the phone's stand-in for the column above. With the
     column on screen it would be a second, competing total. */
  .calc-bar { display: none; }
}

/* ── The bottom sheet ─────────────────────────────────────────────────────── */
/* 95/96 puts it above the cart bar (70), the accessibility panel (75) and the
   shop cart (80), and below the skip link (200). */
.sheet-scrim {
  position: fixed; inset: 0; z-index: 95;
  background: rgba(6, 34, 38, .5);
  animation: scrim-in .18s ease both;
}
.sheet-scrim[hidden] { display: none; }

/* The sheet's resting position is its ONLY position. Entry is an animation
   with just a `from` keyframe, so the `to` is whatever the element computes —
   which keeps tracking --drag after the animation ends.
   
   This used to be a class the script added inside requestAnimationFrame, so
   whether the sheet was visible at all depended on a frame callback firing.
   In a background tab rAF does not run, and the sheet sat open but parked
   off-screen. Visibility is now pure CSS: remove [hidden] and it is there.
   
   --drag is set by the pointer handler while the grip is held. Keeping the
   offset in a variable means the drag composes with the centring transform
   instead of replacing it — writing `transform` directly used to fling the
   sheet half its width sideways on a wide screen. */
.sheet {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 96;
  display: flex; flex-direction: column;
  max-height: 88vh; max-height: 88dvh;
  background: #fff;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  box-shadow: 0 -8px 40px rgba(6, 50, 54, .28);
  --drag: 0px;
  transform: translateY(var(--drag));
  animation: sheet-in .26s cubic-bezier(.2, .8, .3, 1);
}
.sheet[hidden] { display: none; }
.sheet-tall { min-height: 60vh; min-height: 60dvh; }

@keyframes sheet-in { from { transform: translateY(100%); } }

@media (min-width: 720px) {
  .sheet {
    inset-inline: auto; inset-inline-start: 50%;
    width: min(520px, calc(100vw - 48px));
    bottom: 24px; border-radius: var(--radius-lg);
    transform: translate(50%, var(--drag));
    animation-name: sheet-in-wide;
  }
  @keyframes sheet-in-wide { from { transform: translate(50%, 100%); } }
}

/* The grab handle is the drag target, so it needs real height. */
.sheet-grip {
  flex: none; height: 22px; display: grid; place-items: center; cursor: grab;
  /* Only the grip opts out of browser gestures. It used to be the whole
     sheet, which disabled pinch-zoom over all of its content. */
  touch-action: none;
}
.sheet-grip::after {
  content: ''; width: 42px; height: 4px; border-radius: 2px; background: var(--line-strong); opacity: .5;
}
.sheet-x {
  position: absolute; top: 10px; inset-inline-end: 10px;
  width: 36px; height: 36px; border-radius: 50%;
  display: grid; place-items: center;
  background: var(--surface-alt); color: var(--ink-700); border: none;
}
.sheet-x:hover { background: var(--brand-50); color: var(--brand-800); }
.sheet-x svg { width: 18px; height: 18px; }

.sheet-scroll {
  flex: 1; min-height: 0; overflow-y: auto; -webkit-overflow-scrolling: touch;
  padding: 4px 20px 16px;
}
/* Focusable so the arrow keys can scroll it — a sheet taller than the
   viewport was unreachable by keyboard once focus sat on a control. */
.sheet-scroll:focus-visible { outline: 3px solid var(--brand-500); outline-offset: -3px; }
.sheet-title { margin: 0 0 4px; font-size: 22px; }
/* The cart's heading sits outside .sheet-scroll, so it needs its own
   gutters — without them it ran under the rounded edge. */
.sheet > .sheet-title { padding: 2px 20px 10px; padding-inline-end: 62px; }
.sheet-hint { margin: 0 0 18px; font-size: 15px; color: var(--ink-500); }

.sheet-hero { display: grid; place-items: center; margin-bottom: 12px; }
.sheet-art {
  width: 116px; height: 116px; border-radius: var(--radius-lg); background: var(--brand-50);
}

.sheet-opts { display: grid; gap: 18px; }

.sheet-foot {
  flex: none; padding: 14px 20px calc(14px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--line); background: #fff;
  border-radius: 0 0 var(--radius-lg) var(--radius-lg);
}
.sheet-bar { display: flex; align-items: center; gap: 12px; }
.sheet-done { flex: 1; font-size: 17px; padding: 14px 20px; }
.sheet-done:disabled { opacity: .5; cursor: not-allowed; }

/* ── How many, at the end of the sheet ────────────────────────────────────
   Deliberately not the ± stepper used for "מספר מושבים" a few rows above.
   Two identical steppers, one meaning seats and one meaning sofas, were
   told apart only by their label. */
.qty-block {
  margin-top: 18px; padding-top: 16px; border-top: 1px solid var(--line);
}
.qty-fold > summary {
  cursor: pointer; font-size: 15px; font-weight: 700; color: var(--brand-800);
  padding: 8px 0; min-block-size: 44px; display: flex; align-items: center;
}
.qty-fold > summary::-webkit-details-marker { display: none; }
.qty-fold > summary::before {
  content: '+'; font-size: 18px; line-height: 1;
  margin-inline-end: 8px; color: var(--brand-700);
}
.qty-fold[open] > summary::before { content: '−'; }
.qty-body .opt-row { margin: 0; }

.sheet-remove {
  display: block; margin: 12px auto 0;
  font-size: 14.5px; color: var(--ink-500); text-decoration: underline; background: none; border: none;
}
.sheet-remove:hover { color: #a33226; }

body.sheet-open { overflow: hidden; }

@keyframes scrim-in { from { opacity: 0; } to { opacity: 1; } }

/* ── Question groups inside the sheet ─────────────────────────────────────── */
/* 44px targets. In the old inline row these were 29px and 32px, because the
   row had no vertical space to give them. The sheet does. */
.opt-row {
  display: grid; gap: 8px; border: none; margin: 0; padding: 0;
}
.opt-row legend, .opt-legend {
  font-size: 15px; color: var(--ink-900); font-weight: 700; padding: 0; float: none;
}
.opt-chips { display: flex; gap: 8px; flex-wrap: wrap; }
/* ⚠️  THE CHIP IS NOT A FLEX CONTAINER, which is why the first attempt
       put the mark on its own line ABOVE the words — a button is a block
       and the svg simply stacked. Only the chips that HAVE an icon are
       turned into rows, so every other chip keeps the box it has had all
       along and nothing reflows.

   ⚠️  Sized in em so it tracks the label rather than a fixed pixel
       height: the two-line chips set a smaller label and the mark has to
       come down with it. */
.opt-chip:has(> .chip-icon) { display: inline-flex; align-items: center; }
.opt-chip > .chip-icon {
  inline-size: 1.15em; block-size: 1.15em; flex: none;
  margin-inline-end: 7px; opacity: .75;
}
.opt-chip.is-on > .chip-icon { opacity: 1; }
/* The two-line chip is a grid; the mark spans both rows beside them. */
.opt-chip-2:has(> .chip-icon) { display: grid; grid-template-columns: auto 1fr; column-gap: 7px; }
.opt-chip-2 > .chip-icon { grid-row: 1 / span 2; align-self: center; margin-inline-end: 0; }
.opt-chip {
  min-height: 44px; padding: 10px 18px; border-radius: var(--radius-pill);
  font-size: 15.5px; font-weight: 600;
  border: 1.5px solid var(--line-strong); background: #fff; color: var(--ink-700);
}
/* A chip that carries its price on a second line. */
.opt-chip-2 { display: grid; gap: 1px; padding: 8px 16px; text-align: start; }
.opt-chip-note { font-size: 12.5px; font-weight: 500; opacity: .75; }
.opt-chip:hover { border-color: var(--brand-700); color: var(--brand-800); }
.opt-chip.is-on { background: var(--brand-700); border-color: var(--brand-700); color: #fff; }

/* ─────────────────────────────────────────────────────────────────────
   Three movements on the questionnaire, and no more.

   ⚠️  EVERY ONE OF THEM IS A COLOUR OR AN OPACITY, NEVER A SIZE OR A
       POSITION.

       These chips are 44px targets that wrap onto several rows. Anything
       that changes a chip's BOX — a scale, a lift, a margin — reflows the
       row and moves the chips beside it out from under a finger already
       travelling towards one. The sheet redraws on every answer as it is;
       the motion must not also move the furniture.

   ⚠️  AND BOTH SWITCHES ALREADY REACH THEM. prefers-reduced-motion is
       honoured below, and html[data-a11y-no-motion] kills every
       animation and transition on the page from one rule near the
       bottom of this file. Neither needed anything new.
   ───────────────────────────────────────────────────────────────────── */
.opt-chip { transition: background-color .14s ease, border-color .14s ease, color .14s ease; }

/* The count on a closed section, when answering changes it. The redraw
   replaces the node, so this plays on arrival rather than on a change —
   which is the only hook a rebuilt element gives you. */
.intake-group-count { animation: count-settle .22s ease-out both; }
@keyframes count-settle {
  from { opacity: .35; }
  to   { opacity: 1; }
}

/* Moving between steps. The sheet is one scroll container whose contents
   are swapped; without this the page simply blinks.

   ⚠️  A ONE-SHOT CLASS, NOT A SELECTOR ON THE CONTENT. .sheet-scroll
       holds its children directly — there is no wrapper to animate, and
       animating the children themselves would replay on EVERY answer,
       because every answer redraws the sheet. The class is added where
       the step actually changes and removed when the animation ends. */
.sheet-scroll.step-in { animation: step-in .18s cubic-bezier(.2,.7,.3,1) both; }
@keyframes step-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .opt-chip { transition: none; }
  .intake-group-count, .sheet-scroll.step-in { animation: none; }
}

.mini-stepper {
  display: flex; align-items: center; gap: 4px;
  border: 1.5px solid var(--line-strong); border-radius: var(--radius-pill);
  padding: 3px; width: max-content;
}
.mini-stepper button {
  width: 42px; height: 42px; border-radius: 50%;
  font-size: 20px; line-height: 1; font-weight: 600;
  border: none; background: var(--brand-50); color: var(--brand-800);
}
.mini-stepper button:disabled { opacity: .35; cursor: not-allowed; }
.mini-stepper output { min-width: 36px; text-align: center; font-weight: 800; font-size: 17px; }

.size-inputs { display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.size-inputs input { width: 92px; padding: 11px 12px; font-size: 16px; border-radius: 12px; }
.size-inputs .x { color: var(--ink-500); }
.size-inputs .sqm { font-weight: 700; color: var(--brand-800); font-size: 15px; }

/* ── The rug measurement, after the comma bug ───────────────────────────────
   The field is text with inputmode="decimal" now, because what a number
   input does with the comma on a Hebrew keypad is the browser's decision
   and one of the answers priced a rug at 3,675 ₪.

   Both notices sit BELOW the inputs. A message above the control it is
   about pushes that control down under the finger already reaching for it. */
.size-cell { position: relative; display: inline-flex; align-items: center; gap: 6px; }
.size-echo {
  font-size: 13px; color: var(--ink-500); font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.size-inputs input.has-err { border-color: var(--danger-line); background: var(--danger-bg); }
.size-err {
  margin: 8px 0 0; font-size: 14px; color: var(--danger-ink); font-weight: 600;
}
.size-err[hidden] { display: none; }
.size-confirm {
  margin-block-start: 10px; padding: 11px 13px;
  background: var(--warn-bg); border: 1px solid var(--warn-line);
  border-radius: var(--radius);
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
}
.size-confirm[hidden] { display: none; }
.size-confirm-t { margin: 0; font-size: 14.5px; color: var(--warn-ink); font-weight: 600; flex: 1; min-inline-size: 0; }

.item-line-ask {
  margin: 14px 0 0; font-size: 14.5px; color: var(--warn-ink);
  background: var(--warn-bg); border: 1px solid var(--warn-line);
  border-radius: var(--radius); padding: 10px 13px;
}
.item-reject {
  margin: 0 0 16px; padding: 13px 15px;
  background: var(--warn-bg); border: 1px solid var(--warn-line); border-radius: var(--radius);
}
.item-reject p { margin: 0 0 8px; font-size: 15px; color: var(--warn-ink); }
.item-reject-link { font-size: 14.5px; font-weight: 700; text-decoration: underline; }

/* ⚠️  Advice, not a warning — a type we DO take. Amber would read as
       «there is a problem here» on work we want, so it borrows the
       brand's own quiet surface instead of the warning palette. */

/* ── The basket, inside its sheet ─────────────────────────────────────────── */
.cart-lines { list-style: none; margin: 0 0 18px; padding: 0; display: grid; gap: 10px; }
.cart-line {
  display: flex; align-items: center; gap: 12px;
  padding: 10px; border: 1px solid var(--line); border-radius: var(--radius);
}
.cart-line-art { width: 52px; height: 52px; flex: none; border-radius: 10px; background: var(--brand-50); }
.cart-line-text { flex: 1; min-width: 0; display: grid; gap: 2px; }
.cart-line-name { font-size: 15.5px; font-weight: 600; }
.cart-line-warn { font-size: 13.5px; color: var(--warn-ink); }
.cart-line-side { display: flex; align-items: center; gap: 8px; flex: none; }
.cart-line-price { font-weight: 800; color: var(--brand-800); white-space: nowrap; font-size: 15.5px; }
/* The line shows what this line costs today. It used to show the full price
   with a "במבצע" badge and let the discount appear only under the total, so
   the card said 150→132 and the line for the same mattress said 250. */
.cart-line-was {
  color: var(--ink-500); font-size: 13.5px; white-space: nowrap;
  text-decoration-thickness: 1px;
}
.cart-line-price.is-deal { color: var(--brand-800); }

/* ── A bundle is one line ───────────────────────────────────────────────────
   "סלון מלא" used to arrive as three unrelated rows with nothing saying they
   came together and nothing to remove them together. The breakdown lives
   behind a <details> so it is available without being in the way. */
.cart-line-group .cart-line-name { font-weight: 700; }
.cart-group-det { margin-block-start: 3px; }
.cart-group-sum {
  cursor: pointer; font-size: 13.5px; color: var(--ink-500);
  list-style: none; display: inline-flex; align-items: center; gap: 5px;
}
.cart-group-sum::-webkit-details-marker { display: none; }
.cart-group-sum::after { content: '▾'; font-size: 11px; }
.cart-group-det[open] .cart-group-sum::after { content: '▴'; }
.cart-group-sum:focus-visible { outline: 2px solid var(--brand-700); outline-offset: 2px; border-radius: 4px; }
.cart-group-list {
  list-style: none; margin: 7px 0 0; padding: 0 0 0 0;
  display: flex; flex-direction: column; gap: 4px;
}
.cart-group-list li {
  display: flex; justify-content: space-between; gap: 14px;
  font-size: 13.5px; color: var(--ink-700);
}

/* ── "3 בהצעה · עריכה" ──────────────────────────────────────────────────────
   Shown instead of a stepper when "+" would have to guess which of several
   different configurations to copy — the reported ספה card reading 2 over a
   five-seater and a seven-seater. */
.dish-many { display: flex; align-items: center; gap: 8px; }
.dish-many[hidden] { display: none; }
.dish-many-n {
  font-size: 13.5px; font-weight: 700; color: var(--brand-800); white-space: nowrap;
}
.dish-many-edit {
  border: 1px solid var(--line-strong); background: #fff; color: var(--brand-800);
  border-radius: var(--radius-pill); padding: 6px 13px;
  font-size: 13.5px; font-weight: 600; cursor: pointer; white-space: nowrap;
}
.dish-many-edit:hover, .dish-many-edit:focus-visible { background: var(--brand-50); }

/* Where the cart lands when you arrive from that button. */
.cart-line.is-focus { background: var(--brand-50); border-radius: var(--radius); }
/* Says a line is in the deal without printing a second, competing number. */
.cart-line-deal {
  font-size: 11.5px; font-weight: 700; white-space: nowrap;
  color: var(--accent-600); background: var(--accent-100);
  border-radius: 999px; padding: 2px 7px;
}
.cart-line-edit {
  font-size: 13.5px; font-weight: 600; color: var(--brand-800);
  padding: 8px 11px; border-radius: var(--radius-pill);
  border: 1.5px solid var(--line-strong); background: #fff;
}
.cart-line-x {
  width: 34px; height: 34px; border-radius: 50%; display: grid; place-items: center;
  color: var(--ink-500); border: 1.5px solid transparent; background: none; flex: none;
}
.cart-line-x svg { width: 15px; height: 15px; }
.cart-line-x:hover { background: #fde8e8; color: #a33226; border-color: #e7b9b3; }

.calc-pending {
  font-size: 14.5px; color: var(--warn-ink); background: var(--warn-bg);
  border: 1px solid var(--warn-line); border-radius: var(--radius);
  padding: 10px 13px; margin: 0 0 14px;
}
.calc-clear {
  display: block; margin: 18px auto 0; font-size: 14px;
  color: var(--ink-500); text-decoration: underline; background: none; border: none;
}
.calc-clear:hover { color: #a33226; }

/* ── The cart bar ─────────────────────────────────────────────────────────── */
/* Unlike v2 this shows at every width: it is now the only way into the
   basket, so hiding it on desktop would hide the basket. */
.calc-bar {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 70;
  padding: 0 12px calc(12px + env(safe-area-inset-bottom));
  pointer-events: none;
}
.calc-bar[hidden] { display: none; }
.calc-bar-inner { width: min(100%, 560px); margin-inline: auto; pointer-events: auto; }
.calc-bar-btn {
  display: flex; align-items: center; gap: 12px; width: 100%;
  padding: 13px 16px; border: none; border-radius: var(--radius-pill);
  background: var(--brand-800); color: #fff; cursor: pointer;
  box-shadow: 0 6px 24px rgba(6, 50, 54, .3);
  transition: background .15s ease;
}
.calc-bar-btn:hover { background: var(--brand-900); }
.calc-bar-count {
  flex: none; min-width: 28px; height: 28px; padding: 0 8px; border-radius: var(--radius-pill);
  display: grid; place-items: center;
  background: rgba(255, 255, 255, .22); font-weight: 800; font-size: 15px;
}
.calc-bar-label { flex: 1; text-align: center; font-weight: 700; font-size: 16.5px; }
.calc-bar-amt { flex: none; font-weight: 800; font-size: 17px; font-variant-numeric: tabular-nums; }

/* The bar floats over the page, so the last thing on it needs room to clear. */
/* The bar, plus room for the accessibility button that floats above it.
   --calc-bar-h is measured by renderBar(); the fallback is the one-row
   height, for the instant before the first render. */
body.has-calc-bar { padding-bottom: calc(var(--calc-bar-h, 66px) + 70px); }

@media (max-width: 759px) {
  body.has-calc-bar .fab-dock { display: none; }
  body.has-calc-bar .a11y-fab { bottom: calc(var(--calc-bar-h, 66px) + 16px); }
  body.has-calc-bar .a11y-panel { bottom: calc(var(--calc-bar-h, 66px) + 78px); }
}
@media (min-width: 760px) {
  body.has-calc-bar .fab-dock { bottom: 86px; }
}

/* ── Motion ───────────────────────────────────────────────────────────────── */
/* The sheet must still open and close — only the travel goes away. */
/* No travel, but the sheet still appears and still drags. */
@media (prefers-reduced-motion: reduce) {
  .sheet { animation: none; }
  .sheet-scrim { animation: none; }
}
html[data-a11y-no-motion="on"] .sheet { animation: none !important; }
html[data-a11y-no-motion="on"] .sheet-scrim { animation: none !important; }

/* ── High contrast ────────────────────────────────────────────────────────── */
/* --brand-50 becomes white in this mode, so every tint used to separate
   things here has to be replaced with a border or an outline. */
html[data-a11y-contrast="on"] .dish,
html[data-a11y-contrast="on"] .cart-line,
html[data-a11y-contrast="on"] .calc-tabs { border-color: #333; }
html[data-a11y-contrast="on"] .dish.is-in { background: #fff; outline: 2px solid #000; outline-offset: -2px; }
html[data-a11y-contrast="on"] .dish-art,
html[data-a11y-contrast="on"] .cart-line-art,
html[data-a11y-contrast="on"] .sheet-art { background: #fff; border: 1px solid #333; }
html[data-a11y-contrast="on"] .sheet { border: 2px solid #000; }
html[data-a11y-contrast="on"] .sheet-scrim { background: rgba(0, 0, 0, .72); }
html[data-a11y-contrast="on"] .tab.is-on { background: #000; }

/* ── owner note on /about/ ────────────────────────────────────────────────── */
.owner-note {
  max-width: 900px; margin: 0 auto 26px; padding: 22px 24px;
  background: var(--brand-50); border: 1px solid var(--brand-100); border-radius: var(--radius-lg);
}
.owner-note p { font-size: 16.5px; }
.owner-note p:last-of-type { margin-bottom: 16px; }
.owner-note .hero-cta { margin-bottom: 0; }



/* High-contrast mode must reach the new components too. */
html[data-a11y-contrast="on"] .calc-bar { border-color: #333; }


/* ═══════════════════════════════════════════════════════════════════════════
   Article page — illustration, meta, contents, engagement
   The old template put 2,679px of unbroken text between the title and the
   first visual element. Everything here exists to break that up.
   ═══════════════════════════════════════════════════════════════════════════ */

.article-head { margin-bottom: 20px; }

.article-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 8px;
  font-size: 14.5px; color: var(--ink-500);
  padding-bottom: 18px; border-bottom: 1px solid var(--line);
}
.article-meta .article-author { font-weight: 600; color: var(--ink-700); }

.article-hero { margin: 0 0 26px; }
.article-hero .illus,
.card-thumb .illus { width: 100%; height: auto; display: block; border-radius: var(--radius-lg); }
.article-hero .illus { box-shadow: var(--shadow-sm); }

/* Contents */
.toc {
  background: var(--surface-alt); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 18px 20px; margin-bottom: 30px;
}
.toc-title { font-size: 15px; margin: 0 0 10px; color: var(--ink-700); letter-spacing: .02em; }
.toc ol { margin: 0; padding-inline-start: 20px; display: grid; gap: 7px; }
.toc li { font-size: 15.5px; }
.toc a { color: var(--brand-800); text-decoration: none; }
.toc a:hover { text-decoration: underline; }
.toc li::marker { color: var(--brand-600); font-weight: 600; }

/* Callout for the "what not to do" passages that recur across the guides */
.article-body .notice { margin: 24px 0; }

/* Engagement strip */
.engage {
  margin: 36px 0 0; padding: 18px 0 0; border-top: 1px solid var(--line);
}
.engage-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 14px; justify-content: space-between; }

.engage-like {
  display: inline-flex; align-items: center; gap: 9px;
  padding: 10px 18px; border-radius: var(--radius-pill);
  border: 2px solid var(--line-strong); background: #fff;
  font-size: 15.5px; font-weight: 600; color: var(--ink-700);
  transition: background-color .18s ease, border-color .18s ease, color .18s ease;
}
.engage-like svg { width: 19px; height: 19px; transition: transform .2s ease; }
.engage-like:hover { border-color: var(--brand-700); color: var(--brand-800); }
.engage-like[aria-pressed="true"] {
  background: var(--brand-50); border-color: var(--brand-700); color: var(--brand-800);
}
.engage-like[aria-pressed="true"] svg { fill: var(--brand-700); stroke: var(--brand-700); animation: like-pop .32s ease; }
.engage-like-count { font-weight: 700; color: var(--brand-800); }
@keyframes like-pop { 0% { transform: scale(1); } 45% { transform: scale(1.28); } 100% { transform: scale(1); } }

.engage-share { display: flex; align-items: center; gap: 7px; }
.engage-share-label { font-size: 14.5px; color: var(--ink-500); }
.engage-btn {
  width: 40px; height: 40px; border-radius: 50%;
  display: grid; place-items: center;
  border: 2px solid var(--line-strong); background: #fff; color: var(--ink-700);
  transition: border-color .18s ease, color .18s ease, transform .18s ease;
}
.engage-btn svg { width: 19px; height: 19px; }
.engage-btn:hover { border-color: var(--brand-700); color: var(--brand-800); transform: translateY(-2px); text-decoration: none; }
.engage-btn.is-copied { border-color: var(--ok); color: var(--ok); }

.engage-views { margin: 12px 0 0; font-size: 14px; color: var(--ink-500); }
.engage-views[hidden] { display: none; }

/* Guide cards with a thumbnail */
.card-guide { padding: 0; overflow: hidden; }
.card-thumb { background: var(--brand-50); }
.card-thumb .illus { border-radius: 0; }
.card-guide h3 { font-size: 17px; line-height: 1.35; }
.card-guide p { font-size: 14.5px; }

/* ═══════════════════════════════════════════════════════════════════════════
   Motion — all of it opt-out. Content must never be left invisible.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Scoped to .js on purpose — see the inline head script. Without scripting
   these selectors never match and everything renders normally. */
.js [data-reveal] { opacity: 0; transform: translateY(18px); }
[data-reveal].is-in { opacity: 1; transform: none; transition: opacity .6s ease, transform .6s cubic-bezier(.2, .7, .3, 1); }
.js [data-reveal-stagger] > * { opacity: 0; transform: translateY(16px); }
[data-reveal-stagger].is-in > * { opacity: 1; transform: none; transition: opacity .55s ease, transform .55s cubic-bezier(.2, .7, .3, 1); }
[data-reveal-stagger].is-in > *:nth-child(1) { transition-delay: .00s; }
[data-reveal-stagger].is-in > *:nth-child(2) { transition-delay: .07s; }
[data-reveal-stagger].is-in > *:nth-child(3) { transition-delay: .14s; }
[data-reveal-stagger].is-in > *:nth-child(4) { transition-delay: .21s; }
[data-reveal-stagger].is-in > *:nth-child(5) { transition-delay: .28s; }
[data-reveal-stagger].is-in > *:nth-child(6) { transition-delay: .35s; }

/* Three independent escape hatches, and each must leave content VISIBLE. */
.no-motion [data-reveal],
.no-motion [data-reveal-stagger] > * { opacity: 1 !important; transform: none !important; transition: none !important; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal], [data-reveal-stagger] > * { opacity: 1 !important; transform: none !important; transition: none !important; }
}
html[data-a11y-no-motion="on"] [data-reveal],
html[data-a11y-no-motion="on"] [data-reveal-stagger] > * { opacity: 1 !important; transform: none !important; }

/* Hero with an illustration beside the copy */
.hero-grid { display: grid; gap: 28px; align-items: center; }
.hero-grid > * { min-width: 0; }
@media (min-width: 900px) { .hero-grid { grid-template-columns: 1.15fr .85fr; gap: 44px; } }
.hero-art { position: relative; }

/**
 * ⚠️  THE DRAWING'S REDUCED-MOTION RULES WENT WITH THE DRAWING, AND
 *     NOTHING REPLACED THEM — BECAUSE A PHOTOGRAPH DOES NOT MOVE.
 *
 *     What used to live here was `.illus-hero animate { display: none }`
 *     for both `prefers-reduced-motion` and the site's own
 *     `data-a11y-no-motion` switch, because SMIL was the only kind of
 *     motion the toggle could reach. There are no `<animate>` elements on
 *     this page any more, so the rules had nothing left to hide.
 *
 *     That is a hole, not a tidy-up: /accessibility/ promises in public
 *     that somebody who asks for less motion gets it, and a Ken Burns
 *     drift added to this image tomorrow would sail past both switches.
 *     site/hero-art-check.mjs refuses `animation` and `transition` in
 *     this block for exactly that reason — if motion ever belongs here,
 *     it arrives WITH its three escape hatches or it does not arrive.
 */
.hero-art img {
  width: 100%;
  height: auto;
  border-radius: var(--radius-lg, 18px);
  /* The same shadow the drawing carried, so the hero keeps its depth. */
  filter: drop-shadow(0 18px 38px rgba(6, 50, 54, .18));
}

html[data-a11y-contrast="on"] .hero-art img { outline: 2px solid #000; outline-offset: -2px; }
@media (max-width: 899px) { .hero-art { max-width: 420px; margin-inline: auto; order: -1; } }

html[data-a11y-contrast="on"] .article-hero .illus,
html[data-a11y-contrast="on"] .card-thumb .illus { outline: 2px solid #000; outline-offset: -2px; }


/* ═══════════════════════════════════════════════════════════════════════════
   Deal bar — today's offer plus a countdown, above the header
   ═══════════════════════════════════════════════════════════════════════════ */







@media (max-width: 720px) {
  /* Wrapping made this 146px tall — a third of the fold on a phone, before
     the visitor had seen anything. One compact row instead: the offer,
     truncated, the countdown, and a way out. The CTA goes; the headline
     below it already leads to the calculator. */
  /* The condition never shrinks; the offer text takes the ellipsis. */
  /* Same treatment as the clock it replaces on a daily deal. */
}

/* The deal appears in the quote summary too, so the banner and the price
   can never tell the customer two different things. */
.calc-deal {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: var(--brand-50); border: 1px solid var(--brand-100);
  border-radius: var(--radius); padding: 10px 14px; margin-bottom: 12px;
  font-size: 14.5px;
}
.calc-deal-label { font-weight: 600; color: var(--brand-800); }
.calc-deal-amount { font-weight: 800; color: var(--ok); white-space: nowrap; }
.calc-subtotal {
  display: flex; justify-content: space-between; font-size: 14.5px;
  color: var(--ink-500); margin-bottom: 6px;
}
.calc-subtotal s { text-decoration-thickness: 1.5px; }



/* ═══════════════════════════════════════════════════════════════════════════
   Guides index — a lead article, filters, and cards that say how long they are
   ═══════════════════════════════════════════════════════════════════════════ */

.guide-lead {
  display: grid; gap: 0; margin-bottom: 28px;
  background: #fff; border: 1px solid var(--line); border-radius: var(--radius-lg);
  overflow: hidden; box-shadow: var(--shadow-sm); color: inherit;
  transition: transform .18s ease, box-shadow .18s ease, border-color .18s ease;
}
.guide-lead:hover { transform: translateY(-2px); box-shadow: var(--shadow-md); border-color: var(--brand-100); text-decoration: none; }
.guide-lead-art { background: var(--brand-50); }
.guide-lead-art .illus { width: 100%; height: auto; display: block; border-radius: 0; }
.guide-lead-text { padding: 22px; }
.guide-lead-text h2 { font-size: clamp(20px, 3vw, 26px); margin: 8px 0 8px; }
.guide-lead-text p { color: var(--ink-500); margin-bottom: 10px; }
.guide-lead-meta { font-size: 14px; color: var(--ink-500); }
@media (min-width: 760px) {
  .guide-lead { grid-template-columns: .9fr 1.1fr; align-items: center; }
  .guide-lead-text { padding: 28px 30px; }
}

.guide-filter { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 20px; }
.filter-chip {
  padding: 8px 16px; border-radius: var(--radius-pill); font-size: 14.5px; font-weight: 600;
  border: 2px solid var(--line-strong); background: #fff; color: var(--ink-700);
  transition: background-color .16s ease, border-color .16s ease, color .16s ease;
}
.filter-chip:hover { border-color: var(--brand-700); color: var(--brand-800); }
.filter-chip.is-on { background: var(--brand-700); border-color: var(--brand-700); color: #fff; }

.guide-count { font-size: 14.5px; color: var(--ink-500); margin: 0 0 16px; }
.guide-count[hidden], .guide-empty[hidden] { display: none; }
.guide-empty { text-align: center; padding: 30px 0; color: var(--ink-500); }

/* Image on top at full card width — at 375px that renders the artwork around
   343x172, the same size as an article hero and comfortably legible. The
   earlier 104px square thumb made every illustration half-size and unreadable.
   The length this costs on /guides/ is paid for by the category filter. */
@media (max-width: 620px) {
  .card-guide .card-body { padding: 14px 16px 16px; }
  .card-guide h3 { font-size: 16.5px; }
}

.card-guide { display: flex; flex-direction: column; }
.card-guide .card-thumb { display: block; }
.card-guide .card-thumb .illus { width: 100%; height: auto; display: block; border-radius: 0; }
.card-guide .card-body { padding: 16px 18px 18px; }
.card-guide .card-meta { font-size: 13px; color: var(--ink-500); margin: 0 0 6px; }
.card-guide .card-cat { color: var(--brand-800); font-weight: 600; }
.card-guide h3 { margin: 0 0 6px; }
.card-guide p { margin: 0; }
/* Two lines keeps every card the same height in a grid row. */
.card-guide .card-desc {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; font-size: 14.5px;
}
.card-guide[hidden] { display: none; }


/* ═══════════════════════════════════════════════════════════════════════════
   Trust ticker — a continuously scrolling strip under the hero
   ═══════════════════════════════════════════════════════════════════════════ */

/* Grid and flex children default to min-width:auto, so the max-content track
   inside pushed this to 1,579px instead of clipping. Both properties are
   needed: min-width:0 lets it shrink, max-width caps it. */
/* The hero's trust strip was a marquee here. It scrolled a 790px list
   through a 619px slot, so one claim was always cut mid-word at the inline
   edge — see the note over trustList() in site/pages.mjs. It is a static
   wrapped row now (.trust, near the top of this file), and the ticker had
   no other user. */



/* ═══════════════════════════════════════════════════════════════════════════
   Lead capture — three optional details before the handoff
   Never a gate: the WhatsApp button sits below and works regardless.
   ═══════════════════════════════════════════════════════════════════════════ */

.calc-ref {
  margin: 0 0 12px; font-size: 13.5px; color: var(--ink-500);
  letter-spacing: .04em; font-variant-numeric: tabular-nums;
}

.lead {
  background: var(--surface-alt); border: 1px solid var(--line);
  border-radius: var(--radius-lg); padding: 16px 18px; margin-bottom: 14px;
}
.lead-title { margin: 0 0 4px; font-size: 16.5px; }
.lead-sub { margin: 0 0 14px; font-size: 14px; color: var(--ink-500); }

.lead-field { border: none; margin: 0 0 12px; padding: 0; display: grid; gap: 6px; }
.lead-field:last-child { margin-bottom: 0; }
.lead-field > label,
.lead-field > legend { font-size: 14px; font-weight: 600; color: var(--ink-700); padding: 0; }
.lead-field input,
.lead-field select { padding: 10px 13px; font-size: 15.5px; border-radius: var(--radius); background: #fff; min-block-size: 46px; }
.lead-field select { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--ink-500) 50%), linear-gradient(135deg, var(--ink-500) 50%, transparent 50%); background-position: 14px calc(50% - 2px), 19px calc(50% - 2px); background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; padding-inline-start: 34px; }
.lead-field .opt-chips { gap: 7px; }


@media (min-width: 560px) {
  /* Name and town read as one row once there is space for them. */
  /**
   * ⚠️  `align-items: start`, AND IT IS THE SAME FIX AS .gate-form's.
   *
   *     Reported from a real browser: the name box 71px tall against
   *     the phone's 50. The phone CELL is taller because it carries a
   *     hint under the input, and a stretch grid makes the name INPUT
   *     grow to match the row. It was fixed on .gate-form, where those
   *     two fields used to live.
   *
   *     They moved here when the opening screen stopped taking
   *     details, and the fix did not travel with them — so the same
   *     defect came back, 83px against 50px, in the new place. The
   *     browser test followed the fields and caught it.
   */
  .lead { display: grid; grid-template-columns: 1fr 1fr; gap: 0 14px; align-items: start; }
  .lead-title, .lead-sub { grid-column: 1 / -1; }
  /* Named, not counted. :nth-of-type counts div.lead-field and
     fieldset.lead-field as separate sequences, so the pairing depended on
     both the order of the fields and their element types staying put. */
  .lead-field-wide { grid-column: 1 / -1; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   Shop — product cards, product page, cart drawer
   ═══════════════════════════════════════════════════════════════════════════ */

.card-product { display: flex; flex-direction: column; padding: 0; overflow: hidden; }
.card-product .card-thumb { display: block; background: var(--brand-50); }
.card-product .card-thumb .illus { width: 100%; height: auto; display: block; border-radius: 0; }
.card-product .card-body { padding: 16px 18px 18px; display: flex; flex-direction: column; flex: 1; }
.card-product h3 { margin: 0 0 6px; font-size: 17px; line-height: 1.3; }
.product-tagline {
  color: var(--ink-500); font-size: 14.5px; margin: 0 0 14px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.product-foot { margin-top: auto; display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.product-price { font-weight: 800; font-size: 19px; color: var(--brand-800); white-space: nowrap; }
.product-price s { font-weight: 500; font-size: 15px; color: var(--ink-500); }

.product-page { display: grid; gap: 24px; }
@media (min-width: 860px) { .product-page { grid-template-columns: 1fr 1fr; gap: 40px; align-items: start; } }
.product-art { background: var(--brand-50); border-radius: var(--radius-lg); overflow: hidden; }
.product-art .illus { width: 100%; height: auto; display: block; }
.product-cat { font-size: 14px; color: var(--brand-800); font-weight: 600; margin: 0 0 6px; }
.product-info h1 { font-size: clamp(24px, 4.5vw, 34px); margin-bottom: .3em; }
.product-price-lg { font-size: 30px; margin: 16px 0 4px; }
.product-price-lg small { font-size: 15px; font-weight: 500; color: var(--ink-500); margin-inline-start: 8px; }
.product-saving { color: var(--ok); font-weight: 600; font-size: 15px; margin: 0 0 14px; }
.product-ship { font-size: 14px; color: var(--ink-500); text-align: center; margin: 10px 0 0; }
.product-bullets { margin-top: 20px; }

/* Cart button in the header */
.cart-btn {
  position: relative; width: 42px; height: 42px; border-radius: 50%;
  display: grid; place-items: center; border: 2px solid var(--line-strong);
  background: #fff; color: var(--brand-800); flex-shrink: 0;
}
.cart-btn:hover { border-color: var(--brand-700); background: var(--brand-50); }
.cart-btn svg { width: 19px; height: 19px; }
.cart-count {
  position: absolute; top: -5px; inset-inline-end: -5px;
  min-width: 19px; height: 19px; padding: 0 5px; border-radius: 10px;
  background: var(--accent-600); color: #fff;
  font-size: 11.5px; font-weight: 800; line-height: 19px; text-align: center;
}
.cart-count[hidden] { display: none; }

/* Cart drawer */
.cart-panel {
  position: fixed; inset-inline-end: 12px; top: calc(var(--header-h) + 12px); z-index: 80;
  width: min(calc(100vw - 24px), 380px); max-height: calc(100vh - var(--header-h) - 24px);
  overflow-y: auto; background: #fff;
  border: 1px solid var(--line-strong); border-radius: var(--radius-lg);
  box-shadow: var(--shadow-lg);
}
.cart-panel[hidden] { display: none; }
.cart-head {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 18px; border-bottom: 1px solid var(--line);
  position: sticky; top: 0; background: #fff; border-radius: var(--radius-lg) var(--radius-lg) 0 0;
}
.cart-head h2 { margin: 0; font-size: 17px; }
.cart-head .chat-close { color: var(--ink-700); }
.cart-body { padding: 16px 18px 18px; }
.cart-empty { color: var(--ink-500); font-size: 15px; margin: 0; text-align: center; padding: 18px 0; }

.cart-lines { list-style: none; margin: 0 0 14px; padding: 0; }
.cart-lines li {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 0; border-bottom: 1px dashed var(--line);
}
.cart-name { flex: 1; font-size: 14.5px; font-weight: 500; min-width: 0; }
.cart-line-total { font-weight: 700; color: var(--brand-800); white-space: nowrap; font-size: 14.5px; }

.cart-summary { border-top: 2px solid var(--brand-100); padding-top: 12px; margin-bottom: 14px; }
.cart-row { display: flex; justify-content: space-between; font-size: 14.5px; margin-bottom: 6px; color: var(--ink-700); }
.cart-row-total { font-size: 18px; font-weight: 800; color: var(--brand-800); margin-top: 8px; }
.cart-nudge { font-size: 13.5px; color: var(--accent-600); margin: 4px 0 0; font-weight: 600; }

/* Under the job minimum. Warm, not red: this is an invitation to add
   something, not an error the customer made. */
/* .cart-short is gone — replaced by the .cart-min meter above, which
   also says when the minimum IS met. */
html[data-a11y-contrast="on"] .cart-min-t { color: #000; }
html[data-a11y-contrast="on"] .cart-min-bar { border: 1px solid #333; }
.cart-pay { margin-bottom: 10px; min-height: 0; }
.cart-error { color: var(--warn-ink); background: var(--warn-bg); border: 1px solid var(--warn-line); border-radius: var(--radius); padding: 10px 12px; font-size: 14px; margin: 10px 0 0; }
.cart-done-title { margin: 0 0 8px; font-size: 18px; color: var(--ok); }

@media (max-width: 620px) {
  .cart-panel { inset-inline: 8px; width: auto; }
}

html[data-a11y-contrast="on"] .cart-panel,
html[data-a11y-contrast="on"] .card-product { border-color: #333; }

/* ── One contextual product inside a guide ────────────────────────────────── */
.guide-product {
  margin: 30px 0; padding: 18px 20px;
  background: var(--brand-50); border: 1px solid var(--brand-100);
  border-radius: var(--radius-lg);
}
.guide-product-kicker {
  margin: 0 0 12px; font-size: 13px; font-weight: 700;
  letter-spacing: .02em; color: var(--brand-800); text-transform: none;
}
.guide-product-row { display: flex; align-items: center; gap: 18px; }
.guide-product-art { flex: 0 0 132px; border-radius: var(--radius); overflow: hidden; }
.guide-product-art svg { display: block; width: 100%; height: auto; }
.guide-product-text { min-width: 0; flex: 1; }
.guide-product-text h2 { margin: 0 0 4px; font-size: 19px; }
.guide-product-text p { margin: 0 0 12px; color: var(--ink-700); font-size: 15px; }
.guide-product-foot { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }

@media (max-width: 560px) {
  .guide-product-row { flex-direction: column; align-items: stretch; gap: 12px; }
  .guide-product-art { flex: none; max-width: 200px; }
}

/* The one required field in the lead form. Colour alone would not say it. */
.lead-field .req { font-weight: 500; color: var(--ink-500); font-size: 14px; }

/* ── Service cards ────────────────────────────────────────────────────────── */
/* Home page and /services/. Same shape as .card-product and .card-guide: a
   tinted band carrying the illustration, then the body. The front page used
   to run a price teaser here AND these cards directly below it, printing the
   same four prices twice in two different visual languages. */
.card-svc { position: relative; display: flex; flex-direction: column; padding: 0; overflow: hidden; }

/* A gradient, not flat --brand-50. These cards sit on section.alt, which is
   rgb(244,250,251) — within six values of --brand-50 on every channel. A flat
   tint made the illustration band vanish into the page behind the card. */
.card-svc .card-thumb {
  display: grid; place-items: center; padding: 10px 0;
  background: linear-gradient(170deg, var(--brand-100), var(--brand-50) 72%);
  border-bottom: 1px solid var(--line);
}
.card-svc .svc-illus { width: 128px; height: 128px; display: block; transition: transform .2s ease; }
.card-svc .card-body { padding: 18px 20px 20px; display: flex; flex-direction: column; flex: 1; }
.card-svc h3 { margin: 0 0 6px; }
.card-svc p { flex: 1; }
.card-svc .card-price { margin-top: 14px; }

/* The heading's link covers the card, so the whole thing is one target
   without a second link appearing in the accessibility tree. */
.card-svc h3 a::after { content: ''; position: absolute; inset: 0; }
.card-svc:focus-within { border-color: var(--brand-700); box-shadow: var(--shadow-md); }
.card-svc h3 a:focus-visible { outline: none; }
.card-svc:focus-within::after {
  content: ''; position: absolute; inset: -3px; border-radius: var(--radius-lg);
  outline: 3px solid var(--brand-700); outline-offset: 0; pointer-events: none;
}
@media (hover: hover) { .card-svc:hover .svc-illus { transform: scale(1.04); } }

/* One column of five illustrated cards is a long scroll on a phone. The band
   shrinks rather than the type: the drawing is what can afford to be smaller. */
@media (max-width: 619px) {
  .card-svc .card-thumb { padding: 4px 0; }
  .card-svc .svc-illus { width: 96px; height: 96px; }
  .card-svc .card-body { padding: 14px 18px 16px; }
}

/* Five services in a three-wide grid leaves two stranded against the start
   edge. Flex-wrap centres the short last row; grid cannot without knowing
   the count. */
@media (min-width: 900px) {
  .grid-svc { display: flex; flex-wrap: wrap; justify-content: center; }
  .grid-svc .card-svc { flex: 0 1 calc(33.333% - 11px); max-width: calc(33.333% - 11px); }
}

/* One route onward, after the cards rather than competing with them. */
.svc-cta { max-width: 620px; margin: 30px auto 0; text-align: center; }
.svc-cta p { color: var(--ink-500); font-size: 16px; margin: 0 0 18px; }
.svc-cta-actions { display: flex; flex-wrap: wrap; gap: 12px; justify-content: center; }

html[data-a11y-contrast="on"] .card-svc .card-thumb { background: #fff; border-bottom: 1px solid #333; }

/* ── Agent application form (/join/) ──────────────────────────────────────── */
/* A real <form> that posts without JavaScript. The person filling it in is a
   tradesperson on a phone, so the targets are large and the labels are real. */
.apply {
  background: var(--surface); border: 1px solid var(--line);
  border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
  padding: 22px;
}
.apply .field { margin-bottom: 20px; }
.apply fieldset.field { border: none; padding: 0; }
.apply legend { font-weight: 600; font-size: 16px; margin-bottom: 10px; padding: 0; }
.apply textarea { width: 100%; font: inherit; }

.check-grid { display: grid; gap: 4px; grid-template-columns: 1fr; }
@media (min-width: 480px) { .check-grid { grid-template-columns: 1fr 1fr; } }
@media (min-width: 720px) { .check-grid { grid-template-columns: repeat(3, 1fr); } }

/* 44px rows, and the whole row is the label — a checkbox on its own is a
   6mm target on a phone. */
.check {
  display: flex; align-items: center; gap: 10px;
  min-height: 44px; padding: 6px 10px;
  border-radius: var(--radius); font-size: 15.5px; cursor: pointer;
}
.check:hover { background: var(--brand-50); }
.check input { width: 20px; height: 20px; accent-color: var(--brand-700); flex: none; }
.check:focus-within { outline: 3px solid var(--brand-500); outline-offset: 2px; }

.apply-wa { font-weight: 600; text-decoration: underline; }

html[data-a11y-contrast="on"] .apply { border-color: #333; }
html[data-a11y-contrast="on"] .check:hover { background: #eee; }

/* ─── The booking page ─────────────────────────────────────────────────────
   /booking/ — the customer confirms the hour we proposed, or picks another
   from what is genuinely free. Reached only by a token in a link we sent, so
   it is noindex and never cached.
   ────────────────────────────────────────────────────────────────────── */

.booking-summary {
  display: grid; gap: 2px 16px; margin: 24px 0;
  padding: 18px 20px; background: var(--brand-50); border-radius: var(--radius-lg);
}
@media (min-width: 480px) { .booking-summary { grid-template-columns: max-content 1fr; } }
.booking-summary dt { color: var(--brand-800); font-weight: 700; font-size: 14px; }
.booking-summary dd { margin: 0 0 10px; }
.booking-summary dd:last-child { margin-bottom: 0; }

.booking-proposed {
  border: 2px solid var(--brand-500); border-radius: var(--radius-lg);
  padding: 18px 20px; margin-bottom: 8px;
}
.booking-when { margin: 0 0 14px; display: grid; gap: 2px; }
.booking-when span { font-size: 14px; color: var(--ink-500); }
.booking-when strong { font-size: 21px; color: var(--brand-900); }
.booking-ok { margin: 0; font-weight: 700; color: var(--ok); }

.booking-day { border: 0; padding: 0; margin: 0 0 18px; }
.booking-day legend { font-weight: 700; color: var(--brand-800); padding: 0 0 8px; }
.booking-times { display: flex; flex-wrap: wrap; gap: 8px; }

/* Each hour is a button, and each button is a target a thumb can hit. */
.booking-time {
  min-width: 88px; min-height: 48px;
  font-variant-numeric: tabular-nums; font-size: 17px; font-weight: 700;
}

.booking-none { margin-top: 28px; }
.booking-none summary { cursor: pointer; color: var(--brand-700); font-weight: 600; padding: 8px 0; }
.booking-none textarea {
  width: 100%; padding: 12px; font: inherit; min-height: 88px;
  border: 2px solid var(--line-strong); border-radius: var(--radius-lg);
}

/* ─── Touch targets in the header ──────────────────────────────────────────
   Measured on a phone: the menu button was 40px and the header CTA 37px,
   both under the 44px a thumb reliably hits. They are on every page, so the
   miss was everywhere.
   ────────────────────────────────────────────────────────────────────── */
@media (max-width: 900px) {
  .nav-toggle { min-height: 44px; min-width: 44px; }
  .header-cta { min-height: 44px; display: inline-flex; align-items: center; }
}

/* No clock on a daily deal — it ends at midnight and another begins, so a
   countdown on it never runs out. It says when it ends instead. */

/* The error lives with the field that caused it, not only on the send
   button at the bottom of a scrolling sheet. */
.field-err {
  margin: 6px 0 0; font-size: 13.5px; font-weight: 600;
  color: var(--danger-ink); display: flex; align-items: flex-start; gap: 5px;
}
/* `display:flex` beats the `hidden` attribute's UA `display:none`, so an
   empty error still drew its "!" marker under every clean field. */
.field-err[hidden] { display: none; }
.field-err::before { content: '!'; flex: none;
  inline-size: 16px; block-size: 16px; border-radius: 50%;
  background: var(--danger-ink); color: #fff;
  font-size: 11px; font-weight: 800; line-height: 16px; text-align: center;
}
.lead-field.has-err input,
.lead-field.has-err select { border-color: var(--danger-ink); }
.cta-note {
  margin: 8px 0 0; font-size: 13px; color: var(--ink-500);
  text-align: center; line-height: 1.5;
}
/* The same quiet line under «להמשיך לפרטים» — a different sentence
   under a different button, kept apart from .cta-note because a build
   gate pins the wording of that one. */
.step-note { margin: 8px 0 0; font-size: 13px; color: var(--ink-500); text-align: center; }
/* The way back to the basket from the details step. */
.cart-back {
  display: inline-block; margin: 0 0 14px; padding: 6px 0;
  border: none; background: none; cursor: pointer;
  font-size: 14.5px; font-weight: 600; color: var(--brand-700);
  min-block-size: 44px;
}
.cart-back:hover { text-decoration: underline; }

/* ── Floats, while a sheet is open ────────────────────────────────────────
   The WhatsApp bubble and "שאל את דור" sit in the bottom corners, which is
   exactly where the quote sheet puts its send button and where a thumb is
   already heading. Two other ways to contact us, on top of the one the
   customer is in the middle of using, is a choice they did not ask for.

   The accessibility button stays: it is how someone changes contrast or
   text size, and needing it does not pause while a dialog is open. */
body.sheet-open .fab-dock { display: none; }
/* ⚠️  The accessibility button was the one that was missed, and it is the
       one that hurts: z-index 65 against the drawer's 96 should have put it
       behind — but body.sheet-open never named it, and a floating circle
       parked over an open full-screen menu is the same complaint as the
       chat pill over the phone field. All the floaters, or none. */
body.sheet-open .a11y-fab,
body.sheet-open .a11y-panel { display: none; }

/* ── The sticky bottom action bar ───────────────────────────────────────────
   Shown by initCtaBar() in app.js only while neither the hero buttons nor
   the closing band is on screen, so the same two actions are never on the
   page twice. Ships hidden; with JavaScript off it never appears. */
.cta-bar {
  position: fixed; inset-inline: 0; bottom: 0; z-index: 70;
  display: flex; gap: 10px; justify-content: center;
  padding: 10px 14px calc(10px + env(safe-area-inset-bottom, 0px));
  background: var(--surface);
  border-block-start: 1px solid var(--line);
  box-shadow: 0 -4px 18px rgba(10, 27, 29, .10);
}
.cta-bar .btn { flex: 1 1 0; min-width: 0; max-width: 240px; justify-content: center; }
/* ⚠️  display:flex beats [hidden]'s display:none, so the bar shipped visible
       on every page and never hid again. Same bug as .field-err, and the
       same fix: say it explicitly. */
.cta-bar[hidden] { display: none; }

/* Room for it, and nothing else hovering underneath: WhatsApp is already
   in the bar, so the dock would be the third copy of the same action. */
body.has-cta-bar { padding-bottom: 80px; }
body.has-cta-bar .fab-dock { display: none; }
body.has-cta-bar .a11y-fab { bottom: 80px; }
body.has-cta-bar .a11y-panel { bottom: 142px; }
body.sheet-open .cta-bar { display: none; }

/* ── Opening hours, in two blocks ─────────────────────────────────────────
   "When we come out" and "when we answer" are different promises, and the
   site used to print one number for both — the wider one, which the
   scheduler would never honour. */
.hours-kind {
  margin: 0 0 4px; font-size: 13px; font-weight: 700;
  color: var(--ink-900); opacity: .75;
}
.hours-kind ~ .hours-kind { margin-top: 12px; }
[data-hours] ul { list-style: none; margin: 0; padding: 0; }
/* A range must not wrap mid-way: "08:00–" on one line and "16:00" on the
   next reads as two different times. */
[data-hours] .v { white-space: nowrap; }

/* A grouped price list: the service name once, not on every row. */
.price-group th {
  text-align: start; padding-top: 18px;
  font-size: 15px; font-weight: 800; color: var(--brand-900);
}
.price-table tbody:first-of-type .price-group th { padding-top: 0; }
.price-group a { color: inherit; }

/* For a question the page cannot answer. Leather has no list price — the
   work depends on the hide — so the page says so and hands over the one
   action that gets a real answer, with the message already written. */
.ask-box {
  margin-top: 14px; padding: 14px;
  background: var(--brand-50); border: 1px solid var(--brand-100);
  border-radius: var(--radius);
}
.ask-box p {
  margin: 0 0 12px; font-size: 14.5px;
  color: var(--ink-700); line-height: 1.6;
}

/* ═══════════════════════════════════════════════════════════════════════════
   Service pages
   ═══════════════════════════════════════════════════════════════════════════
   One template, five instances. The page has one job: get somebody who
   searched "ניקוי ספות באר שבע" from the headline to a price without
   scrolling past anything that is not helping.
   ═══════════════════════════════════════════════════════════════════════════ */

.svc-hero { padding-block: 40px 48px; }
.svc-hero-grid { display: grid; gap: 28px; align-items: center; }
.svc-hero h1 { margin: 0 0 12px; }
.svc-lead {
  margin: 0 0 20px; font-size: 17.5px;
  color: var(--ink-700); line-height: 1.65; max-width: 52ch;
}

/* The number is the reason most people opened the page. */
.svc-price {
  margin: 0 0 18px; display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
}
.svc-price bdi {
  font-size: 40px; font-weight: 800; line-height: 1;
  color: var(--brand-800); font-variant-numeric: tabular-nums;
}
.svc-price span { font-size: 15px; color: var(--ink-500); }

.svc-trust {
  list-style: none; margin: 0 0 24px; padding: 0;
  display: flex; flex-wrap: wrap; gap: 8px 20px;
}
.svc-trust li {
  display: flex; align-items: center; gap: 7px;
  font-size: 14.5px; color: var(--ink-700);
}
.svc-trust svg { width: 17px; height: 17px; color: var(--ok); flex-shrink: 0; }

/* The same list, standing on its own above the service grid rather than
   beside a hero illustration: centred, and with room to breathe. */
.svc-trust-wide {
  justify-content: center; gap: 10px 28px;
  margin: 0 auto 30px; max-width: 760px;
}

/* Fixed box, so the drawing cannot shift the text as it decodes. */
.svc-hero-art {
  justify-self: center; inline-size: min(280px, 72vw); aspect-ratio: 1;
  background: var(--brand-50); border-radius: var(--radius-lg);
  display: grid; place-items: center; padding: 22px;
}
.svc-hero-art svg { inline-size: 100%; block-size: 100%; display: block; }

@media (min-width: 900px) {
  .svc-hero-grid { grid-template-columns: 1fr auto; gap: 48px; }
  .svc-hero-art { inline-size: 300px; }
}

/* ── What we will not take ────────────────────────────────────────────────
   A refusal is information the customer needs before they book, not a grey
   footnote under a table. */
.wont-box {
  max-width: 700px; margin: 20px auto 0; padding: 16px;
  display: flex; gap: 12px; align-items: flex-start;
  background: var(--warn-bg2); border: 1px solid var(--warn-line2);
  border-radius: var(--radius);
}
.wont-i {
  flex: none; inline-size: 22px; block-size: 22px; border-radius: 50%;
  display: grid; place-items: center; background: var(--warn-ink2);
  color: #fff; font-weight: 800; font-size: 13px;
}
.wont-box strong { display: block; color: var(--warn-ink2); font-size: 15px; }
.wont-box p { margin: 4px 0 0; font-size: 14.5px; color: var(--ink-700); line-height: 1.6; }

/* ── Included / not included ─────────────────────────────────────────────── */
.ticks-no li { align-items: flex-start; }
.ticks-no .x {
  flex: none; inline-size: 17px; color: var(--danger-ink);
  font-weight: 700; line-height: 1.5;
}

/* ── How it works, per service ───────────────────────────────────────────── */
.how-grid {
  max-width: 900px; margin: 0 auto; display: grid; gap: 18px;
}
.how-grid > div {
  padding: 16px 18px; background: var(--surface);
  border: 1px solid var(--line); border-radius: var(--radius);
}
.how-grid dt {
  font-size: 13px; font-weight: 700; color: var(--brand-800);
  margin-bottom: 5px;
}
.how-grid dd { margin: 0; font-size: 15px; color: var(--ink-700); line-height: 1.65; }
@media (min-width: 760px) {
  .how-grid { grid-template-columns: 1fr 1fr; }
  .how-wide { grid-column: 1 / -1; }
}

/* ── FAQ ──────────────────────────────────────────────────────────────────
   <details>, so it works with no JavaScript and so the answer is in the DOM
   for the FAQPage structured data to be honest about. */
.faq-item {
  border: 1px solid var(--line); border-radius: var(--radius);
  background: var(--surface); margin-bottom: 10px;
}
.faq-item > summary {
  list-style: none; cursor: pointer;
  display: flex; align-items: center; gap: 12px;
  min-block-size: 56px; padding: 12px 18px;
  font-size: 16px; font-weight: 600; color: var(--ink-900);
}
.faq-item > summary::-webkit-details-marker { display: none; }
.faq-item > summary::after {
  content: '+'; margin-inline-start: auto; flex: none;
  color: var(--brand-700); font-size: 20px; font-weight: 700; line-height: 1;
}
.faq-item[open] > summary::after { content: '−'; }
.faq-item > summary:hover { background: var(--brand-50); }
.faq-item[open] > summary { border-bottom: 1px solid var(--line); }
.faq-item > p {
  margin: 0; padding: 14px 18px 18px;
  font-size: 15.5px; color: var(--ink-700); line-height: 1.7;
}

/* ── Service areas ───────────────────────────────────────────────────────── */
.area-chips {
  list-style: none; margin: 0 auto; padding: 0; max-width: 700px;
  display: flex; flex-wrap: wrap; gap: 8px; justify-content: center;
}
.area-chips li {
  padding: 7px 15px; border-radius: var(--radius-pill);
  background: var(--surface); border: 1px solid var(--line);
  font-size: 14.5px; color: var(--ink-700);
}

.svc-why {
  max-width: 68ch; margin: 0 auto; font-size: 16.5px;
  color: var(--ink-700); line-height: 1.8;
}

/* ── Before / after ───────────────────────────────────────────────────────
   Empty on purpose. The obvious filler is a stock photo of somebody else's
   clean sofa, and passing that off as our work would be the most plainly
   dishonest thing on the site. It waits for real jobs. */
.ba-placeholder { max-width: 760px; margin: 0 auto; display: grid; gap: 14px; grid-template-columns: 1fr 1fr; }
.ba-slot {
  aspect-ratio: 4 / 3; border-radius: var(--radius);
  border: 2px dashed var(--line-strong); background: var(--surface-alt);
  display: grid; place-items: center;
}
.ba-slot span { font-size: 15px; font-weight: 700; color: var(--ink-500); }
.ba-placeholder p {
  grid-column: 1 / -1; margin: 0; text-align: center;
  font-size: 14.5px; color: var(--ink-500); line-height: 1.7;
}

/* ── Today's deal, inside the price list ──────────────────────────────────
   Added by initDealPrices() in app.js after load, because a static page
   cannot know which day it is being read on. Nothing here renders unless
   that ran, so a visitor with JavaScript off sees the plain price list. */

/* ── Before and after, from real jobs ─────────────────────────────────────
   width and height on every <img> come from assetSize() in
   site/asset-url.mjs, which reads them out of the webp header. The space is
   reserved before the bytes arrive, and the reserved box cannot drift from
   the actual crop the way two hand-typed numbers eventually do.

   The halves stay side by side at every width, 375px included. A before and
   an after that need scrolling between them are not a comparison any more,
   and these differences are large enough to read at 165px. */
.ba-list { max-width: 980px; margin: 0 auto; display: grid; gap: 34px; }
.ba { margin: 0; }
.ba-pair { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; }
@media (min-width: 560px) { .ba-pair { gap: 14px; } }
.ba-half { position: relative; }
.ba-half img {
  inline-size: 100%; block-size: auto; display: block;
  border-radius: var(--radius); border: 1px solid var(--line);
  background: var(--surface-alt);
}
/* The label is a word, never a colour or a position. Which half is "before"
   has to survive greyscale, a screen reader, and a visitor who cannot tell
   the two photographs apart by eye — which is the honest default. */
.ba-tag {
  position: absolute; inset-block-start: 8px; inset-inline-start: 8px;
  background: var(--ink-900); color: #fff;
  font-size: 13px; font-weight: 700; line-height: 1;
  padding: 5px 9px; border-radius: 999px;
}
.ba figcaption {
  margin-block-start: 12px; font-size: 14.5px;
  color: var(--ink-500); line-height: 1.65;
}

/* ── The coverage map ─────────────────────────────────────────────────────
   Inline SVG, no map library, no tile server. Leaflet over OSM would send
   every visitor's IP and viewport to a third party — a new consent
   category and a line in the privacy notice, for "which towns do you drive
   to". This site has no third-party dependency but the webfont.
   ───────────────────────────────────────────────────────────────────── */
.cov-figure { position: relative; margin: 34px auto 0; max-inline-size: 760px; }
.cov-map { inline-size: 100%; block-size: auto; display: block; }
/* ⚠️  Sea, land, water — the map was one flat rectangle and nine dots,
       which is why it was reported missing even though it rendered. The
       geometry is Natural Earth 1:50m, downloaded and clipped by
       site/localities-build.mjs, never sketched. */
.cov-sea   { fill: #dceef2; }
.cov-land  { fill: #f3f7f2; stroke: var(--line-strong, #cdd6d4); stroke-width: 1.2; stroke-linejoin: round; }
.cov-water { fill: #bfe3ec; stroke: none; }

/* ⚠️  Sized in SVG user units, so they shrink with the map. At 375 the
       720-unit viewBox renders 343px wide — a 12-unit label lands at about
       5px and is not text any more. Below the breakpoint the labels go and
       the pins stay: the full list is directly above the map, so nothing
       is lost, and a row of illegible smudges is worse than none. */
.cov-label {
  font-size: 13px; font-weight: 600; fill: var(--ink-700);
  paint-order: stroke; stroke: #fff; stroke-width: 3.5px; stroke-linejoin: round;
}
.cov-label.is-base { font-size: 15px; font-weight: 800; fill: var(--brand-900); }
@media (max-width: 720px) { .cov-label { display: none; } }

.cov-pin { cursor: pointer; }
.cov-drop { fill: var(--brand-700); }
.cov-spark { fill: #fff; }
.cov-pin.is-base .cov-drop { fill: var(--accent-600, #f5a524); }
.cov-pin:focus-visible { outline: none; }
.cov-pin:focus-visible .cov-drop { stroke: var(--ink-900); stroke-width: 2.5; }

/* ⚠️  Hover only, and stopped entirely for anyone who asked for less
       motion. 85 pins breathing in unison is a page that cannot be read. */
@media (hover: hover) {
  .cov-pin:hover .cov-drop, .cov-pin:focus-visible .cov-drop { animation: cov-pulse 1.1s ease-in-out infinite; }
}
@keyframes cov-pulse {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.18); }
}
.cov-pin .cov-drop { transform-origin: 0 -7px; transition: transform .16s ease; }
.cov-pin:hover .cov-drop { transform: scale(1.18); }
@media (prefers-reduced-motion: reduce) {
  .cov-pin .cov-drop { animation: none !important; transition: none; }
}
html[data-a11y-no-motion="on"] .cov-pin .cov-drop { animation: none !important; }

.cov-cap { margin-block-start: 10px; font-size: 13.5px; color: var(--ink-500); text-align: center; }

.cov-pop {
  position: absolute; z-index: 2; top: 0; left: 0;   /* physical — see app.js */
  transform: translate(-50%, calc(-100% - 14px));
  background: #fff; border: 1px solid var(--line-strong); border-radius: var(--radius);
  box-shadow: 0 10px 30px rgba(10, 27, 29, .18);
  padding: 10px 13px; min-inline-size: 168px; text-align: center;
  display: grid; gap: 6px; justify-items: center;
}
.cov-pop[hidden] { display: none; }
.cov-pop-name { font-size: 15.5px; font-weight: 700; color: var(--ink-900); }
.cov-pop-name::before { content: '✓'; color: var(--ok); margin-inline-end: 5px; font-weight: 800; }
.cov-pop-drive { font-size: 13px; color: var(--ink-500); font-variant-numeric: tabular-nums; }
.cov-pop-cta { padding: 7px 15px; font-size: 14px; }

/* ── The icon set ─────────────────────────────────────────────────────────
   One sprite, emitted once per page by the layout. 24 grid, stroke 1.75,
   currentColor — so an icon takes the colour of the text it sits beside and
   they all restyle together. site/icon-check.mjs holds the rules.
   ───────────────────────────────────────────────────────────────────── */
.icon {
  inline-size: 1.15em; block-size: 1.15em; flex: none;
  /* ⚠️  On the wrapper too, not only on the <symbol>.
         iconRef() emits <svg class="icon"><use href="#i-…"></svg>, and the
         stroke lived only on the symbol — so the outer element computed
         `stroke: none` and anything that styled `.icon` directly had no
         colour to work with. Declared here, an icon takes the colour of
         the text beside it whatever route it arrived by. */
  stroke: currentColor; fill: none;
  /* ⚠️  Aligned to the text, not the line box. Left on the baseline an icon
         sits like a sticker under the words — which is exactly the thing
         the emoji were replaced for. */
  vertical-align: -0.16em;
}
/* Beside its own words, in a flex row. */
.icon + * { min-inline-size: 0; }

.sent-warn-ack .icon, .booking-ok .icon { color: var(--ok); }
.ticks-no .icon.x { color: var(--danger-ink); inline-size: 1.05em; block-size: 1.05em; }

/* ── מדרגות כמות ───────────────────────────────────────────────────────────
   ⚠️  שני מקומות, ושניהם ריקים בייצור היום — אף סגמנט לא מגדיר מדרגה בזמן
       ש-segment_prices_approved הוא false. הכללים כאן צריכים להחזיק ריק
       בלי להשאיר רווח, ולכן [hidden] ולא opacity.                         */

/* ⚠️  A FULL-WIDTH ROW, NOT A THIRD FLEX ITEM.
       `.dish` is a flex row of art-and-text plus the stepper. Appending
       the nudge to the card made it a third column: it squeezed between
       the two, wrapped «32 ₪» onto its own line, and pushed the item's
       own price out of the card. `flex-basis: 100%` with `wrap` on the
       parent puts it on a line of its own, under both. */
.dish { flex-wrap: wrap; }

.dish-tier {
  flex: 0 0 100%;
  display: flex;
  align-items: center;
  gap: 0.3rem;
  margin: 0;
  padding: 0.3rem 0.55rem;
  border-radius: 0.5rem;
  background: var(--brand-50, #eef7f6);
  color: var(--brand-700, #0f4c4a);
  font-size: 0.8rem;
  line-height: 1.35;
}

/* ⚠️  display:none and not visibility — a hidden nudge must take no row,
       or every card in the catalogue grows by a line for a feature that
       is switched off. */
.dish-tier[hidden] { display: none; }

.dish-tier-i,
.cart-line-tier-i {
  flex: none;
  inline-size: 1em;
  block-size: 1em;
}

.cart-line-tier {
  display: flex;
  align-items: center;
  gap: 0.25rem;
  margin-block-start: 0.15rem;
  color: var(--brand-deep, #0f4c4a);
  font-size: 0.78rem;
}

/* ⚠️  A nudge is advice, not an alarm. It must not out-shout the price it
       sits beneath, so it never animates and never takes the deal colour. */
@media (prefers-reduced-motion: no-preference) {
  .dish-tier { transition: none; }
}

/* ── הצעה נלווית ───────────────────────────────────────────────────────────
   ⚠️  שורה, לא חלון. אין position:fixed, אין z-index, אין אנימציית כניסה
       ואין טיימר — כל אחד מהם הופך אותה למשהו שקוטע, וזה בדיוק מה שהיא
       לא אמורה להיות.                                                   */

/* ⚠️  WRAPS ON THE CONTAINER, NOT ON THE VIEWPORT.
       The first version stacked below 420px of WINDOW. The desktop
       sidebar is ~300px wide at 1280, so the card stayed horizontal in
       the narrowest place it appears and the reason set one word per
       line. `flex-basis` on the body is the version of the rule that
       can actually see how much room there is. */
.xsell {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3, 12px);
  margin-block-start: 12px;
  padding: 10px 12px;
  border: 1.5px dashed var(--line, #d8e3e2);
  border-radius: var(--radius-lg, 14px);
  background: #fff;
}

.xsell-body {
  flex: 1 1 15rem;
  min-width: 0;
  display: flex;
  align-items: center;
  gap: 10px;
}

.xsell-art { flex: none; inline-size: 40px; block-size: 40px; }

.xsell-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.xsell-name { font-weight: 600; font-size: 0.9rem; }
.xsell-why { font-size: 0.78rem; color: var(--ink-soft, #5a6b6a); line-height: 1.35; }

.xsell-acts { display: flex; align-items: center; gap: 6px; flex: none; }

/* ⚠️  44px, like every other control here. A dismiss the customer has to
       aim at is a dismiss that gets mis-tapped into an add. */
.xsell-x {
  inline-size: 44px; block-size: 44px;
  display: grid; place-items: center;
  padding: 0; border: 0; border-radius: 50%;
  background: none; color: var(--ink-soft, #5a6b6a); cursor: pointer;
}
.xsell-x:hover { background: var(--brand-50, #eef7f6); color: var(--ink, #12302f); }
.xsell-x-i { inline-size: 18px; block-size: 18px; }

/* Once the body has taken its own line, the actions get one too. */
.xsell-acts { margin-inline-start: auto; }

/* ── תוספת מחוץ לשעות ──────────────────────────────────────────────────────
   ⚠️  שורה משלה, לא מספר שזז. סכום שמשתנה כשמסמנים תיבה בלי ששום דבר
       על המסך מסביר את התזוזה הוא ההפתעה היקרה ביותר שהמחשבון הזה יכול
       לייצר — הלקוח ראה מספר, רואה אחר, ואין לו דרך לדעת איזה מהם טעות. */
.calc-surcharge,
.calc-floor {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-3, 12px);
  padding-block: 4px;
  font-size: 0.88rem;
}

.calc-surcharge-label { color: var(--ink-soft, #5a6b6a); }
.calc-surcharge-amount { font-weight: 600; font-variant-numeric: tabular-nums; }

/* ⚠️  לא אזהרה. זו עובדה על המחיר ליד השאלה שקובעת אותו, ולא הודעת
       שגיאה — צבע אדום כאן היה אומר «עשית משהו לא בסדר». */
/* ─────────────────────────────────────────────────────────────────────
   The prep step.

   ⚠️  THE QUESTIONNAIRE HAD NO STYLES OF ITS OWN. `.intake`,
       `.intake-title`, `.intake-list` and the old `.intake-more` were
       classes nothing ever matched — thirteen questions inheriting
       generic element rules, which is why five screens of it read as one
       undifferentiated column. The sections below are the first thing
       that gives the step a shape.

   ⚠️  And the summary follows `.qty-fold` deliberately — same +/− mark,
       same 44px target. A second collapse idiom on one page is a second
       thing to learn for no reason.
   ───────────────────────────────────────────────────────────────────── */
.intake-title { margin: 22px 0 4px; font-size: 18px; color: var(--brand-800); }
.intake-sub { margin: 0 0 4px; font-size: 14.5px; color: var(--ink-500); }

.intake-progress {
  margin: 0 0 14px; font-size: 13.5px; font-weight: 600;
  color: var(--brand-700); font-variant-numeric: tabular-nums;
}

.intake-group { border-top: 1px solid var(--line); }
.intake-group > summary {
  cursor: pointer; padding: 10px 0; min-block-size: 44px;
  display: flex; align-items: center; gap: 8px;
}
.intake-group > summary::-webkit-details-marker { display: none; }
.intake-group > summary::before {
  content: '+'; font-size: 18px; line-height: 1; color: var(--brand-700);
}
.intake-group[open] > summary::before { content: '−'; }
.intake-group-name { font-size: 15px; font-weight: 700; color: var(--brand-800); }
/* The count sits at the far end, so a column of closed sections reads
   down as a column of numbers rather than as a column of labels. */
.intake-group-count {
  margin-inline-start: auto; font-size: 13px; font-weight: 600;
  color: var(--ink-500); font-variant-numeric: tabular-nums;
}
.intake-group .intake-list { padding-block-end: 6px; }

.intake-price-note {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0.3rem 0 0.5rem;
  padding: 0.35rem 0.55rem;
  border-radius: 0.5rem;
  background: var(--brand-50, #eef7f6);
  color: var(--brand-700, #0f4c4a);
  font-size: 0.8rem;
}
.intake-price-note svg { flex: none; inline-size: 1em; block-size: 1em; }

/* ── תוספות ומיקום ────────────────────────────────────────────────────────
   ⚠️  כל צבע כאן הוא טוקן קיים. check:contrast קורא רק את :root בקובץ
       הזה, אז גוון חדש לא היה נבדק על ידי אף אחד — וזה בדיוק איך ששתי
       מערכות תגים נולדו ונמחקו בפרויקט הזה.                             */
.calc-extras {
  margin: var(--space-5, 20px) 0 0;
  padding: var(--space-4, 16px);
  background: var(--surface-alt);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
}
.calc-extras-h {
  margin: 0 0 4px;
  font-size: 15.5px;
  font-weight: 700;
  color: var(--brand-800);
}
.calc-extras-sub {
  margin: 0 0 var(--space-3, 12px);
  font-size: 13.5px;
  line-height: 1.5;
  color: var(--ink-500);
}
.calc-extras .opt-row + .opt-row { margin-block-start: var(--space-3, 12px); }

/* הרצפה, כשהיא חלה — אותה קופסה כמו הערת המחיר בשאלון, כי זו אותה
   קטגוריה של מידע: עובדה על הסכום, לא שגיאה. */
.calc-min-badge {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin: var(--space-3, 12px) 0 0;
  padding: 0.45rem 0.6rem;
  border-radius: 0.5rem;
  background: var(--brand-50);
  color: var(--brand-800);
  font-size: 13.5px;
  line-height: 1.45;
}
.calc-min-badge svg { flex: none; inline-size: 1em; block-size: 1em; }

/* מה שנוסף לפריט, מתחת לשמו — כדי שהמחיר בשורה יהיה קריא ולא רק נכון. */
.cart-line-add {
  display: block;
  font-size: 12.5px;
  line-height: 1.45;
  color: var(--ink-500);
}

/* תוצאה של תשובה קודמת, לא שאלה חדשה — אותה קופסה כמו הערת המחיר בשאלון. */
.sheet-note {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0.4rem 0 0;
  padding: 0.45rem 0.6rem;
  border-radius: 0.5rem;
  background: var(--brand-50);
  color: var(--brand-800);
  font-size: 13.5px;
  line-height: 1.45;
}
.sheet-note svg { flex: none; inline-size: 1em; block-size: 1em; }

/* ── הצעת מחיר רשמית ──────────────────────────────────────────────────── */

.calc-print {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 0.4rem;
  inline-size: 100%;
  min-block-size: 44px;
  margin-block-start: 12px;
  padding: 10px 14px;
  border: 1.5px solid var(--line, #d8e3e2);
  border-radius: var(--radius-lg, 14px);
  background: #fff;
  color: var(--ink, #12302f);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}
.calc-print:hover { border-color: var(--brand-500, #1f8f89); }
.calc-print-i { flex: none; inline-size: 18px; block-size: 18px; }

/* ⚠️  display:flex BEATS THE [hidden] ATTRIBUTE, AND THIS STYLESHEET HAS
       ALREADY BEEN BITTEN BY IT TWICE — see the note on .calc-bar above
       and the matching rule on .calc-focus.

       The formal-quote button is drawn for the whole details step and
       hidden until there is a name and a phone to address it to. Without
       this line the attribute is set, the element stays on screen, and
       the gate reads as though it were never written. */
.calc-print[hidden], .calc-print-hint[hidden] { display: none; }

/* ⚠️  אומר מה יקרה לפני הלחיצה. «הצעת מחיר רשמית» שפותחת חלון הדפסה
       בלי להזהיר היא הפתעה, ומי שרצה קובץ לא ידע שהוא כבר קיבל אותו. */
.calc-print-hint {
  margin: 4px 0 0;
  font-size: 0.75rem;
  color: var(--ink-soft, #5a6b6a);
  text-align: center;
}

/* ── המסמך עצמו ───────────────────────────────────────────────────────────
   ⚠️  מוסתר לגמרי על המסך. הוא כפילות של הסל, ואם הוא ייראה — קורא מסך
       יקריא כל שורה פעמיים, והדף יהיה ארוך פי שניים בלי סיבה.          */
.quote-doc { display: none; }

@media print {
  /**
   * ⚠️  THE SCROLL LOCK COMES OFF, AND THIS IS THE BLANK PAGE.
   *
   *     openSheet() sets `body.sheet-open`, which is `overflow: hidden`
   *     — correct on screen, where a page scrolling behind an open sheet
   *     loses the reader's place. printQuote() never removes it and this
   *     block never reset it, so the browser paginated a document inside
   *     a clipped body.
   *
   *     It was a phone-only fault and the asymmetry is the proof:
   *     basketTotals() draws the print button in BOTH the sidebar foot
   *     and the sheet body. At 1280 the sidebar is visible and no sheet
   *     is ever opened, so the class is absent and the quote printed
   *     correctly the whole time. At 375 the sidebar is display:none and
   *     the sheet is the only route to the button — so every mobile
   *     print ran with the lock on. The owner sent a photograph of an
   *     empty A4; the desktop had never once shown the fault.
   *
   *     Fixed here and not by closing the sheet before print(): closing
   *     it takes the customer off the screen they just pressed a button
   *     on, and leaves them somewhere else when the dialogue ends. A rule
   *     in the stylesheet also covers whoever reaches this document from
   *     a third place later.
   *
   * ⚠️  `height: auto` with it. A locked body is usually a fixed-height
   *     body in the next framework along, and a print clipped to one
   *     viewport is the same bug wearing the other property.
   */
  html, body {
    overflow: visible !important;
    height: auto !important;
  }
  /* ⚠️  הכול יורד חוץ מהמסמך. אין תפריט, אין צפים, אין באנר עוגיות —
         עמוד ראשון של הצעת מחיר שחציו ניווט אינו הצעת מחיר. */
  body > *:not(#quote-doc) { display: none !important; }

  .quote-doc {
    display: block;
    direction: rtl;
    color: #000;
    background: #fff;
    font-size: 11pt;
    line-height: 1.5;
  }

  .quote-doc .qd-kicker {
    margin: 0;
    font-size: 9pt;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }
  .quote-doc .qd-title { margin: 0 0 2mm; font-size: 20pt; }
  .quote-doc .qd-from { margin: 0; font-size: 9pt; }
  .quote-doc .qd-head { border-block-end: 1pt solid #000; padding-block-end: 3mm; }
  /* ⚠️  The number somebody rings to query the quote. It was 9pt grey
         beside a company registration; it is the second thing on the
         page now, after the name. */
  .quote-doc .qd-reach {
    margin: 1.5mm 0 0; font-size: 11pt; font-weight: 700;
    font-variant-numeric: tabular-nums;
  }

  /* ⚠️  Organisation documents only — see the note at the call site. */
  .quote-doc .qd-sign { margin-block-start: 8mm; break-inside: avoid; }
  .quote-doc .qd-sign-grid {
    display: grid; grid-template-columns: 1fr 1fr; gap: 7mm 10mm;
    margin-block-start: 4mm;
  }
  .quote-doc .qd-sign-cell { display: grid; gap: 1mm; }
  .quote-doc .qd-sign-label { font-size: 9pt; }
  .quote-doc .qd-sign-rule { border-block-end: 0.5pt solid #000; block-size: 7mm; }
  .quote-doc .qd-includes ul { margin: 0; padding-inline-start: 5mm; font-size: 9pt; }

  /* ⚠️  padding:0 is load-bearing. The site's own `section { padding:
         40px 0 }` applies here too, and at print scale it opened a
         finger-width of white between every block — a two-page quote
         for four lines of content. A document borrowing the marketing
         site's rhythm is the default failure of printing a web page. */
  .quote-doc section {
    padding: 0;
    margin-block-start: 5mm;
    break-inside: avoid;
  }
  .quote-doc .qd-h { margin: 0 0 1.5mm; font-size: 10pt; }
  .quote-doc .qd-sub { margin: 0; font-size: 9pt; }

  .quote-doc .qd-row {
    display: flex;
    justify-content: space-between;
    gap: 6mm;
    padding-block: 1mm;
    border-block-end: 0.3pt solid #999;
  }
  .quote-doc .qd-row-v { font-variant-numeric: tabular-nums; white-space: nowrap; }

  .quote-doc .qd-total {
    margin-block-start: 2mm;
    border-block-end: 0;
    border-block-start: 1pt solid #000;
    padding-block-start: 2mm;
    font-size: 13pt;
    font-weight: 700;
  }

  .quote-doc .qd-vat { margin: 2mm 0 0; font-size: 9pt; }
  .quote-doc .qd-notes ul { margin: 0; padding-inline-start: 5mm; font-size: 9pt; }

  @page { margin: 15mm; }
}

/* ── עמוד קבוצה ────────────────────────────────────────────────────────────
   ⚠️  אין כאן אווטרים, ראשי תיבות או רשימת משתתפים — רק מספר. הקישור
       מודבק בקבוצת וואטסאפ של יישוב, ומי שהצטרף לא הסכים להופיע בעמוד
       שכל השכנים יכולים לפתוח.                                          */

.grp-progress {
  margin: var(--space-5, 24px) 0;
  padding: 16px;
  border: 1.5px solid var(--line, #d8e3e2);
  border-radius: var(--radius-lg, 14px);
  background: var(--brand-50, #eef7f6);
}

.grp-count {
  margin: 0 0 10px;
  font-size: 1.35rem;
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.grp-bar {
  block-size: 10px;
  border-radius: 999px;
  background: #fff;
  overflow: hidden;
}

.grp-bar-fill {
  display: block;
  block-size: 100%;
  background: var(--brand-600, #12777a);
  border-radius: 999px;
}

.grp-need { margin: 10px 0 0; font-size: 0.9rem; color: var(--ink-soft, #5a6b6a); }
.grp-need.is-met { color: var(--brand-700, #0f4c4a); font-weight: 600; }

.grp-what, .grp-steps { line-height: 1.7; }
.grp-cta { margin-block: var(--space-5, 24px); }

/* ⚠️  נאמר גם על העמוד ולא רק במדיניות. מי שמחליט אם למסור כתובת דרך
       קישור ששכן שלח לא צריך ללכת לקרוא עמוד משפטי כדי לדעת מי רואה. */
.grp-privacy {
  margin-block-start: var(--space-5, 24px);
  padding: 10px 12px;
  border-inline-start: 3px solid var(--brand-500, #1f8f89);
  background: #fff;
  font-size: 0.85rem;
  color: var(--ink-soft, #5a6b6a);
}

/* ── מצב קבוצה במחשבון ─────────────────────────────────────────────────────
   ⚠️  מספר וסרגל. בלי אווטרים ובלי ראשי תיבות — «ז. ש.» במושב של תשעים
       משפחות מזהה בית אחד, ומי שהצטרף הסכים לנקות ספה, לא להופיע על
       מסך שהשכנים שלו פותחים.                                          */

.calc-group {
  margin: 0 0 var(--space-4, 16px);
  padding: 14px 16px;
  border: 1.5px solid var(--brand-500, #1f8f89);
  border-radius: var(--radius-lg, 14px);
  background: var(--brand-50, #eef7f6);
}

.calc-group.is-closed { border-color: var(--line, #d8e3e2); background: #fff; }

.calc-group-h {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  margin: 0 0 8px;
  font-weight: 700;
}

.calc-group-i { flex: none; inline-size: 1.1em; block-size: 1.1em; }

.calc-group-bar {
  block-size: 8px;
  border-radius: 999px;
  background: #fff;
  overflow: hidden;
}

.calc-group-fill {
  display: block;
  block-size: 100%;
  border-radius: 999px;
  background: var(--brand-600, #12777a);
}

.calc-group-t { margin: 8px 0 0; font-size: 0.85rem; color: var(--ink-soft, #5a6b6a); }

.calc-group-share {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-block-size: 44px;
  margin-block-start: 10px;
  padding: 8px 14px;
  border: 1.5px solid var(--brand-500, #1f8f89);
  border-radius: 999px;
  background: #fff;
  color: var(--brand-700, #0f4c4a);
  font: inherit;
  font-weight: 600;
  cursor: pointer;
}

.calc-group-lock { display: block; margin-block-start: 4px; }

/* ── פתיחת יום מרוכז ─────────────────────────────────────────────────────── */

.calc-open-group {
  margin-block-start: 12px;
  padding: 10px 12px;
  border: 1.5px dashed var(--line, #d8e3e2);
  border-radius: var(--radius-lg, 14px);
  background: #fff;
}

.calc-open-group > summary {
  min-block-size: 44px;
  display: flex;
  align-items: center;
  font-weight: 600;
  cursor: pointer;
}

.calc-open-group-body { padding-block-start: 8px; }
.calc-open-group-t { margin: 8px 0; font-size: 0.82rem; color: var(--ink-soft, #5a6b6a); line-height: 1.5; }

.sent-group {
  margin-block-start: var(--space-4, 16px);
  padding: 14px;
  border-radius: var(--radius-lg, 14px);
  background: var(--brand-50, #eef7f6);
  text-align: center;
}

.sent-group-h { margin: 0 0 8px; font-weight: 600; }

/* ⚠️  A link people read off a screen and type into a phone. It wraps
       rather than truncating — «…» in the middle of a URL is a URL
       somebody cannot use. */
.sent-group-url {
  display: block;
  margin-block-end: 12px;
  font-size: 0.9rem;
  word-break: break-all;
  direction: ltr;
}

.sent-group-share { display: inline-flex; min-block-size: 44px; align-items: center; }

/* ── The limited-time offer, and the note that replaces it ───────────────── */
/* ⚠️  Both are in the HTML with one hidden — see sofaNote() in site/pages.mjs.
       `[hidden]` must therefore actually hide: .promo-note is a grid, and a
       display rule on a class beats the browser's own `[hidden]` default,
       which is exactly how a "hidden" element stays on screen. */
.promo-note {
  max-width: 700px; margin: 20px auto 0; padding: 14px 16px;
  display: grid; gap: 4px; justify-items: center; text-align: center;
  background: var(--accent-100); border: 1px solid var(--accent-500);
  border-radius: var(--radius);
}
.promo-note[hidden] { display: none; }
.promo-note strong {
  font-size: 17px; line-height: 1.35; color: var(--accent-600);
  text-wrap: balance;
}
/* The conditions, including ט.ל.ח. Smaller, but not small enough to be the
   fine print a customer is entitled to say they never saw. */
.promo-note span { font-size: 13.5px; color: var(--ink-700); line-height: 1.6; }

.price-note {
  max-width: 700px; margin: 20px auto 0;
  font-size: 14.5px; color: var(--ink-700); line-height: 1.7;
}
.price-note[hidden] { display: none; }

/* The same offer, in the hero. */
/* ⚠️  A VARIANT, NOT A SECOND BANNER. promoBanner() changes the class and
       never the words: the hero needs a different shape from a note under
       a price table, and must not get a different promise.

   ⚠️  LAYOUT ONLY — NO COLOURS. My first version set white text on a
       translucent white box, on the belief that the hero ground was dark
       teal. It is not: the hero is a light gradient from #eefafb to white
       and its h1 is near-black. The conditions line, ט.ל.ח included, was
       rendered white on white — present in the DOM, invisible on screen,
       and the box looked like it had a blank second row. Measured in the
       browser, not assumed, after it had already shipped into a build.

       So the palette comes from .promo-note above and only the geometry
       changes here. A colour that is correct in one place and invisible
       in another is the reason this variant carries no colours at all. */
.promo-hero {
  margin: 0 0 16px; max-width: 520px; justify-items: start; text-align: start;
  padding: 11px 14px; gap: 3px;
}
.promo-hero strong { font-size: 16px; }

/* The offer, as a card in the catalogue. */
/* ⚠️  Not a .dish. A dish opens a sheet that asks questions; this one
       already knows every answer, which is the entire point of it. Giving
       it the dish styling would promise the sheet it does not open. */
.offer-card {
  margin: 0 0 14px; padding: 14px 16px;
  display: grid; gap: 8px; justify-items: start;
  background: var(--accent-100); border: 1px solid var(--accent-500);
  border-radius: var(--radius);
}
.offer-card-title { font-size: 16px; line-height: 1.35; color: var(--accent-600); text-wrap: balance; }
.offer-card-note { font-size: 13px; color: var(--ink-700); line-height: 1.55; }
.offer-card-add { inline-size: 100%; }
/* ⚠️  A disabled button here means «already in your quote», not «broken».
       Keeping it legible matters more than the usual dimming. */
.offer-card-add:disabled { opacity: 1; background: var(--brand-700); cursor: default; }
