/* ===========================================================================
   tokens.css — GAMOS-SITE single source of design truth
   ---------------------------------------------------------------------------
   Spec:        architecture/tokens.md  (LOCKED 2026-05-28 by Agent 02)
   Constitution: CLAUDE.md §4 (Typography), §5 (Palette), §10.2 (Tokens are
                 single-source — any hard-coded value elsewhere is a bug).
   Owner:       Agent 02 — Brand & Typography
   ---------------------------------------------------------------------------
   RULES
   - No raw hex outside the brand block. Every semantic token references a
     brand token via var(...).
   - All numeric scales reference each other where possible.
   - WOFF2 only, self-hosted at /assets/fonts/, font-display: swap mandatory.
   ========================================================================= */


/* ---------------------------------------------------------------------------
   1. @font-face — self-hosted WOFF2 (font-display: swap, unicode-range hints)
   ---------------------------------------------------------------------------
   The browser only downloads a face when a glyph in its unicode-range is
   actually rendered, so listing Hebrew + Latin sub-faces lets the cascade
   pick the right file per glyph automatically (covers numerals/punctuation
   inside Hebrew copy without forcing two full webfonts).
   --------------------------------------------------------------------------- */

/* ---- Rubik (Hebrew + Latin display) ----
   Replaces Frank Ruhl Libre as the display family per user direction
   (2026-06-02): the literary serif read too "writerly"; Rubik is a modern
   geometric humanist that flows in Hebrew without losing premium weight.
   The WOFF2 is a VARIABLE font (wght axis 300–900, verified via fvar). Each
   face is declared as a `font-weight` RANGE (not a discrete value) so the
   browser renders the exact requested weight from the variable file — pinning
   to 700/900 made any lighter token snap back to 700. Lightened site-wide
   2026-06-15 per user request (text felt too bold/heavy).
   Loaded for both Hebrew + Latin so eyebrows like "GAMOS EVENTS" use the
   same family as the Hebrew titles. */
@font-face {
  font-family: "Rubik";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("/assets/fonts/rubik-hebrew.woff2") format("woff2");
  unicode-range: U+0307-0308, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}
@font-face {
  font-family: "Rubik";
  font-style: normal;
  font-weight: 300 900;
  font-display: swap;
  src: url("/assets/fonts/rubik-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* ---- Heebo (Hebrew + Latin body) ----
   Variable font (wght axis 100–900, verified via fvar); the 400/500/600 files
   are byte-identical, so one face with a `font-weight` RANGE serves the whole
   body-weight span from the single VF — the browser renders the exact token
   weight (incl. the lighter 350 default set 2026-06-15). */
@font-face {
  font-family: "Heebo";
  font-style: normal;
  font-weight: 100 900;
  /* `optional` (not `swap`) — Heebo is the above-the-fold hero text + body face,
     so a swap-in mid-view = the letter flicker the user reported (FOUT metric
     shift). `optional` gives a ~100ms block then locks the choice for the view:
     with the head preload (index.html) Heebo wins that race → real font, zero
     flash; on a cold/slow link it shows a STABLE fallback with no late swap.
     Deliberate deviation from the "swap" convention noted above — FOUC fix
     2026-06-16. Other faces keep `swap`. */
  font-display: optional;
  src: url("/assets/fonts/heebo-400.woff2") format("woff2");
  unicode-range: U+0020-007E, U+00A0-00FF, U+0590-05FF, U+200C-2010, U+20AA, U+25CC, U+FB1D-FB4F;
}

/* ---- Playfair Display (Latin display only — used for English flourishes) ---- */
@font-face {
  font-family: "Playfair Display";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/playfair-display-400.woff2") format("woff2");
  unicode-range: U+0020-007E, U+00A0-00FF, U+0152-0153, U+02BB-02BC, U+2010-2027, U+20AC;
}
@font-face {
  font-family: "Playfair Display";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/playfair-display-700.woff2") format("woff2");
  unicode-range: U+0020-007E, U+00A0-00FF, U+0152-0153, U+02BB-02BC, U+2010-2027, U+20AC;
}

/* ---- Cinzel (Latin display only — used for the hero "Events"/"Resort"
   labels, mirroring the all-caps engraved feel of the GAMOS wordmark) ---- */
@font-face {
  font-family: "Cinzel";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/assets/fonts/cinzel-700.woff2") format("woff2");
  unicode-range: U+0020-007E, U+00A0-00FF;
}

/* ---- Canela (Latin display — English headings, per user 2026-07-01) ------
   High-contrast humanist serif (Commercial Type). Self-hosted WOFF2, converted
   from the user's Canela-Regular.ttf. Weight 400 only; used for English display
   headings + hero. §4.1: adopted on explicit user request. */
@font-face {
  font-family: "Canela";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/assets/fonts/canela-regular.woff2") format("woff2");
  /* French display copy needs glyphs above Latin-1: œ/Œ (bœuf, cœur), en/em
     dashes, curly quotes and the ellipsis. All verified present in the woff2, so
     the browser renders Canela for them instead of falling through to the
     Playfair fallback (which produced one mismatched serif glyph mid-heading). */
  unicode-range: U+0020-007E, U+00A0-00FF, U+0152-0153, U+2013-2014, U+2018-201D, U+2026;
}

/* ---- Non-Hebrew display font (2026-07-01, extended to French 2026-07-02) ---
   When the site is switched to any Latin-script language (js/i18n.js sets
   html[lang="en"] or html[lang="fr"]), the DISPLAY family becomes Canela — an
   elegant high-contrast serif — instead of Rubik. Body copy stays Heebo for
   readability (classic serif-display / sans-body luxury pairing).
   html:not([lang="he"]) (0,1,1) outranks :root (0,1,0), so these win regardless
   of source order — and cover en, fr, and any future non-Hebrew language. */
html:not([lang="he"]) {
  --font-display-he:      "Canela", "Playfair Display", serif;
  --font-display-en:      "Canela", "Playfair Display", serif;
  --font-display-luxury:  "Canela", "Playfair Display", serif;
  /* Only Canela Regular (400) is self-hosted, but headings request 700 → the
     browser faux-bolds the single face and thickens the strokes. Disable weight
     synthesis so Canela renders at its true, thinner Regular. */
  font-synthesis-weight: none;
}

/* Bodoni Moda removed 2026-06-02 — the Hero wordmark is now an <img> of
   the central Gamos logo (assets/images/brand/logo-central.webp), so no
   subsetted Latin Didone is needed in the font cascade. */


/* ---------------------------------------------------------------------------
   2. :root tokens
   --------------------------------------------------------------------------- */

:root {

  /* ===== 2.1 Brand palette (LOCKED 2026-05-28 by Agent 01 — CLAUDE.md §5) =====
     Pulled from gamos.co.il scrape (BRANDING.JSON) and upgraded per
     "Luxury or nothing" principle. Maximum 5 active colors at a time. */
  --brass:          #CFAE83;   /* PRIMARY — live brand color, unchanged */
  --brass-deep:     #8B6F46;   /* hover/active — derived */
  --brass-glow:     #D4B98A;   /* glow / highlight */
  --brass-olive:    #857147;   /* v10 hero title accent + eyebrow (2026-06-15) —
                                  warm olive-brass from the findrealestate hero;
                                  sits between brass + brass-deep. */
  --cocoa:          #534133;   /* SECONDARY — live brand color, unchanged */
  --ivory:          #F5EFE6;   /* surface — replaces live #FFFFFF */
  --ivory-warm:     #ECE3D3;   /* warm tint */
  --mist:           #E8DFD3;   /* surface tint, light fade */
  --ink-deep:       #1A1410;   /* body text — warm near-black, replaces #000 */
  --ink-medium:     #2A2A28;   /* subtle borders */
  --accent-rose:    #B8576F;   /* CTA accent — replaces live #CC3366 */

  /* ===== 2.2 Semantic colors (reference brand only) ===== */
  --bg:             var(--ivory);
  --bg-alt:         var(--ivory-warm);
  --bg-tint:        var(--mist);
  --bg-dark:        var(--ink-deep);
  --bg-cocoa:       var(--cocoa);
  --fg:             var(--ink-deep);
  /* Darkened #6B6B68 → #5E5E5B on 2026-07-21 (a11y pass): the old value passed
     on --ivory (4.68) but FAILED WCAG AA on the warmer light surfaces it also
     lands on — 4.20 on --ivory-warm (gallery), 4.05 on --mist (testimonials).
     #5E5E5B clears 4.5 on all three (ivory 5.69 / ivory-warm 5.11 / mist 4.93). */
  --fg-muted:       #5E5E5B;
  --fg-on-dark:     var(--ivory);
  --accent:         var(--brass);
  --accent-hover:   var(--brass-deep);
  --accent-glow:    var(--brass-glow);
  --accent-cta:     var(--accent-rose);
  --border:         rgba(26, 20, 16, 0.12);
  --border-strong:  rgba(26, 20, 16, 0.24);
  --shadow-soft:    0 8px 24px rgba(26, 20, 16, 0.06);
  --shadow-strong:  0 24px 60px rgba(26, 20, 16, 0.16);
  --shadow-image:   0 30px 80px -40px rgba(26, 20, 16, 0.45); /* deep lift for large image cards (shabbat) */
  /* Two-tone focus ring (AMENDED 2026-07-21, a11y pass). Was a single 3px
     --brass box-shadow, but brass-on-ivory = 1.83:1 fails WCAG 1.4.11 (≥3:1
     for a non-text indicator) on every light surface. No single flat token
     clears 3:1 everywhere: brass fails on light, brass-deep fails on cocoa
     (2.05). A two-tone ring is bulletproof because at least ONE band always
     contrasts ≥3:1 with the surface — the ivory gap carries dark surfaces
     (ivory↔cocoa 8.46, ivory↔ink-deep ~15) and the brass-deep band carries
     light surfaces (brass-deep↔ivory 4.12 / ivory-warm 3.70 / mist 3.57).
     Inner tone is hard --ivory (not --bg) so the gap is guaranteed LIGHT even
     if a section rescopes --bg. */
  --focus-ring:     0 0 0 2px var(--ivory), 0 0 0 5px var(--brass-deep);
  /* Offset focus ring for image/hotspot CTAs (hero CTAs, portals, hero cue,
     rooms door). A double box-shadow gives the "outline + gap" look that the
     bespoke `outline: 3px … ; outline-offset: 4-6px` rules used to fake, but
     stays token-driven, works over photographs, and matches the .btn focus
     grammar. The inner ring is the bg color so the gap reads on any surface. */
  --focus-ring-offset: 0 0 0 4px var(--bg), 0 0 0 7px var(--brass);

  /* ===== 2.2c Media scrims + on-dark text (LOCKED 2026-06-15 — unify pass) =====
     Single source for "legible text over media". Replaces three divergent,
     hard-coded gradient formulas (scroll-scene rgba(14,14,12,…), lounge
     rgba(26,20,16,…), culinary rgba(14,14,12,…)) with one ink-deep base.
       --scrim-strong  : heavy bottom wash for tight caption boxes
                         (lounge figcaption, culinary item caption).
       --scrim-overlay : gentler, taller fade for large text overlays
                         (scroll-scene section header over canvas/video).
       --fg-on-dark-muted : the ONE translucent-ivory method for secondary
                         body text over media (replaces the color-mix-88% vs
                         opacity-0.9 split). */
  --scrim-strong:   linear-gradient(to top,
                      color-mix(in srgb, var(--ink-deep) 85%, transparent) 0%,
                      color-mix(in srgb, var(--ink-deep) 55%, transparent) 45%,
                      transparent 78%);
  --scrim-overlay:  linear-gradient(to top,
                      color-mix(in srgb, var(--ink-deep) 72%, transparent) 0%,
                      color-mix(in srgb, var(--ink-deep) 45%, transparent) 30%,
                      color-mix(in srgb, var(--ink-deep) 10%, transparent) 65%,
                      transparent 100%);
  --fg-on-dark-muted: color-mix(in srgb, var(--ivory) 88%, transparent);

  /* ===== 2.2b Texture fills (background-clip:text headings) =====
     2026-06-03 RENAMED for clarity. The previous typo-light/typo-dark pair
     was mapped backwards: the file labeled "dark" was actually the light
     texture, so titles disappeared into the background on every page.
     New names describe the SURFACE the fill sits on:
       --typo-on-light : DARK texture (gold flecks on near-black) — for
                         titles/eyebrows on ivory/cream surfaces (dominant
                         case site-wide).
       --typo-on-dark  : LIGHT texture (cream + gold) — for titles/eyebrows
                         on cocoa/dark surfaces (Hero, halls, kosher,
                         culinary, footer).
     Legacy --typo-light/--typo-dark aliases removed; texture-text.css now
     references the new names directly. */
  --typo-on-light:  url("/assets/images/brand/typo-on-light.webp?v=2026-07-21-slim");
  --typo-on-dark:   url("/assets/images/brand/typo-on-dark.webp?v=2026-07-21-slim");
  --texture-light:  url("/assets/images/brand/texture-light.webp");
  --texture-dark:   url("/assets/images/brand/texture-dark.webp");

  /* ===== 2.3 Typography — families ===== */
  /* Display family — modern Hebrew + Latin (Rubik). Replaced Frank Ruhl
     Libre on 2026-06-02 per user direction ("the literary serif feels too
     writerly; want modern + flowing"). Same family powers BOTH Hebrew
     headings and English eyebrows like "GAMOS EVENTS". */
  --font-display-he:      "Rubik", "Heebo", "Arial", sans-serif;
  --font-display-en:      "Rubik", "Helvetica Neue", "Arial", sans-serif;
  --font-display-luxury:  var(--font-display-he); /* legacy alias */
  --font-body:            "Heebo", "Arial", sans-serif;
  --font-mono:            ui-monospace, "Menlo", "Consolas", monospace;

  /* ===== 2.4 Type scale (modular ratio 1.250) ===== */
  --text-xs:    0.75rem;       /* 12px */
  --text-sm:    0.875rem;      /* 14px */
  --text-base:  1rem;          /* 16px */
  --text-md:    1.25rem;       /* 20px */
  --text-lg:    1.563rem;      /* 25px */
  --text-xl:    1.953rem;      /* 31px */
  --text-2xl:   2.441rem;      /* 39px */
  --text-3xl:   3.052rem;      /* 49px */
  --text-4xl:   3.815rem;      /* 61px */
  --text-hero:  clamp(3.5rem, 9vw, 8rem); /* 56–128px */

  /* ===== 2.5 Weights ===== */
  /* Lightened ~one half-step site-wide 2026-06-15 (text felt too bold/heavy).
     Rubik + Heebo are variable fonts (see @font-face range blocks above), so
     these render exactly — no font files added. Revert to 400/500/600/700 to
     undo. */
  --fw-regular:  350;
  --fw-medium:   400;
  --fw-semibold: 500;
  --fw-bold:     600;

  /* ===== 2.6 Line heights ===== */
  --lh-tight:   1.05;
  --lh-snug:    1.2;
  --lh-normal:  1.5;
  --lh-loose:   1.7;

  /* ===== 2.7 Letter spacing ===== */
  --tracking-tight:    -0.02em;
  --tracking-normal:   0;
  --tracking-wide:     0.05em;
  --tracking-eyebrow:  0.18em;

  /* ===== 2.8 Spacing (4px base) ===== */
  --space-1:   0.25rem;   /* 4px */
  --space-2:   0.5rem;    /* 8px */
  --space-3:   0.75rem;   /* 12px */
  --space-4:   1rem;      /* 16px */
  --space-5:   1.25rem;   /* 20px */
  --space-6:   1.5rem;    /* 24px */
  --space-8:   2rem;      /* 32px */
  --space-10:  2.5rem;    /* 40px */
  --space-12:  3rem;      /* 48px */
  --space-16:  4rem;      /* 64px */
  --space-20:  5rem;      /* 80px — fills the 16→24 gap; consumed by scroll-scene */
  --space-24:  6rem;      /* 96px */
  --space-32:  8rem;      /* 128px */

  /* ===== 2.8b Section rhythm (LOCKED 2026-06-15 — unify pass) =====
     Named section-padding tokens so every scroll section shares ONE vertical
     rhythm instead of re-declaring padding-block. Sections converge on these
     (and the .section utility in layout.css consumes them too). */
  --section-pad:          var(--space-32); /* 128px — default section rhythm */
  --section-pad-tight:    var(--space-24); /* 96px  — denser sections (kosher) */
  --section-pad-hero-gap: 25vh;            /* lounge top: deliberate post-hero pause */

  /* ===== 2.9 Radii ===== */
  --radius-sm:     4px;
  --radius-md:     8px;
  --radius-lg:     16px;
  --radius-xl:     24px;
  --radius-pill:   9999px;
  --radius-circle: 50%;
  --radius-btn:    0;       /* editorial CTA/chip/icon radius — sharp corners (de-pill 2026-06-15) */

  /* ===== 2.9b Component tokens ===== */
  --card-zoom:    1.04;   /* unified media-card hover zoom — single source of truth */

  /* ===== 2.10 Layout ===== */
  --container-max:    1320px;
  --container-narrow: 880px;
  --container-wide:   1480px;
  --gutter:           clamp(1rem, 4vw, 2.5rem);

  /* ===== 2.11 Motion durations ===== */
  --dur-fast:    160ms;
  --dur-base:    240ms;
  --dur-slow:    360ms;
  --dur-deluxe:  600ms;
  --dur-cinema:  1000ms;

  /* ===== 2.12 Easings ===== */
  --ease-out-cinema: cubic-bezier(0.2, 0.8, 0.2, 1);
  --ease-cue:        cubic-bezier(0.55, 0, 0.55, 1);  /* symmetric scroll-cue curve (hero + press cue-fall) */
  --ease-linear:     linear;

  /* ===== 2.13 Z-index scale ===== */
  --z-base:     0;
  --z-content:  10;
  --z-sticky:   100;
  --z-overlay:  1000;
  --z-modal:    2000;
  --z-toast:    3000;
}


/* ---------------------------------------------------------------------------
   3. Global typography defaults — referenced everywhere via these tokens.
      Sets Hebrew body as default; display tokens applied per-element.
   --------------------------------------------------------------------------- */

html {
  /* Smooth Hebrew + Latin shaping; harmless on modern engines. */
  font-feature-settings: "kern" 1, "liga" 1, "calt" 1;
  text-rendering: optimizeLegibility;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

body {
  font-family: var(--font-body);
  font-weight: var(--fw-regular);
  font-size: var(--text-base);
  line-height: var(--lh-normal);
  color: var(--fg);
  background: var(--bg);
}

/* Reduced-motion respect at the token layer (per CLAUDE.md §8). */
@media (prefers-reduced-motion: reduce) {
  :root {
    --dur-fast:    0.01ms;
    --dur-base:    0.01ms;
    --dur-slow:    0.01ms;
    --dur-deluxe:  0.01ms;
    --dur-cinema:  0.01ms;
  }
}

/* Shabbat-chatan scroll tint cycle — image-derived SOFT PASTELS. User-authorised
   §5 exception for this one section: each tint keeps the dominant HUE of the
   photo it's paired with (panel N ↔ image N) but is pastelized (high lightness,
   tempered saturation) so the background is an airy soft tint that still
   matches the picture on screen. Because the tints are light, the heading +
   title texture stay --dark (js/shabbat-gallery.js's luma flip leaves them dark
   above its threshold). The values below are GENERATED by
   scripts/extract-shabbat-tints.mjs — do not hand-edit between the sentinels;
   re-run `npm run extract:shabbat-tints` after changing the source images.
   Logged in §12 Maintenance Log 2026-06-10. */
:root {
  /* >>> shabbat-tints (generated by scripts/extract-shabbat-tints.mjs — do not edit by hand) */
  --shabbat-tint-1: #e7deda; /* from 01.full.webp */
  --shabbat-tint-2: #e7e0da; /* from 02.full.webp */
  --shabbat-tint-3: #e7e6da; /* from 03.full.webp */
  --shabbat-tint-4: #e7dfda; /* from 04.full.webp */
  --shabbat-tint-5: #e4e7da; /* from 05.full.webp */
  --shabbat-tint-6: #e7e2da; /* from 06.full.webp */
  /* <<< shabbat-tints */
  --shabbat-tint:   var(--shabbat-tint-1);
}

/* ============================================================
   GAMOS-SITE — base.css
   Modern reset + RTL-aware typography defaults + a11y primitives
   All visual values derive from var(--*) tokens (css/tokens.css).
   Cascade order: tokens → base → layout → utilities → sections/*
   ============================================================ */

@layer base, layout, utilities, sections;

@layer base {

  /* ----- Modern reset (Andy Bell-flavoured) ----- */

  *,
  *::before,
  *::after {
    box-sizing: border-box;
  }

  html,
  body,
  h1, h2, h3, h4, h5, h6,
  p,
  figure,
  blockquote,
  dl,
  dd,
  ul,
  ol {
    margin: 0;
    padding: 0;
  }

  ul[role="list"],
  ol[role="list"] {
    list-style: none;
  }

  /* Form elements inherit typography by default */
  input,
  button,
  textarea,
  select {
    font: inherit;
    color: inherit;
  }

  button {
    background: none;
    border: 0;
    cursor: pointer;
    padding: 0;
  }

  /* Avoid orphans on paragraphs */
  p,
  li,
  figcaption {
    text-wrap: pretty;
  }

  h1, h2, h3, h4, h5, h6 {
    text-wrap: balance;
  }

  /* ----- Root + body ----- */

  html {
    font-family: var(--font-body);
    font-size: 16px;
    line-height: var(--lh-normal);
    -webkit-text-size-adjust: 100%;
    text-size-adjust: 100%;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    /* NO `scroll-behavior: smooth` (2026-06-10). All in-page anchor scrolls
       run through GSAP ScrollToPlugin (js/scrollytelling.js global handler +
       side-dot-nav). Native smooth-scroll re-animates every per-frame
       window.scrollTo() the plugin makes — the two fight, and `autoKill`
       reads the conflict as a user scroll and kills the tween early (this is
       why the hero cue click never reached #lounge). The reduced-motion block
       below already forces `auto`; default (no declaration) is also `auto`. */
    /* RTL is set on <html dir="rtl" lang="he"> in HTML; CSS uses logical props. */
  }

  body {
    background: var(--bg);
    color: var(--fg);
    font-size: var(--text-base);
    line-height: var(--lh-normal);
    font-weight: var(--fw-regular);
    font-feature-settings: "kern" 1, "liga" 1;
    min-height: 100vh;
    min-height: 100dvh;
    text-align: start;
    overflow-x: hidden;
  }

  /* ----- Headings (Hebrew display by default) ----- */

  h1, h2, h3, h4, h5, h6 {
    font-family: var(--font-display-he);
    font-weight: var(--fw-bold);
    color: var(--fg);
    letter-spacing: var(--tracking-tight);
  }

  h1 {
    font-size: var(--text-4xl);
    line-height: var(--lh-tight);
  }

  h2 {
    font-size: var(--text-3xl);
    line-height: var(--lh-tight);
  }

  h3 {
    font-size: var(--text-2xl);
    line-height: var(--lh-snug);
  }

  h4 {
    font-size: var(--text-xl);
    line-height: var(--lh-snug);
    font-weight: var(--fw-semibold);
  }

  h5 {
    font-size: var(--text-lg);
    line-height: var(--lh-snug);
    font-weight: var(--fw-semibold);
  }

  h6 {
    font-size: var(--text-md);
    line-height: var(--lh-normal);
    font-weight: var(--fw-medium);
  }

  /* ----- Paragraph + inline text ----- */

  p {
    max-inline-size: 70ch;
    line-height: var(--lh-normal);
  }

  small {
    font-size: var(--text-sm);
  }

  strong, b {
    font-weight: var(--fw-bold);
  }

  em, i {
    font-style: italic;
  }

  /* ----- Links ----- */

  a {
    color: inherit;
    text-decoration: none;
    transition: color var(--dur-fast) var(--ease-out-cinema);
  }

  a:hover,
  a:focus-visible {
    color: var(--accent);
  }

  /* ----- Lists ----- */

  ul,
  ol {
    padding-inline-start: var(--space-6);
  }

  /* ----- Media ----- */

  img,
  video,
  picture,
  svg,
  canvas {
    max-inline-size: 100%;
    max-width: 100%;
    display: block;
    block-size: auto;
    height: auto;
  }

  img {
    font-style: italic; /* alt text styling fallback */
  }

  /* ----- Forms ----- */

  input,
  textarea,
  select {
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius-sm);
    padding-block: var(--space-2);
    padding-inline: var(--space-3);
    color: var(--fg);
    text-align: start;
  }

  textarea {
    resize: vertical;
    min-block-size: 6rem;
  }

  /* ----- Tables ----- */

  table {
    border-collapse: collapse;
    inline-size: 100%;
  }

  th,
  td {
    text-align: start;
    padding-block: var(--space-2);
    padding-inline: var(--space-3);
  }

  /* ----- Horizontal rule ----- */

  hr {
    border: 0;
    border-block-start: 1px solid var(--border);
    margin-block: var(--space-8);
  }

  /* ----- Selection ----- */

  ::selection {
    background: var(--brass);
    color: var(--ink-deep);
  }

  /* ----- Focus visible (two-tone ivory+brass-deep ring) -----
     Site-wide default. Switched from `outline: 3px solid brass` to the
     token box-shadow on 2026-07-21 (a11y pass): a flat brass ring is 1.83:1
     on ivory, failing WCAG 1.4.11. The --focus-ring token is a two-tone
     box-shadow that clears 3:1 on every surface (see tokens.css). Elements
     with their own :focus-visible rule (buttons, side-dot, nav, lang) reuse
     the same token, so the ring is uniform across the site. */

  :focus {
    outline: none;
  }

  :focus-visible {
    outline: none;
    box-shadow: var(--focus-ring);
    border-radius: var(--radius-sm);
  }

  /* ----- Skip link (visually hidden until focused) ----- */

  .skip-link {
    position: absolute;
    inset-block-start: var(--space-2);
    inset-inline-start: var(--space-2);
    z-index: var(--z-toast);
    padding-block: var(--space-2);
    padding-inline: var(--space-4);
    background: var(--ink-deep);
    color: var(--ivory);
    border-radius: var(--radius-sm);
    font-weight: var(--fw-semibold);
    transform: translateY(-200%);
    transition: transform var(--dur-fast) var(--ease-out-cinema);
  }

  .skip-link:focus,
  .skip-link:focus-visible {
    transform: translateY(0);
    color: var(--ivory);
  }

  /* ----- Reduced motion (global override) ----- */

  @media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
      animation-duration: 0.01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: 0.01ms !important;
      scroll-behavior: auto !important;
    }

    html {
      scroll-behavior: auto;
    }
  }

}

/* Cross-page fade into the halls pages (they opt in too). 2026-10-11, Moshe
   approved direct entry; replaces the 1.4s loading hold. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}

/* ============================================================
   GAMOS-SITE — layout.css
   Containers, sections, grid + flex primitives.
   RTL-aware (logical properties only).
   ============================================================ */

@layer base, layout, utilities, sections;

@layer layout {

  /* ----- Container ----- */

  .container {
    inline-size: 100%;
    max-inline-size: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--gutter);
  }

  .container--narrow {
    max-inline-size: var(--container-narrow);
  }

  .container--wide {
    max-inline-size: var(--container-wide);
  }

  .container--flush {
    padding-inline: 0;
  }

  /* ----- Section ----- */

  .section {
    padding-block: var(--section-pad);   /* shared section rhythm token */
    position: relative;
  }

  .section--tight {
    padding-block: var(--section-pad-tight);
  }

  .section--loose {
    padding-block: calc(var(--section-pad) + var(--space-16));
  }

  .section--flush {
    padding-block: 0;
  }

  .section--dark {
    background: var(--bg-dark);
    color: var(--fg-on-dark);
  }

  .section--alt {
    background: var(--bg-alt);
  }

  /* ----- Stack (vertical rhythm) ----- */

  .stack > * + * {
    margin-block-start: var(--space-4);
  }

  .stack--sm > * + * { margin-block-start: var(--space-2); }
  .stack--md > * + * { margin-block-start: var(--space-6); }
  .stack--lg > * + * { margin-block-start: var(--space-8); }
  .stack--xl > * + * { margin-block-start: var(--space-12); }

  /* ----- Grid ----- */

  .grid {
    display: grid;
    gap: var(--space-6);
  }

  .grid--auto-fit {
    grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
  }

  .grid--auto-fill {
    grid-template-columns: repeat(auto-fill, minmax(min(240px, 100%), 1fr));
  }

  .grid--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .grid--3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .grid--4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  /* Responsive collapses (mobile-first) */
  @media (max-width: 900px) {
    .grid--3,
    .grid--4 {
      grid-template-columns: repeat(2, minmax(0, 1fr));
    }
  }

  @media (max-width: 600px) {
    .grid--2,
    .grid--3,
    .grid--4 {
      grid-template-columns: 1fr;
    }
  }

  /* Span helpers */
  .col-span-2 { grid-column: span 2; }
  .col-span-3 { grid-column: span 3; }
  .col-span-full { grid-column: 1 / -1; }

  /* ----- Flex ----- */

  .flex {
    display: flex;
    gap: var(--space-4);
  }

  .flex--inline {
    display: inline-flex;
  }

  .flex--column {
    flex-direction: column;
  }

  .flex--wrap {
    flex-wrap: wrap;
  }

  .flex--center {
    align-items: center;
    justify-content: center;
  }

  .flex--center-y {
    align-items: center;
  }

  .flex--center-x {
    justify-content: center;
  }

  .flex--between {
    align-items: center;
    justify-content: space-between;
  }

  .flex--around {
    align-items: center;
    justify-content: space-around;
  }

  .flex--start {
    justify-content: flex-start;
  }

  .flex--end {
    justify-content: flex-end;
  }

  .flex--baseline {
    align-items: baseline;
  }

  .flex--stretch {
    align-items: stretch;
  }

  .flex--1 { flex: 1 1 0%; }
  .flex--auto { flex: 1 1 auto; }
  .flex--none { flex: none; }

  /* ----- Gap utilities (logical, work for grid + flex) ----- */

  .gap-0  { gap: 0; }
  .gap-1  { gap: var(--space-1); }
  .gap-2  { gap: var(--space-2); }
  .gap-3  { gap: var(--space-3); }
  .gap-4  { gap: var(--space-4); }
  .gap-6  { gap: var(--space-6); }
  .gap-8  { gap: var(--space-8); }
  .gap-12 { gap: var(--space-12); }
  .gap-16 { gap: var(--space-16); }

  .gap-x-2 { column-gap: var(--space-2); }
  .gap-x-4 { column-gap: var(--space-4); }
  .gap-x-6 { column-gap: var(--space-6); }
  .gap-x-8 { column-gap: var(--space-8); }

  .gap-y-2 { row-gap: var(--space-2); }
  .gap-y-4 { row-gap: var(--space-4); }
  .gap-y-6 { row-gap: var(--space-6); }
  .gap-y-8 { row-gap: var(--space-8); }

  /* ----- Aspect ratio holders (CLS prevention) ----- */

  .aspect-square  { aspect-ratio: 1 / 1; }
  .aspect-video   { aspect-ratio: 16 / 9; }
  .aspect-portrait { aspect-ratio: 3 / 4; }
  .aspect-cinema  { aspect-ratio: 21 / 9; }

  /* ----- Cluster (wraps inline items with gap) ----- */

  .cluster {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-4);
    align-items: center;
  }

  /* ----- Center (horizontal centering helper) ----- */

  .center {
    box-sizing: content-box;
    margin-inline: auto;
    max-inline-size: var(--container-narrow);
  }

  /* ----- Cover (full-bleed media) ----- */

  .cover {
    position: relative;
    inline-size: 100%;
    block-size: 100%;
  }

  .cover > img,
  .cover > video {
    position: absolute;
    inset: 0;
    inline-size: 100%;
    block-size: 100%;
    object-fit: cover;
  }

  /* ----- Section rails (Agent 20 — weblove-motion side-aligned text) -----
     Pushes text content into the outer 40% of the viewport while leaving
     the opposing 55% empty. Creates the off-center rhythm that defines the
     weblove-motion aesthetic. Mobile collapses to a centered single-column.
     RTL-aware via logical properties (`-start` = right in RTL). */

  .section-rail--start {
    padding-inline-start: 5vw;
    padding-inline-end: 55vw;
  }

  .section-rail--end {
    padding-inline-start: 55vw;
    padding-inline-end: 5vw;
  }

  .section-rail--start > *,
  .section-rail--end > * {
    max-inline-size: 40vw;
  }

  /* ----- Contact override (un-crush the page's last section) -----
     #contact previously inherited .section-rail--end's lopsided
     padding-inline-start:55vw + max-inline-size:40vw, shoving the form
     into a narrow off-center column ("weird angle" look). The contact
     section is a centered, full-width container like every other static
     section. .section-rail--end stays intact for #about. */
  .contact .section-rail--end {
    padding-inline-start: var(--gutter);
    padding-inline-end: var(--gutter);
    inline-size: 100%;
    max-inline-size: var(--container-max);
    margin-inline: auto;
  }

  .contact .section-rail--end > * {
    max-inline-size: 100%;
  }

  @media (max-width: 767px) {
    .section-rail--start,
    .section-rail--end {
      padding-inline-start: 5vw;
      padding-inline-end: 5vw;
    }

    .section-rail--start > *,
    .section-rail--end > * {
      max-inline-size: 100%;
    }
  }

}

/* ============================================================
   GAMOS-SITE — utilities.css
   Single-purpose utility classes.
   Logical properties only. !important is permitted ONLY here
   per Constitution §10.2 to guarantee override of components.
   ============================================================ */

@layer base, layout, utilities, sections;

