/* ============================================================
   ASTER HOTEL GROUP — SHARED STYLES
   Used on every page: design tokens, reset, body, navigation, footer
   ============================================================ */

/* ---------- DESIGN TOKENS ---------- */
:root {
  /* Brand palette — Aster brandbook v7.2, 2026-09-18, slide 13.
     These are fixed values. They are not ours to tune: the previous palette was
     darkened twice to reach 4.5:1, and that option no longer exists. Where a
     brand colour cannot carry text, the fix is to use a different brand colour
     for that role, never to alter the hex.

     Measured on Warm Ivory, 2026-09-22:
       Dark Chocolate  14.29:1   body text
       Oxblood         11.52:1   primary actions, accents
       Brick            7.76:1   hover, secondary
       Muted Brass      2.85:1   fails both thresholds — details only
       Dusted Rose      2.14:1   background only, never text          */
  --ink:    #2B1B18;   /* Dark Chocolate — text and dark fields */
  --cream:  #F4EEE3;   /* Warm Ivory — primary light background   */
  --oxblood:#5A1720;   /* Oxblood — the brand's primary colour     */
  --brick:  #7C3132;   /* Brick — secondary warm, hover states     */
  --brass:  #A88957;   /* Muted Brass — material and small accents */
  --rose:   #C99A8B;   /* Dusted Rose — soft secondary background  */

  /* Height of the fixed header, measured 2026-09-28: 115px from 901px up
     (200px logo + 2 × 22px padding), 77px on a phone (below). Used for
     scroll-padding and for the top offset of pages without a hero photo. */
  --header-h: 115px;

  /* The easing of every entrance on the site: quick start, long soft landing. */
  --ease-soft: cubic-bezier(0.22, 1, 0.36, 1);

  /* Typefaces — Jun, 2026-10-07. Fraunces and Outfit have no Cyrillic: until then
     every Russian heading was drawn in Times and every Russian paragraph, menu item
     and button in Helvetica (measured, tools/checks/fonts.py).
     --sans: Latin letters stay Outfit, Russian letters come from Onest (the browser
               picks per letter, so English pages are unchanged).
     --serif: Fraunces; on Russian pages the whole heading is Noto Serif Display,
               digits and Latin included, so no line mixes two serifs of different
               weight. Large Latin brand names keep Fraunces in any language:
               .hero-title, .brand-pin-label, .page-title («Shade Restaurant»). */
  --sans:  'Outfit', 'Onest', sans-serif;
  --serif: 'Fraunces', serif;
  --brand-serif: 'Fraunces', serif;
}

html:lang(ru) {
  --serif: 'Noto Serif Display', serif;
}

@media (max-width: 900px) {
  :root {
    --header-h: 77px;
  }
}

/* ---------- RESET ---------- */
*,
*::before,
*::after {
  margin: 0;
  padding: 0;
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
  /* Section links (/#about) stop below the fixed header, not under it.
     Until 2026-09-29 every anchor landed about 84px too deep. */
  scroll-padding-top: var(--header-h);
}

/* Visually hidden, still read aloud. The logo is now artwork rather than type,
   but the link still needs a name — and if CSS ever fails to load, the words
   simply appear, which is the right fallback. */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

body {
  background: var(--cream);
  color: var(--ink);
  font-family: var(--sans);
  font-weight: 300;
}

/* ============================================================
   NAVIGATION
   ============================================================ */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 100;
  padding: 22px 52px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  transition: background 0.4s, border-color 0.4s, backdrop-filter 0.4s;
  background: transparent;
  border-bottom: 1px solid transparent;
}

/* Full row (≥ 1280px): three columns, so the links sit on the page's centre line –
   the line the hero eyebrow and the page titles are centred on. With space-between
   they sat in the middle of what was left between the logo and the wider right
   block: 43px left of centre in Russian, 18 in English (Jun, 2026-10-14). The
   1fr columns never shrink below their content and keep 32px from the links. */
@media (min-width: 1280px) {
  .nav {
    display: grid;
    grid-template-columns: minmax(max-content, 1fr) auto minmax(max-content, 1fr);
    column-gap: 32px;
  }
  .nav-logo { justify-self: start; }
  .nav-right { justify-self: end; }
}

.header-solid .nav,
.nav.scrolled {
  background: rgba(244, 238, 227, 0.92);
  backdrop-filter: blur(12px);
  border-bottom-color: rgba(168, 137, 87, 0.15);
}

/* ------------------------------------------------------------
   SOLID HEADER — inner pages (Jun, 2026-09-29)

   The home page opens on a dark photograph, so its header starts
   transparent with cream type and turns solid on scroll (nav.js adds
   .scrolled). Inner pages open on cream, where that header would be
   invisible, so they carry class="header-solid" on <body> and get the
   scrolled look from the first pixel.

   Done in CSS, not by nav.js keeping .scrolled on: a page must not
   depend on a script to have a readable header. Every `.nav.scrolled`
   rule in this file is paired with a `.header-solid .nav` twin — keep
   them paired when adding rules.

   A page may open on a photograph instead — an option, not the default:
   drop the class, and measure the header's contrast over that photo
   first (the home page failed 9 of 10 checks before it was measured).
   ------------------------------------------------------------ */
.header-solid main {
  padding-top: var(--header-h);
}

/* Solid while the mobile panel is open. The panel scrolls on short phones since
   it gained the «Услуги» group (951px of content on a 568px screen, measured
   2026-09-28), and without a background the links slid under the logo and
   «Забронировать» as they scrolled past. */
.nav.menu-open {
  background: var(--cream);
  border-bottom-color: rgba(168, 137, 87, 0.15);
}

/* Logo — brandbook v7.2 master artwork, not type.

   Slide 7 assigns the compositions: the horizontal lock-up to the desktop
   header, the ASTER wordmark alone to the mobile header, the full vertical
   lock-up to the foot of the site.

   Slide 10 gives 320px for the horizontal version, but at its own 604×212
   proportion that is 112px tall and would nearly double the height of a fixed
   header. The same slide says screen figures are working guides that "требуют
   проверки на реальном сайте" — so this was 240px, checked in place.

   200px since 2026-09-28 (Jun chose layout variant A). Six Russian menu items,
   the switcher and «Забронировать» need 1306px at 240px with no air at all;
   at 200px, with the tighter gaps below, the row fits 1280px with 46px either
   side of the menu. Measured in the browser, not calculated.

   Two layers rather than one: ::before carries the light version for the
   photograph, ::after the burgundy one for cream, and they cross-fade on the
   same 0.4s the text logo used. Slide 11 requires a single colour across the
   whole composition with the inner gaps transparent, which is what these
   master files already are — no recolouring is done here. */
