/* ===== tokens ===== */
:root {
  /* ===== palette =====
     Two golds on purpose: #c9a961 on the cream ground measures 1.93:1, which is
     unreadable. Anything that says "tap here" on a light section uses the darker
     one; the bright gold stays for dark grounds and for the fill of a solid
     button (dark text on gold = 8.8:1). tools/check-design.mjs enforces it. */
  --ink-0: #0a0a0b;
  --ink-1: #121213;
  --paper-0: #f4efe7;
  --paper-1: #ece5d9;
  --gold-on-paper: #7d6229;
  --text-on-ink: #f5f2ed;
  --text-on-ink-2: #a8a49d;
  --text-on-paper: #1a1815;
  --text-on-paper-2: #5c564d;

  /* ===== type scale =====
     Bigger is tighter, the way Apple's display type runs. The tracking applies to
     display sizes only: Hebrew has no capitals and no ascender rhythm to tighten
     against, so squeezing it at reading size only crowds it. --measure is a measure
     of line length, so it lives here with the type rather than with the spacing. */
  --step-hero: clamp(2.75rem, 8vw, 5.5rem);
  --step-h2: clamp(2rem, 5.5vw, 3.5rem);
  --step-h3: clamp(1.375rem, 3vw, 1.75rem);
  --step-lead: clamp(1.125rem, 2.2vw, 1.5rem);
  --step-body: 1.0625rem;
  --step-title-sm: clamp(1.75rem, 3vw, 2.25rem); /* a heading inside a tile */
  --step-h2-col: clamp(2rem, 3.8vw, 3rem); /* a section heading that shares its row with a photograph */
  /* The hero's camera move: how far it pushes in on the hair, how long one way takes, and
     the point it closes in on (the hair, which sits right of centre in the wide clip). */
  --hero-zoom: 1.35; --hero-zoom-time: 7s; --hero-zoom-origin: 50% 40%;
  --step-small: .9375rem;
  --track-display: -.015em;
  --measure: 680px;

  /* ===== spacing =====
     One scale on an 8px base. Section padding is fluid so a phone is not asked
     to carry desktop air; Apple's own tiles sit at 96px at desktop width. */
  --sp-1: 8px; --sp-2: 16px; --sp-3: 24px; --sp-4: 32px;
  --sp-5: 48px; --sp-6: 64px; --sp-7: 96px; --sp-8: 128px;
  --section-y: clamp(72px, 10vw, 120px);

  /* ===== motion =====
     --ease is Apple's own curve, read off apple.com. Three durations, because
     one duration for everything is what makes a page feel machine-made: a press
     answers instantly, a hover is quick, a section arriving is unhurried. */
  --ease: cubic-bezier(0.28, 0.11, 0.32, 1);
  --dur-micro: 180ms;
  --dur-ui: 280ms;
  --dur-scene: 600ms;
  --stagger-rise: 12px;
  --stagger-step: 60ms;

  --gold: #c9a961;
  --gold-soft: rgba(201, 169, 97, .35);
  --gold-line: rgba(201, 169, 97, .18);
  --gold-ring: rgba(201, 169, 97, .55);
  /* Pointing at an image lifts its frame and grows the photo inside it. Both the hover
     and the keyboard-focus rules read these, so the strength is tuned in one place —
     and prefers-reduced-motion flattens the whole effect by zeroing the two below. */
  --hl-lift: -6px;
  --hl-zoom: 1.06;
  --hl-shadow: none; /* cards and tiles carry no shadow; --shadow-photo is the site's only one */
  --shadow-photo: 0 3px 30px rgba(0, 0, 0, .22);
  --hl-ease: transform var(--dur-ui) var(--ease), box-shadow var(--dur-ui) var(--ease), border-color var(--dur-ui) var(--ease), opacity var(--dur-ui) var(--ease);
  --gold-hover: #d8b976;
  /* One text family, the way Apple runs SF: hierarchy comes from weight, not
     from switching faces. Assistant is the Hebrew companion to Source Sans —
     the nearest thing to SF that actually ships Hebrew (Inter does not).
     Playfair is the logo's voice and appears only in the wordmark. */
  --font-mark: "Playfair Display", Georgia, "Times New Roman", serif;
  --font-head: "Assistant", "Helvetica Neue", Arial, sans-serif;
  --font-body: "Assistant", "Helvetica Neue", Arial, sans-serif;
  --track-h3: -.01em;
  --container: 1240px;
  --pad: clamp(16px, 5vw, 40px);
  --radius: 18px;
  /* one focus treatment for the whole site; the 2px/3px offsets were never a decision */
  --focus-ring: 2px solid var(--gold);
  --focus-offset: 3px;
  --radius-sm: 4px;
  --reel-w: clamp(220px, 21vw, 300px); --reel-w-phone: min(72vw, var(--card-w)); /* video rail cards */
  --tap: 44px;
  --tile-max: 880px; --map-min: 320px; /* the contact tile */
  --tile-w: clamp(200px, 22vw, 300px); --tile-w-phone: min(62vw, 260px); /* gallery tiles */
  --shot-ratio: 900 / 931; /* the testimonial screenshots' own shape */
  --card-min: 200px; --card-w: 320px; /* proof cards: the clip and every screenshot share this */
}

