/* ============================================================
   Joanna Borys Makeup — Bathgate, Scotland
   Visual language after the "Emily Makes" Wix template:
   white ground, dusty-pink panels, rose-gold foil accents,
   script + letterspaced serif caps + small-caps sans.

   The top of the page (fixed header + full-screen hero) follows
   the composition of patrycjamikolajczykbeauty.com — layout only.
   The colour language stays pink/rose-gold, not gold/cream.
   ============================================================ */

/* ── fallback faces ───────────────────────────────────────────
   Google Fonts load with `display=swap`, so the first paint uses the
   local fallbacks and the page reflows when the real faces arrive. Raw
   Times and Arial are the wrong width — Cormorant is narrower, Montserrat
   wider — so lines re-broke and the About section jumped ~49px on a cold
   cache. (Measured side effect: an anchor tapped during that first second
   scrolled to the pre-swap position and landed under the fixed header.)

   `size-adjust` scales the local face to the same average advance width
   as the web font, so the fallback breaks lines in the same places and
   the swap is invisible. The two percentages are measured, not guessed:
   canvas `measureText` of the same string at 100px gave
   Cormorant/Times = 94.13% and Montserrat/Arial = 111.33%.
   Re-measure if either family is ever swapped out. */
@font-face {
  font-family: "Cormorant Fallback";
  src: local("Times New Roman"), local("Times");
  size-adjust: 94.13%;
  ascent-override: 95%;
  descent-override: 25%;
  line-gap-override: 0%;
}
@font-face {
  font-family: "Montserrat Fallback";
  src: local("Arial"), local("Helvetica Neue"), local("Liberation Sans");
  size-adjust: 111.33%;
  ascent-override: 87%;
  descent-override: 23%;
  line-gap-override: 0%;
}

