/* =============================================================================
   Faresim: "Sodium"
   A lit terminal at 5am, seen from outside: cold blue-green air, warm sodium
   light blooming through it. Warmth here is artificial light in the dark, not
   a sunset. That distinction is the whole palette.
   ============================================================================= */

/* ── tokens ───────────────────────────────────────────────────────────────── */
:root {
  /* surface */
  --hold:        #06141A;  /* tarmac before dawn: the air itself         */
  --hold-deep:   #030B0F;  /* vignette edge                                */
  --cabin:       #0F242D;  /* lit cabin interior; results sit here       */
  --cabin-hi:    #17323D;  /* raised edge / hairline                       */

  /* light */
  --sodium:      #FF9F4A;  /* sodium-vapour terminal glow                  */
  --filament:    #FFD9A8;  /* hottest part of the lamp                     */
  --nav:         #39D3A7;  /* starboard aviation nav light; used once    */

  /* text
     Raised for WCAG AA against the darkest AND lightest points of the
     gradient. The atmosphere varies, so these are set for the worst case,
     which is the sodium bloom at the bottom of the page. Measured, not eyed:
     see the contrast audit note at the foot of this file. */
  --paper:       #EAF2F5;
  --haze:        #B4C6CE;  /* secondary text, plan facts, reasoning */
  --haze-dim:    #93A9B4;  /* metadata, hints, scale marks       */

  /* bloom pigments (low alpha by design: this is light, not paint) */
  --bloom-sodium: rgba(255, 148, 58, .40);
  --bloom-amber:  rgba(255, 196, 122, .26);
  --bloom-nav:    rgba(45, 200, 160, .17);
  --bloom-deep:   rgba(26, 92, 132, .34);
  --bloom-cool:   rgba(18, 64, 104, .40);

  /* type */
  /* Fraunces is reserved for the hero: the headline and the one giant
     figure. Everything else on the page, including every price, is Plex
     Sans, so the interface reads as one voice rather than three. */
  --font-display: 'Fraunces', 'Iowan Old Style', 'Palatino', Georgia, serif;
  --font-sans: 'IBM Plex Sans', system-ui, -apple-system, 'Segoe UI', sans-serif;

  /* rhythm */
  --gutter: clamp(1.25rem, 5vw, 3.5rem);
  --measure: 74rem;

  /* the one easing used everywhere: expo-out */
  --ease: cubic-bezier(.16, 1, .3, 1);
}

*, *::before, *::after { box-sizing: border-box; }

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