.nav-logo {
  position: relative;
  display: block;
  width: 200px;
  aspect-ratio: 604 / 212;
  flex: none;
}

.nav-logo::before,
.nav-logo::after {
  content: '';
  position: absolute;
  inset: 0;
  background: center / contain no-repeat;
  transition: opacity 0.4s;
}

.nav-logo::before {
  background-image: url('../images/logo/logo-horizontal-white.svg');
  opacity: 1;
}

.nav-logo::after {
  background-image: url('../images/logo/logo-horizontal-burgundy.svg');
  opacity: 0;
}

.header-solid .nav .nav-logo::before,
.nav.scrolled .nav-logo::before,
.nav.menu-open .nav-logo::before { opacity: 0; }

.header-solid .nav .nav-logo::after,
.nav.scrolled .nav-logo::after,
.nav.menu-open .nav-logo::after  { opacity: 1; }

/* Center menu links. Gap 28px and letter-spacing 0.20em (were 40px and
   0.22em) — variant A, 2026-09-28; see the logo note above. */
.nav-links {
  list-style: none;
  display: flex;
  align-items: center;
  gap: 28px;
}

.nav-links a,
.nav-drop-toggle {
  font-size: 0.72rem;
  letter-spacing: 0.20em;
  text-transform: uppercase;
  color: var(--cream);
  text-decoration: none;
  transition: color 0.3s;
  font-weight: 400;
}

.header-solid .nav .nav-links a,
.nav.scrolled .nav-links a,
.header-solid .nav .nav-drop-toggle,
.nav.scrolled .nav-drop-toggle {
  color: rgba(43, 27, 24, 0.65);
}

.nav-links a:hover,
.nav-drop-toggle:hover {
  color: var(--oxblood) !important;
}

/* The page the guest is on. Set by nav.js from the address, because one shared
   nav cannot know which page it sits in. Underline rather than colour: over the
   photograph the links are cream, and a colour change would not survive both
   states of the header. */
.nav-links a[aria-current="page"],
.nav-drop.is-current > .nav-drop-toggle {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 7px;
}

/* ------------------------------------------------------------
   DROPDOWN — «Услуги» / Facilities

   A disclosure: a real <button> with aria-expanded and aria-controls,
   not role="menu". A menu role tells a screen reader to expect arrow-key
   navigation that ordinary links do not have. Tab moves through the two
   links as through any others.

   Opens on click or Enter/Space, and on hover for a mouse. nav.js keeps a
   click after hover from closing it, and waits 200ms before closing when
   the pointer leaves, so crossing from the button to the list does not
   snap it shut. Hidden with visibility, so closed links are also out of
   the tab order.
   ------------------------------------------------------------ */
.nav-drop {
  position: relative;
}

.nav-drop-toggle {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
  font-family: inherit;
}

.nav-drop-toggle::after {
  content: '';
  width: 5px;
  height: 5px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 0.3s;
}

.nav-drop.is-open .nav-drop-toggle::after {
  transform: translateY(1px) rotate(-135deg);
}

.nav-drop-menu {
  list-style: none;
  position: absolute;
  top: calc(100% + 20px);
  left: 50%;
  display: grid;
  grid-template-columns: repeat(2, 232px);
  gap: 14px;
  padding: 14px;
  background: var(--cream);
  border: 1px solid rgba(168, 137, 87, 0.3);
  border-radius: 2px;
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, -6px);
  transition: opacity 0.24s, transform 0.24s var(--ease-soft), visibility 0.24s;
}

/* Invisible bridge over the 20px gap, so the pointer never leaves the item
   on its way from the button to the list. */
.nav-drop-menu::before {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: 100%;
  height: 20px;
}

.nav-drop.is-open .nav-drop-menu {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
}

/* Photo cards (variant C, Jun 2026-10-14): a photograph, the name, and the
   button system's arrow, which moves 2px on hover. The panel is cream in both
   header states, so its links are always dark. Three classes deep to outrank
   `.nav.scrolled .nav-links a`. 0.82 – the clickable-on-cream standard. */
.nav .nav-links .nav-drop-menu a {
  display: block;
  padding: 0;
  color: rgba(43, 27, 24, 0.82);
  text-decoration: none;
}

.nav-drop-photo {
  display: block;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  border-radius: 1px;
  /* Sand while the photo arrives on the first opening */
  background: rgba(201, 154, 139, 0.28);
}

.nav-drop-photo img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transform: scale(1.04);
  transition: transform 0.6s var(--ease-soft);
}

.nav-drop-name {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  padding: 14px 2px 4px;
  line-height: 1.5;
  white-space: normal;
}

.nav-drop-name::after {
  content: '';
  flex: none;
  width: 16px;
  height: 16px;
  background: currentColor;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h16M14 6l6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
          mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 12h16M14 6l6 6-6 6'/%3E%3C/svg%3E") center / contain no-repeat;
  opacity: 0.45;
  transition: transform 0.24s var(--ease-soft), opacity 0.24s;
}

/* The page the guest is on: its name underlined, as in the row above. */
.nav .nav-links .nav-drop-menu a[aria-current="page"] { text-decoration: none; }
.nav-drop-menu a[aria-current="page"] .nav-drop-name {
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 7px;
}