/* ── tokens ───────────────────────────────────────────────── */
:root {
  --white:      #ffffff;
  --pink:       #F2DCDB;   /* panels, bands              */
  --pink-deep:  #EFD5D3;   /* tiles, cards               */
  --pink-pale:  #FAF1F0;   /* header, footer bar         */
  --pink-tint:  #FDF8F7;   /* very soft section wash     */
  --line:       #E7CFCD;

  --ink:        #5A4A47;   /* warm dark grey-brown       */
  --ink-soft:   #8B7572;
  --ink-faint:  #A79290;

  --foil: linear-gradient(100deg,
            #A96B5C  0%,
            #E3BCA9 16%,
            #B0705F 33%,
            #F0D9CB 50%,
            #BC8271 68%,
            #E7C7B6 84%,
            #A96B5C 100%);
  --foil-btn: linear-gradient(100deg,
            #8F5C50  0%,
            #C08D7C 20%,
            #85554B 42%,
            #D2A594 58%,
            #90604F 80%,
            #B8836F 100%);
  --foil-flat: #B67F70;    /* fallback where gradients can't apply */

  --serif:  "Cormorant Garamond", "Cormorant Fallback", "Times New Roman", Georgia, serif;
  --sans:   "Montserrat", "Montserrat Fallback", "Helvetica Neue", Arial, sans-serif;
  --script: "Parisienne", "Snell Roundhand", cursive;

  --gutter: clamp(16px, 4vw, 24px);
  --sec-y:  clamp(52px, 8vw, 104px);

  /* Height of the fixed header. Two jobs: the hero's top padding and
     every section's scroll-margin come off this one number, so the bar
     can grow or shrink in exactly one place. */
  --nav-h: 74px;
}

/* ── reset ────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }

html {
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--white);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 15px;
  font-weight: 300;
  line-height: 1.75;
  -webkit-font-smoothing: antialiased;
}

img { display: block; max-width: 100%; }
ul  { list-style: none; margin: 0; padding: 0; }
p   { margin: 0 0 1em; }
h1, h2, h3 { margin: 0; font-weight: 400; }
a   { color: inherit; text-decoration: none; }

.sprite { position: absolute; width: 0; height: 0; overflow: hidden; }

.skip {
  position: absolute; left: -9999px; top: 0; z-index: 99;
  background: var(--ink); color: #fff; padding: 10px 18px;
  font-size: 12px; letter-spacing: .18em; text-transform: uppercase;
}
.skip:focus { left: 8px; top: 8px; }

:focus-visible { outline: 2px solid var(--foil-flat); outline-offset: 3px; }

.wrap {
  width: min(1200px, 100% - var(--gutter) * 2);
  margin-inline: auto;
}

/* The header floats over the page, so anchored sections have to stop
   clear of it — otherwise #services lands with its heading hidden. */
[id] { scroll-margin-top: calc(var(--nav-h) + 12px); }

/* ── shared type ──────────────────────────────────────────── */
.display {
  font-family: var(--serif);
  font-weight: 400;
  text-transform: uppercase;
  letter-spacing: clamp(.10em, .5vw, .20em);
  line-height: 1.14;
  color: var(--ink);
}

.script {
  font-family: var(--script);
  font-size: clamp(30px, 4.6vw, 52px);
  line-height: 1;
  margin: 0 0 .1em;
  text-transform: none;
  letter-spacing: 0;
  color: var(--foil-flat);
  background: var(--foil);
  -webkit-background-clip: text;
  background-clip: text;
  -webkit-text-fill-color: transparent;
}

/* short rose-gold bar under titles */
.foilbar {
  display: block;
  width: 52px; height: 3px;
  margin: 14px auto 0;
  background: var(--foil-flat);
  background-image: var(--foil);
}
.foilbar--wide { width: 88px; height: 2px; margin-top: 18px; }

/* four-pointed foil ornament */
.orn {
  display: block;
  width: 18px; height: 18px;
  margin: 16px auto;
  fill: var(--foil-flat);
  fill: url(#foilGrad);
}
.orn--tiny { width: 11px; height: 11px; margin: 0; }

.ic { width: 17px; height: 17px; fill: currentColor; }

/* ── buttons ──────────────────────────────────────────────── */
/* .btn — the square foil button used inside sections (about, contact). */
.btn {
  display: inline-block;
  padding: 13px 30px;
  background: var(--foil-flat);
  background-image: var(--foil-btn);
  color: #fff;
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .26em;
  text-transform: uppercase;
  border: 0;
  transition: filter .3s ease, transform .3s ease;
}
.btn:hover  { filter: brightness(1.08) saturate(1.05); }
.btn:active { transform: translateY(1px); }

/* .pill — the rounded button of the reference layout: header CTA and the
   hero's button row. One filled, the rest outlined. */
.pill {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 12px 26px;
  border: 1px solid var(--line);
  border-radius: 999px;
  background: rgba(255, 255, 255, .74);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 500;
  letter-spacing: .22em;
  text-transform: uppercase;
  white-space: nowrap;
  transition: background .28s ease, border-color .28s ease,
              color .28s ease, filter .28s ease, transform .28s ease;
}
.pill:hover  { background: var(--white); border-color: var(--foil-flat); color: var(--foil-flat); }
.pill:active { transform: translateY(1px); }

.pill--fill {
  background: var(--foil-flat);
  background-image: var(--foil-btn);
  border-color: transparent;
  color: #fff;
}
.pill--fill:hover {
  background-image: var(--foil-btn);
  border-color: transparent;
  color: #fff;
  filter: brightness(1.08) saturate(1.05);
}
.pill--sm { padding: 10px 20px; font-size: 9.5px; letter-spacing: .18em; }

.ic--arrow { width: 14px; height: 14px; }

/* ── header ───────────────────────────────────────────────────
   Fixed so the hero below can own the whole first screen, and fully
   transparent while it sits on the hero — same behaviour as the reference
   bar. The cream backdrop, the blur and the hairline only arrive once the
   page has moved (JS adds `is-stuck` past 12px). `--nav-h` is the height
   at every scroll position, so the sections' scroll-margin is never short.

   The bar used to tighten by 10px when it stuck. That slid the logo mark
   and the name 5px up the screen on the first scroll — the client asked
   for the logo to stay put, so the stuck state now changes only the
   backdrop. Nothing in the bar moves. */
.site {
  position: fixed;
  inset: 0 0 auto;
  z-index: 40;
  background: transparent;
  border-bottom: 1px solid transparent;
  transition: background .3s ease, border-color .3s ease, box-shadow .3s ease,
              backdrop-filter .3s ease;
}
/* scrolled bar in pink #F5AAB4 (owner's pick, 18.10); over the hero it stays transparent.
   Colour and how solid it is come from Joanna's panel in LSS (script.js sets
   --pasek-rgb and --pasek-krycie); the fallbacks are the owner's picks (18.10). */
.site.is-stuck {
  background: rgba(var(--pasek-rgb, 245, 170, 180), var(--pasek-krycie, .1));
  -webkit-backdrop-filter: blur(9px);
          backdrop-filter: blur(9px);
  border-bottom-color: rgba(231, 207, 205, .8);
  box-shadow: 0 2px 22px -14px rgba(90, 74, 71, .6);
}

/* Three columns, both outer ones 1fr: the links sit on the page's true
   centre no matter how wide the brand or the CTA cluster grow. */
.site__in {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 16px;
  min-height: var(--nav-h);
  padding: 10px 0;
}

.brand {
  justify-self: start;
  display: inline-flex;
  align-items: center;
  gap: 11px;
  min-width: 0;
}
.brand__mark {
  flex: 0 0 auto;
  width: 44px; height: 44px;
  border-radius: 50%;
  overflow: hidden;
  box-shadow: 0 4px 14px rgba(90, 74, 71, .16);
}
.brand__mark img { width: 100%; height: 100%; object-fit: cover; }
/* The lockup from the logo artwork, redrawn in live type:
     JOANNA BORYS   — hairline geometric sans caps, wide tracking
     ··············  — the dotted rule
     Makeup          — the script, centred under the rule
   Same face and colour as the artwork (owner, 18.10.2026: "the same font and
   colour as the logo"): Montserrat 400 for the caps, Ms Madi for the thin
   monoline "Makeup" (Parisienne was a different, calligraphic script), all in
   white. The artwork's white sits on a mid-tone photo; the bar is pale pink,
   so the white carries a glow in every state — colour from Joanna's panel in LSS
   (--poswiata-rgb), fallback #82524A (owner's pick, 18.10)
   — without it the name disappears into the bar. */
.brand__name {
  /* size and tracking live in two custom properties because the script
     line below needs the same numbers — see .brand__sub */
  --fs:  clamp(12.5px, 1.25vw, 15px);
  --trk: .34;
  font-family: var(--sans);
  font-size: var(--fs);
  font-weight: 400;
  letter-spacing: calc(var(--trk) * 1em);
  text-transform: uppercase;
  line-height: 1;
  color: #fff;
  text-shadow: 0 0 1px rgba(var(--poswiata-rgb, 130, 82, 74), 1), 0 0 3px rgba(var(--poswiata-rgb, 130, 82, 74), .85),
               0 1px 8px rgba(var(--poswiata-rgb, 130, 82, 74), .5);
  white-space: nowrap;
  text-align: center;
}
/* The dotted rule is the top border of the script line, so it runs exactly
   the width of the caps above it — the proportion of the artwork.
   `margin-right` trims the trailing letter-space: letter-spacing adds its
   gap AFTER the last S too, so without this the rule would overshoot the S
   and "Makeup" would sit a few px left of centre. */
.brand__sub {
  display: block;
  margin-top: 5px;
  margin-right: calc(var(--fs) * var(--trk));
  padding-top: 2px;
  border-top: 1px dotted #fff;
  font-family: "Ms Madi", var(--script);
  font-size: 1.5em;
  font-weight: 400;
  letter-spacing: .02em;
  line-height: 1.1;
  text-transform: none;
  color: #fff;
}

.menu { justify-self: center; }
.menu__list {
  display: flex;
  align-items: center;
  gap: clamp(18px, 2.6vw, 34px);
}
/* Full `--ink`, not `--ink-soft`: the bar is transparent over the flat lay
   now, and the soft tone measured ~3.2:1 against the photograph. The dark
   tone is ~6.3:1 on the same ground, which 10.5px caps need. */
.menu__list a {
  display: inline-block;
  font-size: 10.5px;
  font-weight: 400;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink);
  padding-bottom: 3px;
  border-bottom: 1px solid transparent;
  transition: color .25s ease, border-color .25s ease;
}
.menu__list a:hover { color: var(--foil-flat); border-bottom-color: var(--foil-flat); }

.site__cta {
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 12px;
}

/* burger — desktop hides it entirely */
.burger {
  display: none;
  width: 42px; height: 38px;
  padding: 0;
  align-items: center;
  justify-content: center;
  flex-direction: column;
  gap: 5px;
  background: transparent;
  border: 0;
  cursor: pointer;
}
.burger__bar {
  display: block;
  width: 21px; height: 1.5px;
  background: var(--ink);
  transition: transform .3s ease, opacity .2s ease;
}
.site.is-open .burger__bar:nth-child(1) { transform: translateY(6.5px) rotate(45deg); }
.site.is-open .burger__bar:nth-child(2) { opacity: 0; }
.site.is-open .burger__bar:nth-child(3) { transform: translateY(-6.5px) rotate(-45deg); }

/* ── hero ─────────────────────────────────────────────────────
   The entire first screen. `isolation: isolate` closes a stacking
   context so the background (z -2) and the legibility halos behind the
   text (z -1) can sit under the in-flow copy without escaping behind the
   page itself. There are no ornament circles here: the client asked for
   the logo on its own, and nothing may be drawn around it. */
.hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;              /* no sideways scroll from the halos */
  display: flex;
  align-items: center;
  min-height: 100vh;
  min-height: 100svh;
  padding: calc(var(--nav-h) + clamp(20px, 4vw, 40px)) var(--gutter)
           clamp(28px, 5vw, 52px);
}

.hero__bg { position: absolute; inset: 0; z-index: -2; }
.hero__bg img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 50%; }

