/* ============================================================
   Components — header, menu, footer, hero pieces, cards.
   ============================================================ */

/* ----------------------------------------------------------------
   Hero background — fixed video + readability gradient
   ---------------------------------------------------------------- */

/* Hero background layer — fixed-position container for the video
   AND a fallback poster background-image. Sits at z-index 0
   (NOT negative — see tokens.css for why). Content above is
   z-index 1+ and either transparent (the .hero section) or
   opaque (everything below) so it scrolls over cleanly. */
.hero-bg {
  position: fixed;
  inset: 0;
  z-index: var(--z-bg);
  pointer-events: none;
  background-color: var(--color-bg);
  background-size: cover;
  background-position: center;
  background-repeat: no-repeat;
  /* Background poster wired in Phase 2 once Algamar hero clips land. */
  transform: translate3d(0, 0, 0);
}

/* Two stacked <video> elements, both fill .hero-bg. The intro
   sits on top with .is-active; the loop sits underneath at
   opacity 0. When the intro nears its end, JS starts the loop
   playing then instantly swaps z-index + opacity on `ended` —
   gapless, no fade, no black frame. */
.hero-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  z-index: 1;
  -webkit-transform: translate3d(0, 0, 0);
  transform: translate3d(0, 0, 0);
  /* Disable any pointer interaction on the video so user taps go to
     the page (e.g. menu toggle, scroll) rather than to the video's
     native play overlay. */
  pointer-events: none;
}

/* Suppress native browser play-button overlays that some browsers
   render when autoplay is blocked. iOS Safari, Android WebView and
   older Chromium ship a centered ▶ overlay on paused videos — these
   shadow-DOM pseudo-element overrides hide all of them so the user
   never sees a "tap to play" prompt even if our autoplay is blocked
   and the silent-gesture fallback hasn't fired yet. */
.hero-video::-webkit-media-controls,
.hero-video::-webkit-media-controls-panel,
.hero-video::-webkit-media-controls-overlay-play-button,
.hero-video::-webkit-media-controls-start-playback-button,
.hero-video::-webkit-media-controls-play-button,
.menu-video::-webkit-media-controls,
.menu-video::-webkit-media-controls-panel,
.menu-video::-webkit-media-controls-overlay-play-button,
.menu-video::-webkit-media-controls-start-playback-button,
.menu-video::-webkit-media-controls-play-button {
  display: none !important;
  -webkit-appearance: none !important;
  appearance: none !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

.hero-video.is-active {
  opacity: 1;
  z-index: 2;
}

/* Deliberately empty. This carried a gradient that reached 65% black at
   the bottom of the hero plus a radial pool at 50%/90% — between them,
   the dark wash across the lower hero that kept being reported as a
   fade. Hero legibility is now carried by text-shadow on the type
   itself, which puts nothing over the water. Kept as an element so the
   markup and the video-suppression rules do not have to change. */
.hero-overlay {
  position: absolute;
  inset: 0;
  background: none;
  pointer-events: none;
}

/* (Tap-to-play overlay removed — autoplay attributes + global
    play() retry on first user gesture make it unnecessary.) */

/* Glass-everywhere: the fixed hero-bg video plays on every page,
   not just the homepage. Internal pages still skip the hero-overlay
   gradient (it's only for darkening the hero section); the per-page
   sections supply their own glass tint. */
body:not(.page-home) .hero-overlay { display: none; }

/* ----------------------------------------------------------------
   Animated hero logo (homepage only).
   The wrapper is a full-viewport, non-interactive layer that centres
   its child by LAYOUT (grid), never by transform. That matters: the
   old translate(-50%,-50%) centring lived inside the same transform
   as the perspective recede, and the interaction between the percent
   translate and the z-projection pinned the mark's RIGHT EDGE to the
   screen centre — it receded at an angle. With grid centring, the
   img's own box sits at dead centre, its 50%/50% transform-origin IS
   the camera axis, and the throw goes straight down the middle.
   GSAP animates the IMG only; the wrapper is never transformed.
   ---------------------------------------------------------------- */

.hero-logo {
  position: fixed;
  inset: 0;
  z-index: var(--z-overlay);
  display: grid;
  place-items: center;
  pointer-events: none;
}

.hero-logo img {
  width: 26vw;
  max-width: 460px;
  min-width: 210px;
  height: auto;
  display: block;
  /* Hidden at rest (and for no-JS visitors); the sequence fades it in. */
  opacity: 0;
  will-change: transform, opacity, filter;
}

body:not(.page-home) .hero-logo { display: none; }

/* ----------------------------------------------------------------
   Site header (top bar)
   ---------------------------------------------------------------- */

.site-header {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--header-h);
  z-index: var(--z-header);
  background: transparent;
  transition:
    background-color var(--dur-short) var(--ease-out),
    backdrop-filter  var(--dur-short) var(--ease-out);
}

.site-header.is-visible {
  /* Whisper glass (brief §3.5) — almost invisible, earns its
     presence on scroll. Tint very light so ocean motion bleeds
     through clearly. */
  background: var(--glass-whisper-bg);
  backdrop-filter: var(--glass-whisper-filter);
  -webkit-backdrop-filter: var(--glass-whisper-filter);
  border-bottom: var(--glass-whisper-border);
}

/* Top-edge specular highlight on the header — the same 1px line
   gradient pearl→transparent. */
.site-header.is-visible::after {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: var(--glass-highlight);
  pointer-events: none;
}

@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-header.is-visible { background: color-mix(in srgb, var(--abyssal) 88%, transparent); }
}

.site-header__inner {
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  height: 100%;
  padding-inline: var(--gutter-x);
  max-width: var(--content-max);
  margin-inline: auto;
}

/* On homepage, top-bar elements start hidden — JS fades them in.
   ONLY elements hero.js animates INDIVIDUALLY may appear here: the
   language picker is revealed via its parent .site-header__end fade,
   and a child's own opacity:0 survives any parent fade — that is
   exactly how the burger menu once vanished. */
.page-home .site-header .cochin-now,
.page-home .site-header .menu-toggle {
  opacity: 0;
}

@media (max-width: 768px) {
  .site-header { height: var(--header-h-mobile); }
}

/* ----------------------------------------------------------------
   Header logo (static, in top bar)
   ---------------------------------------------------------------- */

.header-logo {
  display: block;
  justify-self: center;
  height: 38px;
  line-height: 0;
}

.header-logo img {
  height: 100%;
  width: auto;
  display: block;
}

@media (max-width: 768px) {
  .header-logo { height: 32px; }
}

/* ----------------------------------------------------------------
   Language toggle (left of header)
   ---------------------------------------------------------------- */

.lang-toggle {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0;
  border: none;
  background: transparent;
  justify-self: start;
}

