@font-face{font-family:"Kenao";src:url(/fonts/kenao.woff2) format("woff2");font-weight:400 700;font-display:swap}
@font-face{font-family:"Cormorant";font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/cormorant-500-cyrillic.woff2) format("woff2");unicode-range:U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116}
@font-face{font-family:"Cormorant";font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/cormorant-500-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"Cormorant";font-style:normal;font-weight:500;font-display:swap;src:url(/fonts/cormorant-500-latin.woff2) format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}
@font-face{font-family:"DM Sans";font-style:normal;font-weight:400 500;font-display:swap;src:url(/fonts/dmsans-400-500-latin-ext.woff2) format("woff2");unicode-range:U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF}
@font-face{font-family:"DM Sans";font-style:normal;font-weight:400 500;font-display:swap;src:url(/fonts/dmsans-400-500-latin.woff2) format("woff2");unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD}

:root{
  --radius-sm:10px;--radius-md:18px;--radius-lg:26px;--radius-pill:100px;
  /* 3rem gutters hold up to ~1496px, so nothing shifts on a laptop; past that
     the content centres instead of stretching across a 27" monitor */
  --container:1400px;--gutter:3rem;
  --pad-x:max(var(--gutter), calc((100% - var(--container)) / 2));
}
*{margin:0;padding:0;box-sizing:border-box}
/* any class rule with a display beats the UA sheet's [hidden] — this is
   why a hidden .btn-primary was still on screen */
[hidden]{display:none!important}
html{scroll-behavior:smooth}
body{background:var(--paper);color:var(--ink);font-family:var(--font-body);font-weight:400;overflow-x:hidden}

nav{position:fixed;top:0;left:0;right:0;z-index:100;padding:1.1rem var(--pad-x);display:flex;justify-content:space-between;align-items:center;background:rgb(var(--plate-rgb) / 0.7);backdrop-filter:blur(20px);-webkit-backdrop-filter:blur(20px);border-bottom:1px solid rgb(var(--line-rgb) / 0.15);transition:background 0.3s,border-color 0.3s}
/* :not(.mobile-menu) — как и у правила для hero ниже: шторка бургера тоже <nav>,
   и это правило (0,1,1) перебивало её собственный фон (0,1,0). При прокрутке
   меню открывалось полупрозрачным, сквозь него просвечивали фото и цены. */
body.nav-solid nav:not(.mobile-menu){background:rgb(var(--plate-rgb) / 0.95)}
.nav-logo{display:flex;align-items:center;text-decoration:none}
.nav-logo-img{height:38px;width:auto;object-fit:contain;display:block}
/* Studios without wordmark artwork set their name in the display face instead;
   it follows the same light/solid nav treatment as the image logo below. */
.nav-logo-word{font-family:var(--font-display);font-size:1.6rem;line-height:1;letter-spacing:0.06em;color:var(--ink)}
.nav-links{display:flex;gap:2rem;list-style:none}
.nav-links a{color:var(--ink-soft);text-decoration:none;font-size:0.78rem;letter-spacing:0.08em;text-transform:uppercase;transition:color 0.2s}
.nav-links a:hover{color:var(--purple-900)}
.nav-cta{background:var(--purple-cta);border:1px solid var(--purple-cta);color:var(--on-accent-alt);padding:0.55rem 1.6rem;font-family:var(--font-body);font-size:0.75rem;letter-spacing:0.08em;text-transform:uppercase;cursor:pointer;transition:all 0.3s;border-radius:var(--radius-pill)}
.nav-cta:hover{background:var(--accent-lift);border-color:var(--accent-lift)}
.lang-toggle{display:flex}
.lang-btn{text-decoration:none;display:inline-flex;align-items:center;background:transparent;border:1px solid var(--line-strong);color:var(--ink-soft);padding:0.35rem 0.9rem;font-family:var(--font-body);font-size:0.7rem;cursor:pointer;transition:all 0.2s}
.lang-btn:first-child{border-radius:var(--radius-pill) 0 0 var(--radius-pill)}
.lang-btn:last-child{border-radius:0 var(--radius-pill) var(--radius-pill) 0;border-left:none}
.lang-btn.active{background:var(--accent-lift);border-color:var(--accent-lift);color:var(--on-accent-alt)}

/* ── Обратно к выбору студии ──────────────────────────────────────────────
   Домен один, студий на нём две, и с лендинга обязан быть путь назад к
   плитке — иначе человек, попавший на Шафран из рекламы, про Яшу не узнает.

   Ссылка стоит рядом с логотипом ВНУТРИ .nav-brand, а не шестым ребёнком
   <nav>: у панели justify-content:space-between, и отдельный флекс-ребёнок
   уехал бы от логотипа на треть экрана. Обёртка безопасна и на мобильном:
   там .nav-home скрыт, и в .nav-brand остаётся один логотип — раскладка
   панели не меняется ни на пиксель.

   Между 901 и 1150px рельса пунктов уже стоит впритык (медиазапрос ниже
   ужимает её ради русских подписей), поэтому там от ссылки остаётся кружок
   со стрелкой. Подпись прячется, а не сокращается: aria-label на самой
   ссылке в разметке обязателен и стоит всегда.
   Ниже 901px пункты уезжают в шторку, и ссылку там заменяет .mm-home. */
.nav-brand{display:flex;align-items:center;gap:0.7rem;min-width:0}
.nav-home{display:inline-flex;align-items:center;justify-content:center;gap:0.5rem;
  flex:0 0 auto;height:32px;padding:0 0.9rem;border-radius:var(--radius-pill);
  border:1px solid var(--line-strong);background:transparent;color:var(--ink-soft);
  text-decoration:none;font-size:0.68rem;letter-spacing:0.12em;text-transform:uppercase;
  transition:color 0.2s,border-color 0.2s}
/* Стрелка нарисована рамками, а не глифом ← и не эмодзи: символ подменяется
   системным шрифтом и прыгает по базовой линии — тот же довод, что у галочки
   в блоке «что входит». */
.nav-home::before{content:"";width:6px;height:6px;flex:0 0 6px;
  border-left:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:rotate(45deg);transition:transform 0.25s}
/* --purple-900, а не --purple-600: у Яши шестисотый — это #9d7ed5, 3.29:1
   по белой бумаге. Тем же токеном красится ховер .nav-links a выше, так что
   это ещё и одна подсветка на всю панель. */
.nav-home:hover{color:var(--purple-900);border-color:var(--purple-900)}
.nav-home:hover::before{transform:rotate(45deg) translate(-2px,2px)}
.nav-home:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
@media(max-width:1150px){.nav-home{width:32px;padding:0;gap:0}
  .nav-home .nav-home-txt{display:none}}
@media(max-width:900px){.nav-home{display:none}}

/* Отступ героя ни от чего не зависит и ничего не ждёт. До 11.09 он подрастал
   на высоту куки-баннера через `--consent-h`: баннер стоял `position:fixed` у
   нижнего края, контент героя выровнен по тому же краю, и на айфоне баннер
   накрывал кнопку «Забронировать» целиком (замер 28.08). Теперь вопрос задаёт
   окно по центру — накрывать кнопку нечему, и измерять нечего. */
#hero{min-height:100vh;display:flex;flex-direction:column;justify-content:flex-end;padding:0 var(--pad-x) 5rem;position:relative;overflow:hidden;background:var(--paper);color:var(--ink)}
.hero-bg{position:absolute;inset:0;background:var(--hero-glow),var(--paper)}
.hero-grid-overlay{position:absolute;inset:0;background-image:linear-gradient(rgb(var(--line-rgb) / 0.08) 1px,transparent 1px),linear-gradient(90deg,rgb(var(--line-rgb) / 0.08) 1px,transparent 1px);background-size:60px 60px}
.hero-content{position:relative;z-index:2}
.hero-tag{display:inline-block;font-size:0.7rem;letter-spacing:0.18em;text-transform:uppercase;color:var(--purple-900);border:1px solid var(--line-strong);padding:0.4rem 1.1rem;border-radius:var(--radius-pill);margin-bottom:1.5rem;background:rgb(var(--line-rgb) / 0.07)}
.hero-title{font-family:var(--font-display);font-size:clamp(4rem,10vw,9rem);font-weight:500;line-height:0.95;margin-bottom:1rem;color:var(--ink)}
.hero-title em{font-style:normal;color:var(--accent-display)}
.hero-subtitle{font-size:0.95rem;color:var(--ink-soft);max-width:400px;line-height:1.75;margin-bottom:2.5rem}
.hero-actions{display:flex;gap:1rem;align-items:center}
.btn-primary{background:var(--purple-cta);color:var(--on-accent);border:1px solid var(--purple-cta);padding:0.85rem 2.2rem;font-family:var(--font-body);font-size:0.8rem;letter-spacing:0.1em;text-transform:uppercase;cursor:pointer;transition:all 0.3s;border-radius:var(--radius-pill);text-decoration:none;display:inline-block}
.btn-primary:hover{background:var(--accent-lift);border-color:var(--accent-lift);transform:translateY(-1px)}
.btn-ghost{background:transparent;color:var(--ink-soft);border:none;padding:0.85rem 0;font-family:var(--font-body);font-size:0.8rem;letter-spacing:0.1em;text-transform:uppercase;cursor:pointer;transition:color 0.2s;text-decoration:none}
.btn-ghost:hover{color:var(--ink)}
.btn-ghost.on-light{color:var(--ink-soft)}
.btn-ghost.on-light:hover{color:var(--ink)}
.hero-scroll{position:absolute;bottom:2.5rem;right:3rem;display:flex;flex-direction:column;align-items:center;gap:0.5rem;z-index:2}
.hero-scroll span{font-size:0.65rem;letter-spacing:0.2em;text-transform:uppercase;color:var(--ink-dim);writing-mode:vertical-rl}
.scroll-line{width:1px;height:60px;background:linear-gradient(to bottom,var(--accent-display),transparent);animation:scrollDown 2s ease-in-out infinite}
@keyframes scrollDown{0%{transform:scaleY(0);transform-origin:top;opacity:1}50%{transform:scaleY(1);transform-origin:top;opacity:1}100%{transform:scaleY(1);transform-origin:bottom;opacity:0}}

section{padding:6rem var(--pad-x)}
.section-label{font-size:0.65rem;letter-spacing:0.22em;text-transform:uppercase;color:var(--purple-pale-text);margin-bottom:1rem;font-weight:500}
.section-title{font-family:var(--font-display);font-size:clamp(2.5rem,5vw,4.2rem);font-weight:500;line-height:1.06;margin-bottom:1.5rem;color:var(--ink)}
.section-title em{font-style:normal;color:var(--accent-display)}
.divider{width:40px;height:2px;background:var(--accent-display);margin:1rem 0 1.5rem;border-radius:2px}

/* ── Hero media plumbing. The markup ships in every build; without these
   rules the slides render as eleven stacked full-width images and the
   hero grows to ~11000px. Variant styling is in hero.css (preview). ── */
/* ── Shared plumbing ───────────────────────────────────────────────────── */
.hero-media {
  position: absolute;
  inset: 0;
  z-index: 0;
  display: none;
}
.hero-slide {
  position: absolute;
  inset: 0;
  opacity: 0;
  transition: opacity 1.6s ease;
}
.hero-slide.is-active { opacity: 1; }
.hero-slide picture { display: block; width: 100%; height: 100%; }
.hero-slide img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transform-origin: center;
}
.hero-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  display: none;
}
.hero-content { z-index: 3; }
.hero-frames, .hero-focus { display: none; }

/* Slow push-in on whichever frame is showing. Restarts on every slide change
   because the rule hangs off .is-active. */
@keyframes heroDrift {
  from { transform: scale(1.005); }
  to   { transform: scale(1.085); }
}

/* ── Hero: full-bleed slideshow under a dark scrim ──────────────────────
   Full-bleed slideshow, dark diagonal scrim, white editorial type. The studio
   itself is the first thing you see. Highest impact, least "template". */