@layer utilities {

  /* ============================================================
     Spacing — logical (margin-block / margin-inline)
     Naming: .mt = margin-block-start (top in LTR, top in RTL too)
             .mb = margin-block-end
             .ms = margin-inline-start (right in RTL)
             .me = margin-inline-end   (left  in RTL)
             .mx = margin-inline (start + end)
             .my = margin-block  (start + end)
     Same pattern for .p* (padding).
     ============================================================ */

  /* margin-block-start */
  .mt-0  { margin-block-start: 0 !important; }
  .mt-1  { margin-block-start: var(--space-1) !important; }
  .mt-2  { margin-block-start: var(--space-2) !important; }
  .mt-3  { margin-block-start: var(--space-3) !important; }
  .mt-4  { margin-block-start: var(--space-4) !important; }
  .mt-6  { margin-block-start: var(--space-6) !important; }
  .mt-8  { margin-block-start: var(--space-8) !important; }
  .mt-12 { margin-block-start: var(--space-12) !important; }
  .mt-16 { margin-block-start: var(--space-16) !important; }
  .mt-24 { margin-block-start: var(--space-24) !important; }
  .mt-32 { margin-block-start: var(--space-32) !important; }

  /* margin-block-end */
  .mb-0  { margin-block-end: 0 !important; }
  .mb-1  { margin-block-end: var(--space-1) !important; }
  .mb-2  { margin-block-end: var(--space-2) !important; }
  .mb-3  { margin-block-end: var(--space-3) !important; }
  .mb-4  { margin-block-end: var(--space-4) !important; }
  .mb-6  { margin-block-end: var(--space-6) !important; }
  .mb-8  { margin-block-end: var(--space-8) !important; }
  .mb-12 { margin-block-end: var(--space-12) !important; }
  .mb-16 { margin-block-end: var(--space-16) !important; }
  .mb-24 { margin-block-end: var(--space-24) !important; }
  .mb-32 { margin-block-end: var(--space-32) !important; }

  /* margin-inline-start (= "right" in RTL) */
  .ms-0  { margin-inline-start: 0 !important; }
  .ms-1  { margin-inline-start: var(--space-1) !important; }
  .ms-2  { margin-inline-start: var(--space-2) !important; }
  .ms-3  { margin-inline-start: var(--space-3) !important; }
  .ms-4  { margin-inline-start: var(--space-4) !important; }
  .ms-6  { margin-inline-start: var(--space-6) !important; }
  .ms-8  { margin-inline-start: var(--space-8) !important; }
  .ms-auto { margin-inline-start: auto !important; }

  /* margin-inline-end (= "left" in RTL) */
  .me-0  { margin-inline-end: 0 !important; }
  .me-1  { margin-inline-end: var(--space-1) !important; }
  .me-2  { margin-inline-end: var(--space-2) !important; }
  .me-3  { margin-inline-end: var(--space-3) !important; }
  .me-4  { margin-inline-end: var(--space-4) !important; }
  .me-6  { margin-inline-end: var(--space-6) !important; }
  .me-8  { margin-inline-end: var(--space-8) !important; }
  .me-auto { margin-inline-end: auto !important; }

  /* mx / my shortcuts */
  .mx-auto { margin-inline: auto !important; }
  .mx-0    { margin-inline: 0 !important; }
  .mx-2    { margin-inline: var(--space-2) !important; }
  .mx-4    { margin-inline: var(--space-4) !important; }
  .mx-6    { margin-inline: var(--space-6) !important; }

  .my-0  { margin-block: 0 !important; }
  .my-2  { margin-block: var(--space-2) !important; }
  .my-4  { margin-block: var(--space-4) !important; }
  .my-6  { margin-block: var(--space-6) !important; }
  .my-8  { margin-block: var(--space-8) !important; }
  .my-12 { margin-block: var(--space-12) !important; }
  .my-16 { margin-block: var(--space-16) !important; }

  /* padding-block-start */
  .pt-0  { padding-block-start: 0 !important; }
  .pt-2  { padding-block-start: var(--space-2) !important; }
  .pt-4  { padding-block-start: var(--space-4) !important; }
  .pt-6  { padding-block-start: var(--space-6) !important; }
  .pt-8  { padding-block-start: var(--space-8) !important; }
  .pt-12 { padding-block-start: var(--space-12) !important; }
  .pt-16 { padding-block-start: var(--space-16) !important; }
  .pt-24 { padding-block-start: var(--space-24) !important; }
  .pt-32 { padding-block-start: var(--space-32) !important; }

  /* padding-block-end */
  .pb-0  { padding-block-end: 0 !important; }
  .pb-2  { padding-block-end: var(--space-2) !important; }
  .pb-4  { padding-block-end: var(--space-4) !important; }
  .pb-6  { padding-block-end: var(--space-6) !important; }
  .pb-8  { padding-block-end: var(--space-8) !important; }
  .pb-12 { padding-block-end: var(--space-12) !important; }
  .pb-16 { padding-block-end: var(--space-16) !important; }
  .pb-24 { padding-block-end: var(--space-24) !important; }
  .pb-32 { padding-block-end: var(--space-32) !important; }

  /* px / py shortcuts (logical) */
  .px-0 { padding-inline: 0 !important; }
  .px-2 { padding-inline: var(--space-2) !important; }
  .px-4 { padding-inline: var(--space-4) !important; }
  .px-6 { padding-inline: var(--space-6) !important; }
  .px-8 { padding-inline: var(--space-8) !important; }

  .py-0  { padding-block: 0 !important; }
  .py-2  { padding-block: var(--space-2) !important; }
  .py-4  { padding-block: var(--space-4) !important; }
  .py-6  { padding-block: var(--space-6) !important; }
  .py-8  { padding-block: var(--space-8) !important; }
  .py-12 { padding-block: var(--space-12) !important; }
  .py-16 { padding-block: var(--space-16) !important; }

  /* ============================================================
     Accessibility helpers
     ============================================================ */

  .sr-only {
    position: absolute !important;
    inline-size: 1px !important;
    block-size: 1px !important;
    padding: 0 !important;
    margin: -1px !important;
    overflow: hidden !important;
    clip: rect(0, 0, 0, 0) !important;
    clip-path: inset(50%) !important;
    white-space: nowrap !important;
    border: 0 !important;
  }

  .not-sr-only {
    position: static !important;
    inline-size: auto !important;
    block-size: auto !important;
    padding: 0 !important;
    margin: 0 !important;
    overflow: visible !important;
    clip: auto !important;
    clip-path: none !important;
    white-space: normal !important;
  }

  /* Hide visually but keep in flow for assistive tech (alternative) */
  .visually-hidden {
    clip-path: inset(50%) !important;
    block-size: 1px !important;
    inline-size: 1px !important;
    overflow: hidden !important;
    position: absolute !important;
    white-space: nowrap !important;
  }

  /* ============================================================
     Bidi isolation — for LTR digits inside Hebrew text
     ============================================================ */

  .bidi-iso {
    unicode-bidi: isolate !important;
    direction: ltr !important;
    display: inline-block !important;
  }

  .bidi-iso--block {
    unicode-bidi: isolate !important;
    direction: ltr !important;
    display: block !important;
  }

  /* ============================================================
     Typography size utilities
     ============================================================ */

  .text-xs    { font-size: var(--text-xs) !important; }
  .text-sm    { font-size: var(--text-sm) !important; }
  .text-base  { font-size: var(--text-base) !important; }
  .text-md    { font-size: var(--text-md) !important; }
  .text-lg    { font-size: var(--text-lg) !important; }
  .text-xl    { font-size: var(--text-xl) !important; }
  .text-2xl   { font-size: var(--text-2xl) !important; }
  .text-3xl   { font-size: var(--text-3xl) !important; }
  .text-4xl   { font-size: var(--text-4xl) !important; }
  .text-hero  { font-size: var(--text-hero) !important; line-height: var(--lh-tight) !important; }

  /* Text alignment (RTL-safe) */
  .text-start   { text-align: start !important; }
  .text-end     { text-align: end !important; }
  .text-center  { text-align: center !important; }
  .text-justify { text-align: justify !important; }

  /* Line heights */
  .leading-tight  { line-height: var(--lh-tight) !important; }
  .leading-snug   { line-height: var(--lh-snug) !important; }
  .leading-normal { line-height: var(--lh-normal) !important; }
  .leading-loose  { line-height: var(--lh-loose) !important; }

  /* Tracking */
  .tracking-tight   { letter-spacing: var(--tracking-tight) !important; }
  .tracking-normal  { letter-spacing: var(--tracking-normal) !important; }
  .tracking-wide    { letter-spacing: var(--tracking-wide) !important; }
  .tracking-eyebrow { letter-spacing: var(--tracking-eyebrow) !important; }

  /* Transform */
  .uppercase   { text-transform: uppercase !important; }
  .lowercase   { text-transform: lowercase !important; }
  .capitalize  { text-transform: capitalize !important; }
  .normal-case { text-transform: none !important; }

  /* Decoration */
  .underline    { text-decoration: underline !important; }
  .no-underline { text-decoration: none !important; }

  /* Truncation */
  .truncate {
    overflow: hidden !important;
    text-overflow: ellipsis !important;
    white-space: nowrap !important;
  }

  .clamp-2 {
    display: -webkit-box !important;
    -webkit-line-clamp: 2 !important;
    line-clamp: 2 !important;
    -webkit-box-orient: vertical !important;
    overflow: hidden !important;
  }

  .clamp-3 {
    display: -webkit-box !important;
    -webkit-line-clamp: 3 !important;
    line-clamp: 3 !important;
    -webkit-box-orient: vertical !important;
    overflow: hidden !important;
  }

  /* ============================================================
     Color utilities
     ============================================================ */

  .color-ink         { color: var(--ink-deep) !important; }
  .color-ink-medium  { color: var(--ink-medium) !important; }
  .color-ivory       { color: var(--ivory) !important; }
  .color-ivory-warm  { color: var(--ivory-warm) !important; }
  .color-brass       { color: var(--brass) !important; }
  .color-brass-deep  { color: var(--brass-deep) !important; }
  .color-brass-glow  { color: var(--brass-glow) !important; }
  .color-sage        { color: var(--sage) !important; }
  .color-gold        { color: var(--gold) !important; }
  .color-fg          { color: var(--fg) !important; }
  .color-fg-muted    { color: var(--fg-muted) !important; }
  .color-fg-on-dark  { color: var(--fg-on-dark) !important; }
  .color-accent      { color: var(--accent) !important; }

  /* ============================================================
     Background utilities
     ============================================================ */

  .bg-ivory      { background-color: var(--ivory) !important; }
  .bg-ivory-warm { background-color: var(--ivory-warm) !important; }
  .bg-ink-deep   { background-color: var(--ink-deep) !important; }
  .bg-ink-medium { background-color: var(--ink-medium) !important; }
  .bg-brass      { background-color: var(--brass) !important; }
  .bg-brass-deep { background-color: var(--brass-deep) !important; }
  .bg-sage       { background-color: var(--sage) !important; }
  .bg-transparent { background-color: transparent !important; }
  .bg-bg         { background-color: var(--bg) !important; }
  .bg-bg-alt     { background-color: var(--bg-alt) !important; }

  /* ============================================================
     Font family + weight utilities
     ============================================================ */

  .font-display-he { font-family: var(--font-display-he) !important; }
  .font-display-en { font-family: var(--font-display-en) !important; }
  .font-body       { font-family: var(--font-body) !important; }
  .font-mono       { font-family: var(--font-mono) !important; }

  .weight-400 { font-weight: 400 !important; }
  .weight-500 { font-weight: 500 !important; }
  .weight-600 { font-weight: 600 !important; }
  .weight-700 { font-weight: 700 !important; }

  /* ============================================================
     Eyebrow (small uppercase label, common premium pattern)
     ============================================================ */

  .eyebrow {
    font-family: var(--font-body) !important;
    font-size: var(--text-xs) !important;
    font-weight: var(--fw-semibold) !important;
    letter-spacing: var(--tracking-eyebrow) !important;
    text-transform: uppercase !important;
    color: var(--brass) !important;
    line-height: var(--lh-normal) !important;
  }

  .eyebrow--ivory { color: var(--ivory) !important; }
  .eyebrow--muted { color: var(--fg-muted) !important; }

  /* ============================================================
     Display + visibility
     ============================================================ */

  .block        { display: block !important; }
  .inline-block { display: inline-block !important; }
  .inline       { display: inline !important; }
  .hidden       { display: none !important; }

  @media (max-width: 600px) {
    .hidden-mobile { display: none !important; }
  }

  @media (min-width: 601px) {
    .hidden-desktop { display: none !important; }
  }

  /* ============================================================
     Border radius
     ============================================================ */

  .radius-sm     { border-radius: var(--radius-sm) !important; }
  .radius-md     { border-radius: var(--radius-md) !important; }
  .radius-lg     { border-radius: var(--radius-lg) !important; }
  .radius-xl     { border-radius: var(--radius-xl) !important; }
  .radius-pill   { border-radius: var(--radius-pill) !important; }
  .radius-circle { border-radius: var(--radius-circle) !important; }
  .radius-none   { border-radius: 0 !important; }

  /* ============================================================
     Shadows
     ============================================================ */

  .shadow-soft   { box-shadow: var(--shadow-soft) !important; }
  .shadow-strong { box-shadow: var(--shadow-strong) !important; }
  .shadow-none   { box-shadow: none !important; }

  /* ============================================================
     Position helpers
     ============================================================ */

  .relative { position: relative !important; }
  .absolute { position: absolute !important; }
  .fixed    { position: fixed !important; }
  .sticky   { position: sticky !important; }
  .static   { position: static !important; }

  /* ============================================================
     Overflow
     ============================================================ */

  .overflow-hidden { overflow: hidden !important; }
  .overflow-auto   { overflow: auto !important; }
  .overflow-x-hidden { overflow-x: hidden !important; }
  .overflow-y-auto   { overflow-y: auto !important; }

  /* ============================================================
     Sizing
     ============================================================ */

  .w-full { inline-size: 100% !important; width: 100% !important; }
  .h-full { block-size: 100% !important; height: 100% !important; }
  .min-h-screen { min-block-size: 100vh !important; min-block-size: 100dvh !important; }

  /* ============================================================
     CANONICAL CARD COMPONENTS — single source of truth
     (Constitution §10.2 — tokens are single-source; no forks).

     NOTE — the button system moved OUT of this file (2026-06-15 unify
     pass) to css/components/buttons.css, which is UNLAYERED and linked
     after the section CSS so it wins ties without `!important`. The
     `.card` family stays here in @layer utilities. If you need a new
     CARD look, EXTEND with a `.card--*` variant here, never a bespoke
     rule in a section file.

     Source this generalizes:  .card ← .directions__card

     Aligns the ~6 card species (directions card, testimonial quote,
     gallery + culinary media tiles, press article card) across the site.

     NOTE — section concerns stay in section CSS: positioning
     (position / inset / z-index / max-inline-size) is deliberately
     omitted so .card is position-agnostic and any section can drop it
     in (e.g. directions.css keeps its own absolute/inset/z-index).

     Tokens consumed (all from css/tokens.css — single-source):
       sizing/space:  --space-3, --space-6
       color:         --ivory, --bg, --brass
       radius:        --radius-md, --radius-lg
       elevation:     --shadow-strong, --shadow-soft
       motion:        --dur-cinema, --ease-out-cinema
       media zoom:    --card-zoom
     ============================================================ */

  /* ---- Card base (from .directions__card) ----------------------- *
   * Position-agnostic: NO position / inset / z-index / max-inline-size. */
  .card {
    display: flex !important;
    flex-direction: column !important;
    gap: var(--space-3) !important;
    padding: var(--space-6) !important;
    background: color-mix(in srgb, var(--ivory) 88%, transparent) !important;
    -webkit-backdrop-filter: blur(10px) !important;
    backdrop-filter: blur(10px) !important;
    border: 1px solid var(--brass) !important;
    border-radius: var(--radius-md) !important;
    box-shadow: var(--shadow-strong) !important;
  }

  /* ---- Card variants ------------------------------------------- */

  /* Opaque ivory testimonial card. Generalizes .testimonial. */
  .card--quote {
    background: var(--bg) !important;
    border: 0 !important;
    border-radius: var(--radius-lg) !important;
    box-shadow: var(--shadow-soft) !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }

  /* Image tile w/ hover-zoom contract. Generalizes gallery + culinary
     dish tiles. The child <img> owns the transform; the tile clips it. */
  .card--media {
    padding: 0 !important;
    overflow: hidden !important;
    border-radius: var(--radius-md) !important;
    position: relative !important;
    isolation: isolate !important;
    border: 0 !important;
    box-shadow: none !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }
  .card--media img {
    transition: transform var(--dur-cinema) var(--ease-out-cinema) !important;
  }
  @media (hover: hover) and (pointer: fine) {
    .card--media:hover img { transform: scale(var(--card-zoom)) !important; }
  }

  /* Full-bleed image-led editorial card. Generalizes press article card. */
  .card--editorial {
    padding: 0 !important;
    position: relative !important;
    overflow: hidden !important;
    isolation: isolate !important;
    border: 0 !important;
    border-radius: 0 !important;
    box-shadow: none !important;
    -webkit-backdrop-filter: none !important;
    backdrop-filter: none !important;
  }

  /* Reduced-motion: silence the media zoom. (Button press feedback is
     silenced in css/components/buttons.css alongside the .btn rules.) */
  @media (prefers-reduced-motion: reduce) {
    .card--media:hover img { transform: none !important; }
  }

}

/* ===========================================================================
   hero-scene.css — cinematic scroll-pinned hero (REBUILT 2026-06-15)
   ---------------------------------------------------------------------------
   VERBATIM 1:1 PORT of the findrealestate sandbox hero
   (`…/findrealestate-clone - עותק/`):
     • `.hero_*` layer rules ← `_next/static/css/f46e979614fc3394.css`
     • `.gamos-*` composer/cue/prompt rules ← `_next/static/css/a463080343a8b988.css`
   Class names are copied from the source (user directive 2026-06-15). Verified
   no collision elsewhere in the repo (`.gamos-cue`/`.gamos-hero` were NOT used
   by /press/ — the earlier "collision" note was stale).

   REM-BASE: the sandbox drives every hero `rem` from a viewport-responsive root
   font-size — `html{font-size:2.6666666667vw}` (<768) → `0.5208333333vw`
   (≥768) → `10px` (≥1920). GAMOS-SITE's global root is locked at 16px (base.css),
   so we reproduce the sandbox's exact pixel geometry with a scoped custom
   property `--rem` and write every source `Xrem` as `calc(X * var(--rem))`.
   This is root-independent (no `em` compounding) → pixel-identical at every
   width to the sandbox. (--rem 0.5208333vw = 7.5px @1440 = sandbox @1440.)

   The whole block is unlayered → it wins over base.css's `@layer base` media
   reset (`img{height:auto}`) without `!important`, so `.hero_house img{height:100%}`
   etc. take effect exactly as in the sandbox.
   ========================================================================= */

/* ----- scoped responsive rem-base (mirrors sandbox html{font-size}) -------- */
#hero.hero_root { --rem: 2.6666666667vw; }
@media (min-width: 768px)  { #hero.hero_root { --rem: 0.5208333333vw; } }
@media (min-width: 1920px) { #hero.hero_root { --rem: 10px; } }

/* ----------------------------------------------------------- ROOT / PIN ---- */
/* sandbox: height 350vh (<768) / 500vh (≥768); margin-bottom:-100vh.
   We add background+isolation+z-index so the hero sits cleanly above the site
   chrome and the cream join to #hall-portal is seamless. The root is visible
   from first paint (2026-10-11); see the .hero_content/.hero_clouds rule below. */
.hero_root {
  position: relative;
  height: 300vh;
  margin-bottom: -100vh;
  background: var(--ivory);
  isolation: isolate;
  z-index: 110;
}
@media (min-width: 768px) { .hero_root { height: 400vh; } }

/* 2026-10-11 (§3 amendment): the sky + desert paint at first paint (they are the LCP);
   only the text and the clouds wait for the JS entrance fade (js/hero-scene.js). */
.hero_content,
.hero_clouds { visibility: hidden; }

.hero_top { position: sticky; top: 0; height: 100vh; }

.hero_bg { overflow: hidden; pointer-events: none; }
.hero_back,
.hero_bg { position: absolute; top: 0; left: 0; right: 0; bottom: 0; }
.hero_back img { width: 100%; height: 100%; object-fit: cover; object-position: center center; max-width: none; }

/* desert subject — rises (y:-40%) + grows (scale:1.3) on scroll */
.hero_house {
  position: absolute; top: 60vh; left: 0; right: 0;
  height: calc(33.4 * var(--rem)); z-index: 1; transform-origin: bottom center;
}
@media (min-width: 768px) { .hero_house { height: calc(170.8 * var(--rem)); } }
/* <picture> wrapper (index.html ships responsive WebP) must fill the house so the
   inner <img>'s height:100% resolves against the full house box, not the picture's
   intrinsic height. Without this the desert collapses to ~369px. */
.hero_house picture { display: block; width: 100%; height: 100%; }
.hero_house img { width: 100%; height: 100%; object-fit: contain; max-width: none; }

/* second desert copy, MASKED by the logo letters (mask data-URI injected by JS,
   so the letters "fill" with the desert texture). opacity:0 → revealed on scroll. */
.hero_composite {
  position: absolute; top: 0; left: 0; right: 0; bottom: 0; z-index: 1; opacity: 0;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
  -webkit-mask-position: center center; mask-position: center center;
  /* mask-size is owned by JS (js/hero-scene.js applyCompositeMaskSize) — it fits the
     active logo's viewBox ratio INSIDE the measured .hero_logo box (letterbox), so
     the filled composite matches the outline <svg> for ANY logo (HE/EN/FR) at ANY
     breakpoint. The old hardcoded per-breakpoint mask-size stretched logos whose
     aspect ≠ the box; the dynamic fit replaces it. */
}

.hero_clouds { top: 0; left: 0; right: 0; bottom: 0; }
.hero_cloud,
.hero_clouds { position: absolute; z-index: 2; }
.hero_cloud:first-child {
  top: calc(33.7 * var(--rem)); left: calc(-57.2 * var(--rem));
  width: calc(70.2 * var(--rem)); height: calc(29.8 * var(--rem));
}
@media (min-width: 768px) {
  .hero_cloud:first-child { top: 25%; left: calc(-33.72 * var(--rem)); width: calc(112.4 * var(--rem)); height: calc(47.7 * var(--rem)); }
}
.hero_cloud:last-child {
  top: calc(37.12 * var(--rem)); right: calc(-41.2 * var(--rem));
  width: calc(55.7 * var(--rem)); height: calc(23.6 * var(--rem));
}
@media (min-width: 768px) {
  .hero_cloud:last-child { top: 20%; right: calc(-33.72 * var(--rem)); width: calc(93.6 * var(--rem)); height: calc(39.7 * var(--rem)); }
}
.hero_cloud img { width: 100%; height: 100%; object-fit: cover; max-width: none; }

/* logo letters — white-stroke OUTLINE (drawSVG strokes them on); crossfades to
   the filled .hero_composite. box = 97.7rem × (97.7×79.53/219.78)=35.4rem. */
.hero_logo {
  position: absolute; z-index: 1; opacity: 0;
  top: calc(50% - (5.1 * var(--rem))); left: calc(50% - (11.75 * var(--rem)));
  width: calc(23.5 * var(--rem)); height: calc(10.2 * var(--rem));
}
@media (min-width: 768px) {
  .hero_logo { top: calc(50% - (17.7 * var(--rem))); left: calc(50% - (48.85 * var(--rem))); width: calc(97.7 * var(--rem)); height: calc(35.4 * var(--rem)); }
}
.hero_logo svg { width: 100%; height: 100%; overflow: visible; }
.hero_logo path { fill: rgba(0, 0, 0, 0); stroke: #fff; stroke-width: 0.75px; }
@media (min-width: 768px) { .hero_logo path { stroke-width: 0.5px; } }

/* off-screen smoke/overlay overlap (mirrors sandbox .hero_overlap) */
.hero_overlap { position: absolute; top: 0; left: 0; right: 0; bottom: 100vh; pointer-events: none; }

.hero_smoke { position: absolute; left: 0; right: 0; bottom: 0; height: calc(45 * var(--rem)); z-index: 3; }
@media (min-width: 768px) { .hero_smoke { height: calc(62 * var(--rem)); } }
.hero_top .hero_smoke { transform: translateY(70%); }   /* rises to 0% on scroll */
.hero_smoke img { width: 100%; height: 100%; object-fit: cover; object-position: top center; max-width: none; }

/* overlay fade — sandbox fades to #fff; GAMOS-CREAM override fades to ivory so
   the join to #hall-portal is seamless. */
.hero_overlay {
  position: absolute; left: 0; right: 0; bottom: 0; height: calc(10 * var(--rem)); z-index: 3;
  background: linear-gradient(180deg, color-mix(in srgb, var(--ivory) 0%, transparent), var(--ivory));
}
@media (min-width: 768px) { .hero_overlay { height: calc(30.9 * var(--rem)); } }

.hero_content { position: relative; z-index: 4; display: grid; align-items: center; height: 100%; padding-bottom: calc(15 * var(--rem)); }
@media (min-width: 768px) { .hero_content { padding-bottom: calc(22.8 * var(--rem)); } }

/* Hero text — sandbox geometry/sizes kept verbatim, but COLOURS + WEIGHTS
   re-pointed to the GAMOS palette (§5) and the canonical section-header language
   (2026-06-15, user request "התאם צבעים + עדן את המשפטים הם עבים"):
     eyebrow  → --accent (brass),  --fw-semibold (was #ac9a78 / 600)
     title    → --fg (ink-deep),   --fw-bold     (was #191410 / 800 — too heavy)
     accent   → --brass-deep        (was #857147 — ~identical, now tokenised)
     subtitle → --fg-muted,         --fw-medium   (was #716657 / 500)
   §10.2: no hard-coded hex — all via tokens. */
.hero_eyebrow {
  /* 2026-06-16: was 1.8·rem solid brass — user reported it tiny + wanted the
     brand dark texture. Bumped + texture-filled (fill applied in @supports). */
  margin: 0 0 calc(1.6 * var(--rem)); text-align: center;
  font-family: "Heebo", sans-serif; font-weight: var(--fw-semibold);
  font-size: calc(2.6 * var(--rem)); letter-spacing: 0.18em; color: var(--fg);
}
.hero_title h1 {
  margin: 0; font-family: "Heebo", sans-serif; font-weight: var(--fw-bold);
  font-size: calc(5.4 * var(--rem)); line-height: 100%; letter-spacing: -0.02em;
  text-align: center; color: var(--brass); max-inline-size: none;
}
.hero_title h1 { color: var(--cocoa); } /* Large text contrast over the sky. */
@media (min-width: 768px) { .hero_title h1 { font-size: calc(14 * var(--rem)); } }
/* 2026-06-16 (swapped): line 1 → solid brass, NO texture; line 2 (.accent) →
   brand DARK texture (typo-on-light). The solid `color`s are the
   graceful-degradation fallback when background-clip:text is unsupported
   (line 1 → brass, line 2 → ink). */
.hero_title .accent { color: var(--fg); }

/* ---- Texture fill (graceful-degradation; mirrors texture-text.css) ----
   Eyebrow + title line 2 (.accent) take the DARK gold-flecked brand texture.
   SplitText wraps each title word in a .hero_word span that renders ON TOP
   of the h1, so the fill must live on the SPANS too (a transparent span over
   the h1 shows nothing — the "invisible but selectable" bug). Same multi-span
   technique as .marquee__text. Line 1 (h1 words) stays solid brass. */
@supports ((-webkit-background-clip: text) or (background-clip: text)) {
  .hero_eyebrow,
  .hero_title .accent,
  .hero_title .accent .hero_word {
    background-repeat: no-repeat;
    background-size: 100% 100%;
    background-position: center;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    background-image: var(--typo-on-light);
  }
  .hero_title h1,
  .hero_title h1 .hero_word {
    -webkit-text-fill-color: var(--cocoa);
    background: none;
  }
}
/* Short landscape screens need a horizontal reading layout inside the same
   animated content layer. No GSAP timing or scene height changes. */
@media (min-width: 769px) and (max-height: 600px) {
  #hero .hero_content {
    display: grid;
    grid-template-columns: 1fr 1fr;
    align-content: center;
    gap: var(--space-2) var(--space-6);
    padding: 88px var(--space-8) var(--space-4);
  }
  #hero .hero_eyebrow { grid-column: 1 / -1; font-size: var(--text-xs); margin: 0; }
  #hero .hero_title { grid-column: 1; grid-row: 2 / 5; }
  #hero .hero_title h1 { font-size: clamp(var(--text-xl), 4vw, var(--text-2xl)); line-height: 1.12; }
  #hero .hero_text { grid-column: 2; font-size: var(--text-base); margin: 0; }
  #hero .hero_stats { grid-column: 2; font-size: var(--text-xs); margin: 0; }
  #hero .hero_ctas { grid-column: 2; margin: 0; gap: var(--space-2); }
  #hero .hero_ctas .btn { font-size: var(--text-xs); padding-block: var(--space-2); }
  #hero .hero_top > .gamos-cue { display: none; }
}
.hero_text {
  margin: calc(1.5 * var(--rem)) 0 0; text-align: center; text-wrap: balance;
  font-family: "Heebo", sans-serif; font-weight: var(--fw-medium);
  font-size: calc(1.6 * var(--rem)); line-height: 150%; color: var(--fg-muted); max-inline-size: none;
}
@media (min-width: 768px) {
  .hero_text { margin: calc(2 * var(--rem)) 0 0; font-size: calc(3.2 * var(--rem)); line-height: 130%; letter-spacing: -0.01em; }
}

/* ===========================================================================
   .gamos-hero — the interactive composer section ("the section after the hero")
   VERBATIM from the sandbox GAMOS-HERO-CTA block. Lives at #hall-portal,
   between #hero and #lounge. base image + EVENTS/RESORT wordmark CTAs
   (hover-bulge + dim-siblings via :has()) + brass prompt + scroll cue.
   ========================================================================= */
/* The hero's `margin-bottom:-100vh` tucks this composer up under the hero's
   final screen-height (the sandbox's reveal-from-under). Because the hero is a
   stacking context with z-index:110 (so site chrome layers correctly), the
   composer must sit ABOVE it to be revealed during that overlap — otherwise the
   hero paints over it and the page appears to skip straight to #lounge. */
#hall-portal { position: relative; z-index: 111; }
.gamos-hero {
  position: relative; width: 100%; aspect-ratio: 2048 / 1360;
  background: var(--ivory); overflow: hidden; isolation: isolate;
}
.gamos-hero__base {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: center; z-index: 1;
  pointer-events: none; user-select: none;
}
.gamos-hero__logo {
  position: absolute; top: 4%; left: 4%; width: clamp(140px, 12vw, 260px);
  height: auto; z-index: 2; pointer-events: none; user-select: none;
}
.gamos-hero__cta {
  position: absolute; left: 50%; transform: translateX(-50%);
  width: clamp(220px, 22vw, 360px); height: auto; cursor: pointer;
  text-decoration: none; z-index: 3;
  transition: opacity 280ms ease, filter 280ms ease;
  outline: 0 solid transparent; -webkit-user-drag: none;
}
.gamos-hero__cta--events { top: 42%; z-index: 3; }
.gamos-hero__cta--resort { top: 51%; z-index: 4; }
.gamos-hero__cta img {
  display: block; width: 100%; height: auto; max-width: none;
  transition: filter 280ms ease, transform 320ms cubic-bezier(.16,1,.3,1);
  -webkit-user-drag: none; user-select: none;
}
.gamos-hero__cta:hover img,
.gamos-hero__cta:focus-visible img {
  transform: scale(1.06);
  filter: brightness(1.10) drop-shadow(0 0 28px color-mix(in srgb, var(--brass) 55%, transparent));
}
.gamos-hero__cta:active img { transform: scale(0.98); }
.gamos-hero__cta:focus-visible { outline: none; box-shadow: var(--focus-ring-offset); border-radius: var(--radius-md); }
.gamos-hero:has(.gamos-hero__cta:hover) .gamos-hero__cta:not(:hover),
.gamos-hero:has(.gamos-hero__cta:focus-visible) .gamos-hero__cta:not(:focus-visible) {
  opacity: .55; filter: brightness(.92);
}

.gamos-hero__prompt {
  position: absolute; top: 34%; left: 50%; transform: translateX(-50%); z-index: 5;
  display: flex; flex-direction: column; align-items: center; gap: .9rem;
  pointer-events: none; text-align: center; white-space: nowrap;
}
.gamos-hero__prompt-text {
  font-family: Heebo, sans-serif; font-weight: 500;
  font-size: clamp(1.3rem, 1.5vw, 2rem); letter-spacing: .32em; color: var(--brass-deep); opacity: 0;
  animation: gamos-prompt-in 1100ms cubic-bezier(.16,1,.3,1) 400ms forwards,
             gamos-prompt-pulse 3200ms ease-in-out 1600ms infinite;
}
.gamos-hero__prompt-line {
  width: 1px; height: 0;
  background: linear-gradient(180deg, var(--brass), color-mix(in srgb, var(--brass) 0%, transparent));
  animation: gamos-prompt-line 900ms cubic-bezier(.16,1,.3,1) 1100ms forwards;
}
.gamos-hero__prompt-arrow {
  width: clamp(18px, 1.4vw, 24px); height: clamp(18px, 1.4vw, 24px); opacity: 0;
  animation: gamos-prompt-in 900ms cubic-bezier(.16,1,.3,1) 1100ms forwards,
             gamos-arrow-bob 2400ms ease-in-out 2000ms infinite;
}
.gamos-hero__prompt-arrow svg {
  display: block; width: 100%; height: 100%;
  stroke: var(--brass); fill: none; stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round;
}

/* ----------------------------------------------------------- SCROLL CUE ---- */
/* Brass pill + falling dot. Two instances: inside .hero_top (→#hall-portal) and
   inside .gamos-hero (→#lounge). VERBATIM from the sandbox .gamos-cue. */
.gamos-cue {
  position: absolute; inset-block-end: clamp(24px, 5vh, 48px);
  left: 50%; transform: translateX(-50%); z-index: 20;
  visibility: visible; display: inline-flex; align-items: center; justify-content: center;
  inline-size: 26px; block-size: 60px;
  border: 1.5px solid color-mix(in srgb, var(--brass-deep) 85%, transparent); border-radius: 9999px;
  text-decoration: none; pointer-events: auto; opacity: 1;
  transition: border-color 240ms cubic-bezier(.2,.8,.2,1);
}
.gamos-cue:hover, .gamos-cue:focus-visible { border-color: var(--brass-deep); }
.gamos-cue:focus-visible { outline: none; box-shadow: var(--focus-ring-offset); }

/* Single-cue invariant. The hero's `margin-bottom:-100vh` (+ z-index:110) tucks
   the #hall-portal composer under the hero's last pinned frame, so the HERO cue
   (in .hero_top, → #hall-portal) and the COMPOSER cue (in .gamos-hero, → #lounge)
   render in the same bottom band → two cues at once. Once the hero no longer owns
   the viewport, its cue has served its "scroll into the composer" purpose — hide
   it, leaving only the composer cue. `data-hero-mode` is already maintained every
   scroll frame by js/site-nav-hover-reveal.js (true only while the pin fills the
   screen), so no new JS. Fixes desktop too (the overlap exists at both widths). */
html:not([data-hero-mode="true"]) .hero_top .gamos-cue {
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-base) var(--ease-out-cinema);
}
.gamos-cue__track { position: relative; display: block; inline-size: 1px; block-size: 34px; background: color-mix(in srgb, var(--brass-deep) 40%, transparent); }
.gamos-cue__dot {
  position: absolute; inset-inline-start: -2.5px; inset-block-start: 0;
  inline-size: 6px; block-size: 6px; background: var(--brass-deep); border-radius: 50%;
  animation: gamos-cue-fall 1.6s cubic-bezier(.55,0,.55,1) infinite;
}

/* ----------------------------------------------------------- KEYFRAMES ----- */
@keyframes gamos-prompt-in   { 0% { opacity: 0; transform: translateY(8px); } 100% { opacity: 1; transform: translateY(0); } }
@keyframes gamos-prompt-line { 0% { height: 0; opacity: 0; } 100% { height: clamp(28px, 4vh, 52px); opacity: 1; } }
@keyframes gamos-prompt-pulse { 0%, 100% { opacity: 1; } 50% { opacity: .55; } }
@keyframes gamos-arrow-bob   { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(6px); } }
@keyframes gamos-cue-fall    { 0% { transform: translateY(-4px); opacity: 0; } 20% { opacity: 1; } 80% { opacity: 1; } 100% { transform: translateY(34px); opacity: 0; } }

