/* =========================================================
   Sai Mai — shared foundation
   Design tokens, reset, primitives. Load before any page stylesheet.

   ---------------------------------------------------------
   LAYOUT SYSTEM — 8px rhythm + 16-column grid
   ---------------------------------------------------------
   Grid is defined at the 1440px artboard from Figma:

       viewport   1440
       margin     80  (both sides)
       content    1280
       columns    16
       gutter     16   (15 gutters = 240)
       column     (1280 - 240) / 16 = 65

   The content column is capped at 1280px, so on a 1920px viewport
   the margins simply grow to 320px — which is exactly what the
   Claude Design mockup uses. The grid itself never stretches past
   1280px, so column width stays 65px from 1440px upward.

   EVERY size, spacing and line-height in this project is a multiple
   of 8. Line-height is the smallest multiple of 8 greater than the
   font-size (72px type -> 80px line-height); body copy uses the
   multiple of 8 nearest 1.5x instead, for readability.
   ========================================================= */

:root {
  /* ---------- Grid ---------- */
  --content:  1280px;
  --gutter:   16px;
  --columns:  16;
  --margin:   80px;   /* narrowed at small viewports, see Responsive */

  /* Side padding for every full-width section. Resolves to 80px at
     1440px and 320px at 1920px, keeping content pinned at 1280px. */
  --edge: max(var(--margin), calc((100vw - var(--content)) / 2));

  /* ---------- Spacing scale (multiples of 8) ---------- */
  --s1:   8px;
  --s2:  16px;
  --s3:  24px;
  --s4:  32px;
  --s5:  40px;
  --s6:  48px;
  --s7:  56px;
  --s8:  64px;
  --s9:  72px;
  --s10: 80px;
  --s11: 88px;
  --s12: 96px;
  --s13: 104px;

  /* ---------- Line-height steps (multiples of 8) ---------- */
  --lh1: 16px;   /* labels, 11-13px */
  --lh2: 24px;   /* body copy 14-16px, 20px headings */
  --lh3: 32px;   /* 24-28px */
  --lh4: 40px;   /* 32px */
  --lh5: 48px;   /* 40-44px */
  --lh6: 56px;   /* 48px */
  --lh7: 72px;   /* 64px */

  /* ---------- Colour ---------- */
  --gold:        #C5A059;
  --gold-hover:  #CFAC66;
  --gold-bright: #C9A24B;
  --gold-light:  #D9B46D;
  --gold-soft:   rgba(197, 160, 89, 0.18);

  --cream:       #F3ECDD;
  --surface:     #FFFAF2;
  --cream-warm:  #F6ECE1;
  --cream-hi:    #FBF3E6;
  --cream-mid:   #E8DECC;

  --ink:         #1F1B14;
  --body:        #50453B;
  --muted:       #8F7361;
  --grey:        #8C8478;
  --copper:      #C1966C;

  --brown:       #7D5630;
  --brown-deep:  #3A2215;
  --dark:        #2E2218;
  --header:      #3D2E22;
  /* Hlavička o dva stupně světlejší — pás akce měsíce pod ní. Táž barva,
     jen zesvětlená, aby lišta patřila k navigaci a přitom se od ní
     odlišila. Viz .promo v branch.css. */
  --header-light: #55402F;
  --footer:      #2A1D13;
  --hero-dark:   #291D12;

  --line:        #D4C3B7;
  --line-soft:   #E3D9CE;
  --line-card:   #E4DDCF;

  /* ---------- Type ----------
     Two families, one job each:
       Lora      — every heading, numeral and editorial serif voice
       Manrope   — all body copy and UI labels

     --font-ui, --font-note and --font-num are aliases so page stylesheets
     keep their semantic naming, but they no longer pull extra webfonts.
     Plus Jakarta Sans and Noto Serif went first (near-duplicates of
     Manrope and Lora); Cormorant Garamond followed once the numerals
     moved to Lora — it was the last thing holding a third family on
     every page. Lora italic is loaded for the pull-quotes that used to
     lean on Cormorant's italic. */
  --font-body:   Manrope, "Segoe UI", system-ui, sans-serif;
  --font-serif:  Lora, Georgia, serif;
  --font-ui:     var(--font-body);
  --font-note:   var(--font-serif);
  --font-num:    var(--font-serif);

  --ease:        cubic-bezier(.16, .7, .3, 1);
  /* Gentler decelerate for reveals and hovers — no overshoot, settles calmly. */
  --ease-out:    cubic-bezier(.22, .61, .36, 1);
  --radius:      16px;
  --radius-sm:   8px;

  /* One hover contract for every card on the site (see "Card lift"). */
  --lift:        -4px;
  --lift-speed:  .25s;

  /* ---------- Elevation ----------
     Warm, low-contrast shadows. Deliberately soft: the palette is
     cream-on-cream, so a heavy shadow reads as dirt rather than depth.
     Pick by how far off the page the element should sit — 1 for resting
     cards, 3 for something lifted on hover.

     NOTE: `inset 0 0 0 Npx` rules elsewhere are hairline borders, not
     elevation — leave those alone. */
  --shadow-1:    0 4px 16px rgba(31, 27, 20, .05);
  --shadow-2:    0 12px 28px rgba(31, 27, 20, .07);
  --shadow-3:    0 20px 40px rgba(31, 27, 20, .10);
  --shadow-dark: 0 20px 44px rgba(0, 0, 0, .22);   /* on dark surfaces */

  /* Fallback texture shown wherever a photo has not been added yet. */
  --stripe: repeating-linear-gradient(-45deg, #ECE4D6, #ECE4D6 16px, #F3ECDD 16px, #F3ECDD 32px);
}

/* ---------- Reset ---------- */
*, *::before, *::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--body);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: var(--lh2);
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