.nav .nav-links .nav-drop-menu a:focus-visible .nav-drop-photo img { transform: scale(1); }
.nav .nav-links .nav-drop-menu a:focus-visible .nav-drop-name::after { transform: translateX(2px); opacity: 1; }
@media (hover: hover) {
  .nav .nav-links .nav-drop-menu a:hover { color: var(--oxblood); }
  .nav-drop-menu a:hover .nav-drop-photo img { transform: scale(1); }
  .nav-drop-menu a:hover .nav-drop-name::after { transform: translateX(2px); opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .nav-drop-menu, .nav-drop-photo img, .nav-drop-name::after { transition: none; }
  .nav-drop-photo img { transform: none !important; }
}

/* ------------------------------------------------------------
   LANGUAGE SWITCHER

   Restored 2026-09-08 with the Russian version. It was removed on
   2026-08-27 because the second language did not exist yet and the
   control advertised a URL that returned 404.

   The current language is a <span>, not an <a>: a link that leads
   to the page you are already on is noise to a screen reader and a
   dead click to everyone else. Only the other language is a link,
   and it carries lang/hreflang so the label is pronounced in its
   own language rather than read as English letters.

   Order is fixed EN | RU on both pages. A control that reorders
   itself depending on where you are is a control you have to read
   every time instead of aiming at.
   ------------------------------------------------------------ */
.nav-lang {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 400;
}

.nav-lang a,
.nav-lang span {
  text-decoration: none;
  transition: color 0.3s;
}

/* Over the hero photograph. The link matches .nav-links a at 0.85 rather than
   sitting dimmer: the photograph behind the nav is light stone, and anything
   fainter disappears into it. The current language is full cream — the whole
   distinction rests on that one step, plus aria-current for assistive tech. */
.nav-lang a {
  color: rgba(244, 238, 227, 0.95);
}

.nav-lang-current {
  color: var(--cream);
}

.nav-lang-divider {
  width: 1px;
  height: 11px;
  background: rgba(244, 238, 227, 0.35);
}

/* On cream — scrolled, or with the mobile menu open.
   0.78, not 0.5: the project's clickable-on-cream standard, set on 2026-09-06.
   0.5 measures 3.4:1 and fails; 0.78 measures 8.74:1. This is the same defect
   the footer had, and it is not allowed to come back through new code. */
.header-solid .nav .nav-lang a,
.nav.scrolled .nav-lang a,
.nav.menu-open .nav-lang a {
  color: rgba(43, 27, 24, 0.78);
}

.header-solid .nav .nav-lang-current,
.nav.scrolled .nav-lang-current,
.nav.menu-open .nav-lang-current {
  color: rgba(43, 27, 24, 0.85);
}

.header-solid .nav .nav-lang-divider,
.nav.scrolled .nav-lang-divider,
.nav.menu-open .nav-lang-divider {
  background: rgba(43, 27, 24, 0.25);
}

.nav-lang a:hover {
  color: var(--oxblood) !important;
}

/* Right cluster: language, Book Now, plus the burger below 1280px.
   Gap 20px (was 28px) — variant A, 2026-09-28. */
.nav-right {
  display: flex;
  align-items: center;
  gap: 20px;
}

/* Book Now button: the compact primary of the button system (BUTTONS below). */

/* Nav — burger width. Below 1280px the full Russian row no longer fits
   (measured 2026-09-28: 1280 is the narrowest width with 46px either side),
   so the links and the switcher move into the panel.

   This is the nav's own breakpoint and deliberately not the 900px one that
   the page layout uses: until 2026-09-28 the two were the same number, and the
   Russian row broke between 901 and 1064px. menu.js has no copy of this
   number — it asks whether the burger is visible — so the two cannot drift. */
@media (max-width: 1279px) {
  .nav-links {
    display: none;
  }
  /* The switcher moves into the mobile menu, where there is room for
     it. Keeping both copies visible at once would give the page two
     controls doing the same thing. */
  .nav-lang {
    display: none;
  }
}

/* Nav — phone */
@media (max-width: 900px) {
  .nav {
    padding: 16px 20px;
  }
  .nav-right {
    gap: 14px;
  }
  /* Mobile header carries the flower alone. Slide 7 offers the ASTER wordmark
     here and slide 10 licenses the symbol on its own ("Цветок отдельно: иконка,
     текстиль, детали"); the wordmark left the header looking empty, so the mark
     takes its place. Square, so 44px keeps the header at 76px — slightly shorter
     than the wordmark's 80px, no layout cost. Small is fine on a phone: the
     silhouette is what identifies it at this size, and the full lock-up is at
     the foot of the page. */
  .nav-logo {
    width: 44px;
    aspect-ratio: 1;
  }
  .nav-logo::before { background-image: url('../images/logo/symbol-white.svg'); }
  .nav-logo::after  { background-image: url('../images/logo/symbol-burgundy.svg'); }
}

/* Header «Контакты» lands on the footer's contacts column (Jun, 2026-10-14), not
   on the newsletter at the footer's top. Every jump is already padded by
   --header-h (scroll-padding-top). On a computer the row's hairline stops 24px
   under the header, as the home sections do: 24px + the 51px between that line
   and the column (50px padding + 1px border) = 75px. Near the page's end the
   browser stops earlier on its own. On a phone, the column 24px under the header. */
#contact { scroll-margin-top: 75px; }
@media (max-width: 900px) {
  #contact { scroll-margin-top: 24px; }
}

/* ============================================================
   BUTTONS — the architectural system
   Jun approved the reference (aster-architectural-polished, 2026-10-12) and the
   audit's refinements (2026-10-14): crisp 2px corners, an arrow cell behind a
   short hairline, a fill that sweeps in over 240ms, the arrow travelling 2px,
   1px down on press. No size change on hover, no magnetic pull, no delay.
   The site's uppercase and tracking stay (Jun's choice pending, audit point 1).

   .btn            filled; children .btn-label + .btn-arrow (aria-hidden svg)
     .btn-primary    Brick, Oxblood sweep – booking, choosing a room, Apply
     .btn-light      Cream, rose sweep, dark text – primary on a dark section
     .btn-outline    hairline frame, Oxblood text – secondary on a light section
     .btn-compact    the header's Book Now; no arrow cell on a phone (≤ 900px)
   .btn-text       label + underline + arrow, no ground – tertiary
     .btn-on-dark    light text for the hero photograph and dark sections

   Hover only where there is a mouse: on iOS a :hover style change on tap makes
   the first tap only "hover" (found on the seating buttons, 2026-10-10).
   Focus shows the same sweep plus the ring. Arrows face up-right (does
   something, or leaves the site) or right (.is-right: goes to a place on the
   site). Clicks on the label, arrow or svg all resolve to the same <a>/<button>:
   the GA4 delegate uses closest(), so nothing fires twice.
   ============================================================ */
.btn {
  --btn-base: var(--brick);
  --btn-fill: var(--oxblood);
  --btn-text: var(--cream);
  --btn-hover-text: var(--cream);
  --btn-line: transparent;
  --btn-track: 0.26em;
  position: relative;
  isolation: isolate;
  display: inline-flex;
  align-items: center;
  justify-content: space-between;
  min-height: 54px;
  max-width: 100%;
  margin: 0;
  padding: 0;
  border: 1px solid var(--btn-line);
  border-radius: 2px;
  background: var(--btn-base);
  color: var(--btn-text);
  font-family: var(--sans);
  font-size: 0.7rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: var(--btn-track);
  text-transform: uppercase;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: rgba(124, 49, 50, 0.12);
  transition: color 240ms ease, border-color 240ms ease, transform 120ms ease;
}

.btn::before {
  content: "";
  position: absolute;
  z-index: -1;
  inset: -1px;
  border-radius: 2px;
  background: var(--btn-fill);
  clip-path: inset(0 100% 0 0 round 2px);
  transition: clip-path 240ms var(--ease-soft);
}

/* No min-width: 0: the label may wrap between words on a narrow screen but
   never shrinks under its longest word. */
.btn-label {
  display: block;
  padding: 15px 23px;
}

.btn-arrow {
  position: relative;
  align-self: stretch;
  display: flex;
  align-items: center;
  justify-content: center;
  /* width as well as flex-basis: WebKit sizes the button from the arrow's
     content (the 18px svg) and ignores the basis, so the cell spilled out of
     the Brick by 34px in the hero and 21px in the header (2026-10-14). */
  flex: 0 0 52px;
  width: 52px;
}

/* The short divider: 20px, never the full height */
.btn-arrow::before {
  content: "";
  position: absolute;
  left: 0;
  top: 50%;
  width: 1px;
  height: 20px;
  transform: translateY(-50%);
  background: currentColor;
  opacity: 0.2;
}

.btn svg,
.btn-text svg {
  width: 18px;
  height: 18px;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.5;
  stroke-linecap: round;
  stroke-linejoin: round;
  transition: transform 240ms var(--ease-soft);
}

.btn:focus-visible { color: var(--btn-hover-text); }
.btn:focus-visible::before { clip-path: inset(0 0 0 0 round 2px); }
.btn:focus-visible .btn-arrow svg { transform: translate(2px, -2px); }
.btn:focus-visible .btn-arrow svg.is-right { transform: translateX(2px); }

@media (hover: hover) {
  .btn:hover:not(:disabled) { color: var(--btn-hover-text); }
  .btn:hover:not(:disabled)::before { clip-path: inset(0 0 0 0 round 2px); }
  .btn:hover:not(:disabled) .btn-arrow svg { transform: translate(2px, -2px); }
  .btn:hover:not(:disabled) .btn-arrow svg.is-right { transform: translateX(2px); }
}

.btn:active:not(:disabled),
.btn-text:active { transform: translateY(1px); }

.btn:disabled,
.btn[aria-disabled="true"] {
  opacity: 0.5;
  cursor: not-allowed;
}

/* Light-section focus ring; the hero, the header and dark sections set their own below/in page CSS. */
.btn:focus-visible,
.btn-text:focus-visible {
  outline: 1px solid var(--oxblood);
  outline-offset: 4px;
}

.btn-light {
  --btn-base: var(--cream);
  --btn-fill: #C99A8B;
  --btn-text: var(--ink);
  --btn-hover-text: var(--ink);
}

.btn-outline {
  --btn-base: transparent;
  --btn-text: var(--oxblood);
  --btn-line: rgba(90, 23, 32, 0.4);
  min-height: 50px;
}
.btn-outline .btn-label { padding: 13px 19px; }
.btn-outline .btn-arrow { flex-basis: 46px; width: 46px; }

.btn-outline.btn-on-dark {
  --btn-fill: var(--cream);
  --btn-text: var(--cream);
  --btn-hover-text: var(--ink);
  --btn-line: rgba(244, 238, 227, 0.5);
}

/* Header: the old Book Now size (38px tall, 115px header) with a narrower
   arrow cell; label padding 26 → 20 so the 1280px row keeps ~42px either side
   of the links (54 before). */
.btn-compact {
  min-height: 0;
  line-height: normal;
  font-size: 0.68rem;
  letter-spacing: 0.25em;
}
/* The header row must never break "Book Now" onto two lines. */
.btn-compact { flex-shrink: 0; }
.btn-compact .btn-label { padding: 11px 20px; white-space: nowrap; }
.btn-compact .btn-arrow { flex-basis: 36px; width: 36px; }
.btn-compact .btn-arrow::before { height: 14px; }
.btn-compact svg { width: 15px; height: 15px; }

/* Phone header: label only, exactly the old size – no arrow, no divider,
   no space kept for them (audit point 4). */
@media (max-width: 900px) {
  .btn-compact { font-size: 0.62rem; }
  .btn-compact .btn-label { padding: 9px 17px; }
  .btn-compact .btn-arrow { display: none; }
}

.btn-text {
  --btn-track: 0.26em;
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 10px 0;
  border: 0;
  background: none;
  color: var(--oxblood);
  font-family: var(--sans);
  font-size: 0.7rem;
  font-weight: 500;
  line-height: 1.4;
  letter-spacing: var(--btn-track);
  text-transform: uppercase;
  text-align: left;
  text-decoration: none;
  cursor: pointer;
  -webkit-tap-highlight-color: rgba(124, 49, 50, 0.12);
  transition: transform 120ms ease;
}
.btn-text.btn-on-dark { color: var(--cream); }

.btn-text-label {
  position: relative;
  padding-bottom: 4px;
}

/* A faint line always, a full one drawn in on hover. It stops at the last
   letter, not after the tracking that follows it. */
.btn-text-label::before,
.btn-text-label::after {
  content: "";
  position: absolute;
  left: 0;
  right: var(--btn-track);
  bottom: 0;
  height: 1px;
  background: currentColor;
}
.btn-text-label::before { opacity: 0.32; }
.btn-text-label::after {
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 240ms var(--ease-soft);
}
.btn-text svg { width: 17px; height: 17px; }

.btn-text:focus-visible .btn-text-label::after { transform: scaleX(1); }
.btn-text:focus-visible svg { transform: translate(2px, -2px); }
.btn-text:focus-visible svg.is-right { transform: translateX(2px); }
@media (hover: hover) {
  .btn-text:hover .btn-text-label::after { transform: scaleX(1); }
  .btn-text:hover svg { transform: translate(2px, -2px); }
  .btn-text:hover svg.is-right { transform: translateX(2px); }
}

@media (prefers-reduced-motion: reduce) {
  .btn, .btn::before, .btn svg,
  .btn-text, .btn-text svg, .btn-text-label::after { transition: none; }
  .btn svg, .btn-text svg { transform: none !important; }
  .btn:active, .btn-text:active { transform: none; }
}

/* ============================================================
   FOOTER
   ============================================================ */
.footer {
  background: var(--cream);
  padding: 120px 52px 40px;
  border-top: 1px solid rgba(168, 137, 87, 0.2);
}

.footer-top {
  max-width: 1400px;
  margin: 0 auto 100px;
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: 100px;
  /* center, not start: the two halves are separate blocks of different height,
     and aligning them by their top edges put the monogram level with the first
     line of the newsletter instead of level with the newsletter itself. Their
     centres now sit on the same horizontal line. */
  align-items: center;
}

/* The monogram, not the full lock-up. The footer's first column is wide and the
   vertical composition left a long empty band to its right; the monogram is
   square, so at the same column width it reads much larger and fills it.
   Slide 8 sanctions the monogram as a standalone mark, and the header still
   carries the full horizontal lock-up, so the complete brand is present on the
   page. Burgundy on cream — the primary pairing of slide 11. */
.footer-brand {
  width: clamp(240px, 27vw, 360px);
  aspect-ratio: 1;
  background: url('../images/logo/monogram-burgundy.svg') center / contain no-repeat;
}

.footer-tagline {
  font-family: var(--serif);
  font-style: italic;
  font-size: clamp(1.3rem, 1.9vw, 1.7rem);
  color: rgba(43, 27, 24, 0.65);
  margin-top: 32px;
  line-height: 1.5;
  max-width: 400px;
}

/* Newsletter block */
.footer-newsletter {
  /* The old padding-top: 16px existed only to nudge this block into line with a
     top-aligned monogram. With the two halves centred against each other it
     would push them back out of balance. */
}

.newsletter-label {
  font-size: 0.78rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--oxblood);
  margin-bottom: 20px;
  font-weight: 500;
}

