/* ============================================================
   SKAIWALK · Shared site chrome
   Imports tokens, defines nav + footer + shared layout + motion.
   ============================================================ */
@import url('./tokens.css?v=254');

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; }

/* ============================================================
   Cross-page transitions — works in every browser.

   On every page load, <main> enters with a fade-up keyframe.
   On link click, JS adds `html.is-leaving`, which swaps in an exit
   keyframe that fades + slides up before the navigation fires.

   The nav and footer sit outside <main>, so they never animate — that's
   what makes the page feel like the chrome stays put while the content
   swaps. Earlier we tried the View Transitions API for this, but support
   is uneven and the effect was too subtle to notice; the JS+CSS approach
   is more visible and consistent.
   ============================================================ */
main {
  animation: skPageEnter 520ms var(--sk-ease-flow) both;
}
html.is-leaving main {
  animation: skPageExit 280ms var(--sk-ease-flow) both;
}
@keyframes skPageEnter {
  from { opacity: 0; transform: translateY(14px); }
  to   { opacity: 1; transform: translateY(0); }
}
@keyframes skPageExit {
  to { opacity: 0; transform: translateY(-10px); }
}
@media (prefers-reduced-motion: reduce) {
  main { animation: none !important; }
  /* Stop the looping decorative motion: cloud parallax + the breathing hero arrow. */
  .site::after, body::before, body::after { animation: none !important; }
  .hero__learn-more svg { animation: none !important; }
}

/* ============================================================
   Global keyboard focus ring. Most interactive elements (links, buttons, nav
   items, cards, the icon toggles) had NO focus style — invisible for keyboard /
   screen-reader users. :focus-visible shows the ring only for keyboard focus,
   never for mouse clicks. --sk-fg keeps it high-contrast in both themes.
   ============================================================ */
:focus-visible {
  outline: 2px solid var(--sk-fg);
  outline-offset: 2px;
}

body {
  background: var(--sk-bg);
  color: var(--sk-fg);
  overflow-x: hidden;
  /* "Light feather" baseline:
     - 300 weight on body so paragraphs feel airy
     - 0.025em tracking opens up paragraph rhythm
     - 1.75 line-height gives generous breathing room
     - Hairline shadow gives every glyph a subtle lifted quality
     Headings & UI chrome override these via their own rules. */
  font-weight: var(--sk-weight-light);
  letter-spacing: 0.025em;
  line-height: 1.75;
  text-shadow: 0 1px 2px rgba(35, 42, 56, 0.06);
}

img { max-width: 100%; display: block; }
a { color: inherit; text-decoration: none; }
button { font-family: inherit; cursor: pointer; border: 0; background: none; color: inherit; }

/* ---------- Page shell ---------- */
.site {
  min-height: 100vh;
  position: relative;
}

/* ============================================================
   Atmospheric page background
   Pure white kills frosted glass — glass needs colored light
   moving behind it to read as a material. We layer:
   - a soft tonal gradient (cool top, warmer mid, cool bottom)
   - 3 large blurred light orbs that drift slowly
   - a faint grain to break up flat fills
   ============================================================ */
.site::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  /* Subtle top-to-bottom tint — both ends carry color, gently widened range. */
  background:
    linear-gradient(180deg,
      #EAF0F6 0%,
      #CCD7E2 100%);
}

/* Cloud-layer orbs — TWO layers at different speeds for parallax depth.
   Each layer is a 100vw-wide tile that repeats horizontally. ALL orb centers
   sit safely inside the tile (with their radius fitting too), so the tile's
   edges are transparent and the repeat seam is invisible. */

/* THREE layers, each with its own horizontal scroll AND vertical sway.
   The periods don't divide evenly into each other, so the motion never
   syncs up — it always feels organic. Layers extend beyond the viewport
   so vertical sway never exposes top/bottom edges. */

/* Layer A (back) — biggest, slowest, gentlest sway. */
.site::after {
  content: "";
  position: fixed;
  top: -15%; bottom: -15%; left: 0; right: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(ellipse 52% 42% at 32% 30%,
      rgba(166,211,230,0.70) 0%,
      rgba(166,211,230,0.22) 38%,
      transparent 62%),
    radial-gradient(ellipse 44% 36% at 72% 68%,
      rgba(232,222,210,0.65) 0%,
      rgba(232,222,210,0.20) 40%,
      transparent 65%);
  background-size: 100vw 100%;
  background-repeat: repeat-x;
  animation:
    cloudDrift 50s linear infinite,
    swayA 80s ease-in-out infinite;
  will-change: background-position, transform;
}

/* Layer B (middle) — medium, faster horizontal, sharper vertical sway. */
body::before {
  content: "";
  position: fixed;
  top: -15%; bottom: -15%; left: 0; right: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(ellipse 36% 32% at 35% 18%,
      rgba(214,224,235,0.72) 0%,
      rgba(214,224,235,0.22) 42%,
      transparent 65%),
    radial-gradient(ellipse 34% 30% at 65% 78%,
      rgba(180,210,228,0.58) 0%,
      rgba(180,210,228,0.18) 40%,
      transparent 62%);
  background-size: 100vw 100%;
  background-repeat: repeat-x;
  animation:
    cloudDrift 25s linear infinite,
    swayB 45s ease-in-out infinite;
  will-change: background-position, transform;
}

/* Layer C (front) — smallest, fastest, most lively sway. */
body::after {
  content: "";
  position: fixed;
  top: -15%; bottom: -15%; left: 0; right: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    radial-gradient(ellipse 22% 20% at 50% 42%,
      rgba(255,250,242,0.60) 0%,
      transparent 55%);
  background-size: 100vw 100%;
  background-repeat: repeat-x;
  animation:
    cloudDrift 15s linear infinite,
    swayC 30s ease-in-out infinite;
  will-change: background-position, transform;
}