img { display: block; max-width: 100%; height: auto; }
a { color: var(--gold); text-decoration: none; }
a:hover { color: var(--brown); }
h1, h2, h3, p, figure, blockquote, dl, dd { margin: 0; }
ul, ol { margin: 0; padding: 0; list-style: none; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }

:focus-visible {
  outline: 2px solid var(--gold);
  outline-offset: 4px;
  border-radius: 4px;
}

/* ---------- Povrchy prohlížeče ----------
   Výběr textu, kurzor v poli, posuvník a číslice v cenách jsou taky
   design — bez tohohle by nesly výchozí modrou a šedou prohlížeče. */
::selection { background: rgba(197, 160, 89, .32); color: var(--ink); }
input, textarea, select { caret-color: var(--gold); accent-color: var(--gold); }
html { scrollbar-color: var(--copper) var(--cream-mid); }
a { text-underline-offset: .18em; text-decoration-thickness: 1px; }
.prices dd, .bigprice, .stat__num { font-variant-numeric: tabular-nums lining-nums; }

/* Kreslené ikony (SVG přímo v HTML). Nahradily znaky ✆ ✉ ◷ ⌂ ☎,
   které každý systém kreslí jiným písmem a jinou tloušťkou. Tah 1,7
   je stejný jako u ikony pobočky v hlavičce. */
.ico {
  flex: none;
  display: inline-block;
  width: 1.15em;
  height: 1.15em;
  vertical-align: -.2em;
}

/* ---------- Formuláře: odeslání ----------
   Varianta potvrzení (odesláno / předvyplněný e-mail) drží stejný
   rytmus jako panel kolem ní, viz ukazPotvrzeni() v main.js. */
[data-pro] { display: flex; flex-direction: column; gap: var(--s2); }
[data-pro][hidden] { display: none; }
/* Past na roboty — mimo obrazovku, ne display:none (to roboti poznají). */
.hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.btn[aria-busy="true"] { cursor: progress; opacity: .72; }