.lang-toggle__btn {
  font-family: var(--font-sans);
  font-size: 11px;
  font-weight: 400;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.5);
  padding: 4px 0;
  border: none;
  background: transparent;
  border-radius: 0;
  cursor: pointer;
  min-height: 32px;
  position: relative;
  transition: color var(--dur-micro) var(--ease-micro);
}

@media (hover: none) and (pointer: coarse) {
  .lang-toggle__btn { min-height: 36px; min-width: 36px; padding: 9px 14px; }
}

.lang-toggle__btn:hover {
  color: var(--color-text);
}

.lang-toggle__btn[aria-pressed="true"] {
  color: var(--color-text);
  background: transparent;
}
.lang-toggle__btn[aria-pressed="true"]::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;
  height: 1px;
  background: var(--color-text);
}

@media (max-width: 480px) {
  .lang-toggle { gap: var(--space-1); }
  .lang-toggle__btn { font-size: 10px; letter-spacing: 0.18em; }
}

/* ----------------------------------------------------------------
   Menu toggle (hamburger, right of header)
   ---------------------------------------------------------------- */

.menu-toggle {
  justify-self: end;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
  transition: background-color var(--dur-micro) var(--ease-micro);
}

/* When the menu overlay is open, lift the entire header above it
   so the hamburger (now an X) stays visible and clickable. The class
   `body.menu-is-open` is set by js/nav.js openMenu/closeMenu so the
   header z-index switches in lockstep with the overlay. */
body.menu-is-open .site-header {
  z-index: calc(var(--z-modal) + 1);
}
body.menu-is-open .site-header.is-visible {
  background: transparent;
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
  border-bottom: none;
}

.menu-toggle:hover {
  background: rgba(255, 255, 255, 0.06);
}

/* Two screen-reader labels stacked inside the toggle. CSS swaps which
   is visible to AT based on aria-expanded so screen readers always
   read the correct action ("Open menu" / "Close menu") even though
   the visible icon also morphs from ≡ to X. */
.menu-toggle__label--close { display: none; }
.menu-toggle[aria-expanded="true"] .menu-toggle__label--open { display: none; }
.menu-toggle[aria-expanded="true"] .menu-toggle__label--close { display: inline; }

.menu-toggle__icon {
  position: relative;
  display: block;
  width: 22px;
  height: 14px;
}

/* Both bars are centered vertically; spacing comes from transform only.
   Animating a single property (transform) prevents the jitter that
   shows up when top/bottom and transform animate concurrently. */
.menu-toggle__icon span {
  position: absolute;
  top: 50%;
  left: 0;
  width: 100%;
  height: 1.5px;
  background: var(--color-text);
  transform-origin: center;
  transition: transform 320ms cubic-bezier(0.65, 0, 0.35, 1);
}

/* Closed: spread apart by ±5px from center */
.menu-toggle__icon span:first-child { transform: translateY(calc(-50% - 5px)); }
.menu-toggle__icon span:last-child  { transform: translateY(calc(-50% + 5px)); }

/* Open: collapse to center and rotate into an X */
.menu-toggle[aria-expanded="true"] .menu-toggle__icon span:first-child {
  transform: translateY(-50%) rotate(45deg);
}
.menu-toggle[aria-expanded="true"] .menu-toggle__icon span:last-child {
  transform: translateY(-50%) rotate(-45deg);
}

/* ----------------------------------------------------------------
   Full-screen menu overlay — opaque, centred, premium.
   Solid #0A0A0A covers everything (video included). The header
   stays above with class swap on body, so the X close icon is
   always visible.
   ---------------------------------------------------------------- */

.menu-overlay {
  position: fixed;
  inset: 0;
  z-index: var(--z-modal);
  /* Transparent — the .menu-glass child supplies the tint+blur,
     and the page-level fixed ocean video shows through behind it. */
  background: transparent;
  display: flex;
  align-items: center;
  justify-content: center;
  opacity: 0;
  pointer-events: none;
  /* SCROLLABLE, not clipped. This was `overflow: hidden` on a
     vertically-centred flex container: the moment the list grew taller
     than the viewport (landscape phone, large text settings, or just a
     short window) the first link and the email were cut off with no way
     to reach them. `auto` plus safe centring keeps the block centred
     when it fits and lets it scroll when it does not. */
  overflow-y: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  /* Materialises FROM the control that summoned it (top-right), not
     from the middle of the screen — Apple's spatial-consistency rule:
     a surface emerges from, and returns to, its origin. */
  transform-origin: calc(100% - var(--gutter-x)) 0;
  transform: scale(0.97);
  transition:
    opacity   300ms var(--ease-out),
    transform 420ms var(--ease-out-expo);
}
.menu-overlay.is-open { transform: scale(1); }

@supports (align-items: safe center) {
  .menu-overlay { align-items: safe center; }
}

@media (prefers-reduced-motion: reduce) {
  .menu-overlay,
  .menu-overlay.is-open { transform: none; transition: opacity 160ms linear; }
}

/* Video layer — sits at the bottom of the stack inside the menu.
   Two stacked videos cycle intro→loop forever. */
.menu-bg-video {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
}

.menu-video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  z-index: 1;
}

.menu-video.is-active {
  opacity: 1;
  z-index: 2;
}

/* Modal glass (brief §3.5) — the menu is a full-screen overlay,
   the heaviest surface tier. */
.menu-glass {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--glass-modal-bg);
  backdrop-filter: var(--glass-modal-filter);
  -webkit-backdrop-filter: var(--glass-modal-filter);
  pointer-events: none;
}
.menu-glass::after {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: var(--glass-highlight);
  pointer-events: none;
}

/* Content (links + footer) sits above the glass */
.menu-overlay__inner {
  position: relative;
  z-index: 3;
}