/* Horizontal scroll — seamless because tile is 100vw wide. */
@keyframes cloudDrift {
  from { background-position: 0 0; }
  to   { background-position: 100vw 0; }
}

/* Vertical sway — closed loop (start = end). Each layer has its own curve
   and amplitude, so the layers never move in lockstep. */
@keyframes swayA {
  0%   { transform: translate3d(0, 0, 0); }
  50%  { transform: translate3d(0, 50px, 0); }
  100% { transform: translate3d(0, 0, 0); }
}
@keyframes swayB {
  0%   { transform: translate3d(0, 0, 0); }
  35%  { transform: translate3d(0, -32px, 0); }
  72%  { transform: translate3d(0, 28px, 0); }
  100% { transform: translate3d(0, 0, 0); }
}
@keyframes swayC {
  0%   { transform: translate3d(0, 0, 0); }
  28%  { transform: translate3d(0, 22px, 0); }
  56%  { transform: translate3d(0, -18px, 0); }
  84%  { transform: translate3d(0, 12px, 0); }
  100% { transform: translate3d(0, 0, 0); }
}

/* Subtle grain — breaks the flatness of large fills, never visible up close */
.site > .sk-grain {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: 0.28;
  mix-blend-mode: overlay;
  background-image:
    url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0  0 0 0 0 0  0 0 0 0 0  0 0 0 0.4 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}

/* ============================================================
   DARK THEME — page chrome overrides.
   Apply [data-theme="dark"] on <html> to invert the atmosphere.
   Token-driven surfaces (nav glass, cards, buttons, footer) follow
   automatically via tokens.css; this block handles the painted bits.
   ============================================================ */
[data-theme="dark"] body {
  /* The hairline ink shadow is wrong on a dark field — it darkens already-dark
     pixels under each glyph and reads as a weight gain. Off entirely. */
  text-shadow: none;
}
[data-theme="dark"] .site::before {
  /* Ink ramp from void to elevated chrome — dropped a notch darker
     (2026-05-15) so glass material reads as light, not as colour. */
  background:
    linear-gradient(180deg,
      #06090E 0%,
      #12181F 100%);
}
[data-theme="dark"] .site::after {
  /* Layer A — cool blue clouds at low opacity. The warm cream of the light
     theme is dropped: a cool palette holds the mood and lets accent blue lead.
     Opacities cut ~40% to match the darker field. */
  background-image:
    radial-gradient(ellipse 52% 42% at 32% 30%,
      rgba(166, 211, 230, 0.06) 0%,
      rgba(166, 211, 230, 0.025) 38%,
      transparent 62%),
    radial-gradient(ellipse 44% 36% at 72% 68%,
      rgba(166, 211, 230, 0.05) 0%,
      rgba(166, 211, 230, 0.018) 40%,
      transparent 65%);
}
[data-theme="dark"] body::before {
  /* Layer B — neutral white wash + cool blue, halved against the darker bg. */
  background-image:
    radial-gradient(ellipse 36% 32% at 35% 18%,
      rgba(255, 255, 255, 0.025) 0%,
      rgba(255, 255, 255, 0.008) 42%,
      transparent 65%),
    radial-gradient(ellipse 34% 30% at 65% 78%,
      rgba(166, 211, 230, 0.045) 0%,
      rgba(166, 211, 230, 0.012) 40%,
      transparent 62%);
}
[data-theme="dark"] body::after {
  /* Layer C — single small white highlight, very subtle. */
  background-image:
    radial-gradient(ellipse 22% 20% at 50% 42%,
      rgba(255, 255, 255, 0.02) 0%,
      transparent 55%);
}
[data-theme="dark"] .site > .sk-grain {
  /* Overlay on dark crushes shadows; screen at low opacity gives the same
     "noise" feel without flattening the field. */
  opacity: 0.10;
  mix-blend-mode: screen;
}
/* Wordmark logo — the PNG is dark-on-transparent. Invert so it reads on dark. */
[data-theme="dark"] .sk-nav__brand img {
  filter: invert(1) brightness(1.1);
}
/* Nav hover pill — neutralize the cool ink insets that look wrong on dark. */
[data-theme="dark"] .sk-nav__hover-pill {
  background: rgba(255, 255, 255, 0.08);
  box-shadow:
    inset 0 1px 0 rgba(255, 255, 255, 0.20),
    inset 0 -1px 0 rgba(0, 0, 0, 0.10),
    0 1px 4px -1px rgba(0, 0, 0, 0.18);
}

/* ---------- Global nav ----------
   Two glass pills: left holds logo + links, right holds the search field.
   Both use the unified glass tokens for identical surface treatment. */
/* ============================================================
   Horizontal nav — top bar.
   Logo at the left edge (no surround). Links pill pushed to the right
   edge via `margin-left: auto`. The hidden search pill (when shown)
   sits to the right of the links pill.
   ============================================================ */
.sk-nav {
  position: fixed;
  top: 0; left: 0;
  z-index: 100;
  padding: 10px 20px;
  display: flex;
  align-items: center;
  gap: 16px;
  width: 100vw;
  max-width: none;
}
.sk-nav__brand {
  display: inline-flex;
  align-items: center;
  padding: 6px 16px 6px 8px;
  /* No glass surround — the logo sits directly on the page bg. */
  transition: opacity 240ms var(--sk-ease-flow);
}
.sk-nav__brand img {
  height: 13px;
  width: auto;
  display: block;
  opacity: 0.95;
  transition: opacity 160ms var(--sk-ease-flow);
}
.sk-nav__brand:hover img { opacity: 1; }

/* Links pill — centered glass pill that wraps just the 3 nav items.
   IMPORTANT: no horizontal padding. The first/last link must sit flush with
   the pill's outer edges so the sliding hover indicator aligns with the
   container at the edges. Breathing room around link text comes from the
   LINK's own padding, not the container. */
.sk-nav__links {
  /* Pushed to the right edge of the bar; brand keeps its natural left position. */
  margin-left: auto;
  position: relative; /* anchor for sliding hover pill */
  height: 38px;
  padding: 0;
  border-radius: var(--sk-radius-pill);
  background: var(--sk-glass-bg);
  backdrop-filter: var(--sk-glass-blur);
  -webkit-backdrop-filter: var(--sk-glass-blur);
  border: var(--sk-glass-border);
  box-shadow: var(--sk-glass-shadow);
  display: inline-flex;
  align-items: center;
  gap: 4px;
  font-size: 14px;
  font-weight: var(--sk-weight-regular);
  letter-spacing: 0.04em;
  color: var(--sk-fg);
}

/* Search pill — same glass treatment. Hidden site-wide until search has
   a backend; when shown, sits at the right end of the cluster. */
.sk-nav__search-pill {
  height: 38px;
  padding: 0 6px;
  border-radius: var(--sk-radius-pill);
  background: var(--sk-glass-bg);
  backdrop-filter: var(--sk-glass-blur);
  -webkit-backdrop-filter: var(--sk-glass-blur);
  border: var(--sk-glass-border);
  box-shadow: var(--sk-glass-shadow);
  display: none;
  align-items: center;
}
.sk-nav__link {
  position: relative;
  z-index: 1; /* above hover pill */
  padding: 6px 16px;
  line-height: 1.4;
  white-space: nowrap; /* keep multi-word labels ("Log in") on one line when the bar tightens (~640–900px) */
  border-radius: var(--sk-radius-pill);
  opacity: 0.82;
  transition: opacity 240ms var(--sk-ease-flow);
  /* Grid stack: ::before is a hidden bold "ghost" reserving the bold-weight
     width; .sk-nav__link-text is the visible label rendered on top. The link
     therefore always occupies its bold-state width, so the hover weight change
     never shifts neighbours or expands the bar. */
  display: inline-grid;
  place-items: center;
}
.sk-nav__link::before {
  content: attr(data-text);
  grid-area: 1 / 1;
  font-weight: var(--sk-weight-semibold);
  visibility: hidden;
  pointer-events: none;
}
.sk-nav__link-text {
  grid-area: 1 / 1;
  font-weight: var(--sk-weight-regular);
}
.sk-nav__link:hover { opacity: 1; }
.sk-nav__link:hover .sk-nav__link-text { font-weight: var(--sk-weight-semibold); }
.sk-nav__link[data-active="true"] { opacity: 1; }
.sk-nav__link[data-active="true"] .sk-nav__link-text { font-weight: var(--sk-weight-semibold); }

/* Sliding hover pill — fills the menu-bar pill flush; spring-eased */
.sk-nav__hover-pill {
  position: absolute;
  inset: 0;
  width: 0;
  right: auto;
  transform: translateX(0);
  opacity: 0;
  pointer-events: none;
  z-index: 0;
  border-radius: var(--sk-radius-pill);
  background: rgba(255, 255, 255, 0.10);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.55),
    inset 0 -1px 0 rgba(35,72,96,0.05),
    0 1px 4px -1px rgba(45,90,115,0.10);
  transition:
    transform 380ms var(--sk-ease-lift),
    width 380ms var(--sk-ease-lift),
    opacity 200ms var(--sk-ease-flow);
}
.sk-nav__hover-pill.is-snapping {
  transition: opacity 200ms var(--sk-ease-flow);
}