.newsletter-title {
  font-family: var(--serif);
  font-size: 1.6rem;
  font-weight: 400;
  line-height: 1.25;
  margin-bottom: 20px;
  color: var(--ink);
}

.newsletter-row {
  display: flex;
  border-bottom: 1px solid var(--ink);
  padding-bottom: 12px;
  margin-bottom: 14px;
}

/* Consent (Jun, 2026-10-14): the lawyer's text verbatim, unticked by default, required. */
.newsletter-consent {
  display: grid;
  grid-template-columns: 18px minmax(0, 1fr);
  gap: 10px;
  align-items: start;
  font-size: 0.75rem;
  line-height: 1.55;
  color: rgba(43, 27, 24, 0.72);
  cursor: pointer;
}

.newsletter-consent input {
  width: 16px;
  height: 16px;
  margin: 2px 0 0;
  accent-color: var(--oxblood);
  cursor: pointer;
}

.newsletter-consent a {
  color: var(--oxblood);
}

.newsletter-consent input:focus-visible {
  outline: 2px solid var(--oxblood);
  outline-offset: 2px;
}

.newsletter-row:has(.newsletter-input[aria-invalid="true"]) {
  border-bottom-color: var(--brick);
}

/* The e-mail field shows focus on the row's own line, not with a box: the
   outline's 4px offset ran over the arrow (Jun, 2026-10-14). The line turns
   Oxblood and doubles (a 1px shadow under the 1px border), so focus stays
   plain to see; the arrow keeps its own ring. */