/* No-backdrop-filter fallback: solid dark fill instead of glass. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .menu-glass { background: color-mix(in srgb, var(--deep) 94%, transparent); }
}

/* Low-perf tier: skip the expensive blur entirely. */
html[data-perf="low"] .menu-glass {
  background: rgba(14, 22, 32, 0.94);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

.menu-overlay[hidden] { display: none; }

.menu-overlay.is-open {
  opacity: 1;
  pointer-events: auto;
}

.menu-overlay__inner {
  max-width: 600px;
  width: 100%;
  padding-inline: var(--gutter-x);
  /* Vertical breathing room so the block clears the fixed header when
     it scrolls, instead of the first link sliding under the chrome. */
  padding-block: calc(var(--header-h) + var(--space-4)) var(--space-8);
  /* A grid, not a flex column: the main list + footer occupy rows 1-2
     and the products submenu SPANS the same two rows, so the two views
     overlap in one area. Both stay in the flow (visibility, never
     display) and the area is always as tall as the taller view — the
     centred block cannot move when one swaps for the other. The flex
     version stacked both for the 320ms the old panel took to hide, and
     the whole menu lurched up and back down on every Back. */
  display: grid;
  grid-template-rows: auto auto;
  align-content: center;
  justify-items: center;
  row-gap: var(--space-6);
  text-align: center;
}
.menu-list            { grid-area: 1 / 1; }
.menu-overlay__footer { grid-area: 2 / 1; }
.menu-sub             { grid-area: 1 / 1 / span 2; align-self: center; }

.menu-list,
.menu-overlay__footer {
  transition: opacity 260ms var(--ease-out), visibility 0s linear 0s;
}

.menu-list {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  list-style: none;
  margin: 0;
  padding: 0;
  width: 100%;
}

.menu-list li { width: 100%; }

.menu-list a {
  font-family: var(--font-display);
  font-size: clamp(2.5rem, 6vw, 4rem);
  font-weight: 500;
  line-height: 1.05;
  letter-spacing: var(--tr-display);
  color: var(--color-text);
  display: inline-block;
  position: relative;
  padding: 0;
  border: none;
  background: none;
  text-decoration: none;
  /* Focus ring is defined on :focus-visible below, so it appears for
     keyboard users without boxing the link on mouse click. */
  opacity: 0;
  transform: translateY(20px);
  transition: color 200ms var(--ease-micro);
}

/* Focus needs a real indicator here, not a colour swap.
   The overlay is the site's ONLY navigation at every width, and the
   colour-only approach failed twice: brand red measures about 1.5:1
   against the overlay — under the 3:1 WCAG requires of a focus
   indicator — and on the current page's link, which is already brand
   red, focus changed nothing at all.
   Keeping the colour shift for continuity with hover, and adding a ring
   that carries the contrast on its own. */
.menu-list a:focus-visible {
  color: var(--color-brand);
  outline: 2px solid var(--pearl);
  outline-offset: 8px;
  border-radius: 2px;
}

/* Open animation — stagger each link in */
.menu-overlay.is-open .menu-list a {
  opacity: 1;
  transform: translateY(0);
  transition:
    opacity 600ms var(--ease-out),
    transform 600ms var(--ease-out),
    color 200ms var(--ease-micro);
}
.menu-overlay.is-open .menu-list li:nth-child(1) a { transition-delay: 0ms,   0ms,   0ms; }
.menu-overlay.is-open .menu-list li:nth-child(2) a { transition-delay: 80ms,  80ms,  0ms; }
.menu-overlay.is-open .menu-list li:nth-child(3) a { transition-delay: 160ms, 160ms, 0ms; }
.menu-overlay.is-open .menu-list li:nth-child(4) a { transition-delay: 240ms, 240ms, 0ms; }
.menu-overlay.is-open .menu-list li:nth-child(5) a { transition-delay: 320ms, 320ms, 0ms; }

/* Couture restraint — hover on links is an italic shift, not a
   colour swap. White stays white. The Met Gala uses italics, not
   colour, to signal interaction. */
.menu-list a {
  font-style: normal;
  font-weight: 400;
  transition: opacity var(--dur-micro) var(--ease-micro), letter-spacing var(--dur-short) var(--ease-out);
}
@media (hover: hover) and (pointer: fine) {
  .menu-list a:hover {
    opacity: 0.7;
  }
}

/* Active page — same white, with a hairline underline.

   The rule is positioned OUT of flow rather than left as a block-level
   ::after. .menu-list a is display:inline-flex, so a generated child
   becomes a flex ITEM: the underline was laid out as the second cell of
   a row, vertically centred beside the word, which drew it straight
   through "Home" as a strikethrough — and stretched the link box ~60px
   wider than its text, pulling the label off centre. Absolute
   positioning keeps it under the word and makes it immune to whatever
   display the link is given later. */
.menu-list a[aria-current="page"] {
  color: var(--color-text);
  position: relative;
}
.menu-list a[aria-current="page"]::after {
  content: "";
  position: absolute;
  left: 50%;
  transform: translateX(-50%);
  bottom: 0.06em;          /* clear of the descenders, not floating away */
  width: 64px;
  height: 1px;
  background: rgba(255, 255, 255, 0.5);
}

/* Footer — thin red rule + email block */
.menu-overlay__footer {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-4);
  opacity: 0;
  transition: opacity 400ms var(--ease-out);
}
.menu-overlay.is-open .menu-overlay__footer {
  opacity: 1;
  transition-delay: 600ms;
}

.menu-overlay__rule {
  display: block;
  width: 48px;
  height: 1px;
  background: var(--color-divider);
  border: none;
  margin: 0;
}

.menu-overlay__footer a {
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  text-decoration: none;
  transition: color var(--dur-micro) var(--ease-micro);
}

@media (hover: hover) and (pointer: fine) {
  .menu-overlay__footer a:hover { color: var(--color-text); }
}

/* Mobile — left-aligned, smaller link size. The whole menu inner
   pulls to the page's left gutter so it reads like the rest of
   the site's editorial column. Footer (rule + email) follows. */
@media (max-width: 768px) {
  .menu-overlay {
    justify-content: flex-start;
  }
  .menu-overlay__inner {
    align-items: flex-start;
    text-align: left;
    max-width: none;
    width: 100%;
  }
  .menu-list {
    align-items: flex-start;
  }
  .menu-list a {
    font-size: clamp(2rem, 8vw, 2.75rem);
    text-align: left;
  }
  /* Active-page underline aligns to the left edge of the text. The rule
     is absolutely positioned now, so left-alignment is left/transform
     rather than a margin reset. */
  .menu-list a[aria-current="page"]::after {
    left: 0;
    transform: none;
  }
  .menu-overlay__footer {
    align-items: flex-start;
    margin-top: var(--space-6);
  }
  .menu-overlay__rule {
    margin: 0;
  }
}

/* ----------------------------------------------------------------
   CTA buttons (mailto cards) — used on home + contact
   ---------------------------------------------------------------- */

.cta-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-2);
  /* align-items: start so a hovered button can grow downward
     without stretching its sibling to match its new height. */
  align-items: start;
}

/* Grid layout: row 1 holds the label + arrow (always visible),
   row 2 holds the email reveal (collapsed to 0 by default). The
   box height is determined by row 1 only — when row 2 expands on
   hover, the box grows downward. */
.cta-btn {
  position: relative;
  display: grid;
  grid-template-columns: 1fr auto;
  grid-template-rows: auto;
  column-gap: var(--space-3);
  row-gap: 0;
  align-items: center;
  padding: 14px var(--space-3);
  background: var(--color-bg-elevated);
  border: 1px solid var(--color-divider);
  color: var(--color-text);
  text-decoration: none;
  overflow: hidden;
  transition:
    border-color var(--dur-micro) var(--ease-micro),
    background-color var(--dur-short) var(--ease-out);
}

.cta-btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--color-brand);
  transform: scaleY(0);
  transform-origin: bottom;
  transition: transform var(--dur-short) var(--ease-out);
  z-index: 0;
}

.cta-btn > * { position: relative; z-index: 1; }