/* -------------------------------------------------------- REDUCED MOTION ---- */
/* §8/§9: scrub off, reveals static. JS shows the final composition (logo filled,
   subject in place); only the cue + prompt loops freeze. */
@media (prefers-reduced-motion: reduce) {
  .hero_root { visibility: visible; }
  .gamos-cue__dot,
  .gamos-hero__prompt-text,
  .gamos-hero__prompt-line,
  .gamos-hero__prompt-arrow { animation: none; opacity: 1; }
  .gamos-hero__prompt-line { height: clamp(28px, 4vh, 52px); }
  .gamos-hero__cta img, .gamos-hero__cta { transition: none; }
  .gamos-hero__cta:hover img, .gamos-hero__cta:focus-visible img { transform: none; }
}

/* ------------------------------------------------ CONVERSION ADDITIONS ----- */
/* 2026-07-13 (§3 amendment, marketing-critique conversion pass): trust line +
   CTA pair appended INSIDE .hero_content. Additive only — the children inherit
   the existing content scrub tween; no timeline/scrub changes. Buttons use the
   canonical buttons.css line-language (on-light roles: the hero text sits on
   the bright sky/desert), scaled with the scene's --rem so proportions hold. */
.hero_stats {
  margin: calc(1.4 * var(--rem)) 0 0; text-align: center;
  font-family: var(--font-body); font-weight: var(--fw-medium);
  font-size: calc(1.4 * var(--rem)); letter-spacing: 0.08em; color: var(--fg-muted);
  max-inline-size: none; /* the global <p> measure cap would shrink+right-pin it in the grid (like .hero_text, which also overrides it) */
}
@media (min-width: 768px) {
  .hero_stats { margin-top: calc(2 * var(--rem)); font-size: calc(2.2 * var(--rem)); }
}
.hero_ctas {
  margin: calc(2 * var(--rem)) 0 0;
  display: flex; justify-content: center; align-items: center;
  gap: calc(2.4 * var(--rem)); flex-wrap: wrap;
}
@media (min-width: 768px) { .hero_ctas { margin-top: calc(2.8 * var(--rem)); gap: calc(4 * var(--rem)); } }
/* Scale the editorial labels with the scene (base .btn is a fixed 13px). */
.hero_ctas .btn { font-size: calc(1.5 * var(--rem)); }
@media (min-width: 768px) {
  .hero_ctas .btn { font-size: calc(1.8 * var(--rem)); }
  .hero_ctas .btn--primary-lg { font-size: calc(2.2 * var(--rem)); }
}

/* Copy is UI, not artwork: scene scaling must never shrink it below readable
   sizes on tablets. Keep the portrait composition in the upper sky area. */
@media (min-width: 769px) {
  .hero_text { font-size: max(var(--text-base), calc(3.2 * var(--rem))); }
  .hero_stats { font-size: max(var(--text-sm), calc(2.2 * var(--rem))); }
  .hero_ctas .btn { font-size: max(var(--text-sm), calc(1.8 * var(--rem))); }
  .hero_ctas .btn--primary-lg { font-size: max(var(--text-sm), calc(2.2 * var(--rem))); }
}
@media (min-width: 769px) and (max-width: 1023.98px) and (min-height: 601px) {
  #hero .hero_content {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: var(--space-6);
    padding: 128px var(--space-8) var(--space-8);
  }
  #hero .hero_eyebrow { margin: 0; font-size: var(--text-sm); }
  #hero .hero_title h1 { font-size: clamp(var(--text-2xl), 7vw, var(--text-4xl)); }
  #hero .hero_text { margin: 0; max-inline-size: 46ch; }
  #hero .hero_stats { margin: 0; }
  #hero .hero_ctas { margin: 0; gap: var(--space-5); }
}

/* ---------------------------------------- GESTURE LANGUAGE v2 (2026-10-11) -- */
/* §3 amendment (Moshe: one gesture language site-wide). The scroll cue's
   falling dot is replaced by the site's one hand (css/components/gesture-hint.css):
   rising hand = "scroll on". Old .gamos-cue__track/__dot rules stay inert.
   The hall-portal prompt keeps its chevron (it points at the two halls); the
   tap is taught by the first-visit hint on the EVENTS wordmark instead. */
.gamos-cue__hand {
  display: block; inline-size: 22px; block-size: 22px; fill: var(--brass-deep);
  animation: gamos-cue-rise 1.6s cubic-bezier(.45,0,.25,1) infinite;
}
@keyframes gamos-cue-rise   { 0% { transform: translateY(6px); opacity: 0; } 25%, 70% { opacity: 1; } 100% { transform: translateY(-6px); opacity: 0; } }
@media (prefers-reduced-motion: reduce) {
  .gamos-cue__hand { animation: none; }
}

/* ===========================================================================
   portals.css — invisible hotspots over the bubble plate in the hero canvas
   ---------------------------------------------------------------------------
   Concept (2026-06-01 — replaces the round <video> portals):

   The hero canvas (driven by hero-video-scrub.js) plays the master video,
   whose final frame already shows the two bubbles painted into the plate.
   We overlay two transparent <button> hotspots aligned to those bubble
   positions, with PNG bubble images (extracted from PSB) as the .portal__overlay.
   The PNG itself is mostly transparent except for the bubble's outline +
   refractions — when the user hovers, we apply a brass drop-shadow + soft
   tint to the overlay PNG so only that bubble glows. The user thus sees
   the SAME bubbles they saw in the video but now lit up as a selectable
   hover state.

   Reveal: .portals.is-active toggled by js/portals.js once
   window.gamosHero.progress >= 0.92 (with hysteresis at 0.88).
   ========================================================================= */

.portals {
  /* Lives inside .hero__sticky as Layer D (NOT fixed — moved 2026-06-01). */
  position: absolute;
  inset: 0;
  display: block;             /* children are absolutely positioned */
  z-index: 20;
  pointer-events: none;       /* container = pass-through */

  opacity: 0;
  visibility: hidden;
  transition:
    opacity 0.6s var(--ease-out-cinema),
    visibility 0s linear 0.6s;
}

.portals.is-active {
  opacity: 1;
  visibility: visible;
  transition:
    opacity 0.6s var(--ease-out-cinema),
    visibility 0s linear 0s;
}


/* ---------------------------------------------------------------------------
   Portal — full-viewport plate carrying a FULL-FRAME overlay PNG, plus a
   sized click hotspot centered on its bubble.
   ---------------------------------------------------------------------------
   The portal-resort / portal-venue art (assets/images/brand/portal-*.webp,
   ~3825×~1880 source) are FULL-VIEWPORT PLATES — each contains its bubble
   positioned within the whole frame (resort bubble on the right, venue bubble
   on the left), mostly-transparent elsewhere. To land each bubble EXACTLY on
   the canvas's baked-in bubble, the overlay <img> must fill the viewport with
   the SAME math the canvas renderer uses:
     canvas: scale = max(cw/iw, ch/ih) * ZOOM_FACTOR  (ZOOM_FACTOR = 1.35)
     overlay: object-fit:cover (= max ratio) then transform: scale(1.35).
   Measured bubble centers in the 1280×720 source frame:
     RESORT ≈ (72.8%, 59.6%)   VENUE ≈ (28.0%, 59.6%)
   The visual plate is full-viewport (covers everything); the <button> itself
   is a sized invisible hotspot anchored on the bubble center so the clickable
   region, focus ring, label, and hover glow stay local to one bubble.
   --------------------------------------------------------------------------- */

/* ---------------------------------------------------------------------------
   2026-06-02 redesign — bubbles confined to a small hotspot.
   ---------------------------------------------------------------------------
   Previous spec used full-viewport overlay plates with ZOOM_FACTOR=1.35 to
   match canvas cover-math, but that turned the entire screen brass on hover.
   The user wants: small bubbles, pixel-perfect over the canvas's baked-in
   bubbles, label INSIDE the bubble (not floating below).

   New approach: each `.portal` is a small round hotspot anchored at the
   measured bubble center on the canvas (resort 72.8%/venue 28% × 59.6%).
   The .portal__overlay is now confined to the hotspot box, and the PNG is
   rendered at object-fit:contain so its bubble center sits exactly at the
   center of the hotspot. Glow filters apply only to that small image — not
   the full viewport.
   --------------------------------------------------------------------------- */

.portal {
  position: absolute;
  /* Round hotspot ≈ 22vw at desktop, capped so it never dominates the screen.
     The clip-path keeps the click region perfectly circular. */
  inline-size: clamp(180px, 22vw, 320px);
  block-size: clamp(180px, 22vw, 320px);
  border-radius: 50%;
  transform-origin: center;
  padding: 0;
  margin: 0;
  border: 0;
  background: transparent;
  cursor: pointer;
  pointer-events: auto;       /* opt-in */
  isolation: isolate;
  outline: none;
  -webkit-tap-highlight-color: transparent;

  /* Vertical center of both bubbles ≈ 59.6%. */
  top: 59.6%;

  /* Subtle scale + opacity reveal (overall fade controlled by .portals). */
  opacity: 0;
  transition:
    transform 0.7s var(--ease-out-cinema),
    opacity   0.7s var(--ease-out-cinema),
    filter    0.45s var(--ease-out-cinema);
}

/* Resort bubble center ≈ 72.8% from the left edge of the frame. */
.portal--resort {
  left: 72.8%;
  transform: translate(-50%, -50%) scale(0.94);
}
/* Venue bubble center ≈ 28.0% from the left edge of the frame. */
.portal--venue {
  left: 28.0%;
  transform: translate(-50%, -50%) scale(0.94);
}

.portals.is-active .portal--resort,
.portals.is-active .portal--venue {
  opacity: 1;
  transform: translate(-50%, -50%) scale(1);
}


/* ---------------------------------------------------------------------------
   Bubble overlay image — confined to the hotspot, contained at object-fit so
   the PNG's transparent bubble shape lands centered. Default rest state is
   nearly invisible (the canvas's baked-in bubble already shows the bubble);
   on hover/focus the PNG glows brass to indicate selection.
   --------------------------------------------------------------------------- */

.portal__overlay {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: contain;
  object-position: center;
  pointer-events: none;
  user-select: none;
  z-index: 1;
  opacity: 0;
  filter:
    drop-shadow(0 0 0 transparent)
    drop-shadow(0 0 0 transparent);
  transition:
    opacity 0.4s var(--ease-out-cinema),
    filter  0.45s var(--ease-out-cinema),
    transform 0.6s var(--ease-out-cinema);
}


/* ---------------------------------------------------------------------------
   Label — anchored to CENTER of the bubble (not its bottom). The hotspot
   box IS the bubble box now, so center-of-hotspot = center-of-bubble.
   --------------------------------------------------------------------------- */

.portal__label {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;
  transform: translate(-50%, -50%);
  text-align: center;
  font-family: var(--font-display-he);
  font-weight: var(--fw-bold);
  font-size: clamp(1.4rem, 2.2vw, 2.2rem);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--ivory);
  text-shadow:
    0 2px 12px rgba(0, 0, 0, 0.85),
    0 0 22px rgba(0, 0, 0, 0.70),
    0 0 40px rgba(0, 0, 0, 0.55);
  pointer-events: none;
  user-select: none;
  z-index: 2;
  opacity: 0.95;
  transition:
    opacity 0.4s var(--ease-out-cinema),
    transform 0.5s var(--ease-out-cinema),
    text-shadow 0.4s var(--ease-out-cinema);
}


/* ---------------------------------------------------------------------------
   Hover / focus — strong brass GLOW on the bubble overlay (this is the
   selection indicator the user explicitly asked for: "אמור להיות סימן של
   צל או משהו מואר שמראה את הבחירה"). Only the hovered bubble lights up.
   --------------------------------------------------------------------------- */

.portal:hover .portal__overlay,
.portal:focus-visible .portal__overlay {
  opacity: 1;
  transform: scale(1.04);
  filter:
    drop-shadow(0 0 14px var(--brass-glow))
    drop-shadow(0 0 32px color-mix(in srgb, var(--brass) 70%, transparent))
    brightness(1.15) saturate(1.18);
}

.portal:hover .portal__label,
.portal:focus-visible .portal__label {
  opacity: 1;
  transform: translate(-50%, calc(-50% - 4px));
  text-shadow:
    0 2px 16px rgba(0, 0, 0, 0.90),
    0 0 24px var(--brass-glow);
}

.portal:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring-offset);   /* unified offset ring (2026-06-15) */
  border-radius: 50%;
}

.portals.is-active .portal:active {
  /* Preserve center anchoring (translate) while nudging scale on press. */
  transform: translate(-50%, -50%) scale(0.97);
}


/* ---------------------------------------------------------------------------
   Click feedback — JS adds [data-clicked] on press for ~250ms before the
   expand timeline kicks in. Strong glow + ring confirms selection.
   --------------------------------------------------------------------------- */

.portal[data-clicked] .portal__overlay {
  opacity: 1;
  filter:
    drop-shadow(0 0 36px var(--brass-glow))
    drop-shadow(0 0 100px var(--brass))
    brightness(1.4) saturate(1.4);
}


/* ---------------------------------------------------------------------------
   Expand timeline — js/portals.js (WAAPI) scales to 6× over ~1s.
   While expanding, sibling fades out, body scroll-lock prevents the user
   from scrolling away mid-animation. .is-leaving on .portals dims the rest.
   --------------------------------------------------------------------------- */

.portal.is-expanding {
  z-index: 30;
  pointer-events: none;
}

.portals.is-leaving .portal:not(.is-expanding) {
  opacity: 0.18;
  pointer-events: none;
  transition: opacity 0.35s var(--ease-out-cinema);
}


/* ---------------------------------------------------------------------------
   Reduced motion — instant reveal, no glow scaling, no expand transform.
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .portals,
  .portal,
  .portal__overlay,
  .portal__label {
    transition: none !important;
  }
  .portal:hover .portal__overlay,
  .portal:focus-visible .portal__overlay {
    transform: none;
  }
  .portal:hover .portal__label,
  .portal:focus-visible .portal__label {
    transform: translate(-50%, -50%);
  }
}


/* ---------------------------------------------------------------------------
   Mobile — bubbles square-ish, slightly larger touch target.
   --------------------------------------------------------------------------- */
@media (max-width: 767px) {
  .portal {
    inline-size: 38vw;
    block-size: 38vw;
  }
  .portal__label {
    font-size: clamp(1.1rem, 4.6vw, 1.5rem);
  }
}

/* =========================================================================
   #why-gamos — early trust section (conversion pass 2026-07-13).
   A real photograph of the estate + 4 counter stats + two short verbatim
   guest quotes + the cta-band, right after #hall-portal. Desktop-first
   (§13: mobile overrides live in /mobile/css/why-gamos.css).
   Tokens only (§10.2). Stat styling mirrors about.css (single grammar).
   ========================================================================= */

.why-gamos {
  padding-block: var(--section-pad);
  background: var(--bg);
}

.why-gamos__container {
  inline-size: min(1120px, 92vw);
  margin-inline: auto;
}

/* Header centering comes from the canonical .section-header--center (the bare
   64ch box pinned inline-start gave a ragged 3-line title — user feedback
   2026-07-13). The global h2 text-wrap:balance splits the title into two even
   lines inside the centered 64ch header box. */
.why-gamos .section-header {
  margin-block-end: var(--space-8);
}

/* ---- The real-photo proof — wide, quiet frame, defined ratio (CLS §8). ---- */
.why-gamos__media {
  margin: 0;
  overflow: hidden;
  border-radius: var(--radius-sm);
}
.why-gamos__media img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: 1920 / 1440;
  object-fit: cover;
}
/* Keep the band cinematic on desktop — crop the 4:3 source to a wide frame. */
@media (min-width: 900px) {
  .why-gamos__media img { aspect-ratio: 21 / 9; }
}

/* ---- Stats — the about.css counter grammar, five-up. ---- */
.why-gamos__stats {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-6);
  margin: 0;
  padding-block: var(--space-8) 0;
}

.why-gamos__stat {
  margin: 0;
  text-align: center;
}

.why-gamos__stat dt {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-block-end: var(--space-2);
}

.why-gamos__stat dd {
  font-family: var(--font-display-luxury);
  font-size: clamp(2.25rem, 3.6vw, 3.25rem);
  font-weight: 700;
  color: var(--accent);
  line-height: 1;
  margin: 0;
}

/* Early trust signal: this repeats only the kashrut claims already documented
   in #contact, bringing an important decision factor above the long journey. */
.why-gamos__trust {
  inline-size: fit-content;
  max-inline-size: 100%;
  margin: var(--space-6) auto 0;
  padding-block: var(--space-3);
  border-block: 1px solid var(--border);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  line-height: 1.6;
  color: var(--cocoa);
  text-align: center;
  text-wrap: pretty;
}

/* ---- Two short quotes — quiet editorial cards, no slider chrome. ---- */
.why-gamos__quotes {
  list-style: none;
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-6);
  margin: 0;
  padding: var(--space-8) 0 0;
}

.why-gamos__quote {
  border-inline-start: 2px solid var(--brass);
  padding-inline-start: var(--space-4);
}

.why-gamos__quote blockquote { margin: 0; }

.why-gamos__quote p {
  margin: 0 0 var(--space-2);
  font-family: var(--font-body);
  font-weight: var(--fw-medium);
  font-size: 1.0625rem;
  line-height: 1.6;
  color: var(--fg);
}

.why-gamos__quote cite {
  font-style: normal;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  letter-spacing: var(--tracking-wide);
  color: var(--fg-muted);
}

/* ===========================================================================
   scroll-scene.css — generic baseline for non-hero scroll-driven scenes
   ---------------------------------------------------------------------------
   Used by    : #hall-resort, #hall-venue, #culinary (and any future
                section[data-scrub] not named #hero).
   Spec       : architecture/scroll-orchestrator.md §3 (DOM contract);
                architecture/scroll-video-system.md §4.1;
                video-to-website.md §6c (canvas frames).
   Owner      : Agent 18 (poster/Ken-Burns) + Agent 17 (video pipeline)
                + Agent 21 (canvas-frames migration, 2026-06-01).
   Constitution: §10.2 (tokens-only — no hard-coded values), §10.4 (RTL
                logical properties).
   ---------------------------------------------------------------------------
   Three render modes are supported via attribute selectors:
     - default               : <video class="scroll-scene__video"> as the driver
     - "poster-ken-burns"    : <picture class="scroll-scene__poster"> driven by
                                CSS variable --scene-progress (JS writes per RAF).
     - "canvas-frames"       : <canvas class="scroll-scene__canvas"> painted
                                by canvas-frame-renderer.js drawing pre-extracted
                                30fps WebP frames (Agent 21, 2026-06-01).
   ========================================================================= */

.scroll-scene {
  position: relative;
  display: block;
  isolation: isolate;
  background-color: var(--bg);
  color: var(--fg);
  /* Default progress baseline — JS overrides per scroll. Avoids a flash on
     first paint where transform calc() would resolve to NaN. */
  --scene-progress: 0;
}

/* spacer dictates total scroll length. Default 300vh; override per-section
   with style="--scene-spacer: 450vh;" or data-scrub-spacer-vh. */
.scroll-scene__spacer {
  block-size: var(--scene-spacer, 300vh);
  inline-size: 100%;
  pointer-events: none;
}

/* sticky stage — always 100vh, always pinned to the block-start of viewport. */
.scroll-scene__sticky {
  position: sticky;
  inset-block-start: 0;
  inline-size: 100%;
  block-size: 100vh;
  overflow: hidden;
  background-color: var(--ink-deep);
}

/* video / poster fill the sticky stage edge-to-edge. */
.scroll-scene__video {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: center;
  /* Avoids a flash of intrinsic-size before metadata loads. */
  background-color: var(--ink-deep);
}

.scroll-scene__poster {
  position: absolute;
  inset: 0;
  display: block;
  overflow: hidden;
  background-color: var(--ink-deep);
}

.scroll-scene__poster img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  object-position: center;
  transform-origin: 50% 50%;
  will-change: transform;
}

/* ----- Canvas-frames mode -------------------------------------------------- *
 * <canvas class="scroll-scene__canvas"> sits above the poster <picture>.
 * Until canvas-frame-renderer.js finishes its Phase 1 preload (first 10
 * frames decoded), the canvas is invisible and the poster shows through.
 * Once .is-ready lands the canvas fades in and we hide the poster behind it.
 * The canvas itself is fully painted by JS — including the background fill
 * for the padded-cover edges — so we don't apply object-fit. Width/height
 * are managed by canvas-frame-renderer.js (DPR-aware). */
.scroll-scene__canvas {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  display: block;
  background-color: var(--ink-deep);
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.5s var(--ease-out-cinema, ease-out);
}
.scroll-scene__canvas.is-ready {
  opacity: 1;
}
/* Hide poster once the canvas is ready (canvas covers it edge-to-edge). */
.scroll-scene[data-scrub-mode="canvas-frames"] .scroll-scene__canvas.is-ready ~ .scroll-scene__poster,
.scroll-scene[data-scrub-mode="canvas-frames"] .scroll-scene__poster:has(~ .scroll-scene__canvas.is-ready) {
  opacity: 0;
}

/* ----- Ken-Burns mode --------------------------------------------------- *
 * Pure CSS-driven from --scene-progress. JS only writes the variable.
 * Scale 1 → 1.15, drift 0% → -8% on the block axis. Tuned to match the feel
 * of the hero scrub without competing with it. */
.scroll-scene[data-scrub-mode="poster-ken-burns"] .scroll-scene__poster img {
  transform:
    scale(calc(1 + var(--scene-progress, 0) * 0.15))
    translateY(calc(var(--scene-progress, 0) * -8%));
  transition: none;
}

/* ----- Overlay (text on top of media) ----------------------------------- */
.scroll-scene__overlay {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: flex-end;
  justify-content: flex-start;
  padding-block-end: clamp(var(--space-12), 8vh, var(--space-20));
  padding-inline: var(--gutter);
  z-index: 1;
  pointer-events: none;
  /* Unified ink-deep wash so light type stays legible over light frames
     (2026-06-15 unify pass — was a bespoke rgba(14,14,12,…) gradient). */
  background: var(--scrim-overlay);
}

.scroll-scene__overlay > * {
  pointer-events: auto;
  max-inline-size: var(--container-narrow, 720px);
}

/* The section-header inside the overlay flips to "on dark" coloring. */
.scroll-scene__overlay .section-header__title,
.scroll-scene__overlay .section-header__lede {
  color: var(--ivory);
}

.scroll-scene__overlay .section-header__lede {
  color: var(--fg-on-dark-muted);   /* one translucent-ivory method site-wide */
}

.scroll-scene__overlay .section-header__eyebrow {
  color: var(--brass);
}

/* ----- Post-content (renders after the sticky stage releases) ----------- */
.scroll-scene__post {
  position: relative;
  inline-size: 100%;
  background-color: var(--bg);
  color: var(--fg);
  padding-block: var(--space-20);
  padding-inline: var(--gutter);
}

/* ----- Scaffold features grid (used by Ken-Burns scenes that don't yet
 *       have a fully-built post section). Three-up at md+, single column on
 *       mobile, brass hairline above each card. */
.hall-resort__features,
.hall-venue__features-scaffold {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-8);
  max-inline-size: var(--container-wide, 1200px);
  margin-inline: auto;
}

@media (min-width: 720px) {
  .hall-resort__features,
  .hall-venue__features-scaffold {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

.hall-resort__features > .feature,
.hall-venue__features-scaffold > .feature {
  position: relative;
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--brass);
}

.hall-resort__features > .feature h3,
.hall-venue__features-scaffold > .feature h3 {
  font-family: var(--font-display-he);
  font-size: var(--text-xl);
  font-weight: var(--fw-medium);
  line-height: var(--lh-tight);
  color: var(--ink-deep);
  margin: 0 0 var(--space-3) 0;
}

.hall-resort__features > .feature p,
.hall-venue__features-scaffold > .feature p {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--lh-loose);
  color: var(--fg-muted);
  margin: 0;
}

/* ----- Reduced motion --------------------------------------------------- *
 * Constitution §8 + §9: respect user preference. JS collapses the spacer,
 * but we also hard-cap it via CSS so SSR / no-JS cases stay well-behaved.
 * Video is hidden so the poster is what users see; transforms are off.
 */
@media (prefers-reduced-motion: reduce) {
  .scroll-scene__spacer {
    block-size: auto;
    min-block-size: 100vh;
  }
  .scroll-scene__video {
    visibility: hidden;
  }
  /* Reduced motion: canvas never animates; rely on poster instead. */
  .scroll-scene__canvas {
    display: none;
  }
  .scroll-scene[data-scrub-mode="canvas-frames"] .scroll-scene__poster {
    opacity: 1;
  }
  .scroll-scene[data-scrub-mode="poster-ken-burns"] .scroll-scene__poster img,
  .scroll-scene__poster img {
    transform: none;
    will-change: auto;
  }
}

/* ===========================================================================
   lounge.css — 3D circular gallery (rewrite 2026-06-04)
   ---------------------------------------------------------------------------
   Replaces the previous expanding-carousel rules. The new visual is an
   8-item ring rotating on the Y axis; lounge-selector.js writes
   --lounge-rotation on .lounge__ring and per-item
   --lounge-item-transform + --lounge-opacity on each .lounge__item.

   Below 768px AND when prefers-reduced-motion:reduce, the 3D layer is
   killed and the items lay out as a 2-column grid. JS skips entirely in
   reduced-motion (no listeners, no RAF) so the static grid is the only
   thing the user sees.

   Token note: --lh-base does not exist in tokens.css; substituted with
   --lh-normal (1.5), the closest body-line-height token.
   ========================================================================= */

.lounge {
  background: var(--bg);
  /* Breathing gap (2026-06-10 v9) — the hero is now a static composition
     that scrolls out as one unit (§3). The --section-pad-hero-gap top pad
     (25vh) gives a deliberate pause between the hero and the lounge eyebrow
     before the ring appears. Bottom keeps the standard section rhythm before
     #culinary. (Tokenized 2026-06-15 unify pass.) */
  padding-block: var(--section-pad-hero-gap) var(--section-pad);
  overflow: hidden;             /* contains 3D overflow when items rotate */
}

.lounge__header {
  max-inline-size: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
  text-align: center;
  margin-block-end: var(--space-12);
}

.lounge__stage {
  position: relative;
  inline-size: 100%;
  block-size: clamp(420px, 64vh, 720px);
  perspective: 2000px;
  display: flex;
  align-items: center;
  justify-content: center;
  /* Drag-to-rotate: pointer becomes a grab cursor, becomes grabbing while
     a drag is active. user-select:none stops text drag-selection from
     hijacking the gesture. touch-action:pan-y keeps vertical page scroll
     working on touch even while horizontal drags rotate the ring. */
  cursor: grab;
  user-select: none;
  -webkit-user-select: none;
  touch-action: pan-y;
}

.lounge__stage[data-dragging] {
  cursor: grabbing;
}

.lounge__ring {
  position: relative;
  inline-size: 100%;
  block-size: 100%;
  transform-style: preserve-3d;
  transform: rotateY(var(--lounge-rotation, 0deg));
  /* No transition — the JS RAF loop drives this every frame. A
     transition would compound and produce drift. */
}

.lounge__item {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-start: 50%;        /* ring centre; offset via margin below */
  inline-size: clamp(220px, 22vw, 320px);
  aspect-ratio: 3 / 4;
  margin-inline-start: clamp(-160px, -11vw, -110px);   /* half of inline-size, negated */
  margin-block-start:  clamp(-213px, -14.66vw, -147px); /* half of computed block-size — see note */
  transform: var(--lounge-item-transform, none);
  opacity: var(--lounge-opacity, 1);
  transition: opacity var(--dur-base) var(--ease-out-cinema);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-strong);
  background: var(--bg-cocoa);
}

/* NOTE on the negative margins: aspect-ratio 3/4 means block-size = inline-size × 4/3.
   Inline-size clamp(220, 22vw, 320) → block-size clamp(293.3, 29.33vw, 426.6).
   Half of that, negated, is what we need for centering — clamp(-213.3, -14.66vw, -146.6).
   Rounded to integers above. If the math doesn't read clean to a future maintainer,
   they can replace this whole pair with `translate(-50%, -50%)` AT THE COST of needing
   to write the JS-side --lounge-item-transform with a leading `translate(-50%,-50%)`
   prefix. We use the margin technique to keep the JS side clean (it just emits
   `rotateY() translateZ()`). */

.lounge__item picture,
.lounge__item picture img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  /* Stops native HTML5 image drag from hijacking the pointer mid-gesture
     (the symptom: ring stuck after a fast drag because the browser flipped
     into drag-and-drop of the <img>). The stage still receives the pointer
     since pointer-events bubbles from elsewhere on .lounge__item. */
  -webkit-user-drag: none;
  user-drag: none;
  pointer-events: none;
}

.lounge__item figcaption {
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  padding-block: var(--space-4);
  padding-inline: var(--space-4);
  /* Unified scrim (2026-06-15 unify pass — was a bespoke rgba(26,20,16,…)). */
  background: var(--scrim-strong);
  color: var(--ivory);
  text-align: start;
  pointer-events: none;
}

.lounge__item figcaption h3 {
  font-family: var(--font-display-he);
  font-size: var(--text-lg);
  font-weight: var(--fw-bold);
  margin: 0 0 var(--space-1) 0;
  color: var(--ivory);
}

.lounge__item figcaption p {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  margin: 0;
  color: var(--fg-on-dark-muted);   /* one translucent-ivory method site-wide */
  line-height: var(--lh-normal);
}

/* ---------------------------------------------------------------------------
   Fallback layout: prefers-reduced-motion:reduce ONLY.
   ---------------------------------------------------------------------------
   2026-06-11 mobile-fidelity pass: the `(max-width: 767.98px)` arm was removed
   so the real 3D rotating ring survives on phones (it was flattening it to a
   grid). The ring is fit to narrow viewports by scaling .lounge__stage in
   /mobile/css/lounge.css — rotation/drag/depth preserved. The
   prefers-reduced-motion arm stays: it is the ONE allowed static fallback
   (§13), and lounge-selector.js short-circuits init() under RM so the grid
   below is what renders. (§13 rule-6 sanctioned migration — see Maintenance Log.)
   --------------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .lounge__stage {
    perspective: none;
    block-size: auto;
    display: block;
    cursor: auto;                         /* no drag affordance in fallback */
    touch-action: auto;
  }
  .lounge__ring {
    position: relative;
    transform-style: flat;
    transform: none !important;        /* override any inline JS write */
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-4);
    max-inline-size: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--gutter);
  }
  .lounge__item {
    position: relative;
    inset-block-start: auto;
    inset-inline-start: auto;
    margin: 0 !important;
    inline-size: auto;
    transform: none !important;
    opacity: 1 !important;
  }
}

/* =============================================================================
   Section: #rooms (חדרי אירוח) — hover/focus-swap name-list → shared image stage
   --------------------------------------------------------------------------
   Layout : Two panes. Names list (right side in RTL, the inline-start column)
            + a shared image stage. Hover/focus/tap/keyboard a name reveals its
            room image via a clip-path inset wipe; all panels stack in one grid
            cell, only .is-active is visible.
   Rules  : Logical properties only. Every color/space/font from tokens.css.
            RTL-first. prefers-reduced-motion → instant swap, no wipe.
   Class set (BEM-ish):
     .rooms                 section root  (also carries [data-rooms-stage])
     .rooms__container      max-width wrapper
     .rooms__layout         the two-pane grid
     .rooms__list           the names column   (role=tablist)
     .rooms__trigger        one name button    ([data-rooms-trigger])
     .rooms__trigger-name   room title text
     .rooms__trigger-desc   one-line description
     .rooms__stage          the image stage (right/visual pane)
     .rooms__panel          one stacked image cell ([data-rooms-panel])
   ========================================================================== */

.rooms {
  position: relative;
  background-color: var(--bg);
  color: var(--fg);
  padding-block: var(--section-pad);
  padding-inline: var(--gutter);
  isolation: isolate;
  overflow: clip;
}

.rooms__container {
  max-inline-size: var(--container-wide);
  margin-inline: auto;
}

/* The section already renders a .section-header above; spacing handled there.
   This local container only needs to push the layout below the header. */
.rooms .section-header {
  margin-block-end: var(--space-12);
}

/* ---------------------------------------------------------------------- *
 *  TWO-PANE LAYOUT                                                        *
 *  In RTL the first grid column sits on the right (inline-start) → names. *
 * ---------------------------------------------------------------------- */
.rooms__layout {
  display: grid;
  grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  gap: clamp(var(--space-6), 4vw, var(--space-16));
  align-items: stretch;
}

/* ---------------------------------------------------------------------- *
 *  NAMES LIST (inline-start pane)                                         *
 * ---------------------------------------------------------------------- */
.rooms__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  align-self: center;
  margin: 0;
  padding: 0;
}

.rooms__trigger {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  inline-size: 100%;
  text-align: start;
  background: transparent;
  border: 0;
  border-block-end: 1px solid var(--border);
  padding-block: var(--space-4);
  padding-inline: var(--space-2);
  cursor: pointer;
  color: var(--fg-muted);
  transition:
    color var(--dur-base) var(--ease-out-cinema),
    padding-inline-start var(--dur-base) var(--ease-out-cinema),
    transform var(--dur-fast) var(--ease-out-cinema),
    background-color var(--dur-base) var(--ease-out-cinema);
}

/* Press feedback: unified site-wide press-scale (2026-06-15 — was 0.99). */
.rooms__trigger:active {
  transform: scale(0.98);
}

.rooms__trigger:last-child {
  border-block-end: 0;
}

.rooms__trigger-name {
  font-family: var(--font-display-he);
  font-size: clamp(var(--text-md), 2.2vw, var(--text-xl));
  font-weight: var(--fw-regular);
  line-height: var(--lh-snug);
  letter-spacing: var(--tracking-tight);
  color: inherit;
  margin: 0;
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
}

/* Brass index numeral — kept LTR via isolate per §4 bidi rule. */
.rooms__trigger-num {
  font-family: var(--font-display-en);
  font-size: var(--text-sm);
  font-weight: var(--fw-regular);
  color: var(--brass);
  unicode-bidi: isolate;
  opacity: 0.55;
  transition: opacity var(--dur-base) var(--ease-out-cinema);
}