.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 100;
  padding: var(--s2) var(--s3);
  background: var(--gold);
  color: #fff;
  font-weight: 600;
}
.skip-link:focus { left: var(--s2); top: var(--s2); }

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* ---------- Keyframes ---------- */
@keyframes heroRise { from { opacity: 0; transform: translateY(32px); } to { opacity: 1; transform: none; } }
/* menuDrop je pryč — menu pod hamburgerem už nejede na animaci,
   ale na přechodu, aby mělo i zavírání (viz .hdr__nav v branch.css). */
@keyframes floatY   { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-24px); } }
@keyframes lineGrow { from { transform: scaleX(0); } to { transform: scaleX(1); } }
/* Býval tu promoSweep — diagonální záblesk přejíždějící promo lištu.
   Odstraněn s ní: přejíždějící lesk přes proužek je značka výprodeje
   a na tenhle web nepatří. Viz .promo v branch.css. */

/* =========================================================
   Layout
   ========================================================= */

/* Full-width band whose content sits on the 1280px column. */
.section {
  padding: var(--s13) var(--edge) 0;
}

/* The 16-column grid itself. Children span columns via --span. */
.grid {
  display: grid;
  grid-template-columns: repeat(var(--columns), minmax(0, 1fr));
  gap: var(--gutter);
}
.grid > * { grid-column: span var(--span, 16); }

/* Images degrade to a woven-stripe placeholder if the file is missing,
   so the layout never collapses into a blank box. */
.bg-img {
  background-image: var(--img), var(--stripe);
  background-position: center, 0 0;
  background-size: cover, auto;
  background-repeat: no-repeat, repeat;
}

/* ---------------------------------------------------------
   Fotky, které ještě nedorazily

   Pruhovaná záloha výš udrží tvar stránky, ale člověku, který fotky
   teprve doplňuje, neřekne nic. Na rozestavěné pobočce potřebuje vidět
   dvě věci: kam snímek přijde a jak se má soubor jmenovat.

   initPlaceholders() v main.js proto zkusí každou fotku načíst, a když
   chybí, dá jejímu rámu .is-ph a do data-ph jméno souboru, na který se
   čeká. Nic se nepíše do HTML ručně — jméno se bere z cesty, která tam
   už stojí. Jakmile soubor s tím jménem existuje, obrázek se načte,
   .is-ph se vůbec nepřidá a rámeček zmizí sám.

   Proto tu není žádné „až budou fotky, smaž tenhle blok": nemá co
   mazat, sám se odmlčí.
   --------------------------------------------------------- */
.is-ph { position: relative; }
.is-ph::after {
  content: "FOTO · " attr(data-ph);
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--s2);
  /* Zalomí i dlouhý název souboru, aby nepřetekl z úzké kartičky. */
  overflow-wrap: anywhere;
  text-align: center;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 13px;
  line-height: 1.5;
  letter-spacing: .02em;
  color: #7D5630;
  /* Skoro neprůhledná krémová, ne poloprůhledná: hero fotky mají nad
     sebou tmavý scrim a přes něj by se světlejší štítek nepřečetl. */
  background: rgba(246, 240, 227, .94);
  box-shadow: inset 0 0 0 2px rgba(198, 161, 91, .85);
}
/* V drobných dlaždicích (ikony postupu, loga plateb) by se název
   souboru stejně nevešel — zůstane jen rámeček. */
@media (max-width: 480px) {
  .is-ph::after { font-size: 11px; }
}

/* Hero fotky a spodní CTA pruh nesou bílý text. Krémový štítek by pod
   ním zmizel a půlka stránky by se četla jako bílá na bílé — dokud
   fotka chybí, drží tyhle rámy tmavou plochu, na které nadpis zůstane
   čitelný. Rozdíl je jen v barvě: rámeček i název souboru sedí stejně. */