.cta-btn__label {
  grid-column: 1;
  grid-row: 1;
  font-family: var(--font-sans);
  font-size: var(--fs-md);
  font-weight: 500;
  letter-spacing: -0.005em;
  color: var(--color-text);
  /* Block element with line-height 1.2 — pairs symmetrically
     with the arrow's centred line height for true vertical center. */
  line-height: 1.2;
  min-width: 0;
}

.cta-btn__arrow {
  grid-column: 2;
  grid-row: 1;
  font-size: var(--fs-xl);
  line-height: 1;
  color: var(--color-brand);
  /* Match the label's optical centre exactly */
  display: flex;
  align-items: center;
  justify-content: center;
  height: 100%;
  transition:
    transform var(--dur-short) var(--ease-out),
    color var(--dur-micro) var(--ease-micro);
}

/* Email reveal — second grid row. Collapsed to zero height by
   default; the box reads as a clean rectangle with just label+arrow.
   On hover/focus the row expands and the email fades in. */
.cta-btn__reveal {
  grid-column: 1 / -1;
  grid-row: 2;
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 400;
  color: var(--color-text-muted);
  letter-spacing: 0.01em;
  word-break: break-word;
  overflow-wrap: anywhere;
  min-width: 0;
  opacity: 0;
  max-height: 0;
  margin-top: 0;
  overflow: hidden;
  transition:
    opacity var(--dur-micro) var(--ease-micro),
    max-height var(--dur-short) var(--ease-out),
    margin-top var(--dur-short) var(--ease-out);
}

.cta-btn:hover .cta-btn__reveal,
.cta-btn:focus-visible .cta-btn__reveal,
.cta-btn:focus-within .cta-btn__reveal {
  opacity: 1;
  max-height: 2em;
  margin-top: 8px;
  transition:
    opacity 200ms var(--ease-micro),
    max-height var(--dur-short) var(--ease-out),
    margin-top var(--dur-short) var(--ease-out);
}

@media (hover: hover) {
  .cta-btn:hover {
    border-color: var(--color-brand);
  }
  .cta-btn:hover::before { transform: scaleY(1); }
  .cta-btn:hover .cta-btn__arrow {
    color: var(--color-text);
    transform: translateX(6px);
  }
}

@media (max-width: 640px) {
  .cta-row { grid-template-columns: 1fr; }
}

/* ----------------------------------------------------------------
   Toast — bottom-center notification when mailto fallback fires
   (clipboard copy etc). Subtle, 2s lifetime, fade in/out.
   ---------------------------------------------------------------- */
.cta-toast {
  position: fixed;
  left: 50%;
  bottom: 32px;
  transform: translate(-50%, 12px);
  background: rgba(20, 20, 20, 0.96);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--fs-sm);
  font-weight: 500;
  letter-spacing: 0;
  padding: 12px 20px;
  border: 1px solid rgba(255, 255, 255, 0.12);
  z-index: var(--z-modal);
  opacity: 0;
  pointer-events: none;
  transition:
    opacity 200ms var(--ease-micro),
    transform 200ms var(--ease-out);
}

.cta-toast.is-visible {
  opacity: 1;
  transform: translate(-50%, 0);
}

/* ----------------------------------------------------------------
   Custom cursor (hidden on touch devices)
   ---------------------------------------------------------------- */

.cursor-dot,
.cursor-ring {
  position: fixed;
  top: 0;
  left: 0;
  pointer-events: none;
  z-index: var(--z-modal);
  mix-blend-mode: difference;
}

.cursor-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--color-brand);
  transform: translate(-50%, -50%) translate3d(0, 0, 0);
  transition: opacity var(--dur-micro) var(--ease-micro);
  opacity: 0;
}

.cursor-ring {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  border: 1px solid rgba(255, 255, 255, 0.55);
  transform: translate(-50%, -50%) translate3d(0, 0, 0);
  transition:
    width var(--dur-short) var(--ease-out),
    height var(--dur-short) var(--ease-out),
    border-color var(--dur-micro) var(--ease-micro),
    opacity var(--dur-micro) var(--ease-micro),
    background-color var(--dur-short) var(--ease-out);
  opacity: 0;
}

.cursor-ready .cursor-dot,
.cursor-ready .cursor-ring { opacity: 1; }

/* Hover state — ring grows, dot fades */
.cursor-hover .cursor-dot { opacity: 0; }
.cursor-hover .cursor-ring {
  width: 64px;
  height: 64px;
  border-color: var(--color-brand);
  background: rgba(58, 77, 110, 0.08);
}

/* Hide native cursor on devices with fine pointer */
@media (hover: hover) and (pointer: fine) {
  html.cursor-ready,
  html.cursor-ready *,
  html.cursor-ready a,
  html.cursor-ready button {
    cursor: none !important;
  }
}

/* Touch devices — hide entirely */
@media (hover: none), (pointer: coarse) {
  .cursor-dot, .cursor-ring { display: none; }
}

/* Reduced motion — hide custom cursor, restore native */
@media (prefers-reduced-motion: reduce) {
  .cursor-dot, .cursor-ring { display: none; }
  html.cursor-ready, html.cursor-ready * { cursor: auto !important; }
}

/* ----------------------------------------------------------------
   Site footer
   ---------------------------------------------------------------- */

.site-footer {
  position: relative;
  z-index: var(--z-content);
  /* Paints NO ground of its own. The page pane (body::after) runs
     underneath it to the bottom of the document, so the footer is the
     same sheet of glass as the sections above it — not a panel sitting
     on top of one. There is no border-top for the same reason: a
     divider is only meaningful between two surfaces, and there is now
     only one. */
  background: transparent;
  padding-block: var(--space-12) var(--space-6);
  overflow: hidden;
  isolation: isolate;
}

/* Video layer — same intro+loop cycle pattern as the menu/hero.
   Lazy-loaded by js/footer.js when the footer enters viewport. */
.site-footer__bg-video {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
}

.site-footer__video {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  opacity: 0;
  z-index: 1;
  pointer-events: none;
}

.site-footer__video.is-active {
  opacity: 1;
  z-index: 2;
}

/* Suppress browser play overlays on these too. */
.site-footer__video::-webkit-media-controls,
.site-footer__video::-webkit-media-controls-panel,
.site-footer__video::-webkit-media-controls-overlay-play-button,
.site-footer__video::-webkit-media-controls-start-playback-button,
.site-footer__video::-webkit-media-controls-play-button {
  display: none !important;
  -webkit-appearance: none !important;
  appearance: none !important;
  opacity: 0 !important;
  pointer-events: none !important;
}

/* Card glass (brief §3.5) — the footer is a content surface but
   less dense than the menu modal. */
.site-footer__glass {
  position: absolute;
  inset: 0;
  z-index: 2;
  background: var(--glass-card-bg);
  backdrop-filter: var(--glass-card-filter);
  -webkit-backdrop-filter: var(--glass-card-filter);
  pointer-events: none;
}
.site-footer__glass::after {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: var(--glass-highlight);
  pointer-events: none;
}