/* Search field inside its own pill */
.sk-nav__search {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 28px;
  border-radius: var(--sk-radius-pill);
  background: transparent;
}
.sk-nav__search-icon {
  position: absolute;
  left: 10px;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  color: var(--sk-fg);
  transition: color 200ms var(--sk-ease-flow);
}
.sk-nav__search input {
  border: 0;
  background: none;
  outline: none;
  font: inherit;
  font-size: 14px;
  color: var(--sk-fg);
  width: 180px;
  padding: 0 14px 0 28px;
  height: 100%;
}
.sk-nav__search input::placeholder {
  color: var(--sk-fg);
  opacity: 0.6;
}
.sk-nav__search input::-webkit-search-cancel-button { -webkit-appearance: none; }

/* ---------- Section scaffolding ---------- */
.sk-section {
  padding: 120px 48px;
  position: relative;
}
.sk-section--tight { padding: 80px 48px; }
.sk-section--pad-hero { padding: 112px 48px 80px; }

.sk-container {
  max-width: 1240px;
  margin: 0 auto;
}
.sk-container--narrow { max-width: 840px; }
.sk-container--read { max-width: 640px; }

/* ---------- Eyebrow / heading / lede ---------- */
.sk-eyebrow {
  font-family: var(--sk-font-sans);
  font-weight: var(--sk-weight-semibold);
  font-size: 18px;
  letter-spacing: var(--sk-tracking-caps);
  text-transform: uppercase;
  color: var(--sk-fg-muted);
}

.sk-display {
  font-weight: var(--sk-weight-semibold);
  font-size: clamp(56px, 7.2vw, 104px);
  line-height: 1.02;
  letter-spacing: -0.02em;
}
.sk-title {
  font-weight: var(--sk-weight-semibold);
  font-size: clamp(40px, 4.4vw, 64px);
  line-height: 1.08;
  letter-spacing: -0.015em;
}
.sk-h2 {
  font-weight: var(--sk-weight-medium);
  font-size: clamp(28px, 2.8vw, 40px);
  line-height: 1.2;
  letter-spacing: -0.01em;
}
.sk-lede {
  font-weight: var(--sk-weight-light);
  font-size: 19px;
  line-height: 1.6;
  color: var(--sk-fg-muted);
}