.hero__bg.is-ph::after,
.mhero__bg.is-ph::after,
.ohero__bg.is-ph::after,
.phero__bg.is-ph::after,
.khero__bg.is-ph::after,
.fhero__bg.is-ph::after,
.cta__bg.is-ph::after,
.duo__bg.is-ph::after {
  /* Zarovnat dolů, aby cedule nekolidovala s nadpisem uprostřed. */
  align-items: flex-end;
  padding-bottom: var(--s4);
  color: rgba(246, 240, 227, .82);
  background: var(--hero-dark);
  box-shadow: inset 0 0 0 2px rgba(198, 161, 91, .5);
}

/* Two decorative utilities used to live here and both are gone.

   .section--ornament was a hairline broken by a small lotus diamond,
   sitting above a section heading to mark a change of subject. On the
   built pages it never did that job: the sections it landed on already
   announce themselves with a heading, so the ornament read as a spacer
   someone forgot to remove.

   .section--wash was a very low contrast warm radial meant to stop long
   cream stretches reading as flat printer paper. On a real screen it did
   the opposite — it read as a seam where one section met the next.

   The page is one flat cream from top to bottom, and sections are told
   apart by their own headings.
   ========================================================= */

/* =========================================================
   Type primitives
   ========================================================= */
.h2 {
  font-family: var(--font-serif);
  font-weight: 400;
  font-size: 44px;
  line-height: var(--lh5);
  color: var(--ink);
}
.h2--onDark { color: #fff; }

/* Czech typography, part two: no lone word on a line.
   One-letter prepositions are glued to the next word in JS (initTypography);
   these keep headings evenly balanced and stop a single word from wrapping
   alone onto the last line. Ignored by browsers without text-wrap support,
   which then simply fall back to normal wrapping.

   BOUND TO ELEMENTS, NOT CLASSES, and deliberately so. This used to be two
   lists of class names — .h2, .hero__title, .mcard__name and a handful of
   ledes — written while the homepage was the only page that existed. The
   other five pages were built afterwards and nobody went back to extend
   the lists, so every one of their 60px headlines wrapped unprotected:
   "Devět let opravdové thajské / péče" on O nás was the visible one, and
   the section titles and ledes on Pro firmy, Masáže, Poukazy and Kontakt
   were in the same state.

   A list of class names is a list that has to be maintained; h1/h2/h3/p
   is a rule that cannot fall behind. The only additions are the three
   display elements on this site that are not headings or paragraphs. */
h1, h2, h3,
.qa__q { text-wrap: balance; }

p, li, dd, blockquote { text-wrap: pretty; }

/* Bylo tu .eyebrow — drobný zlatý nadpisek nad nadpisem, verzálkami
   a s vlasovou linkou vedle. Stál nad tři desítky sekcí a pokaždé jen
   jinými slovy zopakoval, co říká nadpis pod ním. Zůstal samotný .rule,
   který se dá postavit kamkoliv bez toho textu. */

.rule { display: block; width: 64px; height: 1px; background: var(--gold); }

/* Buttons — 56px tall, all padding on the 8px scale. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 56px;
  padding: var(--s2) var(--s4);
  border-radius: 9999px;
  font-size: 16px;
  line-height: var(--lh2);
  text-align: center;
  text-transform: uppercase;
  transition: background .3s var(--ease-out), color .3s var(--ease-out),
              transform .25s var(--ease-out), box-shadow .3s var(--ease-out),
              border-color .3s var(--ease-out);
}
/* Every button settles 1px into the page when pressed — a small physical
   acknowledgement that costs nothing and makes taps feel answered. */
.btn:active { transform: translateY(1px); }

.btn--gold {
  background: var(--gold);
  color: #fff;
  font-weight: 600;
}
/* Warms toward copper on hover. No glow behind it — the primary CTA sits
   on photographs as often as on cream, and a soft gold shadow read as a
   blur around the pill rather than as light. */
.btn--gold:hover {
  background: var(--copper);
  color: #fff;
}
.btn--ghostLight {
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .8);
  color: rgba(255, 255, 255, .92);
  font-weight: 600;
}
.btn--ghostLight:hover { background: rgba(255, 255, 255, .12); color: #fff; }

.btn--ghostBrown,
.btn--ghostBrownSoft {
  color: var(--brown);
  font-weight: 600;
}
.btn--ghostBrown { box-shadow: inset 0 0 0 1px var(--brown); }
.btn--ghostBrownSoft { box-shadow: inset 0 0 0 1px rgba(125, 86, 48, .45); }
.btn--ghostBrown:hover,
.btn--ghostBrownSoft:hover { background: var(--brown); color: var(--surface); }

/* ---------------------------------------------------------
   Button arrow
   Drawn as a mask so it inherits the button's text colour and can be
   swapped for one of the gold Thai vectors by changing --arrow alone:

       :root { --arrow: url('../assets/ostrava/home/svg/Vector-64.svg'); }

   The shaft tapers and the head is a slim double chevron — closer to
   the pointed finials in the vector set than a plain →.
   --------------------------------------------------------- */
:root {
  --arrow: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 28 12'%3E%3Cpath d='M1 6h19M15.5 1.5 20.5 6l-5 4.5M20.5 2.8 24.2 6l-3.7 3.2' fill='none' stroke='%23000' stroke-width='1.3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

.btn--arrow { gap: var(--s2); }
.btn--arrow::after {
  content: "";
  flex: none;
  width: 28px;
  height: 12px;
  background: currentColor;
  -webkit-mask: var(--arrow) center / contain no-repeat;
          mask: var(--arrow) center / contain no-repeat;
  transition: transform .35s var(--ease);
}
.btn--arrow:hover::after { transform: translateX(6px); }

.price-note {
  font-family: var(--font-ui);
  font-size: 13px;
  line-height: var(--lh2);
  color: var(--muted);
}

/* =========================================================
   Card lift — jedna hover smlouva pro klikatelné karty

   Karty se původně zvedaly o -8px, -6px a -4px se třemi různými stíny
   a délkami, což z webu dělalo tři weby. Gesto je teď všude stejné;
   stránkový styl si smí přidat vlastní akcent (barvu rámečku, přiblížení
   fotky), ale transform ani délku už nepřepisuje.

   V seznamu jsou jen karty, ve kterých je co zmáčknout: .mcard vede na
   rezervaci, .need na kotvy s masážemi. Zvednutí je slib akce — na
   kartě, která nikam nevede, je to slib naprázdno. Proto z něj odešly
   .tcard (masérka) i .giftee (pro koho je poukaz) a proto ho nikdy
   nedostaly řádky .why__item, kroky .step / .pstep, .review, .tip,
   .ocard, .vshot ani .paylogo.
   ========================================================= */
.mcard,
.need {
  transition: transform var(--lift-speed) var(--ease-out),
              box-shadow var(--lift-speed) var(--ease-out),
              border-color var(--lift-speed) var(--ease-out);
}
.mcard:hover,
.need:hover,
.mcard:focus-within,
.need:focus-within {
  transform: translateY(var(--lift));
  box-shadow: var(--shadow-2);
}

/* Hover lift is a pointer affordance. On touch there is no hover, and
   sticky :hover after a tap leaves cards stranded mid-lift. */
@media (hover: none) {
  .mcard:hover,
  .need:hover {
    transform: none;
    box-shadow: none;
  }
}

/* =========================================================
   Animated underline for links inside running copy

   Scoped to prose containers so it never touches nav links, buttons or
   cards-wrapped-in-an-anchor. The rule is drawn with a pseudo-element
   rather than text-decoration so it can grow from the left; it starts
   visible at 40% opacity so the link is still obviously a link before
   you hover it — a purely hover-revealed underline hides affordance
   from exactly the readers who need it most.
   ========================================================= */
.sec-head__lede a,
.sec-head__note a,
.split__text a,
.qa__a a,
.owner__text a {
  position: relative;
  color: var(--brown);
  text-decoration: none;
}
.sec-head__lede a::after,
.sec-head__note a::after,
.split__text a::after,
.qa__a a::after,
.owner__text a::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: -2px;
  height: 1px;
  background: currentColor;
  opacity: .4;
  transform: scaleX(1);
  transform-origin: left;
  transition: opacity .25s var(--ease-out), transform .35s var(--ease-out);
}
.sec-head__lede a:hover::after,
.sec-head__note a:hover::after,
.split__text a:hover::after,
.qa__a a:hover::after,
.owner__text a:hover::after,
.sec-head__lede a:focus-visible::after,
.split__text a:focus-visible::after {
  opacity: 1;
  /* Redraw from the left rather than just fading — reads as a stroke. */
  animation: underlineWipe .35s var(--ease-out);
}
@keyframes underlineWipe { from { transform: scaleX(0); } to { transform: scaleX(1); } }

/* Section headings */
.sec-head { display: flex; flex-direction: column; gap: var(--s2); max-width: 800px; }
.sec-head--center { align-items: center; text-align: center; max-width: 100%; }
.sec-head--split {
  flex-direction: row;
  justify-content: space-between;
  align-items: flex-end;
  gap: var(--s5);
  max-width: 100%;
}
.sec-head__left { display: flex; flex-direction: column; gap: var(--s1); max-width: 600px; }
.sec-head__note,
.sec-head__lede { max-width: 600px; color: var(--body); }

/* =========================================================
   Hero craft layer — warm gradient + lotus ornament

   Two static additions and one almost-invisible animation:

   ::before  a warm bottom-weighted gradient. Every hero puts light text
             on a photograph, and photographs change brightness as they
             load and as art direction changes. This guarantees the floor
             of contrast rather than trusting the image.
   ::after   a thin gold lotus ornament, drawn once as an inline SVG so
             it costs no request and inherits no colour surprises.

   The ornament breathes over 8s: opacity .30 -> .46 and a 4px rise. That
   is slow enough to sit below the threshold of attention — you notice it
   only if you stop and look, which is the point. Nothing here moves on
   scroll, and neither layer ever sits above the text.
   ========================================================= */
:root {
  --lotus: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 240 56' fill='none' stroke='%23C5A059' stroke-width='1.2' stroke-linecap='round'%3E%3Cpath d='M4 44h80M156 44h80'/%3E%3Cpath d='M120 45c-9-11-13-22 0-35 13 13 9 24 0 35Z'/%3E%3Cpath d='M120 45c-15-4-25-12-29-25 15 3 25 13 29 25Z'/%3E%3Cpath d='M120 45c15-4 25-12 29-25-15 3-25 13-29 25Z'/%3E%3Ccircle cx='120' cy='50' r='2'/%3E%3C/svg%3E");
}

.hero, .ohero, .mhero, .khero, .fhero { position: relative; }

/* Gradient: only the four heroes that set light text on a photograph.
   .khero and .phero are cream-on-cream and .rhero has the branch cards
   pulled up over its foot — a dark wash on any of those would be damage,
   not polish. */
.hero::before, .ohero::before, .mhero::before, .fhero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background: linear-gradient(to top,
    rgba(31, 22, 13, .42) 0%,
    rgba(31, 22, 13, .10) 38%,
    rgba(31, 22, 13, 0) 70%);
}