/* No-backdrop-filter fallback: solid dark fill instead of glass. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-footer__glass { background: color-mix(in srgb, var(--surface) 92%, transparent); }
}

html[data-perf="low"] .site-footer__glass {
  background: color-mix(in srgb, var(--surface) 86%, transparent);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

/* Content sits above the glass + video. */
.site-footer__content {
  position: relative;
  z-index: 3;
  max-width: var(--content-max);
  margin-inline: auto;
  padding-inline: var(--gutter-x);
}

/* Legacy selector kept for any older markup that still scopes via
   .site-footer .container (none after this update, but harmless). */
.site-footer .container {
  max-width: var(--content-max);
}

/* Three columns on desktop: brand | address | email
   Address and email are siblings of equal width, so their
   labels share a baseline and their content aligns vertically. */
.site-footer__grid {
  display: grid;
  grid-template-columns: 1.4fr 1fr 1fr;
  column-gap: var(--space-8);
  row-gap: var(--space-8);
  padding-bottom: var(--space-10);
  align-items: start;
}

.site-footer__brand {
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
}

/* Logo above the tagline — anchored to the same left edge as
   the tagline text. Wrapped in a link to the home page so the
   footer mark behaves the same as the header logo. */
.site-footer__mark-link {
  display: inline-block;
  line-height: 0;
  margin: 0 0 var(--space-1) 0;
  padding: 0;
  border: none;
  transition: opacity var(--dur-micro) var(--ease-micro);
}

.site-footer__mark-link:hover { opacity: 0.85; }

.site-footer__mark {
  display: block;
  width: clamp(120px, 12vw, 150px);
  height: auto;
  margin: 0;
  padding: 0;
}

@media (max-width: 640px) {
  .site-footer__mark { width: 80px; }
}

.site-footer__tagline {
  font-size: var(--fs-xl);
  line-height: 1.15;
  max-width: 18ch;
  margin: 0;
}

.site-footer__col {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  min-width: 0;
}

.site-footer__col .label {
  font-size: var(--fs-xs);
  margin: 0 0 var(--space-1) 0;
  line-height: 1.2;
}

.site-footer__col > p,
.site-footer__col > a {
  font-size: var(--fs-sm);
  line-height: 1.55;
  max-width: none;
  margin: 0;
}

.site-footer__col a {
  display: inline-block;
  align-self: flex-start;
  border-bottom: 1px solid transparent;
  padding-bottom: 1px;
  width: fit-content;
  transition:
    color var(--dur-micro) var(--ease-micro),
    border-color var(--dur-micro) var(--ease-micro);
}
.site-footer__col a:hover {
  color: var(--color-brand-hover);
  border-color: var(--color-brand-hover);
}

.site-footer .divider { margin-block: var(--space-4); }

.site-footer__legal {
  font-size: var(--fs-xs);
  letter-spacing: 0.05em;
  text-align: left;
  margin: 0;
}

/* Tablet: brand on top, address+email side-by-side below */
@media (max-width: 1024px) {
  .site-footer__grid {
    grid-template-columns: 1fr 1fr;
    grid-template-areas:
      "brand brand"
      "addr  email";
    column-gap: var(--space-6);
    row-gap: var(--space-6);
  }
  .site-footer__brand   { grid-area: brand; }
  .site-footer__col--address { grid-area: addr; }
  .site-footer__col--contact { grid-area: email; }
}

/* Mobile: everything stacks */
@media (max-width: 640px) {
  .site-footer__grid {
    grid-template-columns: 1fr;
    grid-template-areas:
      "brand"
      "addr"
      "email";
    row-gap: var(--space-5);
  }
}




/* ============================================================
   Hong Kong live clock — Aston-Martin-dashboard restraint.

   Mono tabular digits (so they don't reflow as numbers tick),
   small uppercase label, brand-red blinking colon between minutes
   and seconds as the live indicator. Two surfaces:

   - .hk-clock              — contact page, under the Office heading
   - .hk-clock--footer      — bottom row of every footer

   Format updated by js/clock.js via Intl.DateTimeFormat with
   timeZone: 'Asia/Hong_Kong'.
   ============================================================ */
.hk-clock {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-3);
  font-family: var(--font-sans);
  font-feature-settings: "tnum";
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
  line-height: 1;
}

.hk-clock__label,
.hk-clock__zone {
  font-size: var(--fs-xs);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  line-height: 1;
}

.hk-clock__time {
  font-size: var(--fs-md);
  letter-spacing: 0.05em;
  line-height: 1;
  color: var(--color-text);
}

.hk-clock__sep {
  color: var(--color-text-muted);
  margin-inline: 0.05em;
}

/* The center colon (between minutes and seconds) blinks once per
   second as the "live" indicator — same idea as a tower-clock pulse. */
/* Blinking separator colon — driven by JS class toggle (on the
   [data-hk-clock] root) so its on/off flip is perfectly in sync
   with the seconds-digit tick. CSS keyframe removed because animation
   start time depends on parse order, drifting out of sync with the
   setInterval-driven digit update. */
.hk-clock__sep--blink {
  color: var(--color-brand);
  opacity: 0.3;
  transition: opacity 80ms ease-out;
}
[data-hk-clock].is-tick-on .hk-clock__sep--blink {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .hk-clock__sep--blink {
    opacity: 1 !important;
    transition: none;
  }
}

/* Footer variant — slightly smaller time, sits opposite the legal
   line in the bottom row. All digits stay white; only the blinking
   colon and the HKT zone label carry the brand red. */
.hk-clock--footer .hk-clock__time {
  font-size: var(--fs-sm);
  letter-spacing: 0.06em;
}

/* HKT zone label in brand red — quiet but unmistakable timezone
   signal pinned to the right of the digits. */
.hk-clock--footer .hk-clock__zone {
  color: var(--color-brand);
}

/* Footer bottom row: legal copyright on the left, clock on the right.
   Stacks on mobile with gap. */
.site-footer__bottom {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-3);
}

@media (max-width: 640px) {
  .site-footer__bottom {
    flex-direction: column;
    align-items: flex-start;
  }
}

/* ============================================================
   Hong Kong clock — special variant for the Contact page.

   Editorial-dateline treatment, more presence than the footer
   variant. Three lines stacked tight:

     [pulse] HONG KONG  ·  GMT+8         ← mono uppercase eyebrow
     16:42                      · 18      ← display serif HH:MM, mono small ·SS
     Sunday, 10 May 2026                  ← italic display serif date

   The pulse dot breathes once per 2s as the live indicator. The
   colon between HH and MM blinks once per second.
   ============================================================ */
.hk-clock--special {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-2);
  margin-top: var(--space-5);
  /* Override the base inline-flex layout. */
  align-items: flex-start;
}