.newsletter-input:focus,
.newsletter-input:focus-visible {
  outline: none;
}
.newsletter-row:has(.newsletter-input:focus-visible) {
  border-bottom-color: var(--oxblood);
  box-shadow: 0 1px 0 var(--oxblood);
}

.newsletter-consent:has(input[aria-invalid="true"]) {
  color: var(--brick);
}

.newsletter-status {
  margin-top: 12px;
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--ink);
}

.newsletter-status.is-error {
  color: var(--brick);
}

.newsletter-input {
  flex: 1;
  border: none;
  background: none;
  font-family: var(--sans);
  font-size: 0.95rem;
  color: var(--ink);
}

.newsletter-input::placeholder {
  color: rgba(43, 27, 24, 0.65);
}

.newsletter-submit {
  border: none;
  background: none;
  cursor: pointer;
  font-size: 1.2rem;
  color: var(--oxblood);
}


/* Footer columns */
.footer-bottom {
  max-width: 1400px;
  margin: 0 auto;
  padding-top: 50px;
  border-top: 1px solid rgba(168, 137, 87, 0.2);
  display: grid;
  /* minmax(0, 1fr), not 1fr. A grid track defaults to min-width:auto, so an
     unbreakable string — reservation@asterhotelgroup.com — refuses to shrink and
     can push the whole grid past the viewport. It does not show at the current
     type sizes, but it is one long address away from doing so. */
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 48px;
}

.footer-col h4 {
  font-size: 0.78rem;
  letter-spacing: 0.25em;
  text-transform: uppercase;
  color: var(--oxblood);
  margin-bottom: 24px;
  font-weight: 500;
}

.footer-col a,
.footer-col button,
.footer-col p {
  overflow-wrap: anywhere;   /* e-mail не должен распирать колонку */
  display: block;
  font-size: 0.85rem;
  color: rgba(43, 27, 24, 0.65);
  text-decoration: none;
  margin-bottom: 10px;
  line-height: 1.6;
  transition: color 0.3s;
}

.footer-col button {
  background: none;
  border: none;
  padding: 0;
  font-family: inherit;
  font-weight: inherit;
  text-align: left;
  cursor: pointer;
}

.footer-col a:hover,
.footer-col button:hover {
  color: var(--oxblood);
}

.footer-col a:focus-visible,
.footer-col button:focus-visible {
  outline: 1px solid var(--oxblood);
  outline-offset: 4px;
}

/* Footer tone carries meaning, and both levels must clear 4.5:1:
     0.78 — clickable       (links, the Book Now button, Privacy · Terms)
     0.65 — not clickable   (pending sections, contact qualifiers, copyright)
   Without the difference a guest cannot tell by eye what opens. */
.footer-col a,
.footer-col button {
  color: rgba(43, 27, 24, 0.78);
}

.footer-col p.footer-col-pending {
  color: rgba(43, 27, 24, 0.65);
}

/* Was opacity: 0.5, which multiplied against the link colour and produced
   2.08:1 — a contrast failure invisible to a scan that only reads `color`. */
.footer-col-muted {
  color: rgba(43, 27, 24, 0.65);
}

/* Copyright row */
.footer-awards {
  max-width: 1400px;
  margin: 62px auto 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 40px 55px;
}

/* Jun's approved design (2026-10-13): light marks on the cream ground, no tiles. Row 1 – the
   honours, a hairline, the certifications; row 2 – Booking.com, newest year first. Each mark
   sits in its own box (object-fit) so the different shapes read at one visual weight. */
.footer-awards ul {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 52px;
}

.footer-awards-certs {
  gap: 24px !important;
  padding-left: 50px;
  border-left: 1px solid rgba(168, 137, 87, 0.3);
}

.footer-awards-booking {
  flex-basis: 100%;
  gap: 44px !important;
}

.footer-awards img { display: block; object-fit: contain; }
.fa-tha { width: 170px; height: 168px; }
.fa-tc { width: 134px; height: 158px; }
.fa-booking { width: 140px; height: 112px; }
.fa-iso { width: 84px; height: 86px; }