/* The wash: an even top-to-bottom veil, edge to edge. It used to be a
   wide ellipse centred on the middle of the hero — which put its
   brightest point directly behind the logo and read as a halo around it.
   A purely vertical gradient cannot do that: every pixel on a given row
   gets the same value, so the logo sits on the photograph like everything
   else. Legibility of the copy is handled by the per-block halos below,
   not here, so this stays light enough for the flat lay to show through. */
.hero__wash {
  position: absolute; inset: 0;
  background: linear-gradient(180deg,
      rgba(253, 248, 247, .66)  0%,
      rgba(255, 255, 255, .46) 24%,
      rgba(255, 255, 255, .46) 74%,
      rgba(253, 248, 247, .76) 100%);
}

/* A local halo behind each text block.
   The wash above is centred on the hero, so how much of it reaches the
   price list and the headline depends entirely on how the flat lay gets
   cropped — at 1024px the columns start 24px from the edge, right on top
   of the powder compact and the palette. These two ellipses are anchored
   to the text instead of to the viewport, so the copy is legible at every
   width without flooding the corners where the kit has to stay visible.
   They are edge-less and sit behind the words, never behind the logo —
   nothing here may draw a shape around the mark. */
.hero__say, .prices { position: relative; }
.hero__say::before, .prices::before {
  content: "";
  position: absolute;
  inset: -22px -28px;
  z-index: -1;
  border-radius: 26px;
  pointer-events: none;
  background: rgba(255, 255, 255, .46);
  border: 1px solid rgba(255, 255, 255, .55);
  -webkit-backdrop-filter: blur(10px);
          backdrop-filter: blur(10px);
}
@media (max-width: 999px) {
  .hero__say::before, .prices::before { inset: -14px -12px; border-radius: 20px; }
}

.hero__in { position: relative; width: min(1200px, 100%); }

/* Below 1000px: one centred column, DOM order (headline, logo, prices).
   The three-column split waits for real room — the logo circle is a fixed
   square box, so at tablet width the side columns would be ~150px and the
   price rows would break after every word. */