.hk-clock--special > * { margin: 0; }

.hk-clock--special .hk-clock__eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-sans);
  font-size: var(--fs-xs);
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--color-text-muted);
  line-height: 1;
}

/* Live indicator — radar-style pulse. Solid red center dot with
   strong inner+outer glow, plus two hollow ring outlines that
   emanate outward continuously (offset 0.75s for a tight rhythm).
   Visually distinct from the on/off binary blink of the seconds
   colon — this reads as analog "transmitting", that reads as
   digital tick. */
/* Live indicator — warm-grey center with a glowing red halo. The
   center stays quiet so it doesn't compete with the seconds colon
   (which is solid brand red); the red glow IS the live signal,
   waxing and waning each cycle. Two faint hollow rings emanate
   outward on offset for a "transmitting" feel. */
.hk-clock--special .hk-clock__pulse {
  position: relative;
  display: inline-block;
  width: 9px;
  height: 9px;
  border-radius: 50%;
  /* Warm-grey center — same hue family as the eyebrow text. Quiet. */
  background: rgba(255, 255, 255, 0.55);
  /* Two-stop red glow: tight bloom + diffuse halo. The glow is the
     visual story; the dot is just its source point. */
  box-shadow:
    0 0 6px  rgba(58, 77, 110, 0.85),
    0 0 14px rgba(58, 77, 110, 0.45);
  animation: hk-clock-pulse-core 1.8s ease-in-out infinite;
}

/* Hollow ring outlines (red border + transparent fill) — read more
   like radar than filled circles, line stays crisp as it expands. */
.hk-clock--special .hk-clock__pulse::before,
.hk-clock--special .hk-clock__pulse::after {
  content: "";
  position: absolute;
  inset: -1px;
  border-radius: 50%;
  border: 1.5px solid var(--color-brand);
  background: transparent;
  box-sizing: border-box;
  animation: hk-clock-pulse-ring 1.8s cubic-bezier(0, 0, 0.3, 1) infinite;
  pointer-events: none;
}

.hk-clock--special .hk-clock__pulse::after {
  animation-delay: 0.9s;
}

@keyframes hk-clock-pulse-core {
  0%, 100% {
    transform: scale(1);
    background: rgba(255, 255, 255, 0.55);
    box-shadow:
      0 0 6px  rgba(58, 77, 110, 0.85),
      0 0 14px rgba(58, 77, 110, 0.45);
  }
  50% {
    transform: scale(1.13);
    /* Center brightens slightly at peak — picks up reflected red
       from the surrounding glow. */
    background: rgba(255, 230, 232, 0.85);
    box-shadow:
      0 0 10px rgba(58, 77, 110, 1),
      0 0 22px rgba(58, 77, 110, 0.7);
  }
}

@keyframes hk-clock-pulse-ring {
  0%   { transform: scale(1);   opacity: 0.6; border-width: 1.5px; }
  75%  {                        opacity: 0;   border-width: 1px;   }
  100% { transform: scale(3);   opacity: 0;   border-width: 1px;   }
}

.hk-clock--special .hk-clock__display {
  display: flex;
  align-items: baseline;
  gap: 0.45em;
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(2.75rem, 5vw, 4.25rem);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--color-text);
}

.hk-clock--special .hk-clock__hm {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum";
}

/* Smaller mono seconds floated next to the big HH:MM. The `·`
   separator visually divides them without a hard punctuation feel.
   The seconds digits themselves are brand red — paired with the
   blinking colon above as the live-tick indicators. */
.hk-clock--special .hk-clock__seconds {
  display: inline-flex;
  align-items: center;
  gap: 0.4em;
  font-family: var(--font-sans);
  font-size: 0.32em;
  letter-spacing: 0.08em;
  color: var(--color-text-muted);
  font-variant-numeric: tabular-nums;
  line-height: 1;
}

.hk-clock--special .hk-clock__seconds [data-s] {
  color: var(--color-brand);
}

.hk-clock--special .hk-clock__sep-dot {
  color: var(--color-text-muted);
  opacity: 0.6;
}

.hk-clock--special .hk-clock__colon {
  margin-inline: 0.05em;
  color: var(--color-text-muted);
}

/* Blinking colon between HH and MM — brand red, driven by JS class
   toggle on the [data-hk-clock] root so it's perfectly in sync with
   the seconds-digit update each second. CSS keyframe removed
   because animation start time drifts independent of the digit tick. */
.hk-clock--special .hk-clock__colon--blink {
  color: var(--color-brand);
  opacity: 0.3;
  transition: opacity 80ms ease-out;
}
[data-hk-clock].is-tick-on .hk-clock--special .hk-clock__colon--blink,
.hk-clock--special[data-hk-clock].is-tick-on .hk-clock__colon--blink {
  opacity: 1;
}

.hk-clock--special .hk-clock__date {
  font-family: var(--font-display);
  font-style: normal;
  font-weight: 400;
  font-size: var(--fs-md);
  line-height: 1.3;
  color: var(--color-text-muted);
  letter-spacing: 0.005em;
}

/* Day name itself is brand red — pulls the eye to the day-of-week
   as the most temporal piece of information on the dateline. The
   surrounding ", 10 May 2026" stays in muted italic. */
.hk-clock--special .hk-clock__date [data-day] {
  color: var(--color-brand);
}

/* CN typography swap on the italic serif date — the CN font has no
   italic, so we drop the italic style and let the family handle it. */
body.lang-cn .hk-clock--special .hk-clock__date {
  font-family: var(--font-cn);
  font-style: normal;
}

@media (prefers-reduced-motion: reduce) {
  .hk-clock--special .hk-clock__pulse,
  .hk-clock--special .hk-clock__pulse::before,
  .hk-clock--special .hk-clock__pulse::after,
  .hk-clock--special .hk-clock__colon--blink {
    animation: none;
    opacity: 1;
  }
  /* Hide the radar rings entirely under reduced motion — they
     have no purpose without their expansion animation. */
  .hk-clock--special .hk-clock__pulse::before,
  .hk-clock--special .hk-clock__pulse::after {
    display: none;
  }
}

/* ==================================================================
   RESPONSE LAYER — feedback on pointer-DOWN, not on click.
   Apple's first principle of fluid interfaces: the instant lag appears
   the feeling of directness "falls off a cliff". The site previously
   had 33 :hover rules and zero :active rules, so on touch — where
   hover does not exist — nothing on the page ever acknowledged being
   pressed. Every interactive surface now depresses immediately.

   Scale is inversely proportional to element size: a large card moves
   less than a small chip for the same perceived "give", which is how
   real physical materials behave.

   `transition` is deliberately asymmetric — press is near-instant
   (60ms) so it feels like contact; release eases back over 260ms so
   it feels elastic rather than mechanical.
   ================================================================== */