body {
  margin: 0;
  min-height: 100svh;
  background: var(--hold);
  color: var(--paper);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.55;
  font-weight: 300;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

/* Guard against a flash of un-choreographed content before fonts settle. */
body.is-loading [data-enter],
body.is-loading .atmosphere { opacity: 0; }

h1, h2, h3, p, ol, ul, figure { margin: 0; }
ol, ul { padding: 0; list-style: none; }

::selection { background: var(--sodium); color: var(--hold); }

.visually-hidden {
  position: absolute; width: 1px; height: 1px;
  margin: -1px; padding: 0; overflow: hidden;
  clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap;
}

/* ── focus ────────────────────────────────────────────────────────────────
   One visible treatment, everywhere. Never removed. */
:focus-visible {
  outline: 2px solid var(--sodium);
  outline-offset: 3px;
  border-radius: 3px;
}

.skip-link {
  position: absolute; top: 0; left: 50%;
  transform: translate(-50%, -120%);
  z-index: 50;
  padding: .75rem 1.25rem;
  background: var(--sodium); color: var(--hold);
  font: 500 .875rem/1 var(--font-sans);
  border-radius: 0 0 10px 10px;
  text-decoration: none;
  transition: transform .3s var(--ease);
}
.skip-link:focus { transform: translate(-50%, 0); }

/* ══ ambient field ═══════════════════════════════════════════════════════════
   Coverage bloom: soft radial pulses spreading and dissolving. Every bloom
   animates transform + opacity only, so the whole field is compositor work.
   The gradient's own falloff supplies the softness. No filter: blur(). */
.atmosphere {
  position: fixed;
  inset: 0;
  z-index: 0;
  overflow: hidden;
  pointer-events: none;
  background:
    radial-gradient(115% 80% at 50% 108%, rgba(255,140,50,.16), transparent 62%),
    radial-gradient(90% 60% at 12% -8%,   rgba(20,72,112,.42),  transparent 70%),
    var(--hold);
  transition: opacity 1.7s var(--ease) .35s;
}
body.is-ready .atmosphere { opacity: 1; }

.bloom {
  position: absolute;
  border-radius: 50%;
  will-change: transform, opacity;
  animation-name: bloom-drift;
  animation-timing-function: cubic-bezier(.42, 0, .58, 1);
  animation-iteration-count: infinite;
  animation-direction: alternate;
}

@keyframes bloom-drift {
  from { transform: translate3d(0, 0, 0)                 scale(var(--s0)); opacity: var(--o0); }
  to   { transform: translate3d(var(--dx), var(--dy), 0) scale(var(--s1)); opacity: var(--o1); }
}

/* Cool strata up top, sodium warmth blooming from below. */
.bloom--1 {
  --dx: 7vw; --dy: -5vh; --s0: .92; --s1: 1.32; --o0: .5; --o1: 1;
  width: 105vmax; height: 105vmax; left: -38vmax; top: -42vmax;
  background: radial-gradient(circle, var(--bloom-cool), transparent 64%);
  animation-duration: 52s; animation-delay: -6s;
}
.bloom--2 {
  --dx: -6vw; --dy: 4vh; --s0: 1.05; --s1: .78; --o0: .95; --o1: .45;
  width: 88vmax; height: 88vmax; right: -34vmax; top: -20vmax;
  background: radial-gradient(circle, var(--bloom-deep), transparent 66%);
  animation-duration: 43s; animation-delay: -19s;
}
.bloom--3 {
  --dx: 5vw; --dy: 6vh; --s0: .8; --s1: 1.28; --o0: .55; --o1: 1;
  width: 96vmax; height: 96vmax; left: -20vmax; bottom: -46vmax;
  background: radial-gradient(circle, var(--bloom-sodium), transparent 62%);
  animation-duration: 38s; animation-delay: -11s;
}
.bloom--4 {
  --dx: -8vw; --dy: -5vh; --s0: 1.1; --s1: .82; --o0: .85; --o1: .4;
  width: 70vmax; height: 70vmax; right: -22vmax; bottom: -30vmax;
  background: radial-gradient(circle, var(--bloom-amber), transparent 64%);
  animation-duration: 47s; animation-delay: -28s;
}
.bloom--5 {
  --dx: 9vw; --dy: -7vh; --s0: .7; --s1: 1.15; --o0: .35; --o1: .85;
  width: 54vmax; height: 54vmax; left: 32%; top: 28%;
  background: radial-gradient(circle, var(--bloom-nav), transparent 60%);
  animation-duration: 61s; animation-delay: -34s;
}
.bloom--6 {
  --dx: -5vw; --dy: 8vh; --s0: 1.0; --s1: .72; --o0: .7; --o1: .3;
  width: 62vmax; height: 62vmax; left: 6%; top: 46%;
  background: radial-gradient(circle, var(--bloom-sodium), transparent 58%);
  animation-duration: 34s; animation-delay: -3s;
}

/* Static noise, purely to stop gradient banding on 6-bit phone panels. */
.grain {
  position: absolute; inset: 0;
  opacity: .055;
  mix-blend-mode: overlay;
  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='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}

.vignette {
  position: absolute; inset: 0;
  background: radial-gradient(130% 95% at 50% 42%, transparent 40%, rgba(3,11,15,.72) 100%);
}

/* ── layout shell ─────────────────────────────────────────────────────────── */
.masthead, main, .colophon { position: relative; z-index: 1; }

.masthead {
  display: flex;
  flex-wrap: wrap;
  gap: .5rem 1rem;
  align-items: baseline;
  justify-content: space-between;
  padding: .9rem var(--gutter) 0;
  max-width: var(--measure);
  margin-inline: auto;
}
.wordmark {
  font-family: var(--font-display);
  font-variation-settings: 'opsz' 40, 'SOFT' 0, 'WONK' 1;
  font-weight: 600;
  font-size: 1.35rem;
  letter-spacing: -.015em;
  color: var(--paper);
}
.masthead__meta {
  font-family: var(--font-sans);
  font-size: .7rem;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--haze-dim);
}

/* ══ lede ═══════════════════════════════════════════════════════════════════
   One line, sized so it introduces the tool without displacing it. The
   multi-line display headline this replaced was handsome and cost the page
   its entire first screen. */
.lede { max-width: 44rem; }
.lede__title {
  font-family: var(--font-display);
  font-variation-settings: 'opsz' 96, 'SOFT' 0, 'WONK' 1;
  font-weight: 400;
  font-size: clamp(1.65rem, 4.2vw, 2.5rem);
  line-height: 1.1;
  letter-spacing: -.022em;
  text-wrap: balance;
}
/* The one flourish left from the old headline. */
.lede__title em {
  font-style: italic;
  font-weight: 300;
  color: var(--filament);
}
.lede__sub {
  margin-top: .45rem;
  font-size: .95rem;
  line-height: 1.55;
  color: var(--haze);
  max-width: 38rem;
}

/* ══ tool ═══════════════════════════════════════════════════════════════════ */
.tool {
  max-width: var(--measure);
  margin-inline: auto;
  padding: clamp(1rem, 2.5vw, 1.5rem) var(--gutter) clamp(3rem, 8vw, 6rem);
  display: grid;
  gap: clamp(.9rem, 2vw, 1.15rem);
}

/* Controls read as glass over the atmosphere; results read as a solid card
   sitting on top of it. That contrast is the zoning the brief asked for. */
.controls {
  display: grid;
  gap: 1.4rem;
  padding: clamp(1rem, 3vw, 1.4rem);
  border-radius: 20px;
  /* Opaque enough that text contrast is deterministic wherever the blooms
     drift underneath, while still reading as glass over the atmosphere. */
  background: rgba(12, 30, 38, .82);
  border: 1px solid rgba(143, 167, 178, .16);
  backdrop-filter: blur(14px) saturate(1.2);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
}
@media (min-width: 48rem) {
  .controls { grid-template-columns: 1.15fr 1fr; gap: 1.6rem 2.5rem; align-items: start; }
}

/* Sentence case, no tracking: the family was always Plex Sans, but
   wide-tracked uppercase read as a different, more technical face than the
   body text it sits next to. */
.control__label {
  display: block;
  font-family: var(--font-sans);
  font-size: .88rem;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--haze);
}
.control__hint {
  font-family: var(--font-sans);
  font-size: .78rem;
  color: var(--haze-dim);
  margin-top: .1rem;
}
.control__value {
  display: block;
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 1.6rem;
  line-height: 1.15;
  letter-spacing: -.015em;
  color: var(--paper);
  margin: .4rem 0 .15rem;
}
.control__num {
  color: var(--sodium);
  font-variant-numeric: tabular-nums;
}

