@import url('/fonts/fonts.css');

/* ============================================================================
   KLINGATLAN — design system
   Aesthetic: "luminous glass". A warm bone ground lit by a slow aurora mesh,
   with genuinely translucent frosted panels floating above it. Editorial serif
   (Fraunces, variable optical size) against a warm geometric sans (Figtree).
   Accent is brass — Budapest ironwork, not the usual tech blue.
   ========================================================================== */

:root {
  /* ── ground ─────────────────────────────────────────────────────────── */
  --bone:        #F4F1E9;
  /* Same colour as --bone, as channels — needed wherever the ground has to be
     laid down at a partial alpha (the header scroll-edge scrim). */
  --bone-rgb:    244, 241, 233;
  --bone-deep:   #E9E4D8;
  --paper:       #FBF9F5;

  /* ── ink ────────────────────────────────────────────────────────────── */
  --ink:         #14171A;
  --ink-2:       #3B4147;
  --ink-3:       #666D73;
  --ink-4:       #9AA0A6;

  /* ── accents ────────────────────────────────────────────────────────── */
  --brass:       #A87C3F;
  --brass-lit:   #C89A4E;
  --brass-glow:  rgba(200, 154, 78, 0.28);
  --forest:      #24453B;
  --clay:        #B4553C;

  /* ── liquid glass ───────────────────────────────────────────────────────
     No hard border. The edge is light: a specular rim that is bright where a
     light source would catch it (top-left) and fades to nothing at the bottom,
     so the panel reads as a lens rather than a white-outlined box. */
  --glass-bg:     linear-gradient(150deg, rgba(255,255,255,0.62) 0%, rgba(255,255,255,0.40) 48%, rgba(255,255,255,0.30) 100%);
  --glass-bg-2:   linear-gradient(150deg, rgba(255,255,255,0.46), rgba(255,255,255,0.24));
  --glass-blur:   saturate(190%) blur(30px);
  --glass-blur-2: saturate(160%) blur(20px);

  /* Specular rim, drawn as inset shadows so it can vary around the shape. */
  --glass-rim: inset 0 1px 0.5px rgba(255,255,255,0.92),
               inset 1px 0 0.5px rgba(255,255,255,0.45),
               inset -1px 0 0.5px rgba(255,255,255,0.30),
               inset 0 -1px 0.5px rgba(255,255,255,0.18);
  --glass-depth:      0 1px 2px rgba(20,23,26,0.035),
                      0 8px 24px -12px rgba(20,23,26,0.16),
                      0 24px 56px -24px rgba(20,23,26,0.22);
  --glass-depth-lift: 0 2px 4px rgba(20,23,26,0.045),
                      0 14px 34px -14px rgba(20,23,26,0.20),
                      0 40px 80px -28px rgba(20,23,26,0.30);
  --glass-shadow:      var(--glass-rim), var(--glass-depth);
  --glass-shadow-lift: var(--glass-rim), var(--glass-depth-lift);

  /* ── type ───────────────────────────────────────────────────────────── */
  --display: 'Fraunces', 'Iowan Old Style', Georgia, serif;
  --sans:    'Figtree', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;

  /* ── rhythm ─────────────────────────────────────────────────────────── */
  --r-sm: 16px;
  --r-md: 22px;
  --r-lg: 32px;
  --r-xl: 44px;
  --r-pill: 999px;
  --gut:  clamp(18px, 4vw, 44px);
  --maxw: 1280px;

  --ease:      cubic-bezier(0.22, 0.8, 0.25, 1);
  --ease-out:  cubic-bezier(0.16, 1, 0.3, 1);
  /* A small, deliberate overshoot for things that SNAP into a slot — a segmented
     thumb, a sheet detent. Apple's controls settle rather than stop dead; the
     overshoot is kept under 8% so it reads as weight, not as bounce. */
  --ease-spring: cubic-bezier(0.34, 1.32, 0.48, 1);
  --t-fast: 0.18s;   /* state change on a control the finger is already on   */
  --t-base: 0.3s;    /* the default: colour, opacity, small transforms       */
  --t-slow: 0.44s;   /* something travelling a distance: thumbs, sheets      */

  /* -- semantic surfaces ---------------------------------------------------
     Everything that used to be a bare rgba(255,255,255,..) or rgba(20,23,26,..)
     lives here instead. Glass is built from two families -- light lifted ON the
     panel (specular) and ink dropped BEHIND it (shadow/hairline) -- and in dark
     mode those do not simply invert: the speculars get much weaker (a 62% white
     rim on a dark panel is a headlight) while the shadows get stronger and
     closer to black. Naming them is what lets one dark block retheme the whole
     site instead of 271 scattered edits. */
  --surface-1:     rgba(255,255,255,0.50);  /* quiet chip / inset field     */
  --surface-2:     rgba(255,255,255,0.72);  /* hover                        */
  --surface-3:     rgba(255,255,255,0.90);  /* active pill, popover, menu   */
  --surface-solid: #FFFFFF;
  --spec-strong:   rgba(255,255,255,0.92);  /* top rim, where light catches */
  --spec-mid:      rgba(255,255,255,0.45);
  --spec-soft:     rgba(255,255,255,0.18);
  --sheen-1:       rgba(255,255,255,0.55);  /* raking corner highlight      */
  --sheen-2:       rgba(255,255,255,0.14);
  --hairline:      rgba(20,23,26,0.09);
  --hairline-2:    rgba(20,23,26,0.055);
  --tint-ink:      rgba(20,23,26,0.05);     /* pressed / selected wash      */
  --shadow-rgb:    20, 23, 26;
  --grain-blend:   multiply;
  --grain-opacity: 0.35;
  --aurora-o:      1;

  /* A "filled" control -- the selected segment, the active pill, the price pin.
     In light it is an ink slab with bone text. In dark it must INVERT rather
     than darken: a near-black pill on a near-black ground disappears, so the
     fill goes light and the label goes dark. Same affordance, opposite ink. */
  --fill-1:  #14171A;
  --fill-2:  #262B31;
  --fill-fg: #F4F1E9;
  /* Status text on a tinted wash. The wash stays; the text has to flip. */
  --ok-fg:   #1B342C;
  --err-fg:  #7C3320;
  /* Second stop of the panel gradient (light cream / lifted charcoal). */
  --panel-2: #F1ECE2;
  --chip-brass-fg: #6E4E1C;
  /* Brass used as TEXT. --brass measures 3.29:1 on bone — right for a fill,
     under AA for 12.6px small caps. Fills keep --brass; type uses this. */
  --brass-ink: #8A6428;

  color-scheme: light;
}