/* Ornament: skipped on .phero (two-column grid — it would land on the
   artwork), .rhero (its foot is covered by the branch cards) and .mhero
   (it ends in a numbered section-nav strip that runs the full width —
   there is no clear floor to sit on, and that strip is already the
   hero's craft detail).

   Also dropped from .ohero: the hero there already carries a gold
   hairline of its own, and the lotus below repeated it a second time
   inside one screen. */
.hero::after, .khero::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: var(--s5);
  z-index: 1;
  width: 200px;
  height: 48px;
  pointer-events: none;
  background: var(--lotus) center / contain no-repeat;
  opacity: .3;
  transform: translate(-50%, 0);
  animation: lotusBreath 8s ease-in-out infinite;
}
/* Per-hero clearance — .khero leaves 96px below its last element. */
.khero::after {
  bottom: var(--s3);
  /* On cream the same gold needs to sit back further to stay a whisper. */
  opacity: .22;
  animation-name: lotusBreathLight;
}

@keyframes lotusBreath {
  0%, 100% { opacity: .30; transform: translate(-50%, 0); }
  50%      { opacity: .46; transform: translate(-50%, -4px); }
}
@keyframes lotusBreathLight {
  0%, 100% { opacity: .22; transform: translate(-50%, 0); }
  50%      { opacity: .34; transform: translate(-50%, -4px); }
}