/* ===== base ===== */
*, *::before, *::after { box-sizing: border-box; }
html { scroll-behavior: smooth; -webkit-text-size-adjust: 100%; }
body { margin: 0; background: var(--ink-0); color: var(--paper-0); font-family: var(--font-body); font-weight: 400; font-size: var(--step-body); line-height: 1.5; overflow-x: hidden; }
img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
h1, h2, h3 { font-family: var(--font-head); font-weight: 600; line-height: 1.1; letter-spacing: var(--track-display); margin: 0; }
h3 { letter-spacing: var(--track-h3); }
p { margin: 0; }
.skip { position: absolute; top: -48px; right: 8px; background: var(--gold); color: var(--ink-0); padding: 8px 12px; z-index: 100; border-radius: 6px; }
.skip:focus { top: 8px; }
.container { width: min(100% - 2 * var(--pad), var(--container)); margin-inline: auto; }
.wordmark { font-family: var(--font-mark); font-weight: 500; letter-spacing: .18em; text-transform: uppercase; direction: ltr; unicode-bidi: isolate; }
.wordmark--sm { font-size: 1rem; letter-spacing: .2em; }
/* Hebrew has no capitals, so it reads small beside an uppercased Latin wordmark.
   HIG, Right to Left: balance the two by growing the Hebrew side. */
.footer__year { font-size: 1.08em; }

/* ===== buttons ===== */
.btn { display: inline-flex; align-items: center; justify-content: center; gap: .5em; padding: 14px 28px; border-radius: 999px; font-family: var(--font-body); font-weight: 500; font-size: var(--step-body); letter-spacing: .02em; border: 1px solid transparent; transition: transform var(--dur-micro) var(--ease), background var(--dur-micro) var(--ease), color var(--dur-micro) var(--ease), border-color var(--dur-micro) var(--ease); }
.btn:hover { transform: translateY(-2px); }
.btn--wa { background: var(--gold); color: var(--ink-0); }
.btn--wa:hover { background: var(--gold-hover); }
.btn--big { padding: 18px 40px; font-size: 1.1rem; }
.btn--gold { background: var(--gold); color: var(--ink-0); border-color: var(--gold); }
.btn--gold:hover { background: var(--gold-hover); border-color: var(--gold-hover); }

/* ===== hero =====
   One picture in two layers, on every screen: a still paints first (it is preloaded),
   and the clip it was taken from plays above it. The two fill the same box with the
   same crop, so the hand-over from one to the other moves nothing. The scrim sits
   above both and the logo on top. The phone gets the tall pair, the desktop the wide. */
.hero { position: relative; background: var(--ink-0); text-align: center; isolation: isolate; display: block; min-height: 100svh; }
.hero__media { position: absolute; inset: 0; height: 100%; line-height: 0; overflow: hidden; }
/* The camera's move. The clips themselves are locked off, because a clip whose camera
   travels snaps back to its start every time it loops. So the slow push-in on the hair is
   made here instead, on the one element that holds both layers: in, and back out as
   slowly, without end. It never has to jump back, and the still and the clip never part. */
.hero__shot { position: absolute; inset: 0; transform-origin: var(--hero-zoom-origin); }
@media (min-width: 820px) { .hero__shot { --hero-zoom: 1.24; --hero-zoom-time: 9s; --hero-zoom-origin: 58% 45%; } }
@media (prefers-reduced-motion: no-preference) {
  .hero__shot { animation: hero-zoom var(--hero-zoom-time) ease-in-out infinite alternate; will-change: transform; }
}
@keyframes hero-zoom { from { transform: scale(1); } to { transform: scale(var(--hero-zoom)); } }
.hero__bg, .hero__video { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; display: block; }
/* Until the script hands them their pictures, the hero's two images have none, and a
   browser draws an image like that as an empty outlined frame. Keep it out of the first paint. */
.hero__bg:not([src]), .hero__logo:not([src]) { visibility: hidden; }
/* The shade deepens by the middle of the screen, where the paragraph and the button sit: the
   band of light in the clip travels the whole height, and behind grey text it would wash a line
   out as it passes. Above the middle it stays light, so the band reads where the logo is. */
.hero__media::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, rgba(10, 10, 11, .35) 0%, rgba(10, 10, 11, .1) 30%, rgba(10, 10, 11, .62) 52%, rgba(10, 10, 11, .9) 100%); }
.hero__inner { position: relative; z-index: 1; max-width: 720px; margin-inline: auto; min-height: 100svh; display: grid; gap: var(--sp-2); justify-items: center; align-content: center; padding: var(--section-y) var(--pad) var(--sp-7); }
.hero__tagline { font-family: var(--font-head); font-size: var(--step-lead); letter-spacing: var(--track-display); }
.hero__text { max-width: 560px; color: var(--text-on-ink-2); font-size: var(--step-body); }
.hero__cta { margin-top: var(--sp-2); }
.hero__scroll { display: none; }
@media (min-width: 820px) {
  .hero__media::after { background: linear-gradient(180deg, rgba(10, 10, 11, .45) 0%, rgba(10, 10, 11, .15) 40%, rgba(10, 10, 11, .85) 100%); }
  .hero__inner { padding: var(--section-y) var(--pad); }
  .hero__scroll { display: block; position: absolute; bottom: var(--sp-3); left: 50%; transform: translateX(-50%); color: var(--gold); font-size: 1.4rem; opacity: .8; }
}

/* ===== sections ===== */
.section { padding: var(--section-y) 0; }
.section--dark { background: var(--ink-0); color: var(--paper-0); }
.section--light { background: var(--paper-0); color: var(--ink-0); }
/* Separation is the background change, so two dark sections in a row need two
   different darks. Same for two light ones. */