/* ── slider ───────────────────────────────────────────────────────────────── */
.slider {
  -webkit-appearance: none; appearance: none;
  width: 100%;
  height: 2.75rem;               /* 44px touch target */
  background: transparent;
  cursor: pointer;
  margin: 0;
}
.slider::-webkit-slider-runnable-track {
  height: 3px; border-radius: 3px;
  background:
    linear-gradient(to right, var(--sodium) var(--fill, 20%), rgba(143,167,178,.22) var(--fill, 20%));
}
.slider::-moz-range-track {
  height: 3px; border-radius: 3px;
  background: rgba(143,167,178,.22);
}
.slider::-moz-range-progress {
  height: 3px; border-radius: 3px; background: var(--sodium);
}
.slider::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 26px; height: 26px; margin-top: -11.5px;
  border-radius: 50%; border: none;
  background: var(--filament);
  box-shadow: 0 0 0 1px rgba(6,20,26,.7), 0 0 26px rgba(255,159,74,.6);
  transition: transform .2s var(--ease);
}
.slider::-moz-range-thumb {
  width: 26px; height: 26px;
  border-radius: 50%; border: none;
  background: var(--filament);
  box-shadow: 0 0 0 1px rgba(6,20,26,.7), 0 0 26px rgba(255,159,74,.6);
  transition: transform .2s var(--ease);
}
.slider:active::-webkit-slider-thumb { transform: scale(1.18); }
.slider:active::-moz-range-thumb     { transform: scale(1.18); }
.slider:focus { outline: none; }
.slider:focus-visible::-webkit-slider-thumb {
  box-shadow: 0 0 0 3px var(--hold), 0 0 0 5px var(--sodium), 0 0 26px rgba(255,159,74,.6);
}
.slider:focus-visible::-moz-range-thumb {
  box-shadow: 0 0 0 3px var(--hold), 0 0 0 5px var(--sodium), 0 0 26px rgba(255,159,74,.6);
}

.slider__scale {
  display: flex; justify-content: space-between;
  font-family: var(--font-sans); font-size: .68rem;
  color: var(--haze-dim);
  margin-top: -.35rem;
}