/* Laptops and tablets in landscape: the first row stays one row. */
@media (min-width: 901px) and (max-width: 1240px) {
  .footer-awards { gap: 36px 36px; }
  .footer-awards ul { gap: 34px; }
  .footer-awards-certs { padding-left: 34px; }
  .fa-tha { width: 136px; height: 134px; }
  .fa-tc { width: 108px; height: 128px; }
  .fa-iso { width: 70px; height: 72px; }
  .footer-awards-booking { gap: 24px !important; }
  .fa-booking { width: 128px; height: 102px; }
}

@media (max-width: 900px) {
  .footer-awards { margin-top: 48px; gap: 28px; flex-direction: column; }
  .footer-awards ul { gap: 14px 12px; }
  .footer-awards-booking { order: 2; gap: 14px !important; }
  .footer-awards-certs { order: 3; gap: 16px !important; padding: 26px 0 0; border-left: 0; border-top: 1px solid rgba(168, 137, 87, 0.3); }
  .fa-tha { width: 27vw; max-width: 120px; height: auto; }
  .fa-tc { width: 20vw; max-width: 92px; height: auto; }
  .fa-booking { width: 24vw; max-width: 104px; height: auto; }
  .fa-iso { width: 64px; height: auto; }
}

.footer-copy-row {
  max-width: 1400px;
  margin: 60px auto 0;
  padding-top: 30px;
  border-top: 1px solid rgba(168, 137, 87, 0.15);
  display: flex;
  justify-content: space-between;
  font-size: 0.72rem;
  color: rgba(43, 27, 24, 0.65);
  letter-spacing: 0.05em;
}

.footer-legal a {
  color: rgba(43, 27, 24, 0.78);
  text-decoration: none;
  transition: color 0.3s;
}

.footer-legal a:hover {
  color: var(--oxblood);
}

.footer-legal a:focus-visible {
  outline: 1px solid var(--oxblood);
  outline-offset: 3px;
}

/* Footer — mobile */
@media (max-width: 900px) {
  .footer {
    padding: 60px 24px 30px;
  }
  .footer-top {
    grid-template-columns: 1fr;
    gap: 48px;
    margin-bottom: 60px;
  }
  .footer-bottom {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 32px;
  }
  /* Contacts take the full row on a phone: in half of a 390px screen the
     addresses broke inside the domain and a last letter could sit alone
     (outside audit, 2026-10-14). The other groups stay two by two;
     overflow-wrap above still guards against overflow. */
  .footer-col-contacts {
    grid-column: 1 / -1;
  }
  .footer-copy-row {
    flex-direction: column;
    gap: 8px;
    margin-top: 40px;
  }
}

/* ============================================================
   MOBILE MENU
   ============================================================ */

/* Burger — two hairlines, hidden on desktop */
.nav-burger {
  display: none;
  position: relative;
  flex-shrink: 0; /* the icon keeps its size; Book Now gives way instead */
  width: 26px;
  height: 16px;
  padding: 0;
  background: none;
  border: none;
  cursor: pointer;
}

.nav-burger-line {
  position: absolute;
  left: 0;
  width: 100%;
  height: 1px;
  background: rgba(244, 238, 227, 0.85);
  transition: transform 0.4s cubic-bezier(0.22, 1, 0.36, 1), background 0.4s;
}

.nav-burger-line:nth-child(1) { top: 3px; }
.nav-burger-line:nth-child(2) { bottom: 3px; }

.header-solid .nav .nav-burger-line,
.nav.scrolled .nav-burger-line,
.nav.menu-open .nav-burger-line {
  background: rgba(43, 27, 24, 0.75);
}

/* Burger becomes a cross when the panel is open */
.nav-burger.is-open .nav-burger-line:nth-child(1) {
  top: 50%;
  transform: translateY(-50%) rotate(45deg);
}

.nav-burger.is-open .nav-burger-line:nth-child(2) {
  top: 50%;
  bottom: auto;
  transform: translateY(-50%) rotate(-45deg);
}

/* Full-screen panel */
.mobile-menu {
  position: fixed;
  inset: 0;
  z-index: 90;
  background: var(--cream);
  display: flex;
  flex-direction: column;
  align-items: center;
  /* Centred with auto margins on the first and last child, not with
     justify-content: center. With seven entries the panel can be taller than a
     small phone, and justify-content centring would push the top of the list
     above the screen where it cannot be scrolled to. Auto margins centre when
     there is room and fall back to the top when there is not. */
  overflow-y: auto;
  overscroll-behavior: contain;
  /* Clears the header: 115px tall between 901 and 1279px, where the panel now
     also appears (full logo); 77px on a phone, see below. */
  padding: 145px 32px 48px;
  opacity: 0;
  visibility: hidden;
  transition: opacity 0.45s ease, visibility 0.45s;
}

.mobile-menu.is-open {
  opacity: 1;
  visibility: visible;
}

/* On a tablet the panel is wide; the column keeps a phone-like measure
   instead of stretching the hairlines across 1,000px. */
.mobile-menu-links,
.mobile-menu-foot {
  width: 100%;
  max-width: 560px;
}

.mobile-menu-links {
  list-style: none;
  margin-top: auto;
}

.mobile-menu-links li {
  border-bottom: 1px solid rgba(168, 137, 87, 0.18);
}

.mobile-menu-links a {
  display: block;
  padding: 22px 0;
  font-family: var(--serif);
  font-weight: 300;
  font-size: 2.1rem;
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--ink);
  text-decoration: none;
  transition: color 0.3s;
}

.mobile-menu-links a:hover {
  color: var(--oxblood);
}

.mobile-menu-foot {
  margin-top: 48px;
  margin-bottom: auto;
}

/* «Услуги» — a heading for the two pages under it, not a link. Small caps
   rather than the large serif, so it does not read as one more destination. */
.mobile-menu-group {
  padding: 20px 0 10px;
}

.mobile-menu-group-label {
  font-size: 0.66rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(43, 27, 24, 0.65);
}

.mobile-menu-sub {
  list-style: none;
  margin-top: 4px;
}

.mobile-menu-links .mobile-menu-sub li {
  border-bottom: none;
}

.mobile-menu-links .mobile-menu-sub a {
  padding: 10px 0;
  font-size: 1.6rem;
}

.mobile-menu-links a[aria-current="page"] {
  color: var(--oxblood);
}

/* Language switcher inside the mobile menu — same rules as the desktop
   one: current language is a span, the other is a link carrying lang
   and hreflang. Sized larger here because it is a primary target on a
   touch screen rather than a corner detail. */