.section--ink-1 { background: var(--ink-1); color: var(--text-on-ink); --fg: var(--text-on-ink); --fg-2: var(--text-on-ink-2); --action: var(--gold); }
.section--paper-1 { background: var(--paper-1); color: var(--text-on-paper); --fg: var(--text-on-paper); --fg-2: var(--text-on-paper-2); --action: var(--gold-on-paper); }
.section__title { font-size: var(--step-h2); line-height: 1.08; text-align: center; margin-bottom: clamp(28px, 5vw, 52px); }

/* ===== services as chapters =====
   No card, no frame, no shadow: a photograph and a paragraph, alternating sides.
   The body is a grid so the text can grow without the column clipping it. */
.cards { display: grid; gap: var(--sp-8); }
.chapter { display: grid; gap: var(--sp-5); align-items: center; }
.chapter__media { border-radius: var(--radius); overflow: hidden; }
.chapter__media img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; display: block; }
.chapter__body { display: grid; gap: var(--sp-3); align-content: center; }
.chapter__title { font-size: var(--step-h2); line-height: 1.08; color: var(--fg); }
.chapter__text { color: var(--fg-2); max-width: var(--measure); }
.chapter__link { color: var(--action); font-weight: 500; justify-self: start; min-height: var(--tap); display: inline-flex; align-items: center; }
.chapter__link:hover { text-decoration: underline; }
@media (min-width: 820px) {
  .chapter { grid-template-columns: 1fr 1fr; gap: var(--sp-7); }
  .chapter--flip .chapter__media { order: 2; }
}

/* ===== testimonials (screenshots) ===== */
.testimonials__empty { text-align: center; color: var(--text-on-ink-2); }
.testimonials__empty[hidden] { display: none; }
.testimonials { columns: 2; column-gap: 12px; max-width: 1000px; margin-inline: auto; }
.testimonial { display: block; width: 100%; break-inside: avoid; margin: 0 0 12px; padding: 0; border: 0; border-radius: 12px; overflow: hidden; background: var(--ink-1); cursor: zoom-in; }
.testimonial img { width: 100%; height: auto; display: block; }
.testimonial:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
/* ===== proof =====
   Client screenshots as uniform cards, one row, one height — a grid on the desktop, a
   strip to swipe on the phone. No masonry, no ragged edge. The card takes the
   screenshots' own shape (they are all 900×931), so nothing is cropped and nothing is
   padded; a screenshot of another shape would sit whole on a ground the colour of the
   chat wallpaper. (The clip used to share this row, which is why the cards were once
   9:16; with seven clips they have a rail of their own, above.) */
.proof { display: grid; grid-template-columns: repeat(auto-fit, minmax(var(--card-min), 1fr)); gap: var(--sp-3); }
.proof__wall, .proof .testimonials { display: contents; }
.proof .testimonial { aspect-ratio: var(--shot-ratio); margin: 0; border-radius: var(--radius); overflow: hidden; background: var(--paper-0); }
.proof .testimonial img { width: 100%; height: 100%; object-fit: contain; }
.proof .testimonials__empty { grid-column: 1 / -1; }
@media (max-width: 819px) {
  .proof { display: flex; overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x mandatory; padding-bottom: var(--sp-2); scrollbar-width: none; }
  .proof::-webkit-scrollbar { display: none; }
  .proof .testimonial { flex: 0 0 min(72vw, var(--card-w)); scroll-snap-align: start; }
  .proof .testimonials__empty { flex: 0 0 auto; align-self: center; }
}

/* ===== about =====
   The same figure as a service chapter, on the same spacing: a photograph, and the
   words that belong to it a clear step away. Stacked and centred on a phone and a
   tablet. Side by side only from 1000px: below that the words' column is too narrow —
   at 820 the heading broke in two and the five paragraphs ran 150px past the photograph. */
.about { display: grid; gap: var(--sp-5); align-items: center; grid-template-columns: 1fr; }
.about__img { width: 100%; aspect-ratio: 4 / 5; object-fit: cover; border-radius: var(--radius); max-width: 440px; justify-self: center; box-shadow: var(--shadow-photo); transition: var(--hl-ease); }
.about__body { display: grid; gap: var(--sp-3); text-align: center; }
/* The heading is one sentence and reads as one: it shrinks to stay on a single line on
   the narrowest phone, and a longer one that has to break does so in even lines rather
   than leaving its last word (or the heart) alone. */
.about .section__title { margin-bottom: 0; font-size: min(var(--step-h2), 8.2vw); text-wrap: balance; }
.about__text { font-size: var(--step-body); max-width: var(--measure); margin-inline: auto; text-align: start; }
.about__text p { margin: 0 0 var(--sp-2); }
.about__text p:last-child { margin-bottom: 0; }
@media (min-width: 1000px) {
  .about { grid-template-columns: 5fr 7fr; gap: var(--sp-6); }
  .about__body { text-align: start; }
  .about .section__title { font-size: var(--step-h2-col); text-align: start; }
  .about .section__title::after { margin-inline: 0; }
  .about__text { margin-inline: 0; }
}

/* ===== contact =====
   One small tile, two halves: what to do and where to find her on the start side, the
   map on the other, both exactly the same height. The tile is the lighter cream on the
   darker one — no frame, no shadow — and it is small on purpose: the page ends on a
   card, not on a billboard. On a phone the halves stack, information first.
   tools/check-design.mjs holds it to that: a height ceiling, and the two halves aligned. */