/* Hero copy must outrank both decorative layers. The photo/scrim layers
   keep z-index auto (or negative, on .ohero) and so stay underneath. */
.hero__inner, .ohero__inner, .mhero__inner, .fhero__inner, .phero__body { position: relative; z-index: 2; }
/* .khero and .rhero have no inner wrapper — their copy is a direct child.
   On the photo variant of .khero the background/scrim are also direct
   children, so exclude them or they'd be lifted over the text too. */
.khero > *:not(.khero__bg):not(.khero__scrim),
.rhero > *:not(.rhero__fade) { position: relative; z-index: 2; }

/* Short viewports: the ornament would collide with the headline block. */
@media (max-height: 640px), (max-width: 640px) {
  .hero::after, .khero::after { display: none; }
}

/* =========================================================
   Stat trio / quartet (hero on branch pages and rozcestník)
   ========================================================= */
.stats { display: flex; flex-wrap: wrap; gap: var(--s5); padding: var(--s1) 0; }
.stat {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: var(--s1);
  min-width: 128px;
}
.stat__value { display: flex; align-items: baseline; justify-content: center; gap: var(--s1); }
/* 44px, not the 64px this used to be. At 64 the figures were the same
   size as the h1 above them and the hero had two headlines fighting for
   the same job — and Lora's figures, which replaced Cormorant's narrow
   ones, made that worse. A statistic is supporting evidence: it should
   be read after the headline, not instead of it. */