/* -- dark ------------------------------------------------------------------
   Not an inversion -- the same room at night. The ground keeps the bone's
   warmth rather than going blue-grey, the aurora drops to an ember instead of a
   wash, and brass steps up a stop because gold needs more light to read as
   metal on a dark field. Text tops out at a warm off-white, never #fff: pure
   white on near-black buzzes, and this face is a serif.

   The token body is emitted TWICE because vanilla CSS cannot share a
   declaration block across a media-query boundary, and the two cases are
   genuinely different selectors:
     · inside the media query  -> "follow the OS", unless the reader forced light
     · outside it              -> the reader forced dark, whatever the OS says
   Both blocks are generated from one source; if you edit one, edit the other.

   `data-theme` is stamped SERVER-SIDE from a cookie so an explicit choice is
   correct on the very first frame: a strict `script-src 'self'` leaves no room
   for the usual inline anti-flash snippet, and a deferred script would repaint
   the whole page a beat after it appears. */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme='light']) {
  color-scheme: dark;

      --bone:        #101311;
      --bone-rgb:    16, 19, 17;
      --bone-deep:   #0A0C0B;
      --paper:       #171B18;

      --ink:         #F2EFE7;
      --ink-2:       #C7C4BA;
      --ink-3:       #A09D94;
      --ink-4:       #8A877E;

      --brass:       #D2A55C;
      --brass-lit:   #E8C583;
      --brass-glow:  rgba(210,165,92,0.30);
      --forest:      #5E9C86;
      --clay:        #E08768;

      /* Frosted DARK glass: a white film thin enough to stay a film, over a
         panel that is itself slightly lighter than the ground so it reads as
         lifted even where backdrop-filter is unavailable. */
      --glass-bg:     linear-gradient(150deg, rgba(255,255,255,0.10) 0%, rgba(255,255,255,0.055) 48%, rgba(255,255,255,0.035) 100%);
      --glass-bg-2:   linear-gradient(150deg, rgba(255,255,255,0.075), rgba(255,255,255,0.03));
      --glass-blur:   saturate(135%) brightness(1.08) blur(30px);
      --glass-blur-2: saturate(125%) brightness(1.05) blur(20px);

      --glass-rim: inset 0 1px 0.5px rgba(255,255,255,0.16),
                   inset 1px 0 0.5px rgba(255,255,255,0.07),
                   inset -1px 0 0.5px rgba(255,255,255,0.05),
                   inset 0 -1px 0.5px rgba(255,255,255,0.03);
      --glass-depth:      0 1px 2px rgba(0,0,0,0.40),
                          0 8px 24px -12px rgba(0,0,0,0.60),
                          0 24px 56px -24px rgba(0,0,0,0.70);
      --glass-depth-lift: 0 2px 4px rgba(0,0,0,0.46),
                          0 14px 34px -14px rgba(0,0,0,0.66),
                          0 40px 80px -28px rgba(0,0,0,0.78);

      --surface-1:     rgba(255,255,255,0.07);
      --surface-2:     rgba(255,255,255,0.13);
      --surface-3:     rgba(255,255,255,0.19);
      /* "Solid" cannot be #fff here; it is the lifted panel colour. */
      --surface-solid: #23271F;
      --spec-strong:   rgba(255,255,255,0.17);
      --spec-mid:      rgba(255,255,255,0.08);
      --spec-soft:     rgba(255,255,255,0.04);
      --sheen-1:       rgba(255,255,255,0.10);
      --sheen-2:       rgba(255,255,255,0.03);
      /* Hairlines on a dark ground read as light, not ink. */
      --hairline:      rgba(255,255,255,0.11);
      --hairline-2:    rgba(255,255,255,0.06);
      --tint-ink:      rgba(255,255,255,0.07);
      --shadow-rgb:    0, 0, 0;
      /* multiply on a near-black ground turns the grain into mud and eats the
         aurora; soft-light keeps the tooth and lets the ember through. */
      --grain-blend:   soft-light;
      --grain-opacity: 0.22;
      --aurora-o:      0.62;

      --fill-1:  #F2EFE7;
      --fill-2:  #DCD8CE;
      --fill-fg: #101311;
      --ok-fg:   #7FC0A6;
      --err-fg:  #E8927A;
      --panel-2: #1C201B;
      --chip-brass-fg: #E8C583;
      --brass-ink: #E8C583;
  }
}

/* Forced dark -- keep in sync with the block above. */
:root[data-theme='dark'] {
color-scheme: dark;

    --bone:        #101311;
    --bone-rgb:    16, 19, 17;
    --bone-deep:   #0A0C0B;
    --paper:       #171B18;

    --ink:         #F2EFE7;
    --ink-2:       #C7C4BA;
    --ink-3:       #A09D94;
    --ink-4:       #8A877E;

    --brass:       #D2A55C;
    --brass-lit:   #E8C583;
    --brass-glow:  rgba(210,165,92,0.30);
    --forest:      #5E9C86;
    --clay:        #E08768;

    /* Frosted DARK glass: a white film thin enough to stay a film, over a
       panel that is itself slightly lighter than the ground so it reads as
       lifted even where backdrop-filter is unavailable. */
    --glass-bg:     linear-gradient(150deg, rgba(255,255,255,0.10) 0%, rgba(255,255,255,0.055) 48%, rgba(255,255,255,0.035) 100%);
    --glass-bg-2:   linear-gradient(150deg, rgba(255,255,255,0.075), rgba(255,255,255,0.03));
    --glass-blur:   saturate(135%) brightness(1.08) blur(30px);
    --glass-blur-2: saturate(125%) brightness(1.05) blur(20px);

    --glass-rim: inset 0 1px 0.5px rgba(255,255,255,0.16),
                 inset 1px 0 0.5px rgba(255,255,255,0.07),
                 inset -1px 0 0.5px rgba(255,255,255,0.05),
                 inset 0 -1px 0.5px rgba(255,255,255,0.03);
    --glass-depth:      0 1px 2px rgba(0,0,0,0.40),
                        0 8px 24px -12px rgba(0,0,0,0.60),
                        0 24px 56px -24px rgba(0,0,0,0.70);
    --glass-depth-lift: 0 2px 4px rgba(0,0,0,0.46),
                        0 14px 34px -14px rgba(0,0,0,0.66),
                        0 40px 80px -28px rgba(0,0,0,0.78);

    --surface-1:     rgba(255,255,255,0.07);
    --surface-2:     rgba(255,255,255,0.13);
    --surface-3:     rgba(255,255,255,0.19);
    /* "Solid" cannot be #fff here; it is the lifted panel colour. */
    --surface-solid: #23271F;
    --spec-strong:   rgba(255,255,255,0.17);
    --spec-mid:      rgba(255,255,255,0.08);
    --spec-soft:     rgba(255,255,255,0.04);
    --sheen-1:       rgba(255,255,255,0.10);
    --sheen-2:       rgba(255,255,255,0.03);
    /* Hairlines on a dark ground read as light, not ink. */
    --hairline:      rgba(255,255,255,0.11);
    --hairline-2:    rgba(255,255,255,0.06);
    --tint-ink:      rgba(255,255,255,0.07);
    --shadow-rgb:    0, 0, 0;
    /* multiply on a near-black ground turns the grain into mud and eats the
       aurora; soft-light keeps the tooth and lets the ember through. */
    --grain-blend:   soft-light;
    --grain-opacity: 0.22;
    --aurora-o:      0.62;

    --fill-1:  #F2EFE7;
    --fill-2:  #DCD8CE;
    --fill-fg: #101311;
    --ok-fg:   #7FC0A6;
    --err-fg:  #E8927A;
    --panel-2: #1C201B;
    --chip-brass-fg: #E8C583;
    --brass-ink: #E8C583;
}