#contact { padding-block: var(--sp-6); }
.contact { display: grid; max-width: var(--tile-max); margin-inline: auto; border-radius: var(--radius); overflow: hidden; background: var(--paper-0); }
.contact__stack { display: grid; gap: var(--sp-1); justify-items: start; align-content: center; padding: var(--sp-4); text-align: start; }
.contact__title { font-size: var(--step-title-sm); text-align: start; margin: 0 0 var(--sp-1); }
/* digits keep their order inside RTL text, and a phone number is a tap target, not a caption */
.contact__tel { font-size: var(--step-lead); font-weight: 500; color: var(--action); direction: ltr; unicode-bidi: isolate; min-height: var(--tap); display: inline-flex; align-items: center; }
.contact__tel:hover { text-decoration: underline; }
.contact__address { color: var(--fg-2); font-size: var(--step-body); }
/* on a phone the button runs edge to edge inside the tile; beside the map it keeps its own width */
.contact__stack .btn { margin-block: var(--sp-3) var(--sp-1); justify-self: stretch; }
.contact__secondary { display: flex; flex-wrap: wrap; gap: var(--sp-3); }
.contact__secondary a { display: inline-flex; align-items: center; gap: var(--sp-1); color: var(--action); font-size: var(--step-body); min-height: var(--tap); }
.contact__secondary a:hover { text-decoration: underline; }
.contact__secondary a:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); border-radius: var(--radius-sm); }
.contact__map { aspect-ratio: 16 / 9; background: var(--paper-1); }
/* desaturated so the map sits inside the palette instead of shouting over it */
.contact__map iframe { width: 100%; height: 100%; border: 0; display: block; filter: grayscale(1) contrast(1.05); }
@media (min-width: 820px) {
  .contact { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
  .contact__stack { padding: var(--sp-6) var(--sp-5); }
  .contact__stack .btn { justify-self: start; }
  /* the map takes its height from the information beside it, never the other way round */
  .contact__map { aspect-ratio: auto; min-height: var(--map-min); }
}

/* ===== footer ===== */
.footer { padding: 28px var(--pad); text-align: center; color: var(--text-on-ink-2); font-size: .9rem; }

/* ===== brand logo ===== */
.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
.hero__logo { width: min(66vw, 400px); height: auto; aspect-ratio: 800 / 622; filter: drop-shadow(0 6px 24px rgba(0, 0, 0, .45)); }
.footer__logo { width: 44px; height: auto; margin: 0 auto 10px; opacity: .9; }

/* ===== gallery: two rows that drift =====
   Ten photographs as two rows running from one edge of the screen to the other, in
   opposite directions: a steady drift at rest, geared to the page scroll — faster when
   it is scrolled hard, turning round when it turns round — resting under a pointer, and
   draggable. The tiles only travel; they are never rotated or skewed. js/motion.js
   drives it and clones the tiles the loop needs. With the motion layer off (no
   JavaScript, or a visitor who asked for less motion) each row is a plain strip that
   scrolls sideways by hand, starting at the page gutter. */
/* A block, not a grid: a clipped row is not a scroll container, so as a grid item its
   automatic minimum width would be its whole track and the row would grow to fit it. */
.gallery { display: block; }
.gallery__row { min-width: 0; overflow-x: auto; overscroll-behavior-x: contain; scrollbar-width: none; }
.gallery__row + .gallery__row { margin-top: var(--sp-1); }
.gallery__row::-webkit-scrollbar { display: none; }
/* clip, not hidden: a clipped box cannot be scrolled, so keyboard focus landing on a tile
   cannot shove the row sideways underneath the transform that positions it */
.is-motion .gallery__row { overflow: hidden; overflow: clip; touch-action: pan-y; cursor: grab; -webkit-user-select: none; user-select: none; }
.gallery__row.is-dragging, .gallery__row.is-dragging .gallery__item, .gallery__row.is-dragging .gallery__ghost { cursor: grabbing; }
/* the block padding is room for the hover lift and the focus ring, which the row would clip */
.gallery__track { display: flex; gap: var(--sp-3); width: max-content; padding-block: var(--sp-1); will-change: transform; }
html:not(.is-motion) .gallery__track { padding-inline: var(--pad); }
.gallery__item, .gallery__ghost { position: relative; flex: 0 0 auto; width: var(--tile-w); aspect-ratio: 4 / 5; padding: 0; border: 0; background: none; cursor: zoom-in; border-radius: var(--radius); overflow: hidden; transition: var(--hl-ease); }
/* the tile is the target, never the photograph: a press on the image would start a native image drag */
.gallery__item img, .gallery__ghost img { width: 100%; height: 100%; object-fit: cover; display: block; transition: var(--hl-ease); pointer-events: none; -webkit-user-drag: none; }
.gallery__item:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
@media (max-width: 819px) { .gallery__row + .gallery__row { margin-top: 0; } .gallery__track { gap: var(--sp-2); } .gallery__item, .gallery__ghost { width: var(--tile-w-phone); } }

/* ===== lightbox ===== */
.lightbox { position: fixed; inset: 0; z-index: 200; overscroll-behavior: contain; background: rgba(10, 10, 11, .94); display: grid; place-items: center; padding: 56px 16px; }
.lightbox[hidden] { display: none; }
.lightbox__img { max-width: 100%; max-height: calc(100vh - 112px); max-height: calc(100svh - 112px); object-fit: contain; border-radius: 8px; box-shadow: 0 20px 60px rgba(0, 0, 0, .6); }
.lightbox__close, .lightbox__nav { position: absolute; background: none; border: 1px solid var(--gold-soft); color: var(--paper-0); width: 44px; height: 44px; border-radius: 50%; font-size: 1.6rem; line-height: 1; cursor: pointer; display: grid; place-items: center; font-family: var(--font-body); }
.lightbox__close { top: 14px; left: 14px; }
.lightbox__nav { top: 50%; transform: translateY(-50%); }
.lightbox__nav--prev { right: 10px; }
.lightbox__nav--next { left: 10px; }
.lightbox__count { position: absolute; bottom: 16px; left: 50%; transform: translateX(-50%); color: var(--text-on-ink-2); font-size: .9rem; direction: ltr; }

/* ===== videos: a rail of reels =====
   The clips stand side by side from one edge of the screen to the other, and the rail
   scrolls sideways — a swipe, a trackpad, a mouse drag, or the two arrows — settling on
   a card. Nothing plays until it is tapped, and only one plays at a time. */
.rail { position: relative; }
.videos { display: flex; gap: var(--sp-3); overflow-x: auto; overscroll-behavior-x: contain; scroll-snap-type: x proximity; scroll-padding-inline: var(--pad); padding: var(--sp-1) var(--pad); scrollbar-width: none; }
.videos::-webkit-scrollbar { display: none; }
.videos.is-dragging { scroll-snap-type: none; cursor: grabbing; -webkit-user-select: none; user-select: none; }
.video { position: relative; flex: 0 0 var(--reel-w); margin: 0; scroll-snap-align: start; }
/* auto margins centre a rail that does not fill the screen, and vanish when it overflows */
.video:first-child { margin-inline-start: auto; }
.video:last-child { margin-inline-end: auto; }
.video__media, .video__placeholder { width: 100%; aspect-ratio: 9 / 16; border-radius: var(--radius); overflow: hidden; background: var(--ink-1); }
.video__media { object-fit: cover; display: block; }
iframe.video__media { border: 0; }
/* no clip on this site makes a sound, so the player offers no volume control.
   Separate rules on purpose: one selector a browser does not know would void a shared rule. */
.video__media::-webkit-media-controls-mute-button { display: none; }
.video__media::-webkit-media-controls-volume-slider { display: none; }
.video__media::-webkit-media-controls-volume-control-container { display: none; }
.video__placeholder { position: relative; display: grid; place-items: center; transition: var(--hl-ease); }
.video__placeholder img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; opacity: .55; transition: var(--hl-ease); }
.video__play { position: relative; width: 64px; height: 64px; border-radius: 50%; border: 1px solid var(--gold); display: grid; place-items: center; background: rgba(10, 10, 11, .35); transition: var(--hl-ease); }
.video__player { position: relative; border-radius: var(--radius); overflow: hidden; }
.video__player .video__media { display: block; }
/* a floor of shade under the caption; it lifts while the clip plays so the controls are clear */
.video__player::after { content: ""; position: absolute; inset: auto 0 0 0; height: 30%; background: linear-gradient(to top, rgba(10, 10, 11, .65), rgba(10, 10, 11, 0)); pointer-events: none; transition: opacity var(--dur-ui) var(--ease); }
.video__player.is-playing::after { opacity: 0; }
.video__player .video__play { position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 1; padding: 0; cursor: pointer; font: inherit; }
.video__player .video__play:hover { transform: translate(-50%, -50%) scale(1.08); background: rgba(10, 10, 11, .5); }
.video__player .video__play:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
.video__player.is-playing .video__play { display: none; }
.video__play::after { content: ""; border-style: solid; border-width: 11px 0 11px 18px; border-color: transparent transparent transparent var(--gold); margin-left: 4px; }
.video__soon { position: absolute; bottom: 16px; color: var(--paper-0); font-size: .9rem; letter-spacing: .05em; }
/* the caption lies on the clip's own poster, over the shade */
.video__title { position: absolute; inset-inline: var(--sp-2); bottom: var(--sp-2); text-align: center; color: var(--text-on-ink); font-size: var(--step-small); text-shadow: 0 1px 8px rgba(0, 0, 0, .6); pointer-events: none; transition: opacity var(--dur-ui) var(--ease); }
.video:has(.is-playing) .video__title { opacity: 0; }
/* an embed or a placeholder already uses its bottom edge, so there the caption sits underneath */
.video[data-type="youtube"] .video__title, .video[data-type="instagram"] .video__title, .video[data-type="placeholder"] .video__title { position: static; margin-top: var(--sp-1); color: var(--fg-2); text-shadow: none; }
/* the arrows: only where there is a pointer to press them and more rail than screen */
.rail__nav { display: none; position: absolute; top: 50%; transform: translateY(-50%); z-index: 2; width: var(--tap); height: var(--tap); border-radius: 50%; border: 1px solid var(--gold-soft); background: rgba(10, 10, 11, .55); color: var(--paper-0); font-size: 1.6rem; line-height: 1; cursor: pointer; place-items: center; font-family: var(--font-body); transition: opacity var(--dur-ui) var(--ease); }
.rail__nav--prev { inset-inline-start: var(--sp-2); }
.rail__nav--next { inset-inline-end: var(--sp-2); }
.rail__nav[disabled] { opacity: 0; pointer-events: none; }
.rail__nav:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
@media (hover: hover) and (pointer: fine) { .rail.is-scrollable .rail__nav { display: grid; } }
@media (max-width: 819px) { .videos { gap: var(--sp-2); scroll-snap-type: x mandatory; } .video { flex-basis: var(--reel-w-phone); } }