.hero__grid {
  display: grid;
  justify-items: center;
  gap: clamp(26px, 5vw, 40px);
  text-align: center;
}

/* headline block */
.hero__say {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 12px;
  /* px, not `ch` — see the note on `.split__inner`. 296px is 30ch of
     Montserrat at 15px, the value this used to compute to. */
  max-width: 296px;
}
.hero__h {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(26px, 3vw, 35px);
  line-height: 1.24;
  letter-spacing: .012em;
  color: var(--ink);
  text-wrap: pretty;
}
.hero__tag {
  margin: 0;
  font-family: var(--serif);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(16px, 1.7vw, 20px);
  line-height: 1.4;
  color: var(--ink-soft);
}
.hero__rule {
  display: block;
  width: 44px; height: 1px;
  background: var(--foil-flat);
  background-image: var(--foil);
}

/* logo stage: a plain circle, and nothing else.
   No concentric rings, no rounded-square tile, no border — the client
   rejected all of it as reading like the reference site. The circle is
   the element itself (clip + shadow on `.stage`), so there is no wrapper
   left that could grow a frame again. If you are tempted to add a ring,
   a halo or a card here: don't. That is the whole brief.

   It also does not move. There was a 7s float (±9px) here; the client
   asked for the mark to be still, so the only motion left is the one-off
   entrance in the "entrance" block further down, after which the logo
   sits exactly where the layout puts it. */
.stage {
  --logo-d: clamp(178px, 42vw, 264px);
  position: relative;            /* anchors the glint pseudos below */
  width: var(--logo-d);
  height: var(--logo-d);
  border-radius: 50%;
  overflow: hidden;              /* also keeps the glint inside the circle */
  box-shadow: 0 22px 48px -22px rgba(90, 74, 71, .42),
              0 8px 22px -16px rgba(182, 127, 112, .45);
}
.stage img {
  width: 100%; height: 100%;
  object-fit: cover;
}

/* The glint: a band of light crossing the face of the mark, the way light
   catches a compact mirror. It lives INSIDE the circle (overflow: hidden
   clips it) and paints over the artwork, never around it — so it does not
   touch the "nothing drawn around the logo" rule above.
   Two pseudos because they are triggered differently: ::after fires once
   on load (see the entrance block), ::before replays on hover. Sharing one
   pseudo would make the load glint restart every time the pointer left. */
.stage::before,
.stage::after {
  content: "";
  position: absolute;
  inset: -20%;
  z-index: 1;
  pointer-events: none;
  opacity: 0;
  background: linear-gradient(115deg,
      transparent               36%,
      rgba(255, 255, 255, .00)  42%,
      rgba(255, 255, 255, .42)  47%,
      rgba(255, 244, 240, .92)  50%,
      rgba(255, 255, 255, .42)  53%,
      rgba(240, 217, 203, .38)  57%,
      transparent               64%);
  mix-blend-mode: screen;
  transform: translateX(-85%) skewX(-14deg);
}
@keyframes glint {
  0%   { transform: translateX(-85%) skewX(-14deg); opacity: 0; }
  14%  { opacity: 1; }
  86%  { opacity: 1; }
  100% { transform: translateX(85%)  skewX(-14deg); opacity: 0; }
}
@media (hover: hover) {
  .stage:hover::before { animation: glint 950ms cubic-bezier(.4, 0, .2, 1); }
}

/* price list — dotted leaders between name and price.
   `.price__dots` is an empty flex item: with `align-items: baseline` the
   browser synthesises its baseline from the bottom of its border box, so
   the dotted rule lands exactly on the text baseline. */
.prices {
  display: flex;
  flex-direction: column;
  gap: clamp(11px, 1.4vw, 17px);
  width: 100%;
  max-width: 340px;
  text-align: left;
}
.price {
  display: flex;
  align-items: baseline;
  gap: 9px;
}
.price__n {
  font-family: var(--serif);
  font-size: clamp(14.5px, 1.4vw, 17px);
  line-height: 1.3;
  color: var(--ink);
}
.price__n em {
  font-style: normal;
  font-size: .84em;
  color: var(--ink-faint);
  white-space: nowrap;
}
.price__dots {
  flex: 1 1 14px;
  min-width: 14px;
  border-bottom: 1px dotted rgba(167, 146, 144, .8);
}
.price__v {
  flex: 0 0 auto;
  font-family: var(--sans);
  font-size: 10.5px;
  font-weight: 400;
  letter-spacing: .10em;
  color: var(--foil-flat);
  white-space: nowrap;
}

/* pill row under the composition */
.hero__cta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 11px;
  margin-top: clamp(30px, 5vw, 56px);
}

/* ── section shells ───────────────────────────────────────── */
.section { padding: var(--sec-y) 0; }
.section--tint { background: var(--pink-tint); }

.sechead { text-align: center; margin-bottom: clamp(34px, 5vw, 58px); }
.sechead .display { font-size: clamp(24px, 4.4vw, 44px); }

.section__cta { margin: 22px 0 0; text-align: center; }

.note {
  margin: clamp(26px, 4vw, 40px) auto 0;
  max-width: 333px;          /* 46ch of Montserrat at 11px — see .split__inner */
  text-align: center;
  font-size: 11px;
  letter-spacing: .10em;
  color: var(--ink-faint);
}