/* ── reset ─────────────────────────────────────────────────────────────── */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
}

body {
  font-family: var(--sans);
  font-size: 16.5px;
  line-height: 1.62;
  color: var(--ink-2);
  background: var(--bone);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  min-height: 100vh;
  overflow-x: hidden;
}

img, svg, video { display: block; max-width: 100%; }
button, input, select, textarea { font: inherit; color: inherit; }
/* Bare <button> keeps the UA's `border: 2px outset ButtonBorder` unless something
   resets it. Every styled control here happens to override `border` — except the
   two inside .rbtn-group, where the black UA border was clipped by the group's
   overflow:hidden and read as a cut-off frame around the map's +/− pill. Reset it
   once, at the source, rather than patching each control that forgets. */
button { border: 0; background: none; }
a { color: inherit; text-decoration: none; }

/* ── the aurora ground ─────────────────────────────────────────────────
   Fixed, behind everything, slowly drifting. This is what the frosted
   panels actually sample — without it the glass has nothing to refract. */
.aurora {
  position: fixed;
  inset: -20vmax;
  z-index: -2;
  pointer-events: none;
  background:
    radial-gradient(38vmax 34vmax at 12% 8%,  rgba(200,154,78,0.30), transparent 62%),
    radial-gradient(42vmax 38vmax at 88% 12%, rgba(36,69,59,0.22),  transparent 64%),
    radial-gradient(46vmax 40vmax at 72% 88%, rgba(180,85,60,0.16), transparent 66%),
    radial-gradient(40vmax 36vmax at 20% 82%, rgba(122,150,170,0.22), transparent 62%);
  filter: blur(12px);
  /* The mesh is a wash by day and an ember by night. */
  opacity: var(--aurora-o);
  animation: drift 44s var(--ease) infinite alternate;
}
@keyframes drift {
  0%   { transform: translate3d(0,0,0) scale(1); }
  50%  { transform: translate3d(2.5%, -2%, 0) scale(1.06); }
  100% { transform: translate3d(-2%, 2.5%, 0) scale(1.02); }
}

/* Fine grain — kills gradient banding and adds a printed-paper tooth. */
.grain {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  /* multiply on a near-black ground turns the tooth into mud and swallows
     the aurora; soft-light keeps it. Both are theme tokens. */
  opacity: var(--grain-opacity);
  mix-blend-mode: var(--grain-blend);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='180' height='180' filter='url(%23n)' opacity='0.16'/%3E%3C/svg%3E");
}

/* Anchor targets must clear the sticky header, or in-page links land with the
   heading hidden underneath it. */
:target, section[id], h2[id], h3[id] { scroll-margin-top: 96px; }

/* ── layout ────────────────────────────────────────────────────────────── */
.wrap { width: 100%; max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gut); }
.wrap-narrow { max-width: 880px; }

/* ── liquid glass primitives ───────────────────────────────────────────────
   Border-less by design: the rim is light (inset specular), not a stroke.
   A soft sheen sweeps the top-left, which is what makes it read as a lens. */
.glass, .glass-quiet {
  position: relative;
  border: 0;
  border-radius: var(--r-lg);
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow);
  isolation: isolate;
}
.glass-quiet {
  border-radius: var(--r-md);
  background: var(--glass-bg-2);
  -webkit-backdrop-filter: var(--glass-blur-2);
  backdrop-filter: var(--glass-blur-2);
  box-shadow: var(--glass-rim), 0 4px 16px -10px var(--tint-ink);
}

/* Sheen — a wide, very soft highlight raking across the top-left corner. */
.glass::before, .glass-quiet::before {
  content: '';
  position: absolute; inset: 0;
  border-radius: inherit;
  pointer-events: none;
  z-index: -1;
  background:
    radial-gradient(120% 80% at 8% -8%, var(--surface-1), transparent 58%),
    radial-gradient(80% 60% at 100% 106%, var(--spec-soft), transparent 62%);
}

/* Browsers without backdrop-filter must not get a transparent unreadable panel. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  /* The point of this fallback is an OPAQUE panel: with no blur behind it a
     translucent surface is just unreadable text over the aurora. --paper is
     the opaque elevated surface in both themes. */
  .glass, .glass-quiet { background: var(--paper); }
}

/* ── typography ────────────────────────────────────────────────────────── */
h1, h2, h3, h4, .display {
  font-family: var(--display);
  color: var(--ink);
  font-weight: 500;
  line-height: 1.06;
  letter-spacing: -0.018em;
  font-variation-settings: 'SOFT' 18, 'WONK' 1;
}
h1, .h1 {
  font-size: clamp(2.6rem, 6.4vw, 5.1rem);
  font-variation-settings: 'opsz' 130, 'SOFT' 22, 'WONK' 1;
  letter-spacing: -0.032em;
}
h2, .h2 { font-size: clamp(1.9rem, 3.8vw, 3rem); font-variation-settings: 'opsz' 72, 'SOFT' 18; }
h3, .h3 { font-size: clamp(1.28rem, 2.1vw, 1.65rem); font-variation-settings: 'opsz' 36, 'SOFT' 14; }

.eyebrow {
  font-family: var(--sans);
  font-size: 0.735rem;
  font-weight: 700;
  letter-spacing: 0.19em;
  text-transform: uppercase;
  color: var(--brass-ink);
}
.lede { font-size: clamp(1.04rem, 1.5vw, 1.22rem); color: var(--ink-2); line-height: 1.62; }
.muted { color: var(--ink-3); }
.tnum  { font-variant-numeric: tabular-nums; font-feature-settings: 'tnum' 1; }

/* Editorial price — the single loudest piece of type on a card. */
.price {
  font-family: var(--display);
  font-weight: 600;
  color: var(--ink);
  font-variation-settings: 'opsz' 60, 'SOFT' 10, 'WONK' 0;
  letter-spacing: -0.028em;
  font-variant-numeric: tabular-nums;
}