/* ===== pointing at an image =====
   The frame lifts and the photo grows inside it, so the picture reads as pushed forward
   behind a fixed window rather than as a box that got bigger.

   Every :hover trigger is behind `hover: hover`. A touch browser applies :hover on tap and
   leaves it there until you tap something else — without this gate a gallery tile would
   stay lifted and zoomed after you closed the lightbox. Keyboard focus gets the same
   treatment, declared outside the gate, because that has to work on any device. */
@media (hover: hover) and (pointer: fine) {
  .gallery__item:hover, .gallery__ghost:hover { transform: translateY(var(--hl-lift)); }
  .gallery__item:hover img, .gallery__ghost:hover img { transform: scale(var(--hl-zoom)); }

  .card:hover { transform: translateY(var(--hl-lift)); }
  .card:hover .card__img { transform: scale(var(--hl-zoom)); }

  /* Not clickable, so no lift and no ring — just enough life to answer the pointer.
     It has no clipping frame either, so the picture itself grows; keep that small. */
  .about__img:hover { transform: scale(1.02); }

  .video__placeholder:hover img { transform: scale(var(--hl-zoom)); opacity: .72; }
  .video__placeholder:hover .video__play { transform: scale(1.08); background: rgba(10, 10, 11, .5); }
}

/* Tab navigation lands on the gallery buttons; give them the same highlight the mouse
   gets, on top of the outline that marks focus itself. */