.hero-bg,
.hero-grid-overlay { opacity: 0; }
.hero-media,
.hero-scrim { display: block; }
.hero-slide.is-active img {
  animation: heroDrift 14s ease-out forwards;
}
.hero-scrim {
  background: var(--scrim-main), var(--scrim-bottom), var(--scrim-top);
}
.hero-title { color: var(--on-hero); }
.hero-title em { color: var(--on-hero-accent); }
.hero-subtitle { color: rgb(var(--on-hero-rgb) / 0.84); max-width: 430px; }
.hero-tag {
  color: var(--on-hero);
  border-color: rgb(var(--on-hero-rgb) / 0.42);
  background: rgb(var(--on-hero-rgb) / 0.10);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.btn-ghost { color: rgb(var(--on-hero-rgb) / 0.86); }
.btn-ghost:hover { color: var(--on-hero); }
.hero-scroll span { color: var(--on-hero-quiet); }
.scroll-line { background: linear-gradient(to bottom, var(--on-hero), transparent); }

/* Часы и нижняя цена под кнопками первого экрана. Жило в теме Шафрана, пока
   блок был только у него; теперь строка есть у обеих студий, и второй копии
   этих правил существовать не должно.
   Цвет — --on-hero-quiet, а не --ink-soft напрямую: текст лежит на скриме
   поверх фотографии, и роль здесь та же, что у индикатора прокрутки.
   Три правила идут подряд намеренно: у медиазапросов ниже та же
   специфичность, что у базы, поэтому побеждает порядок в файле. Разнести их
   по «своим» блокам @media в этом файле нельзя — блок 600px стоит ПОСЛЕ
   блока 420px и на узком экране отменил бы колонку. */
.hero-facts{display:flex;flex-wrap:wrap;gap:0.5rem 1.5rem;margin-top:1.5rem;
  font-size:0.78rem;letter-spacing:0.04em;color:var(--on-hero-quiet)}
.hero-facts span{display:inline-flex;align-items:center;gap:0.55rem}
.hero-facts span+span::before{content:"";width:4px;height:4px;border-radius:50%;
  background:var(--on-hero-accent)}
@media(max-width:600px){
  .hero-facts{gap:0.35rem 1rem;font-size:0.74rem}
}
/* Точка перед вторым фактом — разделитель ВНУТРИ строки. Когда факты в строку
   не помещаются и переносятся, она уезжает в начало новой строки и читается
   как висячий маркер списка. Раньше этого не было видно: колонка целиком
   уходила за левый край экрана вместе с точкой.
   На узком факты идут колонкой, и разделителем работает сам перенос строки.
   Порог 420px — не круглое число ради круглого: в одну строку факты Шафрана
   влезают от 368px на латышском и от 386px на русском, у Яши тексты короче,
   420 накрывает всех с запасом и уже используется как брейкпоинт здесь же.
   Если тексты фактов заметно удлинятся, порог придётся поднять — иначе точка
   снова повиснет. */
@media(max-width:420px){
  .hero-facts{flex-direction:column;align-items:flex-start;gap:0.35rem}
  .hero-facts span+span::before{display:none}
}

/* Nav sits over the photo until the page scrolls.
   :not(.mobile-menu) обязателен — шторка бургера тоже <nav>, и это правило
   (0,1,1) било её собственный фон (0,1,0). В начале страницы меню открывалось
   насквозь прозрачным поверх фотографии. */
body:not(.nav-solid) nav:not(.mobile-menu){background:transparent;border-bottom-color:transparent;
  backdrop-filter:none;-webkit-backdrop-filter:none}
@media(min-width:901px){
  body:not(.nav-solid) .nav-links a{color:rgb(var(--on-hero-rgb) / 0.82)}
  body:not(.nav-solid) .nav-links a:hover,
  body:not(.nav-solid) .nav-links a.is-current{color:var(--on-hero)}
  body:not(.nav-solid) .nav-links a.is-current::after{background:var(--on-hero)}
  body:not(.nav-solid) .lang-btn{color:rgb(var(--on-hero-rgb) / 0.82);border-color:rgb(var(--on-hero-rgb) / 0.35)}
  body:not(.nav-solid) .lang-btn.active{background:var(--accent-lift);border-color:var(--accent-lift);color:var(--on-accent)}
  /* та же логика, что у переключателя языка: над фотографией подпись
     светлеет вместе со всей панелью */
  body:not(.nav-solid) .nav-home{color:rgb(var(--on-hero-rgb) / 0.82);border-color:rgb(var(--on-hero-rgb) / 0.35)}
  body:not(.nav-solid) .nav-home:hover{color:var(--on-hero);border-color:rgb(var(--on-hero-rgb) / 0.6)}
}
@media(max-width:900px){
  body:not(.nav-solid) .nav-burger span{background:var(--on-hero)}
  body:not(.nav-solid) .nav-burger{border-color:rgb(var(--on-hero-rgb) / 0.45)}
  /* только переключатель в верхней панели: в шторке бургера фон светлый,
     и белые буквы на нём пропадали */
  body:not(.nav-solid) .lang-toggle .lang-btn{color:rgb(var(--on-hero-rgb) / 0.85);border-color:rgb(var(--on-hero-rgb) / 0.35)}
}
body:not(.nav-solid) .nav-logo-img{filter:brightness(0) invert(1)}
body:not(.nav-solid) .nav-logo-word{color:var(--on-hero)}

@media(prefers-reduced-motion:reduce){
  .hero-slide{transition:none}
  .hero-slide.is-active img{animation:none}
}

#halls{background:var(--paper);position:relative;overflow:hidden}
.halls-header{display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:3.5rem}
.halls-intro{font-size:0.9rem;color:var(--ink-soft);max-width:320px;line-height:1.8}
.halls-grid{display:grid;grid-template-columns:1fr 1fr;gap:1.75rem}
.hall-card{background:var(--card-grad);border:1px solid var(--line);border-radius:var(--radius-lg);overflow:hidden;transition:border-color 0.3s,transform 0.3s,box-shadow 0.3s;box-shadow:0 18px 40px -20px rgb(var(--shadow-tint) / 0.18)}
.hall-card:hover{border-color:var(--purple-light);transform:translateY(-5px);box-shadow:0 26px 50px -18px rgb(var(--shadow-tint) / 0.28)}
.hall-img{width:100%;aspect-ratio:4/3;position:relative;overflow:hidden;display:flex;align-items:center;justify-content:center;background:var(--placeholder-grad)}
.hall-slideshow{position:relative;overflow:hidden}
.hall-slideshow .slide{position:absolute;inset:0;opacity:0;transition:opacity 1s ease;background-size:cover;background-position:center}
.hall-slideshow .slide.active{opacity:1}
.hall-slideshow .slide picture{display:block;position:absolute;inset:0}
.hall-slideshow .slide img{width:100%;height:100%;object-fit:cover;display:block}
.slide-dots{position:absolute;bottom:0.9rem;left:50%;transform:translateX(-50%);display:flex;gap:0.4rem;z-index:3;background:rgb(var(--ink-rgb) / 0.3);backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);padding:0.4rem 0.6rem;border-radius:var(--radius-pill);align-items:center}
.dot{width:6px;height:6px;border-radius:50%;background:rgb(var(--on-media-rgb) / 0.55);cursor:pointer;transition:all 0.3s;border:none;padding:0}
.dot.active{background:var(--on-media);width:18px;border-radius:3px}
.hall-badge{position:absolute;top:1rem;left:1rem;background:rgb(var(--plate-rgb) / 0.8);border:1px solid rgb(var(--line-rgb) / 0.3);backdrop-filter:blur(10px);padding:0.35rem 0.9rem;font-size:0.6rem;letter-spacing:0.15em;text-transform:uppercase;color:var(--purple-900);border-radius:var(--radius-pill);z-index:4}
.hall-body{padding:1.85rem}
.hall-name{font-family:var(--font-display);font-size:1.9rem;font-weight:500;margin-bottom:0.5rem;color:var(--ink)}
.hall-name em{font-style:normal;color:var(--accent-display)}
.hall-desc{font-size:0.82rem;color:var(--ink-soft);line-height:1.7;margin-bottom:1.5rem}
.hall-tags{display:flex;flex-wrap:wrap;gap:0.5rem;margin-bottom:1.5rem}
.hall-tag{font-size:0.65rem;letter-spacing:0.08em;color:var(--purple-900);border:1px solid rgb(var(--line-rgb) / 0.3);padding:0.3rem 0.75rem;border-radius:var(--radius-pill);background:rgb(var(--line-rgb) / 0.08)}
.hall-equip{border-top:1px solid rgb(var(--line-rgb) / 0.2);padding-top:1.25rem}
.hall-equip-title{font-size:0.6rem;letter-spacing:0.2em;text-transform:uppercase;color:var(--ink-dim);margin-bottom:0.75rem}
.hall-equip-list{list-style:none;display:flex;flex-direction:column;gap:0.4rem}
.hall-equip-list li{font-size:0.78rem;color:var(--ink-soft);display:flex;align-items:center;gap:0.6rem}
.hall-equip-list li::before{content:"";width:4px;height:4px;border-radius:50%;background:var(--purple-light);flex-shrink:0}
.hall-cta{padding-top:1.5rem;border-top:1px solid rgb(var(--line-rgb) / 0.2);margin-top:1.5rem}
.btn-hall{width:100%;padding:0.75rem 1.5rem;background:transparent;border:1px solid var(--control-line);color:var(--purple-900);border-radius:var(--radius-pill);font-family:var(--font-body);font-size:0.78rem;letter-spacing:0.1em;text-transform:uppercase;cursor:pointer;transition:all 0.3s;display:flex;align-items:center;justify-content:center;gap:0.5rem}
.btn-hall::after{content:"→";transition:transform 0.3s}
.btn-hall:hover{background:var(--purple-cta);border-color:var(--purple-cta);color:var(--on-accent)}
.btn-hall:hover::after{transform:translateX(4px)}

/* ── Оборудование: плоская сетка карточек ─────────────────────────────────
   Один блок на обе студии. Приехал сюда из src/saffron/theme.css в тот
   момент, когда тот же блок понадобился Яше: пока правила лежали в теме,
   второй студии оставалось их скопировать — а копия расходится молча и
   ровно этим стоила Шафрану отдельного круга правок.

   Заливку карточки задаёт --equip-bg, а не литерал: «чуть светлее фона
   секции» у студий выражается разными цветами — бумага Яши #ffffff, бумага
   Шафрана #fdfaf4. Обе секции, где блок стоит (#halls и #studija), красятся
   var(--paper), поэтому тон подбирается к нему.

   Подписи записаны потомками .equip-card намеренно. Гейт контраста находит
   пару «текст × заливка» только тогда, когда автор сам сказал «B живёт
   внутри A»; одинокий .equip-name (так было в теме) не привязан ни к какой
   заливке и проезжал проверку вообще. */
/* Отбивка от залов. Секции на этом сайте разведены padding:6rem — значит
   между двумя блоками ВНУТРИ секции честная величина ровно одна: та же
   шестёрка, но разрезанная пополам линией. 3rem воздуха, волосяная линия,
   3rem воздуха. Меньше — оборудование снова читается как продолжение
   карточек залов (так и было); больше — секция разваливается на две, а
   заголовка у второй половины нет.
   Одного капслока для этого мало: 0.7rem подпись в потоке не отделяет
   ничего, работает именно линия. Она же — местная идиома: тем же
   rgb(var(--line-rgb) / …) отбиты .hall-equip и .hall-cta внутри карточки. */
.equip-title{font-size:0.7rem;letter-spacing:0.24em;text-transform:uppercase;
  color:var(--ink-soft);font-weight:500;
  margin-top:3rem;padding-top:3rem;margin-bottom:1.6rem;
  border-top:1px solid rgb(var(--line-rgb) / 0.3)}

/* Четыре колонки заданы числом, а не auto-fill. auto-fill решал сам и у Яши
   с её восемью карточками выкладывал 5+3 — ряд, который выглядит как сбой
   вёрстки, а не как решение. */
.equip-grid{display:grid;grid-template-columns:repeat(4,1fr);gap:0.9rem}

/* Хвост последнего ряда. У Яши карточек восемь и делится нацело, у Шафрана
   десять — 4+4+2, и две сироты справа читаются ровно как забытая правка.
   Пятая колонка на широких экранах чинит Шафрана и ломает Яшу (5+3);
   центрирование остатка уводит карточки с тех же вертикальных рельсов, по
   которым выстроены два ряда выше. Поэтому остаток растягивается по этим
   рельсам: две карточки берут по две колонки и закрывают ряд целиком.
   Правила счётные, а не по студиям: добавится одиннадцатая карточка —
   останется ряд из трёх (три из четырёх читаются как ряд), появится
   девятая одна — встанет по центру на две колонки. */
.equip-grid > :nth-child(4n+1):nth-last-child(2),
.equip-grid > :nth-child(4n+2):last-child{grid-column:span 2}
.equip-grid > :nth-child(4n+1):last-child{grid-column:2 / span 2}

.equip-card{background:var(--equip-bg);border:1px solid var(--line);
  border-radius:var(--radius-md);padding:1.35rem 1.3rem 1.45rem;
  transition:border-color 0.25s,transform 0.25s}
.equip-card:hover{border-color:var(--purple-light);transform:translateY(-2px)}

/* Карточка — <details>, и это ради телефона: там она складывается в строку,
   нативно, без единой строки JS (см. медиазапрос ≤600px ниже). На десктопе
   складывать нечего — блок обязан выглядеть ровно так же, как до правки,
   поэтому содержимое раскрыто принудительно.

   Раскрывает его ::details-content, а НЕ display на детях. Содержимое
   закрытого <details> лежит в UA-слоте теневого дерева, и знакомый хак
   `details > *:not(summary){display:block}` до него не достаёт: выключен сам
   слот, а не дети. Единственный рычаг из CSS — content-visibility на
   ::details-content. Он есть с Chrome 131 / Safari 18.4 / Firefox 139;
   движкам старше `open` проставляет initEquipToggle() в app.js, и там же
   написано, почему современные он намеренно НЕ трогает.

   Маркер-треугольник снят двумя строками сразу — это местная идиома, тем же
   способом раскрывался details.hall-equip. */
.equip-card > summary{list-style:none}
.equip-card > summary::-webkit-details-marker{display:none}
@media(min-width:601px){
  .equip-card > summary{display:block;cursor:default}
  .equip-card::details-content{content-visibility:visible}
}
/* Точки-буллита у названия больше нет: её место заняла иконка, а два маркера
   подряд — шум. */
/* <span>, а не <p>: название переехало внутрь <summary>, а его контент-модель —
   phrasing content, абзац там невалиден. display:block возвращает span ровно ту
   коробку, что была у <p>: глобальный сброс `*{margin:0}` уже обнулил его
   отступы, единственный отступ здесь свой. Поэтому десктоп не двигается. */
.equip-card .equip-name{display:block;font-size:0.84rem;font-weight:500;color:var(--ink);
  margin-bottom:0.4rem}
/* 52ch — та же мера строки, что у .section-sub и .price-footnote. Нужна
   именно здесь: две последние карточки Шафрана растянуты на две колонки, и
   без меры их описание уходит в строку на 110 знаков. */
.equip-card .equip-desc{font-size:0.79rem;line-height:1.65;color:var(--ink-soft);
  max-width:52ch}

/* ── Иконки карточек ──────────────────────────────────────────────────────
   Рисунок лежит в CSS маской, а не <svg> в разметке, и это единственный
   способ не заплатить за него четыре раза. Карточек два набора (Яша и
   Шафран) и у каждого два языка — инлайновый <svg> уехал бы в четыре
   собранных страницы. Здесь он уезжает в два styles.css, по одному на
   студию, и оба кэшируются на переходе LV↔RU. В разметке от иконки остаётся
   один атрибут data-eq.

   Набор общий: четыре понятия (циклорама, рулоны фонов, модификаторы,
   гримёрное зеркало) есть у обеих студий, и второй копии у них нет — по той
   же причине, по которой сам блок переехал сюда из темы Шафрана.

   Почему маска, а не background-image: картинка в background не знает
   currentColor и красилась бы литералом — то есть в одной палитре из двух.
   Маска вырезает форму из заливки, а заливка берётся у элемента, поэтому
   один и тот же файл идёт и в фиолетовую палитру Яши, и в шафрановую.

   Данные внутри url() — обычный SVG, у которого экранированы только < и >.
   Точек с запятой и фигурных скобок там нет намеренно: гейт контраста
   разбирает css регулярками по { } и ;, и любая из них внутри строки увела
   бы разбор в сторону. */
/* Плашка НЕ углубляется на ховере, и это решение, а не упущение. Углубление
   с 0.09 до 0.16 задумывалось как affordance, но между двумя состояниями
   разница выходила 1.14:1 у Шафрана и 1.11:1 у Яши — глазом её нет, — зато
   знак внутри тонул: у Шафрана 3.15 → 2.77:1 при норме WCAG 1.4.11 3:1 для
   нетекстовой графики (у Яши 3.44 → 3.09).
   То есть ховер ухудшал читаемость ровно там, где на карточку смотрят.
   Affordance держит рамка карточки (--purple-light) и подъём на 2px — они
   заметны и ничего не топят.
   Заливка объявлена от --equip-bg предка: см. `.equip-card .equip-ico` ниже —
   селектор записан через предка НАМЕРЕННО, чтобы contrast.py знал, поверх
   чего лежит полупрозрачная плашка, и мог посчитать пару. */
.equip-card .equip-ico{width:44px;height:44px;flex:0 0 44px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;margin-bottom:1rem;
  background:rgb(var(--accent-alt-rgb) / 0.09);color:var(--accent-display)}
.equip-ico::before{content:"";width:24px;height:24px;background:currentColor;
  -webkit-mask:var(--equip-ico) center/24px 24px no-repeat;
  mask:var(--equip-ico) center/24px 24px no-repeat}

/* Модель в полный рост на бесшовном фоне: стена слева уходит в пол одной
   линией, угла нет — ровно то, что обещает карточка. Фигура здесь несущая:
   без неё галтель в любой редакции читается буквой (J у прежней, L у той,
   что с замкнутым профилем, U у фронтальной). Человек ломает чтение как
   буквы, а голова взята r=2.9: на 2.3 и меньше кольцо на 24px заплывает
   в точку, и фигура становится пожарным гидрантом. */
