/* =============================================================================
   I-Passport Index - public site design system
   Ported from the Lovable reference build (Tailwind 4 + oklch tokens) to plain
   CSS custom properties. No build step, no framework.

   "Emerald & Electric Cyan": deep near-black green hero, ivory paper, electric
   cyan accent, four saturated factor tints, hairline rules.

   NOTE ON --accent-cyan: the reference build called this token "--gold". It is
   not gold, it is electric cyan (oklch 0.78 0.14 195). Renamed here so the
   name matches the color.
   ========================================================================== */

/* ── Tokens ───────────────────────────────────────────────────────────────── */

:root {
  --radius: 0.25rem;
  --radius-sm: 0.125rem;
  --radius-lg: 0.5rem;

  --paper: oklch(0.985 0.006 93);
  --ink: oklch(0.29 0.05 160);
  --ink-foreground: oklch(0.97 0.01 120);

  --hero: oklch(0.29 0.05 160);
  --hero-foreground: oklch(0.97 0.01 120);
  --hero-gradient-left: rgb(41 78 61);
  --hero-gradient-glow: rgb(51 99 75);
  --hero-gradient-right: rgb(64 76 87);

  --accent-cyan: oklch(0.78 0.14 195);
  --accent-cyan-soft: oklch(0.92 0.05 195);
  --heritage: oklch(0.8 0.1 150);
  --rule: oklch(0.9 0.015 93);

  /* Pillar accents: cyan (tax), magenta (safety), yellow (cost), green (education) */
  --factor-tax: oklch(0.78 0.13 200);
  --factor-safety: oklch(0.62 0.22 330);
  --factor-cost: oklch(0.84 0.15 95);
  --factor-education: oklch(0.72 0.16 150);

  --background: oklch(0.985 0.006 93);
  --foreground: oklch(0.3 0.04 160);
  --card: oklch(0.995 0.004 93);
  --card-foreground: oklch(0.3 0.04 160);
  --primary: oklch(0.29 0.05 160);
  --primary-foreground: oklch(0.97 0.01 120);
  --secondary: oklch(0.96 0.012 150);
  --secondary-foreground: oklch(0.3 0.04 160);
  --muted: oklch(0.96 0.012 150);
  --muted-foreground: oklch(0.48 0.02 160);
  --accent: oklch(0.92 0.06 195);
  --accent-foreground: oklch(0.29 0.05 160);
  --destructive: oklch(0.55 0.19 27);
  --border: oklch(0.9 0.015 93);
  --input: oklch(0.9 0.015 93);
  --ring: oklch(0.78 0.14 195);

  --font-display: "Libre Baskerville", Georgia, serif;
  --font-sans: "IBM Plex Sans", ui-sans-serif, system-ui, -apple-system, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SFMono-Regular", monospace;

  /* Site-wide content width (was 1152px, widened 2026-10-02 to match the
     Index). Long text keeps its own cap (.doc__body 44rem) so lines stay
     readable. */
  --wrap: 1440px;
  --gutter: 1.25rem;

  --shadow-sm: 0 1px 2px oklch(0.29 0.05 160 / 6%);
  --shadow-lg: 0 10px 30px oklch(0.29 0.05 160 / 10%);
}

[data-theme="dark"] {
  --paper: oklch(0.2 0.02 170);
  --ink: oklch(0.15 0.02 165);
  --ink-foreground: oklch(0.96 0.01 150);
  --hero: oklch(0.24 0.045 160);
  --hero-foreground: oklch(0.97 0.01 150);
  --hero-gradient-left: rgb(31 62 48);
  --hero-gradient-glow: rgb(39 77 58);
  --hero-gradient-right: rgb(47 58 68);
  --rule: oklch(1 0 0 / 12%);
  --background: oklch(0.2 0.02 170);
  --foreground: oklch(0.96 0.01 150);
  --card: oklch(0.24 0.025 170);
  --card-foreground: oklch(0.96 0.01 150);
  --primary: oklch(0.78 0.15 195);
  --primary-foreground: oklch(0.18 0.02 170);
  --secondary: oklch(0.28 0.025 170);
  --secondary-foreground: oklch(0.96 0.01 150);
  --muted: oklch(0.28 0.025 170);
  --muted-foreground: oklch(0.74 0.02 160);
  --accent: oklch(0.34 0.06 195);
  --accent-foreground: oklch(0.9 0.08 195);
  --border: oklch(1 0 0 / 12%);
  --input: oklch(1 0 0 / 16%);
  --accent-cyan-soft: oklch(0.34 0.06 195);
  --heritage: oklch(0.8 0.16 80);
  --shadow-sm: 0 1px 2px rgb(0 0 0 / 30%);
  --shadow-lg: 0 10px 30px rgb(0 0 0 / 35%);
}

/* ── Base ─────────────────────────────────────────────────────────────────── */

*,
*::before,
*::after {
  box-sizing: border-box;
  border-color: var(--border);
}

html {
  /* Reader text-size control. Everything on the page is sized in rem, so
     scaling the root scales all of it proportionally. */
  font-size: calc(100% * var(--fz, 1));
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background-color: var(--background);
  color: var(--foreground);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  display: flex;
  min-height: 100vh;
  flex-direction: column;
}

main {
  flex: 1 1 auto;
}

h1,
h2,
h3,
h4 {
  font-family: var(--font-display);
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.15;
  margin: 0;
}

p {
  margin: 0;
}

a {
  color: inherit;
  text-decoration: none;
}

img,
svg {
  max-width: 100%;
  display: block;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button {
  cursor: pointer;
  background: none;
  border: 0;
  padding: 0;
}

:focus-visible {
  outline: 2px solid var(--ring);
  outline-offset: 2px;
}

::selection {
  background: var(--accent-cyan);
  color: var(--ink);
}

/* ── Utilities ────────────────────────────────────────────────────────────── */

.wrap {
  margin-inline: auto;
  max-width: var(--wrap);
  padding-inline: var(--gutter);
  width: 100%;
}

/* A single full-width form (Contact) keeps its old width (1152px wrap minus
   the gutters): at 1440px the message box would run far wider than anyone
   types. The container stays full width so the form lines up on the left
   with the page title above it. */
.wrap--form > * {
  max-width: 1112px;
  margin-inline: auto;
}

/* 404, after the Lovable NotFoundComponent: centred, max-w-md, text-7xl. */
.notfound {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 60vh;
  padding-block: 4rem;
}
.notfound__inner {
  max-width: 28rem;
  text-align: center;
}
.notfound__code {
  font-size: 4.5rem;
  line-height: 1;
  font-weight: 700;
}
.notfound__title {
  margin-top: 1rem;
  font-size: 1.25rem;
  font-weight: 600;
}
.notfound__text {
  margin-top: 0.5rem;
  font-size: 0.875rem;
}
.notfound__actions {
  margin-top: 1.5rem;
}

.eyebrow {
  font-size: 0.6875rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--muted-foreground);
}

.eyebrow--cyan {
  color: var(--accent-cyan);
}

.eyebrow--onhero {
  color: color-mix(in oklab, var(--ink-foreground) 60%, transparent);
}

.num {
  font-family: var(--font-mono);
  font-variant-numeric: tabular-nums;
}

.muted {
  color: var(--muted-foreground);
}

.rule-top {
  border-top: 1px solid var(--rule);
}

.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;
}

.na {
  font-size: 0.75rem;
  font-style: italic;
  color: var(--muted-foreground);
}

/* ── Hero surface (shared by hero + footer) ───────────────────────────────── */

.surface-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  color: var(--ink-foreground);
  background-color: var(--hero-gradient-left);
  background-image:
    radial-gradient(75% 90% at 0% 100%, var(--hero-gradient-glow) 0%, transparent 68%),
    linear-gradient(
      105deg,
      var(--hero-gradient-left) 0%,
      var(--hero-gradient-left) 48%,
      var(--hero-gradient-right) 100%
    );
}

.surface-hero::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  mix-blend-mode: overlay;
  opacity: 0.12;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='2' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* ── Header ───────────────────────────────────────────────────────────────── */

.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  border-bottom: 1px solid var(--rule);
  background: color-mix(in oklab, var(--background) 95%, transparent);
  backdrop-filter: blur(8px);
}

.site-header__bar {
  display: flex;
  align-items: center;
  gap: 24px;
  height: 64px;
  /* px throughout: the reader text-size control must not move the chrome. */
  padding-inline: 20px;
}

.brand {
  display: flex;
  flex-shrink: 0;
  align-items: center;
  gap: 8px;
}

.brand__logo {
  height: 40px;
  width: auto;
  flex-shrink: 0;
}

@media (max-width: 480px) {
  .brand__logo {
    height: 32px;
  }
}

/* One mark per theme. No data-theme attribute (light preference, or no JS)
   means the colour mark. */
.brand__logo--dark,
[data-theme="dark"] .brand__logo--light {
  display: none;
}

[data-theme="dark"] .brand__logo--dark {
  display: block;
}

/* The logos fade in once their file has arrived, instead of popping in.
   Same contract as the hero photograph: only under .has-js, revealed by the
   img's own onload, so no script failure can leave a logo hidden. */
.has-js .fade-img {
  opacity: 0;
  transition: opacity 0.6s ease;
}

.has-js .fade-img.is-loaded {
  opacity: 1;
}

.site-nav {
  margin-left: auto;
  display: none;
  align-items: center;
  gap: 24px;
}

.site-nav a {
  font-size: 14px;
  color: var(--muted-foreground);
  transition: color 0.15s;
}

.site-nav a:hover {
  color: var(--foreground);
}

.site-nav a[aria-current="page"] {
  color: var(--foreground);
  font-weight: 500;
}