.gallery__item:focus-visible { transform: translateY(var(--hl-lift)); }
.gallery__item:focus-visible img { transform: scale(var(--hl-zoom)); }

/* ===== floating WhatsApp button ===== */
.wa-fab { position: fixed; left: 18px; bottom: 18px; z-index: 150; width: 58px; height: 58px; border-radius: 50%; background: var(--gold); color: var(--ink-0); display: grid; place-items: center; box-shadow: 0 8px 24px rgba(0, 0, 0, .35); opacity: 0; visibility: hidden; transform: translateY(16px) scale(.9); pointer-events: none; transition: opacity .3s ease, transform .3s ease, visibility 0s linear .3s; }
.wa-fab.is-visible { opacity: 1; visibility: visible; transform: none; pointer-events: auto; transition-delay: 0s; }
.wa-fab.is-visible:hover { transform: translateY(-2px); }

/* ===== intro: the monogram assembles, then hands off to the hero logo =====
   Timings are staggered so each letter lands before the next arrives. js/intro.js
   adds .is-running to start them and reads --intro-total to know when to hand off,
   so the clock lives here and the script follows it. */
.intro {
  --t-y: .1s; --t-b: .3s; --t-s: .5s; --t-sweep: .72s; --t-name: .82s; --t-sub: .94s;
  --t-flip: 1.2s; --intro-total: 1800;
  position: fixed; inset: 0; z-index: 300; background: var(--ink-0);
  display: grid; place-items: center; overscroll-behavior: contain;
}
.intro__stage { position: relative; width: min(78vw, 520px); will-change: transform; }
.intro__logo { display: block; width: 100%; height: auto; aspect-ratio: 800 / 622; }
/* Each piece starts off its seat and slides in along the axis it sits on, so the
   three read as locking into one another rather than fading up in place. */
.intro__logo #mg-y, .intro__logo #mg-b, .intro__logo #mg-s,
.intro__logo #wm-name, .intro__logo #wm-sub {
  transform-box: fill-box; transform-origin: center; opacity: 0;
}
.intro__logo #mg-y { transform: translateX(-46%) rotate(-5deg); }
.intro__logo #mg-b { transform: translateX(46%) rotate(5deg); }
.intro__logo #mg-s { transform: translateY(-62%) scaleY(1.35); }
.intro__logo #wm-name { transform: translateY(26%); }
.intro__logo #wm-sub { transform: scaleX(.9); }

.intro.is-running .intro__logo #mg-y,
.intro.is-running .intro__logo #mg-b,
.intro.is-running .intro__logo #mg-s,
.intro.is-running .intro__logo #wm-name,
.intro.is-running .intro__logo #wm-sub {
  opacity: 1; transform: none;
  transition: transform .55s cubic-bezier(.2, .85, .2, 1), opacity .3s ease-out;
}
.intro.is-running .intro__logo #mg-y { transition-delay: var(--t-y); }
.intro.is-running .intro__logo #mg-b { transition-delay: var(--t-b); }
.intro.is-running .intro__logo #mg-s { transition-delay: var(--t-s); transition-duration: .5s; }
.intro.is-running .intro__logo #wm-name { transition-delay: var(--t-name); transition-duration: .5s; }
.intro.is-running .intro__logo #wm-sub { transition-delay: var(--t-sub); transition-duration: .5s; }

/* A single pass of light across the mark once the three letters have seated.
   Masked to the logo's own alpha so the sheen only touches the ink. */