/* ── buttons ───────────────────────────────────────────────────────────── */
.btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.55em;
  padding: 0.86em 1.5em;
  border-radius: 999px;
  border: 1px solid transparent;
  font-family: var(--sans);
  font-weight: 600;
  font-size: 0.95rem;
  letter-spacing: -0.005em;
  cursor: pointer;
  text-align: center;
  transition: transform 0.42s var(--ease-out), box-shadow 0.42s var(--ease-out),
              background-color 0.28s var(--ease), color 0.28s var(--ease);
  will-change: transform;
}
.btn:active { transform: scale(0.975); }
.btn:focus-visible { outline: 2.5px solid var(--brass); outline-offset: 3px; }

.btn-primary {
  background: linear-gradient(168deg, var(--fill-1) 0%, var(--fill-2) 100%);
  color: var(--fill-fg);
  box-shadow: 0 1px 0 var(--spec-soft) inset, 0 10px 26px -10px rgba(var(--shadow-rgb),0.62);
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 1px 0 var(--spec-soft) inset, 0 18px 38px -12px rgba(var(--shadow-rgb),0.55); }

.btn-brass {
  background: linear-gradient(168deg, var(--brass-lit) 0%, var(--brass) 100%);
  color: #24180A;
  box-shadow: 0 1px 0 var(--spec-mid) inset, 0 10px 26px -10px var(--brass-glow);
}
.btn-brass:hover { transform: translateY(-2px); box-shadow: 0 1px 0 var(--spec-mid) inset, 0 18px 40px -12px var(--brass-glow); }

.btn-glass {
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur);
  backdrop-filter: var(--glass-blur);
  border-color: transparent;
  color: var(--ink);
  box-shadow: var(--glass-shadow);
}
.btn-glass:hover { transform: translateY(-2px); box-shadow: var(--glass-shadow-lift); }

.btn-ghost { background: transparent; border-color: var(--tint-ink); color: var(--ink); }
.btn-ghost:hover { background: var(--surface-1); border-color: rgba(var(--shadow-rgb),0.28); }
.btn-sm { padding: 0.6em 1.1em; font-size: 0.86rem; }

/* ── chips / pills ─────────────────────────────────────────────────────── */
.chip {
  display: inline-flex; align-items: center; gap: 0.42em;
  padding: 0.4em 0.86em;
  border-radius: 999px;
  font-size: 0.8rem; font-weight: 600;
  background: var(--surface-1);
  border: 0;
  color: var(--ink-2);
  box-shadow: inset 0 1px 0 var(--surface-2), 0 1px 3px var(--hairline-2);
  -webkit-backdrop-filter: saturate(170%) blur(12px); backdrop-filter: saturate(170%) blur(12px);
  white-space: nowrap;
}
.chip-brass { background: rgba(200,154,78,0.22); color: var(--chip-brass-fg); box-shadow: inset 0 1px 0 var(--surface-1), 0 1px 3px rgba(168,124,63,0.14); }
.chip-forest{ background: rgba(36,69,59,0.16);  color: var(--ok-fg); box-shadow: inset 0 1px 0 var(--spec-mid), 0 1px 3px rgba(36,69,59,0.14); }

/* ── blur-up images ────────────────────────────────────────────────────
   The LQIP data-URI sits as the element background; the real image fades in
   over it once decoded. Prevents both layout shift and a flash of empty box. */
.ph { position: relative; overflow: hidden; background: var(--bone-deep) center/cover no-repeat; }
.ph > img {
  width: 100%; height: 100%; object-fit: cover;
  opacity: 0;
  transform: scale(1.035);
  transition: opacity 0.85s var(--ease-out), transform 1.5s var(--ease-out);
}
.ph > img.loaded { opacity: 1; transform: scale(1); }

/* ── scroll reveal ─────────────────────────────────────────────────────── */
.rise { opacity: 0; transform: translateY(24px); }
.rise.in {
  opacity: 1; transform: none;
  transition: opacity 0.85s var(--ease-out), transform 0.95s var(--ease-out);
}
@media (prefers-reduced-motion: reduce) { .rise { opacity: 1; transform: none; } }

/* ── header ────────────────────────────────────────────────────────────── */
.site-head {
  position: sticky; top: 0; z-index: 60;
  padding: 10px 0;
  transition: padding 0.45s var(--ease);
}

/* Scroll-edge scrim.

   The bar is a pill inset by --gut with 10px of clear air above and below it,
   so scrolling content passed through those gaps completely unobscured and
   through the pill itself at only 30–62% white — a half-line of the next
   section stayed legible across the top of every page and read exactly like
   text sliced in half. Blurring harder is not the fix: the gaps have no glass
   over them at all.

   So put a full-bleed layer behind the pill that dissolves the page as it
   approaches the top edge — the same "scroll edge effect" iOS uses. It is
   pinned to the viewport rather than the header box because the sticky header
   is only as tall as its pill, and it fades to transparent at the bottom so
   the boundary is never a visible hard line.

   Only while scrolled: at rest the hero is meant to run under the glass. */
.site-head::before {
  content: '';
  position: fixed;
  inset: 0 0 auto 0;
  /* An explicit height, NOT a percentage: this element is `fixed`, so a
     percentage resolves against the viewport (the initial containing block)
     and a `100%` scrim washes out the entire screen. The band is the pill
     (~62px) + its 10px of air + a fade tail below it. */
  height: 124px;
  pointer-events: none;
  z-index: -1;
  -webkit-backdrop-filter: saturate(150%) blur(16px);
  backdrop-filter: saturate(150%) blur(16px);
  background: linear-gradient(to bottom,
    rgba(var(--bone-rgb),0.94) 0%,
    rgba(var(--bone-rgb),0.80) 46%,
    rgba(var(--bone-rgb),0.42) 76%,
    rgba(var(--bone-rgb),0) 100%);
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 62%, transparent 100%);
  mask-image: linear-gradient(to bottom, #000 0%, #000 62%, transparent 100%);
  opacity: 0;
  transition: opacity 0.34s var(--ease);
}
.site-head.scrolled::before { opacity: 1; }

/* Where backdrop-filter is unavailable the scrim must still hide the page. */
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
  .site-head::before {
    background: linear-gradient(to bottom,
      rgba(var(--bone-rgb),0.99) 0%, rgba(var(--bone-rgb),0.96) 60%, rgba(var(--bone-rgb),0) 100%);
  }
}
.site-head .bar {
  display: flex; align-items: center; gap: 18px;
  padding: 11px 12px 11px 20px;
  border-radius: 999px;
  background: var(--glass-bg);
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  border: 0;
  box-shadow: var(--glass-shadow);
  transition: box-shadow 0.45s var(--ease), background-color 0.45s var(--ease);
}
.site-head.scrolled .bar { box-shadow: var(--glass-shadow-lift); }