.header-search {
  display: none;
  width: 224px;
}

.header-tools {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

/* Reader text size: A / A+ / A++ */
.text-size {
  display: none;
  align-items: stretch;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  overflow: hidden;
  flex-shrink: 0;
}

.text-size button {
  border-right: 1px solid var(--border);
  padding: 5px 8px;
  font-size: 13px;
  line-height: 1.1;
  color: var(--muted-foreground);
  transition: color 0.15s, background 0.15s;
}

.text-size button:last-child {
  border-right: 0;
}

.text-size button:hover {
  color: var(--foreground);
}

.text-size button[aria-pressed="true"] {
  background: color-mix(in oklab, var(--accent-cyan) 18%, transparent);
  color: var(--accent-foreground);
}

@media (min-width: 1024px) {
  .text-size {
    display: flex;
  }
}

/* In the mobile panel it is always shown, laid out full width. */
.mobile-menu .text-size {
  display: flex;
  margin-top: 12px;
}

.mobile-menu .text-size button {
  flex: 1;
  padding-block: 8px;
}

.icon-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  border-radius: var(--radius);
  color: var(--muted-foreground);
  transition:
    color 0.15s,
    background 0.15s;
}

/* The theme button holds a sun and a moon and site.js hides one. "svg
   { display: block }" above beats the browser's own [hidden] rule, so without
   this both icons showed at once. */
.icon-btn svg[hidden] {
  display: none;
}

.icon-btn:hover {
  color: var(--foreground);
  background: var(--secondary);
}

.mobile-menu {
  border-top: 1px solid var(--rule);
  background: var(--background);
  padding: 16px 20px;
}

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

.mobile-menu nav {
  display: grid;
  gap: 4px;
  margin-top: 12px;
}

.mobile-menu nav a {
  border-radius: var(--radius);
  padding: 8px;
  font-size: 14px;
}

.mobile-menu nav a:hover {
  background: var(--secondary);
}

@media (min-width: 1024px) {
  .site-nav {
    display: flex;
  }
  .header-search {
    display: block;
    margin-left: 0;
  }
  .header-tools {
    margin-left: 0;
  }
  .menu-toggle {
    display: none;
  }
}

/* Shared classes, pinned inside the chrome only. The same .eyebrow and .search
   rules are used in the page body, where they SHOULD follow the reader's
   text-size choice. */
.site-header .eyebrow,
.mobile-menu .eyebrow {
  font-size: 11px;
}

.site-header .search input,
.mobile-menu .search input {
  padding: 8px 12px 8px 36px;
  font-size: 14px;
}

.site-header .search__icon,
.mobile-menu .search__icon {
  left: 12px;
}

/* The header search sat almost invisible on the header (pale border, pale
   icon and hint). Firmer outline, darker icon and placeholder; mixed from
   --foreground so it holds in the dark theme too. */
.site-header .search input {
  border-color: color-mix(in oklab, var(--foreground) 28%, var(--border));
  box-shadow: inset 0 1px 2px rgb(0 0 0 / 0.04);
}

.site-header .search input::placeholder {
  color: color-mix(in oklab, var(--foreground) 62%, transparent);
}

.site-header .search__icon {
  color: color-mix(in oklab, var(--foreground) 75%, transparent);
}

.site-header .search input:hover {
  border-color: color-mix(in oklab, var(--foreground) 45%, var(--border));
}

/* Restated: the rules above outrank the shared .search input:focus. */
.site-header .search input:focus {
  border-color: var(--accent-cyan);
  box-shadow: 0 0 0 1px var(--accent-cyan);
}

.site-header .search__results a,
.mobile-menu .search__results a {
  gap: 8px;
  padding: 8px 12px;
  font-size: 14px;
}

.site-header .search__results .region,
.mobile-menu .search__results .region {
  font-size: 11px;
}

.site-header .search__empty,
.mobile-menu .search__empty {
  padding: 12px;
  font-size: 13px;
}

.site-header .search__results,
.mobile-menu .search__results {
  max-height: 288px;
}
/* ── Country search ───────────────────────────────────────────────────────── */

.search {
  position: relative;
}

.search__icon {
  position: absolute;
  left: 0.75rem;
  top: 50%;
  transform: translateY(-50%);
  pointer-events: none;
  color: var(--muted-foreground);
}

.search input {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  padding: 0.5rem 0.75rem 0.5rem 2.25rem;
  font-size: 0.875rem;
  outline: none;
}

.search input:focus {
  border-color: var(--accent-cyan);
  box-shadow: 0 0 0 1px var(--accent-cyan);
}

.search__results {
  position: absolute;
  z-index: 50;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 18rem;
  overflow-y: auto;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--card);
  box-shadow: var(--shadow-lg);
}

.search__results[hidden] {
  display: none;
}

.search__results a {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.75rem;
  font-size: 0.875rem;
  border-bottom: 1px solid var(--rule);
}

.search__results a:last-child {
  border-bottom: 0;
}

.search__results a:hover,
.search__results a.on {
  background: var(--secondary);
}

.search__results .region {
  margin-left: auto;
  font-size: 0.6875rem;
  color: var(--muted-foreground);
}