.mobile-menu-lang {
  display: flex;
  align-items: center;
  gap: 14px;
  font-size: 0.8rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding-bottom: 22px;
  border-bottom: 1px solid rgba(168, 137, 87, 0.18);
}

.mobile-menu-lang a {
  color: rgba(43, 27, 24, 0.78);   /* clickable-on-cream standard — see above */
  text-decoration: none;
  padding: 6px 0;
  transition: color 0.3s;
}

.mobile-menu-lang .nav-lang-current {
  color: rgba(43, 27, 24, 0.85);
  padding: 6px 0;
}

.mobile-menu-lang .nav-lang-divider {
  width: 1px;
  height: 12px;
  background: rgba(43, 27, 24, 0.25);
}

.mobile-menu-lang a:hover {
  color: var(--oxblood);
}

/* Direct contact — the Book Now button has no destination until Phase 5 */
.mobile-menu-contact {
  margin-top: 22px;
  padding-top: 20px;
  /* No border here either. The language switcher directly above already closes
     with a border-bottom, and the two together read as a double rule. */
}

.mobile-menu-contact a {
  display: block;
  font-size: 0.9rem;
  letter-spacing: 0.02em;
  color: rgba(43, 27, 24, 0.75);
  text-decoration: none;
  margin-bottom: 12px;
  transition: color 0.3s;
}

.mobile-menu-contact a:last-child {
  margin-bottom: 0;
}

.mobile-menu-contact a:hover {
  color: var(--oxblood);
}

.mobile-menu-contact span {
  display: block;
  margin-top: 3px;
  font-size: 0.62rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: rgba(43, 27, 24, 0.65);
}

/* Phone header is 77px, so the panel's original 100px top clears it. */
@media (max-width: 900px) {
  .mobile-menu {
    padding-top: 100px;
  }
}

/* Stops the page scrolling behind the open panel */
body.menu-open {
  overflow: hidden;
}

/* Below the nav's own breakpoint (see "Nav — burger width"). This block must
   stay BELOW the `.nav-burger { display: none }` base rule above — same
   specificity, so the later rule wins. */
@media (max-width: 1279px) {
  .nav-burger {
    display: block;
  }
}

/* The panel can never appear where the full row is shown */
@media (min-width: 1280px) {
  .mobile-menu {
    display: none;
  }
}

/* ============================================================
   BOOKING CHANNELS — reception, Telegram, e-mail
   Under the Bnovo module on /booking/ (2026-10-14). They were the
   contents of the booking dialog, which every Book Now opened until
   the booking page replaced it; the class names are kept from then.
   ============================================================ */
.booking-dialog-eyebrow {
  font-size: 0.65rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--oxblood);
  font-weight: 500;
  margin-bottom: 14px;
}

.booking-dialog-title {
  font-family: var(--serif);
  font-weight: 400;
  font-size: 2rem;
  line-height: 1.15;
  letter-spacing: -0.01em;
  margin-bottom: 14px;
}

.booking-dialog-title em {
  font-style: italic;
  color: var(--brass);
}

.booking-dialog-note {
  font-size: 0.9rem;
  line-height: 1.7;
  color: rgba(43, 27, 24, 0.65);
  margin-bottom: 30px;
}

.booking-dialog-channels {
  border-top: 1px solid rgba(168, 137, 87, 0.22);
}

.booking-channel {
  display: block;
  padding: 18px 0;
  border-bottom: 1px solid rgba(168, 137, 87, 0.22);
  text-decoration: none;
  color: var(--ink);
  transition: color 0.3s;
}

.booking-channel:hover {
  color: var(--oxblood);
}

.booking-channel:focus-visible {
  outline: 1px solid var(--oxblood);
  outline-offset: 4px;
}

.booking-channel-label {
  display: block;
  font-size: 0.62rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(43, 27, 24, 0.65);
  margin-bottom: 5px;
}

.booking-channel-value {
  display: block;
  font-size: 1.05rem;
  letter-spacing: 0.01em;
}

@media (max-width: 900px) {
  .booking-dialog-title {
    font-size: 1.6rem;
  }
  .booking-channel-value {
    font-size: 0.95rem;
  }
}

/* ============================================================
   404 PAGE
   Standalone: no nav, no footer. A guest who lands here needs
   one clear way back, not the whole site's furniture.
   ============================================================ */
.notfound {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: flex-start;
  padding: 52px;
  max-width: 720px;
  margin: 0 auto;
}

/* Same vertical lock-up as the footer — the 404 is a full-page composition on
   cream, so it takes the full logo rather than the header's horizontal one. */
.notfound-logo {
  display: block;
  width: 140px;
  aspect-ratio: 840 / 1118;
  background: url('../images/logo/logo-vertical-burgundy.svg') center / contain no-repeat;
  margin-bottom: 40px;
}

.notfound-logo span {
  color: rgba(43, 27, 24, 0.7);
}

.notfound-eyebrow {
  font-size: 0.65rem;
  letter-spacing: 0.3em;
  text-transform: uppercase;
  color: var(--oxblood);
  font-weight: 500;
  margin-bottom: 18px;
}

.notfound-title {
  font-family: var(--serif);
  font-weight: 300;
  font-size: clamp(2.2rem, 5vw, 3.4rem);
  line-height: 1.1;
  letter-spacing: -0.01em;
  color: var(--ink);
  margin-bottom: 22px;
}

.notfound-title em {
  font-style: italic;
  color: var(--brass);
}

.notfound-text {
  font-size: 1rem;
  line-height: 1.75;
  color: rgba(43, 27, 24, 0.65);
  max-width: 440px;
  margin-bottom: 40px;
}

/* Return to the hotel: .btn.btn-primary (BUTTONS above) */

@media (max-width: 900px) {
  .notfound { padding: 32px 20px; }
  .notfound-logo { margin-bottom: 40px; font-size: 1.2rem; }
}


/* ============================================================
   KEYBOARD FOCUS
   Collected in one place so coverage can be checked at a glance
   rather than hunted rule by rule — twelve controls were found
   with no focus style at all, including a text input whose
   browser default had been suppressed with `outline: none`.

   Oxblood on light surfaces. Over the hero photograph the outline
   is Warm Ivory instead: a dark ring sinks into the image, and a
   focus ring that cannot be seen is not a focus ring.
   ============================================================ */
.nav-logo:focus-visible,
.nav-links a:focus-visible,
.nav-drop-toggle:focus-visible,
.nav-lang a:focus-visible,
.nav-book:focus-visible,
.nav-burger:focus-visible,
.hero-cta:focus-visible {
  outline: 2px solid var(--cream);
  outline-offset: 4px;
}