/* ---------- Horizon line — the signature ---------- */
.sk-horizon {
  display: block;
  width: 100%;
  height: 48px;
  position: relative;
  overflow: visible;
}
.sk-horizon svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}
.sk-horizon path {
  fill: none;
  stroke: var(--sk-accent);
  stroke-width: 1;
  opacity: 0.55;
}

/* ---------- Buttons ---------- */
.sk-btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 14px 24px;
  border-radius: var(--sk-radius-pill);
  font-size: 14px;
  font-weight: var(--sk-weight-medium);
  letter-spacing: 0.01em;
  transition: transform 360ms var(--sk-ease-flow),
              background 360ms var(--sk-ease-flow),
              color 360ms var(--sk-ease-flow),
              border-color 360ms var(--sk-ease-flow);
}
.sk-btn__arrow { transition: transform 360ms var(--sk-ease-flow); }
.sk-btn:hover .sk-btn__arrow { transform: translateX(4px); }
.sk-btn:active { opacity: 0.85; }

/* All translucent surfaces use the unified glass tokens — same visual language
   for buttons, cards, nav, hero CTA. Change tokens.css to retune everything. */
.sk-btn--primary,
.sk-btn--ghost {
  position: relative;
  background: var(--sk-glass-bg);
  backdrop-filter: var(--sk-glass-blur);
  -webkit-backdrop-filter: var(--sk-glass-blur);
  border: var(--sk-glass-border);
  box-shadow: var(--sk-glass-shadow);
  color: var(--sk-fg);
  text-shadow: none;
  transition:
    background 240ms var(--sk-ease-flow),
    border-color 240ms var(--sk-ease-flow),
    box-shadow 240ms var(--sk-ease-flow);
}
.sk-btn--primary { font-weight: var(--sk-weight-semibold); }
/* Rim-only hover (2026-05-15) — the surface holds at base glass-bg; only the
   border and ambient shadow lift. Same rule applied to all cards/buttons. */
.sk-btn--primary:hover,
.sk-btn--ghost:hover {
  border: var(--sk-glass-border-hover);
  box-shadow: var(--sk-glass-shadow-hover);
}

.sk-btn--link {
  padding: 4px 0;
  color: var(--sk-fg);
  font-size: 14px;
  border-bottom: 1px solid transparent;
  border-radius: 0;
}
.sk-btn--link:hover { border-bottom-color: var(--sk-accent); }

/* ---------- Cards (frosted glass) ---------- */
/* Uses the unified glass tokens so light/dark theming and the system-wide
   transparency baseline are consistent with every other glass surface. */
.sk-card {
  position: relative;
  background: var(--sk-glass-bg);
  backdrop-filter: var(--sk-glass-blur);
  -webkit-backdrop-filter: var(--sk-glass-blur);
  border: var(--sk-glass-border);
  border-radius: var(--sk-radius-lg);
  box-shadow: var(--sk-glass-shadow);
}

/* ---------- Footer (minimal single-row) ---------- */
.sk-footer {
  padding: 28px 48px;
  border-top: 1px solid var(--sk-hairline);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  max-width: 1240px;
  margin: 40px auto 0;
  font-size: 13px;
  color: var(--sk-fg-subtle);
}
.sk-footer__brand {
  font-weight: var(--sk-weight-light);
  color: var(--sk-fg-muted);
  /* Settles the brand tagline a touch lower than the other footer items;
     all the right-side controls keep their centered baseline. */
  transform: translateY(4px);
}
.sk-footer__links {
  display: flex;
  align-items: center;
  gap: 24px;
}
.sk-footer__links a {
  color: var(--sk-fg-subtle);
  opacity: 0.85;
  transition: opacity 240ms var(--sk-ease-flow), color 240ms var(--sk-ease-flow);
}
.sk-footer__links a:hover { opacity: 1; color: var(--sk-fg); }
.sk-footer__copyright { white-space: nowrap; }
/* Social icons cluster — line-style, sit between Contact and 繁中. */
.sk-footer__social {
  display: inline-flex;
  align-items: center;
  gap: 14px;
}
.sk-footer__social a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: var(--sk-fg-subtle);
}
.sk-footer__social svg { display: block; }

/* Theme toggle — sun (light) ↔ moon (dark). Same color treatment as the
   language picker. Icon-only; the active glyph is chosen by the page-level
   [data-theme] attribute on <html>. */
.sk-theme-toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  border-radius: var(--sk-radius-pill);
  color: var(--sk-fg-subtle);
  cursor: pointer;
  transition: color 240ms var(--sk-ease-flow);
}
.sk-theme-toggle:hover { color: var(--sk-fg); }
.sk-theme-toggle__icon { display: block; }
.sk-theme-toggle__moon { display: none; }
[data-theme="dark"] .sk-theme-toggle__sun { display: none; }
[data-theme="dark"] .sk-theme-toggle__moon { display: block; }

/* Language picker — same glass tokens as nav.
   `.sk-lang--nav` is the top-right variant that lives in the nav and pops
   the menu DOWN instead of up. */