/* ── split (about) ────────────────────────────────────────── */
.split {
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: stretch;
  background: var(--pink);
}
.split__media { position: relative; min-height: clamp(320px, 52vw, 620px); }
.split__media img {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  object-fit: cover;
}
.split__panel {
  display: grid;
  place-items: center;
  padding: clamp(40px, 6vw, 78px) clamp(22px, 5vw, 62px);
}
/* 454px = what `max-width: 46ch` used to compute to in Montserrat at 15px.
   The measure is pinned in px on purpose: `ch` is the advance of "0" in
   whatever font is CURRENTLY resolved, so before the web font arrives the
   fallback's narrower "0" shrank this box by ~6% — the paragraphs took an
   extra line and the section jumped when Montserrat landed. A px measure
   is font-independent, so the box is the same width before and after the
   swap. Same reason for `.band__copy`, `.card__copy`, `.note`,
   `.hero__say`. If you change the font size here, recompute the px. */
.split__inner { max-width: 454px; text-align: center; }
.split__inner .display { font-size: clamp(24px, 4vw, 44px); }
/* `:not(.script)` — the "about me" eyebrow is also a <p>, and this rule's
   specificity beat `.script`, shrinking the script to 14px body size. */
.split__inner p:not(.script) {
  font-size: 14px;
  color: var(--ink-soft);
  margin-bottom: 1.15em;
}
/* the studio's name links out to elite-aesthetics.vip */
.split__link {
  color: var(--foil-flat);
  border-bottom: 1px solid rgba(182, 127, 112, .45);
  transition: color .25s ease, border-color .25s ease;
}
.split__link:hover { color: var(--ink); border-color: var(--ink); }
/* the greeting line, in her voice: the serif at reading size, full ink */
.split__inner p.split__lead {
  font-family: var(--serif);
  font-size: clamp(19px, 2vw, 23px);
  line-height: 1.3;
  color: var(--ink);
  margin-bottom: .8em;
}
.split__inner .btn { margin-top: 12px; }

/* ── work grid ────────────────────────────────────────────── */
/* "My Work" is only what Joanna adds in LSS: hidden (section + links) until
   script.js gets at least one photo and sets html.ma-prace. */
html:not(.ma-prace) [data-prace] { display: none !important; }
.grid {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(16px, 2.4vw, 32px) clamp(12px, 2vw, 26px);
}
.cell { text-align: center; }
.cell__media {
  position: relative;
  aspect-ratio: 1 / 1;
  overflow: hidden;
  background: var(--pink-deep);
}
.cell__media img {
  width: 100%; height: 100%;
  object-fit: cover;
  transition: transform .8s cubic-bezier(.22, .61, .36, 1);
}
.cell:hover .cell__media img { transform: scale(1.05); }

.cell__name {
  margin: 14px 0 4px;
  font-family: var(--serif);
  font-size: clamp(13px, 1.5vw, 17px);
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink);
}
.cell__meta {
  margin: 0;
  font-size: 9.5px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* ── carousel ─────────────────────────────────────────────── */
.carousel { --per: 3; --gap: clamp(12px, 2vw, 26px); }
/* `touch-action: pan-y` is what makes the swipe work at all. Without it a
   horizontal drag on a touch screen is claimed by the browser's own
   panning gesture: the pointer stream ends in `pointercancel`, never
   `pointerup`, and script.js's swipe handler is listening for the latter.
   `pan-y` keeps the vertical page scroll and hands us the sideways drag. */
.carousel__viewport { overflow: hidden; touch-action: pan-y; }
.carousel__track {
  display: flex;
  gap: var(--gap);
  will-change: transform;
}
.carousel__track.is-anim { transition: transform .62s cubic-bezier(.4, .1, .2, 1); }

.card {
  flex: 0 0 calc((100% - (var(--per) - 1) * var(--gap)) / var(--per));
  background: var(--pink-deep);
  padding: clamp(26px, 3.4vw, 44px) clamp(18px, 2.6vw, 34px);
  min-height: clamp(250px, 30vw, 330px);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
}
.card__kicker {
  font-size: clamp(8px, 1.2vw, 9.5px);
  letter-spacing: .30em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: .9em;
}
.card__title {
  font-family: var(--serif);
  font-size: clamp(17px, 2.1vw, 25px);
  font-weight: 400;
  letter-spacing: .10em;
  text-transform: uppercase;
  line-height: 1.24;
  color: var(--ink);
}
.card .foilbar { margin: 14px auto 18px; }
.card__copy {
  font-size: 12.5px;
  line-height: 1.8;
  color: var(--ink-soft);
  margin: 0 0 1.1em;
  max-width: 247px;          /* 30ch of Montserrat at 12.5px — see .split__inner */
}
.card__price {
  margin: 0;
  font-size: 10px;
  font-weight: 500;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--foil-flat);
}

.carousel__nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 22px;
  margin-top: clamp(24px, 3.4vw, 38px);
}
.cbtn {
  width: 38px; height: 38px;
  display: grid; place-items: center;
  background: transparent;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background .25s ease, color .25s ease, border-color .25s ease;
}
.cbtn:hover { background: var(--pink-deep); color: var(--ink); border-color: var(--pink-deep); }
.cbtn .ic { width: 13px; height: 13px; }
.cbtn--next .ic { transform: rotate(180deg); }

/* ── contact band ─────────────────────────────────────────────
   The "Get in touch" block from elite-aesthetics.vip, in this site's
   language: a card of rows on the left, the map on the right, both on the
   pink band. Rows are a <dl>: icon + label on the term, the value under it. */