/* ── segmented control ────────────────────────────────────────────────────── */
.segment {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  margin-top: .75rem;
  padding: 4px;
  border-radius: 15px;
  background: rgba(6, 20, 26, .5);
  border: 1px solid rgba(143, 167, 178, .13);
}
.segment__indicator {
  position: absolute;
  top: 4px; bottom: 4px; left: 4px;
  width: calc(50% - 4px);
  border-radius: 11px;
  background: linear-gradient(160deg, rgba(255,159,74,.22), rgba(255,159,74,.09));
  border: 1px solid rgba(255, 159, 74, .38);
  box-shadow: 0 6px 22px rgba(255, 140, 50, .16);
  transition: transform .45s var(--ease);
}
.segment:has(#usage-heavy:checked) .segment__indicator,
.segment:has(#fmt-story:checked)   .segment__indicator { transform: translateX(100%); }

.segment__input { position: absolute; width: 1px; height: 1px; opacity: 0; margin: 0; }
.segment__option {
  position: relative;
  z-index: 1;
  display: grid;
  gap: .1rem;
  padding: .7rem .75rem;
  min-height: 44px;
  align-content: center;
  text-align: center;
  border-radius: 11px;
  cursor: pointer;
  transition: color .3s var(--ease);
  color: var(--haze);
}
.segment__name {
  font-family: var(--font-sans);
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: -.005em;
  text-transform: none;
}
.segment__hint { font-size: .78rem; color: var(--haze-dim); line-height: 1.35; }
.segment__input:checked + .segment__option { color: var(--filament); }
.segment__input:checked + .segment__option .segment__hint { color: var(--haze); }
.segment__input:focus-visible + .segment__option {
  outline: 2px solid var(--sodium);
  outline-offset: 2px;
}
@media (hover: hover) {
  .segment__option:hover { color: var(--paper); }
}

/* ══ results, the calm zone ════════════════════════════════════════════════
   Opaque on purpose. Ambient motion continues behind this card but never
   under the text. Credibility is the product. */
.results {
  border-radius: 22px;
  background: linear-gradient(180deg, #10262F 0%, #0C1D25 100%);
  border: 1px solid rgba(143, 167, 178, .12);
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, .8);
  padding: clamp(1.1rem, 3.5vw, 1.75rem);
}

.results__head {
  display: flex;
  flex-wrap: wrap;
  gap: .85rem;
  align-items: center;
  justify-content: space-between;
  padding-bottom: 1.1rem;
  border-bottom: 1px solid rgba(143, 167, 178, .13);
}
.results__title {
  font-family: var(--font-sans);
  font-size: .78rem;
  font-weight: 500;
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--haze);
}
.results__title span { color: var(--paper); }

.share-btn {
  display: inline-flex; align-items: center; gap: .5rem;
  min-height: 44px;
  padding: .55rem 1.05rem;
  border-radius: 999px;
  border: 1px solid rgba(255, 159, 74, .4);
  background: rgba(255, 159, 74, .1);
  color: var(--filament);
  font: 500 .78rem/1 var(--font-sans);
  letter-spacing: .06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background .25s var(--ease), border-color .25s var(--ease), transform .2s var(--ease);
}
.share-btn svg {
  width: 15px; height: 15px; fill: none;
  stroke: currentColor; stroke-width: 1.7;
  stroke-linecap: round; stroke-linejoin: round;
}
@media (hover: hover) {
  .share-btn:hover { background: rgba(255,159,74,.18); border-color: rgba(255,159,74,.65); }
}
.share-btn:active { transform: scale(.97); }

/* ── rows ─────────────────────────────────────────────────────────────────── */
.rows { display: grid; gap: .6rem; padding-top: 1.1rem; position: relative; }

/* Departing rows are lifted out of flow so the incoming list can lay out
   immediately underneath them while they dissolve. */
.row--ghost {
  position: absolute;
  left: 0; right: 0;
  margin: 0;
  pointer-events: none;
}

.row {
  position: relative;
  padding: 1.05rem 1.1rem 1.15rem;
  border-radius: 14px;
  background: rgba(255, 255, 255, .028);
  border: 1px solid rgba(143, 167, 178, .1);
}

/* Row entrance, staggered by JS via --i. */
.row {
  opacity: 0;
  transform: translateY(10px);
}
body.is-ready .row {
  animation: row-in .62s var(--ease) forwards;
  animation-delay: calc(.5s + var(--i, 0) * .06s);
}
body.rows-settled .row {
  opacity: 1; transform: none; animation: none;
}
@keyframes row-in {
  to { opacity: 1; transform: none; }
}

.row__top {
  display: grid;
  grid-template-columns: auto 1fr auto;
  gap: .25rem .9rem;
  align-items: start;
}
.row__rank {
  font-family: var(--font-sans);
  font-size: .78rem;
  font-variant-numeric: tabular-nums;
  color: var(--haze-dim);
  padding-top: .3rem;
}
.row__id { display: grid; gap: .1rem; align-content: start; padding-top: .05rem; }
.row__provider {
  font-size: 1.02rem;
  font-weight: 500;
  letter-spacing: -.005em;
  color: var(--paper);
}
.row__plan {
  font-family: var(--font-sans);
  font-size: .76rem;
  color: var(--haze);
}
.row__money { display: grid; gap: .05rem; text-align: right; justify-items: end; }
.row__price {
  font-family: var(--font-sans);
  font-weight: 600;
  font-size: 1.55rem;
  line-height: 1.12;
  letter-spacing: -.022em;
  font-variant-numeric: tabular-nums;
  color: var(--paper);
  white-space: nowrap;
}
.row__perday {
  font-family: var(--font-sans);
  font-size: .72rem;
  font-variant-numeric: tabular-nums;
  color: var(--haze-dim);
  white-space: nowrap;
}
.row__topup {
  font-family: var(--font-sans);
  font-size: .68rem;
  color: var(--sodium);
  white-space: nowrap;
}
.row__topup:empty { display: none; }

/* Rank changed on the last recompute, a brief edge flare, then gone. */
.row.is-moved { animation: moved 900ms var(--ease); }
@keyframes moved {
  0%   { box-shadow: 0 0 0 1px rgba(255,159,74,.55), 0 0 26px -6px rgba(255,159,74,.5); }
  100% { box-shadow: 0 0 0 1px rgba(255,159,74,0),   0 0 26px -6px rgba(255,159,74,0); }
}
.row--best.is-moved { animation: none; }

/* Plan facts read as one instrument line, tracked and hairline-separated,
   rather than a row of boxes. Same information, far less furniture. */
.row__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: .2rem .95rem;
  margin: .2rem 0 0;
  font-family: var(--font-sans);
  font-size: .67rem;
  font-weight: 500;
  letter-spacing: .13em;
  text-transform: uppercase;
}
.meta {
  position: relative;
  color: var(--haze);
  white-space: nowrap;
}
.meta + .meta::before {
  content: '';
  position: absolute;
  left: -.53rem;
  top: 50%;
  width: 1px;
  height: .85em;
  transform: translateY(-50%);
  background: rgba(143, 167, 178, .3);
}
.meta--warn { color: var(--sodium); }