.intro__sweep { position: absolute; inset: 0; opacity: 0; pointer-events: none; }
@supports (mask-image: url("../assets/brand/logo-full-light.svg")) or (-webkit-mask-image: url("../assets/brand/logo-full-light.svg")) {
  .intro__sweep {
    background: linear-gradient(105deg, transparent 42%, rgba(255, 255, 255, .55) 50%, transparent 58%);
    background-size: 300% 100%;
    -webkit-mask: url("../assets/brand/logo-full-light.svg") center / 100% 100% no-repeat;
    mask: url("../assets/brand/logo-full-light.svg") center / 100% 100% no-repeat;
  }
  .intro.is-running .intro__sweep { animation: intro-sweep .7s ease-out var(--t-sweep) both; }
}
@keyframes intro-sweep {
  from { opacity: 1; background-position: 100% 0; }
  to { opacity: 1; background-position: 0 0; }
}

/* Hand-off: the stage travels to the hero logo's exact rect (js sets --flip-*),
   the black lifts, and the identical hero logo is already sitting underneath. */
.intro.is-landing .intro__stage {
  transform: translate(var(--flip-x), var(--flip-y)) scale(var(--flip-s));
  transition: transform .53s cubic-bezier(.65, 0, .2, 1);
}
.intro.is-landing { background: transparent; transition: background .42s ease .1s; }
.intro.is-done { opacity: 0; transition: opacity .25s ease; pointer-events: none; }
/* The black lifts while the logo is still travelling, which would show the resting hero
   logo underneath the flying one. Hide it until the flight lands on top of it — at that
   moment the two are the same artwork at the same rect, so the swap cannot be seen. */
html.intro-running .hero__logo { visibility: hidden; }