/* Once the nav turns light — scrolled, or with the menu open —
   an ivory outline would vanish, so it flips to Oxblood. */
.header-solid .nav .nav-logo:focus-visible,
.nav.scrolled .nav-logo:focus-visible,
.header-solid .nav .nav-links a:focus-visible,
.nav.scrolled .nav-links a:focus-visible,
.header-solid .nav .nav-drop-toggle:focus-visible,
.nav.scrolled .nav-drop-toggle:focus-visible,
.header-solid .nav .nav-lang a:focus-visible,
.nav.scrolled .nav-lang a:focus-visible,
.header-solid .nav .nav-book:focus-visible,
.nav.scrolled .nav-book:focus-visible,
.header-solid .nav .nav-burger:focus-visible,
.nav.scrolled .nav-burger:focus-visible,
.nav.menu-open .nav-logo:focus-visible,
.nav.menu-open .nav-lang a:focus-visible,
.nav.menu-open .nav-book:focus-visible,
.nav.menu-open .nav-burger:focus-visible {
  outline-color: var(--oxblood);
}

/* The dropdown panel is cream in both header states, so its links always
   take the dark ring. Without this they inherited the ivory ring meant for
   the photograph — invisible on the panel (missed in stage 1, fixed
   2026-09-29). Three classes to outrank `.nav-links a:focus-visible`. */
.nav .nav-drop-menu a:focus-visible {
  outline-color: var(--oxblood);
  outline-offset: 2px;
}

.mobile-menu-links a:focus-visible,
.mobile-menu-lang a:focus-visible,
.mobile-menu-contact a:focus-visible,
.room-reserve-btn:focus-visible,
.location-btn:focus-visible,
.brand-pin:focus-visible,
.newsletter-submit:focus-visible,
.page-contacts a:focus-visible {
  outline: 1px solid var(--oxblood);
  outline-offset: 4px;
}

/* ============================================================
   MOTION — chosen by Jun from the staging demo, 2026-09-29
   Classes are set by assets/js/motion.js from the markup's
   data-reveal / data-mask. Only blocks that start below the first
   screen ever get .is-pending, so nothing on the first screen waits
   for these (the first screen's own entrance lives in home.css).
   ============================================================ */

/* Blocks appear on scroll — "мягко": a 16px rise over 0.9s, siblings
   80ms apart (the delay is set per block by the script). */
.motion-reveal {
  transition: opacity 0.9s var(--ease-soft), transform 0.9s var(--ease-soft);
  transition-delay: var(--reveal-delay, 0ms);
}

.motion-reveal.is-pending {
  opacity: 0;
  transform: translate3d(0, 16px, 0);
}

/* Photographs open from the bottom up. The clip exists only while it opens
   (.is-revealing is removed after 1.2s); the negative sides keep the room
   cards' 90px shadows visible meanwhile. */
.motion-mask.is-pending {
  clip-path: inset(100% -30% -30% -30%);
}

.motion-mask.is-revealing {
  clip-path: inset(-30% -30% -30% -30%);
  transition: clip-path 1.2s var(--ease-soft);
}

/* Photographs open from a sand-coloured pill: the frame grows from a small
   rounded shape in its middle, then the photograph grows inside it (Dining,
   2026-10-07 — after Gucci Osteria's image loading, in our colours; Jun ruled
   out a burgundy plate). The clip is removed once open (.is-revealing goes),
   so it can never cut anything later. */
[data-plate] {
  background: #E3D5BF;
}

.motion-plate.is-pending {
  clip-path: inset(41% 34% 41% 34% round 999px);
}

.motion-plate.is-pending img {
  clip-path: inset(50% 50% 50% 50%);
  scale: 1.3;
}

.motion-plate.is-revealing {
  clip-path: inset(0 0 0 0 round 0px);
  transition: clip-path 0.75s cubic-bezier(0.77, 0, 0.175, 1);
}

.motion-plate.is-revealing img {
  transition: clip-path 0.95s cubic-bezier(0.77, 0, 0.175, 1) 0.3s, scale 1.5s var(--ease-soft) 0.3s;
}

/* Text arrives line by line, from faint to full ink (after Aiyanna). The
   script wraps each word; words on one line share a delay. */
.motion-lines .ln {
  transition: opacity 1s var(--ease-soft), filter 1s var(--ease-soft);
  transition-delay: var(--line-delay, 0ms);
}

.motion-lines.is-pending .ln {
  opacity: 0.12;
  filter: blur(3px);
}

/* A hairline drawn from the left. */
.motion-rule {
  transform-origin: left;
  transition: transform 1.4s cubic-bezier(0.77, 0, 0.175, 1);
}

.motion-rule.is-pending {
  transform: scaleX(0);
}

/* Smooth scrolling — Lenis 1.3.26 (assets/js/vendor/lenis.min.js, MIT), on
   every page with motion.js (Jun, 2026-10-07). Started by motion.js, never
   under reduced motion. The rules are Lenis's own stylesheet (lenis.css of the
   same version) plus one: while Lenis runs, the browser's smooth scrolling of
   the html element steps aside — Lenis does the easing, and a second easing on
   top of it would fight it. Panels marked data-lenis-prevent (the mobile menu,
   the booking dialog) scroll natively; iframes (the map) ignore the pointer
   only while a smooth scroll is in progress. */
html.lenis,
html.lenis body {
  height: auto;
}

html.lenis {
  scroll-behavior: auto;
}

.lenis:not(.lenis-autoToggle).lenis-stopped {
  overflow: clip;
}

.lenis [data-lenis-prevent] {
  overscroll-behavior: contain;
}

.lenis.lenis-smooth iframe {
  pointer-events: none;
}

/* Between pages: the browser cross-fades the page and holds the header
   still. Browsers without View Transitions simply change page. */
@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
}

.nav {
  view-transition-name: site-header;
}

::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 0.35s;
}

/* ------------------------------------------------------------
   REDUCED MOTION — Jun's requirement: EVERY animation stops.
   One rule for the whole site rather than one per effect, so a new
   animation cannot be forgotten. Durations near zero (not `none`)
   so each animation lands on its final frame: the first-screen text
   ends visible, the photo ends still, the two endless pulses
   (.hero-scroll-line, .brand-pin-pulse) run once instantly and stop.
   Smooth scrolling to anchors is motion too, and goes. motion.js
   hides nothing when this preference is set.
   ------------------------------------------------------------ */
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-delay: 0s !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    transition-delay: 0s !important;
    scroll-behavior: auto !important;
  }
}