.row__reason {
  margin-top: .7rem;
  font-size: .9rem;
  line-height: 1.55;
  color: var(--haze);
  max-width: 46rem;
}
.row--best .row__reason { color: #C3D6DE; }

/* This is the only thing on the page anyone is meant to click, so it is a
   button rather than an underlined link. The prominence is carried by the
   treatment, not by the wording, which stays as dry as the rest of the row. */
.row__cta {
  display: inline-flex;
  align-items: center;
  gap: .55rem;
  margin-top: 1.05rem;
  min-height: 44px;
  padding: .6rem 1.15rem;
  border-radius: 11px;
  border: 1px solid rgba(143, 167, 178, .3);
  background: rgba(234, 242, 245, .05);
  color: var(--paper);
  font-family: var(--font-sans);
  font-size: .8rem;
  font-weight: 500;
  letter-spacing: .01em;
  text-transform: none;
  text-decoration: none;
  transition: background .22s var(--ease), border-color .22s var(--ease), transform .18s var(--ease);
}
.row__arrow { color: var(--sodium); transition: transform .22s var(--ease); }
@media (hover: hover) {
  .row__cta:hover { background: rgba(234, 242, 245, .1); border-color: rgba(143, 167, 178, .5); }
  .row__cta:hover .row__arrow { transform: translateX(3px); }
}
.row__cta:active { transform: scale(.98); }

/* The recommendation is warmer and a size up, but still a quiet surface with
   a defined edge rather than a slab of colour. It should read as the obvious
   thing to press without competing with the price above it. */
.row--best .row__cta {
  margin-top: 1.2rem;
  padding: .75rem 1.35rem;
  font-size: .85rem;
  font-weight: 600;
  background: rgba(255, 159, 74, .13);
  border-color: rgba(255, 159, 74, .5);
  color: var(--filament);
}
@media (hover: hover) {
  .row--best .row__cta:hover {
    background: rgba(255, 159, 74, .21);
    border-color: rgba(255, 159, 74, .8);
  }
}

/* The recommendation, not merely the first row. */
.row--best {
  background:
    radial-gradient(120% 140% at 0% 0%, rgba(255,159,74,.11), transparent 58%),
    rgba(255, 255, 255, .045);
  border-color: rgba(255, 159, 74, .34);
  box-shadow: 0 0 0 1px rgba(255,159,74,.08), 0 18px 44px -22px rgba(255,140,50,.42);
  padding-top: 1.35rem;
}
.row--best .row__price { font-size: 2.05rem; color: var(--filament); }
.row--best .row__provider { font-size: 1.18rem; font-weight: 600; }
.row--best .row__rank { color: var(--sodium); }

.badge {
  position: absolute;
  top: -.62rem; left: 1.1rem;
  font-family: var(--font-sans);
  font-size: .62rem;
  font-weight: 600;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--hold);
  background: var(--nav);
  border-radius: 5px;
  padding: .22rem .5rem;
}

@media (min-width: 34rem) {
  .row { padding: 1.15rem 1.35rem 1.25rem; }
  .row--best .row__price { font-size: 2.35rem; }
  .row__top { gap: .3rem 1.25rem; }
}