.brand { display: inline-flex; align-items: baseline; gap: 0; font-family: var(--display); font-size: 1.32rem; font-weight: 600; color: var(--ink); letter-spacing: -0.03em; font-variation-settings: 'opsz' 40, 'SOFT' 20, 'WONK' 1; }
.brand em { font-style: normal; color: var(--brass); }

.nav { display: flex; align-items: center; gap: 4px; margin-left: auto; }
.nav a {
  position: relative;
  padding: 0.5em 0.92em; border-radius: 999px;
  font-size: 0.925rem; font-weight: 550; color: var(--ink-2);
  transition: color 0.26s var(--ease), background-color 0.26s var(--ease);
}
.nav a:hover { color: var(--ink); background: var(--surface-1); }
.nav a[aria-current='page'] { color: var(--ink); background: var(--surface-2); box-shadow: 0 1px 2px var(--hairline-2); }

/* ── grouped nav item ──────────────────────────────────────────────────────
   Click, not hover: a hover menu is unreachable by keyboard and fires by
   accident on a touch laptop. Escape and an outside click close it. */
.nav-group { position: relative; }
.nav-groupbtn {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 0.5em 0.92em; border-radius: 999px;
  font-size: 0.925rem; font-weight: 550; color: var(--ink-2);
  background: none; border: 0; cursor: pointer;
  transition: color var(--t-base) var(--ease), background-color var(--t-base) var(--ease);
}
.nav-groupbtn:hover { color: var(--ink); background: var(--surface-1); }
.nav-groupbtn svg { transition: transform var(--t-base) var(--ease-out); }
.nav-groupbtn[aria-expanded='true'] { color: var(--ink); background: var(--surface-1); }
.nav-groupbtn[aria-expanded='true'] svg { transform: rotate(180deg); }
.nav-group.is-current .nav-groupbtn {
  color: var(--ink); background: var(--surface-2); box-shadow: 0 1px 2px var(--hairline-2);
}
.nav-menu {
  position: absolute; top: calc(100% + 9px); left: 50%;
  width: 280px; padding: 7px;
  border-radius: var(--r-md);
  /* A menu must stay legible over whatever it covers — here, a photographic
     hero. The gradient alone (0.90 -> 0.72 white) let the picture through and
     ate a whole label. Solid paper underneath, gradient on top: the sheen
     survives, the text stops fighting the background. */
  background-color: var(--paper);
  background-image: linear-gradient(150deg, var(--surface-3), var(--surface-2));
  -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
  box-shadow: var(--glass-shadow-lift);
  transform: translate(-50%, -6px) scale(0.97); transform-origin: top center;
  opacity: 0; visibility: hidden; pointer-events: none;
  /* visibility is delayed only as long as the fade actually lasts — any longer
     and the menu stays in the tab order after it has visually gone. */
  transition: opacity var(--t-base) var(--ease-out), transform var(--t-base) var(--ease-out),
              visibility 0s linear var(--t-base);
  z-index: 80;
}
.nav-group.open .nav-menu {
  opacity: 1; visibility: visible; pointer-events: auto;
  transform: translate(-50%, 0) scale(1);
  transition: opacity var(--t-base) var(--ease-out), transform var(--t-slow) var(--ease-spring),
              visibility 0s;
}
.nav-menu a {
  display: block; padding: 0.62em 0.8em; border-radius: var(--r-sm);
  font-size: 0.94rem;
}
.nav-menu-t { display: block; font-weight: 600; color: var(--ink-2); }
.nav-menu a:hover .nav-menu-t, .nav-menu a[aria-current='page'] .nav-menu-t { color: var(--ink); }
.nav-menu-d { display: block; margin-top: 1px; font-size: 0.79rem; line-height: 1.4; color: var(--ink-3); }

.nav-toggle { display: none; }

/* ── language pill ───────────────────────────────────────────────────────
   Three plain links, no JavaScript: the switcher has to work on first paint,
   before app.js runs, and be followable by a crawler (each language is a
   distinct, indexable URL). Visual order is brand → nav → pill; the pill sits
   after the brand in the DOM so that on mobile it stays next to the burger. */
.site-head .brand { order: 1; }
.site-head .nav { order: 2; }
.site-head .bar-right { order: 3; display: flex; align-items: center; gap: 8px; }

.lang-pill {
  display: inline-flex; align-items: center; gap: 2px;
  padding: 3px; border-radius: 999px;
  background: var(--surface-1);
  box-shadow: inset 0 1px 0 var(--surface-2), 0 1px 2px var(--hairline-2);
}
.lang-opt {
  display: inline-flex; align-items: center; justify-content: center;
  min-width: 34px; height: 28px; padding: 0 0.5em;
  border-radius: 999px;
  font-size: 0.74rem; font-weight: 650; letter-spacing: 0.05em;
  color: var(--ink-3);
  transition: color 0.24s var(--ease), background-color 0.24s var(--ease);
}
.lang-opt:hover { color: var(--ink); background: var(--surface-2); }
.lang-opt.on {
  color: var(--ink); background: var(--surface-solid);
  box-shadow: 0 1px 2px var(--hairline);
}
.lang-opt:focus-visible { outline: 2.5px solid var(--brass); outline-offset: 2px; }


/* ── mobile nav ──────────────────────────────────────────────────────────
   The panel is anchored to .bar ON PURPOSE.

   .bar carries a backdrop-filter, and per Filter Effects a non-none
   backdrop-filter makes an element the containing block for its absolutely
   AND fixed positioned descendants. The panel used to be `position: fixed;
   inset: auto 12px 12px 12px`, expecting the viewport — it resolved against
   the ~62px header pill instead, so a 420px-tall menu grew upward and its top
   sat 358px ABOVE the screen. Every link was unreachable on every phone.

   Rather than fight that, anchor to the bar deliberately: the menu becomes a
   dropdown hanging off its own trigger, which is also the honest affordance.
   `position: relative` on .bar keeps the anchor even where backdrop-filter is
   unsupported (there the filter would not establish a containing block, and
   the panel would escape to the sticky header). */