.stat__num {
  font-family: var(--font-num);
  font-weight: 400;
  font-size: 44px;
  line-height: var(--lh5);
  letter-spacing: -.5px;
  color: var(--gold);
}
.stat__num--sm { font-size: 40px; }
.stat__unit {
  font-family: var(--font-num);
  font-size: 20px;
  line-height: var(--lh3);
  color: var(--gold);
}
.stat__label {
  font-weight: 500;
  font-size: 14px;
  line-height: var(--lh1);
  letter-spacing: 2px;
  text-align: center;
  color: rgba(255, 255, 255, .92);
  text-transform: uppercase;
}

/* =========================================================
   Scroll-reveal (progressive enhancement — see js/main.js)

   Deliberately understated: 16px of travel over 600ms. The earlier
   32px/900ms version read as content "flying in" — at reading distance
   the eye tracks the movement instead of the words, which is exactly
   wrong for an older audience. This is a settle, not an entrance.

   Stagger delay is written to --reveal-delay by main.js, so the wait
   happens in the compositor rather than a setTimeout per element.
   ========================================================= */
.js [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity .6s var(--ease-out) var(--reveal-delay, 0ms),
              transform .6s var(--ease-out) var(--reveal-delay, 0ms);
  will-change: opacity, transform;
}
.js [data-reveal].is-visible { opacity: 1; transform: none; }
/* Drop the hint once the element has landed — a permanent will-change
   on dozens of nodes keeps them on their own layer for the whole session. */
.js [data-reveal].is-settled { will-change: auto; }