/* ── disclosure ───────────────────────────────────────────────────────────
   Sits directly under the results header, in the utility face, stated once
   and plainly. Quiet confidence, not a legal notice: no box, no icon, no
   shouting, just the same weight as every other piece of metadata. */
.disclosure {
  margin: 0;
  padding: .85rem 0 0;
  font-family: var(--font-sans);
  font-size: .72rem;
  line-height: 1.6;
  letter-spacing: .02em;
  color: var(--haze);
  max-width: 46rem;
}

.results__foot {
  margin-top: 1.35rem;
  padding-top: 1.1rem;
  border-top: 1px solid rgba(143, 167, 178, .13);
  font-family: var(--font-sans);
  font-size: .7rem;
  line-height: 1.6;
  color: var(--haze-dim);
  max-width: 46rem;
}

/* ── freshness ────────────────────────────────────────────────────────────
   Past the staleness threshold the date dims and gains a marker, so old
   pricing is obvious to whoever maintains it. */
.freshness { white-space: nowrap; }
.freshness.is-stale { color: var(--sodium); opacity: .75; }
.freshness__flag {
  display: inline-block;
  font-family: var(--font-sans);
  font-size: .62rem;
  font-weight: 600;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--hold);
  background: var(--sodium);
  border-radius: 4px;
  padding: .1rem .32rem;
  vertical-align: .05em;
}

/* The only text on the page sitting directly on the sodium bloom rather than
   on a card, so it needs the brighter token: --haze-dim measures 3.7:1 here
   against the bloom at full strength, --haze measures 5.2:1. */
.colophon {
  max-width: var(--measure);
  margin-inline: auto;
  padding: 0 var(--gutter) 3rem;
  font-family: var(--font-sans);
  font-size: .7rem;
  letter-spacing: .06em;
  color: var(--haze);
}

/* ══ share sheet ════════════════════════════════════════════════════════════ */
.sheet {
  border: none;
  padding: 0;
  background: transparent;
  max-width: min(94vw, 30rem);
  max-height: 92svh;
  color: var(--paper);
  overflow: visible;
}
.sheet::backdrop {
  background: rgba(3, 11, 15, .82);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
}
.sheet__inner {
  background: linear-gradient(180deg, #122A34, #0A1A21);
  border: 1px solid rgba(143, 167, 178, .16);
  border-radius: 20px;
  padding: 1.1rem;
  display: grid;
  gap: 1rem;
  box-shadow: 0 40px 90px -30px rgba(0,0,0,.9);
}
.sheet__head { display: flex; align-items: center; justify-content: space-between; }
.sheet__title {
  font-family: var(--font-sans);
  font-size: .76rem; font-weight: 500;
  letter-spacing: .12em; text-transform: uppercase;
  color: var(--haze);
}
.sheet__close {
  display: grid; place-items: center;
  width: 44px; height: 44px;
  border: none; background: transparent;
  color: var(--haze); cursor: pointer;
  border-radius: 10px;
  transition: color .2s var(--ease), background .2s var(--ease);
}
.sheet__close svg { width: 17px; height: 17px; fill: none; stroke: currentColor; stroke-width: 1.8; stroke-linecap: round; }
@media (hover: hover) { .sheet__close:hover { color: var(--paper); background: rgba(255,255,255,.06); } }

.sheet__stage { display: grid; place-items: center; }
.sheet__canvas {
  display: block;
  width: 100%;
  height: auto;
  max-height: 56svh;
  object-fit: contain;
  border-radius: 12px;
  background: var(--hold);
}
.sheet__controls {
  display: grid;
  gap: .75rem;
  grid-template-columns: 1fr;
}
.segment--sm { margin-top: 0; }
.segment--sm .segment__option { padding: .5rem .6rem; }

.dl-btn {
  min-height: 46px;
  border-radius: 12px;
  border: none;
  background: var(--sodium);
  color: #14100B;
  font: 600 .82rem/1 var(--font-sans);
  letter-spacing: .07em;
  text-transform: uppercase;
  cursor: pointer;
  transition: filter .2s var(--ease), transform .18s var(--ease);
}
@media (hover: hover) { .dl-btn:hover { filter: brightness(1.09); } }
.dl-btn:active { transform: scale(.98); }

@media (min-width: 26rem) {
  .sheet__controls { grid-template-columns: 1fr auto; align-items: center; }
  .dl-btn { padding-inline: 1.5rem; }
}

/* ══ entrance choreography ══════════════════════════════════════════════════
   One sequence: type, then the field wakes, then the tool settles in. */
[data-enter] { opacity: 0; transform: translateY(1.1rem); }
body.is-ready [data-enter] {
  animation: enter .95s var(--ease) forwards;
  animation-delay: var(--d, 0s);
}
@keyframes enter { to { opacity: 1; transform: none; } }

[data-enter="1"] { --d: .06s; }   /* lede       */
[data-enter="2"] { --d: .20s; }   /* calculator */
[data-enter="3"] { --d: .38s; }   /* results    */

/* ══ reduced motion, non-negotiable ════════════════════════════════════════
   The field freezes into a single static gradient; nothing choreographs,
   nothing counts up, and the FLIP reorder is skipped in JS. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }

  .bloom { animation: none; }
  .bloom--1 { transform: scale(1.1); opacity: .8; }
  .bloom--2 { transform: scale(.95); opacity: .7; }
  .bloom--3 { transform: scale(1.05); opacity: .85; }
  .bloom--4 { transform: scale(.95); opacity: .6; }
  .bloom--5, .bloom--6 { display: none; }

  .atmosphere { transition: none; opacity: 1; }
  body.is-loading .atmosphere { opacity: 1; }

  [data-enter],
  .row {
    opacity: 1 !important;
    transform: none !important;
    animation: none !important;
  }
  .segment__indicator,
  .row__cta,
  .share-btn,
  .skip-link { transition: none; }
  *, *::before, *::after { scroll-behavior: auto !important; }
}

/* ══ small screens ═════════════════════════════════════════════════════════
   Three blooms instead of six. Same composition, a third of the overdraw. */
@media (max-width: 40rem) {
  .bloom--2, .bloom--5, .bloom--6 { display: none; }
  .bloom--1 { width: 130vmax; height: 130vmax; }
  .controls { backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); }

  .row__top { grid-template-columns: auto 1fr; }
  .row__money {
    grid-column: 2;
    text-align: left;
    justify-items: start;
    margin-top: .6rem;
  }

  /* Share sat on its own line under the heading and cost a full row. Shrink
     it and let it share the line instead. */
  .results__head { flex-wrap: nowrap; gap: .7rem; align-items: center; }
  .results__title { font-size: .72rem; letter-spacing: .07em; }
  .share-btn {
    flex-shrink: 0;
    min-height: 40px;
    padding: .45rem .8rem;
    font-size: .74rem;
    letter-spacing: .04em;
  }
  .share-btn__more { display: none; }
}