.equip-card[data-eq="cyclo"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.4 2.6V12.4a7 7 0 0 0 7 7h11.2'/%3E%3Ccircle cx='15.2' cy='9' r='2.9'/%3E%3Cpath d='M11.6 19.4v-3.2a3.6 3.6 0 0 1 7.2 0v3.2'/%3E%3C/svg%3E")}
/* три рулона под потолком, средний раскатан */
.equip-card[data-eq="rolls"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 4.4h18'/%3E%3Ccircle cx='6.6' cy='7.1' r='2.1'/%3E%3Ccircle cx='12' cy='7.1' r='2.1'/%3E%3Ccircle cx='17.4' cy='7.1' r='2.1'/%3E%3Cpath d='M9.3 9.1v10.5h5.4V9.1'/%3E%3C/svg%3E")}
/* импульсная голова на стойке, в рефлекторе молния */
.equip-card[data-eq="flash"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7.2 3.4h9.6l1.8 8.6H5.4z'/%3E%3Cpath d='M12.9 5l-2 3.4h2.4l-2 3.2'/%3E%3Cpath d='M12 12v5.6'/%3E%3Cpath d='M8.6 20.4 12 17.6l3.4 2.8'/%3E%3C/svg%3E")}
/* панель на стойке, внутри треугольник play */
.equip-card[data-eq="video"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4.6 3.4h14.8v8.8H4.6z'/%3E%3Cpath d='M10.4 6.1 14.4 7.8l-4 1.7z'/%3E%3Cpath d='M12 12.2v5.4'/%3E%3Cpath d='M8.4 20.4 12 17.6l3.6 2.8'/%3E%3C/svg%3E")}
/* та же голова, но в ней сразу молния и play — импульс и видеосвет */
.equip-card[data-eq="lights"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5.6 3.4h12.8l1.8 8.2H3.8z'/%3E%3Cpath d='M10.6 4.9 8.6 8.1h2.2l-1.6 2.6'/%3E%3Cpath d='M13.4 5.8 17 7.5l-3.6 1.7z'/%3E%3Cpath d='M12 11.6v6'/%3E%3Cpath d='M8.4 20.4 12 17.6l3.6 2.8'/%3E%3C/svg%3E")}
/* софтбокс на журавле, а не «квадрат» */
.equip-card[data-eq="mods"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.4 9.2 10.2 3.6l5.6 7.8-7.8 5.6z'/%3E%3Cpath d='M13 7.5 19.4 12.4'/%3E%3Cpath d='M19.4 12.4v7.8'/%3E%3Cpath d='M16.8 20.4h5.2'/%3E%3C/svg%3E")}
/* окно с переплётом и лучи дневного света */
.equip-card[data-eq="windows"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.4 3.6h11.2v16.8H3.4z'/%3E%3Cpath d='M9 3.6v16.8M3.4 12h11.2'/%3E%3Cpath d='M17.4 8.4 20.6 6.2M17.8 12h3.4M17.4 15.6 20.6 17.8'/%3E%3C/svg%3E")}
/* Арочное окно с переплётом и рядом полотно до пола: карниз общий, у
   полотна складка и фестонный низ — по ним ткань и опознаётся.
   Композиция намеренно НЕсимметрична: прежняя редакция ставила две
   зеркальные волны в раму, и главным становился просвет между ними —
   получались песочные часы. Окно и штора в одной иконке потому, что
   карточка обещает и дневной свет, и возможность его отрезать. */
.equip-card[data-eq="curtains"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.5 3.6h19'/%3E%3Cpath d='M3.8 19.9V10.4a4.6 4.6 0 0 1 9.2 0v9.5z'/%3E%3Cpath d='M8.4 5.9v14'/%3E%3Cpath d='M3.9 10.9h9'/%3E%3Cpath d='M2.9 19.9h11'/%3E%3Cpath d='M15.6 3.6V18c1.15 1.3 1.61 1.3 2.3 0s.69-1.3 2.3 0V3.6'/%3E%3Cpath d='M17.9 3.6v15.1'/%3E%3C/svg%3E")}
/* кровать и подвесная люстра — Home Chic */
.equip-card[data-eq="interior"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 19.8V9.4'/%3E%3Cpath d='M3 14.2h13.4v3.4H3z'/%3E%3Cpath d='M16.4 17.6v2.2'/%3E%3Cpath d='M5 14.2v-2.2h3.8v2.2'/%3E%3Cpath d='M19.6 3.4v3.4'/%3E%3Cpath d='M17 10.8 19.6 6.8l2.6 4z'/%3E%3C/svg%3E")}
/* диван с подлокотниками */
.equip-card[data-eq="elements"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M5 11.2V8.8a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2v2.4'/%3E%3Cpath d='M3 17.2v-4a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2v4z'/%3E%3Cpath d='M5.4 17.2v2M18.6 17.2v2'/%3E%3C/svg%3E")}
/* Гримёрный стол: прямоугольное зеркало, по бокам ДВЕ ВЕРТИКАЛЬНЫЕ
   ЛАМПЫ — так они и названы в тексте обеих карточек, — под ними широкая
   столешница на ножках. Ни стойки, ни круглой опоры: капсула на ножке с
   опорой и делала микрофон, а боковые лампы дочитывались звуковыми
   волнами. Столешница шире ламп и стоит на двух разнесённых ножках —
   это мебель, а не основание прибора. */
.equip-card[data-eq="mirror"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Crect x='7.4' y='3.4' width='9.2' height='13' rx='1.3'/%3E%3Cpath d='M4.4 6.4v8.4M19.6 6.4v8.4'/%3E%3Cpath d='M2.6 18.4h18.8'/%3E%3Cpath d='M5.6 18.4v2.4M18.4 18.4v2.4'/%3E%3C/svg%3E")}
/* ваза и пуф на полу */
.equip-card[data-eq="props"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M2.6 19.8h18.8'/%3E%3Cpath d='M5.4 7.6h5.6v1.8c0 1-.9 1.7-.9 2.8 0 1.9 2 2.7 2 4.9 0 1.6-1.7 2.7-3.9 2.7s-3.9-1.1-3.9-2.7c0-2.2 2-3 2-4.9 0-1.1-.9-1.8-.9-2.8z'/%3E%3Cpath d='M13.6 19.8v-3.6a2 2 0 0 1 2-2h3.4a2 2 0 0 1 2 2v3.6'/%3E%3C/svg%3E")}
/* жалюзи с ламелями и шнуром */
.equip-card[data-eq="blackout"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3.4 3.4h17.2v17.2H3.4z'/%3E%3Cpath d='M3.4 6.8h17.2M3.4 9.9h17.2M3.4 13h17.2'/%3E%3Cpath d='M18.6 13v3.2'/%3E%3Ccircle cx='18.6' cy='17.4' r='.9'/%3E%3C/svg%3E")}
/* чашка с паром */
.equip-card[data-eq="tea"]{--equip-ico:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 8.6h11.6v6.2a4.6 4.6 0 0 1-4.6 4.6H8.6A4.6 4.6 0 0 1 4 14.8z'/%3E%3Cpath d='M15.6 10.2h1.8a2.6 2.6 0 0 1 0 5.2h-1.8'/%3E%3Cpath d='M7.4 5.8c0-1.2 1.2-1.2 1.2-2.4M11 5.8c0-1.2 1.2-1.2 1.2-2.4'/%3E%3Cpath d='M3.4 21.2h13'/%3E%3C/svg%3E")}

/* Планшет: две колонки. Растяжку хвоста здесь надо снять явно — счётные
   правила выше не знают, сколько колонок в сетке сейчас.
   ⚠ Селекторы сноса повторены целиком, а не сокращены до `.equip-grid > *`:
   у счётных правил специфичность (0,3,0), у звёздочки (0,1,0), и порядок в
   файле её не спасает. На одной колонке это не «чуть шире карточка», а
   вторая НЕЯВНАЯ колонка на всю сетку: span 2 в сетке из одной колонки
   создаёт себе вторую, и вся сетка Шафрана на телефоне встаёт в два
   столбца. Ровно так и было поймано на 375px. */
@media(max-width:1150px){
  .equip-grid{grid-template-columns:1fr 1fr}
  .equip-grid > :nth-child(4n+1):nth-last-child(2),
  .equip-grid > :nth-child(4n+2):last-child,
  .equip-grid > :nth-child(4n+1):last-child{grid-column:auto}
}
/* Телефон: строка-гармошка вместо карточки.
   Иконка уходит влево от названия — столбиком она съела бы по 60px высоты на
   карточку. Тот же приём, что у .rule-item ниже 600px. Но одной перекладкой
   в строку дело не решалось: описания у карточек по три-шесть строк, и блок
   занимал 1,8 экрана у обеих студий — у Яши восемью карточками, у Шафрана
   десятью, они просто короче.

   Свёрнуто именно ОПИСАНИЕ, а название и иконка остаются на виду. Блок
   отвечает на два разных вопроса: «есть ли здесь циклорама и гримёрка» —
   это скан по названиям, весь список сразу, — и «что такое China Ball» —
   это одно описание из десяти. Пряча первое ради второго, мы бы поменяли
   их местами; здесь скан остался бесплатным, а чтение стоит один тап.

   Раскрытие нативное: <details>/<summary> работает без JS, с клавиатуры и в
   скринридере объявляется как disclosure. Своего механизма заводить не надо —
   на сайте этим же способом раскрывался details.hall-equip. */
@media(max-width:600px){
  .equip-title{margin-top:1.75rem;padding-top:1.75rem;margin-bottom:1.1rem}
  .equip-grid{grid-template-columns:1fr;gap:0.5rem}
  /* Отступы ушли внутрь summary и описания: нажимать надо всю строку, а не
     текст в ней. overflow держит подсветку нажатия и рамку фокуса внутри
     скругления — обе рисуются по краю карточки. */
  .equip-card{padding:0;overflow:hidden}
  /* min-height, а не только padding: 34px иконка с отбивкой даёт 53px, но
     иконка может однажды уменьшиться, а строка обязана остаться пальцем
     нажимаемой (WCAG 2.5.8 — 24px минимум, 44px комфортно). */
  .equip-card > summary{display:flex;align-items:center;gap:0.75rem;
    padding:0.6rem 1rem;min-height:52px;cursor:pointer;
    -webkit-tap-highlight-color:transparent}
  /* Селектор ОБЯЗАН повторять предка: базовое правило записано через
     `.equip-card .equip-ico` (0-2-0), а медиазапрос специфичности не
     добавляет. Одинокий `.equip-ico` (0-1-0) здесь проигрывал каскад молча,
     и на телефоне плашка оставалась 44px с отбивкой 16px. */
  .equip-card .equip-ico{width:34px;height:34px;flex-basis:34px;margin-bottom:0}
  .equip-ico::before{width:19px;height:19px;
    -webkit-mask-size:19px 19px;mask-size:19px 19px}
  .equip-card .equip-name{margin-bottom:0;flex:1 1 auto}
  /* Шеврон ровно той же постройки, что у details.hall-equip: уголок из двух
     границ, поворот на [open]. Цвет взят --ink-soft, а не --ink-dim: на
     0.38 альфы уголок на светлой карточке не добирал 3:1 по WCAG 1.4.11,
     а он здесь единственный знак «строка раскрывается». */
  .equip-card > summary::after{content:"";width:7px;height:7px;flex:0 0 auto;
    color:var(--ink-soft);
    border-right:1.4px solid currentColor;border-bottom:1.4px solid currentColor;
    transform:rotate(45deg) translateY(-2px);transition:transform 0.25s}
  .equip-card[open] > summary::after{transform:rotate(-135deg) translateY(-2px)}
  /* Второй маркер состояния, для тех, кто уголок не читает: у раскрытой
     строки рамка того же цвета, что даёт ховер на десктопе. */
  .equip-card[open]{border-color:var(--purple-light)}
  /* Отступ рамки фокуса отрицательный, а не 3px как у прочих: summary
     заполняет карточку целиком, и рамка снаружи ушла бы под overflow:hidden. */
  .equip-card > summary:focus-visible{outline:2px solid var(--focus);outline-offset:-3px}
  .equip-card > summary:active{background:rgb(var(--accent-alt-rgb) / 0.06)}
  /* Строка не должна подпрыгивать под пальцем: подъём на 2px задуман для
     курсора, а на тапе :hover залипает и после того, как палец убрали. */
  .equip-card:hover{transform:none}
  .equip-card .equip-desc{margin-top:0;padding:0 1rem 0.95rem;
    animation:equipOpen 0.28s ease both}
}
/* Раскрытие показано движением содержимого, а не высотой карточки: высоту
   пришлось бы гнать через interpolate-size, а opacity и transform считает
   композитор и не трогает раскладку. */
@keyframes equipOpen{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}
@media(prefers-reduced-motion:reduce){
  /* Иконка больше ничего не анимирует: ховер её не трогает, transition с неё
     снят. Осталась карточка, шеврон и раскрытие описания. */
  .equip-card{transition:none}
  .equip-card:hover{transform:none}
  .equip-card > summary::after{transition:none}
  .equip-card .equip-desc{animation:none}
}

#pricing{background:var(--paper2);position:relative}
.pricing-layout{display:grid;grid-template-columns:1fr;gap:3.5rem;align-items:start;margin-top:3rem}
/* Колонки объявлены здесь, а не в карточке: см. блок «Prices» ниже —
   карточки подключаются к ним через subgrid, чтобы цифры во всех четырёх
   стояли на одной линии. row-gap = расстояние между карточками,
   column-gap = внутренний зазор цифра/единица (карточки его наследуют). */
.pricing-cards{display:grid;grid-template-columns:1fr auto auto;
  row-gap:0.85rem;column-gap:0.5rem}
.price-card{background:var(--card-grad);border:1px solid var(--line);border-radius:var(--radius-md);padding:1.5rem 1.75rem;display:flex;justify-content:space-between;align-items:center;transition:border-color 0.3s,transform 0.25s;box-shadow:0 8px 24px -12px rgb(var(--shadow-tint) / 0.15)}
.price-card:hover{border-color:var(--purple-light);transform:translateY(-2px);box-shadow:0 14px 32px -12px rgb(var(--shadow-tint) / 0.22)}
.price-card.featured{border-color:var(--featured-border);background:var(--featured-grad);position:relative}
.price-card.featured .price-duration,.price-card.featured .price-num{color:var(--on-featured)}
.price-card.featured .price-note,.price-card.featured .price-per,.price-card.featured .price-total{color:var(--on-featured-soft)}
.price-card.featured::before{content:attr(data-badge);position:absolute;top:-11px;left:1.75rem;background:var(--paper);border:1px solid rgb(var(--line-rgb) / 0.45);font-size:0.6rem;letter-spacing:0.14em;text-transform:uppercase;color:var(--purple-900);padding:0.25rem 0.75rem;border-radius:var(--radius-pill)}
.price-duration{font-family:var(--font-display);font-size:1.35rem;font-weight:500;color:var(--ink)}
.price-note{font-size:0.75rem;color:var(--ink-dim);margin-top:0.2rem}
.price-num{font-family:var(--font-display);font-size:2.1rem;font-weight:500;color:var(--ink)}
.price-per{font-size:0.7rem;color:var(--ink-soft);margin-left:0.25rem}
.price-total{font-size:0.7rem;color:var(--purple-900);margin-top:0.2rem;font-weight:500}
.price-footnote{margin-top:1.25rem;font-size:0.78rem;color:var(--ink-soft);line-height:1.7;max-width:52ch}
.combo-card{background:var(--combo-grad);border:1px solid rgb(var(--line-rgb) / 0.3);border-radius:var(--radius-lg);padding:2.25rem;box-shadow:0 24px 50px -20px rgb(var(--shadow-tint) / 0.3)}
.combo-badge{display:inline-block;background:rgb(var(--plate-rgb) / 0.25);color:var(--ink);font-size:0.6rem;letter-spacing:0.14em;text-transform:uppercase;padding:0.35rem 0.9rem;border-radius:var(--radius-pill);margin-bottom:1.25rem}
.combo-title{font-family:var(--font-display);font-size:2.3rem;font-weight:500;margin-bottom:0.5rem;color:var(--ink);line-height:1.1}
.combo-desc{font-size:0.82rem;color:var(--ink-soft);line-height:1.7;margin-bottom:1.5rem}
.combo-halls{display:flex;gap:0.75rem;margin-bottom:1.5rem;flex-wrap:wrap}
.combo-hall-pill{background:rgb(var(--plate-rgb) / 0.3);border:1px solid rgb(var(--plate-rgb) / 0.4);font-size:0.72rem;color:var(--ink);padding:0.4rem 0.95rem;border-radius:var(--radius-pill)}
.combo-price{display:flex;align-items:baseline;gap:0.5rem}
.combo-price-num{font-family:var(--font-display);font-size:3.6rem;font-weight:500;line-height:1;color:var(--ink)}
.combo-price-label{font-size:0.8rem;color:var(--ink-soft)}

#gallery{background:var(--paper);padding:5rem var(--pad-x)}
.gallery-header{display:flex;justify-content:space-between;align-items:flex-end;margin-bottom:2.5rem}
.gallery-grid{display:grid;grid-template-columns:repeat(3,1fr);grid-auto-rows:242px;gap:0.9rem}.gallery-item picture{display:block;width:100%;height:100%}
.gallery-item{border-radius:var(--radius-md);overflow:hidden;position:relative;box-shadow:0 12px 30px -10px rgb(var(--shadow-tint) / 0.15)}
.gallery-item:first-child{grid-column:1/3;grid-row:1/3}
.gallery-item img{width:100%;height:100%;object-fit:cover;display:block;transition:transform 0.4s ease}
.gallery-item:hover img{transform:scale(1.03)}

/* ── «Снято у нас» ──────────────────────────────────────────────────────────
   Просьба владелицы 07.09, голосовым: «сейчас мы, по сути, продаём голые
   стены, а продают именно фотографии — как человек может выглядеть в этих
   стенах». Блок показывает чужие съёмки, сделанные В студии, а не студию.

   Лента, а не сетка, по двум причинам, и обе про кадры, а не про вкус.
   Первая: съёмки приходят вертикальными, а на странице уже три горизонтальные
   сетки — четвёртая читалась бы как та же самая, только с людьми.
   Вторая: пропорции у кадров разные (2:3, 5:7, 3:4). Сетка приводит их к
   одному окну и режет; лента задаёт общую ВЫСОТУ и оставляет каждому свою
   ширину. Кроп чужой съёмки — это правка чужой работы, и делать её ради
   выравнивания плиток нельзя.

   Лента намеренно уходит под правый край экрана: обрезанный кадр у границы —
   единственный честный признак, что дальше есть ещё. Стрелок нет, потому что
   на телефоне их всё равно не будет, а два разных способа листать на одном
   блоке — это два способа не понять, что он листается. */
.shots-strip{
  display:flex;gap:0.9rem;
  overflow-x:auto;overscroll-behavior-x:contain;
  scroll-snap-type:x proximity;
  /* Точки притяжения считаются от края СОДЕРЖИМОГО, а не от края отступа:
     без этого браузер сам уезжал на padding-left (48 px на широком экране),
     и первый кадр вставал в край экрана вместо линии заголовка — ровно того
     выравнивания, ради которого отступ и добавлен ниже. Заодно от этого
     зависела стрелка «назад»: лента стояла не в нуле и кнопка не гасла. */
  scroll-padding-inline:var(--pad-x);
  /* В край экрана и обратно: отрицательное поле выводит ленту из колонки,
     внутренний отступ возвращает первому кадру ту же левую границу, по
     которой стоит заголовок. */
  margin-inline:calc(var(--pad-x) * -1);
  padding:0.4rem var(--pad-x) 0.6rem;
  /* Системная полоса прокрутки снята намеренно: 11.09 владелец сказал, что
     тащить её мышью неудобно, и он прав — это единственный орган управления,
     который на десктопе был. Её заменили стрелки и точки, а две шкалы под
     одной лентой спорили бы друг с другом. */
  scrollbar-width:none;
}
.shots-strip::-webkit-scrollbar{display:none}
/* Рельс — система координат для стрелок. Лента шире его на величину выпуска
   в край экрана, поэтому кнопки, привязанные к рельсу, встают над кадрами,
   а не над полями страницы. */
.shots-rail{position:relative}
/* Перетаскивание мышью: на время захвата снимаем притяжение, иначе лента
   дёргается к ближайшему кадру прямо под курсором. cursor:grabbing вешаем
   на саму ленту, а не на body — курсор должен меняться там, где держат. */
.shots-strip.is-dragging{scroll-snap-type:none;cursor:grabbing;scroll-behavior:auto}
.shots-strip.is-dragging .shot{cursor:grabbing}
@media (pointer:fine){ .shots-strip{cursor:grab} }
/* Картинка в браузере перетаскиваемая по умолчанию, и это не мелочь: нажатие
   с движением уходило в НАТИВНЫЙ drag-and-drop файла, после чего ни одного
   pointermove до ленты уже не доходило — жест просто пропадал. Снимаем и
   выделение: без него протяжка мышью подсвечивает соседние кадры синим. */
.shots-strip{-webkit-user-select:none;user-select:none}
.shots-strip img{-webkit-user-drag:none}
/* Контейнер с прокруткой обязан брать фокус: иначе с клавиатуры лента
   недостижима — внутри только кнопки, а сама прокрутка ничья. */
.shots-strip:focus-visible{outline:2px solid var(--focus);outline-offset:4px;border-radius:var(--radius-sm)}
.shot{
  flex:0 0 auto;scroll-snap-align:start;
  border:0;padding:0;background:none;font:inherit;cursor:zoom-in;
  border-radius:var(--radius-md);overflow:hidden;position:relative;
  box-shadow:0 12px 30px -10px rgb(var(--shadow-tint) / 0.15);
}
.shot:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
/* Стрелки только там, где есть точный указатель. На телефоне их не рисуем —
   палец и так листает, а две кнопки поверх кадров съели бы их край, по
   которому и видно, что лента продолжается. */
.shots-arrow{
  position:absolute;top:calc(50% - 22px);z-index:2;
  width:44px;height:44px;border-radius:50%;display:none;place-items:center;
  border:1px solid rgb(var(--line-rgb) / 0.55);background:rgb(var(--plate-rgb) / 0.92);
  color:var(--ink);cursor:pointer;
  box-shadow:0 8px 22px -10px rgb(var(--shadow-tint) / 0.45);
  transition:background 0.2s ease,border-color 0.2s ease,opacity 0.2s ease;
}
.shots-arrow svg{width:20px;height:20px}
.shots-arrow--prev{left:calc(var(--pad-x) * -1 + 0.6rem)}
.shots-arrow--next{right:calc(var(--pad-x) * -1 + 0.6rem)}
.shots-arrow:hover{background:rgb(var(--plate-rgb) / 1);border-color:var(--line-strong)}
.shots-arrow:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
/* Кнопка у края ленты не исчезает, а гаснет: пропадающий орган управления
   заставляет искать, куда он делся, и сдвигает соседний. */
.shots-arrow[disabled]{opacity:0.32;cursor:default;box-shadow:none}
@media (pointer:fine){ .shots-arrow:not([hidden]){display:grid} }

/* Точки. Их столько, сколько ЭКРАНОВ в ленте, а не сколько кадров: двадцать
   четыре точки — это забор, по которому не попасть пальцем и в котором не
   видно, где ты. Считает и ограничивает initShots(). */
.shots-dots{display:flex;justify-content:center;align-items:center;gap:0.45rem;
  min-height:18px;margin-top:0.35rem}
.shots-dot{width:7px;height:7px;padding:0;border:0;border-radius:50%;cursor:pointer;
  background:rgb(var(--line-rgb) / 0.5);
  transition:background 0.25s ease,transform 0.25s ease}
.shots-dot:hover{background:rgb(var(--line-rgb) / 0.8)}
.shots-dot.is-on{background:var(--purple-cta);transform:scale(1.45)}
@media(prefers-reduced-motion:reduce){
  .shots-dot{transition:none}
  .shots-arrow{transition:none}
}
.shot picture{display:block}
/* Высота общая, ширина своя у каждого кадра — отсюда и ритм ленты.
   width:auto считается из width/height, которые проставляет expand_images:
   без них строка дёргалась бы по мере загрузки. */
.shot img{display:block;height:clamp(300px,34vw,440px);width:auto;transition:transform 0.45s ease}
.shot:hover img{transform:scale(1.03)}
@media(prefers-reduced-motion:reduce){
  .shots-strip{scroll-behavior:auto}
  .shot img{transition:none}
  .shot:hover img{transform:none}
}

/* ── #ietilpst · «Что входит в стоимость» ─────────────────────────────────
   Один блок на обе студии. Полоса намеренно другого тона, чем соседние
   секции: она отвечает на «за что я плачу» и не должна пролистываться как
   ещё одна светлая полоса. Тон полосы и карточки на ней задаёт тема —
   --band-bg / --band-card, потому что у студий разная бумага.
   Правая колонка пунктирная и без заливки: «не входит» обязано читаться
   как сноска к левой, а не как второе равноправное предложение. */
#ietilpst,#abonement{background:var(--band-bg);border-top:1px solid var(--line);border-bottom:1px solid var(--line)}
.section-sub{font-size:0.9rem;line-height:1.75;color:var(--ink-soft);max-width:52ch}
.incl-grid{display:grid;grid-template-columns:1.1fr 0.9fr;gap:1.25rem;margin-top:2.25rem;align-items:start}
.incl-col{background:var(--band-card);border:1px solid var(--line);border-radius:var(--radius-lg);padding:1.6rem 1.7rem}
.incl-col-no{background:transparent;border-style:dashed}
.incl-head{font-size:0.64rem;letter-spacing:0.2em;text-transform:uppercase;color:var(--purple-900);font-weight:500;margin-bottom:1.1rem}
.incl-list{list-style:none;display:grid;gap:0.65rem}
.incl-list li{font-size:0.86rem;line-height:1.6;color:var(--ink-soft);display:flex;gap:0.75rem;align-items:flex-start}
.incl-list li::before{content:"";flex:0 0 11px}
/* Галочка и прочерк нарисованы рамками, а не глифами: ✓ и — подменяются
   системным шрифтом и прыгают по базовой линии. */
.incl-yes li::before{width:11px;height:6px;margin-top:0.35em;border-left:1.6px solid var(--accent-display);border-bottom:1.6px solid var(--accent-display);transform:rotate(-45deg)}
.incl-no li::before{width:11px;height:0;margin-top:0.68em;border-top:1.6px solid var(--line-strong)}
.incl-note{margin-top:1.25rem;padding-top:1.1rem;border-top:1px solid rgb(var(--line-rgb) / 0.35);font-size:0.84rem;line-height:1.6;color:var(--ink)}
@media(max-width:900px){.incl-grid{grid-template-columns:1fr;gap:0.9rem;margin-top:1.75rem}}
@media(max-width:600px){.incl-col{padding:1.15rem 1.25rem}.incl-list li{font-size:0.82rem}}

/* ── #abonement · предоплаченные часы ──────────────────────────────────────
   Своей палитры блок не заводит: тон полосы, карточки, точки и кнопки
   приходят токенами из темы, поэтому у Яши он фиолетовый, у Шафрана —
   оксблад с шафрановыми точками, а check_css_vars остаётся зелёным.

   Селекторы намеренно начинаются с #abonement / #pricing: у contrast.py
   предок ищется по пробельному префиксу, и без id-шного начала пара
   «подпись × заливка» не считается ВООБЩЕ — ровно тот тихий провал, из-за
   которого на плитке выбора студии четыре месяца жил текст 2.52:1.
   С префиксом гейт видит все восемь новых пар. Прогнано: у Яши 17 провалов
   до и 17 после (все из CONTRAST_DEBT), у Шафрана 0 и 0 — а у него долг
   пуст, то есть ЛЮБОЙ новый провал уронил бы сборку.
   ────────────────────────────────────────────────────────────────────────── */

/* На #abonement ведут объявления Meta и Google, а шапка fixed (~73 px на
   широком экране, ~61 px на телефоне при section padding-top 56 px ниже
   600 px). Без этого заголовок секции уезжает под панель ровно на мобильном
   трафике, которого у объявлений большинство. Остальные якоря страницы живут
   без запаса давно, но туда приходят прокруткой, а не внешним переходом. */
#abonement{scroll-margin-top:5rem}

/* Блок центрирован целиком — единственная секция на странице, которая стоит
   по центру. Это не разнобой, а разница назначения: остальные секции читают
   слева направо длинными абзацами, здесь же короткое предложение и две цены,
   и колонка в 760 px, прижатая к левому краю, оставляла полэкрана пустоты
   справа. Центрируются и заголовок с подзаголовком — иначе колонка по центру
   с подписями слева читается как сбой вёрстки. */
#abonement .section-title,#abonement .section-sub{text-align:center}
#abonement .section-sub{margin-inline:auto}
.abon{display:grid;gap:1.25rem;margin-top:2.5rem;max-width:760px;margin-inline:auto}

/* Кнопка «Купить» живёт ВНУТРИ карточки: цена и действие не должны стоять на
   разных этажах блока — до кнопок под условиями на телефоне надо было
   пролистать семь абзацев. Четвёртая колонка добавляется только абонементам,
   прайс выше остаётся трёхколоночным и не разъезжается. */
.abon-cards{grid-template-columns:1fr auto auto auto}
.abon-buy{grid-column:4;grid-row:1/3;align-self:center;margin-left:1.5rem;
  white-space:nowrap;padding:0.72rem 1.7rem;font-size:0.72rem;letter-spacing:0.08em}
/* На тёмной карточке фиолетовая кнопка сливается с заливкой: меняем местами
   фон и подпись. Пара --plate-rgb × --purple-900 уже стоит на этой карточке —
   ею набрана плашка «экономия 100 €», то есть цвета проверены. */
#abonement .price-card.featured .abon-buy{background:rgb(var(--plate-rgb) / 1);color:var(--purple-900);border-color:rgb(var(--plate-rgb) / 1)}
#abonement .price-card.featured .abon-buy:hover{background:var(--paper2);border-color:var(--paper2)}

#abonement .abon-lead{font-size:0.82rem;line-height:1.65;color:var(--ink-soft);max-width:62ch;margin:0 auto;text-align:center}

/* Условия — аккордеоном, а не колонкой в полстраницы. Свёрнуты, но в одном
   нажатии и ДО покупки: предоплаченный пакет, условия которого показаны
   после оплаты, этих условий юридически не имеет. Самое существенное живёт
   выше открытым текстом — срок стоит в подзаголовке блока.
   <details> вместо своего аккордеона: работает без JS, открывается поиском
   по странице, не ломает пререндер. */
#abonement .abon-terms{border:1px dashed rgb(var(--line-rgb) / 0.5);border-radius:var(--radius-md);padding:0.95rem 1.5rem}
#abonement .abon-terms summary{cursor:pointer;font-size:0.64rem;letter-spacing:0.2em;text-transform:uppercase;color:var(--purple-900);font-weight:500;list-style:none;display:flex;justify-content:space-between;align-items:center;gap:1rem}
#abonement .abon-terms summary::-webkit-details-marker{display:none}
/* Знак, а не стрелка: стрелку пришлось бы рисовать и поворачивать, а «+»
   и «−» читаются в любом шрифте и не зависят от направления письма. */
#abonement .abon-terms summary::after{content:"+";font-size:1rem;line-height:1;letter-spacing:0}
#abonement .abon-terms[open] summary::after{content:"\2212"}
#abonement .abon-terms[open] summary{margin-bottom:1.1rem}
#abonement .abon-terms .incl-list{display:grid;gap:0.7rem}

/* Ни галочка, ни прочерк здесь не правдивы: галочка над сезонным окном врёт,
   прочерк над правом отказа 14 дней читается как отказ ОТ права. Нужна
   точка, которая не утверждает ничего. flex-basis переопределяется вместе с
   width: базовое .incl-list li::before ставит flex:0 0 11px, и одной width
   коробка бы не сжалась. */
#abonement .incl-list li::before{flex:0 0 6px;width:6px;height:6px;margin-top:0.5em;border-radius:50%;background:var(--accent-display)}

/* Общего правила для <a> на сайте нет, и без этого ссылки в указателе и в
   сноске пришли бы браузерной синей. Оформление — идиома сайта
   (.contact-info-value a): базовый --purple-pale-text, наведение в
   --purple-900. */
#pricing .price-footnote a,#abonement .incl-note a{color:var(--purple-pale-text);text-decoration:none;border-bottom:1px solid var(--consent-link-line);transition:color 0.2s,border-color 0.2s}
#pricing .price-footnote a:hover,#pricing .price-footnote a:focus-visible,#abonement .incl-note a:hover,#abonement .incl-note a:focus-visible{color:var(--purple-900);border-bottom-color:var(--purple-900)}

/* ⚠ .price-note до сих пор существовал ТОЛЬКО внутри .price-card.featured,
   где его красит --on-featured-soft. Здесь он впервые попадает на обычную
   карточку — и там --ink-dim даёт 2.36:1 на --card-grad у Яши при кегле
   12 px. Гейт это НЕ поймал бы: у селектора .price-note нет предка с
   объявленной заливкой, пара не считается вообще. */
.price-card .price-note{color:var(--ink-soft)}

@media(max-width:600px){
  /* Карточка складывается: цена в свой ряд, кнопка во всю ширину под ней.
     «Купить» одним словом влезает и в 320 px, но в ряд с четырёхзначной
     ценой места уже нет. */
  .abon{margin-top:1.75rem;gap:1rem}
  #abonement .abon-cards .price-card{row-gap:0.85rem}
  .abon-buy{grid-column:1/-1;grid-row:3;margin-left:0;width:100%;text-align:center;padding-inline:1.2rem}
  #abonement .abon-terms{padding:0.85rem 1.15rem}
}


#rules{background:var(--paper2)}
.rules-grid{display:grid;grid-template-columns:1fr 1fr;gap:1.1rem;margin-top:3rem}
.rule-item{background:var(--card-grad);border:1px solid var(--line);border-radius:var(--radius-md);padding:1.6rem;display:flex;gap:1.1rem;align-items:flex-start;transition:border-color 0.2s,transform 0.2s;box-shadow:0 8px 20px -12px rgb(var(--shadow-tint) / 0.12)}
.rule-item:hover{border-color:var(--purple-light);transform:translateY(-2px)}
.rule-icon{width:38px;height:38px;flex-shrink:0;display:flex;align-items:center;justify-content:center;border:1px solid rgb(var(--line-rgb) / 0.25);border-radius:50%;font-size:1rem;background:rgb(var(--line-rgb) / 0.08)}
.rule-text{font-size:0.82rem;color:var(--ink-soft);line-height:1.7}

#faq{background:var(--paper);padding:5rem var(--pad-x)}
.faq-list{margin-top:2.5rem;display:grid;grid-template-columns:1fr 1fr;gap:0.6rem}
.faq-item{background:var(--card-grad-soft);border:1px solid var(--line-soft);border-radius:var(--radius-md);overflow:hidden;transition:border-color 0.25s}
.faq-item.open{border-color:var(--purple-light)}
.faq-q{width:100%;background:none;border:none;padding:1.25rem 1.5rem;display:flex;justify-content:space-between;align-items:center;gap:1rem;cursor:pointer;text-align:left;font-family:var(--font-body);font-size:0.88rem;font-weight:500;color:var(--ink);transition:color 0.2s}
.faq-q:hover{color:var(--purple-600)}
.faq-item.open .faq-q{color:var(--purple-900)}
.faq-icon{width:20px;height:20px;flex-shrink:0;border:1px solid rgb(var(--accent-alt-rgb) / 0.25);border-radius:50%;display:flex;align-items:center;justify-content:center;transition:all 0.3s;color:var(--purple-pale-text)}
.faq-icon svg{transition:transform 0.3s}
.faq-item.open .faq-icon{background:var(--accent-solid);border-color:var(--accent-solid);color:var(--on-accent-alt)}
.faq-item.open .faq-icon svg{transform:rotate(45deg)}
.faq-a{max-height:0;overflow:hidden;transition:max-height 0.4s ease}
.faq-item.open .faq-a{max-height:300px}
.faq-a-inner{padding:0 1.5rem 1.25rem;font-size:0.85rem;color:var(--ink-soft);line-height:1.75}

#contact{background:var(--paper);position:relative;overflow:hidden}
#contact::before{content:"";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);width:800px;height:400px;border-radius:50%;background:radial-gradient(ellipse,rgb(var(--accent-alt-rgb) / 0.07) 0%,transparent 70%);pointer-events:none}
.contact-layout{display:grid;grid-template-columns:1fr 1.2fr;gap:4rem;align-items:start;margin-top:3rem;position:relative}
.contact-info-block{display:flex;flex-direction:column;gap:2rem}
.contact-info-item{display:flex;flex-direction:column;gap:0.35rem}
.contact-info-label{font-size:0.6rem;letter-spacing:0.2em;text-transform:uppercase;color:var(--ink-dim)}
.contact-info-value{font-size:0.95rem;color:var(--ink)}
.contact-info-value a{color:var(--purple-600);text-decoration:none;transition:color 0.2s}
.contact-info-value a:hover{color:var(--purple-700)}
.social-links{display:flex;gap:1rem;margin-top:0.5rem}
.social-link{display:flex;align-items:center;gap:0.5rem;color:var(--ink-soft);text-decoration:none;font-size:0.78rem;transition:all 0.2s;border:1px solid var(--pill-line);padding:0.55rem 1.1rem;border-radius:var(--radius-pill)}
.social-link:hover{color:var(--purple-700);border-color:var(--purple-600)}
.map-btn{display:inline-flex;align-items:center;gap:0.55rem;margin-top:1.5rem;padding:0.7rem 1.4rem;background:var(--paper2);border:1px solid var(--map-line);border-radius:var(--radius-pill);font-size:0.8rem;color:var(--ink-soft);text-decoration:none;transition:all 0.2s}
.map-btn:hover{border-color:var(--purple-600);color:var(--purple-600)}
.booking-form{background:var(--form-grad);border:1px solid rgb(var(--line-rgb) / 0.25);border-radius:var(--radius-lg);padding:2.5rem;box-shadow:0 24px 55px -20px rgb(var(--shadow-tint) / 0.18)}
.form-title{font-family:var(--font-display);font-size:1.9rem;font-weight:500;margin-bottom:0.4rem;color:var(--ink)}
.form-subtitle{font-size:0.78rem;color:var(--ink-soft);margin-bottom:2rem}
.booking-cta{display:block;width:100%;text-align:center;padding:1rem}
.booking-fallback{display:block;width:100%;text-align:center;padding:1rem;margin-bottom:0.25rem}
.form-consent-note{font-size:0.68rem;color:var(--ink-dim);text-align:center;margin-top:1rem;line-height:1.6}

/* ── «Вторая студия»: кросс-ссылка перед подвалом ─────────────────────────
   Человек, дочитавший лендинг одной студии, обязан узнать, что на этом же
   домене есть вторая. Заголовок и лид секции говорит ХОЗЯЙСКАЯ студия и
   красится её палитрой (.section-title / .section-sub из shared). Карточка
   ниже — слово соседа, и красится палитрой СОСЕДА.

   ── Как красится чужая палитра ────────────────────────────────────────────
   Механика: капсула токенов, привязанная к слагу студии, а не к слову
   «вторая». В теме каждой студии лежит блок вида

       [data-palette="saffron"]{ --other-ink:…; --other-fill:…; … }

   — «вот чем красить кусок страницы, если он представляет Шафран». Разметка
   ставит атрибут на сам элемент: <a class="other-card" data-palette="saffron">.
   Токены объявляются на элементе, поэтому их видит и он сам, и все потомки,
   и ничего за пределами карточки не перекрашивается.

   Почему капсула, а не просто --other-* на :root темы. С двумя студиями
   разницы нет: «другая» ровно одна. С третьей слово «другая» перестаёт
   что-либо значить — на странице Яши их станет две, и один набор :root-имён
   пришлось бы разбирать заново. Капсула этого не требует: третья студия
   добавляет по одному блоку [data-palette="<её слаг>"] в существующие темы
   и получает свой блок в своей, а правила ниже не трогает никто.

   Что обязана объявить тема, чтобы капсула была полной, — весь список
   --other-* ниже. Забытое имя ловит гейт check_css_vars на сборке: shared
   читает их БЕЗ запасного значения именно ради этого.

   Ограничение, о котором надо знать заранее: гейт контраста разворачивает
   var() по последнему объявлению в собранном файле. Пока капсула в теме одна,
   он проверяет именно её. Когда капсул станет две, посчитанной окажется
   последняя — вторую придётся проверить руками или развести правила по
   [data-palette=…] явно. ── */
.other-card{display:grid;grid-template-columns:minmax(0,0.9fr) minmax(0,1.1fr);
  margin-top:2.5rem;background:var(--other-card-bg);
  border:1px solid var(--other-line);border-radius:var(--radius-lg);
  overflow:hidden;text-decoration:none;
  box-shadow:0 18px 44px -26px rgb(var(--other-shadow-rgb) / 0.35);
  transition:transform 0.35s cubic-bezier(0.16,1,0.3,1),
             box-shadow 0.35s cubic-bezier(0.16,1,0.3,1),border-color 0.3s}
.other-card:hover{transform:translateY(-5px);border-color:var(--other-accent);
  box-shadow:0 30px 60px -28px rgb(var(--other-shadow-rgb) / 0.45)}
/* Кольцо фокуса берётся из чужой палитры вместе с остальным: на карточке в
   тёплых тонах фиолетовое кольцо хозяйской студии читалось бы как чужой
   элемент, случайно попавший внутрь. */
.other-card:focus-visible{outline:2px solid var(--other-focus);outline-offset:3px}
/* Заливка под фотографией — на время загрузки и на случай, если пропорции
   колонки и кадра разойдутся. Тон тоже чужой. */
.other-media{position:relative;overflow:hidden;background:var(--other-media-bg)}
.other-media picture{display:block;width:100%;height:100%}
.other-media img{width:100%;height:100%;object-fit:cover;display:block;
  transition:transform 0.6s cubic-bezier(0.16,1,0.3,1)}
.other-card:hover .other-media img{transform:scale(1.035)}
.other-body{display:flex;flex-direction:column;align-items:flex-start;
  justify-content:center;gap:0.6rem;
  padding:clamp(1.5rem,1rem + 2vw,2.75rem)}
.other-card .other-name{font-family:var(--font-display);font-weight:500;line-height:1;
  font-size:clamp(1.9rem,1.2rem + 2vw,3rem);color:var(--other-ink)}
.other-card .other-where{font-size:0.68rem;letter-spacing:0.16em;text-transform:uppercase;
  color:var(--other-accent)}
.other-card .other-tag{font-size:0.88rem;line-height:1.7;color:var(--other-ink-soft);
  max-width:44ch}
.other-card .other-go{display:inline-flex;align-items:center;gap:0.6rem;margin-top:0.9rem;
  padding:0.72rem 1.5rem;border-radius:var(--radius-pill);
  background:var(--other-fill);color:var(--other-on-fill);
  font-size:0.75rem;letter-spacing:0.1em;text-transform:uppercase;
  transition:background 0.25s}
.other-card .other-go::after{content:"→";transition:transform 0.3s}
.other-card:hover .other-go{background:var(--other-fill-lift);color:var(--other-on-fill)}
.other-card:hover .other-go::after{transform:translateX(4px)}
/* Порог 900px не круглый ради круглого: сборка отдаёт этому кадру
   sizes="(max-width:900px) calc(100vw - 3rem), 46vw" (роль slide в build.py),
   и раскладка обязана переключаться там же — иначе браузер выбирает файл под
   ширину, которой на экране нет. */
@media(max-width:900px){
  .other-card{grid-template-columns:minmax(0,1fr);margin-top:2rem}
  .other-media{aspect-ratio:5/4}
  .other-card .other-tag{max-width:none}
}
@media(prefers-reduced-motion:reduce){
  .other-card,.other-media img,.other-card .other-go,
  .other-card .other-go::after{transition:none}
  .other-card:hover{transform:none}
  .other-card:hover .other-media img{transform:none}
  .other-card:hover .other-go::after{transform:none}
}

/* Подвал — одна центрированная колонка. Раньше logo | меню | копирайт стояли
   через space-between, и на широком экране это расползалось по краям, а пункты
   меню и политика висели без выравнивания. */
footer{background:var(--bg-dark);color:var(--white-muted);padding:3rem var(--pad-x) 2.5rem;
  display:flex;flex-direction:column;align-items:center;text-align:center;gap:1.5rem;
  border-top:1px solid rgb(var(--footer-line-rgb) / 0.14)}
.footer-logo{font-family:var(--font-display);font-size:1.15rem;font-weight:500;letter-spacing:0.1em;color:var(--white-muted)}
.footer-links{display:flex;justify-content:center;gap:1.75rem;list-style:none;flex-wrap:wrap}
.footer-links a{font-size:0.74rem;letter-spacing:0.06em;text-transform:uppercase;
  color:var(--white-dim);text-decoration:none;transition:color 0.2s}
.footer-links a:hover{color:var(--white-muted)}
.footer-contact{display:flex;justify-content:center;align-items:center;gap:1.5rem;flex-wrap:wrap}
.footer-contact a{font-size:0.92rem;color:var(--white-muted);text-decoration:none;
  transition:color 0.2s,border-color 0.2s;border-bottom:1px solid transparent;padding-bottom:2px}
.footer-contact a:hover{color:var(--white);border-bottom-color:rgb(var(--footer-line-rgb) / 0.5)}
/* Юридическая строка отделена от остального линией во всю ширину подвала —
   это не декоративный разделитель, а граница смысловых зон. */
.footer-legal{width:100%;padding-top:1.5rem;border-top:1px solid rgb(var(--footer-line-rgb) / 0.12);
  display:flex;flex-direction:column;align-items:center;gap:0.5rem}
.footer-legal-links{display:flex;justify-content:center;gap:1.5rem;flex-wrap:wrap}
.footer-legal a{font-size:0.74rem;color:var(--white-muted);text-decoration:none;
  border-bottom:1px solid rgb(var(--footer-line-rgb) / 0.28);padding-bottom:2px;transition:color 0.2s,border-color 0.2s}
/* Реквизиты продавца — самая тихая строка подвала, но она обязана быть видна. */
.footer-entity{font-size:0.68rem;color:var(--white-dim);margin:0;line-height:1.6}
.footer-legal a:hover{color:var(--white);border-bottom-color:var(--white)}
.footer-copy{font-size:0.72rem;color:var(--white-dim);margin:0}

/* Подпись разработчика — последняя строка подвала, тише реквизитов. Цвет пишем
   здесь, а не в made-by.css: пара «фон footer × цвет подписи» должна стоять
   через предка, иначе гейт контраста её не увидит и промолчит.
   Наведение уводит подпись в фирменный светлый Marketerra — единственное место,
   где на странице клиента появляется чужая палитра, и появляется она только
   в ответ на курсор. */
footer .made-by{color:var(--white-dim)}
footer .made-by:hover,footer .made-by:focus-visible{color:var(--made-by-hover)}

.fade-up{opacity:0;transform:translateY(28px);transition:opacity 0.7s ease,transform 0.7s ease}
.fade-up.visible{opacity:1;transform:translateY(0)}
.fade-up-delay-1{transition-delay:0.1s}
.fade-up-delay-2{transition-delay:0.2s}
.fade-up-delay-3{transition-delay:0.3s}
.fade-up-delay-4{transition-delay:0.4s}


.nav-burger{display:none;background:transparent;border:1px solid var(--line-strong);border-radius:var(--radius-pill);width:40px;height:36px;cursor:pointer;padding:0;align-items:center;justify-content:center;flex-direction:column;gap:4px;transition:border-color 0.2s}
.nav-burger:hover{border-color:var(--purple-600)}
.nav-burger span{display:block;width:16px;height:1.5px;background:var(--ink-soft);border-radius:2px;transition:transform 0.3s,opacity 0.2s}
.nav-burger[aria-expanded="true"] span:nth-child(1){transform:translateY(5.5px) rotate(45deg)}
.nav-burger[aria-expanded="true"] span:nth-child(2){opacity:0}
.nav-burger[aria-expanded="true"] span:nth-child(3){transform:translateY(-5.5px) rotate(-45deg)}
.mobile-menu{position:fixed;top:0;right:0;bottom:0;left:auto;width:min(78vw,320px);z-index:150;justify-content:flex-start;align-items:stretch;border-bottom:none;backdrop-filter:none;-webkit-backdrop-filter:none;background:var(--paper2);border-left:1px solid var(--line);padding:5.5rem 2rem 2rem;transform:translateX(101%);transition:transform 0.38s cubic-bezier(0.16,1,0.3,1);display:flex;flex-direction:column;gap:0.25rem;box-shadow:-24px 0 60px -30px rgb(var(--shadow-tint) / 0.45);overflow-y:auto;overscroll-behavior:contain}
.mobile-menu.open{transform:translateX(0)}
.mobile-menu a{color:var(--ink);text-decoration:none;font-size:1.05rem;letter-spacing:0.02em;padding:0.85rem 0;border-bottom:1px solid rgb(var(--line-rgb) / 0.16);transition:color 0.2s,padding-left 0.2s}
.mobile-menu a:last-of-type{border-bottom:none}
.mobile-menu a:hover,.mobile-menu a:focus-visible{color:var(--purple-700);padding-left:0.35rem}
/* Тот же выход к плитке, что .nav-home в шапке, но для шторки: ниже 901px
   пунктов в панели нет вообще. Пилюлей, а не строкой списка, — это переход
   на другой сайт домена, а не якорь по этой странице, и выглядеть одинаково
   с пунктами он не должен. Селекторы двухклассовые: одноклассовый .mm-home
   проиграл бы .mobile-menu a (0,1,1) и получил бы кегль 1.05rem. */
.mobile-menu .mm-home{display:inline-flex;align-items:center;gap:0.55rem;
  align-self:flex-start;margin-bottom:1.25rem;padding:0.5rem 1rem;
  border:1px solid var(--line-strong);border-bottom:1px solid var(--line-strong);
  border-radius:var(--radius-pill);font-size:0.72rem;letter-spacing:0.1em;
  text-transform:uppercase;color:var(--ink-soft)}
.mobile-menu .mm-home::before{content:"";width:6px;height:6px;flex:0 0 6px;
  border-left:1.5px solid currentColor;border-bottom:1.5px solid currentColor;
  transform:rotate(45deg)}
/* Остальные ссылки шторки на ховере уходят в --purple-700, и у Яши это
   #8b69c9 = 3.93:1 — записанный долг из CONTRAST_DEBT. Дописывать в него
   новый элемент нельзя, поэтому здесь --purple-900: 9.22 у Яши, 9.61
   у Шафрана. */
.mobile-menu .mm-home:hover,.mobile-menu .mm-home:focus-visible{padding-left:1rem;
  color:var(--purple-900);border-color:var(--purple-900)}
.mobile-menu .mm-cta{margin-top:1.5rem;background:var(--accent-solid);color:var(--on-accent-alt);border:none;border-radius:var(--radius-pill);padding:0.9rem 1.5rem;font-family:var(--font-body);font-size:0.8rem;letter-spacing:0.1em;text-transform:uppercase;cursor:pointer;text-align:center}

/* Низкий экран: семь пунктов плюс кнопка брони в 640 px не помещались, и
   «Забронировать» уходило под сгиб — на том самом трафике, который приходит
   из встроенного браузера инстаграма. Режем вертикальный ритм, а не пункты:
   верхний отступ шторки (он клирит шапку в 61 px, 4.5rem = 72 px хватает),
   поля ссылок и отступ кнопки. Замерено: кнопка встаёт на 561 px при 640. */
@media(max-height:700px){
  .mobile-menu{padding-top:4.5rem}
  .mobile-menu a{padding:0.6rem 0;font-size:1rem}
  .mobile-menu .mm-cta{margin-top:1rem;padding:0.8rem 1.5rem}
  .mobile-menu .mm-lang{margin-bottom:0.6rem}
}
/* Связь прямо из меню: не нужно закрывать его и искать блок контактов.
   Отбивка сверху — граница между навигацией и контактами, а не украшение. */
.mm-contact{margin-top:1.35rem;padding-top:1.15rem;
  border-top:1px solid var(--line-soft);display:flex;flex-direction:column}
.mobile-menu .mm-c{display:flex;align-items:center;gap:0.7rem;padding:0.58rem 0;
  border-bottom:none;font-size:0.92rem;color:var(--ink-soft)}
.mobile-menu .mm-c:hover,.mobile-menu .mm-c:focus-visible{padding-left:0;color:var(--purple-700)}
.mm-c-ico{flex:0 0 20px;display:flex;align-items:center;justify-content:center;color:var(--accent-display)}
.mm-c-ico svg{width:18px;height:18px}
/* по колонке текста ссылок (20px иконка + 0.7rem зазор), а не по иконкам */
.mm-hours{margin-top:0.5rem;padding-left:calc(20px + 0.7rem);
  font-size:0.76rem;color:var(--ink-dim)}

/* Политика — не пункт навигации по странице, поэтому под кнопкой и тише. */
.mobile-menu .mm-privacy{margin-top:1.1rem;padding:0;border-bottom:none;text-align:center;
  font-size:0.78rem;letter-spacing:0.03em;color:var(--ink-soft)}
.mobile-menu .mm-privacy:hover,.mobile-menu .mm-privacy:focus-visible{padding-left:0;color:var(--purple-700)}
.menu-scrim{position:fixed;inset:0;z-index:140;background:rgb(var(--ink-rgb) / 0.35);opacity:0;pointer-events:none;transition:opacity 0.3s}
.menu-scrim.open{opacity:1;pointer-events:auto}
body.menu-open{overflow:hidden}
@media(max-width:900px){.nav-burger{display:flex}}
@media(min-width:901px){.mobile-menu,.menu-scrim{display:none}}
/* Russian nav labels are much longer than Latvian and pushed the CTA off the
   row between 901-1150px; tighten the link rail instead of truncating copy. */
@media(min-width:901px) and (max-width:1150px){
  nav{padding:1.1rem 1.75rem}
  .nav-links{gap:1.15rem}
  .nav-links a{font-size:0.7rem;letter-spacing:0.05em}
}
/* Below 420px the logo + toggle + burger + CTA no longer fit, and the CTA is
   the one element that must not be clipped — move the toggle into the menu.
   Base rule first: an equal-specificity rule after the media query would win. */
/* Переключатель был растянут во всю ширину шторки: два двухбуквенных ярлыка
   на 240px, где половина пустая. Делаем компактный сегмент по содержимому.
   justify-content обязателен: .lang-btn — inline-flex, и text-align:center
   на флекс-контейнер не действует, поэтому в растянутых половинках буквы
   прижимались к левому краю. */
.mm-lang{display:none;gap:0;margin-bottom:1.5rem;align-self:flex-start}
.mm-lang a{flex:0 0 auto;min-width:64px;justify-content:center;text-align:center;
  padding:0.5rem 0.9rem;font-size:0.78rem;letter-spacing:0.1em;border-bottom:none;
  border:1px solid var(--line-strong);color:var(--ink-soft)}
.mm-lang a:first-child{border-radius:var(--radius-pill) 0 0 var(--radius-pill)}
.mm-lang a:last-child{border-radius:0 var(--radius-pill) var(--radius-pill) 0;border-left:none}
.mm-lang a.active{background:var(--accent-lift);border-color:var(--accent-lift);color:var(--on-accent-alt)}
.mm-lang a:hover{padding-left:0}
@media(max-width:420px){
  nav .lang-toggle{display:none}
  .mm-lang{display:flex}
}
@media(max-width:900px){
  :root{--gutter:1.5rem}
  nav{padding:1rem 1.5rem}
  .nav-links{display:none}

  /* ── Прозрачная шапка: контент виден под ней, а не упирается в белую плашку.
     Панель ничего не рисует ни до, ни после прокрутки; вместо неё фон носят
     на себе логотип и бургер — иначе на кадрах галереи тёмный логотип
     пропадал бы. Над hero фон им не нужен: там логотип белый по тёмному. */
  nav:not(.mobile-menu),
  body.nav-solid nav:not(.mobile-menu){background:transparent;border-bottom-color:transparent;
    backdrop-filter:none;-webkit-backdrop-filter:none}
  /* Открытая шторка (z-index 150) накрывала бургер (100). Пока он просвечивал
     сквозь полупрозрачное меню, крестик был виден, но не нажимался — клик
     всё равно уходил в шторку. Поднимаем панель над ней: бургер уже
     превращается в × по aria-expanded, и это единственная явная кнопка
     закрытия, кроме затемнения по сторонам. */
  body.menu-open nav:not(.mobile-menu){z-index:160}
  body.nav-solid .nav-logo{background:rgb(var(--plate-rgb) / 0.82);
    backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
    border-radius:var(--radius-pill);padding:0.3rem 0.8rem;
    box-shadow:0 6px 18px -8px rgb(var(--shadow-tint-deep) / 0.3)}
  body.nav-solid .nav-burger{background:rgb(var(--plate-rgb) / 0.82);
    backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px);
    border-color:var(--plate-line);box-shadow:0 6px 18px -8px rgb(var(--shadow-tint-deep) / 0.3)}
  body.nav-solid .lang-toggle .lang-btn{background:rgb(var(--plate-rgb) / 0.82);
    backdrop-filter:blur(14px);-webkit-backdrop-filter:blur(14px)}
  body.nav-solid .lang-toggle .lang-btn.active{background:var(--accent-lift)}
  section,#gallery,#faq{padding:4rem 1.5rem}
  #hero{padding:0 1.5rem 4rem}
  .halls-grid,.pricing-layout,.contact-layout{grid-template-columns:1fr}
  .pricing-layout,.contact-layout{gap:2.5rem}
  .gallery-grid{grid-template-columns:1fr 1fr;grid-auto-rows:180px}
  .gallery-item:first-child{grid-column:1/3;grid-row:auto}
  .rules-grid,.faq-list{grid-template-columns:1fr}
  footer{gap:1.25rem}                      /* колонка и центрирование теперь в базе */
  .footer-links{gap:1.1rem 1.35rem}
  .halls-header{flex-direction:column;align-items:flex-start;gap:1rem}
}
@media(max-width:600px){
  /* Nav — slightly smaller to avoid overflow */
  nav{padding:0.75rem 1.1rem;gap:0.6rem}
  .nav-logo-img{height:28px}
  .nav-logo-word{font-size:1.2rem}
  .lang-btn{padding:0.28rem 0.7rem;font-size:0.65rem}
  /* Шесть пунктов в один ряд не влезают, а перенос 5+1 читается как обрубок —
     фиксируем ровные 3+3. */
  .footer-links{display:grid;grid-template-columns:repeat(3,auto);justify-content:center;gap:0.95rem 1.5rem}
  /* Hide scroll indicator on mobile */
  .hero-scroll{display:none}
  /* Hide Instagram link in gallery on mobile */
  .gallery-header .btn-ghost{display:none}
  .booking-form{padding:1.5rem 1.25rem}
}

  /* ── Согласие на куки ──────────────────────────────────────────────────
     Окно по центру, а не полоска у нижнего края. Полоске отвечали 6,7 %
     посетителей (замер 20.08–11.09, разбор у initConsent() в app.js): её не
     отклоняли, а не замечали — проскроллить мимо было самым дешёвым
     действием, а неответ у нас равен отказу навсегда. Окно убирает из выбора
     вариант «не отвечать».

     z-index выше лайтбокса (250): это ворота, и поверх них не должно
     оказаться ничего — ни шторки меню, ни липкой полосы брони. */
  .consent-scrim{
    position:fixed;inset:0;z-index:300;
    display:flex;align-items:center;justify-content:center;padding:24px;
    background:rgb(var(--shadow-tint-deep) / 0.55);
    backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
    /* Прокрутку держит замок на <html>, но на iOS одного overflow мало:
       касание по вуали продолжает тянуть страницу под ней. */
    touch-action:none;overscroll-behavior:contain;
    /* visibility переключается мгновенно, а не переходом: `transition` по ней
       оставляет элемент невидимым на первый кадр, и focus() по нему молча не
       срабатывает — замерено 11.09, фокус оставался на <body>, а первый Tab
       уводил на ссылки страницы под вуалью. Задержка нужна только на закрытие,
       чтобы окно дожило до конца затухания. */
    opacity:0;visibility:hidden;
    transition:opacity 0.28s ease,visibility 0s linear 0.28s;
  }
  .consent-scrim.visible{
    opacity:1;visibility:visible;
    transition:opacity 0.28s ease,visibility 0s linear 0s;
  }
  /* Замок прокрутки; класс вешает и снимает lockConsentScroll(). */
  html.consent-open,.consent-open body{overflow:hidden}
  .consent-card{
    width:min(460px,100%);
    /* Карточка, а не вуаль, забирает прокрутку на низком экране: иначе в
       альбомной ориентации кнопки уезжают за нижний край без шанса до них
       добраться. */
    max-height:100%;overflow-y:auto;touch-action:auto;
    background:var(--consent-bg);
    border:1px solid rgb(var(--line-rgb) / 0.25);
    border-radius:var(--radius-lg);
    padding:1.75rem 1.6rem 1.5rem;
    box-shadow:0 24px 60px -18px rgb(var(--shadow-tint-deep) / 0.45);
    transform:translateY(12px) scale(0.98);
    transition:transform 0.28s cubic-bezier(0.34,1.2,0.64,1);
  }
  .consent-scrim.visible .consent-card{transform:none}
  .consent-card:focus{outline:none}
  .consent-title{
    font-family:var(--font-display);font-size:1.3rem;font-weight:400;
    color:var(--ink);margin:0 0 0.6rem;
  }
  .consent-text{font-size:0.85rem;color:var(--ink-soft);line-height:1.65;margin:0}
  .consent-text a{color:var(--purple-pale-text);text-decoration:none;border-bottom:1px solid var(--consent-link-line);transition:color 0.2s}
  .consent-text a:hover{color:var(--purple-900);border-bottom-color:var(--purple-900)}
  /* Обе кнопки одного размера и формы: отказ обязан стоить ровно одного
     нажатия, как и согласие. Этого требует и GDPR, и здравый смысл — мелкая
     подчёркнутая ссылка «Noraidīt» была риском без единой выгоды, согласий
     она всё равно не приносила. */
  .consent-actions{display:flex;gap:0.6rem;margin-top:1.35rem}
  .consent-btn{
    flex:1 1 0;min-height:46px;
    font-family:var(--font-body);font-size:0.78rem;letter-spacing:0.08em;
    text-transform:uppercase;cursor:pointer;border-radius:var(--radius-pill);
    transition:background 0.25s,border-color 0.25s,color 0.25s;
  }
  .consent-accept{background:var(--purple-cta);color:var(--on-accent);border:1px solid var(--purple-cta)}
  .consent-accept:hover{background:var(--accent-lift);border-color:var(--accent-lift)}
  .consent-decline{background:transparent;color:var(--ink);border:1px solid var(--control-line)}
  .consent-decline:hover{border-color:var(--purple-cta);color:var(--purple-cta)}
  @media(max-width:600px){
    .consent-scrim{padding:16px}
    .consent-card{padding:1.4rem 1.25rem 1.25rem}
    .consent-title{font-size:1.15rem}
    .consent-text{font-size:0.8rem}
    /* 360px — самый узкий живой экран: два слова капителью в одну строку
       помещаются только с укороченным трекингом. */
    .consent-btn{font-size:0.72rem;letter-spacing:0.06em}
  }
  /* `.consent-scrim.visible` перечислен отдельно не для красоты: у него
     специфичность выше, чем у `.consent-scrim`, и без явного упоминания
     переход открытия переживал это правило — окно продолжало проявляться
     плавно там, где анимаций просили не показывать (замерено 11.09:
     прозрачность 0.62 на 120-й миллисекунде). */
  @media(prefers-reduced-motion:reduce){
    .consent-scrim,.consent-scrim.visible,.consent-card{transition:none}
  }

  /* Низкий экран — отдельный случай, и решает его не ширина, а высота.
     На 664px (айфон во встроенном браузере инстаграма) и ниже первый экран
     делят между собой заголовок, подзаголовок и кнопка, и уступать приходится
     всем сразу. Правило по высоте, а не по ширине: планшет в альбомной
     ориентации такой же тесный, как маленький телефон. */
  @media(max-height:700px){
    .hero-subtitle{margin-bottom:1.5rem}
    /* Верхний отступ, а не только нижний: контент героя выровнен по низу, и
       на низком экране плашка «ФОТОСТУДИЯ · РИГА» заезжала под логотип в
       шапке. Шапка `position:fixed` высотой 61px — отступ держит контент
       под ней. */
    #hero{padding-top:4.75rem;padding-bottom:2.5rem}
  }


/* Space the widget will occupy, reserved before it loads. The iframe arrives
   lazily and CLS is 0 today; a block that appears late is the usual way to
   lose that. 620px is the widget's own grid/day-list breakpoint, so the
   reserved height matches what actually mounts on each side of it. */
/* Heights measured on the widget, not guessed: it reports 965px whenever the
   frame is wider than 620px and 861px below that — its own breakpoint, not this
   page's — and the same in both languages. Reserving a little above each keeps
   the container from growing when pw:height arrives; undershooting by 300px is
   what took this page's CLS off zero the first time.
   Re-measure if the widget's layout changes. The one-screen redesign took ~340px
   off every breakpoint, and the reserve sized for the old widget went on holding
   that much empty space underneath the new one. */
.booking-embed { min-height: 1014px; width: 100%; }
.booking-embed iframe { width: 100%; border: 0; display: block; border-radius: 18px; }
.booking-embed[hidden] { display: none; }
@media (max-width: 620px) { .booking-embed { min-height: 852px; } }

/* ── Clickable gallery ──────────────────────────────────────────────────── */
.gallery-item{border:none;padding:0;background:none;cursor:zoom-in;font:inherit;display:block}
.gallery-item:focus-visible{outline:2px solid var(--focus);outline-offset:3px}

/* ── Lightbox ───────────────────────────────────────────────────────────── */
.lightbox{position:fixed;inset:0;z-index:250;background:var(--lightbox-bg);
  backdrop-filter:blur(8px);-webkit-backdrop-filter:blur(8px);
  display:flex;align-items:center;justify-content:center;padding:3.5rem 1rem;
  opacity:0;transition:opacity 0.25s ease}
.lightbox.open{opacity:1}
.lightbox[hidden]{display:none}
.lb-stage{margin:0;max-width:min(1200px,92vw);max-height:100%;display:flex;
  flex-direction:column;align-items:center;gap:0.9rem}
.lb-stage img{max-width:100%;max-height:78vh;object-fit:contain;display:block;
  border-radius:var(--radius-md);box-shadow:0 40px 90px -30px rgba(0,0,0,0.7)}
.lb-stage figcaption{color:rgb(var(--on-media-rgb) / 0.66);font-size:0.8rem;text-align:center;max-width:60ch}
.lb-close,.lb-nav{position:absolute;background:rgb(var(--on-media-rgb) / 0.10);border:1px solid rgb(var(--on-media-rgb) / 0.22);
  border-radius:50%;cursor:pointer;transition:background 0.2s,border-color 0.2s;
  display:flex;align-items:center;justify-content:center;padding:0}
.lb-close:hover,.lb-nav:hover{background:rgb(var(--on-media-rgb) / 0.2);border-color:rgb(var(--on-media-rgb) / 0.45)}
.lb-close:focus-visible,.lb-nav:focus-visible{outline:2px solid var(--on-media);outline-offset:2px}
.lb-close{top:1.1rem;right:1.1rem;width:42px;height:42px}
.lb-close::before,.lb-close::after{content:"";position:absolute;width:16px;height:1.5px;background:var(--on-media)}
.lb-close::before{transform:rotate(45deg)}
.lb-close::after{transform:rotate(-45deg)}
.lb-nav{top:50%;transform:translateY(-50%);width:46px;height:46px}
.lb-prev{left:1.1rem}
.lb-next{right:1.1rem}
.lb-nav::before{content:"";width:11px;height:11px;border-top:1.5px solid var(--on-media);border-right:1.5px solid var(--on-media)}
.lb-prev::before{transform:rotate(-135deg);margin-left:4px}
.lb-next::before{transform:rotate(45deg);margin-right:4px}
@media(max-width:600px){
  .lightbox{padding:4.5rem 0.5rem}
  .lb-nav{width:40px;height:40px}
  .lb-prev{left:0.4rem}
  .lb-next{right:0.4rem}
}

/* ── Instagram as a second channel in the booking card ──────────────────── */
.booking-alt{display:block;text-align:center;margin-top:0.85rem;font-size:0.8rem;
  color:var(--purple-pale-text);text-decoration:none;border-bottom:1px solid transparent;
  transition:color 0.2s,border-color 0.2s;width:fit-content;margin-left:auto;margin-right:auto}
.booking-alt:hover{color:var(--purple-900);border-bottom-color:var(--purple-900)}

/* ── Hall slideshow arrows ──────────────────────────────────────────────── */
.sl-nav{position:absolute;top:50%;transform:translateY(-50%);z-index:4;
  width:34px;height:34px;border-radius:50%;cursor:pointer;padding:0;
  background:rgb(var(--ink-rgb) / 0.34);border:1px solid rgb(var(--on-media-rgb) / 0.3);
  backdrop-filter:blur(6px);-webkit-backdrop-filter:blur(6px);
  display:flex;align-items:center;justify-content:center;
  opacity:0;transition:opacity 0.25s,background 0.2s}
.hall-slideshow:hover .sl-nav,.sl-nav:focus-visible{opacity:1}
.sl-nav:hover{background:rgb(var(--ink-rgb) / 0.55)}
.sl-nav:focus-visible{outline:2px solid var(--on-media);outline-offset:2px}
.sl-nav::before{content:"";width:8px;height:8px;border-top:1.5px solid var(--on-media);border-right:1.5px solid var(--on-media)}
.sl-prev{left:0.7rem}
.sl-prev::before{transform:rotate(-135deg);margin-left:3px}
.sl-next{right:0.7rem}
.sl-next::before{transform:rotate(45deg);margin-right:3px}
/* no hover on touch — keep them permanently visible there */
@media(hover:none){.sl-nav{opacity:1}}

/* ── Contacts: one number, one row ──────────────────────────────────────── */
.contact-phone{display:flex;align-items:center;gap:0.9rem;flex-wrap:wrap}
.wa-inline{display:inline-flex;align-items:center;gap:0.35rem;font-size:0.78rem;
  color:var(--purple-pale-text);text-decoration:none;border:1px solid var(--pill-line);
  padding:0.3rem 0.7rem;border-radius:var(--radius-pill);transition:all 0.2s}
.wa-inline:hover{color:var(--purple-900);border-color:var(--purple-600)}

/* ── Floating WhatsApp ──────────────────────────────────────────────────── */
.wa-fab{position:fixed;right:1.4rem;bottom:1.4rem;z-index:130;width:56px;height:56px;
  border-radius:50%;display:flex;align-items:center;justify-content:center;
  background:var(--wa-grad);color:var(--on-wa);
  box-shadow:0 14px 34px -12px rgb(var(--shadow-tint-deep) / 0.65);text-decoration:none;
  transition:transform 0.22s cubic-bezier(0.16,1,0.3,1),box-shadow 0.22s;
  opacity:0;pointer-events:none}
.wa-fab.show{opacity:1;pointer-events:auto}
.wa-fab:hover{transform:scale(1.07);box-shadow:0 20px 44px -12px rgb(var(--shadow-tint-deep) / 0.75)}
.wa-fab:focus-visible{outline:2px solid var(--purple-900);outline-offset:3px}
.wa-fab svg{width:28px;height:28px}
.wa-fab::after{content:"";position:absolute;inset:-4px;border-radius:50%;
  border:1px solid var(--wa-pulse-ring);animation:waPulse 2.8s ease-out infinite}
@keyframes waPulse{0%{transform:scale(1);opacity:0.7}70%{transform:scale(1.35);opacity:0}100%{opacity:0}}
@media(max-width:900px){
  /* sits above the sticky booking bar rather than on top of it */
  .wa-fab{right:1rem;bottom:calc(66px + 1rem + env(safe-area-inset-bottom));width:50px;height:50px}
  .wa-fab svg{width:25px;height:25px}
}
@media(prefers-reduced-motion:reduce){.wa-fab::after{animation:none}}

/* ── Rule icons: one line-drawn set instead of six unrelated emoji ─────── */
.rule-icon{color:var(--accent-display);background:rgb(var(--line-rgb) / 0.10)}
.rule-icon svg{width:19px;height:19px}

/* ── Current section in the nav ─────────────────────────────────────────── */
.nav-links a{position:relative}
.nav-links a.is-current{color:var(--purple-900)}
.nav-links a.is-current::after{content:"";position:absolute;left:0;right:0;bottom:-6px;
  height:1.5px;background:var(--accent-display);border-radius:2px}
body[data-hero="1"]:not(.nav-solid) .nav-links a.is-current{color:var(--on-hero)}
body[data-hero="1"]:not(.nav-solid) .nav-links a.is-current::after{background:var(--on-hero)}
.mobile-menu a.is-current{color:var(--purple-700)}

/* ── Sticky bar: transparent, button centred, WhatsApp on the same line ─── */
/* `bottom` считает куки-баннер, а не прячется за ним. Раньше липкую кнопку
   просто гасили, пока баннер висит — и это работало, пока баннер накрывал
   кнопку в герое: человек был вынужден его закрыть. 28.08 баннер перестал
   мешать, закрывать его стало незачем, он повис на всю сессию — и вместе с
   ним осталась выключенной главная дорога к виджету на длинном лендинге.
   Доля открывших виджет упала с 10% до 3,3% ровно с этого дня. */
.mobile-cta{position:fixed;left:0;right:0;bottom:0;z-index:120;display:none;
  align-items:center;justify-content:center;
  padding:0.55rem 1rem calc(0.75rem + env(safe-area-inset-bottom));
  pointer-events:none;
  transform:translateY(140%);
  transition:transform 0.32s cubic-bezier(0.16,1,0.3,1), bottom 0.45s cubic-bezier(0.34,1.2,0.64,1)}
.mobile-cta.show{transform:translateY(0)}
.mobile-cta > *{pointer-events:auto}
.mobile-cta-btn{background:var(--purple-cta);color:var(--on-accent);border:none;border-radius:var(--radius-pill);
  padding:0.95rem 2.4rem;font-family:var(--font-body);font-size:0.8rem;letter-spacing:0.1em;
  text-transform:uppercase;cursor:pointer;white-space:nowrap;
  box-shadow:0 12px 30px -8px rgb(var(--shadow-tint-deep) / 0.55)}
.mobile-cta-wa{position:absolute;right:1rem;width:48px;height:48px;border-radius:50%;
  display:flex;align-items:center;justify-content:center;text-decoration:none;color:var(--on-wa);
  background:var(--wa-grad);
  box-shadow:0 12px 30px -8px rgb(var(--shadow-tint-deep) / 0.55)}
.mobile-cta-wa svg{width:25px;height:25px}
@media(max-width:900px){
  .mobile-cta{display:flex}
  .wa-fab{display:none}                    /* его роль на телефоне играет кнопка в панели */
  /* Две постоянно видимые кнопки «Забронировать» — верхняя в шапке и нижняя в
     липкой панели — это перебор. Оставляем нижнюю: она ближе к большому пальцу
     и шире. До первого экрана её ещё нет, но там своя кнопка в hero. */
  .nav-cta{display:none}
  footer{padding-bottom:calc(2.5rem + 76px + env(safe-area-inset-bottom))}
}

/* ── Map: embedded, mounted on approach ─────────────────────────────────── */
.map-embed{margin-top:1.5rem;border-radius:var(--radius-md);overflow:hidden;
  border:1px solid var(--line);background:var(--paper2);aspect-ratio:16/10}
.map-embed iframe{width:100%;height:100%;border:0;display:block}
.map-skeleton{width:100%;height:100%;
  background:var(--skeleton-grad);
  background-size:220% 100%;animation:mapShimmer 1.6s linear infinite}
@keyframes mapShimmer{from{background-position:120% 0}to{background-position:-120% 0}}
@media(prefers-reduced-motion:reduce){.map-skeleton{animation:none}}

/* ── Denser on phones: the same information in half the scrolling ───────── */
@media(max-width:600px){
  .price-card{padding:0.95rem 1.15rem}
  .pricing-cards{row-gap:0.5rem;column-gap:0.4rem}
  .price-duration{font-size:1.05rem}
  .price-num{font-size:1.55rem}
  .price-note{font-size:0.68rem}
  .price-card.featured::before{top:-9px;left:1.15rem;font-size:0.55rem}
  .price-footnote{margin-top:0.9rem;font-size:0.74rem}

  .rules-grid{gap:0.55rem;margin-top:1.75rem}
  .rule-item{padding:0.9rem 1rem;gap:0.8rem;align-items:center}
  .rule-icon{width:32px;height:32px}
  .rule-icon svg{width:17px;height:17px}
  .rule-text{font-size:0.78rem;line-height:1.55}

  section{padding:3.5rem var(--pad-x)}
  #gallery,#faq{padding:3.5rem var(--pad-x)}
  .section-title{margin-bottom:1.1rem}
  .faq-list{margin-top:1.5rem}
  .faq-q{padding:0.95rem 1.1rem;font-size:0.84rem}
  .faq-a-inner{padding:0 1.1rem 1rem;font-size:0.81rem}
}

/* ── Dragging the slideshow ─────────────────────────────────────────────── */
.hall-slideshow{cursor:grab;user-select:none;-webkit-user-select:none}
.hall-slideshow.is-dragging{cursor:grabbing}
.hall-slideshow img{-webkit-user-drag:none;user-drag:none}

/* ── Halls: 2.2 screens on a phone was the worst offender ───────────────── */
details.hall-equip > summary{cursor:pointer;list-style:none;display:flex;
  align-items:center;justify-content:space-between;gap:0.5rem}
details.hall-equip > summary::-webkit-details-marker{display:none}
details.hall-equip > summary::after{content:"";width:7px;height:7px;flex-shrink:0;
  border-right:1.4px solid currentColor;border-bottom:1.4px solid currentColor;
  transform:rotate(45deg) translateY(-2px);transition:transform 0.25s}
details.hall-equip[open] > summary::after{transform:rotate(-135deg) translateY(-2px)}
details.hall-equip > summary:focus-visible{outline:2px solid var(--focus);outline-offset:3px}
@media(max-width:600px){
  .hall-body{padding:1.15rem}
  .hall-name{font-size:1.5rem;margin-bottom:0.35rem}
  .hall-desc{font-size:0.78rem;line-height:1.6;margin-bottom:1rem}
  .hall-tags{gap:0.35rem;margin-bottom:1rem}
  .hall-tag{font-size:0.62rem;padding:0.25rem 0.6rem}
  .hall-equip{padding-top:0.9rem}
  .hall-equip-list li{font-size:0.75rem}
  .halls-grid{gap:1rem}
  .halls-header{margin-bottom:1.75rem}
  /* the sticky bar carries the CTA on every screen — this one only repeats it */
  .hall-cta{display:none}
}

/* ── Prices: a narrow column, all four cards on shared columns ──────────── */
.pricing-layout{max-width:640px}

/* Каждая карточка раньше была самостоятельным гридом, поэтому её колонки
   считались только по своему содержимому: у карточек с «€ / час» третья
   колонка шире, и цифра уезжала левее, чем у карточек с одним «€». Правые
   края стояли на двух разных линиях (462 и 509 px) — отсюда ощущение
   разнобоя, и никакая min-width этого не лечила.
   Теперь колонки живут на .pricing-cards, а карточки берут их через subgrid:
   трек один на все четыре, цифры выровнены по определению. */
.price-card{grid-column:1/-1;display:grid;grid-template-columns:subgrid;
  align-items:baseline;padding:1.05rem 1.5rem}
.price-duration{grid-column:1;grid-row:1;align-self:center}
.price-note{grid-column:1;grid-row:2;margin-top:0.1rem}
/* lining-nums: у Cormorant и Kenao по умолчанию минускульные цифры — 3 и 5
   свисают под базовую линию, 0 и 2 стоят на ней. Даже при идеальном
   выравнивании такой ряд читается как «врассыпную». */
.price-num{grid-column:2;grid-row:1;justify-self:end;text-align:right;
  font-variant-numeric:lining-nums tabular-nums}
.price-per{grid-column:3;grid-row:1;justify-self:start;margin-left:0;white-space:nowrap}
.price-total{grid-column:2/4;grid-row:2;justify-self:end;margin-top:0.1rem}
.price-footnote{max-width:640px}

/* Без subgrid (старые движки) — прежнее поведение, чтобы вёрстка не сложилась */
@supports not (grid-template-columns:subgrid){
  .pricing-cards{display:flex;flex-direction:column;gap:0.85rem}
  .price-card{grid-template-columns:1fr auto auto;column-gap:0.5rem}
  .price-num{min-width:2.6ch}
  .price-per{min-width:5.2ch}
}

@media(max-width:600px){
  .price-card{padding:0.9rem 1.1rem}
  .price-per{font-size:0.66rem}
}

/* ── Contact card heading: it is a card, not a section ──────────────────── */
.contact-heading{font-family:var(--font-display);font-size:1.5rem;font-weight:500;
  color:var(--ink);margin-bottom:1.1rem;line-height:1.15}
.contact-heading em{font-style:normal;color:var(--accent-display)}

/* On a phone the action comes first; contacts and the map follow it. */
@media(max-width:1000px){
  .booking-layout{display:flex;flex-direction:column}
  .booking-layout .booking-form{order:1}
  .booking-side{order:2}
}

/* ── Offer panel: price + contacts on the left, the widget on the right ─── */
.offer{display:grid;gap:1.75rem;margin-top:2rem}
.offer-price{grid-area:price}
.offer-book{grid-area:book}
.offer-contacts{grid-area:contacts}
.offer .section-title{margin-bottom:1.1rem}
@media(min-width:1001px){
  .offer{grid-template-columns:minmax(0,0.78fr) minmax(0,1.22fr);
    grid-template-rows:auto 1fr;
    grid-template-areas:"price book" "contacts book";
    gap:1.75rem 2.5rem}
  /* the left column stretches to the widget's height, and the map takes up the slack */
  .offer-contacts{align-self:stretch;display:flex;flex-direction:column}
  .offer-contacts .contact-info-block{flex:1;display:flex;flex-direction:column}
  .offer-contacts .map-embed{flex:1;aspect-ratio:auto;min-height:170px;margin-top:1rem}
}
/* the widget sat on a purple card that only made it narrower */
.offer-book .booking-embed{width:100%}

/* ── Contacts: icon and value, nothing else ─────────────────────────────── */
.contact-info-block{background:var(--panel-grad);
  border:1px solid var(--line);border-radius:var(--radius-lg);padding:1.5rem 1.6rem;gap:0}
/* the original rule set flex-direction:column, which stacked icon over value */
.contact-info-item{display:flex;flex-direction:row;align-items:center;gap:0.85rem;
  padding:0.72rem 0;border-bottom:1px solid rgb(var(--line-rgb) / 0.16)}
.contact-info-item:first-of-type{padding-top:0}
.contact-info-item:last-of-type{border-bottom:none;padding-bottom:0}
.contact-ico{flex-shrink:0;color:var(--accent-display);display:flex;align-items:center;justify-content:center;
  width:20px;height:20px}
.contact-ico svg{width:18px;height:18px}
.contact-info-value{font-size:0.92rem;color:var(--ink);line-height:1.4}
.contact-info-value a{color:var(--purple-pale-text);text-decoration:none;transition:color 0.2s}
.contact-info-value a:hover{color:var(--purple-900)}
.contact-phone{display:flex;align-items:center;gap:0.7rem;flex-wrap:wrap;flex:1}
@media(max-width:600px){
  .contact-info-block{padding:1.15rem 1.25rem}
  .contact-info-item{padding:0.62rem 0;gap:0.7rem}
  .contact-info-value{font-size:0.87rem}
}

@media(max-width:1000px){
  /* named grid-areas without a matching template produced a phantom column */
  .offer{grid-template-columns:1fr;grid-template-areas:"price" "book" "contacts"}
}

/* Подпись разработчика в подвале. Разметка — src/shared/made-by.html.

   Здесь только геометрия. Цвет намеренно не назначен: логотип залит
   currentColor, а currentColor приходит от поверхности — `footer .made-by`
   в shared/styles.css для тёмного подвала студий, `.home-foot .made-by`
   в home/home.css для светлого подвала плитки. Так пара «цвет × фон»
   оказывается написанной через предка, и её видит гейт контраста; цвет,
   объявленный здесь, для гейта был бы парой без фона, то есть тишиной. */
.made-by{
  display:inline-flex;align-items:center;gap:0.5rem;
  text-decoration:none;transition:color 0.25s ease;
}
.made-by-label{
  font-size:0.6rem;letter-spacing:0.2em;text-transform:uppercase;
  white-space:nowrap;line-height:1;
}
/* Ширина задана, высота — из viewBox: пропорцию держит сам логотип, и подпись
   не поедет, если контур когда-нибудь переобведут с другой рамкой. */
.made-by-mark{width:94px;height:auto;display:block;flex:0 0 auto}
.made-by:focus-visible{outline:2px solid currentColor;outline-offset:5px;border-radius:3px}

@media (prefers-reduced-motion:reduce){
  .made-by{transition:none}
}

/* ── Studio palette — YASHA ─────────────────────────────────────────────────
   Appended to shared/styles.css and shared/privacy.css by build.py, so these
   :root declarations win. Only colour and typography tokens belong here, plus
   rules unique to this studio. Never redefine --gutter/--container/--pad-x:
   shared/styles.css overrides those inside a media query that this file would
   silently outrank.

   Два слоя токенов:
     1) ЛЕГАСИ-ШКАЛА (--purple-*, --paper*, --ink*, --white*) — исторические
        имена Яши. Их читают правила shared напрямую.
     2) СЕМАНТИЧЕСКИЕ токены (--on-accent, --line, --shadow-tint, --scrim-*…) —
        роли, а не цвета. Введены на шаге 0, чтобы shared/*.css перестал знать
        про фиолетовый. Их значения ниже — ровно те литералы, что были
        захардкожены в shared до токенизации, hex в hex.
   ────────────────────────────────────────────────────────────────────────── */
:root{
  --bg-dark:#0d0b15;--bg-dark2:#181228;
  --purple-900:#4a3580;--purple-700:#8b69c9;--purple-600:#9d7ed5;--purple-cta:#7a56bb;
  --purple-light:#b89fd8;--purple-pale:#d4c0ed;--purple-pale-text:#7b5cb5;
  --card-bg:#f2edfb;--card-bg2:#e9e1f7;
  --paper:#ffffff;--paper2:#f8f5fe;
  --ink:#1c1726;--ink-soft:rgba(28,23,38,0.65);--ink-dim:rgba(28,23,38,0.38);
  --white:#faf7ff;--white-muted:rgba(250,247,255,0.72);--white-dim:rgba(250,247,255,0.62);
  --font-display:"Kenao",Georgia,serif;--font-body:"DM Sans",sans-serif;

  /* ── Линии ────────────────────────────────────────────────────────────────
     --line-rgb — триплет для всей лестницы альф (0.07…0.45) в shared.
     --line / --line-soft — бывшие --card-border / --card-border-light.
     --line-strong — рамка контрола (переключатель языка, бургер, теги). */
  --line-rgb:155 130 210;
  --line:rgba(155,130,210,0.22);
  --line-soft:rgba(155,130,210,0.18);
  --line-strong:rgba(155,130,210,0.35);

  /* Тени. Две разные, потому что в Яше их исторически две: мягкая под
     карточками и плотная под плавающими элементами. */
  --shadow-tint:120 90 180;
  --shadow-tint-deep:74 53 128;

  /* Тёмная фурнитура поверх фото: точки слайдера, стрелки, затемнение шторки */
  --ink-rgb:28 23 38;

  /* Волосяные линии подвала: осветлённый тон студии на --bg-dark */
  --footer-line-rgb:196 174 224;

  /* Фирменный светлый Marketerra (White Jade) — наведение на подпись
     разработчика в подвале. Палитра чужая и в остальной странице не участвует:
     это подпись агентства, а не элемент студии. */
  --made-by-hover:#DAE0B7;

  /* Четвёртый фиолетовый Яши, вне основной шкалы: иконка FAQ, рамка кнопки
     карты, ореол под секцией контактов. У Saffron сводится к бордо. */
  --accent-alt-rgb:83 74 163;

  /* ── Герой ────────────────────────────────────────────────────────────────
     Вся стратегия героя живёт в теме: подложка и три слоя скрима отдаются
     значениями целиком, чтобы студия со светлым героем меняла их, не трогая
     shared. Порядок слоёв = порядок наложения, первый сверху.
       --scrim-main   диагональ, читаемость текста слева
       --scrim-bottom виньетка у нижнего края
       --scrim-top    виньетка под шапкой */
  --hero-glow:
    radial-gradient(ellipse 65% 55% at 75% 35%,rgba(180,150,230,0.22) 0%,transparent 60%),
    radial-gradient(ellipse 50% 60% at 15% 75%,rgba(195,170,240,0.16) 0%,transparent 55%),
    radial-gradient(ellipse 40% 40% at 50% 10%,rgba(210,190,245,0.12) 0%,transparent 50%);
  --scrim-main:
    linear-gradient(100deg,
      rgba(16, 11, 28, 0.90) 0%,
      rgba(16, 11, 28, 0.70) 32%,
      rgba(16, 11, 28, 0.26) 62%,
      rgba(16, 11, 28, 0.08) 100%);
  --scrim-bottom:linear-gradient(to top, rgba(16, 11, 28, 0.55) 0%, transparent 42%);
  --scrim-top:linear-gradient(to bottom, rgba(16, 11, 28, 0.55) 0%, rgba(16, 11, 28, 0.12) 14%, transparent 22%);

  /* Фурнитура поверх СЫРОГО фото — точки и стрелки слайдшоу, хром лайтбокса.
     Всегда светлая: под ней фотография, а не скрим. */
  --on-media:#fff;
  --on-media-rgb:255 255 255;

  /* Текст и шапка ПОВЕРХ ГЕРОЯ. Отдельно от --on-media*: у студии со светлым
     героем это тёмный цвет, а точки слайдера всё равно остаются белыми.
     Меняется в паре со --scrim-*. */
  --on-hero:#fff;
  --on-hero-rgb:255 255 255;
  --on-hero-accent:#c6a9f2;
  /* Самая тихая надпись героя (индикатор прокрутки). Отдельным именем,
     потому что альфа 0.6 читается только на тёмном скриме. */
  --on-hero-quiet:rgb(var(--on-hero-rgb) / 0.6);

  /* Матовые светлые плашки: шапка, бейдж зала, пилюли на цветной карточке.
     Отдельно от --on-media-rgb: это подложка, а не текст на фото. */
  --plate-rgb:255 255 255;

  /* ── Подписи на цветных заливках ───────────────────────────────────────────
     ⚠ Ровно те восемь мест, из-за которых прямая перекраска shared дала бы
     ~2.7:1 у Saffron. Два имени, потому что Яша исторически красит их двумя
     разными белыми: #fff в .btn-primary и --white (#faf7ff) в .nav-cta.
     Студия со светлой заливкой обязана поставить сюда тёмный цвет. */
  --on-accent:#fff;                /* .btn-primary .btn-hall:hover .consent-accept .mobile-cta-btn */
  --on-accent-alt:var(--white);    /* .nav-cta .lang-btn.active .mm-cta .faq-icon */

  /* ── Акцент по РОЛЯМ ───────────────────────────────────────────────────────
     У Яши --purple-600/--purple-700 работают сразу и заливкой, и текстом по
     бумаге. Одному имени два значения не выдать, а светлой студии нужно ровно
     это: заливка светлеет, текст темнеет. Значения ниже — те же литералы Яши.
       --accent-lift    заливка «светлее основной»: ховер кнопок, активный язык
       --accent-solid   сплошная акцентная заливка: иконка FAQ, кнопка в шторке
       --accent-display крупный акцентный текст (em в заголовках), полоски, иконки
     Что осталось на легаси-именах: --purple-cta — заливка покоя; --purple-600
     и --purple-700 — акцентный ТЕКСТ и границы по светлому; --purple-900 —
     самый плотный акцентный текст. */
  --accent-lift:#9d7ed5;           /* = --purple-600 */
  --accent-solid:#8b69c9;          /* = --purple-700 */
  --accent-display:#8b69c9;        /* = --purple-700 */

  /* Границы КОНТРОЛОВ, где общая альфа-линия не дотягивает до 3:1 (WCAG 1.4.11).
     У Яши остаются прежние альфы — тема вправе поставить сплошную линию. */
  --control-line:rgb(var(--line-rgb) / 0.4);        /* .btn-hall */
  --plate-line:rgb(var(--line-rgb) / 0.3);          /* бургер на прокрученной шапке */
  --control-line-dark:rgb(var(--footer-line-rgb) / 0.3); /* переключатель языка в политике */
  --pill-line:var(--line-soft);                     /* .social-link .wa-inline */
  --map-line:rgb(var(--accent-alt-rgb) / 0.18);     /* .map-btn */

  /* Featured-карточка прайса: своя заливка, своя рамка, свои подписи */
  --featured-grad:linear-gradient(160deg,#7352b4 0%,#5a3f96 100%);
  --featured-border:#5a3f96;
  --on-featured:#fff;
  --on-featured-soft:rgba(255,255,255,0.86);

  /* ── Поверхности ──────────────────────────────────────────────────────────
     Четыре почти одинаковых градиента — исторический разнобой Яши. Отданы
     значениями целиком: студия с плоской бумагой ставит сюда сплошной цвет
     и не переписывает ни одного селектора shared. */
  /* Полоса «что входит в стоимость»: плотнее бумаги, карточка на ней светлее
     полосы. Правило живёт в shared, тон — здесь. */
  --band-bg:var(--card-bg);        /* #f2edfb — плотнее и --paper, и --paper2 */
  --band-card:var(--paper);        /* белая карточка поверх полосы            */
  /* Карточка оборудования. Правило живёт в shared, тон — здесь: бумага Яши
     белая, поэтому карточке нужен тинт, иначе на #ffffff её видно только по
     рамке. Секция #halls, где стоит блок, красится var(--paper). */
  --equip-bg:var(--paper2);        /* #f8f5fe                                 */

  --card-grad:linear-gradient(160deg,#f5f0fd 0%,#ede6f9 100%);       /* .hall-card .price-card .rule-item */
  --card-grad-soft:linear-gradient(160deg,#f7f3fd 0%,#f0eafb 100%);  /* .faq-item */
  --form-grad:linear-gradient(160deg,#f5f0fd 0%,#ede8fb 100%);       /* .booking-form */
  --panel-grad:linear-gradient(160deg,#f7f3fd 0%,#efe8fa 100%);      /* .contact-info-block */
  --placeholder-grad:linear-gradient(135deg,#e4d8f7,#d8ccf0);        /* .hall-img под слайдшоу */
  --skeleton-grad:linear-gradient(100deg,#f2ecfb 30%,#e7dff6 50%,#f2ecfb 70%); /* мерцание карты */
  --combo-grad:linear-gradient(160deg,#c4a8e8 0%,#a882d4 100%);      /* .combo-card */

  /* Одиночные поверхности */
  --consent-bg:rgba(245,240,253,0.98);
  --lightbox-bg:rgba(14,10,24,0.94);
  --privacy-nav-bg:rgba(13,11,21,0.92);
  --consent-link-line:rgba(123,92,181,0.45);

  /* WhatsApp: заливка и глиф раздельно, чтобы студия могла взять бордовую
     заливку и оставить белый значок. */
  --wa-grad:linear-gradient(145deg,var(--purple-700),var(--purple-cta));
  --on-wa:#fff;
  --wa-pulse-ring:rgba(139,105,201,0.45);

  /* Кольцо фокуса — одно на всю страницу */
  --focus:var(--purple-cta);
}
body.lang-ru{--font-display:"Cormorant","Cormorant Garamond",Georgia,serif}

/* ══ ПАЛИТРА СОСЕДА ═══════════════════════════════════════════════════════
   Блок «вторая студия» перед подвалом красится не нашими цветами, а цветами
   той студии, про которую он рассказывает: иначе на карточке Шафрана тёплый
   бренд выходит сиреневым, и стилистика, ради которой блок и стоит, врёт.

   Значения ниже — КОПИИ литералов из src/saffron/theme.css. Копия здесь
   неизбежна: build.py склеивает shared + ТОЛЬКО СВОЮ тему, и палитре Шафрана
   больше неоткуда взяться в этом файле. Расхождение не молчаливое — цвет
   виден глазом на собственной странице Шафрана рядом.
   Переименование в Шафране сюда НЕ доедет: при правке его палитры проверять
   этот блок вручную.

   Селектор по слагу, а не по слову «другая»: с третьей студией «другая»
   перестаёт быть одной, и тогда рядом просто встаёт второй такой блок
   [data-palette="<слаг>"], а правила в shared/styles.css не меняются.

   Контраст посчитан по WCAG 2.1 на заливке карточки #fefbf6:
     --other-ink       #321813  15.95
     --other-ink-soft  #69524c   6.99
     --other-accent    #6e2827  10.19
     --other-on-fill на --other-fill      #2b100d на #e18518  6.40
     --other-on-fill на --other-fill-lift #2b100d на #f09b40  8.01
   ⚠ Главный запрет палитры Шафрана держится и здесь: НИКАКОГО БЕЛОГО ТЕКСТА
   НА ШАФРАНОВОЙ ЗАЛИВКЕ — белый по #e18518 даёт 2.73. Подпись пилюли всегда
   --espresso, а ховер СВЕТЛЕЕТ (в тёплой светлой системе так, наоборот
   к Яше).
   ══════════════════════════════════════════════════════════════════════════ */
[data-palette="saffron"]{
  --other-card-bg:    #fefbf6;   /* = saffron --card      */
  --other-media-bg:   #f6e9d8;   /* = saffron --sand      */
  --other-ink:        #321813;   /* = saffron --ink       */
  --other-ink-soft:   #69524c;   /* = saffron --ink-soft  */
  --other-accent:     #6e2827;   /* = saffron --oxblood   */
  --other-fill:       #e18518;   /* = saffron --saffron      */
  --other-fill-lift:  #f09b40;   /* = saffron --saffron-lift */
  --other-on-fill:    #2b100d;   /* = saffron --espresso  */
  --other-line:       #e0cdbe;   /* = saffron --line      */
  --other-shadow-rgb: 110 40 39; /* = saffron --oxblood   */
  --other-focus:      #6e2827;   /* = saffron --focus     */
}