@media (max-width: 980px) {
  .site-head .bar { position: relative; }

  .site-head .bar-right { margin-left: auto; }

  .nav-toggle {
    display: inline-flex; align-items: center; justify-content: center;
    /* 44×44 is Apple's minimum comfortable target; the visual pill stays 42. */
    width: 44px; height: 44px; border-radius: 999px;
    background: var(--surface-1); border: 0;
    cursor: pointer;
    transition: background-color 0.24s var(--ease);
  }
  .nav-toggle:active { background: var(--surface-3); }

  .nav {
    position: absolute;
    top: calc(100% + 10px); left: 0; right: 0;
    margin: 0;
    flex-direction: column; align-items: stretch; gap: 2px;
    padding: 8px;
    border-radius: var(--r-lg);
    /* A menu must stay legible over whatever it covers — here, a photographic
     hero. The gradient alone (0.90 -> 0.72 white) let the picture through and
     ate a whole label. Solid paper underneath, gradient on top: the sheen
     survives, the text stops fighting the background. */
  background-color: var(--paper);
  background-image: linear-gradient(150deg, var(--surface-3), var(--surface-2));
    -webkit-backdrop-filter: var(--glass-blur); backdrop-filter: var(--glass-blur);
    border: 0;
    box-shadow: var(--glass-shadow-lift);
    /* Seven links do not fit a landscape phone (393px tall), so the panel
       scrolls itself rather than running off the bottom. */
    max-height: calc(100vh - 96px);
    max-height: calc(100dvh - 96px);
    overflow-y: auto;
    overscroll-behavior: contain;
    -webkit-overflow-scrolling: touch;
    transform: translateY(-8px) scale(0.985);
    transform-origin: top center;
    /* visibility (not just opacity) — otherwise the closed menu's links stay
       in the tab order and VoiceOver reads a menu the user cannot see. */
    opacity: 0; visibility: hidden; pointer-events: none;
    transition: opacity 0.26s var(--ease-out), transform 0.3s var(--ease-out),
                visibility 0s linear 0.3s;
    z-index: 70;
  }
  .nav.open {
    opacity: 1; transform: none; visibility: visible; pointer-events: auto;
    transition: opacity 0.26s var(--ease-out), transform 0.3s var(--ease-out),
                visibility 0s;
  }
  .nav a {
    display: flex; align-items: center;
    min-height: 46px;
    padding: 0.72em 0.95em; font-size: 1.02rem;
    border-radius: var(--r-sm);
  }
  .nav a:active { background: var(--surface-3); }

  /* In the sheet the group flattens. A disclosure inside a menu is a second
     thing to open before you can reach the thing you wanted; the whole point of
     the group is to save width, and inside a full-width sheet there is none to
     save. */
  .nav-group { position: static; }
  .nav-groupbtn { display: none; }
  .nav-menu {
    position: static; width: auto; padding: 0;
    background: none; box-shadow: none;
    -webkit-backdrop-filter: none; backdrop-filter: none;
    transform: none; opacity: 1; visibility: visible; pointer-events: auto;
    transition: none;
    display: flex; flex-direction: column; gap: 2px;
  }
  .nav-menu a {
    min-height: 46px; padding: 0.55em 0.95em;
    display: flex; flex-direction: column; justify-content: center;
  }
  .nav-menu-t { font-size: 1.02rem; }
  .nav-menu-d { font-size: 0.8rem; }

  .lang-opt { min-width: 36px; height: 34px; font-size: 0.78rem; }
}

/* ── footer ────────────────────────────────────────────────────────────── */
.site-foot { margin-top: clamp(60px, 9vw, 120px); padding: clamp(38px, 6vw, 68px) 0 30px; border-top: 1px solid var(--hairline); }
.foot-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr; gap: 36px; }
@media (max-width: 760px) { .foot-grid { grid-template-columns: 1fr; gap: 26px; } }
.foot-grid a { color: var(--ink-3); font-size: 0.94rem; display: block; padding: 3px 0; transition: color 0.2s; }
.foot-grid a:hover { color: var(--brass); }
.foot-legal { margin-top: 34px; padding-top: 22px; border-top: 1px solid var(--hairline); font-size: 0.8rem; color: var(--ink-4); display: flex; flex-wrap: wrap; gap: 8px 22px; }

/* ── forms ─────────────────────────────────────────────────────────────── */
.field { display: flex; flex-direction: column; gap: 7px; }
.field > label { font-size: 0.83rem; font-weight: 650; color: var(--ink-2); letter-spacing: 0.005em; }
.field .hint { font-size: 0.78rem; color: var(--ink-4); }
.input, .select, .textarea {
  width: 100%;
  padding: 0.82em 1.02em;
  border-radius: var(--r-sm);
  border: 1px solid var(--hairline);
  background: var(--surface-1);
  box-shadow: inset 0 1px 0 var(--surface-2);
  color: var(--ink);
  font-size: 0.98rem;
  transition: border-color 0.24s var(--ease), box-shadow 0.24s var(--ease), background-color 0.24s var(--ease);
  -webkit-appearance: none; appearance: none;
}
.textarea { resize: vertical; min-height: 118px; line-height: 1.55; }
.select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1.5 6 6.5l5-5' stroke='%236B7278' stroke-width='1.8' fill='none' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right 1em center;
  padding-right: 2.6em;
}
.input:focus, .select:focus, .textarea:focus {
  outline: none;
  border-color: var(--brass);
  background: var(--surface-3);
  box-shadow: 0 0 0 3.5px var(--brass-glow);
}
.input:invalid:not(:placeholder-shown) { border-color: var(--clay); }

/* Honeypot — must be reachable by nothing and visible to no one. */
.hp { position: absolute !important; left: -9999px !important; width: 1px; height: 1px; opacity: 0; }

/* ── newsletter signup ─────────────────────────────────────────────────── */
.foot-nl {
  display: grid; grid-template-columns: 1.5fr 1fr; gap: 30px; align-items: start;
  padding-bottom: clamp(28px, 4vw, 40px); margin-bottom: clamp(28px, 4vw, 40px);
  border-bottom: 1px solid var(--hairline);
}
@media (max-width: 860px) { .foot-nl { grid-template-columns: 1fr; gap: 18px; } }
.nl-row { display: flex; gap: 8px; align-items: stretch; }
.nl-row .input { flex: 1 1 auto; min-width: 0; }
.nl-row .btn { flex: 0 0 auto; white-space: nowrap; }
@media (max-width: 420px) { .nl-row { flex-direction: column; } }
.nl-consent { margin-top: 10px; }
.nl-form .form-note:empty { display: none; }

/* ── utility ───────────────────────────────────────────────────────────── */
/* [hidden] is a UA style (display:none) and loses to any class that sets display
   — .field is display:flex, so conditional fields stayed visible. Make it win. */
[hidden] { display: none !important; }

.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0,0,0,0); white-space: nowrap; border: 0;
}
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  padding: 12px 20px; border-radius: 999px;
  background: var(--ink); color: var(--paper); font-weight: 600;
  transition: top 0.24s var(--ease);
}
.skip-link:focus { top: 12px; }
.stack   { display: flex; flex-direction: column; }
.row     { display: flex; align-items: center; }
.wrapf   { flex-wrap: wrap; }
.grow    { flex: 1 1 auto; }

/* ══ COMBOBOX ══════════════════════════════════════════════════════════════
   Liquid-glass replacement for <select>. The native element stays in the DOM
   (form source of truth) but is visually removed. */