.rooms__trigger-desc {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: var(--lh-normal);
  color: var(--fg-muted);
  margin: 0;
  max-block-size: 0;
  opacity: 0;
  overflow: hidden;
  transition:
    max-block-size var(--dur-slow) var(--ease-out-cinema),
    opacity var(--dur-slow) var(--ease-out-cinema);
}

/* Hover / focus / active states ---------------------------------------- */
.rooms__trigger:hover,
.rooms__trigger:focus-visible {
  color: var(--ink-deep);
  outline: none;
}

.rooms__trigger:focus-visible {
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}

.rooms__trigger.is-active {
  color: var(--ink-deep);
  padding-inline-start: var(--space-4);
  background-color: var(--bg-alt);
  border-radius: var(--radius-sm);
}

.rooms__trigger.is-active .rooms__trigger-num {
  opacity: 1;
}

.rooms__trigger.is-active .rooms__trigger-name {
  font-weight: var(--fw-medium);
}

.rooms__trigger.is-active .rooms__trigger-desc {
  max-block-size: 6rem;
  opacity: 1;
  margin-block-start: var(--space-2);
}

/* ---------------------------------------------------------------------- *
 *  IMAGE STAGE (visual pane) — stacked panels, clip-path wipe reveal      *
 * ---------------------------------------------------------------------- */
.rooms__stage {
  position: relative;
  display: grid;
  /* All panels occupy the same single cell. */
  grid-template-areas: "stack";
  aspect-ratio: 4 / 5;
  inline-size: 100%;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background-color: var(--ink-medium);
  box-shadow: var(--shadow-strong);
}

.rooms__panel {
  grid-area: stack;
  margin: 0;
  inline-size: 100%;
  block-size: 100%;
  /* Hidden default: clipped to nothing from the inline-start edge. */
  clip-path: inset(0 0 0 100%);
  opacity: 0;
  transition:
    clip-path var(--dur-deluxe) var(--ease-out-cinema),
    opacity var(--dur-deluxe) var(--ease-out-cinema);
  pointer-events: none;
}

.rooms__panel.is-active {
  clip-path: inset(0 0 0 0);
  opacity: 1;
}

.rooms__panel picture,
.rooms__panel img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
}

/* Subtle Ken-Burns drift on the active image for "premium" feel. */
.rooms__panel img {
  transform: scale(1.04);
  transition: transform var(--dur-cinema) var(--ease-out-cinema);
}
.rooms__panel.is-active img {
  transform: scale(1);
}

/* ---------------------------------------------------------------------- *
 *  RESPONSIVE — stack vertically; names become a horizontal scroller above *
 * ---------------------------------------------------------------------- */
@media (max-width: 768px) {
  .rooms__layout {
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-6);
  }

  /* Stage first (visual), names scroller below — order via grid source flow. */
  .rooms__stage {
    aspect-ratio: 4 / 3;
    order: -1;
  }

  .rooms__list {
    flex-direction: row;
    gap: var(--space-2);
    align-self: stretch;
    overflow-x: auto;
    overflow-y: hidden;
    scroll-snap-type: x mandatory;
    -webkit-overflow-scrolling: touch;
    padding-block-end: var(--space-2);
  }

  .rooms__trigger {
    flex: 0 0 auto;
    inline-size: auto;
    border-block-end: 0;
    border-radius: var(--radius-btn);
    padding-block: var(--space-2);
    padding-inline: var(--space-4);
    background-color: var(--bg-alt);
    scroll-snap-align: start;
  }

  .rooms__trigger:last-child {
    border-block-end: 0;
  }

  .rooms__trigger.is-active {
    padding-inline-start: var(--space-4);
    background-color: var(--cocoa);
    color: var(--fg-on-dark);
  }

  .rooms__trigger.is-active .rooms__trigger-num {
    color: var(--brass-glow);
  }

  /* On mobile the one-liner would jitter the horizontal scroller — hide it. */
  .rooms__trigger-desc,
  .rooms__trigger.is-active .rooms__trigger-desc {
    display: none;
  }

  .rooms__trigger-name {
    font-size: var(--text-base);
    white-space: nowrap;
  }
}

/* ---------------------------------------------------------------------- *
 *  REDUCED MOTION — instant swap, no wipe, no drift                       *
 * ---------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .rooms__panel {
    transition: none;
    /* Hidden panels collapse instantly. */
    clip-path: inset(0 0 0 100%);
  }
  .rooms__panel.is-active {
    clip-path: inset(0 0 0 0);
  }
  .rooms__panel img,
  .rooms__panel.is-active img {
    transform: none;
    transition: none;
  }
  .rooms__trigger,
  .rooms__trigger-desc {
    transition: none;
  }
  .rooms__trigger:active {
    transform: none;
  }
}

/* ====================================================================== *
 *  DOOR ENTRY (2026-06-11) — replaces the two-pane gallery on the home    *
 *  page. The #rooms section now shows a centered door image that links    *
 *  to the /rooms/dist/ sub-app (Constitution §2.1, third route — the      *
 *  phantom.land curved image wall). Clicking it navigates with no         *
 *  animation today; the future door-opening MP4 seam is documented in     *
 *  index.html (#rooms) + rooms/src/intro/README.md.                       *
 *                                                                          *
 *  LEGACY: the .rooms__container / .rooms__layout / .rooms__list /         *
 *  .rooms__stage / .rooms__panel / .rooms__trigger rules ABOVE are now     *
 *  orphaned (the markup they styled was removed). Kept on disk per §2.1    *
 *  rule 6 ("vanilla legacy preserved") so a revert is one markup swap;     *
 *  js/rooms-gallery.js self-no-ops without [data-rooms-stage].            *
 * ====================================================================== */
.rooms__door-wrap {
  display: flex;
  justify-content: center;
  margin-block-start: var(--space-8);
}

.rooms__door {
  position: relative; /* positioning context for the cursor-click cue */
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  text-decoration: none;
  color: var(--ink-deep);
  cursor: pointer;
  border-radius: var(--radius-lg);
  padding: var(--space-3);
  transition:
    transform var(--dur-base) var(--ease-out-cinema),
    filter var(--dur-base) var(--ease-out-cinema);
}

/* Cursor-click cue (2026-07-01) — an animated pointer + expanding brass ring on
   the door leaf, inviting a click to enter the rooms gallery (requested for the
   entry point, before the sub-app). Fades once the user hovers/focuses the door
   (they've found it). reduced-motion → static ring, no loop. */
.rooms__door-tap {
  position: absolute;
  /* PHYSICAL left/top (not logical): aligned to the door raster, which is NOT
     mirrored in RTL. Sits ON the door leaf face (centre), both desktop + mobile. */
  left: 48%;
  top: 48%;
  transform: translate(-50%, -50%);
  inline-size: 52px;
  block-size: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: none;
  z-index: 2;
  transition: opacity var(--dur-base) var(--ease-out-cinema);
}
/* A pointing hand (Lucide "pointer") — clearer than a mouse-arrow. Dark cocoa
   stroke + a tight ivory halo pops it off the light door leaf. */
.rooms__door-tap-cursor {
  inline-size: 34px;
  block-size: 34px;
  /* 2026-10-11: the site's one hand (gesture language v2) — filled ivory with
     a cocoa edge, same drawing as css/components/gesture-hint.css. */
  fill: var(--ivory);
  stroke: var(--cocoa);
  stroke-width: 0.6;
  filter:
    drop-shadow(0 0 1px var(--cocoa))
    drop-shadow(0 2px 6px color-mix(in srgb, var(--ink-deep) 35%, transparent));
  animation: rooms-door-tap-press 2s ease-in-out infinite;
  transform-origin: 50% 30%;
}
.rooms__door-tap-ring {
  position: absolute;
  inset: 0;
  margin: auto;
  inline-size: 46px;
  block-size: 46px;
  border-radius: 50%;
  border: 2px solid var(--brass);
  opacity: 0;
  animation: rooms-door-tap-ring 2s ease-out infinite;
}
.rooms__door:hover .rooms__door-tap,
.rooms__door:focus-visible .rooms__door-tap {
  opacity: 0;
}
@keyframes rooms-door-tap-press {
  0%, 100% { transform: translate(0, 0) scale(1); }
  45%      { transform: translate(1px, 2px) scale(0.88); }
  60%      { transform: translate(0, 0) scale(1); }
}
@keyframes rooms-door-tap-ring {
  0%   { transform: scale(0.4); opacity: 0; }
  25%  { opacity: 0.85; }
  100% { transform: scale(1.6); opacity: 0; }
}

.rooms__door picture,
.rooms__door img {
  display: block;
}

.rooms__door img {
  inline-size: auto;
  block-size: clamp(22rem, 52vh, 34rem);
  max-inline-size: 90vw;
  object-fit: contain;
  filter: drop-shadow(0 24px 48px color-mix(in srgb, var(--ink-deep) 22%, transparent));
  transition: transform var(--dur-base) var(--ease-out-cinema);
}

/* Hover/focus: the door eases forward a touch — an invitation to enter. */
.rooms__door:hover img,
.rooms__door:focus-visible img {
  transform: translateY(-6px) scale(1.015);
}

.rooms__door:active img {
  transform: translateY(-2px) scale(1.005);
}

.rooms__door:focus-visible {
  /* Was `outline: var(--focus-ring)` — invalid (the token is a box-shadow,
     not an outline shorthand), so the door had NO visible focus ring. Fixed
     to the unified offset ring token (2026-06-15 unify pass). */
  outline: none;
  box-shadow: var(--focus-ring-offset);
}

.rooms__door-cue {
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--cocoa);
  border-block-end: 1px solid color-mix(in srgb, var(--brass) 55%, transparent);
  padding-block-end: var(--space-1);
  transition: color var(--dur-base) var(--ease-out-cinema);
}

.rooms__door:hover .rooms__door-cue,
.rooms__door:focus-visible .rooms__door-cue {
  color: var(--ink-deep);
}

@media (prefers-reduced-motion: reduce) {
  .rooms__door,
  .rooms__door img {
    transition: none;
  }
  .rooms__door:hover img,
  .rooms__door:focus-visible img,
  .rooms__door:active img {
    transform: none;
  }
  .rooms__door-tap-cursor,
  .rooms__door-tap-ring { animation: none; }
  .rooms__door-tap-ring { opacity: 0.4; }
}

/* ====================================================================== *
 *  DOOR-OPENING TRANSITION (2026-06-11, v4 — opaque cropped clip IN PLACE)  *
 *  js/rooms-door.js plays the producer's door clip RIGHT WHERE THE DOOR     *
 *  SITS in the #rooms section — NOT a fullscreen player. The clip is an     *
 *  OPAQUE H.264 MP4 (door.mp4), cropped tight to the casing so there's NO   *
 *  white background box, opening onto a BLACK void that STAYS black (you    *
 *  enter the dark gallery). It's layered over the still cut-out, which is   *
 *  hidden once the clip renders (no "two doors"). On `ended`/skip an        *
 *  ink-deep veil fades in, then we navigate to /rooms/dist/; the black void *
 *  + the sub-app's ink-deep boot make the handoff seamless. reduced-motion  *
 *  / modified click / playback failure → plain navigation (no overlay).     *
 * ====================================================================== */

/* While playing, the link is the positioning context for the video overlay. */
.rooms__door.is-playing {
  position: relative;
}

/* Once the video is actually rendering, hide the still cut-out + the cue so the
   ONLY door on screen is the video's (no "two doors"). The still image stays
   visible until then (covers the decode-start; same closed-door first frame). */
.rooms__door.is-video-ready picture,
.rooms__door.is-video-ready .rooms__door-cue {
  opacity: 0;
}

/* The video sits ON TOP of the still door <picture> and must register onto the
   SAME door box so the swap has NO zoom/jump. The clip is cropped tight to the
   casing (casing = the full frame), but door.webp shows the door at 84.7% of its
   height, inset 9.9% from the top, centred (measured: door bbox 504×1307 @356,153
   of the 1200×1543 still). So we shrink the clip to 0.847× the still box and drop
   it 0.099× down — its door then lands exactly on the still door underneath. */
.rooms__door .rooms-door__video {
  position: absolute;
  --rd-still-h: clamp(22rem, 52vh, 34rem); /* the still image's block-size */
  inset-block-start: calc(var(--space-3) + var(--rd-still-h) * 0.099);
  inset-inline: 0;
  margin-inline: auto;
  block-size: calc(var(--rd-still-h) * 0.847);
  inline-size: auto;
  max-inline-size: 90vw;
  object-fit: contain;
  pointer-events: none;
  z-index: 1;
}

/* Skip link — minimal-editorial: ivory-on-page text + brass underline that
   grows on hover (the site's link grammar). Anchored under the door. */
.rooms__door .rooms-door__skip {
  position: absolute;
  inset-block-end: calc(-1 * var(--space-8));
  inset-inline: 0;
  margin-inline: auto;
  inline-size: max-content;
  z-index: 2;
  background: transparent;
  border: 0;
  cursor: pointer;
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: 600;
  letter-spacing: 0.04em;
  color: var(--brass-deep);
  padding-block-end: var(--space-1);
  pointer-events: auto;
  transition: color var(--dur-base) var(--ease-out-cinema);
}

.rooms__door .rooms-door__skip::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: 0;
  block-size: 1px;
  background: var(--brass);
  transform: scaleX(0.4);
  transform-origin: inline-end;
  transition: transform var(--dur-base) var(--ease-out-cinema);
}

.rooms__door .rooms-door__skip:hover,
.rooms__door .rooms-door__skip:focus-visible {
  color: var(--brass);
  outline: none;
}

.rooms__door .rooms-door__skip:hover::after,
.rooms__door .rooms-door__skip:focus-visible::after {
  transform: scaleX(1);
}

/* Ink-deep veil — fades the whole page out at the end of the clip, then
   navigation lands on the sub-app's matching ink-deep boot (no flash). */
.rooms-door-veil {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: var(--ink-deep);
  opacity: 0;
  transition: opacity 0.56s var(--ease-out-cinema, ease);
  pointer-events: none;
}

.rooms-door-veil.is-on {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .rooms-door-veil {
    transition: none;
  }
}

/* =============================================================================
   Section: #culinary (קולינריה — gallery, NOT a hall)
   Owner  : Agent 08 (Phase 4b — Hall Sections Engineer)
   --------------------------------------------------------------------------
   Layout : Header + responsive 3-col gallery; each item aspect-ratio 4/5.
            Captions overlay revealed on hover/focus-within. Mobile shows
            captions always (no hover available).
   Rules  : Logical properties only. Tokens for every value.
   ========================================================================== */

/* Wrapper: when used as a .scroll-scene (Agent 17), no padding/background
   on the outer <section> — the sticky stage paints its own background and
   the post-content paints its own. When used as a plain (legacy) gallery
   without .scroll-scene, the original padding+ink-deep wash kicks in via
   the :not() guard. */
.culinary {
  position: relative;
  isolation: isolate;
  overflow: clip;
}

.culinary:not(.scroll-scene) {
  background-color: var(--ink-deep);
  color: var(--fg-on-dark);
  padding-block: var(--section-pad);
}

/* Post-content (gallery after the scrub) gets the ink-deep background so it
   contrasts properly with the rest of the page — single-source via tokens. */
.culinary__post {
  background-color: var(--ink-deep);
  color: var(--fg-on-dark);
  padding-block: var(--section-pad);
  padding-inline: var(--gutter);
}

.culinary__container {
  max-inline-size: var(--container-wide);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Inside the post-content the gallery should still be width-constrained. */
.culinary__post .culinary__grid {
  max-inline-size: var(--container-wide);
  margin-inline: auto;
}

/* HEADER --------------------------------------------------------------- */
.culinary__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin-block-end: var(--space-16);
  max-inline-size: var(--container-narrow);
}

.culinary__eyebrow {
  font-family: var(--font-body);
  /* Size + weight aligned to the global .section-header__eyebrow (was
     --text-sm / --fw-medium) so eyebrows read identically site-wide.
     Color stays --brass-glow: --brass is too dim on this section's dark
     ink-deep background (documented on-dark exception). 2026-06-15. */
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--brass-glow);
  margin: 0;
}

.culinary__title {
  font-family: var(--font-display-he);
  font-size: clamp(var(--text-2xl), 5vw, var(--text-4xl));
  font-weight: var(--fw-regular);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
  color: var(--ivory);
  margin: 0;
  text-wrap: balance;
}

.culinary__body {
  font-family: var(--font-body);
  font-size: var(--text-md);
  line-height: var(--lh-loose);
  color: var(--ivory);
  opacity: 0.85;
  max-inline-size: 56ch;
  margin: 0;
}

/* ---------------------------------------------------------------------- *
 *  GRID — 1 → 2 → 3 columns                                               *
 * ---------------------------------------------------------------------- */
.culinary__grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-6);
}

@media (min-width: 560px) {
  .culinary__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .culinary__grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: var(--space-8);
  }
}

/* ITEM ----------------------------------------------------------------- */
.culinary__item {
  position: relative;
  display: block;
  inline-size: 100%;
  aspect-ratio: 4 / 5;
  border-radius: var(--radius-md);
  overflow: hidden;
  background-color: var(--ink-medium);
  isolation: isolate;
}

.culinary__item picture,
.culinary__item img {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

.culinary__item img {
  object-fit: cover;
  transition:
    transform var(--dur-cinema) var(--ease-out-cinema),
    filter var(--dur-deluxe) var(--ease-out-cinema);
}

/* CAPTION ----------------------------------------------------------------
   Skin + always-on visibility now come from the canonical .media-caption
   component (css/components/media-caption.css), applied in markup alongside
   the legacy .culinary__item-* hooks (kept for mobile overrides). Captions
   are no longer hover-gated — they read for keyboard/touch/AT users without
   interaction (2026-06-15 unify pass). `.culinary__item-desc` keeps only its
   section-specific measure cap. */
.culinary__item-desc { max-inline-size: 36ch; }

/* Image hover-zoom — pure enhancement on top of the always-visible caption. */
@media (hover: hover) and (pointer: fine) {
  .culinary__item:hover img,
  .culinary__item:focus-within img {
    transform: scale(1.05);
    filter: brightness(0.92);
  }
}

/* Reduced motion ------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  .culinary__item img { transition: none; }
  .culinary__item:hover img,
  .culinary__item:focus-within img {
    transform: none;
    filter: none;
  }
}

/* ===========================================================================
   about.css — אודות / מי אנחנו
   Agent 20 (2026-06-01): aligned to actual #about markup (`.about__body`,
   `.about__lede`, `.about__stats > .about__stat > dt/dd`). Added stat-number
   styling for the animated counter. Section uses .section-rail--end.
   ========================================================================= */


.about {
  overflow-x: clip; /* Contain off-canvas reveal paint inside this static section. */
  padding-block: var(--section-pad);
  background: var(--bg);
}

/* 2026-06-02: switched from section-rail--end (text floats right, half the
   section was empty) to a 2-column grid with a B&W venue photo on the right
   (RTL reading start) and copy on the left. Photo is desaturated for an
   editorial feel that matches the brass/cocoa palette. */
.about__container {
  max-inline-size: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(var(--space-8), 5vw, var(--space-24));
  align-items: center;
}

.about__media {
  margin: 0;
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-strong);
  aspect-ratio: 4 / 5;
}

/* The <picture> wrapper is inline by default, so .about__photo's block-size:100%
   collapsed → the image filled only its natural height while the figure kept its
   aspect-ratio:4/5 box, leaving an empty lower half whose box-shadow showed as
   stray corner marks. Make the picture a full-height block so the photo fills
   the frame. */
.about__media picture {
  display: block;
  block-size: 100%;
}

.about__photo {
  display: block;
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  filter: grayscale(1) contrast(1.05) brightness(0.96);
}

.about__copy {
  min-inline-size: 0;
}

.about__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.about__lede {
  font-family: var(--font-body);
  font-size: clamp(1.125rem, 1.5vw, 1.4rem);
  line-height: var(--lh-loose);
  color: var(--fg-muted);
  margin: 0 0 var(--space-4) 0;
}

.about__usp {
  list-style: none;
  margin: 0 0 var(--space-8) 0;
  padding: 0;
  display: grid;
  gap: var(--space-3);
}
.about__usp li {
  font-family: var(--font-body);
  font-size: clamp(1rem, 1.2vw, 1.125rem);
  line-height: var(--lh-base);
  color: var(--fg);
  padding-inline-start: var(--space-6);
  position: relative;
}
.about__usp li::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 0.7em;
  inline-size: var(--space-4);
  block-size: 1px;
  background: var(--brass);
}

.about__stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
  margin: 0;
  padding-block-start: var(--space-8);
  border-block-start: 1px solid var(--border);
}

.about__stat {
  margin: 0;
  text-align: center;
}

.about__stat dt {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--fg-muted);
  margin-block-end: var(--space-2);
}

.about__stat dd {
  font-family: var(--font-display-luxury);
  font-size: clamp(2.25rem, 3.6vw, 3.25rem);
  font-weight: 700; /* lightened from 900 with the 2026-06-15 site-wide weight pass */
  color: var(--accent);
  line-height: 1;
  margin: 0;
  letter-spacing: var(--tracking-tight);
  white-space: nowrap;
}

/* Stat number wrapper — keeps digits LTR inside Hebrew flow, isolates bidi.
   The counter animation in js/counters.js reads data-value and writes
   textContent; we just need the layout primitives. */
.stat-number {
  unicode-bidi: isolate;
  direction: ltr;
  display: inline-block;
}

/* Mobile — stack stats into 1 column, keep typography readable */
@media (max-width: 600px) {
  .about__stats {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }
}

/* Tablet & narrower — collapse the 2-column grid into a single column.
   DOM order is copy-first, photo-second; on mobile we keep that order so
   the user reads the headline before scrolling past the image. */
@media (max-width: 900px) {
  .about__container {
    grid-template-columns: 1fr;
    gap: var(--space-12);
  }
  .about__media {
    aspect-ratio: 16 / 10;
    max-block-size: 60vh;
  }
}

/* ===========================================================================
   testimonials.css — slider of testimonials (powered by js/slider.js)
   Agent 20 (2026-06-01): aligned to actual #testimonials markup
   (.testimonials__track > .testimonial > .testimonial__quote +
   .testimonial__author > cite + .testimonial__meta).
   Section frame uses [data-reveal="clip-reveal"] (top→bottom wipe).
   ========================================================================= */


.testimonials {
  padding-block: var(--section-pad);
  padding-inline: var(--gutter);
  background: var(--bg-tint);
  /* Clip slider overflow so off-screen slides don't expand the layout. */
  overflow-x: clip;
}

/* The section-header inside #testimonials lives in the gutter-padded zone */
.testimonials > .section-header {
  max-inline-size: var(--container-narrow);
  margin-inline: auto;
}

.testimonials__track {
  /* Slider track: horizontal flex; each child = one slide at 100% width.
     RTL is auto-handled by flex; slider.js applies translate3d(±N%, 0, 0).
     Section-level `overflow-x: clip` keeps off-screen slides from expanding
     layout. */
  max-inline-size: var(--container-narrow);
  margin-inline: auto;
  margin-block-start: var(--space-12);
  display: flex;
  flex-direction: row;
  align-items: stretch;
  gap: 0;
  /* Initial transition is set by JS — the visual default keeps slides snapped. */
  will-change: transform;
}

.testimonial {
  flex: 0 0 100%;
  width: 100%;
  background: var(--bg);
  padding: var(--space-12);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
  /* Only the active slide is interactive; others are visually hidden by track translate. */
}

.testimonial__quote {
  font-family: var(--font-display-he);
  font-size: clamp(1.5rem, 2.2vw, 2rem);
  line-height: var(--lh-snug);
  color: var(--fg);
  margin: 0 0 var(--space-6) 0;
  font-style: italic;
}

.testimonial__quote p { margin: 0; }

.testimonial__quote::before { content: "\201C"; color: var(--accent); margin-inline-end: 0.2em; }
.testimonial__quote::after  { content: "\201D"; color: var(--accent); margin-inline-start: 0.2em; }

.testimonial__author {
  display: flex;
  align-items: baseline;
  gap: var(--space-4);
  flex-wrap: wrap;
}

.testimonial__author cite {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: var(--fw-semibold);
  color: var(--cocoa);
  font-style: normal;
}

.testimonial__meta {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--fg-muted);
}

.testimonials__controls {
  display: flex;
  justify-content: center;
  gap: var(--space-3);
  margin-block-start: var(--space-8);
}

/* .testimonials__btn skin removed 2026-06-15 (unify pass) — the prev/next
   arrows now use the canonical `.btn .btn--icon` (css/components/buttons.css):
   44×44 circle, one focus ring, unified press-scale(0.98). Only the arrow
   glyph size is section-specific layout. */
.testimonials__btn { font-size: var(--text-lg); }

/* Slider dots (rendered programmatically by js/slider.js) ---------------- */
/* Double selector: motion-slider.css's [data-slider-dots] default is
   position:absolute (dots overlaying the slider) AND it loads after this file,
   so a bare .testimonials__dots ties and loses. Here the dots sit IN the
   controls row — the absolute default collapsed the row to 0 height and
   spilled the dots over the content below it (user report 2026-07-13). */
.testimonials__dots[data-slider-dots] {
  position: static;
  inset: auto;
  display: flex;
  align-items: center;
  gap: var(--space-2);
  /* Sit between prev / next buttons in the controls row. */
}

.testimonials__dots [data-slider-dot] {
  width: 10px;
  height: 10px;
  border-radius: var(--radius-circle);
  border: 1px solid var(--border-strong);
  background: transparent;
  cursor: pointer;
  padding: 0;
  transition: background var(--dur-base) var(--ease-out-cinema),
              border-color var(--dur-base) var(--ease-out-cinema),
              transform var(--dur-base) var(--ease-out-cinema);
}

.testimonials__dots [data-slider-dot]:hover {
  border-color: var(--accent);
}

/* Keyboard affordance — the dots are real <button>s (slider.js) but don't carry
   .btn, so they need their own ring. Box-shadow grammar (var(--focus-ring))
   suits the tiny circle better than an offset outline. */
.testimonials__dots [data-slider-dot]:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.testimonials__dots [data-slider-dot].is-active {
  background: var(--accent);
  border-color: var(--accent);
  transform: scale(1.2);
}

@media (max-width: 600px) {
  .testimonial { padding: var(--space-8); }
}

/* Honor reduced-motion: null the dot transforms. (The arrow buttons' press
   feedback is nulled in css/components/buttons.css alongside .btn.) */
@media (prefers-reduced-motion: reduce) {
  .testimonials__dots [data-slider-dot] { transition: none; }
  .testimonials__dots [data-slider-dot].is-active { transform: none; }
}

/* ===========================================================================
   contact.css — צור קשר (form + contact info + map)
   Agent 20 (2026-06-01): aligned to actual #contact markup
   (.contact__grid > .contact__form + .contact__details). Section uses
   .section-rail--end on its inner wrapper for weblove-motion alignment.
   ========================================================================= */


.contact {
  overflow-x: clip; /* Nested horizontal reveals stay inside their section. */
  padding-block: var(--section-pad);
  background: var(--bg);
}

/* When .contact uses a section-rail, gutter is handled by the rail. */
.contact > :not(.section-rail--start):not(.section-rail--end) {
  padding-inline: var(--gutter);
  max-inline-size: var(--container-max);
  margin-inline: auto;
}

.contact__grid {
  display: grid;
  gap: var(--space-12);
  margin-block-start: var(--space-12);
}

@media (min-width: 900px) {
  .contact__grid { grid-template-columns: 7fr 5fr; }
}

/* ----- Form ----- */

.contact__form {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: 1fr 1fr;
}

.contact__field {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.contact__field--full {
  grid-column: 1 / -1;
}

.contact__field label {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  color: var(--fg-muted);
}

.contact__field-optional {
  font-size: var(--text-xs);
  font-weight: var(--fw-regular);
  color: var(--fg-muted);
  margin-inline-start: var(--space-1);
  /* No extra opacity: the smaller size + regular weight + --fg-muted already
     de-emphasize this "(optional)" hint; a 0.7 layer on muted gray pushed it
     under the AA legibility floor. (polish 2026-06-10) */
}

.contact__field input,
.contact__field select,
.contact__field textarea {
  font-family: var(--font-body);
  font-size: var(--text-base);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  background: var(--bg-alt);
  color: var(--fg);
  transition: border-color var(--dur-base) var(--ease-out-cinema);
}

.contact__field input:focus,
.contact__field select:focus,
.contact__field textarea:focus {
  border-color: var(--accent);
  outline: none;
}

.contact__submit-wrap {
  grid-column: 1 / -1;
  display: flex;
  align-items: center;
  gap: var(--space-6);
  flex-wrap: wrap;
}

.contact__response-time {
  flex-basis: 100%;
  max-inline-size: none;
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: var(--fw-medium);
  color: var(--fg-muted);
}

/* .contact__submit skin removed 2026-06-15 (unify pass) — the primary submit
   CTA now uses the canonical `.btn .btn--filled .btn--primary-lg`
   (css/components/buttons.css): brass fill, larger padding + --text-md size,
   one focus ring + one press-scale. `.contact__submit-wrap` above owns layout. */

.contact__feedback {
  font-size: var(--text-sm);
  color: var(--fg-muted);
  margin: 0;
}

.contact__feedback[data-kind="ok"]  { color: var(--cocoa); }
.contact__feedback[data-kind="err"] { color: var(--cocoa); }

/* ----- Inline field errors (agent-23 Phase D1) ----- */

.contact__field-error {
  display: block;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: var(--fw-medium);
  color: var(--cocoa);
  margin-block-start: var(--space-1);
}

.contact__field input.is-invalid,
.contact__field select.is-invalid,
.contact__field textarea.is-invalid {
  border-color: var(--accent-cta);
}

/* "שלחו במייל במקום" fallback link rendered after a successful submit. */
.contact__mailto-fallback {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--fg-muted);
  text-decoration: underline;
  text-underline-offset: 2px;
  transition: color var(--dur-base) var(--ease-out-cinema);
}

.contact__mailto-fallback:hover { color: var(--cocoa); }

/* Inline WhatsApp fallback link (rendered if window.open is blocked). */
.contact__wa-fallback {
  color: var(--cocoa);
  text-decoration: underline;
  text-underline-offset: 2px;
  margin-inline-start: var(--space-2);
}

@media (max-width: 600px) {
  .contact__form { grid-template-columns: 1fr; }
}

/* ----- Aside (channels + CTA + map) ----- */

.contact__details {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.contact__details-title {
  font-family: var(--font-display-he);
  font-size: var(--text-xl);
  font-weight: var(--fw-bold);
  color: var(--fg);
  margin: 0;
}

.contact__channels {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--space-4);
}

/* Each channel row = icon + a vertical text stack (label over value). Flex
   (not grid) keeps the icon glued to its text so the LTR phone/email values
   never fly off to the far edge — fixes the "jumps" between icon and words.
   Icons added 2026-06-02; layout reworked 2026-06-10. */
.contact__channel {
  display: flex;
  align-items: center;
  gap: var(--space-4);
}

.contact__channel-icon {
  inline-size: 22px;
  block-size: 22px;
  display: block;
  flex: none;               /* never shrink — keeps text alignment stable */
  color: var(--accent);     /* phone + mail + pin strokes use currentColor */
}

/* WhatsApp icon ships with its own brand green (#25D366) baked into the SVG
   fill — keep currentColor inheritance off so the green isn't overridden. */
.contact__channel-icon--whatsapp {
  color: #25D366;
}

/* Vertical stack: label on top, value beneath, both start-aligned so every
   row's text begins at the same inline offset right next to the icon. */
.contact__channel-text {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-1);
  min-inline-size: 0;
}

.contact__channel-label {
  display: block;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--cocoa);
}

.contact__channel-value {
  font-family: var(--font-body);
  font-size: var(--text-md);
  color: var(--fg);
  text-decoration: none;
}

 .contact__channel-value:hover,
.contact__channel-value:focus-visible { color: var(--cocoa); }

/* ----- Accessibility note (2026-06-10, Maron copy). A short "100% נגיש"
   block under the contact channels. A brass start-border sets it apart from
   the channel list without adding a heavy card. ----- */
.contact__access {
  border-inline-start: 2px solid var(--brass);
  padding-inline-start: var(--space-4);
}

.contact__access-title {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--cocoa);
  margin: 0 0 var(--space-2) 0;
}

.contact__access-text {
  font-family: var(--font-body);
  font-size: var(--text-md);
  line-height: var(--lh-normal);
  color: var(--fg-muted);
  margin: 0;
  max-inline-size: 48ch;
}


@media (prefers-reduced-motion: reduce) {
  /* .contact__submit:active press feedback is now nulled by the canonical
     .btn reduced-motion rule (css/components/buttons.css). */
}

/* NOTE: the generic Google Maps iframe (.contact__map) was removed 2026-06-10
   — the branded interactive #routes map (css/sections/directions.css) now
   serves the "where are we / how to get here" job. */

/* ---------------------------------------------------------------------------
   #routes — מסלולי הגעה (extracted from #contact 2026-06-03 so the
   sticky-reveal pair effect can slide #contact up over #routes).
   2026-06-10: the old 3-PNG .routes__grid was replaced by the branded
   Leaflet map in css/sections/directions.css. Only the section shell rules
   (.routes / .routes__container / header) stay here — the grid rules are gone.
   --------------------------------------------------------------------------- */

.routes {
  background: var(--bg);
  padding-block: var(--section-pad);
}