:where(a, button, summary, [role="button"], .btn, .nav-link,
       .contact-card, .folio-card, .cert, .chapter-nav__link,
       .menu-list a, .enquiry__submit) {
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

/* Small controls — crisper, deeper press. */
.btn:active,
.enquiry__submit:active,
.menu-toggle:active,
.chapter-nav__link:active,
.nav-link:active,
.menu-list a:active {
  transform: scale(0.96);
  transition: transform 60ms linear;
}

/* Large surfaces — a card the size of a postcard should barely move. */
.contact-card:active,
.folio-card:active,
.cert:active {
  transform: scale(0.988);
  transition: transform 60ms linear;
}

/* Release: ease back out. Kept separate from :active so the return
   curve differs from the press curve (mirrored easing, Apple §7). */
.btn,
.enquiry__submit,
.menu-toggle,
.chapter-nav__link,
.nav-link,
.menu-list a,
.contact-card,
.folio-card,
.cert {
  transition: transform 260ms var(--ease-out-expo);
}

/* Hover is a POINTER affordance. Ungated, it sticks on touch: the
   :hover state latches after a tap and only clears on the next tap
   elsewhere, which reads as a stuck highlight. */
@media (hover: none) {
  .contact-card:hover,
  .folio-card:hover,
  .cert:hover {
    transform: none;
    box-shadow: none;
  }
}

/* Reduced motion: keep the acknowledgement, drop the movement — a
   press must still be felt, so swap scale for a brightness shift. */
@media (prefers-reduced-motion: reduce) {
  .btn:active,
  .enquiry__submit:active,
  .menu-toggle:active,
  .chapter-nav__link:active,
  .nav-link:active,
  .menu-list a:active,
  .contact-card:active,
  .folio-card:active,
  .cert:active {
    transform: none;
    filter: brightness(1.35);
    transition: filter 60ms linear;
  }
}

/* ==================================================================
   CONTACT DOCK — WhatsApp, Zalo, mail.

   Circles only. At 52px a labelled pill reads as a banner ad, and a
   word beside one of three buttons unbalances the group; the glyphs
   are unambiguous on their own and the accessible name carries the
   rest. Buyers across Asia, Africa and the Gulf transact on WhatsApp
   and Zalo, so a mail address alone was losing exactly those enquiries.

   Styled as site glass rather than each service's brand colour: three
   saturated logos stacked in the corner would be the loudest thing on
   a page built entirely from restraint.
   ================================================================== */
.dock {
  position: fixed;
  right: clamp(1rem, 2.5vw, 2rem);
  bottom: clamp(1rem, 2.5vw, 2rem);
  z-index: calc(var(--z-modal) - 1);
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.dock.is-retired {
  opacity: 0;
  transform: translateY(8px) scale(0.96);
  visibility: hidden;
  pointer-events: none;
  transition:
    opacity 320ms var(--ease-out-expo),
    transform 320ms var(--ease-out-expo),
    visibility 0s linear 320ms;
}

/* Held back through the homepage hero sequence. Three buttons parked in
   the corner while the mark recedes and the title comes forward are the
   only things on screen not part of the choreography. hero.js adds
   .hero-complete at the scroll cue, and in the reduced-motion path too,
   so nobody is left without them. */
.page-home .dock {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transform: translateY(10px);
}
.page-home.hero-complete .dock {
  opacity: 1;
  visibility: visible;
  pointer-events: auto;
  transform: none;
  transition:
    opacity 520ms var(--ease-out-expo),
    transform 520ms var(--ease-out-expo);
}
.page-home.hero-complete .dock.is-retired {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .page-home.hero-complete .dock { transform: none; transition: opacity 200ms linear; }
}
@media print { .dock { display: none; } }

/* ================================================================
   LANGUAGE SELECTOR
   Sits left of the primary nav. Each language in its own script,
   never translated into English.
   ================================================================ */
.lang-select { position: relative; display: inline-flex; align-items: center; justify-self: start; }

.lang-select__trigger {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-family: var(--font-sans);
  font-size: var(--type-eyebrow);
  font-weight: 550;
  letter-spacing: 0.1em;
  color: var(--color-text-muted);
  padding: 8px 12px;
  min-height: 36px;
  border: 1px solid rgba(245, 243, 238, 0.14);
  border-radius: 999px;
  background: rgba(26, 35, 48, 0.42);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  backdrop-filter: blur(14px) saturate(150%);
  cursor: pointer;
  transition: color 240ms var(--ease-out-expo), border-color 240ms var(--ease-out-expo);
}
.lang-select__trigger:hover { color: var(--pearl); }
.lang-select__trigger[aria-expanded="true"] { color: var(--pearl); border-color: rgba(245,243,238,0.3); }

.lang-select__chev {
  width: 6px; height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: translateY(-2px) rotate(45deg);
  transition: transform 240ms var(--ease-out-expo);
}
.lang-select__trigger[aria-expanded="true"] .lang-select__chev { transform: translateY(1px) rotate(225deg); }

.lang-select__menu {
  position: absolute;
  top: calc(100% + 8px); left: 0;
  z-index: calc(var(--z-header) + 5);
  min-width: 170px;
  margin: 0; padding: 6px;
  list-style: none;
  border: 1px solid rgba(245, 243, 238, 0.14);
  border-radius: 12px;
  background: rgba(16, 22, 34, 0.94);
  -webkit-backdrop-filter: blur(20px) saturate(160%);
  backdrop-filter: blur(20px) saturate(160%);
  box-shadow: 0 22px 48px -14px rgba(0,0,0,0.8);
}
.lang-select__menu[hidden] { display: none; }

.lang-select__opt {
  display: block; width: 100%;
  text-align: left;
  font-family: var(--font-sans);
  font-size: var(--type-caption);
  color: var(--color-text-muted);
  padding: 10px 12px;
  min-height: 44px;
  border-radius: 8px;
  background: none;
  cursor: pointer;
  white-space: nowrap;
  transition: color 200ms var(--ease-out-expo), background-color 200ms var(--ease-out-expo);
}
.lang-select__opt:hover { color: var(--pearl); background: rgba(245,243,238,0.06); }
.lang-select__opt[aria-selected="true"] { color: var(--pearl); background: rgba(245,243,238,0.09); }
.lang-select__opt:focus-visible { outline: 2px solid var(--pearl); outline-offset: -2px; }

/* The selector rides in the right-hand group with the menu toggle, so
   the header keeps its three-column grid (logo | nav | end) rather than
   wrapping to a second row. */
.site-header__end {
  display: inline-flex;
  align-items: center;
  gap: var(--space-3);
  justify-self: end;
}

/* Homepage: hidden until the hero sequence lands, like the rest of the
   bar. hero.js fades .site-header__end in with the other controls —
   the selector previously carried opacity: 0 with nothing to reveal it,
   so it was invisible on the homepage permanently. */
.page-home .site-header .site-header__end { opacity: 0; }

@media (max-width: 900px) {
  /* 44px minimum tap target — the trigger was 36px, the only control on
     the site still under it. */
  .lang-select__trigger { min-height: 44px; }
}

@media (max-width: 480px) {
  .lang-select__trigger { padding: 7px 10px; min-height: 44px; }
  .lang-select__menu { min-width: 152px; max-width: calc(100vw - 32px); }
}

/* ================================================================
   COCHIN NOW — Cochin local time and live weather, one quiet line.
   "Cochin · 19:04 IST · ☁ 26° Cloudy". No open/closed judgement —
   the client asked for just the two facts.
   ================================================================ */
.cochin-now {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  padding: 0.5rem 1.05rem;
  border-radius: 999px;
  background: rgba(255, 255, 255, 0.05);
  border: 1px solid rgba(245, 243, 238, 0.10);
  -webkit-backdrop-filter: blur(16px) saturate(160%);
  backdrop-filter: blur(16px) saturate(160%);
  /* The inline nav is hidden at every width on this site, so centring
     this in the empty middle column would leave it floating alone in
     the gap. Grouped against the language picker and the menu button,
     it reads instead as one utility cluster. */
  justify-self: end;
  margin-right: clamp(0.75rem, 2vw, 1.5rem);
  font-family: var(--font-sans);
  line-height: 1;
  white-space: nowrap;
}
.cochin-now__time {
  font-size: 0.9rem;
  font-weight: 600;
  letter-spacing: 0.02em;
  font-variant-numeric: tabular-nums;
  color: var(--pearl);
}
.cochin-now__zone {
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  color: var(--color-text-subtle);
}
.cochin-now__place {
  font-size: 0.78rem;
  letter-spacing: 0.04em;
  color: var(--pearl-muted);
}
.cochin-now__sep { color: var(--color-text-subtle); opacity: 0.6; }
.cochin-now__weather { display: inline-flex; align-items: center; gap: 0.45rem; }
.cochin-now__weather[hidden] { display: none; }
.cochin-now__glyph { font-size: 0.95rem; }
.cochin-now__temp {
  font-size: 0.9rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--pearl);
}
.cochin-now__cond {
  font-size: 0.78rem;
  letter-spacing: 0.03em;
  color: var(--pearl-muted);
}

/* Tightening order as the header narrows: the condition word goes
   first, then the place name — the time and the temperature survive
   the longest. The child combinator spares the weather\'s own sep,
   which is nested one level down. */
@media (max-width: 1180px) { .cochin-now__cond { display: none; } }
@media (max-width: 980px)  {
  .cochin-now > .cochin-now__place,
  .cochin-now > .cochin-now__sep { display: none; }
}
@media (max-width: 860px)  { .cochin-now { display: none; } }

/* ================================================================
   MENU — PRODUCTS SUBMENU. Clicking Products in the overlay slides to
   a second panel: the four forms, each with its products, each title a
   link into that section of the products page.
   ================================================================ */
.menu-overlay.menu-sub-open .menu-list,
.menu-overlay.menu-sub-open .menu-overlay__footer {
  opacity: 0;
  visibility: hidden;
  pointer-events: none;
  transition: opacity 200ms var(--ease-out), visibility 0s linear 200ms;
}

.menu-sub {
  width: 100%;
  max-width: 34rem;
  max-height: calc(100vh - 11rem);
  max-height: calc(100dvh - 11rem);
  overflow-y: auto;
  scrollbar-width: none;
  display: flex;
  flex-direction: column;
  gap: clamp(1.5rem, 4vh, 2.5rem);
  opacity: 0;
  transform: translateY(14px);
  transition:
    opacity 380ms var(--ease-out),
    transform 380ms var(--ease-out);
}
/* Kept in the flow while hidden — that is what holds the layout still.
   visibility:hidden also drops it from the tab order. */
.menu-sub[hidden] { display: flex; visibility: hidden; pointer-events: none; }
.menu-overlay.menu-sub-open .menu-sub { opacity: 1; transform: none; }

.menu-sub__back {
  align-self: flex-start;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.55rem 1.1rem;
  border-radius: 999px;
  border: 1px solid rgba(245, 243, 238, 0.18);
  background: rgba(255, 255, 255, 0.06);
  -webkit-backdrop-filter: blur(16px) saturate(170%);
  backdrop-filter: blur(16px) saturate(170%);
  color: var(--pearl);
  font-family: var(--font-sans);
  font-size: 0.85rem;
  letter-spacing: 0.04em;
  cursor: pointer;
  transition: background-color 240ms var(--ease-out-expo);
}
.menu-sub__back:hover { background: rgba(255, 255, 255, 0.12); }

/* Five destinations, one format — the same scale and voice as the
   main menu list, so the second level feels like the same room. */
.menu-sub__list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}
.menu-sub__link {
  display: inline-flex;
  align-items: center;
  gap: 0.75rem;
  font-family: var(--font-display);
  font-size: clamp(2rem, 5vw, 3.25rem);
  font-weight: 400;
  line-height: 1.05;
  letter-spacing: var(--tr-display);
  color: var(--color-text);
  text-decoration: none;
  transition: opacity var(--dur-micro) var(--ease-micro);
}
@media (hover: hover) and (pointer: fine) {
  .menu-sub__link:hover { opacity: 0.7; }
}
.menu-sub__link:focus-visible {
  outline: 2px solid var(--pearl);
  outline-offset: 8px;
  border-radius: 2px;
}
.menu-sub__arrow {
  font-size: 0.55em;
  opacity: 0;
  transform: translateX(-6px);
  transition: opacity 240ms var(--ease-out), transform 240ms var(--ease-out);
}
.menu-sub__link:hover .menu-sub__arrow,
.menu-sub__link:focus-visible .menu-sub__arrow { opacity: 1; transform: none; }

/* Stagger the destinations in, like the main list. */
.menu-overlay.menu-sub-open .menu-sub__list li {
  animation: menu-sub-rise 500ms var(--ease-out) backwards;
}
.menu-overlay.menu-sub-open .menu-sub__list li:nth-child(1) { animation-delay: 40ms; }
.menu-overlay.menu-sub-open .menu-sub__list li:nth-child(2) { animation-delay: 110ms; }
.menu-overlay.menu-sub-open .menu-sub__list li:nth-child(3) { animation-delay: 180ms; }
.menu-overlay.menu-sub-open .menu-sub__list li:nth-child(4) { animation-delay: 250ms; }
.menu-overlay.menu-sub-open .menu-sub__list li:nth-child(5) { animation-delay: 320ms; }
@keyframes menu-sub-rise {
  from { opacity: 0; transform: translateY(18px); }
  to   { opacity: 1; transform: none; }
}
@media (prefers-reduced-motion: reduce) {
  .menu-overlay.menu-sub-open .menu-sub__list li { animation: none; }
}

.menu-sub::-webkit-scrollbar { display: none; }