.cb { position: relative; }
.cb-native {
  position: absolute !important; width: 1px; height: 1px;
  opacity: 0; pointer-events: none; clip: rect(0,0,0,0);
}
.cb-btn {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 0.82em 1.02em;
  border: 1px solid var(--hairline);
  border-radius: var(--r-sm);
  background: var(--surface-1);
  box-shadow: inset 0 1px 0 var(--surface-2);
  color: var(--ink-3);
  font-size: 0.98rem; text-align: left; cursor: pointer;
  transition: border-color 0.24s var(--ease), box-shadow 0.24s var(--ease), background-color 0.24s var(--ease);
}
.cb-btn.cb-set { color: var(--ink); font-weight: 550; }
.cb-btn:hover { background: var(--surface-2); }
.cb-btn:focus-visible { outline: none; border-color: var(--brass); box-shadow: 0 0 0 3.5px var(--brass-glow); }
.cb.open .cb-btn { border-color: var(--brass); box-shadow: 0 0 0 3.5px var(--brass-glow); background: var(--surface-3); }
.cb-val { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cb-caret { flex: 0 0 auto; color: var(--ink-4); transition: transform 0.32s var(--ease-out); }
.cb.open .cb-caret { transform: rotate(180deg); }

.cb-panel {
  position: absolute; z-index: 90; left: 0; right: 0; top: calc(100% + 8px);
  padding: 6px;
  border-radius: var(--r-md);
  background: linear-gradient(150deg, var(--surface-3), var(--surface-3));
  -webkit-backdrop-filter: saturate(200%) blur(34px); backdrop-filter: saturate(200%) blur(34px);
  box-shadow: var(--glass-rim), 0 20px 50px -18px rgba(var(--shadow-rgb),0.34);
  opacity: 0; transform: translateY(-6px) scale(0.985); pointer-events: none;
  transform-origin: top center;
  transition: opacity 0.24s var(--ease-out), transform 0.28s var(--ease-out);
}
.cb.open .cb-panel { opacity: 1; transform: none; pointer-events: auto; }
.cb.up .cb-panel { top: auto; bottom: calc(100% + 8px); transform-origin: bottom center; }

.cb-search-wrap { position: relative; display: flex; align-items: center; padding: 2px 2px 6px; }
.cb-search-wrap svg { position: absolute; left: 12px; color: var(--ink-4); pointer-events: none; }
.cb-search {
  width: 100%; padding: 0.6em 0.8em 0.6em 2.15em;
  border: 0; border-radius: var(--r-sm);
  background: var(--hairline-2);
  font-size: 0.92rem; color: var(--ink);
}
.cb-search:focus { outline: none; background: var(--hairline); }

.cb-list { list-style: none; margin: 0; padding: 0; max-height: 246px; overflow-y: auto; overscroll-behavior: contain; }
.cb-opt {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 0.6em 0.8em; border-radius: 12px;
  font-size: 0.94rem; color: var(--ink-2); cursor: pointer;
  transition: background-color 0.16s var(--ease), color 0.16s var(--ease);
}
.cb-opt.act { background: var(--hairline-2); color: var(--ink); }
.cb-opt.sel { color: var(--ink); font-weight: 600; }
.cb-opt.sel.act { background: rgba(200,154,78,0.2); }
.cb-tick { color: var(--brass); flex: 0 0 auto; }
.cb-empty { padding: 1.1em 0.8em; text-align: center; font-size: 0.88rem; color: var(--ink-4); }

@media (max-width: 700px) { .cb-list { max-height: 40vh; } }

/* ── mobile refinements ────────────────────────────────────────────────────
   Phone-only sizing corrections. Everything here is inside a max-width query
   so the desktop layout is byte-identical.

   Two rules drive all of it:
     · nothing a finger taps may be smaller than 44×44 (Apple HIG). Where the
       *visual* element is deliberately small, the hit area grows via an
       ::after overlay rather than the design inflating to match.
     · no text under 12px. Hungarian is a long-word language, so the answer to
       a cramped label is wrapping, not shrinking. */
@media (max-width: 760px) {

  /* 11.76px at 0.19em tracking was both hard to read and needlessly wide —
     the tracking is what pushed these onto two lines. Slightly larger, slightly
     tighter: same editorial voice, fewer wraps. */
  .eyebrow {
    font-size: 0.79rem;
    letter-spacing: 0.15em;
  }

  /* The language switcher measured 30×26. The pill is a segmented control and
     should not grow to 44px tall in the header, so the visual size stays and an
     invisible overlay carries the touch target. Siblings sit in a row, so the
     overlay only needs to grow vertically — it cannot swallow a neighbour. */
  .lang-opt { position: relative; }
  .lang-opt::after {
    content: '';
    position: absolute;
    left: 0; right: 0;
    top: 50%; transform: translateY(-50%);
    height: 44px;
    /* Purely a hit area — it must never paint or trap the pill's own hover. */
    background: transparent;
  }

  /* Footer links were 30px tall in a 10-link column: the primary navigation on
     a phone, at half the comfortable target size. */
  .foot-grid a {
    padding: 10px 0;
    font-size: 0.97rem;
  }
  .foot-legal { gap: 10px 18px; }
  .foot-legal a { padding: 4px 0; }

  /* The wordmark is a link and was 34px tall. Same overlay trick as .lang-opt:
     the type must not grow, the target must. */
  .brand { position: relative; }
  .brand::after {
    content: '';
    position: absolute;
    left: 0; right: 0;
    top: 50%; transform: translateY(-50%);
    height: 44px;
    background: transparent;
  }
}

/* ── the 320px case ────────────────────────────────────────────────────────
   On a 320px-wide device the header's contents did not fit: brand (102) + gap
   (18) + language pill (118) + burger (44) + the bar's own 32px of padding
   came to ~290 inside 252 available, so .bar-right overflowed its own bar and
   the right edge of the hamburger sat off-screen on every page.

   It was invisible to measurement because `body { overflow-x: hidden }` clips
   the overflow instead of scrolling it, while the layout viewport still widens
   — `window.innerWidth` reports 328 on a 320 device, so scrollWidth never
   exceeds innerWidth and the usual overflow check reads clean. The element
   rectangles are the tell: .bar-right ended at 328 while .bar ended at 302.

   So buy the ~40px back from padding, gap and the wordmark rather than from
   the language pill, whose segments are already at the floor of what a thumb
   can hit. */
@media (max-width: 380px) {
  .site-head .bar { gap: 10px; padding: 11px 10px 11px 12px; }
  .brand { font-size: 1.15rem; }
  .site-head .bar-right { gap: 6px; }
  .lang-opt { min-width: 32px; padding: 0 0.34em; }
}

/* ── theme switcher ────────────────────────────────────────────────────────
   Segmented, and deliberately the same object as the language pill: they are
   the same kind of choice (a display preference that persists), so they should
   not look like two different controls sitting next to each other.

   Auto / Light / Dark rather than a two-way toggle — "follow the system" has to
   be reachable, and it is the default, so it cannot be the state you can only
   get back to by clearing cookies. */
.theme-pill {
  position: relative;
  display: inline-flex; align-items: center; gap: 0;
  padding: 3px; margin: 0; border: 0;
  border-radius: 999px;
  background: var(--surface-1);
  box-shadow: inset 0 1px 0 var(--spec-strong), 0 1px 2px rgba(var(--shadow-rgb),0.05);
  touch-action: pan-y; /* let a horizontal drag pick a segment, keep vertical scroll */
  --seg: 34px;
}
/* The selection is a single object that MOVES between segments — the thing that
   makes a segmented control read as one control rather than three buttons. It is
   under the icons (z-index) so the lit glyph is never dimmed by the thumb. */
.theme-thumb {
  position: absolute; z-index: 0;
  top: 3px; left: 3px;
  width: var(--seg); height: calc(100% - 6px);
  border-radius: 999px;
  background: var(--surface-solid);
  box-shadow: 0 1px 2px rgba(var(--shadow-rgb),0.09), inset 0 1px 0 var(--spec-soft);
  transform: translate3d(calc(var(--i, 0) * var(--seg)), 0, 0);
  transition: transform var(--t-slow) var(--ease-spring);
}
.theme-pill[data-i='0'] { --i: 0; }
.theme-pill[data-i='1'] { --i: 1; }
.theme-pill[data-i='2'] { --i: 2; }
/* While a finger is down the thumb tracks the pointer, so the spring must not
   fight it; the snap on release re-enables it. */
.theme-pill.is-dragging .theme-thumb { transition: none; }
.theme-opt {
  position: relative; z-index: 1;
  display: inline-flex; align-items: center; justify-content: center;
  width: var(--seg); height: 30px; padding: 0;
  border: 0; border-radius: 999px;
  background: none; color: var(--ink-3);
  cursor: pointer;
  transition: color 0.3s var(--ease), transform 0.3s var(--ease-out);
}
.theme-opt:hover { color: var(--ink-2); }
.theme-opt.on { color: var(--ink); }
.theme-opt:active { transform: scale(0.9); }
.theme-opt:focus-visible { outline: 2.5px solid var(--brass); outline-offset: 3px; z-index: 2; }
@media (prefers-reduced-motion: reduce) {
  .theme-thumb { transition: none; }
}

/* In the top bar only from the width where the bar has room to spare — below
   that it lives in the nav panel instead, because the 320px header budget is
   already exactly spent (see "the 320px case"). */
.theme-pill--nav, .theme-pill--foot { display: none; }
@media (max-width: 980px) {
  .theme-pill--bar { display: none; }
  .theme-pill--nav { display: inline-flex; }
  .nav-theme {
    display: flex; align-items: center; justify-content: center;
    margin-top: 6px; padding: 12px 10px 4px;
    border-top: 1px solid var(--hairline-2);
  }
  /* In a menu the control is a thumb target, not a glance target: segments grow
     to the 44pt floor rather than relying on an invisible ::after, which would
     have overlapped its neighbours and stolen their taps. */
  .theme-pill--nav { --seg: 60px; padding: 4px; }
  .theme-pill--nav .theme-opt { height: 40px; }
  .theme-pill--nav .theme-thumb { top: 4px; left: 4px; height: calc(100% - 8px); }
}

/* The footer copy is the one place a preference control can sit permanently
   without competing with navigation, so it shows at every width. */
.theme-pill--foot { display: inline-flex; margin-right: 6px; }

/* ── segmented control (generic) ───────────────────────────────────────────
   The same object as the theme switcher, sized for text rather than icons and
   able to stretch. Used for the calculator tabs and the map's layer modes so
   every "pick one of these" on the site is the same control.

   The thumb is one segment wide, so translating it by its OWN width lands it
   exactly on segment N — which keeps the maths correct at any container width
   without JS having to measure anything. Set --seg-n to the number of options. */
.seg {
  position: relative;
  display: inline-flex; align-items: stretch;
  padding: 4px; margin: 0; border: 0;
  border-radius: 999px;
  background: var(--surface-1);
  box-shadow: inset 0 1px 0 var(--spec-strong), 0 1px 2px rgba(var(--shadow-rgb),0.05);
  touch-action: pan-y;
  --seg-n: 2;
}
.seg-wide { display: flex; width: 100%; }
/* Positioned with `left`, not a percentage translate.
   GOTCHA, and it fails silently: a percentage inside translate3d() resolves
   against the transformed element's OWN box, and Chromium computes it to zero
   here — `translate3d(calc(1 * 100%),0,0)` measured as the identity matrix, so
   the thumb never moved while data-i updated correctly. A percentage in `left`
   resolves against the containing block, which is exactly the geometry we mean.
   (The theme pill keeps its transform because its segments are a fixed 34px, so
   it multiplies a LENGTH and never touches this trap.) */
.seg-thumb {
  position: absolute; z-index: 0;
  top: 4px; bottom: 4px;
  width: calc((100% - 8px) / var(--seg-n));
  left: calc(4px + var(--i, 0) * ((100% - 8px) / var(--seg-n)));
  border-radius: 999px;
  background: var(--surface-solid);
  box-shadow: 0 1px 2px rgba(var(--shadow-rgb),0.10), inset 0 1px 0 var(--spec-soft);
  transition: left var(--t-slow) var(--ease-spring);
}
.seg[data-i='0'] { --i: 0; } .seg[data-i='1'] { --i: 1; }
.seg[data-i='2'] { --i: 2; } .seg[data-i='3'] { --i: 3; }
.seg.is-dragging .seg-thumb { transition: none; }
@media (prefers-reduced-motion: reduce) { .seg-thumb { transition: none; } }
.seg-opt {
  position: relative; z-index: 1;
  flex: 1 1 0; min-width: 0;
  display: inline-flex; align-items: center; justify-content: center; gap: 7px;
  min-height: 38px; padding: 0 16px;
  border: 0; border-radius: 999px; background: none;
  font-size: 0.9rem; font-weight: 600; color: var(--ink-3);
  white-space: nowrap; cursor: pointer;
  transition: color var(--t-base) var(--ease), transform var(--t-base) var(--ease-out);
}
.seg-opt svg { width: 16px; height: 16px; flex: 0 0 auto; }
.seg-opt:hover { color: var(--ink-2); }
.seg-opt.on { color: var(--ink); }
.seg-opt:active { transform: scale(0.97); }
.seg-opt:focus-visible { outline: 2.5px solid var(--brass); outline-offset: 3px; z-index: 2; }
@media (max-width: 560px) {
  .seg-opt { min-height: 44px; padding: 0 10px; font-size: 0.84rem; gap: 5px; }
}
@media (prefers-reduced-motion: reduce) {
  .seg-thumb { transition: none; }
}