.sk-lang { position: relative; display: inline-flex; align-items: center; }
.sk-lang--nav { margin-left: 8px; }
.sk-lang--nav .sk-lang__menu {
  bottom: auto;
  top: calc(100% + 8px);
  /* Slide-down enter animation instead of slide-up. */
  transform: translateY(-4px);
}
.sk-lang--nav .sk-lang__menu[data-open="true"] { transform: translateY(0); }
.sk-lang__toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-radius: var(--sk-radius-pill);
  font: inherit;
  font-size: 13px;
  /* fg-muted (was fg-subtle) — same brightness as nav links so the toggle
     reads as part of the nav, not as auxiliary chrome. */
  color: var(--sk-fg-muted);
  cursor: pointer;
  transition: opacity 240ms var(--sk-ease-flow), color 240ms var(--sk-ease-flow);
}
.sk-lang__toggle:hover { color: var(--sk-fg); }
.sk-lang__toggle svg { display: block; opacity: 1; }
.sk-lang__menu {
  position: absolute;
  bottom: calc(100% + 8px);
  right: 0;
  min-width: 160px;
  padding: 6px;
  border-radius: var(--sk-radius-popover);
  background: var(--sk-glass-bg);
  backdrop-filter: var(--sk-glass-blur);
  -webkit-backdrop-filter: var(--sk-glass-blur);
  border: var(--sk-glass-border);
  box-shadow: var(--sk-glass-shadow);
  display: flex;
  flex-direction: column;
  gap: 2px;
  opacity: 0;
  pointer-events: none;
  transform: translateY(4px);
  transition:
    opacity 200ms var(--sk-ease-flow),
    transform 240ms var(--sk-ease-flow);
  z-index: 50;
}
.sk-lang__menu[data-open="true"] {
  opacity: 1;
  pointer-events: auto;
  transform: translateY(0);
}
.sk-lang__item {
  display: block;
  width: 100%;
  text-align: left;
  padding: 8px 12px;
  border-radius: 10px;
  font: inherit;
  font-size: 13px;
  color: var(--sk-fg);
  cursor: pointer;
  transition: background 200ms var(--sk-ease-flow);
}
/* Menu rows have no base surface and no rim — the fill IS the feedback.
   Hover uses --sk-glass-bg-hover (a notch brighter than the base) so the
   change is perceptible. Active row stays at the base fill and is marked
   by font-weight instead, so hover always clearly contrasts with idle. */
.sk-lang__item:hover { background: var(--sk-glass-bg-hover); }
html[data-lang="en"] .sk-lang__item[data-lang="en"],
html[data-lang="zh-TW"] .sk-lang__item[data-lang="zh-TW"] {
  font-weight: var(--sk-weight-medium);
  background: var(--sk-glass-bg);
}

/* ---------- Reveal-on-scroll ---------- */
.sk-reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 900ms var(--sk-ease-flow),
              transform 900ms var(--sk-ease-flow);
}
.sk-reveal[data-visible="true"] {
  opacity: 1;
  transform: translateY(0);
}
.sk-reveal[data-delay="1"] { transition-delay: 80ms; }
.sk-reveal[data-delay="2"] { transition-delay: 160ms; }
.sk-reveal[data-delay="3"] { transition-delay: 240ms; }
.sk-reveal[data-delay="4"] { transition-delay: 320ms; }