/* Very short viewports: keep the calculator on screen. */
@media (max-height: 34rem) {
  .lede__sub { display: none; }
  .tool { padding-top: .75rem; }
}

/* ══ contrast audit ═════════════════════════════════════════════════════════
   Measured, not eyeballed: the page was rasterised with all text forced
   transparent and every bloom pinned to full opacity at 1.3× scale, a
   conservative upper bound on background brightness that no real animation
   frame reaches, then the composited pixels behind each text element were
   sampled and ratioed against its computed colour.

   Worst ratios at the time of writing (WCAG AA body text needs 4.5:1):

     .colophon p          5.2   on the sodium bloom, brightest point on the page
     .row__perday         5.6   on the results card
     .control__hint       6.2   inside the glass controls panel
     .slider__scale span  6.2   inside the glass controls panel
     .masthead__meta      6.6   on the atmosphere
     .results__foot       7.1   on the results card (#0C1D25, opaque)
     .lede__sub           8.3   on the atmosphere
     .meta                9.4   on the results card
     .row__reason        10.1   on the results card
     .segment__name      11.0   inside the glass controls panel

   Two things keep this stable rather than lucky: the controls panel is 82%
   opaque, so drifting blooms cannot lighten what sits on it by more than a
   couple of percent, and the results card is fully opaque. Raise --haze or
   --haze-dim if either surface is ever made more transparent.
   ============================================================================= */

/* ── estimated figures ────────────────────────────────────────────────────
   Anything derived from TUNING.shortfallCostPerGB is a model output, not a
   quoted price. It gets a visible marker and a tooltip rather than being
   presented with the same confidence as a plan price. */
.est {
  font-size: .92em;
  font-style: italic;
  opacity: .85;
  letter-spacing: .01em;
}
.row__topup { cursor: help; }

/* ── card density ─────────────────────────────────────────────────────────
   The rows were six stacked bands: provider, plan name, price, per-day,
   a boxed fact row, a full-sentence reason, then the button. Provider and
   facts now share the top block, the plan name is left to the button and the
   screen-reader label, and the reason is a few words rather than a sentence.
   Four bands instead of six, scannable at a glance. */
.row { padding: .95rem 1.05rem 1rem; }
.row__reason {
  margin-top: .7rem;
  font-size: .88rem;
  line-height: 1.45;
  color: var(--haze);
}
.row__cta { margin-top: .8rem; }
.row--best { padding-top: 1.2rem; }
.row--best .row__cta { margin-top: .95rem; }