.band {
  background: var(--pink);
  padding: var(--sec-y) 0;
}
.sechead--band { margin-bottom: clamp(30px, 4.4vw, 50px); }
.band .display { font-size: clamp(26px, 4.6vw, 46px); }
.band__copy {
  max-width: 405px;          /* 44ch of Montserrat at 14px — see .split__inner */
  margin: 0 auto;
  font-size: 14px;
  color: var(--ink-soft);
}

.touch {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: clamp(16px, 2.4vw, 32px);
  align-items: stretch;
}
.touch__card,
.touch__map {
  border-radius: 24px;
  border: 1px solid rgba(255, 255, 255, .7);
  background: rgba(255, 255, 255, .5);
  box-shadow: 0 18px 44px -30px rgba(90, 74, 71, .5);
}
.touch__card {
  display: flex;
  flex-direction: column;
  padding: clamp(24px, 3.2vw, 42px);
}
.touch__rows { margin: 0; display: grid; gap: clamp(16px, 2vw, 22px); }
.touch__row dt {
  display: flex;
  align-items: center;
  gap: 9px;
  font-size: 9px;
  font-weight: 500;
  letter-spacing: .30em;
  text-transform: uppercase;
  color: var(--ink-soft);
  margin-bottom: 6px;
}
.touch__row dt .ic { width: 15px; height: 15px; color: var(--foil-flat); }
.touch__row dd {
  margin: 0;
  font-family: var(--serif);
  font-size: clamp(15px, 1.5vw, 18px);
  line-height: 1.45;
  letter-spacing: .03em;
  color: var(--ink);
}
.touch__row dd a { transition: color .25s ease; }
.touch__row dd a:hover { color: var(--foil-flat); }
.touch__note {
  display: block;
  margin-top: 3px;
  font-family: var(--sans);
  font-size: 10px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-faint);
}
.touch__btn { align-self: flex-start; margin-top: clamp(22px, 3vw, 34px); }

/* the map fills its card; the pill floats over its corner */
.touch__map {
  position: relative;
  overflow: hidden;
  min-height: 340px;
}
.touch__map iframe {
  position: absolute; inset: 0;
  width: 100%; height: 100%;
  border: 0;
  display: block;
}
.touch__open {
  position: absolute;
  right: 14px; bottom: 14px;
  background: rgba(255, 255, 255, .92);
}

@media (max-width: 860px) {
  .touch { grid-template-columns: 1fr; }
  .touch__map { min-height: 300px; }
}

/* ── footer ───────────────────────────────────────────────── */
.foot { background: var(--white); }
.feats {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: clamp(22px, 3vw, 38px);
  padding: clamp(42px, 6vw, 72px) 0;
  text-align: center;
  border-bottom: 1px solid var(--line);
}
.feats__t {
  display: block;
  font-size: clamp(9.5px, 1.3vw, 11px);
  font-weight: 500;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--ink);
  margin-bottom: 9px;
}
.feats__d {
  display: block;
  font-size: 11.5px;
  line-height: 1.7;
  color: var(--ink-faint);
}

.foot__bar { background: var(--pink-pale); }
.foot__bar-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding: 18px 0;
}
.foot__bar p {
  margin: 0;
  font-size: 9.5px;
  letter-spacing: .22em;
  text-transform: uppercase;
  color: var(--ink-soft);
}
.foot__by a {
  color: var(--foil-flat);
  border-bottom: 1px solid rgba(182, 127, 112, .45);
  transition: color .25s ease, border-color .25s ease;
}
.foot__by a:hover { color: var(--ink); border-color: var(--ink); }

.social { display: flex; gap: 14px; align-items: center; }
.social a { color: var(--ink-soft); display: block; transition: color .25s ease; }
.social a:hover { color: var(--foil-flat); }
.social .ic { width: 15px; height: 15px; }

/* ── scroll reveal (classes added by JS only) ─────────────── */
.rv { opacity: 0; transform: translateY(16px); transition: opacity .8s ease, transform .8s ease; }
.rv.in { opacity: 1; transform: none; }

/* ── entrance — "the compact opens" ───────────────────────────
   One orchestrated moment on load, then stillness. The round mark irises
   open from its own centre like a compact lid, the flat lay settles in
   behind it, and the two text blocks slide in from either side towards
   the logo. Price rows and the pill row follow in short staggers. The
   header drops in over the top while this happens.

   Rules that keep it safe:
   · Everything is scoped to `.js`, which index.html sets in <head> before
     first paint. No script, no entrance — the first screen renders whole.
   · Every keyframe ends in the element's NATURAL state and the fill mode
     is `backwards`, never `forwards`. So once a keyframe has played the
     element is simply itself again: the pills' :active nudge and the
     logo's box-shadow are untouched, and nothing can be left stranded.
   · transform / opacity / clip-path / filter only, all compositor work.
   · Stagger steps are 60–70ms, in line with the ui-ux-pro-max motion
     guidance (expo-out easing, sub-100ms per item); the whole sequence is
     over in ~3s, the first 1.8s of it being the focus pull on the logo.
   · prefers-reduced-motion and print zero the delays and durations at the
     bottom of this file, so those readers get the finished screen at once. */
:root { --enter: cubic-bezier(.16, 1, .3, 1); }

@keyframes enter {
  from { opacity: 0; transform: translate(var(--fx, 0), var(--fy, 0)); }
  to   { opacity: 1; transform: none; }
}