.search__empty {
  padding: 0.75rem;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

/* ── Buttons ──────────────────────────────────────────────────────────────── */

.btn {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  border-radius: var(--radius);
  padding: 0.75rem 1.25rem;
  font-size: 0.875rem;
  font-weight: 500;
  transition: opacity 0.15s, background 0.15s, color 0.15s;
  border: 1px solid transparent;
}

.btn:hover {
  opacity: 0.9;
}

.btn--cyan {
  background: var(--accent-cyan);
  color: var(--ink);
}

.btn--primary {
  background: var(--primary);
  color: var(--primary-foreground);
}

.btn--lg {
  padding: 0.875rem 1.5rem;
  box-shadow: var(--shadow-lg);
}

.btn--ghost-hero {
  border-color: color-mix(in oklab, var(--ink-foreground) 25%, transparent);
  color: var(--ink-foreground);
}

.btn--ghost-hero:hover {
  background: color-mix(in oklab, var(--ink-foreground) 10%, transparent);
  opacity: 1;
}

.btn--outline {
  border-color: var(--rule);
  color: var(--muted-foreground);
}

.btn--outline:hover {
  color: var(--foreground);
  opacity: 1;
}

.btn[disabled] {
  opacity: 0.55;
  cursor: not-allowed;
}

/* ── Page header ──────────────────────────────────────────────────────────── */

.page-header {
  border-bottom: 1px solid var(--rule);
  background: color-mix(in oklab, var(--secondary) 40%, transparent);
  padding-block: 3.5rem;
}

.page-header h1 {
  margin-top: 0.75rem;
  max-width: 48rem;
  font-size: 2rem; /* every page title is 2rem (Lay, 2026-10-20) */
}

.page-header__intro {
  margin-top: 1.25rem;
  max-width: 42rem;
  color: var(--muted-foreground);
}

@media (min-width: 768px) {
  .page-header {
    padding-block: 5rem;
  }
}

/* ── Home hero ────────────────────────────────────────────────────────────── */

.hero {
  border-bottom: 1px solid var(--rule);
}

/* One of the uploaded photographs, drawn afresh on every page load.
 *
 * The layers, back to front: the gradient that .surface-hero paints as its own
 * background, then the photo, then the scrim, then the noise texture that
 * .surface-hero::before already contributed, then the text. An element paints
 * its own background below its negative z-index children, which is what lets
 * the photo cover the gradient while the text, at the default z-index, stays
 * above all of it. .surface-hero sets isolation:isolate, so none of this
 * escapes the section.
 *
 * With no photo uploaded, neither of these elements is rendered at all and the
 * hero is exactly the gradient it has always been.
 */
.hero__bg {
  position: absolute;
  inset: 0;
  z-index: -2;
  width: 100%;
  height: 100%;
  object-fit: cover;
  /* Keeps faces and horizons out of the bottom crop, where the buttons are. */
  object-position: center 40%;
}

/* The blurred placeholder, one layer below the photograph. Framed identically
   so the swap is a sharpening rather than a jump. */
.hero__lqip {
  position: absolute;
  inset: 0;
  z-index: -3;
  background-size: cover;
  background-position: center 40%;
  background-repeat: no-repeat;
  /* A 24px image stretched this far is already soft, but the blur hides the
     block edges that would otherwise show at the largest sizes. */
  filter: blur(16px);
  transform: scale(1.06);   /* absorbs the blur's feathered edge */
}

/* The photograph arrives rather than appears.
 *
 * Only under .has-js: the class is set by the inline head script, so with
 * JavaScript off the image is never hidden in the first place. The fade is
 * driven by the img's own onload handler, not by motion.js, so a blocked or
 * broken script cannot leave the hero blank. */
.has-js .hero__bg {
  opacity: 0;
  transform: scale(1.04);
  transition: opacity 0.9s ease, transform 1.4s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.has-js .hero__bg.is-loaded {
  opacity: 1;
  transform: none;
}

/* Contrast, not decoration. The headline is near-white and the lede runs at
 * 0.75 opacity, so a bright sky behind them would fail to be readable. Heavier
 * on the left, where every line of text begins, and lighter on the right so
 * the photograph is still visibly a photograph.
 */
.hero__scrim {
  position: absolute;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  background-image:
    linear-gradient(
      100deg,
      color-mix(in srgb, var(--ink) 88%, transparent) 0%,
      color-mix(in srgb, var(--ink) 74%, transparent) 45%,
      color-mix(in srgb, var(--ink) 40%, transparent) 100%
    ),
    linear-gradient(
      to bottom,
      color-mix(in srgb, var(--ink) 30%, transparent) 0%,
      color-mix(in srgb, var(--ink) 55%, transparent) 100%
    );
}

/* Wide screens let the right-hand side of the photograph through.
 *
 * Only from here up, and the width is not arbitrary. The text sits in the
 * --wrap container (1440px since 2026-10-02, 1152px before), and the headline
 * is capped at 48rem inside it, so on any viewport at least this wide no line
 * of text reaches past about 65% (about 55% with the wider wrap, which only
 * keeps it further inside the dark side). Everything to the
 * right of that is carrying no words and has no reason to be dark. Below this
 * width the headline can span the full viewport, so the scrim above stays as it
 * is rather than putting white text over a bright sky.
 *
 * The knee sits at 72% with the steep fall after it, which keeps the last of
 * the headline over roughly 70 percent ink while the right edge drops to about
 * a third. The vertical wash is eased off here too, because it darkens the
 * right-hand side just as much as the left and would undo half of this.
 */
@media (min-width: 1024px) {
  .hero__scrim {
    background-image:
      linear-gradient(
        100deg,
        color-mix(in srgb, var(--ink) 88%, transparent) 0%,
        color-mix(in srgb, var(--ink) 78%, transparent) 52%,
        color-mix(in srgb, var(--ink) 50%, transparent) 72%,
        color-mix(in srgb, var(--ink) 12%, transparent) 100%
      ),
      linear-gradient(
        to bottom,
        color-mix(in srgb, var(--ink) 18%, transparent) 0%,
        color-mix(in srgb, var(--ink) 42%, transparent) 100%
      );
  }
}

/* A photograph earns a taller hero than a flat gradient does. */
.hero--photo .hero__inner {
  padding-block: 6rem;
}

.hero__inner {
  padding-block: 5rem;
}

.hero__badge {
  display: inline-block;
  border: 1px solid color-mix(in oklab, var(--ink-foreground) 20%, transparent);
  background: color-mix(in oklab, var(--ink-foreground) 5%, transparent);
  border-radius: var(--radius-sm);
  padding: 0.375rem 0.75rem;
  font-size: 0.6875rem;
  font-weight: 500;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--accent-cyan);
}

.hero h1 {
  margin-top: 1.5rem;
  max-width: 48rem;
  font-size: clamp(2.25rem, 6vw, 4.5rem);
  line-height: 1.08;
}

.hero h1 em {
  font-style: italic;
  color: #a3c9a3;
}

.hero__lede {
  margin-top: 1.5rem;
  max-width: 36rem;
  opacity: 0.75;
  font-size: 1.0625rem;
}

.hero__actions {
  margin-top: 2.25rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

/* What the Index compares, said under the headline (the name alone reads as
   a passport-strength ranking to many first-time visitors). */
.hero__tagline {
  margin-top: 1rem;
  max-width: 40rem;
  font-size: 1.1875rem;
  font-weight: 500;
  color: var(--accent-cyan);
}

/* Which of the two buttons suits which visitor. */
.hero__cue {
  margin-top: 1rem;
  max-width: 36rem;
  font-size: 0.875rem;
  opacity: 0.7;
}


@media (min-width: 768px) {
  .hero__inner {
    padding-block: 7rem;
  }
  /* Restated here because .hero--photo .hero__inner is two classes and would
     otherwise beat the single-class rule above at every width. */
  .hero--photo .hero__inner {
    padding-block: 8.5rem;
  }
}

/* ── Cards & grids ────────────────────────────────────────────────────────── */

.card {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--card);
}

.section {
  padding-block: 5rem;
}

.section--tint {
  border-block: 1px solid var(--rule);
  background: color-mix(in oklab, var(--secondary) 40%, transparent);
}

.grid-4 {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .grid-4 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .grid-4 {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* Three across on desktop, and two-then-one below, so a row of three never
   leaves a single orphaned card on a tablet. */
.grid-3 {
  display: grid;
  gap: 1.5rem;
  grid-template-columns: 1fr;
}

@media (min-width: 768px) {
  .grid-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

@media (min-width: 768px) {
  .grid-3--two {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/* Pillar cards */
.pillar {
  padding: 2rem;
  transition: border-color 0.3s;
}

.pillar:hover {
  border-color: var(--factor-color);
}

.pillar__num {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  margin-bottom: 1.5rem;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  font-weight: 600;
  background: var(--factor-color);
  color: var(--ink);
}

.pillar h3 {
  font-size: 1.25rem;
  transition: color 0.2s;
}

.pillar:hover h3 {
  color: var(--factor-color);
}

.pillar p {
  margin-top: 0.75rem;
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

/* Feature panel (weighting simulator / advisor CTA) */
.panel {
  position: relative;
  overflow: hidden;
  padding: 2rem;
}

.panel__glow {
  position: absolute;
  bottom: -6rem;
  right: -6rem;
  width: 16rem;
  height: 16rem;
  border-radius: 9999px;
  filter: blur(100px);
  opacity: 0.15;
  pointer-events: none;
}

.panel__grid {
  position: relative;
  z-index: 1;
  display: grid;
  gap: 3rem;
  align-items: center;
}

@media (min-width: 768px) {
  .panel {
    padding: 3rem;
  }
  .panel__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.panel h2 {
  font-size: clamp(1.5rem, 3vw, 2.25rem);
}

.panel p {
  color: var(--muted-foreground);
}

/* Simulator preview */
.sim {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: color-mix(in oklab, var(--secondary) 60%, transparent);
  padding: 1.5rem;
  box-shadow: var(--shadow-sm);
}

.sim__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.sim__bars {
  margin-top: 1.5rem;
  display: grid;
  gap: 1.25rem;
}

.sim__bar-label {
  display: flex;
  justify-content: space-between;
  font-size: 0.75rem;
  color: var(--muted-foreground);
  margin-bottom: 0.5rem;
}

.sim__track {
  height: 0.375rem;
  width: 100%;
  overflow: hidden;
  background: var(--rule);
}

.sim__fill {
  height: 100%;
}

.sim__rows {
  margin-top: 1.5rem;
  border-top: 1px solid var(--rule);
  padding-top: 1.25rem;
  display: grid;
  gap: 0.75rem;
}

.sim__row {
  display: flex;
  align-items: center;
  gap: 1rem;
  font-size: 0.875rem;
}

.sim__row .rank {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.sim__row .name {
  flex: 1;
}

.sim__row .shift {
  font-size: 0.625rem;
}

/* Quote / example card */
.quote {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: color-mix(in oklab, var(--secondary) 50%, transparent);
  padding: 1.5rem;
  font-size: 0.875rem;
}

.quote p {
  font-style: italic;
  color: var(--muted-foreground);
}

.quote__list {
  margin-top: 1.25rem;
  display: grid;
  gap: 0.5rem;
}

.quote__item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--card);
  padding: 0.625rem 1rem;
}

/* ── Index controls ───────────────────────────────────────────────────────── */

.controls {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
  /* Pinned under the 64px site header while the index scrolls. The 10px of
     breathing room is padding in the page colour, not an offset, so rows
     passing underneath never show through the gap. */
  position: sticky;
  top: 64px;
  z-index: 30;
  padding-block: 10px 0.75rem;
  background: var(--background);
}

/* One quiet line under the search row, saying what the opening order is. */
.controls__note {
  flex-basis: 100%;
  margin: 0;
  font-size: 0.8125rem;
  line-height: 1.45;
  color: var(--muted-foreground);
}

.controls .search {
  flex: 1 1 14rem;
  min-width: min(14rem, 100%);
}

.select {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  padding: 0.625rem 0.75rem;
  font-size: 0.875rem;
  outline: none;
}

.select:focus {
  border-color: var(--accent-cyan);
}

/* The sort select exists only for the card layout. Above the table breakpoint
   the column headers do the job and a second control beside them would be two
   ways to set one thing. */
.select--sort {
  flex: 1 1 12rem;
  min-width: min(10rem, 100%);
}

@media (min-width: 1024px) {
  .select--sort {
    display: none;
  }
}

/* Index: the goals in one line above the table, with the button that opens
   the goals window. The window itself is the advisor's .goals (further down). */
.goals-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 1rem 1.5rem;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: color-mix(in oklab, var(--secondary) 40%, transparent);
  padding: 1rem 1.5rem;
}

.goals-bar__list {
  margin: 0.375rem 0 0;
  padding: 0;
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem 1.25rem;
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.goals-bar__list li {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
}

/* The factor's colour, as a dot before its name. */
.goals-bar__list li::before {
  content: "";
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 50%;
  background: var(--factor-color);
}

.goals-bar__list strong {
  color: var(--foreground);
  font-weight: 600;
}

/* The Index goals window: the four factors stacked, one per row. */
.goals--index .weights__grid {
  grid-template-columns: 1fr;
}

.goals-form__note {
  margin-top: 1.25rem;
}

/* Reset (shown once a rating changed) sits at the left, the main button right. */
.goals--index #reset {
  margin-right: auto;
}

.weights__intro {
  margin-top: 0.25rem;
  max-width: 42rem;
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

.weights__grid {
  margin-top: 1.5rem;
  display: grid;
  gap: 1.25rem;
  grid-template-columns: 1fr;
}

@media (min-width: 640px) {
  .weights__grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1024px) {
  .weights__grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

.weight {
  padding-top: 0;
}

/* The factor's coloured line, now a slider. Track 4px, coloured up to the dot
   and grey after it; at 1 the dot sits on the far left and the line is grey.
   The fill stop is offset by half the dot (8px) so it ends under the dot's
   centre at every step, not at the raw percentage. */
.weight__range {
  --dot: 16px;
  --fill: linear-gradient(
    to right,
    var(--factor-color) calc(var(--dot) / 2 + (100% - var(--dot)) * var(--f, 0)),
    var(--border) 0
  );
  display: block;
  width: 100%;
  height: 24px;
  margin: 0 0 0.375rem;
  /* Room for the dot at either end: the goals window body scrolls (and so
     clips), and the dot's ring, focus halo and grow-on-drag reach 7px
     past the track (8px gives a pixel to spare). Without this the outer columns
     cut it in half. */
  padding: 0 8px;
  background: transparent;
  -webkit-appearance: none;
  appearance: none;
  cursor: pointer;
  touch-action: pan-y;
}

.weight__range::-webkit-slider-runnable-track {
  height: 4px;
  border-radius: 999px;
  background: var(--fill);
}

.weight__range::-moz-range-track {
  height: 4px;
  border-radius: 999px;
  background: var(--fill);
}

.weight__range::-webkit-slider-thumb {
  -webkit-appearance: none;
  appearance: none;
  width: var(--dot);
  height: var(--dot);
  margin-top: calc((4px - var(--dot)) / 2);
  border: 3px solid var(--background);
  border-radius: 50%;
  background: var(--factor-color);
  box-shadow: 0 0 0 1px var(--factor-color), 0 1px 4px rgb(0 0 0 / 0.25);
  cursor: grab;
  transition: transform 0.15s;
}

.weight__range::-moz-range-thumb {
  box-sizing: border-box;
  width: var(--dot);
  height: var(--dot);
  border: 3px solid var(--background);
  border-radius: 50%;
  background: var(--factor-color);
  box-shadow: 0 0 0 1px var(--factor-color), 0 1px 4px rgb(0 0 0 / 0.25);
  cursor: grab;
  transition: transform 0.15s;
}

.weight__range:active::-webkit-slider-thumb {
  cursor: grabbing;
  transform: scale(1.2);
}

.weight__range:active::-moz-range-thumb {
  cursor: grabbing;
  transform: scale(1.2);
}

.weight__range:focus {
  outline: none;
}

.weight__range:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 1px var(--factor-color), 0 0 0 5px color-mix(in oklab, var(--factor-color) 35%, transparent);
}

.weight__range:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 1px var(--factor-color), 0 0 0 5px color-mix(in oklab, var(--factor-color) 35%, transparent);
}

@media (prefers-reduced-motion: reduce) {
  /* Separate rules: one browser drops a whole rule over the other's prefix. */
  .weight__range::-webkit-slider-thumb {
    transition: none;
  }
  .weight__range::-moz-range-thumb {
    transition: none;
  }
}

.weight__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
}

.weight__label {
  font-size: 0.875rem;
  font-weight: 500;
}

.weight__value {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.weight__scale {
  margin-top: 0.5rem;
  display: flex;
  gap: 0.375rem;
}

.weight__scale button {
  flex: 1;
  height: 2.25rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--muted-foreground);
  font-family: var(--font-mono);
  font-size: 0.875rem;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.weight__scale button:hover {
  color: var(--foreground);
}

.weight__scale button[aria-pressed="true"] {
  border-color: transparent;
  background: var(--factor-color);
  color: var(--ink);
}

.weights__actions {
  margin-top: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem;
}

.weights__note {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

/* Index: the pointer to the advisor, above the priorities. */
.index-cue {
  margin-bottom: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem 1rem;
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

/* Index: which way the figures run, just above the table. */
.index-legend {
  margin-bottom: 0.75rem;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

/* Country names in the Index read as links before anyone hovers them. */
table.index .country-link {
  text-decoration: underline;
  text-decoration-color: color-mix(in oklab, currentColor 30%, transparent);
  text-underline-offset: 4px;
}

/* On hover the animated cyan underline takes over. */
table.index .country-link:hover {
  text-decoration-color: transparent;
}

/* The Index section's own spacing (was an inline style, moved here so phones
   can tighten it). */
.wrap--index {
  padding-block: 2.5rem;
}

/* The search + region bar sits directly above the table, under the goals line. */
.index-main {
  margin-top: 1.5rem;
}

/* ── Index table ──────────────────────────────────────────────────────────── */

/* Factor tint carriers. Used as a class rather than an inline style because the
   index writes one per cell and there are four per row. */
.f-tax {
  --factor-color: var(--factor-tax);
}
.f-safety {
  --factor-color: var(--factor-safety);
}
.f-cost {
  --factor-color: var(--factor-cost);
}
.f-education {
  --factor-color: var(--factor-education);
}

.table-wrap {
  margin-top: 0.75rem;   /* the pinned bar above carries another 0.75rem */
  /* Scroll rather than hide. Seven columns fit comfortably on a wide screen,
     but just above the 1024px breakpoint they can run past the edge, and
     overflow:hidden would take the last column away with nothing to say so. */
  overflow-x: auto;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--card);
}

table.index {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

/* Column headers pinned under the controls bar (desktop table only; below
   1024px the rows are cards and there is no header). Sticky needs the wrapper
   not to be a scroll box, so index.js adds .is-fit whenever the table fits its
   width; a window too narrow for it keeps the sideways scroll and the headers
   simply scroll with the rows, as before. --ipx-bar-h is the bar height, which
   index.js measures because the bar wraps and follows the reader text size. */
@media (min-width: 1024px) {
  .table-wrap.is-fit {
    overflow: visible;
  }

  .table-wrap.is-fit table.index th {
    position: sticky;
    top: calc(64px + var(--ipx-bar-h, 4.5rem));
    z-index: 20;
    /* Opaque version of the header row tint, so rows pass behind, not through. */
    background: color-mix(in oklab, var(--secondary) 60%, var(--card));
    box-shadow: inset 0 -1px 0 var(--rule);
  }

  .table-wrap.is-fit table.index th:first-child {
    border-top-left-radius: var(--radius);
  }

  .table-wrap.is-fit table.index th:last-child {
    border-top-right-radius: var(--radius);
  }
}

table.index thead tr {
  border-bottom: 1px solid var(--rule);
  background: color-mix(in oklab, var(--secondary) 60%, transparent);
  text-align: left;
}

table.index th {
  padding: 1rem 1rem 0.75rem;
  vertical-align: bottom;
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted-foreground);
}

table.index th button {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: inherit;
  font-weight: 600;
  font-size: inherit;
}

table.index th button:hover {
  color: var(--accent-cyan);
}

table.index th.factor {
  width: 7rem;
  text-align: center;
}

table.index th.factor button {
  display: block;
  width: 100%;
  border-top: 2px solid var(--factor-color);
  padding-top: 0.375rem;
}

table.index th.factor button:hover {
  color: var(--foreground);
}

table.index th.rank {
  width: 4rem;
}

table.index th.score {
  width: 7rem;
  text-align: right;
}

table.index td {
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--rule);
  vertical-align: middle;
}

table.index tbody tr:last-child td {
  border-bottom: 0;
}

table.index tbody tr:hover {
  background: color-mix(in oklab, var(--secondary) 50%, transparent);
}

table.index td.rank {
  color: var(--muted-foreground);
}

table.index td.factor {
  text-align: center;
}

table.index td.score {
  text-align: right;
  font-weight: 500;
}

.country-link {
  font-weight: 500;
}

.country-link:hover {
  color: var(--accent-cyan);
  text-decoration: underline;
  text-underline-offset: 4px;
}

.row-region {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

/* Flag images. Inline with the country name, with a hairline border so a flag
   that is mostly white (Japan, Finland) still reads as a rectangle against the
   ivory background rather than floating. */
img.flag {
  display: inline-block;
  vertical-align: -0.15em;
  margin-right: 0.45rem;
  border-radius: 1px;
  box-shadow: 0 0 0 1px oklch(0.29 0.05 160 / 12%);
  object-fit: cover;
  background: var(--muted);
}

[data-theme="dark"] img.flag {
  box-shadow: 0 0 0 1px rgb(255 255 255 / 18%);
}

.flag--emoji {
  margin-right: 0.4rem;
}

/* The country page draws its flag large, beside the title. */
.country-hero h1 img.flag {
  vertical-align: -0.05em;
  margin-right: 0.75rem;
  border-radius: 2px;
}

table.index td.factor .num {
  font-size: 1rem;
}

/* Below the table breakpoint the same rows become cards. One list in the
   markup, two layouts, so the server never ships the index twice. */
@media (max-width: 1023px) {
  .table-wrap {
    border: 0;
    background: none;
    overflow: visible;
  }

  table.index,
  table.index tbody,
  table.index tr,
  table.index td {
    display: block;
    width: auto;
  }

  table.index thead {
    display: none;
  }

  table.index tr {
    position: relative;
    margin-bottom: 0.75rem;
    border: 1px solid var(--rule);
    border-radius: var(--radius);
    background: var(--card);
    padding: 1rem;
    display: grid;
    /* Two columns on a phone, four on a tablet. Four across 375px leaves each
       factor about 70px, and the column label above it ("EDUCATION", 10px
       uppercase with 0.12em tracking) needs very nearly all of that. */
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.75rem 0.5rem;
  }

  @media (min-width: 540px) {
    table.index tr {
      grid-template-columns: repeat(4, minmax(0, 1fr));
    }
  }

  table.index tr:hover {
    background: var(--card);
  }

  table.index td {
    border: 0;
    padding: 0;
  }

  /* Full width of the card. The room for the rank and the score in the two top
     corners is reserved further down, by the .is-ranked rules, because until a
     weighting is applied neither corner holds anything. */
  table.index td.country {
    grid-column: 1 / -1;
  }

  table.index td.rank {
    position: absolute;
    top: 1rem;
    left: 1rem;
    font-size: 0.8125rem;
  }

  table.index td.score {
    position: absolute;
    top: 0.875rem;
    right: 1rem;
    text-align: right;
    font-size: 1.125rem;
  }

  table.index td.factor {
    text-align: left;
    border-top: 2px solid var(--factor-color);
    padding-top: 0.375rem;
  }

  table.index td.factor::before,
  table.index td.score::before {
    content: attr(data-k);
    display: block;
    font-family: var(--font-sans);
    font-size: 0.625rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.12em;
    color: var(--muted-foreground);
    margin-bottom: 0.125rem;
  }

  table.index td.score::before {
    display: none;
  }

  table.index td.factor .num {
    font-size: 0.875rem;
  }
}

/* The rank and score cells only earn their absolute slots once a weighting is
   applied. Until then the rank holds a dash and the score holds the words "Set
   weighting", and both sit on top of the country name. The weighting panel
   immediately above already says scores are hidden until you set one, so on a
   card there is nothing lost by leaving the corner empty. */
@media (max-width: 1023px) {
  table.index td.rank,
  table.index td.score {
    display: none;
  }
  table.index td.country {
    padding-right: 0;
  }

  table.index.is-ranked td.rank,
  table.index.is-ranked td.score {
    display: block;
  }
  table.index.is-ranked td.country {
    padding-left: 2.5rem;
    padding-right: 4rem;
  }
}

/* ── Country page ─────────────────────────────────────────────────────────── */

.country-hero {
  border-bottom: 1px solid var(--rule);
  background: var(--ink);
  color: var(--ink-foreground);
  padding-block: 3.5rem;
}

@media (min-width: 768px) {
  .country-hero {
    padding-block: 5rem;
  }
}

.back-link {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  opacity: 0.7;
}

.back-link:hover {
  opacity: 1;
}

.country-hero__top {
  margin-top: 1.5rem;
  display: flex;
  flex-wrap: wrap;
  align-items: flex-end;
  justify-content: space-between;
  gap: 2rem;
}

.country-hero h1 {
  margin-top: 0.75rem;
  font-size: 2rem;
}

.country-hero__stats {
  display: flex;
  gap: 2.5rem;
}

.stat__k {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  opacity: 0.6;
}

.stat__v {
  margin-top: 0.25rem;
  font-size: 1.875rem;
  font-family: var(--font-mono);
}

.stat__v--cyan {
  color: var(--accent-cyan);
}

.stat__v .of {
  font-size: 1rem;
  opacity: 0.5;
}

.notice {
  margin-top: 2rem;
  max-width: 42rem;
  border: 1px solid color-mix(in oklab, var(--accent-cyan) 40%, transparent);
  background: color-mix(in oklab, var(--accent-cyan) 10%, transparent);
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  font-size: 0.875rem;
}

/* Country photo band: edge to edge, a wide crop of the photograph. The image is
   24% taller than the band (12% hidden above, 12% below) so motion.js can slide
   it gently as the page scrolls. Without JavaScript, or with reduced motion,
   it simply sits centred. */
.country-photo {
  position: relative;
  overflow: hidden;
  height: clamp(220px, 38vw, 560px);
  background: var(--secondary);
}

.country-photo__img {
  position: absolute;
  left: 0;
  top: -12%;
  width: 100%;
  height: 124%;
  max-width: none;
  object-fit: cover;
  will-change: transform;
}

.factor-grid {
  margin-top: 2rem;
  display: grid;
  gap: 1px;
  overflow: hidden;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--rule);
}

@media (min-width: 768px) {
  .factor-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.factor-card {
  background: var(--card);
  padding: 1.5rem;
}

.factor-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
}

.factor-card h3 {
  font-size: 1.125rem;
}

.factor-card__score {
  text-align: right;
}

.factor-card__score .v {
  font-family: var(--font-mono);
  font-size: 1.5rem;
  color: var(--factor-color);
}

.factor-card__score .tier {
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--muted-foreground);
}

.factor-card p {
  margin-top: 1rem;
  font-size: 0.875rem;
  color: var(--muted-foreground);
}

/* The comment on what the score means for someone moving there: the answer
   the card exists for, so it reads in the body colour, verdict first. */
.factor-card .factor-card__note {
  font-size: 0.9375rem;
  line-height: 1.55;
  color: var(--foreground);
}

.factor-card__note strong {
  font-weight: 600;
}

.factor-card .source {
  margin-top: 0.75rem;
  font-size: 0.75rem;
  opacity: 0.8;
}

.scorebar {
  margin-top: 1rem;
  width: 100%;
  height: 8px;
  border-radius: 9999px;
  background: var(--muted);
  overflow: hidden;
}

.scorebar__fill {
  height: 100%;
  border-radius: 9999px;
  background: var(--factor-color);
}

.info-grid {
  margin-top: 2rem;
  display: grid;
  gap: 1.5rem;
}

@media (min-width: 768px) {
  .info-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.info-card {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--card);
  padding: 1.5rem;
}

.info-card h3 {
  font-size: 1.125rem;
}

.info-card .body {
  margin-top: 0.75rem;
  font-size: 0.9375rem;
  color: var(--muted-foreground);
}

.info-card .body p {
  margin-bottom: 0.75rem;
}

.info-card .body p:last-child {
  margin-bottom: 0;
}

/* Headline rates: the three figures most people came for, given room. */
.rate-table {
  margin-top: 1rem;
  width: 100%;
  border-collapse: collapse;
}

.rate-table th {
  text-align: left;
  vertical-align: top;
  padding: 0.75rem 1rem 0.75rem 0;
  font-size: 0.8125rem;
  font-weight: 500;
  color: var(--muted-foreground);
  white-space: nowrap;
  border-top: 1px solid var(--rule);
}

.rate-table tr:first-child th,
.rate-table tr:first-child td {
  border-top: 0;
}

.rate-table td {
  padding: 0.75rem 0;
  border-top: 1px solid var(--rule);
}

.rate-table .rate {
  font-size: 1.125rem;
  color: var(--foreground);
}

.rate-note {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

.kv {
  margin: 0;
  display: grid;
  grid-template-columns: max-content 1fr;
  gap: 0.5rem 1.25rem;
  font-size: 0.875rem;
}

.kv dt {
  color: var(--muted-foreground);
}

.kv dd {
  margin: 0;
}

/* Phones: label above its value, full width each. Side by side, a long label
   (white-space: nowrap) left the value and its note a thin squeezed column. */
@media (max-width: 767px) {
  .rate-table,
  .rate-table tbody,
  .rate-table tr,
  .rate-table th,
  .rate-table td {
    display: block;
  }
  .rate-table tr {
    padding-block: 0.75rem;
    border-top: 1px solid var(--rule);
  }
  .rate-table tr:first-child {
    border-top: 0;
    padding-top: 0;
  }
  .rate-table th,
  .rate-table td {
    padding: 0;
    border-top: 0;
  }
  .rate-table th {
    white-space: normal;
    margin-bottom: 0.25rem;
  }

  .kv {
    grid-template-columns: 1fr;
    gap: 0;
  }
  .kv dt {
    padding-top: 0.75rem;
    border-top: 1px solid var(--rule);
  }
  .kv dt:first-of-type {
    padding-top: 0;
    border-top: 0;
  }
  .kv dd {
    margin-top: 0.25rem;
    padding-bottom: 0.75rem;
  }
}

.prog {
  border-top: 1px solid var(--rule);
  padding-top: 1rem;
  margin-top: 1rem;
}

.prog:first-of-type {
  border-top: 0;
  padding-top: 0;
  margin-top: 0;
}

.prog__name {
  font-weight: 600;
  font-size: 0.9375rem;
}

.prog__type {
  display: inline-block;
  margin-left: 0.5rem;
  font-size: 0.6875rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--accent-cyan);
}

.prog__facts {
  margin-top: 0.5rem;
  display: flex;
  flex-wrap: wrap;
  gap: 0.375rem 1rem;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

/* Link to the programme's page on the HLG site. */
.prog__link {
  display: inline-block;
  margin-top: 0.5rem;
  font-size: 0.8125rem;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.prog__note {
  margin-top: 0.5rem;
  font-size: 0.8125rem;
  color: var(--muted-foreground);
}

.pager {
  margin-top: 3rem;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  border-top: 1px solid var(--rule);
  padding-top: 1.5rem;
  font-size: 0.875rem;
}

.pager a:hover {
  color: var(--accent-cyan);
}

/* ── Advisor ──────────────────────────────────────────────────────────────── */

.advisor-grid {
  display: grid;
  gap: 2rem;
  align-items: start;
}

@media (min-width: 1024px) {
  .advisor-grid {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  }
  /* Since the sliders and details moved into the goals window the form is about
     half the height of the example beside it. Sticky keeps it level with the
     reader instead of leaving an empty column under it. When the chat makes it
     taller than the screen, sticky simply has no effect. */
  .adv-form {
    position: sticky;
    top: calc(64px + 1rem);
  }
}

.field {
  display: block;
  margin-bottom: 1rem;
}

.field > span {
  display: block;
  font-size: 0.8125rem;
  font-weight: 500;
  margin-bottom: 0.375rem;
}

.field input,
.field textarea,
.field select {
  width: 100%;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  padding: 0.625rem 0.75rem;
  font-size: 0.875rem;
  outline: none;
}

.field textarea {
  min-height: 7rem;
  resize: vertical;
  line-height: 1.55;
}

.field input:focus,
.field textarea:focus,
.field select:focus {
  border-color: var(--accent-cyan);
  box-shadow: 0 0 0 1px var(--accent-cyan);
}

.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* .btn sets display:inline-flex, which beats the browser's own [hidden] rule, so
   a hidden button (Reset on the Index, Try this example once answered) stayed visible. */
.btn[hidden] {
  display: none;
}

.btn--sm {
  padding: 0.375rem 0.75rem;
  font-size: 0.75rem;
}

/* ── Advisor: form on the left, results on the right (updates/ai advisor update.png) */

.adv-form {
  padding: 1.75rem;
}

/* The situation box, which becomes the chat after the first question: the
   conversation above, the text field below, one frame around both. */
.adv-box {
  margin-top: 1rem;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--card);
  overflow: hidden;
}

.adv-box:focus-within {
  border-color: var(--accent-cyan);
  box-shadow: 0 0 0 1px var(--accent-cyan);
}

.adv-box__log {
  max-height: 32rem;
  overflow-y: auto;
  padding: 1.25rem 1rem;
  border-bottom: 1px solid var(--rule);
}

.adv-box__log[hidden],
.adv-box__send[hidden],
.chips[hidden] {
  display: none;
}

.adv-box__log .pick:first-of-type {
  margin-top: 0.5rem;
}

.adv-situation {
  display: block;
  width: 100%;
  min-height: 9rem;
  resize: vertical;
  border: 0;
  background: transparent;
  padding: 0.75rem 0.875rem;
  font-size: 0.875rem;
  line-height: 1.6;
  outline: none;
}

/* In chat mode the field is a reply box, not a blank page */
.adv-box__log:not([hidden]) + label + .adv-situation {
  min-height: 4.5rem;
}

/* Send row, directly under the box */
.adv-box__send {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 0.75rem;
  margin-top: 0.75rem;
}

.adv-box__buttons {
  display: flex;
  gap: 0.5rem;
  flex-shrink: 0;
}

/* Example chips: one line each, cut with an ellipsis; the full text is the title */
.chips {
  display: grid;
  justify-items: start;
  gap: 0.5rem;
  margin-top: 0.75rem;
}

.chips__label {
  font-size: 0.6875rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--muted-foreground);
  margin-top: 0.25rem;
}

.chip {
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  text-align: left;
  border: 1px solid var(--rule);
  border-radius: calc(var(--radius) * 0.6);
  background: var(--muted);
  padding: 0.375rem 0.625rem;
  font-size: 0.75rem;
  color: var(--muted-foreground);
  transition: border-color 0.15s, color 0.15s;
}

.chip:hover {
  border-color: var(--accent-cyan);
  color: var(--foreground);
}

.adv-rule {
  border: 0;
  border-top: 1px solid var(--rule);
  margin: 1.75rem 0;
}

/* Sliders in the factor colours: native accent-color, plus a painted track for
   the filled part where the browser does not draw one (--fill is set by the JS). */
.sliders {
  display: grid;
  gap: 1.25rem;
  margin-top: 1.25rem;
}

.slider__head {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  font-size: 0.8125rem;
  font-weight: 500;
  margin-bottom: 0.375rem;
}

.slider__head output {
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.slider input[type="range"] {
  display: block;
  width: 100%;
  margin: 0;
  accent-color: var(--factor-color);
  cursor: pointer;
}

.adv-fields {
  display: grid;
  gap: 0 1rem;
}

@media (min-width: 640px) {
  .adv-fields {
    grid-template-columns: 1fr 1fr;
  }
}

.adv-form .field > .eyebrow {
  display: block;
  margin-bottom: 0.5rem;
}

/* "Set up your goals": tinted in the accent so it reads as a control of its
   own next to the plain Reset and the dark Send. The badge counts what the
   visitor has set inside the window. */
.btn--goals {
  background: var(--accent-cyan-soft);
  border-color: color-mix(in oklab, var(--accent-cyan) 70%, transparent);
  color: var(--foreground);
  font-weight: 600;
}

.btn--goals:hover {
  border-color: var(--accent-cyan);
  opacity: 1;
}

.goals-count {
  min-width: 1.25rem;
  height: 1.25rem;
  padding: 0 0.375rem;
  border-radius: 999px;
  background: var(--primary);
  color: var(--primary-foreground);
  font-size: 0.6875rem;
  line-height: 1.25rem;
  text-align: center;
}

.goals-count[hidden] {
  display: none;
}

/* The goals window */
.goals {
  width: min(34rem, calc(100vw - 2rem));
  max-height: calc(100dvh - 4rem);
  padding: 0;
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--card);
  color: var(--card-foreground);
  box-shadow: var(--shadow-lg);
  overflow: hidden;
}

.goals[open] {
  display: flex;
  flex-direction: column;
}

.goals::backdrop {
  background: oklch(0.18 0.02 170 / 55%);
}

.goals__head,
.goals__foot {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 1rem 1.5rem;
  flex-shrink: 0;
}

.goals__head {
  justify-content: space-between;
  border-bottom: 1px solid var(--rule);
}

.goals__title {
  font-size: 1.25rem;
}

.goals__body {
  padding: 1.5rem;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.goals__body .adv-rule {
  margin: 1.5rem 0;
}

.goals__foot {
  justify-content: flex-end;
  border-top: 1px solid var(--rule);
}

/* Phones: the window takes almost the whole screen, and the goals button gets
   the full row under the box so nobody misses it. */
@media (max-width: 767px) {
  .goals {
    width: calc(100vw - 1rem);
    max-width: none;
    height: calc(100dvh - 1rem);
    max-height: none;
  }
  .goals__head,
  .goals__foot {
    padding: 0.875rem 1.125rem;
  }
  .goals__body {
    padding: 1.25rem 1.125rem;
    flex: 1;
  }
  .goals__foot .btn {
    flex: 1;
    justify-content: center;
  }
  .adv-box__buttons {
    width: 100%;
    flex-wrap: wrap;
  }
  .adv-box__buttons .btn--goals {
    order: -1;
    width: 100%;
    justify-content: center;
    padding-block: 0.875rem;
  }
  .adv-box__buttons #adv-reset,
  .adv-box__buttons #send {
    flex: 1;
    justify-content: center;
  }
}

.adv-submit {
  width: 100%;
  justify-content: center;
  margin-top: 1.5rem;
}

/* Results panel */
.adv-results {
  padding: 1.75rem;
  background: var(--muted);
}

.adv-form__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  min-height: 1.75rem;
}

.adv-results__tools {
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.adv-close {
  display: inline-grid;
  place-items: center;
  width: 2rem;
  height: 2rem;
  border: 1px solid var(--rule);
  border-radius: 999px;
  background: var(--card);
  color: var(--muted-foreground);
  cursor: pointer;
  transition: color 0.15s, border-color 0.15s;
}

.adv-results__tools {
  position: relative;
}

/* "You can close this example": pops in under the ×, then fades away */
.adv-close-tip {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  z-index: 5;
  white-space: nowrap;
  padding: 0.4rem 0.7rem;
  border-radius: calc(var(--radius) * 0.8);
  background: var(--ink);
  color: var(--ink-foreground);
  font-size: 0.75rem;
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(-4px);
  transition: opacity 0.35s ease, transform 0.35s ease;
  pointer-events: none;
}

.adv-close-tip::before {
  content: "";
  position: absolute;
  top: -5px;
  right: 11px;
  width: 10px;
  height: 10px;
  background: var(--ink);
  transform: rotate(45deg);
}

.adv-close-tip.is-in {
  opacity: 1;
  transform: none;
}

.adv-close-tip[hidden] {
  display: none;
}

.adv-close:hover {
  color: var(--foreground);
  border-color: var(--foreground);
}

/* Closing the example column (desktop): the content fades out first, then the
   column slides shut to the right while the form widens into the space.
   Opening runs the other way: the column opens, then the content fades in.
   Each state carries the timing used to ENTER it, which is how the two
   directions get their own order. The inner block keeps a minimum width, so
   while the column narrows its content is clipped, never re-wrapped (re-wrap
   would make it very tall and shove the page down). */
@media (min-width: 1024px) {
  .advisor-grid {
    transition:
      grid-template-columns 0.55s cubic-bezier(0.22, 0.61, 0.36, 1),
      column-gap 0.55s cubic-bezier(0.22, 0.61, 0.36, 1);
  }
  .advisor-grid.is-collapsed {
    grid-template-columns: minmax(0, 1fr) minmax(0, 0fr);
    column-gap: 0;
    transition:
      grid-template-columns 0.55s cubic-bezier(0.22, 0.61, 0.36, 1) 0.18s,
      column-gap 0.55s cubic-bezier(0.22, 0.61, 0.36, 1) 0.18s;
  }
  .adv-results {
    overflow: hidden;
    transition: padding 0.55s cubic-bezier(0.22, 0.61, 0.36, 1), border-color 0.3s, visibility 0s;
  }
  .adv-results__inner {
    min-width: 24rem;
    transition: opacity 0.3s ease 0.45s;
  }
  .is-collapsed .adv-results {
    padding-inline: 0;
    border-color: transparent;
    visibility: hidden;
    transition:
      padding 0.55s cubic-bezier(0.22, 0.61, 0.36, 1) 0.18s,
      border-color 0.3s 0.3s,
      visibility 0s 0.75s;
  }
  .is-collapsed .adv-results__inner {
    opacity: 0;
    transition: opacity 0.18s ease;
  }
}

/* Phones: the two panels run edge to edge, no page margin, side borders or
   rounded corners around them, and less padding inside, so the content gets
   the whole screen width instead of sitting in nested boxes. */
@media (max-width: 767px) {
  .advisor-grid {
    gap: 0;
    margin-inline: calc(-1 * var(--gutter));
  }
  .adv-form,
  .adv-results {
    border-radius: 0;
    border-left: 0;
    border-right: 0;
    padding: 1.5rem var(--gutter);
  }
  .adv-results {
    border-top: 0;
  }
  .adv-box__log {
    padding: 1rem 0.75rem;
  }
  .pick {
    padding: 1rem;
  }
  .adv-box__send {
    flex-wrap: wrap;
  }
}

/* Phones and tablets: the panels are stacked, so the example just goes away. */
@media (max-width: 1023px) {
  .is-collapsed .adv-results {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .advisor-grid,
  .advisor-grid.is-collapsed,
  .adv-results,
  .is-collapsed .adv-results,
  .adv-results__inner,
  .is-collapsed .adv-results__inner {
    transition: none;
  }
}

.adv-results__head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 1rem;
  margin-bottom: 1rem;
}

.adv-intro,
.adv-intro p,
.adv-prose p {
  font-size: 0.875rem;
  line-height: 1.65;
  color: var(--muted-foreground);
  margin: 0 0 0.875rem;
}

.adv-prose {
  font-size: 0.9375rem;
}

.pick {
  margin-top: 1rem;
  border: 1px dashed color-mix(in oklab, var(--foreground) 22%, transparent);
  border-radius: var(--radius);
  background: var(--card);
  padding: 1.25rem;
}

.pick__head {
  display: flex;
  justify-content: space-between;
  align-items: flex-start;
  gap: 1rem;
  padding-bottom: 0.875rem;
  border-bottom: 1px solid var(--rule);
}

.pick__name {
  font-size: 1.0625rem;
  font-weight: 600;
}

.pick__name a {
  color: inherit;
  text-decoration: none;
}

.pick__name a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.pick__no {
  font-size: 0.75rem;
  font-weight: 400;
  color: var(--muted-foreground);
  margin-right: 0.25rem;
}

.pick__region {
  margin-top: 0.125rem;
  font-size: 0.75rem;
  color: var(--muted-foreground);
}

.pick__score {
  text-align: right;
  flex-shrink: 0;
}

.pick__score .num {
  display: block;
  font-size: 1.75rem;
  line-height: 1;
  color: var(--accent-cyan);
}

.pick__score-label {
  display: block;
  margin-top: 0.25rem;
  font-size: 0.625rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted-foreground);
}

/* A country missing a factor has no match score: said in words. */
.pick__score-na {
  display: block;
  max-width: 7rem;
  font-size: 0.75rem;
  line-height: 1.3;
  color: var(--muted-foreground);
}

.pick__facts {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0.75rem;
  margin: 0.875rem 0 0;
  padding-bottom: 0.875rem;
  border-bottom: 1px solid var(--rule);
}

@media (max-width: 479px) {
  .pick__facts {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

.pick__facts dt {
  font-size: 0.625rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--muted-foreground);
}

.pick__facts dd {
  margin: 0.25rem 0 0;
  font-size: 0.9375rem;
}

.pick__why {
  margin: 0.875rem 0 0;
  font-size: 0.875rem;
  line-height: 1.65;
  color: var(--muted-foreground);
}


.chat {
  border: 1px solid var(--rule);
  border-radius: var(--radius);
  background: var(--card);
  display: flex;
  flex-direction: column;
  min-height: 28rem;
}

.chat__log {
  flex: 1;
  padding: 1.5rem;
  display: grid;
  gap: 1.25rem;
  align-content: start;
  overflow-y: auto;
  max-height: 34rem;
}

.msg {
  display: grid;
  gap: 0.375rem;
}

.msg__who {
  font-size: 0.625rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.15em;
  color: var(--muted-foreground);
}

.msg__body {
  font-size: 0.9375rem;
  line-height: 1.65;
}

.msg__body p {
  margin-bottom: 0.75rem;
}

.msg__body p:last-child {
  margin-bottom: 0;
}

.msg__body ul,
.msg__body ol {
  margin: 0 0 0.75rem;
  padding-left: 1.25rem;
}

.msg__body li {
  margin-bottom: 0.25rem;
}

.msg__body strong {
  font-weight: 600;
}

.msg--user .msg__body {
  border-left: 2px solid var(--accent-cyan);
  padding-left: 0.875rem;
  color: var(--muted-foreground);
}

.msg--ai .msg__who {
  color: var(--accent-cyan);
}

.chat__empty {
  color: var(--muted-foreground);
  font-size: 0.9375rem;
}

.chat__form {
  border-top: 1px solid var(--rule);
  padding: 1rem;
  display: flex;
  gap: 0.75rem;
  align-items: flex-end;
}

.chat__form textarea {
  flex: 1;
  min-height: 3rem;
  max-height: 10rem;
  resize: vertical;
  border: 1px solid var(--border);
  border-radius: var(--radius);
  background: var(--background);
  padding: 0.625rem 0.75rem;
  font-size: 0.875rem;
  outline: none;
}

.chat__form textarea:focus {
  border-color: var(--accent-cyan);
  box-shadow: 0 0 0 1px var(--accent-cyan);
}

.dots {
  display: inline-flex;
  gap: 0.25rem;
}

.dots span {
  width: 0.375rem;
  height: 0.375rem;
  border-radius: 9999px;
  background: var(--accent-cyan);
  animation: pulse 1.2s infinite ease-in-out;
}

.dots span:nth-child(2) {
  animation-delay: 0.15s;
}

.dots span:nth-child(3) {
  animation-delay: 0.3s;
}

@keyframes pulse {
  0%,
  80%,
  100% {
    opacity: 0.25;
  }
  40% {
    opacity: 1;
  }
}

.alert {
  border: 1px solid color-mix(in oklab, var(--destructive) 40%, transparent);
  background: color-mix(in oklab, var(--destructive) 8%, transparent);
  color: var(--destructive);
  border-radius: var(--radius);
  padding: 0.75rem 1rem;
  font-size: 0.875rem;
  margin: 0 1.5rem 1rem;
}

.alert--ok {
  border-color: color-mix(in oklab, var(--factor-education) 45%, transparent);
  background: color-mix(in oklab, var(--factor-education) 10%, transparent);
  color: var(--foreground);
}

/* ── Document pages (methodology, about, legal) ───────────────────────────── */

.doc {
  display: grid;
  gap: 3rem;
  padding-block: 4rem;
}

@media (min-width: 1024px) {
  .doc {
    grid-template-columns: 16rem 1fr;
  }
}

.toc {
  position: sticky;
  top: 5rem;
  align-self: start;
  font-size: 0.875rem;
  display: none;
}

@media (min-width: 1024px) {
  .toc {
    display: block;
  }
}

.toc ol {
  list-style: none;
  margin: 0.75rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
}

.toc a {
  color: var(--muted-foreground);
}

.toc a:hover {
  color: var(--foreground);
}

.doc__body {
  max-width: 44rem;
}

.doc__body section {
  margin-bottom: 3rem;
  scroll-margin-top: 5rem;
}

.doc__body h2 {
  font-size: 1.5rem;
  padding-top: 0.5rem;
}

.doc__body h3 {
  font-size: 1.125rem;
  margin-top: 1.5rem;
}

.doc__body p {
  margin-top: 1rem;
  color: var(--muted-foreground);
}

.doc__body ul,
.doc__body ol {
  margin-top: 1rem;
  padding-left: 1.25rem;
  color: var(--muted-foreground);
}

.doc__body li {
  margin-bottom: 0.5rem;
}

.doc__body a {
  color: var(--foreground);
  text-decoration: underline;
  text-underline-offset: 4px;
}

.formula {
  margin-top: 1rem;
  border: 1px solid var(--rule);
  border-left: 3px solid var(--accent-cyan);
  border-radius: var(--radius);
  background: color-mix(in oklab, var(--secondary) 50%, transparent);
  padding: 0.875rem 1rem;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  color: var(--foreground);
  overflow-x: auto;
}

.source-link {
  display: inline-flex;
  align-items: center;
  gap: 0.375rem;
  margin-top: 0.75rem;
  font-size: 0.8125rem;
}

table.doc-table {
  margin-top: 1.5rem;
  width: 100%;
  border-collapse: collapse;
  font-size: 0.875rem;
}

table.doc-table th,
table.doc-table td {
  border: 1px solid var(--rule);
  padding: 0.625rem 0.75rem;
  text-align: left;
}

table.doc-table th {
  background: color-mix(in oklab, var(--secondary) 60%, transparent);
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--muted-foreground);
}

table.doc-table td {
  color: var(--muted-foreground);
}

/* ── Footer ───────────────────────────────────────────────────────────────── */

.site-footer {
  margin-top: 6rem;
  border-top: 1px solid var(--rule);
}

.site-footer__grid {
  display: grid;
  gap: 2.5rem;
  padding-block: 3.5rem;
}

@media (min-width: 768px) {
  .site-footer__grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
  .site-footer__brand {
    grid-column: span 2;
  }
}

.site-footer__logo {
  height: 48px;
  width: auto;
  max-width: 100%;
  object-fit: contain;
  object-position: left;
}

.site-footer__brand p {
  margin-top: 0.75rem;
  max-width: 28rem;
  font-size: 0.875rem;
  opacity: 0.7;
}

/* "Powered by" link in the bottom line: same size and colour as the copyright text. */
.site-footer__powered {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.site-footer__powered:hover {
  color: var(--accent-cyan);
}

.site-footer ul {
  list-style: none;
  margin: 1rem 0 0;
  padding: 0;
  display: grid;
  gap: 0.5rem;
  font-size: 0.875rem;
}

.site-footer ul a {
  opacity: 0.8;
}

.site-footer ul a:hover {
  opacity: 1;
}

.site-footer__base {
  border-top: 1px solid color-mix(in oklab, var(--ink-foreground) 15%, transparent);
  padding-block: 1.25rem;
  font-size: 0.75rem;
  opacity: 0.6;
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: space-between;
}

/* ── Print ────────────────────────────────────────────────────────────────── */

@media print {
  .site-header,
  .site-footer,
  .goals-bar,
  .controls {
    display: none;
  }
}

/* ── Motion ───────────────────────────────────────────────────────────────── */

/* The hidden state is scoped to .has-js, which the inline head script sets.
   Without JavaScript nothing is ever hidden, so the page is unaffected. */
.has-js [data-reveal] {
  opacity: 0;
  transform: translateY(12px);
}

.has-js [data-reveal="in"] {
  opacity: 1;
  transform: none;
  transition:
    opacity 0.55s cubic-bezier(0.22, 0.61, 0.36, 1) var(--reveal-delay, 0ms),
    transform 0.55s cubic-bezier(0.22, 0.61, 0.36, 1) var(--reveal-delay, 0ms);
}

/* Rows settle horizontally: a table shifting vertically reads as a jump. */
.has-js .rate-table tr[data-reveal] {
  transform: translateX(-8px);
}

.has-js .rate-table tr[data-reveal="in"] {
  transform: none;
}

/* Score bars grow from nothing when they come into view. */
.scorebar__fill {
  transition: width 0.9s cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* Sticky header lifts off the page once it is over content. */
.site-header {
  transition: box-shadow 0.25s, border-color 0.25s;
}

.site-header.is-scrolled {
  box-shadow: 0 1px 0 var(--rule), 0 6px 20px oklch(0.29 0.05 160 / 7%);
}

[data-theme="dark"] .site-header.is-scrolled {
  box-shadow: 0 1px 0 var(--rule), 0 6px 20px rgb(0 0 0 / 35%);
}

/* Cards lift very slightly under the cursor. */
.pillar,
.index-card {
  transition:
    border-color 0.3s,
    transform 0.25s cubic-bezier(0.22, 0.61, 0.36, 1),
    box-shadow 0.25s;
}

.pillar:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-sm);
}

/* The arrow leans toward where it is taking you. */
.btn svg {
  transition: transform 0.2s cubic-bezier(0.22, 0.61, 0.36, 1);
}

.btn:hover svg:last-child {
  transform: translateX(3px);
}

.back-link svg {
  transition: transform 0.2s;
}

.back-link:hover svg {
  transform: translateX(-3px);
}

/* Table rows tint rather than snap. */
table.index tbody tr {
  transition: background 0.18s;
}

/* The weighting buttons feel like buttons. */
.weight__scale button,
.text-size button {
  transition:
    background 0.18s,
    color 0.18s,
    border-color 0.18s,
    transform 0.12s;
}

.weight__scale button:active {
  transform: scale(0.94);
}

/* Country links underline in from the left instead of appearing. */
.country-link {
  background-image: linear-gradient(var(--accent-cyan), var(--accent-cyan));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 1px;
  transition: background-size 0.25s cubic-bezier(0.22, 0.61, 0.36, 1), color 0.2s;
}

.country-link:hover {
  color: var(--accent-cyan);
  background-size: 100% 1px;
  text-decoration: none;
}

/* The advisor's answer arrives rather than appearing. */
.has-js .msg {
  animation: msg-in 0.4s cubic-bezier(0.22, 0.61, 0.36, 1) both;
}

@keyframes msg-in {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

/* ── Reduced motion ───────────────────────────────────────────────────────── */

/* Everything resolves instantly to its final state. Nothing is skipped, and
   nothing is left invisible. */
@media (prefers-reduced-motion: reduce) {
  .has-js [data-reveal],
  .has-js [data-reveal="in"],
  .has-js .rate-table tr[data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }

  .scorebar__fill,
  .site-header,
  .pillar,
  .index-card,
  .btn svg,
  .back-link svg,
  table.index tbody tr,
  .weight__scale button,
  .text-size button,
  .country-link {
    transition: none;
  }

  .pillar:hover,
  .weight__scale button:active {
    transform: none;
  }

  .has-js .msg {
    animation: none;
  }

  /* The hero photograph is present immediately rather than fading in. Note it
     resolves to the FINAL state, not to nothing: the picture is still there,
     it simply does not move to get there. */
  .has-js .hero__bg,
  .has-js .fade-img {
    opacity: 1;
    transform: none;
    transition: none;
  }

  html {
    scroll-behavior: auto;
  }
}

/* ── Advisor first-visit tour (assets/js/advisor-tour.js) ─────────────────── */

.tour-target {
  outline: 2px solid var(--accent-cyan);
  outline-offset: 6px;
  border-radius: var(--radius);
  transition: outline-color 0.2s;
}

.tour-bubble {
  position: absolute;
  z-index: 70;
  width: min(20rem, calc(100vw - 24px));
  padding: 1rem 1.125rem;
  border-radius: var(--radius);
  background: var(--ink);
  color: var(--ink-foreground);
  box-shadow: var(--shadow-lg);
  opacity: 0;
  transform: translateY(6px);
  transition: opacity 0.25s ease, transform 0.25s ease;
}

.tour-bubble.is-in {
  opacity: 1;
  transform: none;
}

/* The arrow, pointing at the element (--arrow-x is set by the script) */
.tour-bubble::before {
  content: "";
  position: absolute;
  left: var(--arrow-x, 50%);
  width: 12px;
  height: 12px;
  margin-left: -6px;
  background: var(--ink);
  transform: rotate(45deg);
}

.tour-bubble[data-side="below"]::before {
  top: -6px;
}

.tour-bubble[data-side="above"]::before {
  bottom: -6px;
}

.tour-bubble[data-side="inside"]::before {
  display: none;
}

.tour-bubble__step {
  font-size: 0.625rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--accent-cyan);
}

.tour-bubble__title {
  margin-top: 0.375rem;
  font-weight: 600;
  font-size: 0.9375rem;
}

.tour-bubble__text {
  margin: 0.375rem 0 0;
  font-size: 0.8125rem;
  line-height: 1.55;
  opacity: 0.85;
}

.tour-bubble__actions {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-top: 0.875rem;
}

.tour-bubble__nav {
  display: flex;
  gap: 0.5rem;
}

.tour-bubble button {
  font: inherit;
  font-size: 0.75rem;
  border-radius: 999px;
  padding: 0.375rem 0.875rem;
  cursor: pointer;
}

.tour-bubble__skip {
  border: 0;
  background: transparent;
  color: inherit;
  opacity: 0.7;
  padding-inline: 0 !important;
}

.tour-bubble__skip:hover {
  opacity: 1;
  text-decoration: underline;
}

.tour-bubble__back {
  border: 1px solid color-mix(in oklab, var(--ink-foreground) 35%, transparent);
  background: transparent;
  color: inherit;
}

.tour-bubble__next {
  border: 0;
  background: var(--accent-cyan);
  color: var(--ink);
  font-weight: 600;
}

@media (prefers-reduced-motion: reduce) {
  .tour-bubble {
    transition: none;
  }
}

/* ── Phones: no sideways scrolling, no zoom-on-tap ────────────────────────── */

/* Nothing may make the page wider than the screen. The real causes are fixed
   where they live; this is the safety net. "clip" (unlike hidden) does not turn
   the page into a scroll box, so the sticky header keeps working; older
   browsers get hidden on body, which the browser applies to the window. */
body {
  overflow-x: hidden;
}

@supports (overflow-x: clip) {
  html,
  body {
    overflow-x: clip;
  }
}

/* Long words or links in an advisor answer wrap instead of widening the page. */
.msg__body,
.pick__why {
  overflow-wrap: anywhere;
}

/* iPhones zoom the whole page in when a field's text is under 16px. Every
   text field, text area and dropdown is 16px on phones (the sliders and
   checkboxes are not text fields). */
@media (max-width: 767px) {
  input:not([type="range"]):not([type="checkbox"]):not([type="radio"]):not([type="hidden"]),
  textarea,
  select {
    font-size: 16px !important;
  }
}

/* ── Index on phones ──────────────────────────────────────────────────────── */

/* Below 768px (keep in step with MOBILE in index.js): the search bar comes
   FIRST, then the goals line, then the cards; search, region and sort share one line with short
   labels (index.js swaps them), and the vertical spacing is tightened.
   .index-main dissolves (display:contents) so its search bar and table become
   items of the column and can be ordered around the goals line. */
@media (max-width: 767px) {
  .page-header:has(+ .wrap--index) {
    padding-block: 2rem 1.75rem;
  }

  .wrap--index {
    padding-block: 0.25rem 2rem;
  }

  .index-layout {
    display: flex;
    flex-direction: column;
  }

  .index-main {
    display: contents;
  }

  .index-layout .controls {
    order: -1;
    display: grid;
    /* Fixed dropdown widths: a select is as wide as its LONGEST option
       ("Asia-Pacific", "Cost of Living, high to low") whatever it shows, which
       left the search box a few letters wide. */
    grid-template-columns: minmax(6.5rem, 1fr) minmax(0, 6rem) minmax(0, 5.5rem);
    gap: 0.5rem;
    padding-block: 8px;
  }

  .index-layout .controls .search,
  .index-layout .controls .select {
    min-width: 0;
  }

  .index-layout .controls .select {
    width: 100%;
    padding: 0.5rem 0.375rem;
    text-overflow: ellipsis;
  }

  .index-layout .controls .search input {
    padding: 0.5rem 0.5rem 0.5rem 2rem;
  }

  .index-layout .controls .search__icon {
    left: 0.625rem;
  }

  /* The count and the default-weighting line would take two more rows of a
     bar that stays pinned over the cards. The priorities block says the same. */
  .index-layout #shown,
  .index-layout .controls__note {
    display: none;
  }

  .goals-bar {
    margin-top: 0.25rem;
    padding: 1rem;
  }

  .goals-bar .btn--goals {
    width: 100%;
    justify-content: center;
  }
}