@media (min-width: 34rem) {
  .row { padding: 1.05rem 1.25rem 1.1rem; }
}

/* The description sits under the headline at every width. It rode alongside
   it on wide screens, which read as two separate statements rather than one
   introduction. */


/* ── reserving the results height ─────────────────────────────────────────
   The list renders empty on first paint and gains five rows a moment later,
   which pushed the footer down and cost 0.043 CLS. Reserving close to the
   real height while it is empty removes the shift. The value tracks the
   rendered rows (one best-fit row plus four standard ones); it only has to
   be approximately right, since any residual difference is a fraction of
   what an unreserved list costs. */
.rows:empty {
  min-height: 58rem;
  display: block;
}
@media (max-width: 40rem) {
  .rows:empty { min-height: 72rem; }
}

/* ── country picker ───────────────────────────────────────────────────────
   Collapsed by default: the whole point of the fold work was that the two
   questions people always answer stay visible, and this is a third question
   most travellers will skip. A <details> costs one row shut and expands to a
   scrollable grid when someone does care. */
.countries { margin-top: .5rem; }
.countries__summary {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .75rem;
  min-height: 44px;
  padding: .55rem .9rem;
  border-radius: 12px;
  border: 1px solid rgba(143, 167, 178, .22);
  background: rgba(6, 20, 26, .5);
  color: var(--paper);
  font-size: .95rem;
  cursor: pointer;
  list-style: none;
  transition: border-color .2s var(--ease);
}
.countries__summary::-webkit-details-marker { display: none; }
.countries__summary svg {
  width: 16px; height: 16px; flex-shrink: 0;
  fill: none; stroke: var(--haze); stroke-width: 2;
  stroke-linecap: round; stroke-linejoin: round;
  transition: transform .25s var(--ease);
}
.countries[open] .countries__summary svg { transform: rotate(180deg); }
.countries[open] .countries__summary { border-color: rgba(255, 159, 74, .45); }
@media (hover: hover) {
  .countries__summary:hover { border-color: rgba(143, 167, 178, .45); }
}
.countries__summary:focus-visible { outline: 2px solid var(--sodium); outline-offset: 2px; }

.countries__panel {
  margin-top: .5rem;
  padding: .75rem .9rem .9rem;
  border-radius: 12px;
  border: 1px solid rgba(143, 167, 178, .16);
  background: rgba(6, 20, 26, .55);
}
.countries__actions { display: flex; justify-content: flex-end; margin-bottom: .5rem; }
.countries__clear {
  border: none;
  background: transparent;
  color: var(--sodium);
  font: 500 .8rem var(--font-sans);
  cursor: pointer;
  padding: .3rem .2rem;
  min-height: 32px;
}
.countries__clear:focus-visible { outline: 2px solid var(--sodium); outline-offset: 2px; }

.countries__list {
  display: grid;
  /* 7.5rem gets two columns onto a 390px phone, which halves the scrolling
     through 45 entries. Long names wrap rather than forcing one column. */
  grid-template-columns: repeat(auto-fill, minmax(7.5rem, 1fr));
  gap: .1rem .6rem;
  max-height: 14rem;
  overflow-y: auto;
  margin: 0;
}
.country {
  display: flex;
  align-items: center;
  gap: .5rem;
  min-height: 34px;
  font-size: .84rem;
  line-height: 1.25;
  color: var(--haze);
  cursor: pointer;
}
.country input {
  accent-color: var(--sodium);
  width: 15px; height: 15px;
  flex-shrink: 0;
  cursor: pointer;
}
.country input:checked + span { color: var(--paper); }
.country input:focus-visible { outline: 2px solid var(--sodium); outline-offset: 2px; }

/* Plans whose coverage nobody has confirmed. Shown, but never silently
   presented as if they were checked. */
.meta--unknown { color: var(--haze-dim); font-style: italic; }

.results__filtered {
  margin: 0 0 .1rem;
  padding: .7rem 0 0;
  font-size: .8rem;
  color: var(--haze-dim);
}
.results__filtered:empty { display: none; padding: 0; }

/* A row whose affiliate link is not live yet. Keeps the price, which is real
   and worth comparing, but never presents a placeholder URL as a button. */
.row__cta--pending {
  cursor: default;
  border-style: dashed;
  border-color: rgba(143, 167, 178, .28);
  background: transparent;
  color: var(--haze-dim);
}
.row__cta--pending .row__arrow { display: none; }
.row--best .row__cta--pending {
  background: transparent;
  border-color: rgba(255, 159, 74, .3);
  color: var(--haze);
}
@media (hover: hover) {
  .row__cta--pending:hover { background: transparent; border-color: rgba(143, 167, 178, .28); }
}