/* ===== promo popup (first-visit discount) ===== */
.promo { position: fixed; inset: 0; z-index: 180; display: grid; place-items: center; padding: 16px; background: rgba(10, 10, 11, .74); opacity: 0; transition: opacity .3s ease; }
.promo[hidden] { display: none; }
.promo.is-open { opacity: 1; }
.promo__card { position: relative; width: min(100%, 400px); background: var(--paper-0); color: var(--ink-0); border-radius: var(--radius); overflow: hidden; box-shadow: 0 30px 80px rgba(0, 0, 0, .6); transform: translateY(18px) scale(.97); transition: transform .35s ease; }
.promo.is-open .promo__card { transform: none; }
.promo__close { position: absolute; top: 10px; left: 10px; z-index: 1; width: var(--tap); height: var(--tap); border-radius: 50%; border: 0; background: rgba(10, 10, 11, .55); color: var(--paper-0); font-size: 1.5rem; line-height: 1; cursor: pointer; display: grid; place-items: center; font-family: var(--font-body); }
.promo__close:hover { background: var(--ink-0); }
.promo__close:focus-visible { outline: var(--focus-ring); outline-offset: var(--focus-offset); }
.promo__visual { position: relative; }
.promo__visual--photo .promo__img { width: 100%; aspect-ratio: 5 / 4; object-fit: cover; object-position: 50% 18%; display: block; }
.promo__visual--logo { display: grid; place-items: center; padding: 34px 28px; aspect-ratio: 4 / 3; background: radial-gradient(ellipse at 50% 42%, #2b2416 0%, #151209 45%, var(--ink-0) 100%); }
.promo__visual--logo::before { content: ""; position: absolute; inset: 12px; border: 1px solid var(--gold-soft); border-radius: 12px; pointer-events: none; }
.promo__visual--logo .promo__img { width: min(68%, 240px); height: auto; display: block; filter: drop-shadow(0 8px 26px rgba(0, 0, 0, .6)); }
.promo__body { padding: 22px 22px 20px; text-align: center; display: grid; gap: 10px; justify-items: center; }
.promo__eyebrow { font-family: var(--font-head); font-weight: 600; font-size: 1.15rem; line-height: 1.3; }
.promo__big { display: flex; align-items: baseline; justify-content: center; gap: 12px; line-height: .95; }
.promo__big-num { font-family: var(--font-mark); font-weight: 600; font-size: 4.4rem; color: var(--gold-on-paper); letter-spacing: -.02em; direction: ltr; unicode-bidi: isolate; }
.promo__big-label { font-family: var(--font-head); font-weight: 600; font-size: 1.7rem; }
.promo__subtitle { font-family: var(--font-head); font-weight: 600; font-size: 1.15rem; margin-top: -2px; }
.promo__text { color: var(--text-on-paper-2); font-size: .98rem; max-width: 320px; }
.promo__text p { margin: 0 0 8px; }
.promo__text p:last-child { margin-bottom: 0; }
.promo__highlight { border: 1px solid var(--gold); border-radius: 999px; padding: 8px 16px; font-weight: 500; font-size: .95rem; color: var(--ink-0); }
.promo__highlight[hidden], .promo__subtitle[hidden] { display: none; }
.promo__cta { width: 100%; }
.promo__fine { color: var(--text-on-paper-2); font-size: .8rem; }
@media (min-width: 640px) {
  .promo__card { width: min(100%, 720px); display: grid; grid-template-columns: 1fr 1fr; }
  .promo__visual { min-height: 440px; }
  .promo__visual--photo .promo__img { height: 100%; aspect-ratio: auto; }
  .promo__visual--logo { aspect-ratio: auto; height: 100%; }
  .promo__body { padding: 36px 28px; align-content: center; }
}
@media (prefers-reduced-motion: reduce) { .promo, .promo__card { transition: none; } }

/* ===== reveal on scroll =====
   What arrives is a section's content, never the section. Its ground is there before
   the visitor reaches it, and its direct children rise into place in a short stagger,
   so the eye is led down the section instead of being handed all of it at once.
   (The section itself used to fade in too. On a cream page over a dark body that
   showed as a dark gap under the hero which cleared late, in the middle of the scroll.)
   Reduced motion collapses it to nothing. */
.js .reveal .container > *, .js .reveal .chapter { opacity: 0; transform: translateY(var(--stagger-rise)); transition: opacity var(--dur-scene) var(--ease), transform var(--dur-scene) var(--ease); }
.reveal.is-in .container > *, .reveal.is-in .chapter { opacity: 1; transform: none; }
.reveal.is-in .container > *:nth-child(2), .reveal.is-in .chapter:nth-child(2) { transition-delay: var(--stagger-step); }
.reveal.is-in .container > *:nth-child(3), .reveal.is-in .chapter:nth-child(3) { transition-delay: calc(var(--stagger-step) * 2); }
.reveal.is-in .container > *:nth-child(n+4), .reveal.is-in .chapter:nth-child(n+4) { transition-delay: calc(var(--stagger-step) * 3); }
/* With the motion layer running, the chapters are its own to bring in: the photograph is
   unveiled and the words follow one by one. Hiding the whole list and each whole chapter
   as well stacked three fades on the same content, and made it late. */
.is-motion .reveal .cards, .is-motion .reveal .chapter { opacity: 1; transform: none; transition: none; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .js .reveal .container > *, .js .reveal .chapter { opacity: 1; transform: none; transition: none; }
  .btn, .card, .gallery__item img, .wa-fab { transition: none; }
  /* One switch for the whole image highlight: the gold ring still answers the pointer,
     the lift and the zoom go to nothing. Feedback without movement. */
  :root { --hl-lift: 0px; --hl-zoom: 1; --hl-shadow: none; }
  .gallery__item, .card__img, .about__img,
  .video__placeholder, .video__placeholder img, .video__play { transition: none; }
  /* No lift, no zoom, no ring — but a pointer still deserves an answer. A brightness
     lift on the photo is a state change with no movement in it. */
  @media (hover: hover) and (pointer: fine) { .gallery__item:hover img { filter: brightness(1.08); } }
  /* The inline gate in index.html already refuses to arm the intro here; this is the
     belt to that braces, so a stale overlay can never sit over the page. */
  .intro { display: none; }
}

/* ===== gift card: photo banner on the home page (owner: no plain black band) + popup ===== */
.gift-band { position: relative; isolation: isolate; overflow: hidden; min-height: min(78vh, 640px); display: grid; align-items: end; color: var(--paper-0); }
.gift-band[hidden] { display: none; }
.gift-band__img { position: absolute; inset: 0; z-index: -2; width: 100%; height: 100%; object-fit: cover; object-position: 50% 22%; }
/* cream text on a bright kitchen: darken from the bottom (phones) */
.gift-band::before { content: ""; position: absolute; inset: 0; z-index: -1; background: linear-gradient(180deg, rgba(10, 10, 11, .35) 0%, rgba(10, 10, 11, .05) 30%, rgba(10, 10, 11, .6) 60%, rgba(10, 10, 11, .92) 100%); }
.gift-band__inner { position: relative; display: grid; gap: 14px; justify-items: center; text-align: center; padding: 120px 0 48px; }
.gift-band__eyebrow { margin: 0; color: var(--gold); letter-spacing: .14em; font-size: .95rem; font-weight: 500; text-shadow: 0 1px 8px rgba(0, 0, 0, .6); }
.gift-band__title { font-size: clamp(1.8rem, 5.5vw, 2.8rem); max-width: 640px; text-shadow: 0 2px 18px rgba(0, 0, 0, .55); }
.gift-band .btn { margin-top: 8px; cursor: pointer; box-shadow: 0 10px 30px rgba(0, 0, 0, .45); }
@media (min-width: 820px) {
  .gift-band { min-height: 560px; align-items: center; }
  .gift-band__img { object-position: 50% 30%; }
  /* text on the start side (right, in RTL): darken that side instead of the bottom */
  .gift-band::before { background: linear-gradient(to left, rgba(10, 10, 11, .85) 0%, rgba(10, 10, 11, .65) 40%, rgba(10, 10, 11, .1) 72%, rgba(10, 10, 11, 0) 100%), linear-gradient(180deg, rgba(10, 10, 11, .3), rgba(10, 10, 11, 0) 25%); }
  .gift-band__inner { justify-items: start; text-align: start; padding: 90px 0; }
}
/* the popup reuses the promo card (.promo__*); only the gift-specific lines differ */
.promo--gift .gift__eyebrow { margin: 0; color: var(--gold-on-paper); letter-spacing: .14em; font-size: .85rem; font-weight: 500; }
.promo--gift .gift__title { font-size: 1.5rem; line-height: 1.25; }
.promo--gift .gift__closing { margin: 0; font-family: var(--font-head); font-weight: 600; color: var(--gold-on-paper); font-size: 1.1rem; }
.promo--gift .promo__text { max-width: none; }
.promo--gift .promo__visual--photo .promo__img { object-position: 50% 30%; }

/* ===== mobile pass (task 15) =====
   Point fixes found by reading tools/shots/mobile.png and mobile-fold.png section by
   section, not by re-guessing the whole layout. Every number here is a token already
   declared in :root. */
@media (max-width: 819px) {
  /* Works (gallery): the two-column gutter reused the section-level --sp-3 (24px),
     which reads as wasted air between thumbnails at 390px wide. --sp-2 (16px) keeps
     the same rhythm the rest of the mobile grid uses for tight clusters. */
  .gallery { gap: var(--sp-2); }
}