/* =========================================================
   Draw-in hairlines

   Every decorative rule on the site is a 1px line whose whole job is to
   say "a new thought starts here". Painted instantly it is just a
   border. Drawn left→right as its block lands it reads as a stroke
   somebody made. Contract for every hairline on the site: .rule and
   (in branch.css) the .split__frame.

   Hung off the reveal system rather than its own scroll listener, for
   two reasons. A line then cannot draw itself before the heading it
   belongs to has arrived, and it inherits that block's stagger through
   --reveal-delay for free — in a [data-stagger] group the rules come in
   one after another, in step with their rows.

   --rule-delay is the head start the copy gets before the line follows
   it. Long enough that the two are read as one gesture rather than a
   race; short enough that nobody waits for it.
   ========================================================= */
:root { --rule-delay: 220ms; }

.js [data-reveal] .rule {
  transform: scaleX(0);
  transform-origin: left;
}
.js [data-reveal].is-visible .rule {
  animation: lineGrow .9s var(--ease-out)
             calc(var(--reveal-delay, 0ms) + var(--rule-delay)) forwards;
}

/* =========================================================
   Responsive — type steps down, line-heights stay on the 8px grid
   ========================================================= */
@media (max-width: 1180px) {
  .h2 { font-size: 40px; line-height: var(--lh5); }
}

@media (max-width: 860px) {
  :root { --margin: 40px; }
  .h2 { font-size: 32px; line-height: var(--lh4); }
  .sec-head--split { flex-direction: column; align-items: flex-start; gap: var(--s2); }
  .stats { gap: var(--s4); }
}

@media (max-width: 640px) {
  :root { --margin: 24px; }

  .h2 { font-size: 28px; line-height: var(--lh4); }

  /* Nine headings across the site carry a hard <br> — "Darujte chvíle<br>
     skutečného odpočinku" and friends. That is art direction for a wide
     screen, where the author picked the better of two possible splits.
     On a phone the same break fights the balancer: the forced first line
     is locked, the rest wraps again underneath it, and a two-line
     heading becomes three with a word alone at the bottom. Below this
     width the break steps aside and text-wrap: balance does the job it
     was added for. Addresses in <dd> keep their breaks — those are real
     line breaks in a postal address, not typography.

     POZOR PŘI PSANÍ NADPISŮ: před <br> musí v HTML být mezera, tedy
     "Darujte chvíle <br>skutečného odpočinku". Zalomení totiž tenhle
     řádek jen skryje, nenahradí ho mezerou — bez ní se slova na mobilu
     slepí ("Darujte chvíleskutečného odpočinku"). Na širokém displeji
     se mezera na konci řádku sbalí, takže tam nezmění vůbec nic.
     Takhle bylo rozbitých všech osmnáct nadpisů na webu. */
  h1 br, h2 br { display: none; }

  .btn { width: 100%; padding: var(--s2) var(--s3); }
  .price-note { width: 100%; text-align: center; }

  .stats { gap: var(--s3); }
  .stat { min-width: 0; flex: 1 1 calc(50% - var(--s2)); }
  .stat__num { font-size: 36px; line-height: var(--lh5); }
  .stat__num--sm { font-size: 32px; }
  .stat__label { font-size: 12px; letter-spacing: 1.68px; }

  .section { padding-top: var(--s8); }
}

/* =========================================================
   Reduced motion
   ========================================================= */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
    /* Without this, a staggered element would still sit out its
       --reveal-delay before appearing — a pause with no motion to
       explain it, which is worse than the animation was. */
    transition-delay: 0ms !important;
    animation-delay: 0ms !important;
  }
  .js [data-reveal] { opacity: 1; transform: none; }

  /* Hairlines are simply there. The global animation-duration override
     above would land them at full width anyway, but only once the
     animation had been applied — this holds regardless. */
  .js [data-reveal] .rule { transform: none; }

  /* The lotus stops breathing and simply rests at its base opacity. */
  .hero::after, .khero::after { animation: none; }
}