/* ---------- Watch render — pure CSS device ---------- */
.sk-watch {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: 50%;
}
.sk-watch__case {
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background:
    radial-gradient(circle at 32% 28%,
      #4a5260 0%, #2c333f 22%, #151a22 55%, #0a0e14 100%);
  /* Outer halo lit by the hero atmosphere + grounded floor shadow. */
  box-shadow:
    inset 0 0 0 2px rgba(255,255,255,0.10),
    inset 0 1px 0 rgba(255,255,255,0.18),
    0 0 60px 8px rgba(166,211,230,0.18),
    0 30px 80px rgba(35,42,56,0.22),
    0 8px 20px rgba(35,42,56,0.12);
}
.sk-watch__bezel {
  position: absolute;
  inset: 2.5%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 35% 25%,
      rgba(255,255,255,0.85) 0%,
      rgba(220,228,240,0.55) 8%,
      transparent 20%),
    conic-gradient(from 200deg,
      #d9dde4 0deg,
      #8c96a6 60deg,
      #3b4455 120deg,
      #1a1f2a 180deg,
      #5b6576 260deg,
      #b3bbc8 320deg,
      #d9dde4 360deg);
  box-shadow:
    inset 0 0 0 1px rgba(255,255,255,0.2);
}
.sk-watch__glass {
  position: absolute;
  inset: 6%;
  border-radius: 50%;
  background:
    radial-gradient(circle at 30% 25%,
      rgba(255,255,255,0.16) 0%,
      rgba(255,255,255,0.04) 18%,
      transparent 40%),
    radial-gradient(circle at 72% 78%,
      rgba(166,211,230,0.14) 0%,
      transparent 45%),
    linear-gradient(145deg, #0a0f16 0%, #12202b 60%, #0a0f16 100%);
  overflow: hidden;
  box-shadow:
    inset 0 0 40px rgba(0,0,0,0.6),
    inset 0 1px 0 rgba(255,255,255,0.12);
}
.sk-watch__glass::after {
  /* 2.5D curved glass highlight sweep */
  content: "";
  position: absolute;
  inset: -10%;
  border-radius: 50%;
  background: linear-gradient(135deg,
    transparent 30%,
    rgba(255,255,255,0.06) 45%,
    rgba(255,255,255,0.14) 50%,
    rgba(255,255,255,0.04) 58%,
    transparent 70%);
  pointer-events: none;
}
.sk-watch__screen {
  position: relative;
  width: 100%;
  height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  color: rgba(255,255,255,0.95);
  font-family: var(--sk-font-sans);
  text-align: center;
  z-index: 2;
}
.sk-watch__time {
  font-weight: var(--sk-weight-light);
  font-size: clamp(40px, 8vw, 64px);
  letter-spacing: -0.02em;
  line-height: 1;
}
.sk-watch__meta {
  font-size: 10px;
  color: rgba(255,255,255,0.55);
  letter-spacing: 0.18em;
  text-transform: uppercase;
  margin-top: 8px;
}
.sk-watch__horizon {
  position: absolute;
  left: -10%; right: -10%;
  bottom: 28%;
  height: 1px;
  background: linear-gradient(90deg,
    transparent, rgba(166,211,230,0.8), transparent);
  filter: blur(0.5px);
}

/* Crown dot on the side */
.sk-watch__crown {
  position: absolute;
  right: -2%;
  top: 42%;
  width: 4%;
  height: 16%;
  border-radius: 4px 0 0 4px;
  background: linear-gradient(180deg, #6b7280, #2a2f3a);
  box-shadow:
    inset 1px 0 0 rgba(255,255,255,0.25),
    inset -1px 0 0 rgba(0,0,0,0.4);
}

/* ---------- Mobile hamburger + dropdown (injected by nav.js; shown ≤640px) --- */
.sk-nav__burger {
  display: none;                 /* desktop: hidden — the links pill shows instead */
  margin-left: auto;
  width: 40px; height: 38px;
  flex-direction: column;
  align-items: center; justify-content: center;
  gap: 4px;
  border-radius: var(--sk-radius-pill);
  background: var(--sk-glass-bg);
  backdrop-filter: var(--sk-glass-blur);
  -webkit-backdrop-filter: var(--sk-glass-blur);
  border: var(--sk-glass-border);
  box-shadow: var(--sk-glass-shadow);
  cursor: pointer;
}
.sk-nav__burger span {
  display: block; width: 16px; height: 2px;
  background: var(--sk-fg); border-radius: 2px;
  transition: transform 240ms var(--sk-ease-flow), opacity 200ms var(--sk-ease-flow);
}
.sk-nav__burger.is-open span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.sk-nav__burger.is-open span:nth-child(2) { opacity: 0; }
.sk-nav__burger.is-open span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

.sk-nav__mobile {
  display: none;                 /* base hidden; the mobile query shows it when open */
  position: absolute;
  top: calc(100% + 8px);
  right: 16px;
  min-width: 200px;
  max-width: calc(100vw - 32px);
  padding: 8px;
  border-radius: 18px;
  background: var(--sk-glass-bg);
  backdrop-filter: var(--sk-glass-blur);
  -webkit-backdrop-filter: var(--sk-glass-blur);
  border: var(--sk-glass-border);
  box-shadow: var(--sk-glass-shadow);
}
.sk-nav__mobile-link {
  display: block;
  padding: 12px 16px;
  border-radius: 12px;
  color: var(--sk-fg);
  font-size: 16px;
  letter-spacing: 0.02em;
  opacity: 0.9;
  transition: background 200ms var(--sk-ease-flow), opacity 200ms var(--sk-ease-flow);
}
.sk-nav__mobile-link:hover { background: rgba(128,128,128,0.14); opacity: 1; }

/* ---------- Responsive ---------- */
@media (max-width: 900px) {
  .sk-nav { padding: 6px 16px; }
  .sk-nav__links { gap: 20px; font-size: 14px; }
  .sk-section { padding: 80px 20px; }
  .sk-footer { padding: 64px 20px 32px; }
  .sk-footer__grid { grid-template-columns: 1fr 1fr; gap: 40px; }
  .sk-footer__bottom { flex-direction: column; gap: 16px; align-items: flex-start; }
}
@media (max-width: 640px) {
  .sk-nav__links { display: none; }
  .sk-footer__grid { grid-template-columns: 1fr; }
  /* Mobile nav: hamburger replaces the hidden links pill; account moves into the menu. */
  .sk-nav__burger { display: flex; }
  .sk-nav__mobile:not([hidden]) { display: block; }
  .sk-nav a[data-nav-account] { display: none; }
}

/* ---------- Global hover lift (snappy) ----------
   Applied to any clickable card / tile / image / icon target.
   "Breathing" feel: small movement, layered timing, gentle return.
*/
.flow__tile,
.moment__visual,
.eco-node,
.action-card,
.surface,
.box-item,
.purchase__visual,
.design__visual,
.drive-int__visual,
.press__strip a,
.sk-footer__col a,
.sk-nav__link {
  /* Default state = "exhale": slow, long-tailed return */
  transition:
    transform 360ms var(--sk-ease-flow),
    box-shadow 440ms 60ms var(--sk-ease-flow),
    border-color 360ms var(--sk-ease-flow),
    opacity 240ms var(--sk-ease-flow),
    background 360ms var(--sk-ease-flow);
  will-change: transform;
  cursor: pointer;
}

/* On hover = "inhale": gentler ease, slight delay between transform and shadow.
   Unified hover (2026-05-15) — every clickable card uses the same recipe:
     translateY(-2px) + --sk-glass-border-hover + --sk-glass-shadow-hover.
   No scale, no hardcoded shadow. `.action-card` is intentionally NOT in this
   list — it uses a ::before reveal pattern (no base surface), see air.css /
   actions.css. */
.flow__tile:hover,
.moment__visual:hover,
.eco-node:hover,
.surface:hover,
.box-item:hover {
  transform: translateY(-2px);
  border: var(--sk-glass-border-hover);
  box-shadow: var(--sk-glass-shadow-hover);
  transition:
    transform 420ms var(--sk-ease-breathe),
    border-color 240ms var(--sk-ease-flow),
    box-shadow 360ms 40ms var(--sk-ease-flow);
}

/* Image-heavy panels — slower, more breath-like scale */
.purchase__visual,
.design__visual,
.drive-int__visual {
  overflow: hidden;
}
.purchase__visual img,
.design__visual img,
.drive-int__visual img {
  transition: transform 720ms var(--sk-ease-flow);
  will-change: transform;
}
.purchase__visual:hover img,
.design__visual:hover img,
.drive-int__visual:hover img {
  transform: scale(1.025);
  transition: transform 700ms var(--sk-ease-breathe);
}

/* Inline links / footer links — subtle drift */
.press__strip a:hover,
.sk-footer__col a:hover {
  transform: translateY(-1px);
  transition: transform 380ms var(--sk-ease-breathe), opacity 240ms var(--sk-ease-flow);
}

/* Generic glass-card hover */
.sk-card {
  transition:
    transform 360ms var(--sk-ease-flow),
    box-shadow 440ms 60ms var(--sk-ease-flow);
  will-change: transform;
}
a.sk-card:hover,
button.sk-card:hover,
.sk-card[data-clickable="true"]:hover {
  /* Same unified recipe as every other card hover. */
  transform: translateY(-2px);
  border: var(--sk-glass-border-hover);
  box-shadow: var(--sk-glass-shadow-hover);
  transition:
    transform 420ms var(--sk-ease-breathe),
    border-color 240ms var(--sk-ease-flow),
    box-shadow 360ms 40ms var(--sk-ease-flow);
}

/* ---------- Buttons: breathing hover ---------- */
.sk-btn {
  /* Override the static base transitions with breathing timing */
  transition:
    transform 360ms var(--sk-ease-flow),
    background 360ms var(--sk-ease-flow),
    box-shadow 440ms 40ms var(--sk-ease-flow),
    color 360ms var(--sk-ease-flow);
  will-change: transform;
}
.sk-btn:hover {
  /* Same unified lift as every card hover — no scale, no hardcoded shadow.
     The token-driven border + shadow set above (lines ~547–552) carry the rim. */
  transform: translateY(-2px);
  transition:
    transform 380ms var(--sk-ease-breathe),
    box-shadow 320ms 30ms var(--sk-ease-flow);
}
/* Earlier passes had per-variant hardcoded inset shadows here for primary
   and ghost buttons. They've been removed (2026-05-15) so every button hover
   shares the same --sk-glass-shadow-hover recipe applied earlier. */
/* ============================================================
   Download section (index page only)
   ============================================================ */
.download {
  padding: 120px 48px;
  max-width: 1280px;
  margin: 0 auto;
}
.download__head {
  text-align: center;
  /* Match the cards' max-width below so the head and the cards row share
     the same horizontal bounds. */
  max-width: 920px;
  margin: 0 auto 56px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 18px;
}
/* Statement — same two-line "Any device. / Always In Reach." pattern as the
   homepage hero, scaled down a touch since this page also has the desktop
   mock and download cards below. */
.download__statement {
  margin: 0;
  line-height: 1.1;
  letter-spacing: -0.025em;
}
.download__statement-setup,
.download__statement-claim {
  display: block;
}
.download__statement-setup {
  font-size: clamp(28px, 2.6vw, 40px);
  font-weight: var(--sk-weight-light);
  color: var(--sk-fg-muted);
}
.download__statement-claim {
  font-size: clamp(40px, 4.2vw, 60px);
  font-weight: var(--sk-weight-light);
  color: var(--sk-fg);
  margin-top: 8px;
}

/* ---------- Desktop UI mockup (above the cards) ---------- */
.download__mock {
  width: 100%;
  max-width: 920px;
  margin: 0 auto 64px;
  display: flex;
  justify-content: center;
}
.download__mock-window {
  width: 100%;
  aspect-ratio: 16 / 10;
  border-radius: 18px;
  padding: 8px;
  background: linear-gradient(180deg, #D8E0EA 0%, #C2CFDC 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.55),
    0 24px 56px -16px rgba(35,60,90,0.28),
    0 8px 20px -8px rgba(35,60,90,0.18);
  display: flex;
  flex-direction: column;
}
[data-theme="dark"] .download__mock-window {
  background: linear-gradient(180deg, #2A3548 0%, #131A26 100%);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.10),
    0 24px 56px -16px rgba(0,0,0,0.32),
    0 8px 20px -8px rgba(0,0,0,0.22);
}
.download__mock-chrome {
  height: 22px;
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px;
  flex-shrink: 0;
}
.download__mock-chrome i {
  width: 11px;
  height: 11px;
  border-radius: 50%;
  display: block;
}
.download__mock-chrome i:nth-child(1) { background: #E5A091; }
.download__mock-chrome i:nth-child(2) { background: #E5C586; }
.download__mock-chrome i:nth-child(3) { background: #91C99B; }
.download__mock-screen {
  flex: 1;
  border-radius: 12px;
  background: linear-gradient(180deg, #EFF3F8 0%, #DDE4ED 100%);
  padding: 20px;
  display: grid;
  grid-template-columns: 120px 1fr;
  gap: 18px;
  overflow: hidden;
}
[data-theme="dark"] .download__mock-screen {
  background: linear-gradient(180deg, #1A2230 0%, #0F131B 100%);
}
.download__mock-side {
  display: flex;
  flex-direction: column;
  gap: 10px;
  border-right: 1px solid rgba(35,60,90,0.10);
  padding-right: 12px;
}
[data-theme="dark"] .download__mock-side {
  border-right-color: rgba(255,255,255,0.08);
}
.download__mock-side i {
  height: 10px;
  background: rgba(35,60,90,0.10);
  border-radius: 4px;
  display: block;
}
[data-theme="dark"] .download__mock-side i {
  background: rgba(255,255,255,0.10);
}
.download__mock-side i:first-child {
  background: var(--sk-accent);
  opacity: 0.85;
  width: 70%;
}
.download__mock-main {
  display: flex;
  flex-direction: column;
  gap: 8px;
  min-width: 0;
}
.download__mock-eyebrow {
  font-weight: var(--sk-weight-medium);
  font-size: 14px;
  letter-spacing: -0.01em;
  color: var(--sk-fg);
  margin-bottom: 2px;
}
.download__mock-meta-row {
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--sk-fg-muted);
  margin-bottom: 8px;
}
.download__mock-row {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 8px 12px;
  border-radius: 8px;
  background: rgba(255,255,255,0.55);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.6),
    0 1px 3px -1px rgba(35,60,90,0.06);
  font-size: 11px;
  color: var(--sk-fg);
}
[data-theme="dark"] .download__mock-row {
  background: rgba(255,255,255,0.06);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.10),
    0 1px 3px -1px rgba(0,0,0,0.20);
}
.download__mock-row .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--sk-accent);
  flex-shrink: 0;
}
.download__mock-row .line {
  flex: 1;
  height: 6px;
  border-radius: 3px;
  background: rgba(35,60,90,0.10);
}
[data-theme="dark"] .download__mock-row .line {
  background: rgba(255,255,255,0.10);
}
.download__mock-row .meta {
  font-size: 10px;
  letter-spacing: 0.04em;
  color: var(--sk-fg-subtle);
  font-variant-numeric: tabular-nums;
  flex-shrink: 0;
}
.download__mock-row--accent {
  background: rgba(166,211,230,0.32);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.7),
    0 2px 6px -2px rgba(166,211,230,0.40);
}
[data-theme="dark"] .download__mock-row--accent {
  background: rgba(166,211,230,0.18);
  box-shadow:
    inset 0 1px 0 rgba(255,255,255,0.14),
    0 2px 6px -2px rgba(166,211,230,0.30);
}
.download__cards {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 24px;
  max-width: 920px;
  margin: 0 auto;
}
.download-card {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  padding: 40px 36px 36px;
  border-radius: var(--sk-radius-lg);
  background: var(--sk-glass-bg);
  -webkit-backdrop-filter: var(--sk-glass-blur);
  backdrop-filter: var(--sk-glass-blur);
  border: var(--sk-glass-border);
  box-shadow: var(--sk-glass-shadow);
  text-decoration: none;
  color: inherit;
  transition:
    transform 360ms var(--sk-ease-flow),
    background 360ms var(--sk-ease-flow),
    border-color 360ms var(--sk-ease-flow),
    box-shadow 360ms var(--sk-ease-flow);
  position: relative;
}
.download-card:hover {
  /* Unified card hover — translateY(-2px) + rim only, matches every other surface. */
  transform: translateY(-2px);
  border: var(--sk-glass-border-hover);
  box-shadow: var(--sk-glass-shadow-hover);
}
/* The accent border + halo is enough signal; the textual "For your system"
   badge was removed (2026-05-15) — recommendations should whisper, not label. */
.download-card[data-recommended="true"] {
  border-color: var(--sk-accent);
  box-shadow: 0 0 0 1px var(--sk-accent-glow), 0 24px 60px rgba(166,211,230,0.18);
}
.download-card__icon {
  width: 52px;
  height: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 28px;
  color: var(--sk-fg);
}
.download-card__platform {
  font-size: 14px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--sk-fg-subtle);
  margin-bottom: 8px;
}
.download-card__name {
  font-weight: var(--sk-weight-semibold);
  font-size: 24px;
  letter-spacing: -0.01em;
  color: var(--sk-fg);
  margin-bottom: 14px;
}
.download-card__meta {
  font-size: 14px;
  color: var(--sk-fg-muted);
  margin-bottom: 32px;
  display: flex;
  gap: 8px;
}
.download-card__meta .dot-sep { opacity: 0.4; }
.download-card__cta {
  margin-top: auto;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 15px;
  font-weight: var(--sk-weight-medium);
  color: var(--sk-accent);
}
.download-card__cta svg { transition: transform 240ms var(--sk-ease-flow); }
.download-card:hover .download-card__cta svg { transform: translateY(2px); }

/* ---------- Mobile companion app cards (iOS / Android) ----------
   A second tier below the desktop downloads — same glass recipe, compact
   horizontal layout, no version meta. Both link out to the platform's
   official store. */
.download__cards--mobile {
  margin-top: 24px;
}
.download-card--mobile {
  flex-direction: row;
  align-items: center;
  gap: 18px;
  padding: 18px 22px;
}
.download-card--mobile .download-card__icon {
  width: 40px;
  height: 40px;
  margin-bottom: 0;
  flex-shrink: 0;
}
.download-card--mobile .download-card__body {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.download-card--mobile .download-card__platform {
  font-size: 11px;
  letter-spacing: 0.22em;
  margin-bottom: 0;
}
.download-card--mobile .download-card__name {
  font-size: 16px;
  font-weight: var(--sk-weight-medium);
  letter-spacing: -0.005em;
  margin-bottom: 0;
}
.download-card__external {
  color: var(--sk-fg-subtle);
  flex-shrink: 0;
  transition: transform 240ms var(--sk-ease-flow), color 240ms var(--sk-ease-flow);
}
.download-card--mobile:hover .download-card__external {
  color: var(--sk-fg);
  transform: translate(2px, -2px);
}

.download__notes {
  text-align: center;
  margin: 48px auto 0;
  font-size: 13px; /* legal disclaimer — kept smaller intentionally */
  color: var(--sk-fg-subtle);
  max-width: 720px;
  line-height: 1.6;
}
@media (max-width: 720px) {
  .download { padding: 80px 20px; }
  .download__cards { grid-template-columns: 1fr; }
  .download-card { padding: 32px 28px 28px; }
  /* Mobile cards stay compact even on narrow screens — overrides the
     base .download-card padding bump above. */
  .download-card--mobile { padding: 16px 20px; }
}