.routes__container {
  max-inline-size: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.routes .section-header {
  text-align: center;
  margin-block-end: var(--space-10);
}

/* ---------------------------------------------------------------------------
   .reveal-pair — sticky reveal between #contact and #routes
   ---------------------------------------------------------------------------
   Effect cloned from olivierlarose/sticky-footer:
   #routes is position:sticky pinned to bottom:0, sitting at z-index:0.
   #contact above it has z-index:1 and a solid --bg background, so it
   covers #routes until the user scrolls. As the wrapper scrolls past
   #contact, #contact slides UP off the viewport while #routes stays
   pinned at the bottom — gradually revealed underneath, like lifting
   a sheet of paper to expose the desk below. Pure CSS, no JS.

   The wrapper itself doesn't need any positioning — both children just
   share its scroll context.
   --------------------------------------------------------------------------- */
.reveal-pair {
  position: relative;
}

.reveal-pair__top {
  position: relative;
  z-index: 1;
  background: var(--bg);                  /* MUST be opaque to occlude #routes */
}

.reveal-pair__bottom {
  position: sticky;
  inset-block-end: 0;
  z-index: 0;
  /* Limit height so the reveal completes within one viewport. If routes
     is taller than 100vh the user has to scroll past contact AND through
     routes; capping it at viewport height + giving the inner container
     scroll keeps the moment self-contained. */
  min-block-size: 100vh;
  display: flex;
  align-items: center;
}

.reveal-pair__bottom .routes__container {
  inline-size: 100%;
}

@media (prefers-reduced-motion: reduce) {
  /* No transition logic to disable — the reveal is a scroll-position
     consequence, not an animation. Effect stays identical. */
}

/* ===========================================================================
   directions.css — #routes "מסלולי הגעה" branded interactive map (2026-06-10)
   ---------------------------------------------------------------------------
   Replaces the 3 dated PNG route cards + the generic Google iframe with ONE
   Leaflet map (js/directions-map.js) themed to the brass/cocoa/ivory palette,
   plus origin tabs (מירושלים / מהמרכז / מצפון) and a floating glass card.

   Constitution: all values from css/tokens.css (§10.2 — no hard-coded hex).
   Leaflet's own chrome is restyled here to drop its blue/white default look.
   Desktop-first; mobile overrides live in /mobile/css/directions.css (§13).
   ========================================================================= */

.directions {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

/* Explicit map navigation switches the oversized bottom-pinned panel into
   normal reading flow. Existing section padding clears the fixed navbar. */
.routes.reveal-pair__bottom {
  position: relative;
  inset-block-end: auto;
}
.reveal-pair[data-map-sticky]:not([data-map-reading]) .routes.reveal-pair__bottom {
  position: sticky;
  inset-block-end: 0;
}

/* Tile/network failure message stays readable while route actions remain. */
#directions-map > .directions__fallback {
  position: absolute;
  inset-block-start: var(--space-6);
  inset-inline: var(--space-6);
  z-index: 600;
  padding: var(--space-4);
  margin: 0;
  color: var(--ink-deep);
  background: var(--ivory);
  border: 1px solid var(--brass-deep);
  text-align: center;
  line-height: var(--lh-normal);
}

/* ----- Free-text address search (geocode + live route/ETA) ----- */

.directions__search {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-3);
  inline-size: 100%;
  max-inline-size: 640px;
  margin-inline: auto;
}
.directions__search[hidden] { display: none; }

.directions__search input {
  flex: 1 1 320px;
  min-inline-size: 0;
  padding-block: var(--space-3);
  padding-inline: var(--space-4);
  font-family: var(--font-body);
  font-size: var(--text-base);
  color: var(--ink-deep);
  background: var(--ivory);
  border: 1px solid var(--border);
  border-radius: var(--radius-md);
  transition: border-color var(--dur-base) var(--ease-out-cinema),
              box-shadow var(--dur-base) var(--ease-out-cinema);
}

.directions__search input::placeholder { color: var(--fg-muted); }

.directions__search input:focus-visible {
  outline: none;
  border-color: var(--brass);
  box-shadow: var(--focus-ring);
}

/* Submit button leans on the canonical .btn/.btn--filled brass look; this
   just gives it a comfortable inline footprint next to the input. */
.directions__search-btn {
  flex: 0 0 auto;
  white-space: nowrap;
}

.directions__search-msg {
  flex: 1 0 100%;
  margin: 0;
  text-align: center;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--cocoa);
}

/* ----- Origin tabs (line-language; native radios for a11y) -----
   No segmented box — quiet text labels with a growing brass underline that
   stays lit on the active tab (the .site-nav grammar). LINE-LANGUAGE rev. */

.directions__tabs {
  display: inline-flex;
  align-self: center;
  gap: var(--space-6, 1.5rem);
}

.directions__tab {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}

/* The radio drives state but stays invisible (label is the hit target). */
.directions__tab input {
  position: absolute;
  inset: 0;
  margin: 0;
  opacity: 0;
  cursor: pointer;
}

.directions__tab-label {
  position: relative;
  display: block;
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: var(--fw-semibold);
  color: var(--fg-muted);
  padding-block: var(--space-2);
  transition: color var(--dur-base) var(--ease-out-cinema);
}

/* Growing brass underline — verbatim the .site-nav link grammar (RTL-safe). */
.directions__tab-label::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  block-size: 2px;
  background: var(--brass);
  transform: scaleX(0);
  transform-origin: right center;
  transition: transform var(--dur-base) var(--ease-out-cinema);
}

.directions__tab:hover .directions__tab-label {
  color: var(--ink-deep);
}
.directions__tab:hover .directions__tab-label::after {
  transform: scaleX(1);
}

.directions__tab.is-active .directions__tab-label,
.directions__tab input:checked ~ .directions__tab-label {
  color: var(--ink-deep);
}
.directions__tab.is-active .directions__tab-label::after,
.directions__tab input:checked ~ .directions__tab-label::after {
  transform: scaleX(1);          /* active tab keeps its underline lit */
}

/* Visible keyboard focus ring on the active radio (§9). */
.directions__tab input:focus-visible ~ .directions__tab-label {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}
@media (prefers-reduced-motion: reduce) {
  .directions__tab-label::after { transition: none; }
}

/* ----- Stage (map + floating card) ----- */

.directions__stage {
  position: relative;
  inline-size: 100%;
  min-block-size: clamp(380px, 52vh, 560px);
  border-radius: var(--radius-lg);
  overflow: hidden;
  box-shadow: var(--shadow-soft);
  background: var(--mist);          /* shows while tiles load */
  isolation: isolate;
}

.directions__map {
  position: absolute;
  inset: 0;
  inline-size: 100%;
  block-size: 100%;
  background: var(--mist);
}

/* Brand tint: CARTO Voyager-no-labels already has warm beige land + BLUE
   water. Keep the sea blue — use only a gentle warm/contrast nudge (NOT a
   heavy sepia, which would drain the blue). Applied to the tile pane only;
   controls/pin/route/labels live above and stay true-color. Single knob for
   the whole map's tone. */
.directions__map .leaflet-tile-pane {
  /* 2026-06-22 (user: "make the map look like a REAL map") — dropped the brand
     recolor (the sepia/desaturate AND the earlier garish saturate-boost both
     read un-map-like). CARTO Voyager's natural palette IS a real, legible map
     (warm beige land, green parks, blue water); a light saturate+contrast keeps
     it crisp without tinting it. The BRAND identity stays where the user asked
     it to: the route polyline (--brass-deep) and the place/city labels (--cocoa)
     sit ABOVE the tile pane and keep their colors — this filter is tiles only. */
  filter: saturate(1.08) contrast(1.05);
}

/* ----- Venue pin (brass divIcon + gentle pulse) ----- */

.directions__pin-wrap { background: none; border: 0; }

.directions__pin {
  display: block;
  inline-size: 32px;
  block-size: 44px;
  filter: drop-shadow(0 4px 6px rgba(26, 20, 16, 0.28));
  transform-origin: 50% 100%;
  animation: directions-pin-pulse 2.4s var(--ease-out-cinema) infinite;
}

@keyframes directions-pin-pulse {
  0%, 100% { transform: translateY(0) scale(1); }
  50%      { transform: translateY(-3px) scale(1.05); }
}

.directions__pin-name {
  position: absolute;
  inset-block-start: -4px;
  inset-inline-start: 38px;
  white-space: nowrap;
  font-family: var(--font-display-he);
  font-size: var(--text-base);
  font-weight: var(--fw-bold);
  color: var(--cocoa);
  text-shadow: 0 1px 2px var(--ivory), 0 0 6px var(--ivory);
}

/* ----- Per-route place labels (dot + name) for distance scale ----- */

.directions__label-wrap { background: none; border: 0; }

.directions__place {
  position: relative;
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
  pointer-events: none;
}

/* Anchor variants nudge the text just off its geographic point so it doesn't
   land directly on the route line. No dot — the name sits tight on its place. */
.directions__place--right  { transform: translate(4px, -50%); }
.directions__place--left   { transform: translate(-4px, -50%); flex-direction: row-reverse; }
.directions__place--top    { transform: translate(-50%, calc(-100% - 3px)); }
.directions__place--bottom { transform: translate(-50%, 3px); }

.directions__place-name {
  font-family: var(--font-body);
  font-size: var(--text-sm, 0.875rem);
  font-weight: var(--fw-semibold);
  color: var(--cocoa);
  /* readable over the tiles without a hard chip behind the text */
  text-shadow: 0 1px 2px var(--ivory), 0 0 5px var(--ivory), 0 0 5px var(--ivory);
}

/* Origin city (route start) reads a touch larger/stronger. */
.directions__place--origin .directions__place-name {
  font-family: var(--font-display-he);
  font-size: var(--text-base);
  font-weight: var(--fw-bold);
  color: var(--brass-deep);
}

/* ----- Route polyline (SVG path, brass-deep + glow) ----- */

.directions__route {
  stroke: var(--brass-deep);
  stroke-width: 4;
  fill: none;
  filter: drop-shadow(0 0 5px rgba(207, 174, 131, 0.55)); /* brass glow */
}

/* ----- Floating glass card (RTL: anchored to inline-end/bottom) ----- */

.directions__card {
  position: absolute;
  inset-block-end: var(--space-6);
  inset-inline-end: var(--space-6);
  z-index: 500;                      /* above Leaflet panes (≤400) */
  max-inline-size: min(340px, 78%);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  padding: var(--space-6);
  background: color-mix(in srgb, var(--ivory) 88%, transparent);
  -webkit-backdrop-filter: blur(10px);
  backdrop-filter: blur(10px);
  border: 1px solid var(--brass);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-strong);
}

.directions__eta {
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-1, 0.25rem);
}

.directions__eta-label {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--cocoa);
}

.directions__eta-stat {
  font-family: var(--font-display-he);
  font-size: var(--text-lg);
  font-weight: var(--fw-bold);
  color: var(--ink-deep);
}

.directions__address {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-base);
  color: var(--fg-muted);
}

.directions__cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
}

/* .directions__cta skin removed 2026-06-15 (unify pass) — the Waze/Maps/WA
   buttons now use the canonical `.btn` (secondary outline) from
   css/components/buttons.css. The `--waze/--maps/--wa` modifiers carry no
   CSS (JS hooks only); `.directions__cta-row` above still owns layout. */

/* ----- Attribution + JS-off fallback ----- */

.directions__attribution {
  margin: 0;
  text-align: center;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: var(--cocoa);
  opacity: 1;
}

.directions__fallback {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-8);
  text-align: center;
}

.directions__fallback a { color: var(--accent); }

/* ----- Leaflet chrome → brand restyle (drop the default blue/white) ----- */

.directions__map .leaflet-control-zoom a {
  background: var(--ivory);
  color: var(--cocoa);
  border-color: var(--border);
}

.directions__map .leaflet-control-zoom a:hover {
  background: var(--brass);
  color: var(--ink-deep);
}

.directions__map .leaflet-bar {
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-soft);
  overflow: hidden;
}

.directions__map .leaflet-control-attribution {
  background: color-mix(in srgb, var(--ivory) 85%, transparent);
  color: var(--fg-muted);
  font-family: var(--font-body);
}

.directions__map .leaflet-control-attribution a { color: var(--accent-hover); }

/* ----- Reduced motion (§8): no pin pulse; JS already skips fly/draw ----- */

@media (prefers-reduced-motion: reduce) {
  .directions__pin { animation: none; }
}

.directions__attribution a { color: inherit; }
.directions__attribution a:hover,
.directions__attribution a:focus-visible { color: var(--ink-deep); }

/* ===========================================================================
   gallery.css — mixed media gallery
   Agent 20 (2026-06-01): items use [data-reveal="scale-up"] with staggered
   --reveal-delay; the grid keeps its centered container layout.
   ========================================================================= */


.gallery {
  overflow-x: clip; /* Local horizontal reveal paint, no body-wide masking. */
  /* padding-block-end: 0 — the .gallery__outro dissolve provides the closing
     space and fades into #events, so no plain gap between them. */
  padding-block-start: var(--section-pad);
  padding-block-end: 0;
  padding-inline: var(--gutter);
  background: var(--bg-alt);
}

.gallery > .section-header {
  max-width: var(--container-max);
  margin-inline: auto;
}

.gallery__container {
  max-width: var(--container-max);
  margin-inline: auto;
}

/* Proportional masonry (2026-07-01, rev 2026-07-01): JS shortest-column masonry.
   Every photo keeps its true ratio (portraits tall, landscapes wide, no crop) AND
   the columns pack NEAR-EVEN — js/gallery-masonry.js distributes each item into the
   currently-shortest column (by cumulative aspect ratio). Neither CSS `columns`
   (balance-fill) nor CSS-grid `dense` can equalise column bottoms, which left a
   ~850px ragged light gap; shortest-column placement is the only reliable evener.
   The grid is a flex row of .gallery__col columns the JS creates + fills. */
.gallery__grid {
  list-style: none;
  margin: 0;
  padding: 0;
  margin-block-start: var(--space-12);
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

/* Column wrappers are created by js/gallery-masonry.js. Before the JS runs (or if
   it no-ops) the items sit directly in the flex row — still visible, just not
   column-balanced. */
.gallery__col {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.gallery__item {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-md);
  cursor: pointer;
  background: linear-gradient(135deg, var(--mist), var(--brass));
}

.gallery__item picture { display: block; }

.gallery__item img {
  display: block;
  width: 100%;
  height: auto;               /* natural ratio — no crop */
  transition: transform var(--dur-cinema) var(--ease-out-cinema);
}

@media (hover: hover) and (pointer: fine) {
  .gallery__item:hover img,
  .gallery__item:focus-within img { transform: scale(var(--card-zoom)); }
}

@media (prefers-reduced-motion: reduce) {
  .gallery__item img { transition: none; }
  .gallery__item:hover img,
  .gallery__item:focus-within img { transform: none; }
}

/* ---------------------------------------------------------------------------
   .gallery__outro (2026-07-01) — graphic "arch dissolve" that veils the small
   residual raggedness and bridges into #events. Text-free / decorative. Pulled
   up with a negative margin so its transparent-topped gradient fades the last row
   of photos into the bg; the gradient bottom resolves to --bg (the #events bg) so
   the colour flows seamlessly into the next section. A thin brass arch (echoing
   the venue arches in the photos) + a faded GAMOS monogram sit near the seam.
   --------------------------------------------------------------------------- */
.gallery__outro {
  position: relative;
  pointer-events: none;
  /* Full-bleed: cancel the section's padding-inline so the dissolve gradient
     spans edge-to-edge. Otherwise the gradient rectangle is inset by --gutter and
     its lighter (--bg) lower band shows two visible vertical seams against the
     section's --bg-alt on both sides. */
  margin-inline: calc(-1 * var(--gutter));
  /* Largest-first masonry keeps residual raggedness small (<~150px), so a modest
     overlap absorbs the shortest column's tail while the transparent-topped
     gradient softly dissolves the last photos — on-concept for the "arch dissolve". */
  margin-block-start: calc(-1 * clamp(140px, 18vw, 260px));
  block-size: clamp(300px, 36vw, 460px);
  background: linear-gradient(to bottom,
    transparent 0%,
    var(--bg-alt) 42%,
    var(--bg) 100%);
  display: grid;
  place-items: end center;
}

.gallery__outro-inner {
  position: relative;
  inline-size: min(92%, 640px);
  padding-block-end: clamp(var(--space-8), 6vw, var(--space-16));
  display: grid;
  justify-items: center;
  gap: clamp(var(--space-2), 2vw, var(--space-5));
}

/* Wide, shallow concave brass arc — a callback to the arched tunnel in the
   gallery photos. Thin stroke, low opacity, purely decorative. */
.gallery__outro-arch {
  inline-size: min(100%, 560px);
  block-size: auto;
  color: var(--brass);
  opacity: 0.85;
}

/* Gold GAMOS monogram — the "content" of this text-free block. Clearly legible
   (a graphic sign-off, not a faint watermark). */
.gallery__outro-mark {
  inline-size: clamp(170px, 20vw, 260px);
  block-size: auto;
  opacity: 0.9;
}

@media (max-width: 768px) {
  .gallery__outro {
    margin-block-start: calc(-1 * clamp(90px, 22vw, 160px));
    block-size: clamp(240px, 52vw, 340px);
  }
}

/* ===========================================================================
   events.css — #events "סוגי אירועים" editorial fixed-preview gallery
   (2026-07-13 v4 — user-chosen redesign; replaces the mouse-distortion look,
   see git history)

   RTL two-column stage: event-name rows on the inline-start (right) side, a
   framed sticky preview panel on the inline-end (left) side. Activating a
   row (hover/focus on desktop — js/events-gallery.js) swaps the panel image
   with a soft top→down clip-path wipe + settle-scale. Row 1 is active by
   default; the panel is never empty. Calm, fashion-house editorial —
   nothing chases the cursor. ≤768px = stacked cards (mobile/css/events.css).

   RTL: grid-template-areas + logical properties only.
   ========================================================================= */

/* Seam design (v4.1 — after two gradient attempts read as muddy/banded,
   especially at phone widths): the dark block is a SHAPE, not a color
   smear. Its TOP edge is a gentle full-width elliptical arch (border-radius
   dome) echoing the brand arc ornaments right above this section in
   #gallery's GAMOS EVENTS mark; the ivory above shows through the rounded
   corners. The bottom edge is a straight cut (user decision). */
.events {
  overflow-x: clip; /* Does not create a scroll container for sticky preview. */
  --events-arch: clamp(28px, 6vw, 72px);
  padding-block-start: calc(var(--section-pad) + var(--events-arch));
  padding-block-end: var(--section-pad);
  /* Warm taupe ground (user-picked from the retired kosher circle) — cocoa
     at 82% over the ivory body, same single-token §5 mix kosher.css used.
     Replaces the previous ink-deep black. */
  background: color-mix(in srgb, var(--cocoa) 82%, var(--bg));
  /* Arch on the TOP edge only — the bottom stays a clean straight cut
     (user decision). */
  border-radius: 50% 50% 0 0 / var(--events-arch) var(--events-arch) 0 0;
}

.events__inner {
  max-width: var(--container-max);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Eyebrow on the TAUPE ground: brass-glow only reaches ~3.2:1 here (it
   cleared 7:1 on the old ink-deep — the culinary exception doesn't carry
   over), so the eyebrow goes ivory for AA (§9). */
.events .section-header__eyebrow { color: var(--ivory); }

/* ---- Stage: rows (inline-start) | preview panel (inline-end) ---- */
.events__stage {
  display: grid;
  grid-template-columns: 1.1fr 1fr;
  grid-template-areas: "list panel";
  gap: clamp(var(--space-8), 5vw, var(--space-16));
  align-items: start;
  margin-block-start: var(--space-12);
}

/* ---- Preview panel — framed, sticky beside the list ---- */
.events__preview {
  grid-area: panel;
  position: sticky;
  inset-block-start: var(--space-24);
  margin: 0;
  aspect-ratio: 4 / 5;
  max-block-size: 70vh;
  inline-size: 100%;
  border: 1px solid color-mix(in srgb, var(--brass) 30%, transparent);
  border-radius: var(--radius-md);
  overflow: hidden;
  background: color-mix(in srgb, var(--ivory) 4%, transparent);
}

.events__preview-img {
  position: absolute;
  inset: 0;
  background-size: cover;
  background-position: center;
  clip-path: inset(0 0 100% 0);
  transform: scale(1.06);
  transition:
    clip-path 700ms var(--ease-out-cinema),
    transform 900ms var(--ease-out-cinema);
}

.events__preview-img.is-shown {
  clip-path: inset(0);
  transform: scale(1);
}

/* JS toggles this while resetting the outgoing layer beneath the fresh one —
   prevents a reverse-wipe flash. */
.events__preview-img.no-transition { transition: none; }

/* ---- Row list ---- */
.events__list {
  grid-area: list;
  list-style: none;
  margin: 0;
  padding: 0;
  border-block-end: 1px solid color-mix(in srgb, var(--ivory) 25%, transparent);
}

.events__row {
  border-block-start: 1px solid color-mix(in srgb, var(--ivory) 25%, transparent);
}

.events__link {
  display: block;
  position: relative;
  padding-block: var(--space-5);
  padding-inline: var(--space-2);
  text-decoration: none;
  color: var(--fg-on-dark);
}

/* Per-row <picture> — mobile-only cards (mobile/css/events.css shows it).
   display:none keeps the lazy images unfetched on desktop, where the
   preview panel owns the imagery. */
.events__media { display: none; }

.events__link:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}

.events__name {
  display: inline-block;
  font-family: var(--font-display-he);
  font-weight: var(--fw-medium);
  font-size: clamp(1.8rem, 2.6vw, 3rem);
  line-height: 1.2;
  color: color-mix(in srgb, var(--ivory) 72%, transparent);
  transition: color var(--dur-slow) var(--ease-out-cinema);
}

/* ---- Original per-event description (restored 2026-07-13) ----
   Expands under the active row's name via the pure-CSS 0fr→1fr grid trick;
   collapsed rows keep it hidden without measuring heights in JS. */
.events__desc-wrap {
  display: grid;
  grid-template-rows: 0fr;
  transition: grid-template-rows var(--dur-deluxe) var(--ease-out-cinema);
}

.events__desc {
  display: block;
  overflow: hidden;
  min-block-size: 0;
  max-inline-size: 56ch;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  line-height: 1.7;
  /* ivory-94% — --fg-on-dark-muted (88%) sits exactly on the 4.5:1 AA
     boundary against the taupe ground; small text needs headroom (§9). */
  color: color-mix(in srgb, var(--ivory) 94%, transparent);
  opacity: 0;
  transition:
    opacity var(--dur-slow) var(--ease-out-cinema),
    padding var(--dur-deluxe) var(--ease-out-cinema);
}

.events__row.is-active .events__desc-wrap { grid-template-rows: 1fr; }
.events__row.is-active .events__desc {
  opacity: 1;
  padding-block-start: var(--space-3);
  transition-delay: 120ms, 0ms;
}

/* Active row: brass name + a short brass rule sliding in from the start,
   with the link text making room (logical padding shift — RTL-safe). */
.events__row.is-active .events__name { color: var(--brass-glow); }

.events__row .events__link::before {
  content: "";
  position: absolute;
  inset-inline-start: 0;
  inset-block-start: 50%;
  translate: 0 -50%;
  inline-size: 0;
  block-size: 1px;
  background: var(--brass-glow);
  transition: inline-size var(--dur-slow) var(--ease-out-cinema);
}
.events__row.is-active .events__link::before { inline-size: var(--space-8); }
.events__row.is-active .events__link { padding-inline-start: var(--space-12); }
.events__link { transition: none; } /* Avoid animating layout during pointer movement. */

/* ---- Reduced motion: instant swap, no wipe/scale/slide ---- */
@media (prefers-reduced-motion: reduce) {
  .events__preview-img {
    clip-path: inset(0);
    transform: none;
    opacity: 0;
    transition: opacity 0.01ms;
  }
  .events__preview-img.is-shown { opacity: 1; }
  .events__link,
  .events__link::before,
  .events__name,
  .events__desc-wrap,
  .events__desc { transition: none; }
}

/* ===========================================================================
   site-nav.css — sticky top navigation (RTL Hebrew)
   ---------------------------------------------------------------------------
   Constitution: §4 (RTL, logical properties only), §5 (single accent —
   --accent-rose reserved for CTA), §8/§9 (reduced-motion, 3px brass focus
   ring), §10.2 (tokens are single-source).

   Redesign 2026-06-01:
   - Single clean breakpoint at 1024px (was a dead-zone at 901–1023px).
       ≥ 1024px → full desktop bar.
       < 1024px → hamburger + overlay.
   - Desktop shows ~6 PRIMARY links; [data-secondary] links are hidden on
     desktop and surface only in the mobile overlay clone.
   - Scroll state: .site-nav.is-scrolled condenses the bar (less padding,
     opaque ivory + shadow, slightly smaller logo). JS adds the class.
   - RTL underline grows from the inline-start (right) edge correctly.
   - CTA: outline by default, fills with --accent-rose on hover/focus.
   ========================================================================= */


.site-nav {
  /* position: fixed (was sticky) — 2026-06-10 bounce fix. A sticky nav
     reserves an 81px box at its document origin (above #hero). The hero
     hover-reveal mode switches the nav to `fixed` (no reserve, hero flush at
     y=0); when the user scrolled ~80% past the hero, hero-mode dropped and the
     nav reverted to `sticky`, RE-INSERTING that 81px reserve above the hero —
     shoving the whole page down 81px mid-scroll (the "bounce" the user saw;
     Playwright confirmed docHeight 21411→21492 + hero.top 0→81 at that exact
     point). Keeping it `fixed` always removes the swap → no reserve ever →
     no bounce. The hero is full-bleed at y=0 (correct), and post-hero the
     fixed bar pins to top:0 exactly as the sticky one did when stuck. */
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 120; /* Above hero 110/composer 111; below modal overlays. */
  background: color-mix(in srgb, var(--ivory) 86%, transparent); /* ivory @ 86% */
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  border-block-end: 1px solid var(--border);
  transition: background var(--dur-base) var(--ease-out-cinema),
              box-shadow var(--dur-base) var(--ease-out-cinema),
              border-color var(--dur-base) var(--ease-out-cinema);
}

/* Scroll state — condensed, opaque, lifted ------------------------------- */
.site-nav.is-scrolled {
  background: color-mix(in srgb, var(--ivory) 97%, transparent); /* ivory @ 97% — near-solid */
  box-shadow: var(--shadow-soft);
  border-block-end-color: transparent;
}

.site-nav__inner {
  max-inline-size: 1440px;
  margin-inline: auto;
  padding-block: var(--space-6);
  padding-inline: clamp(20px, 3.4vw, 40px);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-6);
  min-block-size: 88px;
  /* Condensed layout changes once; avoid animating a document layout metric. */
}

.site-nav.is-scrolled .site-nav__inner {
  padding-block: var(--space-3);
  min-block-size: 68px;
}

/* Reveal-grow (2026-06-09 v8) — driven by the JS-toggled
   [data-hero-mode][data-nav-revealed] attributes (NOT CSS :hover). The bar
   arrives at 160px in the SAME transition as the slide-in, so the user sees
   one motion instead of the v7 double-jump (88px slide-in followed by an
   88→160px snap when :hover later fired). 160px guarantees the bar fully
   covers the GAMOS brand mark (top:4%, ~95px tall → ~140px from top).
   The opaque-ivory + box-shadow treatment lives in
   css/components/site-nav-hover.css under the same selector. */
/* Desktop-only: reveal-grow is a CURSOR-hover affordance (cover the brand mark
   when the bar slides in). On touch there's no hover, and the mobile pass keeps
   the bar revealed for hamburger reachability — so 160px there is just a giant
   bar. Scoping this to ≥769px makes it self-document as desktop-only; the mobile
   compact cap lives in mobile/css/touch-targets.css. */
@media (min-width: 769px) {
  html[data-hero-mode="true"][data-nav-revealed="true"] .site-nav__inner {
    padding-block: var(--space-10);
    min-block-size: 160px;
  }
}

/* Brand -------------------------------------------------------------------- */
.site-nav__brand {
  display: inline-flex;
  align-items: center;
  flex-shrink: 0;
  text-decoration: none;
  color: var(--fg);
  line-height: 0;
}

.site-nav__brand-logo {
  display: block;
  height: 76px;
  width: auto;
  max-inline-size: 340px;
  object-fit: contain;
  transition: opacity var(--dur-base) var(--ease-out-cinema),
              height  var(--dur-base) var(--ease-out-cinema);
}
.site-nav.is-scrolled .site-nav__brand-logo { height: 56px; }

.site-nav__brand:hover .site-nav__brand-logo { opacity: 0.85; }
.site-nav__brand:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);   /* two-tone ring (a11y pass 2026-07-21) */
  border-radius: var(--radius-sm);
}

/* Link list ---------------------------------------------------------------- */
.site-nav__links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  gap: clamp(20px, 2.4vw, 40px);
  align-items: center;
  flex: 1;
  justify-content: center;
}

.site-nav__links a {
  font-family: var(--font-body);
  font-size: clamp(1.25rem, 1.5vw, 1.5rem);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-normal);
  color: var(--fg);
  text-decoration: none;
  padding-block: var(--space-3);
  white-space: nowrap;
  position: relative;
  transition: color var(--dur-base) var(--ease-out-cinema);
}

/* Underline — grows from the inline-start (right edge in RTL).
   transform-origin keywords are NOT logical, so in an RTL context we want the
   origin pinned to the RIGHT (the reading start). We set it explicitly to
   `right center` for the resting/exit state and keep it RIGHT on enter so the
   wipe always tracks reading direction. */
.site-nav__links a::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  block-size: 2px;
  background: var(--brass);
  transform: scaleX(0);
  transform-origin: right center; /* RTL: grow from reading start */
  transition: transform var(--dur-base) var(--ease-out-cinema);
}

.site-nav__links a:hover,
.site-nav__links a:focus-visible {
  color: var(--cocoa);
}
.site-nav__links a:hover::after,
.site-nav__links a:focus-visible::after {
  transform: scaleX(1);
}

.site-nav__links a:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);   /* two-tone ring — visible on the light bar
                                      and when the hero reveals it (a11y 2026-07-21) */
  border-radius: var(--radius-sm);
}

/* Active link (scroll-spy sets aria-current="true" + .is-active) ----------- */
.site-nav__links a[aria-current="true"],
.site-nav__links a.is-active {
  color: var(--cocoa);
}
.site-nav__links a[aria-current="true"]::after,
.site-nav__links a.is-active::after {
  transform: scaleX(1);
}

/* Secondary links never show on the desktop bar — they live in the overlay. */
.site-nav__links a[data-secondary],
.site-nav__links li:has(a[data-secondary]) {
  display: none;
}

/* CTA removed 2026-06-02 (per user: "the standalone Book button is too
   aggressive — let the nav bar BE the call to action").
   CTA REINSTATED 2026-07-13 (conversion pass — user decision after the
   marketing critique: "תיאום סיור" must be the one distinct action in the
   bar). It stays in the nav's own line-language — no box, no pill: the
   .btn--filled grammar expressed on the nav link (thick brass underline AT
   REST, semibold, thickens on hover). */
.site-nav__links a.site-nav__cta {
  font-weight: var(--fw-semibold);
  color: var(--cocoa);
}
.site-nav__links a.site-nav__cta::after {
  transform: scaleX(1);            /* visible at rest — anchors the action */
  block-size: 2.5px;
  transition: block-size var(--dur-base) var(--ease-out-cinema),
              background var(--dur-base) var(--ease-out-cinema);
}
.site-nav__links a.site-nav__cta:hover::after,
.site-nav__links a.site-nav__cta:focus-visible::after {
  block-size: 3.5px;
  background: var(--brass-deep);
}

/* Hamburger toggle --------------------------------------------------------- */
.site-nav__toggle {
  display: none;
  background: transparent;
  border: 0;
  padding: var(--space-2);
  cursor: pointer;
  position: relative;
  z-index: calc(var(--z-overlay) + 1); /* above mobile overlay backdrop */
  width: 44px;  /* WCAG 2.5.5 target size — ≥ 44×44px */
  height: 44px;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  gap: 5px;
}

.site-nav__toggle:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}

.site-nav__toggle-bar {
  display: block;
  width: 24px;
  height: 2px;
  background: var(--fg);
  border-radius: 2px;
  transform-origin: 50% 50%;
  transition: transform var(--dur-base) var(--ease-out-cinema),
              opacity   var(--dur-base) var(--ease-out-cinema);
}

/* Hamburger → X morph (CSS-only) ----------------------------------------- */
.site-nav__toggle.is-open .site-nav__toggle-bar:nth-child(1) {
  transform: translateY(7px) rotate(45deg);
}
.site-nav__toggle.is-open .site-nav__toggle-bar:nth-child(2) {
  opacity: 0;
}
.site-nav__toggle.is-open .site-nav__toggle-bar:nth-child(3) {
  transform: translateY(-7px) rotate(-45deg);
}

/* ===========================================================================
   Below 1360px use the menu; French labels need the wider full-link bar.
   Use the same breakpoint in js/site-nav.js resize cleanup.
   ========================================================================= */
@media (max-width: 1359.98px) {
  .site-nav__links { display: none; }
  .site-nav__toggle { display: inline-flex; }
}

/* On desktop, never show the overlay even if state somehow lingers. */
@media (min-width: 1360px) {
  .site-nav__mobile { display: none !important; }
}

@media (min-width: 769px) and (max-width: 1359.98px) {
  .site-nav__inner { min-block-size: 72px; padding-block: var(--space-2); }
  .site-nav__brand-logo { inline-size: 110px; }
}

/* ===========================================================================
   Mobile overlay menu (.site-nav__mobile)
   Injected by js/site-nav.js into <body>. Hidden via [hidden] attribute by
   default; .is-open class toggles the visible state with a fade.
   ========================================================================= */

.site-nav__mobile {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  background: color-mix(in srgb, var(--ivory) 97%, transparent); /* ivory @ 97% — token-mapped */
  backdrop-filter: saturate(140%) blur(16px);
  -webkit-backdrop-filter: saturate(140%) blur(16px);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out-cinema);
  display: flex;
  justify-content: center;
  /* NOTE: do NOT use `align-items: center` here. With all ~15 links the inner
     list is TALLER than the viewport; flex centering then overflows
     SYMMETRICALLY and pushes the top items ABOVE the scroll origin where they
     can't be reached (the bug: "can't scroll to the top items"). Instead the
     inner block centers via `margin: auto` (see __inner) — it centers when the
     content fits and collapses to 0 when it overflows, keeping the top
     reachable. -webkit-overflow-scrolling gives momentum scroll on iOS. */
  padding-block: var(--space-24) var(--space-16);
  padding-inline: var(--gutter);
  overflow-y: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior: contain;
}

.site-nav__mobile[hidden] {
  display: none;
}

.site-nav__mobile.is-open {
  opacity: 1;
}

/* Close (X) button — the visible way out of the overlay. The overlay's
   backdrop-filter makes it the containing block for this fixed child, so it
   pins to the overlay's top-inline-end corner and doesn't scroll with the list.
   ≥44px tap target (§9). Injected by js/site-nav.js buildOverlay(). */
.site-nav__mobile__close {
  position: fixed;
  inset-block-start: var(--space-16);
  inset-inline-end: var(--gutter);
  z-index: 1;
  inline-size: 44px;
  block-size: 44px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0;
  border: 0;
  background: transparent;
  color: var(--cocoa);
  cursor: pointer;
  border-radius: 999px;
  -webkit-tap-highlight-color: transparent;
  transition: color var(--dur-base) var(--ease-out-cinema),
              transform var(--dur-base) var(--ease-out-cinema);
}
.site-nav__mobile__close:hover,
.site-nav__mobile__close:focus-visible { color: var(--brass-deep); }
.site-nav__mobile__close:focus-visible { outline: none; box-shadow: var(--focus-ring); }
.site-nav__mobile__close:active { transform: scale(0.94); }

.site-nav__mobile__inner {
  width: 100%;
  max-width: var(--container-narrow);
  /* margin:auto (not the parent's align-items:center) does the vertical
     centering. When the list fits, the auto top/bottom margins split the slack
     evenly → centered. When it's taller than the scroll area, the auto margins
     collapse to 0 → the list starts at the top and EVERY item is scroll-
     reachable (incl. padding-block on the parent). This is the standard
     overflow-safe centering pattern for a scrollable flex overlay. */
  margin-block: auto;
  margin-inline: auto;
}