/* the flat lay is part of the focus pull: soft and a touch too big at
   first, sharp and at rest by the time the logo lands */
.js .hero__bg img { animation: bg-settle 1700ms cubic-bezier(.3, .8, .25, 1) backwards; }
@keyframes bg-settle {
  from { transform: scale(1.08); filter: blur(7px); }
  to   { transform: none; filter: none; }
}

/* the mark — "focus pull".
   The scene opens out of focus: the flat lay is soft and a touch too big,
   and the logo hangs over it huge, blurred and half-transparent, like a
   lens that has not found its subject yet. Over ~1.4s the lens pulls focus:
   the logo shrinks into place and sharpens, the shadow arrives as it
   lands, the flat lay resolves underneath. Then the light crosses the
   mirror. Pure CSS — transform, filter, opacity, box-shadow — and every
   keyframe ends in the natural state, so nothing is left behind. */
.js .stage {
  /* a gentler curve than --enter: expo-out spent the whole pull in the
     first half-second; this one lets the big blurred phase linger */
  animation: focus-pull 1800ms cubic-bezier(.3, .8, .25, 1) 100ms backwards;
}
@keyframes focus-pull {
  0% {
    opacity: 0;
    transform: scale(3.4);
    filter: blur(30px);
    box-shadow: 0 22px 48px -22px rgba(90, 74, 71, 0),
                0 8px 22px -16px rgba(182, 127, 112, 0);
  }
  16% { opacity: .82; }
  100% {
    opacity: 1;
    transform: none;
    filter: none;
    box-shadow: 0 22px 48px -22px rgba(90, 74, 71, .42),
                0 8px 22px -16px rgba(182, 127, 112, .45);
  }
}
/* …and once focus has locked, the light crosses the mirror once */
.js .stage::after { animation: glint 1100ms cubic-bezier(.4, 0, .2, 1) 1950ms backwards; }

/* header: brand first, then the links one by one, the CTA last */
.js .brand     { --fy: -10px; animation: enter 800ms var(--enter) 260ms backwards; }
.js .site__cta { --fy: -8px;  animation: enter 700ms var(--enter) 660ms backwards; }
.js .burger    { --fy: -8px;  animation: enter 700ms var(--enter) 660ms backwards; }
@media (min-width: 901px) {
  /* desktop only: on the phone the list lives in the burger panel and is
     display:none until opened — an animation with a 400ms delay would
     replay on every open and make the panel feel late */
  .js .menu__list > li { --fy: -8px; animation: enter 700ms var(--enter) backwards; }
  .js .menu__list > li:nth-child(1) { animation-delay: 400ms; }
  .js .menu__list > li:nth-child(2) { animation-delay: 460ms; }
  .js .menu__list > li:nth-child(3) { animation-delay: 520ms; }
  .js .menu__list > li:nth-child(4) { animation-delay: 580ms; }
}

/* the two text blocks come in towards the mark, each with its frosted plate */
.js .hero__say { --fx: 26px;  animation: enter 950ms var(--enter) 900ms backwards; }
.js .prices    { --fx: -26px; animation: enter 950ms var(--enter) 900ms backwards; }
@media (max-width: 999px) {
  /* stacked layout: nothing is beside the logo, so both rise instead */
  .js .hero__say { --fx: 0; --fy: 16px; }
  .js .prices    { --fx: 0; --fy: 16px; animation-delay: 1080ms; }
}

/* the foil rule under the tagline draws in from its centre once the block
   has landed (the block is centred at every width, so no per-breakpoint
   origin) */
.js .hero__rule { transform-origin: 50% 50%; animation: rule-in 800ms var(--enter) 1400ms backwards; }
@keyframes rule-in {
  from { transform: scaleX(0); }
  to   { transform: none; }
}

/* price rows, one after another */
.js .price { --fy: 10px; animation: enter 700ms var(--enter) backwards; }
.js .price:nth-child(1) { animation-delay: 1160ms; }
.js .price:nth-child(2) { animation-delay: 1230ms; }
.js .price:nth-child(3) { animation-delay: 1300ms; }
.js .price:nth-child(4) { animation-delay: 1370ms; }

/* the pill row last, so the eye has read the page before it is asked to act */
.js .hero__cta .pill { --fy: 12px; animation: enter 700ms var(--enter) backwards; }
.js .hero__cta .pill:nth-child(1) { animation-delay: 1500ms; }
.js .hero__cta .pill:nth-child(2) { animation-delay: 1560ms; }
.js .hero__cta .pill:nth-child(3) { animation-delay: 1620ms; }
.js .hero__cta .pill:nth-child(4) { animation-delay: 1680ms; }

/* ── responsive ───────────────────────────────────────────── */

/* ≥1000px — the reference's three-part hero: prices left, logo centre,
   headline right. Column placement (not `order`) does the swap, so the
   DOM keeps the mobile reading order. */