.site-nav__mobile__links {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  text-align: center;
}

/* In the overlay, ALL links (primary + secondary) are visible. */
.site-nav__mobile__links a {
  display: block;
  font-family: var(--font-display-he);
  font-size: var(--text-xl);
  font-weight: var(--fw-medium);
  color: var(--fg);
  text-decoration: none;
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  transition: color var(--dur-base) var(--ease-out-cinema),
              background var(--dur-base) var(--ease-out-cinema);
}

.site-nav__mobile__links a:hover,
.site-nav__mobile__links a:focus-visible {
  color: var(--cocoa);
  background: var(--bg-alt);
  outline: none;
}

.site-nav__mobile__links a:focus-visible {
  box-shadow: var(--focus-ring);
}

.site-nav__mobile__links a[aria-current="true"],
.site-nav__mobile__links a.is-active {
  color: var(--cocoa);
}

/* Body scroll lock while mobile nav is open. */
html.nav-open,
html.nav-open body {
  overflow: hidden;
}

/* ===========================================================================
   Reduced motion — kill the condense/underline/CTA transitions.
   (Token durations already collapse to ~0ms via tokens.css, but we also drop
   the transform translate on the CTA so nothing jumps.)
   ========================================================================= */
.site-nav__links .site-nav__lang-opt:not(.is-active) {
  color: var(--cocoa);
}

@media (prefers-reduced-motion: reduce) {
  .site-nav,
  .site-nav__inner,
  .site-nav__brand-logo,
  .site-nav__links a::after,
  .site-nav__mobile {
    transition: none;
  }
}

/* ===========================================================================
   site-footer.css — the closing "engraved-invitation" footer (contentinfo)
   ---------------------------------------------------------------------------
   REBUILT 2026-07-21 (footer-craft pass). The page previously ended on the
   #routes map with NO <footer> at all; this is the site's first real footer.

   Design brief — a brand CLOSE, not a sitemap. Three quiet bands on the
   deepest tone in the palette (ink-deep), so brass sings and every text tier
   clears WCAG AA with headroom:
     ground = --ink-deep (#1A1410)
       ivory      15.96:1   claim / values / lede
       brass      8.72:1    decorative eyebrow / hairline
       brass-glow 9.65:1    accents / hover
       muted ivory (~70%) ≈ 8.2:1   secondary labels
       faint ivory (~55%)  ≈ 5.5:1   copyright / legal (still ≥4.5 for 12px)

     1. CLOSE — centered peak-end beat: positioning eyebrow, texture claim
        (.texture-text--light — the site's signature "engraved" fill), a warm
        lede, and the primary CTA pair (Book a tour → #contact + WhatsApp),
        reusing the canonical .btn / .btn--glass line-language (§ buttons.css).
     2. META — a refined masthead-footer row: concierge contact block (start)
        + labelled social links (end). NOT a four-column link farm.
     3. BASE — thin closing line: copyright · legal links · back-to-top.

   Discipline: tokens only (§10.2), logical properties only (§4, RTL-first),
   section-rhythm spacing tokens. NO mobile @media here (§13 — narrow overrides
   live in mobile/css/site-footer.css). Focus rings come from the site-wide
   two-tone --focus-ring (base.css :focus-visible) — never a flat brass outline
   (a11y pass 2026-07-21). Editorial line-language: no boxes/borders/fills on
   CTAs; the only lines are hairline dividers + the growing brass underlines.
   ========================================================================= */

.site-footer {
  /* CSS gradients and transform-origin do not accept logical side keywords.
     Keep one direction-aware percentage token instead: RTL starts at the
     inline start (right), while the LTR override below starts at the left. */
  --footer-inline-origin: 100% 50%;
  position: relative;
  isolation: isolate;
  background: var(--bg-dark);            /* ink-deep — the deepest close */
  color: var(--fg-on-dark);              /* ivory */
  padding-block: var(--section-pad-tight) var(--space-10);
  padding-inline: var(--gutter);
}

html[dir="ltr"] .site-footer {
  --footer-inline-origin: 0% 50%;
}

/* Brass "seam" hairline at the very top edge — the invitation's foil rule,
   dividing the routes map from the close. Within bounds (no overflow clip). */
.site-footer::before {
  content: "";
  position: absolute;
  inset-block-start: 0;
  inset-inline: 0;
  block-size: 1px;
  background: linear-gradient(
    90deg,
    transparent 0%,
    color-mix(in srgb, var(--brass) 60%, transparent) 50%,
    transparent 100%
  );
  pointer-events: none;
  z-index: 0;
}

.site-footer__inner {
  position: relative;
  z-index: 1;
  max-inline-size: 1040px;
  margin-inline: auto;
  display: flex;
  flex-direction: column;
  gap: var(--space-16);
}


/* ----- 1. Close block (the peak-end beat) ─────────────────────────────── */

.site-footer__close {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-5);
}

.site-footer__eyebrow {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-eyebrow);   /* 0.18em — engraved */
  color: var(--brass-glow);                   /* 9.65:1 on ink — decoration */
  text-wrap: balance;
}

.site-footer__claim {
  margin: 0;
  max-inline-size: 20ch;
  font-family: var(--font-display-he);
  font-weight: var(--fw-bold);
  font-size: clamp(var(--text-xl), 4.6vw, var(--text-3xl));
  line-height: 1.1;
  letter-spacing: var(--tracking-tight);
  /* Solid fallback for engines without background-clip:text; the
     .texture-text--light class paints the cream texture over it. */
  color: var(--ivory);
  text-wrap: balance;
}

.site-footer__lede {
  margin: 0;
  max-inline-size: 52ch;
  font-family: var(--font-body);
  font-size: var(--text-md);
  line-height: var(--lh-normal);
  /* ~78% ivory over ink ≈ 10:1 — well above AA for this larger body text. */
  color: color-mix(in srgb, var(--ivory) 80%, transparent);
}

.site-footer__cta-row {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: baseline;
  gap: var(--space-4) var(--space-8);
  margin-block-start: var(--space-2);
}

/* The canonical text-button stays visually unboxed, but both footer actions
   still need a complete WCAG-size hit target (the secondary label is otherwise
   only ~25px tall). Keep this scoped to the footer so the global editorial
   button rhythm is unchanged. */
.site-footer__cta-row .btn {
  min-block-size: 44px;
}

/* Primary CTA emphasis on the dark ground: anchor a brass-glow underline AT
   REST — the site's .btn--filled "this is the main action" language, tuned for
   the ivory-on-ink glass button (.btn--filled's ink-deep text is unreadable
   here). Thickens on hover/focus. Scoped under .site-footer so it out-specifies
   .btn::after (0,1,1) — which otherwise wins the tie by source order, buttons.css
   being linked after the section CSS. */
.site-footer .site-footer__cta--primary::after {
  transform: scaleX(1);
  block-size: 2px;
  transition: block-size var(--dur-base) var(--ease-out-cinema);
}
.site-footer .site-footer__cta--primary:hover::after,
.site-footer .site-footer__cta--primary:focus-visible::after {
  block-size: 3px;
}


/* ----- 2. Meta row (contact + social) ─────────────────────────────────── */

.site-footer__meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: flex-start;
  gap: var(--space-10) var(--space-12);
  padding-block-start: var(--space-12);
  border-block-start: 1px solid color-mix(in srgb, var(--ivory) 12%, transparent);
}

.site-footer__col-title {
  margin: 0 0 var(--space-5);
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-eyebrow);
  color: var(--brass-glow);
}

/* Concierge contact list — quiet "label / value" rows, not a table. */
.site-footer__contact {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  max-inline-size: 34ch;
}

.site-footer__contact-row {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--space-1) var(--space-3);
}

.site-footer__contact-label {
  flex: 0 0 auto;
  min-inline-size: 6.5ch;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  /* ~62% ivory over ink ≈ 6.5:1 — passes AA for this 14px label. */
  color: color-mix(in srgb, var(--ivory) 64%, transparent);
}

.site-footer__contact-value {
  font-family: var(--font-body);
  font-size: var(--text-base);
  color: var(--ivory);
  text-decoration: none;
}

/* Links inside the value slot grow a brass underline (nav/CTA grammar). */
a.site-footer__contact-value {
  position: relative;
  transition: color var(--dur-base) var(--ease-out-cinema);
}
a.site-footer__contact-value::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: -2px;
  block-size: 1px;
  background: var(--brass-glow);
  transform: scaleX(0);
  transform-origin: var(--footer-inline-origin);
  transition: transform var(--dur-base) var(--ease-out-cinema);
}
a.site-footer__contact-value:hover,
a.site-footer__contact-value:focus-visible {
  color: var(--brass-glow);
  outline: none;
}
a.site-footer__contact-value:hover::after,
a.site-footer__contact-value:focus-visible::after {
  transform: scaleX(1);
}

/* Social — visible, LABELLED links (icon + text; §9, not icon-only). */
.site-footer__social {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.site-footer__social-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  min-block-size: 44px;              /* WCAG target even though visual is text */
  font-family: var(--font-body);
  font-size: var(--text-base);
  color: var(--ivory);
  text-decoration: none;
  transition: color var(--dur-base) var(--ease-out-cinema);
}
.site-footer__social-glyph {
  display: inline-flex;
  inline-size: 20px;
  block-size: 20px;
  color: var(--brass-glow);
  transition: transform var(--dur-base) var(--ease-out-cinema);
}
.site-footer__social-glyph svg {
  inline-size: 100%;
  block-size: 100%;
  display: block;
}
.site-footer__social-text {
  position: relative;
}
.site-footer__social-text::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: -3px;
  block-size: 1px;
  background: var(--brass-glow);
  transform: scaleX(0);
  transform-origin: var(--footer-inline-origin);
  transition: transform var(--dur-base) var(--ease-out-cinema);
}
.site-footer__social-link:hover,
.site-footer__social-link:focus-visible {
  color: var(--brass-glow);
  outline: none;
}
.site-footer__social-link:hover .site-footer__social-text::after,
.site-footer__social-link:focus-visible .site-footer__social-text::after {
  transform: scaleX(1);
}
.site-footer__social-link:hover .site-footer__social-glyph,
.site-footer__social-link:focus-visible .site-footer__social-glyph {
  transform: translateY(-1px);
}


/* ----- 3. Base row (copyright · legal · back-to-top) ──────────────────── */

.site-footer__base {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: center;
  gap: var(--space-4) var(--space-8);
  padding-block-start: var(--space-8);
  border-block-start: 1px solid color-mix(in srgb, var(--ivory) 10%, transparent);
}

.site-footer__copyright {
  margin: 0;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  /* ~58% ivory over ink ≈ 5.9:1 — passes AA for 12px. */
  color: color-mix(in srgb, var(--ivory) 60%, transparent);
}

.site-footer__legal {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
}
.site-footer__legal a {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  color: color-mix(in srgb, var(--ivory) 66%, transparent);  /* ≈ 6.9:1 */
  text-decoration: none;
  transition: color var(--dur-base) var(--ease-out-cinema);
}
.site-footer__legal a:hover,
.site-footer__legal a:focus-visible {
  color: var(--brass-glow);
  outline: none;
}

/* Back-to-top — editorial text + arrow (line language, no box). Sized to a
   44px hit area; the label underline grows and the arrow lifts on hover.
   Scrolls to #hero via js/footer.js (Lenis → native fallback). */
.site-footer__totop {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: 44px;
  padding-inline: var(--space-1);
  background: transparent;
  border: 0;
  cursor: pointer;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-wide);
  color: var(--brass-glow);
  transition: color var(--dur-base) var(--ease-out-cinema);
}
.site-footer__totop-label {
  position: relative;
}
.site-footer__totop-label::after {
  content: "";
  position: absolute;
  inset-inline: 0;
  inset-block-end: -3px;
  block-size: 1px;
  background: var(--brass-glow);
  transform: scaleX(0);
  transform-origin: var(--footer-inline-origin);
  transition: transform var(--dur-base) var(--ease-out-cinema);
}
.site-footer__totop-arrow {
  display: inline-flex;
  inline-size: 16px;
  block-size: 16px;
  transition: transform var(--dur-base) var(--ease-out-cinema);
}
.site-footer__totop-arrow svg {
  inline-size: 100%;
  block-size: 100%;
  display: block;
}
.site-footer__totop:hover,
.site-footer__totop:focus-visible {
  color: var(--ivory);
}
.site-footer__totop:hover .site-footer__totop-label::after,
.site-footer__totop:focus-visible .site-footer__totop-label::after {
  transform: scaleX(1);
}
.site-footer__totop:hover .site-footer__totop-arrow,
.site-footer__totop:focus-visible .site-footer__totop-arrow {
  transform: translateY(-3px);
}


/* ----- Reduced motion (§8) — silence the grows/lifts; final state static. --- */

@media (prefers-reduced-motion: reduce) {
  a.site-footer__contact-value,
  a.site-footer__contact-value::after,
  .site-footer__social-link,
  .site-footer__social-glyph,
  .site-footer__social-text::after,
  .site-footer__legal a,
  .site-footer__totop,
  .site-footer__totop-label::after,
  .site-footer__totop-arrow {
    transition: none;
  }
  .site-footer__social-link:hover .site-footer__social-glyph,
  .site-footer__social-link:focus-visible .site-footer__social-glyph,
  .site-footer__totop:hover .site-footer__totop-arrow,
  .site-footer__totop:focus-visible .site-footer__totop-arrow {
    transform: none;
  }
}

/* ===========================================================================
   section-header.css — global section header pattern (eyebrow + title + lede)
   Used by: lounge, rooms, culinary, about, testimonials, gallery, events, ...
   ========================================================================= */


.section-header {
  margin-block-end: var(--space-12);
  max-inline-size: 64ch;
}

.section-header--center {
  margin-inline: auto;
  text-align: center;
}

.section-header__eyebrow {
  font-family: var(--font-body);
  /* 2026-06-16: was --text-xs (12px) — user reported "נורא קטן". Bumped to a
     clamp that scales with the title yet stays subordinate to the lede. */
  font-size: clamp(0.95rem, 1.1vw, 1.125rem);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  /* Was var(--accent) (brass) — brass-as-text on ivory = 1.83:1, a systematic
     WCAG AA fail across the light sections (2026-07-21 a11y pass). Per the
     Brass Decoration Rule (DESIGN.md §2) brass is decoration/underline/on-dark
     only; a text eyebrow on a LIGHT surface uses --cocoa (8.46:1). This is the
     DEFAULT — every dark/on-dark section already re-colors its own eyebrow with
     higher specificity (events → --ivory in events.css; culinary → --brass in
     scroll-scene.css), so their look is untouched. Do NOT add a broad
     :has(.texture-text--light) override here: it would out-specify and clobber
     the events section's deliberate ivory eyebrow (brass = 2.88:1 on the taupe
     ground there, which is exactly why events chose ivory). */
  color: var(--cocoa);
  margin: 0 0 var(--space-4) 0;
}

.section-header__title {
  font-family: var(--font-display-he);
  /* Capped at 4vw so it never breaks out of a 40vw section-rail container.
     Min 2rem keeps mobile readable. (was 5vw → overflowed rooms heading). */
  font-size: clamp(2rem, 4vw, 3.75rem);
  line-height: var(--lh-tight);
  letter-spacing: var(--tracking-tight);
  font-weight: var(--fw-bold);
  color: var(--fg);
  margin: 0 0 var(--space-4) 0;
  max-inline-size: 100%;
  word-break: keep-all;
  overflow-wrap: break-word;
}

.section-header--center .section-header__title { max-inline-size: none; }

.section-header__lede {
  font-family: var(--font-body);
  font-size: clamp(1.125rem, 1.5vw, 1.4rem); /* Agent 20 — luxury body lede */
  line-height: var(--lh-snug);
  color: var(--fg-muted);
  margin: 0;
  max-inline-size: 56ch;
}

.section-header--on-dark .section-header__title { color: var(--fg-on-dark); }
.section-header--on-dark .section-header__lede  { color: color-mix(in srgb, var(--ivory) 78%, transparent); }



/* =====================================================================
 * motion-reveals.css
 * Agent 09 — reveal-on-scroll patterns (paired with js/reveals.js).
 * Original variants: fade, fade-up, mask, scale.
 *
 * Agent 20 — Choreographer extension (2026-06-01): added weblove-motion
 * variants for the static sections — slide-left, slide-right, scale-up,
 * clip-reveal, rotate-in. Per-item delay supported via inline
 * `style="--reveal-delay: 240ms"` (CSS reads it as transition-delay).
 *
 * Tokens consumed from css/tokens.css (Agent 02).
 * ===================================================================== */

/* ---------------------------------------------------------------------
 * Initial states — every [data-reveal] starts hidden + offset.
 * The default variant is "fade-up". JS adds .is-visible on intersect.
 * --reveal-delay (inline) → transition-delay (Agent 20 weblove pipeline).
 * ------------------------------------------------------------------- */
[data-reveal] {
  opacity: 0;
  will-change: opacity, transform, clip-path;
  transition-property: opacity, transform, clip-path;
  transition-duration: var(--dur-deluxe, 600ms);
  transition-timing-function: var(--ease-out-cinema, cubic-bezier(0.2, 0.8, 0.2, 1));
  transition-delay: var(--reveal-delay, 0ms);
}

/* Default + explicit fade-up: opacity + slide up */
[data-reveal],
[data-reveal="fade-up"] {
  transform: translate3d(0, 24px, 0);
}

/* Pure fade — no transform */
[data-reveal="fade"] {
  transform: none;
  transition-duration: var(--dur-slow, 360ms);
}

/* Mask reveal — clip-path inset (used on large display headings) */
[data-reveal="mask"] {
  transform: none;
  clip-path: inset(0 0 100% 0);
  transition-duration: var(--dur-cinema, 1000ms);
}

/* Scale reveal — gentle inset zoom (legacy from Agent 09) */
[data-reveal="scale"] {
  transform: scale(0.94);
  transition-duration: var(--dur-deluxe, 600ms);
}

/* ---------------------------------------------------------------------
 * Agent 20 — weblove-motion variants
 * ------------------------------------------------------------------- */

/* slide-left — element enters with translateX(-40px) */
[data-reveal="slide-left"] {
  transform: translate3d(-40px, 0, 0);
  transition-duration: 800ms;
}

/* slide-right — element enters with translateX(+40px) */
[data-reveal="slide-right"] {
  transform: translate3d(40px, 0, 0);
  transition-duration: 800ms;
}

/* scale-up — pop in with a slight zoom */
[data-reveal="scale-up"] {
  transform: scale(0.92);
  transition-duration: 800ms;
}

/* clip-reveal — top→bottom wipe.
   REBUILT 2026-07-13: originally clip-path on the element itself, but modern
   Chromium's IntersectionObserver applies the TARGET'S OWN clip-path when
   computing intersection — a fully-clipped hidden state is an empty box, the
   observer never reports intersecting, reveals.js never fires, and the
   section stays invisible forever (user report: #testimonials). The wipe is
   now a page-surface curtain (::after) that shrinks toward the bottom edge —
   the observed element is never clipped, the visual over the flat surface is
   identical. (The unused "mask" variant above still carries the old pattern —
   rebuild it the same way before using it on anything.) */
[data-reveal="clip-reveal"] {
  transform: none;
  opacity: 0.8;
  transition-duration: var(--dur-cinema, 1000ms);
  position: relative;
}
[data-reveal="clip-reveal"]::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 20;                       /* above the section's own content */
  background: var(--bg);             /* the page surface the old clip exposed */
  transform-origin: bottom center;   /* shrink downward → content appears top-first */
  pointer-events: none;
  transition: transform var(--dur-cinema, 1000ms) var(--ease-out-cinema, cubic-bezier(0.2, 0.8, 0.2, 1)) var(--reveal-delay, 0ms);
}
[data-reveal="clip-reveal"].is-visible::after {
  transform: scaleY(0);
}

/* rotate-in — subtle 3deg tilt + scale + fade (calm "stamp") */
[data-reveal="rotate-in"] {
  transform: rotate(3deg) scale(0.97);
  transition-duration: var(--dur-cinema, 1000ms);
}

/* ---------------------------------------------------------------------
 * Final states — JS adds .is-visible when target intersects viewport.
 * ------------------------------------------------------------------- */
[data-reveal].is-visible {
  opacity: 1;
  transform: translate3d(0, 0, 0) scale(1) rotate(0);
  clip-path: inset(0 0 0 0);
}

/* ---------------------------------------------------------------------
 * Stagger container — child reveal delays are JS-driven (80ms step) OR
 * inline-property-driven (CSS reads --reveal-delay).
 * ------------------------------------------------------------------- */
[data-stagger] {
  /* Layout untouched — purely a hook for js/reveals.js. */
}

/* ---------------------------------------------------------------------
 * Reduced motion — instant final state. JS also short-circuits, this
 * is a belt-and-braces guarantee per architecture/rtl-and-a11y.md §
 * "Reduced Motion".
 * ------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  [data-reveal] {
    opacity: 1 !important;
    transform: none !important;
    clip-path: none !important;
    transition: none !important;
    will-change: auto;
  }
  /* The clip-reveal curtain must vanish instantly too. */
  [data-reveal="clip-reveal"]::after {
    content: none !important;
  }
}

/* =====================================================================
 * motion-slider.css
 * Agent 09 — touch + keyboard slider styling (paired with js/slider.js).
 *
 * The track uses translateX. JS computes the sign per dir (RTL/LTR).
 * Tokens consumed from css/tokens.css.
 * ===================================================================== */

/* ---------------------------------------------------------------------
 * Container — clip overflow, position relative for absolute children.
 * Focus ring sits on the root for keyboard users (tabindex=0 set by JS).
 * ------------------------------------------------------------------- */
[data-slider] {
  position: relative;
  overflow: hidden;
  inline-size: 100%;
  /* Reserve a stable height when items load asynchronously. */
  contain: layout paint;
}

[data-slider]:focus-visible {
  outline: 3px solid var(--accent);   /* container roving-focus outline */
  outline-offset: 4px;
  border-radius: var(--radius-md);
}

/* ---------------------------------------------------------------------
 * Track — flex row, each item full width. JS drives translateX.
 *
 * RTL caveat: in `dir="rtl"` flex-direction: row reverses visually.
 *   - We keep flex-direction: row (no override).
 *   - JS uses sign +1 in RTL for translateX, -1 in LTR.
 * ------------------------------------------------------------------- */
[data-slider-track] {
  display: flex;
  flex-direction: row;
  inline-size: 100%;
  will-change: transform;
  /* Touch action: pan-y allows vertical page scroll, JS handles horizontal. */
  touch-action: pan-y;
  /* Disable text selection during drag — prevents long-press surprises. */
  user-select: none;
  -webkit-user-select: none;
}

/* Each slide takes the full track width. */
[data-slider-item] {
  flex: 0 0 100%;
  inline-size: 100%;
  min-inline-size: 0;
  /* Ensure inner media never spills. */
  overflow: hidden;
}

/* ---------------------------------------------------------------------
 * Prev / Next buttons — neutral skeleton; section-specific styling lives
 * in the consuming section's CSS. Default places them at the inline edges.
 * Uses logical inset properties so RTL flips automatically.
 * ------------------------------------------------------------------- */
[data-slider-prev],
[data-slider-next] {
  position: absolute;
  inset-block-start: 50%;
  transform: translateY(-50%);
  z-index: var(--z-content, 10);
  inline-size: 3rem;
  block-size: 3rem;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;          /* LINE-LANGUAGE rev: no box — glyph only */
  color: var(--brass-deep, #8b6f46);
  border: 0;
  cursor: pointer;
  font-size: 1.5rem;
  transition: color var(--dur-base, 240ms) var(--ease-out-cinema, cubic-bezier(0.2, 0.8, 0.2, 1)),
              transform var(--dur-base, 240ms) var(--ease-out-cinema, cubic-bezier(0.2, 0.8, 0.2, 1));
}

[data-slider-prev] {
  inset-inline-start: var(--space-4, 1rem);
}

[data-slider-next] {
  inset-inline-end: var(--space-4, 1rem);
}

[data-slider-prev]:hover,
[data-slider-next]:hover {
  color: var(--brass, #cfae83);
  transform: translateY(-50%) scale(1.15);
}

[data-slider-prev]:focus-visible,
[data-slider-next]:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring-offset);   /* unified offset ring (2026-06-15) */
}

/* In RTL, mirror inline arrow icons inside the buttons (chevrons etc.). */
[dir="rtl"] [data-slider-prev] svg,
[dir="rtl"] [data-slider-next] svg {
  transform: scaleX(-1);
}

/* ---------------------------------------------------------------------
 * Dots — built programmatically by JS into [data-slider-dots].
 * Each dot is a <button>. Active dot grows + uses brass accent.
 * ------------------------------------------------------------------- */
[data-slider-dots] {
  position: absolute;
  inset-block-end: var(--space-4, 1rem);
  inset-inline-start: 0;
  inset-inline-end: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  gap: var(--space-2, 0.5rem);
  z-index: var(--z-content, 10);
}

[data-slider-dots] [data-slider-dot] {
  inline-size: 0.5rem;
  block-size: 0.5rem;
  padding: 0;
  border: 0;
  border-radius: var(--radius-pill, 9999px);
  background: color-mix(in srgb, var(--ivory) 50%, transparent);
  cursor: pointer;
  transition: inline-size var(--dur-base, 240ms) var(--ease-out-cinema, cubic-bezier(0.2, 0.8, 0.2, 1)),
              background var(--dur-base, 240ms) var(--ease-out-cinema, cubic-bezier(0.2, 0.8, 0.2, 1));
}

[data-slider-dots] [data-slider-dot].is-active {
  background: var(--accent, #b89766);
  inline-size: 1.5rem;
}

[data-slider-dots] [data-slider-dot]:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring-offset);   /* unified offset ring (2026-06-15) */
}

/* ---------------------------------------------------------------------
 * Reduced motion — kill all transitions; JS already skips animation.
 * ------------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  [data-slider-track],
  [data-slider-prev],
  [data-slider-next],
  [data-slider-dots] [data-slider-dot] {
    transition: none !important;
  }
}

/* ===========================================================================
   loading-overlay.css
   ---------------------------------------------------------------------------
   Owner       : Agent 19 — Loading Overlay + Side-Dot Nav Implementer
   Spec        : architecture/transitions-and-nav.md §1–§7
   Constitution: §4 (logical properties), §5 (palette), §8 (perf), §9 (a11y),
                 §10.2 (tokens are single source).
   ---------------------------------------------------------------------------
   Behavior
   - Fixed overlay covering full viewport (z-index = --z-overlay = 1000).
   - Hidden by default (opacity 0, visibility hidden, pointer-events: none).
   - Shown by adding `.is-visible` (JS sets aria-hidden="false" in parallel).
   - Inner: gold logo + brass progress bar + dynamic caption, stacked center.
     The JS injects "טוען…" by default and per-hall text
     ("טוען את האולם" / "טוען את הריזורט").
   - Surface: ivory wash + soft brass-tinted center glow + blur.
   - The progress bar fills 0→100% over ~1.2s while .is-visible, growing from
     the right edge (RTL: inset-inline-start + inline-size) toward the left.
   - Honors prefers-reduced-motion: instant show/hide; logo appears instantly;
     progress bar shows full statically (no growth animation).
   ========================================================================= */


/* --------------------------------------------------------------------------
   1. Container
   -------------------------------------------------------------------------- */

.loading-overlay {
  /* Position: fixed, full-viewport */
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);

  /* Layout: center content */
  display: grid;
  place-items: center;

  /* Surface — warm ivory wash with a faint brass-tinted glow blooming from the
     center, fading to mist at the edges. Layered over the blur for depth
     without busyness. Both layers are composed from palette tokens (§5/§10.2). */
  background:
    radial-gradient(
      ellipse 70% 55% at 50% 42%,
      color-mix(in srgb, var(--brass) 22%, transparent) 0%,
      color-mix(in srgb, var(--mist) 60%, transparent) 55%,
      color-mix(in srgb, var(--ivory) 96%, transparent) 100%
    ),
    color-mix(in srgb, var(--ivory) 97%, transparent);
  backdrop-filter: blur(8px) saturate(0.9);
  -webkit-backdrop-filter: blur(8px) saturate(0.9);

  /* Default: hidden */
  opacity: 0;
  visibility: hidden;
  pointer-events: none;

  /* Fade in/out */
  transition:
    opacity 200ms var(--ease-out-cinema),
    visibility 0s linear 200ms;
}

.loading-overlay.is-visible {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transition:
    opacity 200ms var(--ease-out-cinema),
    visibility 0s linear 0s;
}


/* --------------------------------------------------------------------------
   2. Inner stack (logo + bar + text)
   -------------------------------------------------------------------------- */

.loading-overlay__inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--space-6);  /* 24px */
  padding-inline: var(--space-6);
  text-align: center;
}


/* --------------------------------------------------------------------------
   3. Logo
   -------------------------------------------------------------------------- */

.loading-overlay__logo-wrap {
  display: block;
  /* Logo entrance: scale 0.85 → 1, opacity 0 → 1 (200ms) */
  opacity: 0;
  transform: scale(0.85);
  transition:
    opacity 200ms var(--ease-out-cinema),
    transform 200ms var(--ease-out-cinema);
}

.loading-overlay.is-visible .loading-overlay__logo-wrap {
  opacity: 1;
  transform: scale(1);
}

.loading-overlay__logo {
  display: block;
  inline-size: 240px;
  block-size: auto;
  max-inline-size: min(240px, 60vw);
  /* No filter — the logo asset is already gold-on-transparent */
}


/* --------------------------------------------------------------------------
   4. Progress bar (replaces the old spinner — "logo + brass progress bar")
   -------------------------------------------------------------------------- */

.loading-overlay__bar {
  /* Thin pill track */
  position: relative;
  inline-size: min(280px, 70vw);
  block-size: 2px;
  overflow: hidden;
  border-radius: var(--radius-pill);
  /* Brass rail, a touch stronger so the empty track reads as gold on ivory */
  background: color-mix(in srgb, var(--brass) 32%, transparent);
}

.loading-overlay__bar-fill {
  /* Grows from the right edge leftward in RTL: inset-inline-start anchors to
     the start (right), and inline-size sweeps toward the left. */
  position: absolute;
  inset-block: 0;
  inset-inline-start: 0;
  inline-size: 0;
  border-radius: inherit;
  /* Subtle brass → brass-deep sweep for a machined, lit edge. In RTL the fill
     grows from the right (start) edge toward the left, so the brighter brass
     leads at the right and deepens toward the advancing left edge. */
  background: linear-gradient(to left, var(--brass) 0%, var(--brass-deep) 100%);
}

/* Animate only while the overlay is shown, so the fill restarts each open. */
.loading-overlay.is-visible .loading-overlay__bar-fill {
  animation: la-fill 1200ms var(--ease-out-cinema) forwards;
}

@keyframes la-fill {
  from { inline-size: 0; }
  to   { inline-size: 100%; }
}


/* --------------------------------------------------------------------------
   5. Caption — dynamic ("טוען…" default; per-hall set by JS)
   -------------------------------------------------------------------------- */

.loading-overlay__text {
  margin: 0;
  font-family: var(--font-display-he);
  font-size: var(--text-md);                /* 20px */
  font-weight: var(--fw-regular);
  color: var(--ink-deep);
  opacity: 0.85;
  letter-spacing: var(--tracking-wide);     /* 0.05em */
  line-height: var(--lh-snug);
}


/* --------------------------------------------------------------------------
   6. Reduced-motion overrides
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .loading-overlay {
    /* Instant show/hide — duration tokens are already 0.01ms via tokens.css,
       but we override the visibility transition delay explicitly to remove
       any chance of a 200ms gap. */
    transition:
      opacity 0.01ms,
      visibility 0s linear 0.01ms;
  }
  .loading-overlay.is-visible {
    transition:
      opacity 0.01ms,
      visibility 0s linear 0s;
  }
  .loading-overlay__logo-wrap {
    /* Skip scale animation; just appear */
    transform: none;
    transition: opacity 0.01ms;
  }
  /* Progress bar shows full, statically — no growth animation. */
  .loading-overlay__bar-fill,
  .loading-overlay.is-visible .loading-overlay__bar-fill {
    inline-size: 100%;
    animation: none;
  }
}

/* ===========================================================================
   side-dot-nav.css
   ---------------------------------------------------------------------------
   Owner       : Agent 19 — Loading Overlay + Side-Dot Nav Implementer
   Spec        : architecture/transitions-and-nav.md §8–§16
   Constitution: §4 (logical properties — RTL-safe), §5 (palette via tokens),
                 §9 (visible focus rings), §10.2 (tokens are single source).
   ---------------------------------------------------------------------------
   Behavior
   - Vertical column of dots fixed on the RIGHT edge (RTL-leading via
     `inset-inline-end`). Hidden below 768px (mobile uses top-nav).
   - Each dot is a small circle outlined in brass; active state fills brass
     with a soft glow. Tooltip-on-hover shows the section name on the
     LEADING side (left in RTL, right in LTR).
   - When `[data-suppressed]` attribute is set on the nav (loading-overlay
     active), dots dim to ~0.4 opacity and pointer-events disabled.
   ========================================================================= */


/* --------------------------------------------------------------------------
   1. Container
   -------------------------------------------------------------------------- */

.side-dot-nav {
  /* Position: fixed on the visual RIGHT edge regardless of document
     direction. In RTL, `inset-inline-end` resolves to the visual LEFT
     edge — but the user wants right-edge anchoring for natural eye
     flow. We use the physical `right` property to lock it to right. */
  position: fixed;
  inset-block-start: 50%;
  right: var(--space-6);                 /* 24px from physical right edge */
  transform: translateY(-50%);
  z-index: var(--z-sticky);              /* 100 — below loading-overlay (1000) */

  /* Layout: vertical column with gaps */
  display: flex;
  flex-direction: column;
  gap: var(--space-4);                   /* 16px between dots */

  /* Default visible state */
  opacity: 1;
  pointer-events: auto;
  transition: opacity 240ms var(--ease-out-cinema);
}

/* Hide on mobile (< 768px) — top nav takes over there. */
@media (max-width: 767px) {
  .side-dot-nav {
    display: none;
  }
}

/* Suppressed: while loading-overlay is up, dim and disable. */
.side-dot-nav[data-suppressed] {
  opacity: 0.4;
  pointer-events: none;
}


/* --------------------------------------------------------------------------
   2. Dot (each is an <a>)
   -------------------------------------------------------------------------- */

.side-dot-nav__dot {
  /* Box */
  inline-size: 12px;
  block-size: 12px;
  border-radius: var(--radius-circle);
  border: 1px solid var(--brass);
  background: transparent;

  /* Anchor positioning context */
  position: relative;
  display: block;

  /* Strip default <a> underline / text */
  text-decoration: none;
  color: inherit;

  /* Interaction */
  cursor: pointer;
  transition:
    transform var(--dur-base) var(--ease-out-cinema),
    background-color var(--dur-base) var(--ease-out-cinema),
    box-shadow var(--dur-base) var(--ease-out-cinema);
}

.side-dot-nav__dot:hover {
  transform: scale(1.3);
  background-color: color-mix(in srgb, var(--brass) 30%, transparent);  /* --brass at 30% */
}

/* Placeholder dots — target section not yet in DOM. Muted, non-interactive,
   tooltip suppressed. As soon as the section's id="…" lands and the user
   re-runs init (or just reloads), the dot loses [data-placeholder] and
   becomes a normal dot. */
.side-dot-nav__dot[data-placeholder] {
  opacity: 0.35;
  cursor: default;
  pointer-events: none;
}
.side-dot-nav__dot[data-placeholder]:hover {
  transform: none;
  background-color: transparent;
}

.side-dot-nav__dot[aria-current="true"] {
  background-color: var(--brass);
  box-shadow: 0 0 12px var(--brass-glow);
}

/* Focus ring per Constitution §9. Was a flat 3px brass outline, but the dots
   are fixed and overlay EVERY section — brass fails on the light ones (1.83:1).
   The two-tone --focus-ring token (ivory gap + brass-deep) clears 3:1 on light
   AND on the dark/cocoa sections the dots also cross. (a11y pass 2026-07-21) */
.side-dot-nav__dot:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}


/* --------------------------------------------------------------------------
   3. Tooltip (hover/focus label) — appears on LEADING side
   -------------------------------------------------------------------------- */

.side-dot-nav__label {
  position: absolute;
  inset-block-start: 50%;
  inset-inline-end: calc(100% + var(--space-3));   /* 12px past dot LEADING side */
  transform: translateY(-50%) translateX(4px);

  /* Type */
  font-family: var(--font-display-he);
  font-size: var(--text-xs);                       /* 12px */
  letter-spacing: var(--tracking-wide);            /* 0.05em */
  white-space: nowrap;
  color: var(--brass-deep);

  /* Surface — ivory pill w/ hairline brass border, soft drop-shadow.
     Replaces the previous near-black surface that read as a "weird
     black stripe" against the ivory page (user feedback 2026-06-03). */
  background: var(--ivory);
  padding-inline: var(--space-3);                  /* 12px */
  padding-block: 6px;
  border-radius: var(--radius-btn);
  border: 1px solid var(--brass);
  box-shadow: var(--shadow-soft);

  /* Hidden by default */
  opacity: 0;
  pointer-events: none;
  transition: opacity 150ms var(--ease-out-cinema),
              transform 200ms var(--ease-out-cinema);
}

.side-dot-nav__dot:hover .side-dot-nav__label,
.side-dot-nav__dot:focus-visible .side-dot-nav__label {
  opacity: 1;
  transform: translateY(-50%) translateX(0);
}

/* The rail stays on the physical right in both directions; RTL labels must
   therefore grow inward (inline-start), not off the screen. */
html[dir="rtl"] .side-dot-nav__label {
  inset-inline-start: calc(100% + var(--space-3));
  inset-inline-end: auto;
}


/* --------------------------------------------------------------------------
   4. Reduced-motion overrides
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .side-dot-nav__dot {
    transition: none;
  }
  .side-dot-nav__label {
    transition: none;
  }
}

/* =====================================================================
 * marquee.css — horizontal infinite-scroll text band
 * Owner: Agent 20 — Static Sections Choreographer (2026-06-01)
 *
 * Pure CSS animation. Pairs with js/marquee.js which ONLY:
 *   1. duplicates the track contents to make the loop seamless,
 *   2. sets `--marquee-duration` from `data-speed` (seconds).
 *
 * Reduced motion: animation halted (kept static); content stays readable.
 *
 * Tokens consumed from css/tokens.css.
 * ===================================================================== */

.marquee {
  --marquee-duration: 30s;
  inline-size: 100%;
  overflow: hidden;
  /* Force LTR on the WHOLE band (not just the track). The document is dir="rtl",
     which anchors the wider-than-viewport track to the RIGHT edge and lets the
     0 → -50% keyframe scroll it off and reveal an empty gap on the right (the
     bug the user reported — twice). LTR anchors the track to the LEFT so the
     duplicated half wraps in seamlessly from the right. Each .marquee__text
     still renders its Hebrew RTL internally; only phrase left↔right order
     (decorative) is normalised. */
  direction: ltr;
  background: var(--bg);
  border-block: 1px solid var(--border);
  padding-block: var(--space-8);
  user-select: none;
  /* Marquee text is decorative — semantic content lives in surrounding
     sections. We expose it for sighted users only. JS sets aria-hidden
     on duplicate spans; the original is screen-reader-readable. */
}

.marquee--cocoa {
  background: var(--cocoa);
  border-color: color-mix(in srgb, var(--brass) 20%, transparent);
}

.marquee--ivory-warm {
  background: var(--bg-alt);
}

.marquee__track {
  display: flex;
  align-items: center;
  /* Force LTR track flow even though the document is dir="rtl". In RTL the flex
     track anchors to the RIGHT, so the 0 → -50% keyframe scrolls the content
     fully off to the left and reveals an empty white gap on the right (the bug
     the user reported). LTR anchors the track left, so -50% wraps onto the
     duplicated half seamlessly. Each .marquee__text still renders its Hebrew
     RTL internally — only the left↔right order of the (decorative) phrases is
     normalised. */
  direction: ltr;
  /* Spacing lives on each item's padding-inline-end (NOT flex `gap`): `gap`
     adds a slot between every item including across the midpoint, so the
     0 → -50% keyframe lands half a gap short of the seamless wrap and the
     loop visibly jumps. Per-item padding makes the duplicated half a
     pixel-exact copy → -50% wraps seamlessly. */
  inline-size: max-content;
  animation: marquee-scroll var(--marquee-duration) linear infinite;
  will-change: transform;
}

/* Hebrew is RTL, so default scroll direction (negative translateX) reads
   content moving from start (right) to end (left) — which feels natural
   for Hebrew copy. data-speed attribute can flip the sign by setting
   --marquee-duration to a negative value via JS — keep the CSS pure. */
@keyframes marquee-scroll {
  from { transform: translateX(0); }
  to   { transform: translateX(-50%); }
}

.marquee__text {
  font-family: var(--font-display-he);
  /* 2026-06-02: dropped from clamp(6rem, 12vw, 14rem) — the previous size
     ate the entire viewport; the user reported a single Hebrew letter
     filling the screen. Tuned to read as a continuous band, not a billboard. */
  font-size: clamp(2rem, 5vw, 4rem);
  font-weight: var(--fw-bold);
  line-height: 1.05;
  color: var(--brass);
  letter-spacing: var(--tracking-tight);
  white-space: nowrap;
  flex-shrink: 0;
  margin: 0;
  padding-inline-end: var(--space-16); /* loop spacing — see .marquee__track */
}

.marquee--cocoa .marquee__text { color: var(--brass); }

/* Latin/numeric variant: switch to luxury Bodoni for English flourishes */
.marquee__text--luxury {
  font-family: var(--font-display-luxury);
  font-weight: 700; /* lightened from 900 with the 2026-06-15 site-wide weight pass */
}

@media (max-width: 767px) {
  .marquee {
    padding-block: var(--space-4);
  }
  .marquee__text {
    font-size: clamp(1.4rem, 5.5vw, 2.4rem);
    padding-inline-end: var(--space-8);
  }
}

/* Reduced motion → stop the scroll, keep the band visible. */
@media (prefers-reduced-motion: reduce) {
  .marquee__track {
    animation: none !important;
  }
}


/* ===========================================================================
   scrollytelling-loader.css — fullscreen loader shown while frame sequences
   decode. Dismissed by js/scrollytelling.js once all canvases hit 100%.
   ========================================================================= */