@media (min-width: 1000px) {
  .hero__grid {
    grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
    align-items: center;
    justify-items: stretch;
    gap: clamp(28px, 4vw, 56px);
    text-align: left;
  }
  /* 270px, not a `ch` measure: Cormorant is narrow, so 20ch came out at
     ~197px and broke the headline over four lines. This matches the
     reference's 260px column at a comparable type size. */
  /* Both side blocks are the same box: one width, stretched to the row
     height (= the logo), each hugging the logo column so the gap to the
     mark is identical on both sides. The frosted plates (::before) then
     come out the same size too. */
  .hero__grid  { gap: clamp(36px, 6vw, 90px); }
  /* the block itself is centred on its plate — headline, tagline and the
     rule all sit on one axis, as asked; only the price list stays ragged-left */
  .hero__say   { grid-column: 3; grid-row: 1; align-items: center; text-align: center; max-width: 270px; justify-self: start; }
  .stage       { grid-column: 2; grid-row: 1; --logo-d: clamp(240px, 22vw, 300px); }
  .prices      { grid-column: 1; grid-row: 1; max-width: 340px; justify-self: end; }
  .hero__rule  { width: 48px; }
}

@media (max-width: 1000px) {
  /* 4 → 2, never 3: four cells fill one row on desktop and two even rows
     on tablet; a 3-wide step would leave one orphan. */
  .grid  { grid-template-columns: repeat(2, 1fr); }
  .feats { grid-template-columns: repeat(2, 1fr); }
}

/* ── mobile header: burger panel ─────────────────────────────
   Only the section LINKS collapse into the burger, exactly as on the
   reference bar: the booking pill stays in the top row next to the
   burger at every width, because it is the page's primary conversion and
   hiding it inside a panel costs taps. The panel is a second row of the
   same fixed bar — no overlay, no absolute positioning; the header simply
   gets taller while it is open. */
@media (max-width: 900px) {
  :root { --nav-h: 62px; }

  .burger { display: flex; }

  .site__in {
    grid-template-columns: 1fr auto auto;
    grid-template-areas:
      "brand cta  burger"
      "menu  menu menu";
    column-gap: 10px;
    row-gap: 0;
  }
  .brand      { grid-area: brand; }
  .site__cta  { grid-area: cta; justify-self: end; }
  .burger     { grid-area: burger; justify-self: end; }
  .menu       { grid-area: menu; justify-self: stretch; }

  .menu { display: none; }
  .site.is-open .menu { display: block; }

  /* fully opaque, not .97: the bar carries no blur until it is stuck, so
     3% transparency let the hero headline ghost through the open panel */
  .site.is-open {
    background: rgb(var(--pasek-rgb, 245, 170, 180));
    border-bottom-color: rgba(231, 207, 205, .8);
    box-shadow: 0 12px 26px -20px rgba(90, 74, 71, .7);
  }

  .menu__list {
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin-top: 8px;
    border-top: 1px solid rgba(231, 207, 205, .7);
  }
  .menu__list a {
    display: block;
    padding: 14px 2px;
    border-bottom: 1px solid rgba(231, 207, 205, .7);
    font-size: 11px;
  }
  .menu__list a:hover { border-bottom-color: rgba(231, 207, 205, .7); }

  /* the pill has to share the top row with the brand and the burger */
  .site__cta .pill { padding: 9px 16px; letter-spacing: .14em; }
}

@media (max-width: 860px) {
  .split { grid-template-columns: 1fr; }
  .split__media { min-height: clamp(300px, 62vw, 460px); }
}

/* buttons as a 2×2 grid on phones, as asked */
@media (max-width: 640px) {
  .hero__cta {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
    width: min(360px, 100%);
    margin-inline: auto;
  }
  .hero__cta .pill {
    width: 100%;
    padding: 12px 8px;
    font-size: 9.5px;
    letter-spacing: .13em;
    gap: 6px;
  }
  .ic--arrow { width: 12px; height: 12px; }
}

@media (max-width: 520px) {
  body { font-size: 14px; }
  .feats { grid-template-columns: 1fr; }
  .foot__bar-in { justify-content: center; }

}

/* Narrow phones: brand + booking pill + burger will not all fit with the
   script name in the middle, and the pill is the one that has to survive
   (it is the conversion). The round mark alone still reads as the brand,
   and the full name is the first thing in the hero right below it. */
@media (max-width: 430px) {
  .brand { gap: 8px; }
  .brand__mark { width: 38px; height: 38px; }
  .brand__name { --fs: 12px; --trk: .12; }
  .site__cta .pill { padding: 9px 12px; font-size: 8.5px; letter-spacing: .08em; }
}
@media (max-width: 350px) {
  .brand { gap: 6px; }
  .brand__name { --fs: 11px; --trk: .07; }
  .site__cta .pill { padding: 8px 10px; }
  .burger { width: 36px; }
}

/* Short phones (SE-class): the hero is one screen tall on paper but its
   content is not, so trim the logo and the vertical rhythm to keep the
   button row above the fold. */
@media (max-width: 640px) and (max-height: 700px) {
  .stage { --logo-d: clamp(126px, 30vw, 168px); }
  .hero__grid { gap: 18px; }
  .hero__cta  { margin-top: 20px; }
  .hero__h    { font-size: clamp(22px, 6.4vw, 27px); }
}

/* ── motion ───────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .carousel__track.is-anim { transition: none; }
  .cell__media img { transition: none; }
  .burger__bar { transition: none; }
  .rv { opacity: 1; transform: none; transition: none; }
  /* `animation-delay: 0s` matters as much as the duration: the entrance
     uses `backwards` fill, so a zeroed duration with a live 1.3s delay
     would still hold the pill row invisible for 1.3s. */
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
  }
}

/* Print has no timeline — a delayed `backwards` keyframe would print its
   `from` state (opacity 0), so the entrance is switched off outright. */
@media print {
  .js *, .js *::before, .js *::after { animation: none !important; }
}