.scrollytelling-loader {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: var(--ink-deep, #0E0E0C);
  color: var(--ivory, #F5EFE6);
  display: grid;
  place-items: center;
  opacity: 1;
  pointer-events: auto;
  transition: opacity var(--dur-slow) var(--ease-out-cinema);
}

.scrollytelling-loader.is-done {
  opacity: 0;
  pointer-events: none;
}

.scrollytelling-loader__inner {
  display: grid;
  place-items: center;
  gap: var(--space-5, 20px);
  padding: var(--gutter, 24px);
  text-align: center;
}

.scrollytelling-loader__brand {
  font-family: var(--font-display-he, "Frank Ruhl Libre", serif);
  font-weight: 700;
  font-size: clamp(2.5rem, 5vw, 4rem);
  letter-spacing: 0.02em;
  color: var(--brass, #CFAE83);
  margin-block-end: var(--space-3, 12px);
}

.scrollytelling-loader__bar {
  inline-size: clamp(180px, 30vw, 320px);
  block-size: 2px;
  background: color-mix(in srgb, var(--ivory, #F5EFE6) 15%, transparent);
  border-radius: var(--radius-pill);
  overflow: hidden;
  margin-block-end: var(--space-3, 12px);
}

.scrollytelling-loader__fill {
  inline-size: 100%;
  block-size: 100%;
  background: var(--brass, #CFAE83);
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform var(--dur-base) var(--ease-out-cinema);
}

[dir="rtl"] .scrollytelling-loader__fill {
  transform-origin: right center;
}

.scrollytelling-loader__pct {
  font-family: var(--font-body, "Heebo", sans-serif);
  font-size: 0.875rem;
  font-weight: 500;
  letter-spacing: 0.08em;
  color: color-mix(in srgb, var(--ivory, #F5EFE6) 75%, transparent);
  font-variant-numeric: tabular-nums;
}

.scrollytelling-loader__caption {
  font-family: var(--font-display-he, "Frank Ruhl Libre", serif);
  font-size: 0.75rem;
  letter-spacing: 0.16em;
  text-transform: none;
  color: color-mix(in srgb, var(--brass, #CFAE83) 80%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  .scrollytelling-loader {
    transition: none;
  }
  .scrollytelling-loader__fill {
    transition: none;
  }
}

/* =====================================================================
 * texture-text.css — texture-filled headings via background-clip: text
 * Owner: texture-text agent (2026-06-01) · expanded 2026-06-02
 *
 * As of 2026-06-02 the user wants EVERY display-text element (titles,
 * eyebrows — Hebrew AND English) to be filled with the brand texture.
 * To honor that without hand-tagging every element in markup, this
 * stylesheet now does TWO things:
 *
 *   1. The opt-in classes (.texture-text, .texture-text--dark/--light)
 *      keep working — for places that need to override the auto behavior.
 *   2. A site-wide RULE applies the dark-on-ivory texture automatically to:
 *        - .section-header__title
 *        - .section-header__eyebrow
 *        - h2.lounge__title, h3.lounge__title  (lounge labels)
 *        - .hall-* h1/h2 titles
 *      Sections with dark backgrounds get the cream-on-cocoa texture instead.
 *
 * Two textures available (renamed 2026-06-03 to remove the dark/light
 * inversion that was making titles vanish):
 *   --typo-on-light : DARK gold-flecked fill, for headings on LIGHT/ivory bg
 *                     (the dominant case across the site).
 *   --typo-on-dark  : LIGHT cream + gold fill, for headings on DARK bg
 *                     (Hero, Halls, Kosher, Culinary, Footer).
 * Plus the older --texture-{dark,light} aliases for opt-in compatibility.
 *
 * GRACEFUL DEGRADATION: the texture fill lives ENTIRELY inside an
 * @supports block. Browsers without background-clip:text keep the solid
 * token color inherited from base.css — headings stay readable.
 *
 * RTL: background-clip is direction-agnostic.
 * Tokens consumed from css/tokens.css — never hard-code url().
 * ===================================================================== */

@supports ((-webkit-background-clip: text) or (background-clip: text)) {

  /* ---- Shared paint base ----
     2026-06-03: background-size changed to `100% 100%`. The previous
     `auto 280%` over-zoomed the texture: each glyph saw only a tiny crop,
     and if that crop happened to land in a near-bg-luma patch the letter
     vanished. Forcing the texture to fill the heading box exactly means
     every glyph samples the entire texture; combined with luma-clamped
     textures (typo-on-light ≤ 112, typo-on-dark ≥ 153), no letter ever
     blends into ivory or cocoa. */
  .texture-text,
  .texture-text--dark,
  .texture-text--light,
  .section-header__title,
  .lounge__title,
  .rooms__name,
  .feature h3,
  .marquee__text,
  .band__num,
  .about__stat dd,
  .why-gamos__stat dd {
    background-repeat: no-repeat;
    background-size: 100% 100%;
    background-position: center;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }

  /* ---- Default: DARK texture (gold flecks on near-black) for headings on
     light/ivory surfaces — the dominant case across the site.
     Gallery + kosher titles also live on ivory and want the dark fill
     (corrected 2026-06-03 — they were previously forced to the light
     cream texture which disappears on ivory).

     2026-06-08: brightness/contrast/saturate lift removed. The current
     typo-on-light source is calibrated for ivory backgrounds without a
     filter; the lift was flattening the bronze ribbons into uniform gold. */
  .texture-text,
  .texture-text--dark,
  .section-header__title,
  .rooms__name,
  .feature h3,
  .marquee__text,
  .gallery .section-header__title,
  .band__num,
  .about__stat dd,
  .why-gamos__stat dd {
    background-image: var(--typo-on-light);
  }

  /* ---- LIGHT texture override for content on dark surfaces ----
     Sections with cocoa/dark imagery, and the lounge panel titles
     (which sit over dark indoor photography). Eyebrows stay solid brass,
     per impeccable: texture only earns its place at display sizes.
     Footer claim was removed 2026-06-03 — user wants flat ivory text
     there ("בהיר בלבד ללא טקסטורה מאחורה"). ---- */
  [data-bg="dark"] .section-header__title,
  [data-bg="dark"] .band__num,
  .bg-dark .section-header__title,
  .culinary .section-header__title,
  .hero .section-header__title,
  .lounge__title,
  .texture-text--light {
    background-image: var(--typo-on-dark) !important;
  }

  /* These extra titles also need the paint base (background-clip etc.). */
  .culinary .section-header__title,
  .hero .section-header__title,
  .lounge__title {
    background-repeat: no-repeat;
    background-size: 100% 100%;
    background-position: center;
    -webkit-background-clip: text;
    background-clip: text;
    -webkit-text-fill-color: transparent;
    color: transparent;
  }

  /* Dark-bg consumers don't get the brightness lift — the LIGHT texture
     fills are already calibrated for cocoa surfaces. */
  [data-bg="dark"] .section-header__title,
  .bg-dark .section-header__title,
  .culinary .section-header__title,
  .hero .section-header__title,
  .lounge__title,
  .texture-text--light {
    filter: none;
  }

  /* ---- Per-element overrides: legacy `.texture-text--dark/--light`
     classes can also pick the older background-tile textures, in case any
     element wants the surface tile rather than the typo fill. ---- */
  .texture-text--dark.texture-text--bg {
    background-image: var(--texture-dark);
  }
  .texture-text--light.texture-text--bg {
    background-image: var(--texture-light);
  }

  /* ---- Brass solid fallback for tiny text elements that should NOT be
     filled (footer copyright, slider dots, etc.). Opt out via
     `.texture-text--off`. ---- */
  .texture-text--off {
    background: none !important;
    color: var(--brass) !important;
    -webkit-text-fill-color: currentColor !important;
  }
}

/* ===========================================================================
   site-nav-hover.css — Hero hover-reveal mode (2026-06-04)
   ---------------------------------------------------------------------------
   While the user is in the hero (top of page), the site-nav is hidden under
   the WebGL distortion canvas. Cursor entering the top 12vh trigger band
   reveals the bar; leaving hides it. js/site-nav-hover-reveal.js toggles
   `[data-hero-mode]` on <html> while #hero is at viewport-top, and writes
   `[data-nav-revealed]` on <html> based on cursor position.

   When the hero is scrolled past, the bar reverts to its native sticky
   behaviour (no hover-mode at all).
   ========================================================================= */

html[data-hero-mode="true"] .site-nav {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  z-index: 120;            /* above the hero canvas (z-index: 110) */
  transform: translateY(-100%);
  transition: transform var(--dur-base) var(--ease-out-cinema),
              background  var(--dur-base) var(--ease-out-cinema);
  pointer-events: none;
  background: transparent;   /* fully transparent on first reveal */
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-block-end-color: transparent;
  box-shadow: none;
}

html[data-hero-mode="true"][data-nav-revealed="true"] .site-nav {
  transform: translateY(0);
  pointer-events: auto;
  background: color-mix(in srgb, var(--ivory) 92%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  box-shadow: 0 12px 40px -16px rgba(26, 20, 16, 0.45);
}

/* Keyboard-focus reveal (WCAG 2.4.7, a11y pass 2026-07-21).
   In hero-mode the bar is translated off-screen and only the CURSOR band reveals
   it (js/site-nav-hover-reveal.js). A keyboard user tabbing off the skip-link
   lands on nav links that sit at y≈-100% — focused but invisible. `:focus-within`
   pulls the bar on-screen the moment any nav link takes focus, mirroring the
   revealed treatment. Specificity (0,3,1) with :focus-within beats the hidden
   base rule (0,2,1) and ties the revealed rule, and it's later in source order,
   so it wins whenever focus is inside the nav. */
html[data-hero-mode="true"] .site-nav:focus-within {
  transform: translateY(0);
  pointer-events: auto;
  background: color-mix(in srgb, var(--ivory) 92%, transparent);
  backdrop-filter: saturate(140%) blur(12px);
  -webkit-backdrop-filter: saturate(140%) blur(12px);
  box-shadow: 0 12px 40px -16px rgba(26, 20, 16, 0.45);
}

/* Tiny invisible trigger band at the top of the viewport — keeps the bar
   reachable even before the cursor crosses the (hidden) bar's bounding box.
   pointer-events:none on the band itself; the band is just a "tripwire"
   read by the hover-reveal JS via mouseenter coordinates, not by CSS hover.
   But it also needs to NOT block hero canvas pointer events. */
.site-nav-hover-band {
  position: fixed;
  inset-block-start: 0;
  inset-inline: 0;
  height: 14vh;
  z-index: 55;            /* above hero canvas (50), below revealed nav (60) */
  pointer-events: none;
}

/* Touch has no hover entry point: keep navigation above the pinned scene. */
@media (hover: none), (pointer: coarse) {
  html[data-hero-mode="true"] .site-nav,
  html[data-hero-mode="true"][data-nav-revealed="false"] .site-nav {
    transform: none !important;
    opacity: 1 !important;
    pointer-events: auto;
    background: color-mix(in srgb, var(--ivory) 96%, transparent);
  }
}

/* Reduced motion — disable transform, just toggle opacity instantly. */
@media (prefers-reduced-motion: reduce) {
  html[data-hero-mode="true"] .site-nav {
    transition: opacity 0.2s ease;
    transform: none;
    opacity: 0;
  }
  html[data-hero-mode="true"][data-nav-revealed="true"] .site-nav {
    opacity: 1;
  }
  /* Keyboard reveal in the reduced-motion branch: the hidden state here is
     opacity:0 (not a transform), so focus-within must restore opacity +
     pointer-events for the tabbed link to become visible. (a11y 2026-07-21) */
  html[data-hero-mode="true"] .site-nav:focus-within {
    opacity: 1;
    pointer-events: auto;
  }
}

/* ===========================================================================
   lang-toggle.css — HE ⇄ EN language switch button
   ---------------------------------------------------------------------------
   The button is injected by js/i18n.js as the last <li> of .site-nav__links,
   so it appears in the desktop bar AND (via site-nav.js's clone) in the mobile
   overlay. Styling is a small brass pill that reads as a control, not a link.
   Tokens only (§5, §10.2). RTL/LTR agnostic (logical props).
   ========================================================================= */

.site-nav__lang-item {
  display: flex;
  align-items: center;
}

/* Segmented control: globe + [ עב | EN ], active language filled in brass so
   it's unmistakably a language switch and reads as a deliberate, luxe control. */
.site-nav__lang {
  display: inline-flex;
  align-items: center;
  gap: 0.15em;
  padding: 0.22em 0.4em;
  border: 1px solid color-mix(in srgb, var(--brass) 42%, transparent);
  border-radius: 999px;
  background: color-mix(in srgb, var(--ivory) 45%, transparent);
}

.site-nav__lang-globe {
  color: var(--brass-deep);
  margin-inline: 0.15em 0.05em;
  flex: none;
  opacity: 0.9;
}

.site-nav__lang-opt {
  appearance: none;
  cursor: pointer;
  font-family: var(--font-body);
  font-weight: 600;
  font-size: 0.72rem;
  letter-spacing: 0.08em;
  line-height: 1;
  color: var(--brass-deep);
  background: transparent;
  border: 0;
  border-radius: 999px;
  padding: 0.36em 0.62em;
  min-width: 2.1em;
  text-align: center;
  transition: color var(--dur-base, 240ms) var(--ease-out-cinema, ease),
              background-color var(--dur-base, 240ms) var(--ease-out-cinema, ease);
}

.site-nav__lang-opt:not(.is-active):hover {
  color: var(--ink-deep);
}

.site-nav__lang-opt.is-active {
  /* Was --ivory on --brass = 1.83:1 (WCAG AA fail). --ink-deep on --brass is
     8.72:1 and matches the .btn--filled grammar (ink text on the brass anchor).
     a11y pass 2026-07-21. */
  color: var(--ink-deep);
  background: var(--brass);
  cursor: default;
}

.site-nav__lang-opt:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);   /* two-tone ring (a11y pass 2026-07-21) */
}

.site-nav__lang-sep {
  inline-size: 1px;
  block-size: 0.95em;
  background: color-mix(in srgb, var(--brass) 45%, transparent);
  flex: none;
}

/* Mobile overlay clone — larger tap targets, centred among the stacked links. */
.site-nav__mobile .site-nav__lang-item {
  justify-content: center;
}

.site-nav__mobile .site-nav__lang {
  gap: 0.25em;
  padding: 0.3em 0.5em;
}

.site-nav__mobile .site-nav__lang-opt {
  font-size: 0.95rem;
  padding: 0.55em 1em;
  min-width: 2.6em;
}

.site-nav__mobile .site-nav__lang-globe {
  width: 18px;
  height: 18px;
}

/* Review translations follow the selected language. The optional original
   text carries its own lang=he/dir=rtl in the markup. */
html:not([lang="he"]) .testimonial__quote {
  direction: ltr;
  text-align: start;
}

/* The hero title markup hard-codes dir="rtl" (needed for the Hebrew SplitText
   reveal). In any Latin-script language (English or French) the sentence-final
   period must sit at the end, so flip this one block to LTR. Author rule beats
   the UA [dir] rule by specificity. */
html:not([lang="he"]) .hero_title,
html:not([lang="he"]) .hero_title h1 {
  direction: ltr;
}

/* The hero title + eyebrow hard-code "Heebo" in hero-scene.css (they bypass the
   display token), so the token override in tokens.css can't reach them — set
   Canela here so the non-Hebrew (English/French) hero matches the wordmark.
   .hero_word covers the SplitText spans. */
html:not([lang="he"]) .hero_title h1,
html:not([lang="he"]) .hero_title h1 .hero_word,
html:not([lang="he"]) .hero_eyebrow {
  font-family: var(--font-display-en);
}

/* /press/ display headlines hard-code Heebo (var(--font-body)) in press.css, so
   the tokens.css Canela override can't reach them either — restate it here so the
   English/French press page renders its editorial headlines in Canela, matching
   the rest of the site's non-Hebrew display type. Hebrew keeps Heebo (Canela has
   no Hebrew glyphs). */
html:not([lang="he"]) .press-hero__title,
html:not([lang="he"]) .press-intro__sentence,
html:not([lang="he"]) .press-card__title,
html:not([lang="he"]) .press-closer__title {
  font-family: var(--font-display-en);
}

/* #about stats: Latin-script labels (English/French) wrap to different
   line-counts ("GUESTS IN A SINGLE EVENING" = 2 lines, the others = 1), which
   knocks the three numbers off a shared baseline. Reserve two lines for every
   label box and bottom-align the label so the numbers line up. Hebrew labels are
   all one line → scoped to non-Hebrew so Hebrew spacing is untouched. */
html:not([lang="he"]) .about__stat dt {
  min-block-size: 3.2em;      /* fit two lines so 1- and 2-line labels match */
  display: flex;
  align-items: flex-end;
  justify-content: center;
}

/* ===========================================================================
   lounge-lightbox.css — fullscreen viewer for the #lounge ring (2026-06-15)
   ---------------------------------------------------------------------------
   js/lounge-lightbox.js builds this overlay on tap (a tap = pointer barely
   moved; a drag still rotates the ring via lounge-selector.js). Full-viewport
   ink-deep backdrop, image at object-fit:contain, caption (h3 + p) beneath,
   prev/next arrows + close. RTL-first, logical properties, palette from §5
   tokens only (no hard-coded colour/size). Fades via --dur-base/--ease-out-cinema;
   reduced-motion collapses the transition (tokens already ~0ms under RM).
   ========================================================================= */

.lounge-lightbox {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);            /* above sticky nav + overlays */
  display: flex;
  align-items: center;
  justify-content: center;
  padding: clamp(var(--space-4), 5vw, var(--space-12));
  background: color-mix(in srgb, var(--ink-deep) 92%, transparent);
  backdrop-filter: blur(8px) saturate(0.95);
  -webkit-backdrop-filter: blur(8px) saturate(0.95);
  opacity: 0;
  transition: opacity var(--dur-base) var(--ease-out-cinema);
}

.lounge-lightbox.is-open {
  opacity: 1;
}

/* ----- Figure: image + caption stacked ----- */
.lounge-lightbox__figure {
  margin: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-4);
  max-inline-size: min(92vw, 1100px);
  max-block-size: 90vh;
}

.lounge-lightbox__img {
  display: block;
  max-inline-size: 100%;
  /* leave room for the caption beneath within the 90vh figure */
  max-block-size: 74vh;
  inline-size: auto;
  block-size: auto;
  object-fit: contain;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-strong);
  background: var(--bg-cocoa);
  /* gentle zoom-in as the box opens */
  transform: scale(0.98);
  transition: transform var(--dur-slow) var(--ease-out-cinema);
}

.lounge-lightbox.is-open .lounge-lightbox__img {
  transform: scale(1);
}

/* ----- Caption ----- */
.lounge-lightbox__caption {
  text-align: center;
  color: var(--ivory);
  max-inline-size: 60ch;
}

.lounge-lightbox__title {
  font-family: var(--font-display-he);
  font-size: var(--text-xl);
  font-weight: var(--fw-bold);
  margin: 0 0 var(--space-1) 0;
  color: var(--ivory);
}

.lounge-lightbox__desc {
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: var(--lh-normal);
  margin: 0;
  color: color-mix(in srgb, var(--ivory) 85%, transparent);
}

/* ----- Close button (top-inline-end) — minimal glyph, no box -----
   Mirrors .btn--icon (css/components/buttons.css): transparent, no fill/border,
   ≥44px transparent hit area, glyph tints brass + scales on hover. The user
   wanted this minimal on desktop too (no filled brass circle). */
.lounge-lightbox__close {
  position: absolute;
  inset-block-start: clamp(var(--space-2), 3vw, var(--space-5));
  inset-inline-end: clamp(var(--space-2), 3vw, var(--space-5));
  inline-size: 44px;
  block-size: 44px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.6rem;
  line-height: 1;
  color: var(--ivory);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out-cinema),
              transform var(--dur-fast) var(--ease-out-cinema);
}

.lounge-lightbox__close:hover,
.lounge-lightbox__close:focus-visible {
  color: var(--brass);
  transform: scale(1.12);
}
.lounge-lightbox__close:focus-visible {
  outline: 3px solid var(--brass);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ----- Prev / next arrows — minimal glyph, no box (desktop) -----
   No filled circle/border (matches the close button + .btn--icon idiom). The
   arrows sit in the LOWER corners (not dead-centre on the image) so they read as
   quiet affordances; ≥44px transparent hit area; glyph tints brass + scales on
   hover. On mobile these are hidden (swipe replaces them — see mobile/css/lounge.css). */
.lounge-lightbox__nav {
  position: absolute;
  inset-block-end: clamp(var(--space-3), 4vw, var(--space-6));
  inline-size: 44px;
  block-size: 44px;
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--ivory);
  background: transparent;
  border: 0;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out-cinema),
              transform var(--dur-fast) var(--ease-out-cinema);
}

.lounge-lightbox__nav:hover,
.lounge-lightbox__nav:focus-visible {
  color: var(--brass);
}
.lounge-lightbox__nav:focus-visible {
  outline: 3px solid var(--brass);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* Chevron glyph: a small square showing only its top + right PHYSICAL borders,
   rotated so the open corner points toward the button's screen edge. Physical
   borders (not logical) on purpose — logical border-inline-* flips under RTL and
   was rotating the glyph to point DOWN. The buttons sit on fixed screen sides
   (prev = right, next = left) regardless of writing direction, so physical is
   correct here. */
.lounge-lightbox__nav::before {
  content: "";
  inline-size: 9px;
  block-size: 9px;
  border-top: 2px solid currentColor;
  border-right: 2px solid currentColor;
}

/* --prev sits on the RIGHT edge (inline-end in RTL); its chevron points RIGHT. */
.lounge-lightbox__nav--prev {
  inset-inline-end: clamp(var(--space-3), 2.5vw, var(--space-5));
}
.lounge-lightbox__nav--prev::before {
  transform: rotate(45deg);
  margin-inline-start: 3px; /* optical centering of the rotated glyph */
}

/* --next sits on the LEFT edge (inline-start in RTL); its chevron points LEFT. */
.lounge-lightbox__nav--next {
  inset-inline-start: clamp(var(--space-3), 2.5vw, var(--space-5));
}
.lounge-lightbox__nav--next::before {
  transform: rotate(-135deg);
  margin-inline-end: 3px; /* optical centering of the rotated glyph */
}

/* Prev points toward reading start; next toward reading end. */
html[dir="ltr"] .lounge-lightbox__nav--prev { inset-inline-start: var(--space-4); inset-inline-end: auto; }
html[dir="ltr"] .lounge-lightbox__nav--next { inset-inline-end: var(--space-4); inset-inline-start: auto; }
html[dir="ltr"] .lounge-lightbox__nav--prev::before { transform: rotate(-135deg); }
html[dir="ltr"] .lounge-lightbox__nav--next::before { transform: rotate(45deg); }

.lounge-lightbox__nav:hover {
  transform: scale(1.12);
}

@media (prefers-reduced-motion: reduce) {
  .lounge-lightbox,
  .lounge-lightbox__img,
  .lounge-lightbox__close,
  .lounge-lightbox__nav {
    transition: none;
  }
  .lounge-lightbox__img {
    transform: none;
  }
}

/* Narrow viewports: keep the chrome compact + tighten the caption gap. The
   38–40px controls already read fine on phones; no up-sizing (that was the
   "ענקיים" bug). 40px nav meets the comfortable tap floor without dominating. */
@media (max-width: 768px) {
  .lounge-lightbox__figure {
    gap: var(--space-3);
  }
}

/* =====================================================================
 * buttons.css — the ONE canonical button/CTA system (GAMOS-SITE)
 * Owner: unify pass (2026-06-15) · LINE-LANGUAGE rev (2026-06-15)
 *
 * EDITORIAL LANGUAGE — "minimal-editorial chrome" (user decision 2026-06-15):
 * NO boxes, NO borders, NO fills, NO pill radius. Every CTA is TEXT + a brass
 * underline that GROWS on hover — the canonical `.site-nav__links a::after`
 * grammar (css/sections/site-nav.css:142-161), reused verbatim. This reverses
 * the earlier "bordered pill" and the "sharp 0px box" looks; the reference is
 * the original rooms-back link ("plain text + a brass underline that grows on
 * hover, quiet typography, no blur").
 *
 * The roles:
 *   SECONDARY / on light bg   → .btn            (cocoa text, underline grows on hover)
 *   PRIMARY / emphasis        → .btn.btn--filled (thick brass underline AT REST → thickens)
 *   PRIMARY big               → + .btn--primary-lg (larger type/padding)
 *   ON DARK / on image        → .btn.btn--glass  (ivory text + soft shadow, underline grows)
 *   CHIP / editorial tag      → .btn--chip       (small caps + thin underline)
 *   ICON (glyph-only)         → .btn.btn--icon   (no box; glyph tints brass on hover)
 *
 * The underline lives on `::after`. On controls with an inner label span
 * (sub-apps' __label / press __text) the section CSS may hang it on the span
 * instead, but on the main site the CTAs are bare text so it sits on .btn.
 *
 * CASCADE: UNLAYERED + linked AFTER section CSS in index.html → wins ties by
 * source order, zero !important.
 *
 * Tokens only (css/tokens.css §10.2):
 *   --font-body, --brass, --brass-deep, --brass-glow, --cocoa, --ink-deep,
 *   --ivory, --dur-base, --ease-out-cinema, --focus-ring, --tracking-eyebrow,
 *   --radius-sm, --text-xs
 *
 * RTL-safe: transform-origin pinned to `right` (reading-start in RTL), logical
 * insets, inline-flex + gap. Arrow direction handled per-arrow.
 * ===================================================================== */

/* ---- Shared editorial line geometry (base = SECONDARY on light bg) ---- */
.btn {
  position: relative;            /* anchor for the ::after underline */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  padding-block: 0.45em;
  padding-inline: 0;             /* no box — the text IS the target */
  border: 0;
  background: transparent;
  color: var(--cocoa);
  font-family: var(--font-body);
  font-size: 0.8125rem;            /* 13px — editorial label scale */
  font-weight: var(--fw-semibold); /* 500 */
  line-height: 1;
  letter-spacing: var(--tracking-eyebrow);  /* 0.18em — engraved feel */
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: color var(--dur-base) var(--ease-out-cinema);
}

/* The growing brass underline — verbatim the .site-nav link grammar. */
.btn::after {
  content: "";
  position: absolute;
  inset-block-end: 0;
  inset-inline: 0;
  block-size: 1.5px;
  background: var(--brass);
  transform: scaleX(0);
  transform-origin: right center;  /* RTL: grow from the reading start */
  transition: transform var(--dur-base) var(--ease-out-cinema);
}
/* Hover/focus text was --brass-deep = 4.12:1 on ivory — below 4.5 for this
   13px label (a11y pass 2026-07-21). The growing brass underline IS the hover
   affordance, so the text simply stays --cocoa (8.46:1); no color flash needed. */
.btn:hover,
.btn:focus-visible { color: var(--cocoa); }
.btn:hover::after,
.btn:focus-visible::after { transform: scaleX(1); }
.btn:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);   /* two-tone ring (a11y pass 2026-07-21) */
  border-radius: var(--radius-sm);
}

/* ---- Press feedback — the canonical tactile dip every CTA shares. A discrete
   transform is instant (no transition), so it's reduced-motion-safe as-is. ---- */
.btn:active { transform: scale(0.98); }

/* ---- Hebrew labels are not uppercase-able; keep their natural case but
   preserve the wide editorial tracking. Latin-only labels stay uppercase. */
.btn:lang(he),
.btn[lang="he"] { text-transform: none; }

/* ---- Directional arrow (opt-in: wrap the glyph in .btn__arrow). Mirrors
   for RTL and slides outward on hover. ---- */
.btn__arrow {
  display: inline-block;
  font-size: 1.1em;
  line-height: 1;
  unicode-bidi: isolate;
  direction: ltr;
  transition: transform var(--dur-base) var(--ease-out-cinema);
}
[dir="rtl"] .btn__arrow { transform: scaleX(-1); }
.btn:hover .btn__arrow,
.btn:focus-visible .btn__arrow { transform: translateX(4px); }
[dir="rtl"] .btn:hover .btn__arrow,
[dir="rtl"] .btn:focus-visible .btn__arrow { transform: scaleX(-1) translateX(4px); }

/* ---- GLASS: text over dark bg / imagery. Ivory text + a soft shadow for
   legibility (replaces the old scrim+blur box), underline grows on hover. ---- */
.btn--glass {
  color: var(--ivory);
  text-shadow: 0 1px 8px rgba(26, 20, 16, 0.55);  /* readability over imagery */
}
.btn--glass:hover,
.btn--glass:focus-visible { color: var(--brass-glow); }
.btn--glass::after { background: var(--brass-glow); }

/* ---- PRIMARY (filled role → now a thick brass underline shown AT REST).
   Keeps "this is the main action" weight without a box. Thickens on hover. ---- */
.btn--filled { color: var(--ink-deep); }
.btn--filled::after {
  block-size: 2.5px;
  transform: scaleX(1);          /* always visible — anchors the primary CTA */
  transition: block-size var(--dur-base) var(--ease-out-cinema),
              background var(--dur-base) var(--ease-out-cinema);
}
/* Hover text was --brass-deep (4.12:1, fails at 13px). Base is --ink-deep;
   on hover it warms to --cocoa (8.46:1) while the underline thickens+darkens
   to brass-deep — the affordance stays on the line, not the text. (a11y 2026-07-21) */
.btn--filled:hover,
.btn--filled:focus-visible { color: var(--cocoa); }
.btn--filled:hover::after,
.btn--filled:focus-visible::after { block-size: 3.5px; background: var(--brass-deep); }

/* ---- PRIMARY (large emphasis): bigger type for the single most important CTA. ---- */
.btn--primary-lg {
  padding-block: 0.6em;
  font-size: 0.9375rem;            /* 15px */
}

/* ---- Editorial chip / tag (small caps + a thin underline, no box). ---- */
.btn--chip {
  font-size: var(--text-xs);
  letter-spacing: 0.14em;
}
.btn--chip::after { block-size: 1px; }

/* ---- ICON (glyph-only: slider arrows, etc.) — no box. 44px hit-area kept for
   WCAG; the glyph tints brass + nudges on hover, no underline (it's a symbol,
   not a label). ---- */
.btn--icon {
  inline-size: 44px;
  block-size: 44px;
  padding: 0;
  gap: 0;
  color: var(--brass-deep);
  letter-spacing: normal;
  text-transform: none;
  transition: color var(--dur-base) var(--ease-out-cinema),
              transform var(--dur-base) var(--ease-out-cinema);
}
.btn--icon::after { content: none; }   /* no underline under a glyph */
.btn--icon:hover,
.btn--icon:focus-visible {
  color: var(--brass);
  transform: scale(1.12);
}
/* Press dips below the hover-scale (must out-order .btn--icon:hover above). */
.btn--icon:active { transform: scale(1.04); }

/* ---- Reduced motion: show underlines statically (no grow), silence nudges. ---- */
@media (prefers-reduced-motion: reduce) {
  .btn::after,
  .btn:hover::after,
  .btn:focus-visible::after { transition: none; }
  .btn:hover::after,
  .btn:focus-visible::after { transform: scaleX(1); }   /* appear, don't wipe */
  .btn__arrow,
  .btn:hover .btn__arrow,
  .btn:focus-visible .btn__arrow { transition: none; transform: none; }
  [dir="rtl"] .btn__arrow { transform: scaleX(-1); }
  .btn--icon:hover,
  .btn--icon:focus-visible { transform: none; }
}

/* =====================================================================
 * cta-band.css — reusable conversion band (2026-07-13 conversion pass)
 *
 * A slim, centered invitation + the primary/secondary CTA pair, repeated at
 * the persuasion points the marketing critique named: end of #why-gamos and
 * end of #testimonials. Buttons come from the canonical buttons.css
 * line-language — this file only lays them out.
 *
 * Tokens only (§10.2): --font-body, --fw-medium, --fg-muted, --space-*.
 * RTL-safe: flex + gap, logical padding.
 * ===================================================================== */

.cta-band {
  text-align: center;
  padding-block: clamp(2.5rem, 6vw, 4.5rem) clamp(1.5rem, 4vw, 3rem);
  padding-inline: var(--space-4, 1.5rem);
}

.cta-band__lede {
  margin: 0 0 1.4rem;
  font-family: var(--font-body);
  font-weight: var(--fw-medium);
  font-size: clamp(1.05rem, 2vw, 1.35rem);
  color: var(--fg-muted);
  text-wrap: balance;
}

.cta-band__actions {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: clamp(1.5rem, 4vw, 3rem);
  flex-wrap: wrap;
}

/* Give the pair a touch more presence than the base 13px editorial scale. */
.cta-band__actions .btn { font-size: 0.9375rem; }
.cta-band__actions .btn--primary-lg { font-size: 1.0625rem; }

/* =====================================================================
 * media-caption.css — the ONE caption pattern for text over media
 * Owner: unify pass (2026-06-15)
 *
 * Replaces the divergent per-section caption skins (lounge figcaption,
 * culinary item caption) with a single component. The box is an absolutely
 * positioned bottom overlay; the scrim under it comes from the shared
 * --scrim-strong token so legibility is identical everywhere.
 *
 * CONVENTION: captions are ALWAYS VISIBLE (not hover-gated) — keyboard,
 * touch, and AT users must read them without interaction. Sections may add
 * an image hover-zoom as a pure enhancement, but must not gate the caption
 * text behind :hover.
 *
 * Markup:
 *   <figcaption class="media-caption">
 *     <span class="media-caption__tag">…</span>     (optional brass capsule)
 *     <h3 class="media-caption__title">…</h3>
 *     <p  class="media-caption__body">…</p>
 *   </figcaption>
 *
 * Tokens only (css/tokens.css §10.2):
 *   --scrim-strong, --ivory, --fg-on-dark-muted, --brass-glow, --ink-deep,
 *   --font-display-he, --font-body, --fw-bold, --fw-medium, --fw-regular,
 *   --text-lg, --text-sm, --text-xs, --lh-snug, --lh-normal, --space-*,
 *   --radius-pill, --tracking-eyebrow
 *
 * UNLAYERED + linked after section CSS, so it wins ties without !important.
 * RTL: text-align:start + logical padding. Direction-safe.
 * ===================================================================== */

.media-caption {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  gap: var(--space-2);
  padding-block: var(--space-8) var(--space-6);
  padding-inline: var(--space-6);
  background: var(--scrim-strong);
  color: var(--ivory);
  text-align: start;
  pointer-events: none;   /* the caption never eats clicks meant for the card/link */
}

/* Editorial tag label (generalizes the old .culinary__item-tag) — LINE-LANGUAGE
   rev (2026-06-15): no brass capsule box; brass text + a thin brass underline,
   matching the site-wide "text + line" CTA grammar. Sits on dark imagery. */
.media-caption__tag {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: var(--fw-medium);
  letter-spacing: var(--tracking-eyebrow);
  text-transform: uppercase;
  color: var(--brass-glow);
  padding-block: var(--space-1);
  border-block-end: 1.5px solid var(--brass-glow);
  margin: 0;
}

.media-caption__title {
  font-family: var(--font-display-he);
  font-size: var(--text-lg);
  font-weight: var(--fw-bold);
  line-height: var(--lh-snug);
  color: var(--ivory);
  margin: 0;
}

.media-caption__body {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: var(--fw-regular);
  line-height: var(--lh-normal);
  color: var(--fg-on-dark-muted);
  margin: 0;
}

/* =============================================================================
   interaction-hint.css — minimalist brass affordance cue
   ---------------------------------------------------------------------------
   One visual language for "this responds to a gesture" cues (drag a gallery,
   keep scrolling). Matches the site's existing minimalist brass line — the
   hero .gamos-hero__prompt (letter-spaced brass text + thin arrow, NO box):
   just text + a hairline icon in brass, sitting directly on the background.
   No pill, no fill, no backdrop-blur (§1 "Luxury or nothing" = restraint).

   Markup ships the element; js/interaction-hint.js sets [data-dismissed] once
   the gesture happens (drag) or after a short delay (scroll). Self-contained
   keyframes; §10.2 tokens only (no hard-coded hex).

   Host requirement: the cue is position:absolute, so its section/stage must be
   a positioned ancestor. The :where():has() rule below guarantees that for the
   vanilla hosts WITHOUT touching their section CSS (and WITHOUT clobbering an
   existing sticky/relative context — :where() keeps specificity 0).
   ========================================================================== */

:where(#lounge):has(> .ix-hint) { position: relative; }

/* Desktop lounge: the section keeps extra height below the ring, so the base
   inset leaves a ~74px gap under the gallery. Raise the cue toward the gallery
   (a touch). Desktop-only — mobile keeps its own placement (mobile/css). */
@media (min-width: 769px) {
  #lounge > .ix-hint { inset-block-end: clamp(52px, 8.5vh, 92px); }
}

.ix-hint {
  position: absolute;
  left: 50%;
  inset-block-end: clamp(16px, 4vh, 40px);
  transform: translateX(-50%);
  z-index: 40;
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  color: var(--cocoa);           /* readable at small sizes on ivory */
  font-family: Heebo, sans-serif;
  font-weight: 500;
  font-size: clamp(.82rem, 1.02vw, .98rem);
  letter-spacing: .2em;
  white-space: nowrap;
  pointer-events: none;            /* never blocks the gesture it advertises */
  opacity: 0;
  animation: ix-hint-in 900ms cubic-bezier(.16, 1, .3, 1) 600ms forwards;
  transition: opacity 600ms ease, transform 600ms ease;
}

/* On dark sections (#culinary), the deep brass would sink into the background —
   step up to the lighter primary brass, matching the site's dark-surface text. */
.ix-hint--on-dark { color: var(--brass); }

.ix-hint__icon { display: inline-flex; inline-size: 1.1em; block-size: 1.1em; }
.ix-hint__icon svg {
  inline-size: 100%; block-size: 100%;
  stroke: currentColor; fill: none;      /* follows the cue's brass colour */
  stroke-width: 1.5; stroke-linecap: round; stroke-linejoin: round;
}

/* 2026-10-11 (gesture language v2): every cue icon is the site's one hand
   (Material "touch_app", same as css/components/gesture-hint.css) — filled. */
.ix-hint__icon svg.ix-hand { fill: currentColor; stroke: none; }
.ix-hint__icon:has(.ix-hand) { inline-size: 1.35em; block-size: 1.35em; }
.ix-hint--scroll .ix-hint__icon:has(.ix-hand) { animation-name: ix-hint-rise; }
@keyframes ix-hint-rise { 0%, 100% { transform: translateY(2px); } 50% { transform: translateY(-4px); } }

/* Drag → icon sways left↔right (⟷). Scroll → icon bobs downward.
   Tap → icon breathes (concentric circles pulse). */
.ix-hint--drag   .ix-hint__icon { animation: ix-hint-sway 2200ms ease-in-out 1600ms infinite; }
.ix-hint--scroll .ix-hint__icon { animation: ix-hint-bob  2000ms ease-in-out 1400ms infinite; }
.ix-hint--tap    .ix-hint__icon { animation: ix-hint-tap  2200ms ease-in-out 1600ms infinite; }
.ix-hint__text { opacity: 1; } /* The icon animates; instruction text stays readable. */

/* Static-flow placement (2026-07-13, #gallery): sits in normal flow between the
   section header and the grid — the absolute bottom-center grammar would land
   on the photos. Own entry keyframes (no translateX(-50%)). */
.ix-hint--static {
  position: static;
  display: flex;
  justify-content: center;
  transform: none;
  animation-name: ix-hint-in-static;
}
.ix-hint--static[data-dismissed] {
  animation: none;
  transform: translateY(10px);
}

/* Dismissed after first gesture / timeout → fade up and out. animation:none
   cancels the forwards fill of ix-hint-in so the opacity:0 + transition apply. */
.ix-hint[data-dismissed] {
  animation: none;
  opacity: 0;
  transform: translateX(-50%) translateY(10px);
}

@keyframes ix-hint-in    { from { opacity: 0; transform: translateX(-50%) translateY(10px); } to { opacity: 1; transform: translateX(-50%) translateY(0); } }
@keyframes ix-hint-in-static { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
@keyframes ix-hint-sway  { 0%, 100% { transform: translateX(-3px); } 50% { transform: translateX(3px); } }
@keyframes ix-hint-bob   { 0%, 100% { transform: translateY(0); }    50% { transform: translateY(4px); } }
@keyframes ix-hint-tap   { 0%, 100% { transform: scale(1); }          50% { transform: scale(1.15); } }
@keyframes ix-hint-pulse { 0%, 100% { opacity: 1; }                  50% { opacity: .6; } }

/* §8/§9 — reduced motion: cue is shown static, all loops frozen.
   js/interaction-hint.js also skips the auto-fade timer so scroll cues stay. */
@media (prefers-reduced-motion: reduce) {
  .ix-hint { animation: none; opacity: 1; }
  .ix-hint__icon, .ix-hint__text { animation: none; }
}

/* =============================================================================
   gesture-hint.css — the site's ONE gesture language (2026-10-11, v2)
   ---------------------------------------------------------------------------
   Research basis: PLANS/next-steps/2026-10-11_coach-marks.md.
   One hand, one touch point, one label, one rhythm (2.4s loop) for every
   gesture: tap · swipe-x · swipe-up · pinch (desktop scrolling
   is shown as swipe-up too — Moshe: one hand everywhere, no mouse icon).

   The hint sits ON the element it teaches (local scrim, not a page blackout),
   and the element's own content moves in sync with the hand ("hint motion"):
   put .gh-move on the content to nudge. The nudge uses the individual
   translate/scale properties, so it composes with any transform a module
   already sets on that element.

     <div class="… gh-host" data-gh="swipe-x" data-gh-on>
       <div class="… gh-move">…content…</div>
       <div class="gh" aria-hidden="true">…built by JS / markup…</div>
     </div>

   Direction: swipes travel toward "next" — left→right in RTL, right→left in
   LTR (--gh-dir).
   ========================================================================== */

.gh-host {
  --gh-ink: var(--ink-deep);
  --gh-ivory: var(--ivory);
  --gh-brass: var(--brass);
  --gh-cocoa: var(--cocoa);
  --gh-font: var(--font-body);
  --gh-loop: 2.4s;
  --gh-dir: 1;
  /* JS adds position:relative only when the host is static (masonry items
     etc. keep their own positioning). */
}
[dir="ltr"] .gh-host, .gh-host[dir="ltr"] { --gh-dir: -1; }

/* Local scrim — dims only the taught element, content stays visible. A real
   element (not ::after) so section pseudo-elements never collide with it. */
.gh-scrim {
  position: absolute;
  inset: 0;
  z-index: 1100;            /* above Leaflet panes/controls; local thanks to isolation */
  border-radius: inherit;
  /* Warm spotlight centred on the hand (--gh-x/--gh-y set by JS): dark enough
     around the hand for the ivory hand to read, lighter toward the edges so a
     large ivory section does not turn muddy. */
  background: radial-gradient(circle at var(--gh-x, 50%) var(--gh-y, 50%),
    color-mix(in srgb, var(--gh-ink) 62%, transparent) 0,
    color-mix(in srgb, var(--gh-cocoa) 52%, transparent) clamp(120px, 22vmax, 340px),
    color-mix(in srgb, var(--gh-cocoa) 30%, transparent) 100%);
  opacity: 0;
  pointer-events: none;
  transition: opacity 500ms ease;
}
.gh-host[data-gh-on] > .gh-scrim { opacity: 1; }
.gh-host:has(> .gh-scrim) { isolation: isolate; }
/* The big hint replaces the small resting cue while it plays. */
.gh-host[data-gh-on] .ix-hint { visibility: hidden; } /* its entry animation pins opacity */

.gh {
  position: absolute;
  inset: 0;
  z-index: 1101;
  display: grid;
  place-items: center;
  pointer-events: none;   /* the real gesture goes through to the element */
  opacity: 0;
  transition: opacity 500ms ease;
}
.gh-host[data-gh-on] > .gh { opacity: 1; }

.gh__stage {
  position: relative;
  inline-size: 132px;
  block-size: 132px;
  direction: ltr;          /* geometry only; mirroring is done by --gh-dir */
}
.gh__stage > * { position: absolute; }
@media (min-width: 1024px) {
  .gh__stage { scale: 1.3; }
  .gh__label { inset-block-start: calc(50% + 100px); }
}

/* Touch point: brass disc + soft halo. Centre of the stage = fingertip. */
.gh__touch, .gh__touch2 {
  inset-block-start: calc(50% - 14px);
  inset-inline-start: calc(50% - 14px);
  inline-size: 28px;
  block-size: 28px;
  border-radius: 50%;
  background: color-mix(in srgb, var(--gh-brass) 70%, transparent);
  box-shadow: 0 0 0 2px var(--gh-ivory), 0 0 0 8px color-mix(in srgb, var(--gh-brass) 30%, transparent);
  opacity: 0;
}
.gh__touch2 { display: none; }

/* Ripple (tap) */
.gh__ring {
  inset-block-start: calc(50% - 14px);
  inset-inline-start: calc(50% - 14px);
  inline-size: 28px;
  block-size: 28px;
  border-radius: 50%;
  border: 2px solid var(--gh-brass);
  opacity: 0;
}

/* Trail (swipes): a brass line drawn along the path behind the finger. */
.gh__trail {
  inset-block-start: calc(50% - 2px);
  inset-inline-start: 50%;
  inline-size: 64px;
  block-size: 4px;
  border-radius: 2px;
  background: linear-gradient(to right, transparent, var(--gh-brass));
  transform-origin: 0 50%;
  opacity: 0;
}

/* Hand: filled ivory (Material "touch_app" hand, Apache-2.0). The fingertip
   sits on the stage centre; the palm hangs below-right of it. */
.gh__hand {
  inset-block-start: calc(50% - 24px);   /* fingertip (11.5,6)/24 of 96px */
  inset-inline-start: calc(50% - 46px);
  inline-size: 96px;
  block-size: 96px;
  fill: var(--gh-ivory);
  stroke: color-mix(in srgb, var(--gh-ink) 55%, transparent);
  stroke-width: .5;
  filter: drop-shadow(0 8px 16px color-mix(in srgb, var(--gh-ink) 55%, transparent));
}

.gh__label {
  /* Always just under the hand; may be wider than a small anchor (a gallery
     tile) — it sits in the host, not inside the tile. */
  position: absolute;
  inset-block-start: calc(50% + 78px);
  left: 50%;
  translate: -50% 0;
  margin: 0;
  inline-size: max-content;
  max-inline-size: min(86vw, 26em);
  padding: .55em 1.15em;
  border-radius: 999px;
  background: color-mix(in srgb, var(--gh-ink) 78%, transparent);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--gh-brass) 55%, transparent);
  color: var(--gh-ivory);
  font-family: var(--gh-font);
  font-weight: 500;
  font-size: clamp(.92rem, 1.4vw, 1.05rem);
  line-height: 1.4;
  letter-spacing: .03em;
  text-align: center;
}

/* On-demand message (map cooperative gestures): label only, centred. */
.gh--message .gh__label { position: static; translate: none; }

/* ── Rhythm ──────────────────────────────────────────────────────────────
   Every gesture: 0–12% approach · 18% touch down · 18–62% act · 68% lift ·
   80–100% rest. Same easing everywhere.                                    */
.gh-host[data-gh-on] .gh__stage *,
.gh-host[data-gh-on] .gh-move {
  animation-duration: var(--gh-loop);
  animation-iteration-count: var(--gh-loops, infinite);
  animation-timing-function: cubic-bezier(.45, 0, .25, 1);
  animation-fill-mode: both;
}

/* swipe-x */
.gh-host[data-gh="swipe-x"][data-gh-on] .gh__hand  { animation-name: gh-hand-x; }
.gh-host[data-gh="swipe-x"][data-gh-on] .gh__touch { animation-name: gh-touch-x; }
.gh-host[data-gh="swipe-x"][data-gh-on] .gh__trail { animation-name: gh-trail-x; }
.gh-host[data-gh="swipe-x"][data-gh-on] .gh-move   { animation-name: gh-move-x; }
@keyframes gh-hand-x {
  0%   { opacity: 0; transform: translateX(calc(var(--gh-dir) * -40px)) scale(1.08); }
  12%  { opacity: 1; transform: translateX(calc(var(--gh-dir) * -40px)) scale(1.08); }
  18%  { transform: translateX(calc(var(--gh-dir) * -40px)) scale(.94); }
  62%  { transform: translateX(calc(var(--gh-dir) * 40px)) scale(.94); }
  68%  { opacity: 1; transform: translateX(calc(var(--gh-dir) * 40px)) scale(1.06); }
  80%, 100% { opacity: 0; transform: translateX(calc(var(--gh-dir) * 40px)) scale(1.06); }
}
@keyframes gh-touch-x {
  0%, 16% { opacity: 0; transform: translateX(calc(var(--gh-dir) * -40px)) scale(.4); }
  18%  { opacity: 1; transform: translateX(calc(var(--gh-dir) * -40px)) scale(1); }
  62%  { opacity: 1; transform: translateX(calc(var(--gh-dir) * 40px)) scale(1); }
  70%, 100% { opacity: 0; transform: translateX(calc(var(--gh-dir) * 40px)) scale(1.6); }
}
@keyframes gh-trail-x {
  0%, 18% { opacity: 0; transform: translateX(calc(var(--gh-dir) * -40px)) scaleX(calc(var(--gh-dir) * 0)); }
  62%  { opacity: .9; transform: translateX(calc(var(--gh-dir) * -40px)) scaleX(calc(var(--gh-dir) * 1.25)); }
  76%, 100% { opacity: 0; transform: translateX(calc(var(--gh-dir) * -40px)) scaleX(calc(var(--gh-dir) * 1.25)); }
}
@keyframes gh-move-x {
  0%, 18% { translate: 0 0; }
  62% { translate: calc(var(--gh-dir) * 36px) 0; }
  86%, 100% { translate: 0 0; }
}

/* swipe-up */
.gh-host[data-gh="swipe-up"][data-gh-on] .gh__hand  { animation-name: gh-hand-y; }
.gh-host[data-gh="swipe-up"][data-gh-on] .gh__touch { animation-name: gh-touch-y; }
.gh-host[data-gh="swipe-up"][data-gh-on] .gh__trail { animation-name: gh-trail-y; }
.gh-host[data-gh="swipe-up"][data-gh-on] .gh-move   { animation-name: gh-move-y; }
.gh-host[data-gh="swipe-up"] .gh__trail {
  inset-inline-start: calc(50% - 2px);
  inset-block-start: 50%;
  inline-size: 4px;
  block-size: 64px;
  background: linear-gradient(to top, transparent, var(--gh-brass));
  transform-origin: 50% 0;
}
@keyframes gh-hand-y {
  0%   { opacity: 0; transform: translateY(36px) scale(1.08); }
  12%  { opacity: 1; transform: translateY(36px) scale(1.08); }
  18%  { transform: translateY(36px) scale(.94); }
  62%  { transform: translateY(-36px) scale(.94); }
  68%  { opacity: 1; transform: translateY(-36px) scale(1.06); }
  80%, 100% { opacity: 0; transform: translateY(-36px) scale(1.06); }
}
@keyframes gh-touch-y {
  0%, 16% { opacity: 0; transform: translateY(36px) scale(.4); }
  18%  { opacity: 1; transform: translateY(36px) scale(1); }
  62%  { opacity: 1; transform: translateY(-36px) scale(1); }
  70%, 100% { opacity: 0; transform: translateY(-36px) scale(1.6); }
}
@keyframes gh-trail-y {
  0%, 18% { opacity: 0; transform: translateY(-36px) scaleY(0); }
  62%  { opacity: .9; transform: translateY(-36px) scaleY(1.1); }
  76%, 100% { opacity: 0; transform: translateY(-36px) scaleY(1.1); }
}
@keyframes gh-move-y {
  0%, 18% { translate: 0 0; }
  62% { translate: 0 -32px; }
  86%, 100% { translate: 0 0; }
}

/* tap */
.gh-host[data-gh="tap"][data-gh-on] .gh__hand  { animation-name: gh-hand-tap; }
.gh-host[data-gh="tap"][data-gh-on] .gh__touch { animation-name: gh-touch-tap; }
.gh-host[data-gh="tap"][data-gh-on] .gh__ring  { animation-name: gh-ring-tap; }
.gh-host[data-gh="tap"][data-gh-on] .gh-move   { animation-name: gh-move-tap; }
@keyframes gh-hand-tap {
  0%   { opacity: 0; transform: translate(14px, 18px) scale(1.08); }
  14%  { opacity: 1; transform: translate(0, 0) scale(1.08); }
  24%  { transform: scale(.9); }
  34%  { transform: scale(1.04); }
  70%  { opacity: 1; transform: scale(1.04); }
  82%, 100% { opacity: 0; transform: scale(1.04); }
}
@keyframes gh-touch-tap {
  0%, 22% { opacity: 0; transform: scale(.4); }
  26%  { opacity: 1; transform: scale(1); }
  40%, 100% { opacity: 0; transform: scale(1.2); }
}
@keyframes gh-ring-tap {
  0%, 24% { opacity: 0; transform: scale(.6); }
  30%  { opacity: 1; }
  62%, 100% { opacity: 0; transform: scale(3.2); }
}
@keyframes gh-move-tap {
  0%, 22% { scale: 1; }
  28% { scale: .975; }
  40%, 100% { scale: 1; }
}

/* pinch — two touch points open apart; the content zooms with them */
.gh-host[data-gh="pinch"] .gh__hand { display: none; }
.gh-host[data-gh="pinch"] .gh__touch2 { display: block; }
.gh-host[data-gh="pinch"][data-gh-on] .gh__touch  { animation-name: gh-pinch-a; }
.gh-host[data-gh="pinch"][data-gh-on] .gh__touch2 { animation-name: gh-pinch-b; }
.gh-host[data-gh="pinch"][data-gh-on] .gh-move    { animation-name: gh-move-pinch; }
@keyframes gh-pinch-a {
  0%, 10% { opacity: 0; transform: translate(-10px, 10px) scale(.4); }
  18%  { opacity: 1; transform: translate(-10px, 10px) scale(1); }
  62%  { opacity: 1; transform: translate(-44px, 44px) scale(1); }
  72%, 100% { opacity: 0; transform: translate(-44px, 44px) scale(1.5); }
}
@keyframes gh-pinch-b {
  0%, 10% { opacity: 0; transform: translate(10px, -10px) scale(.4); }
  18%  { opacity: 1; transform: translate(10px, -10px) scale(1); }
  62%  { opacity: 1; transform: translate(44px, -44px) scale(1); }
  72%, 100% { opacity: 0; transform: translate(44px, -44px) scale(1.5); }
}
@keyframes gh-move-pinch {
  0%, 18% { scale: 1; }
  62% { scale: 1.12; }
  86%, 100% { scale: 1; }
}

/* §8 — reduced motion: the same picture, frozen at "finger down". */
@media (prefers-reduced-motion: reduce) {
  .gh-host[data-gh-on] .gh__stage *,
  .gh-host[data-gh-on] .gh-move { animation: none !important; }
  .gh-host .gh__hand, .gh-host .gh__touch, .gh-host .gh__touch2 { opacity: 1; }
  .gh-host[data-gh="pinch"] .gh__touch  { transform: translate(-30px, 30px); }
  .gh-host[data-gh="pinch"] .gh__touch2 { transform: translate(30px, -30px); }
}

/* ===========================================================================
   a11y-widget.css — floating accessibility menu + the effects it switches on
   ---------------------------------------------------------------------------
   Markup injected by js/a11y-widget.js. Each option is a data-a11y-* attribute
   on <html>; the rules at the bottom of this file are the effects.
   Corner is PHYSICAL bottom-left by request (the right edge holds the side-dot
   nav) — same reasoning as side-dot-nav.css locking to `right`.
   Phone placement (above the CTA bar) lives in mobile/css/a11y-widget.css (§13).
   ========================================================================= */

.a11y-widget {
  position: fixed;
  left: 24px;
  bottom: 24px;
  z-index: 125; /* above hero (110/111) + mobile bars (120), below nav overlay (130+) and lightboxes */
  font-family: var(--font-body);
}

.a11y-widget__fab {
  display: grid;
  place-items: center;
  inline-size: 52px;
  block-size: 52px;
  padding: 0;
  border: 1px solid var(--brass);
  border-radius: var(--radius-circle);
  background: var(--ink-deep);
  color: var(--brass);
  box-shadow: var(--shadow-strong);
  cursor: pointer;
  transition: transform var(--dur-base) var(--ease-out-cinema),
              background-color var(--dur-base) var(--ease-out-cinema);
}

.a11y-widget__fab:hover,
.a11y-widget__fab[aria-expanded="true"] {
  background: var(--cocoa);
  transform: scale(1.06);
}

.a11y-widget button:focus-visible,
.a11y-widget a:focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
}

.a11y-widget__panel {
  position: absolute;
  left: 0;
  bottom: calc(100% + 12px);
  inline-size: min(320px, calc(100vw - 32px));
  max-block-size: calc(100vh - 120px);
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 1.1rem;
  background: var(--ivory);
  color: var(--ink-deep);
  border: 1px solid var(--brass);
  box-shadow: var(--shadow-strong);
}

.a11y-widget__panel[hidden] { display: none; }

.a11y-widget__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  padding-block-end: 0.75rem;
  margin-block-end: 0.85rem;
  border-block-end: 1px solid var(--border-strong);
}

.a11y-widget__title {
  margin: 0;
  font-family: var(--font-display-he);
  font-size: 1.15rem;
  font-weight: var(--fw-bold);
  letter-spacing: 0.02em;
  color: var(--ink-deep);
}

.a11y-widget__close,
.a11y-widget__step {
  display: grid;
  place-items: center;
  inline-size: 44px;
  block-size: 44px;
  padding: 0;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-btn);
  background: transparent;
  color: var(--ink-deep);
  font: inherit;
  font-size: 1.25rem;
  line-height: 1;
  cursor: pointer;
}

.a11y-widget__step:disabled {
  opacity: 0.35;
  cursor: default;
}

.a11y-widget__row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-block-end: 0.85rem;
  font-size: var(--text-sm);
  font-weight: var(--fw-semibold);
}

.a11y-widget__stepper {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.a11y-widget__value {
  min-inline-size: 3.6em;
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.a11y-widget__grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0.5rem;
}

.a11y-widget__opt {
  min-block-size: 48px;
  padding: 0.55rem 0.6rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-btn);
  background: transparent;
  color: var(--ink-deep);
  font: inherit;
  font-size: var(--text-sm);
  font-weight: var(--fw-semibold);
  line-height: 1.25;
  text-align: center;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out-cinema),
              border-color var(--dur-fast) var(--ease-out-cinema);
}

.a11y-widget__opt:hover { border-color: var(--brass-deep); }

/* Active = brass fill + ink text (8.72:1, same grammar as .btn--filled). */
.a11y-widget__opt[aria-pressed="true"] {
  background: var(--brass);
  border-color: var(--brass-deep);
}

.a11y-widget__foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  margin-block-start: 0.95rem;
  padding-block-start: 0.85rem;
  border-block-start: 1px solid var(--border-strong);
  font-size: var(--text-sm);
}

.a11y-widget__reset {
  min-block-size: 44px;
  padding: 0 0.9rem;
  border: 1px solid var(--ink-deep);
  border-radius: var(--radius-btn);
  background: var(--ink-deep);
  color: var(--ivory);
  font: inherit;
  font-weight: var(--fw-semibold);
  cursor: pointer;
}

.a11y-widget__link {
  display: inline-flex;
  align-items: center;
  min-block-size: 44px;
  color: var(--ink-deep);
  text-decoration: underline;
  text-underline-offset: 0.2em;
}

/* --- Effects ------------------------------------------------------------- */

/* Text size: 112.5% … 150% of the root (base.css locks it at 16px). */
html[data-a11y-text="1"] { font-size: 112.5%; }
html[data-a11y-text="2"] { font-size: 125%; }
html[data-a11y-text="3"] { font-size: 137.5%; }
html[data-a11y-text="4"] { font-size: 150%; }

/* Contrast + grayscale compose into one root filter. A filter on the ROOT
   element does not make it a containing block, so fixed bars stay pinned. */
html[data-a11y-contrast] { --a11y-filter-contrast: contrast(1.6); }
html[data-a11y-gray]     { --a11y-filter-gray: grayscale(1); }
html[data-a11y-contrast],
html[data-a11y-gray] {
  filter: var(--a11y-filter-contrast, ) var(--a11y-filter-gray, );
}

html[data-a11y-links] a[href] {
  text-decoration: underline !important;
  text-underline-offset: 0.2em;
  outline: 2px solid var(--brass-deep);
  outline-offset: 2px;
}

/* Readable font: everything in the body sans (Heebo), normal tracking. */
html[data-a11y-font] body,
html[data-a11y-font] body * {
  font-family: var(--font-body) !important;
  letter-spacing: normal !important;
}

/* Stop animations: same reset as prefers-reduced-motion — finish instantly. */
html[data-a11y-still] {
  --dur-fast: 0.01ms;
  --dur-base: 0.01ms;
  --dur-slow: 0.01ms;
  --dur-deluxe: 0.01ms;
  --dur-cinema: 0.01ms;
}
html[data-a11y-still] *,
html[data-a11y-still] *::before,
html[data-a11y-still] *::after {
  animation-duration: 0.01ms !important;
  animation-iteration-count: 1 !important;
  transition-duration: 0.01ms !important;
  scroll-behavior: auto !important;
}

/* Large cursor. Data-URI SVG can't read tokens: fill = --ink-deep, stroke = --ivory. */
html[data-a11y-cursor],
html[data-a11y-cursor] * {
  cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='48' height='48' viewBox='0 0 48 48'%3E%3Cpath d='M6 4l30 18-13 3 8 15-6 3-8-15-11 9z' fill='%231A1410' stroke='%23F5EFE6' stroke-width='2.5' stroke-linejoin='round'/%3E%3C/svg%3E") 6 4, auto !important;
}
