/* ==========================================================================
   Rxference - site styles
   --------------------------------------------------------------------------
   One stylesheet, no framework, no build step. The palette is not invented
   here: every colour below is lifted from THEMES["dark"] in main.py, so the
   demo overlay on the landing page is painted in the application's own colours
   rather than an approximation of them. Change one and they drift.

   The page background is #0d1219 - the ground baked into the logo art itself.
   That does two things at once: the wordmark can never show a seam, and the
   app's own #14171c card reads as genuinely elevated above the page, which is
   the whole idea of a floating overlay.
   ========================================================================== */

/* --------------------------------------------------------------- type stack
   No webfont, and specifically no font CDN. The site used to @import Inter
   from fonts.googleapis.com, which means every visitor's browser announces
   their IP address to Google before the first paint - the single most
   litigated GDPR item for a small site, and flatly at odds with cookies.html
   telling readers that loading a page from us contacts nobody but us.
   check_site.check_no_external_requests() now refuses any third-party
   subresource, so this cannot come back by accident.

   The replacement is the operating system's own UI face, which on every
   platform this site is read on is a better-fitted typeface than Inter and
   arrives in zero bytes. Clinical software is read on locked-down Windows
   more than anywhere else, so Segoe UI Variable leads.

   Numerals are tabular everywhere by default. This is a site whose body copy
   is full of counts - 9,285 edges, 8,343 drugs, 1,996 major - and proportional
   figures make a column of them ripple. */
:root {
  --font-ui: 'Segoe UI Variable Text', 'Segoe UI', -apple-system,
             BlinkMacSystemFont, 'SF Pro Text', system-ui, 'Helvetica Neue',
             Arial, sans-serif;
  --font-display: 'Segoe UI Variable Display', 'Segoe UI', -apple-system,
                  BlinkMacSystemFont, 'SF Pro Display', system-ui,
                  'Helvetica Neue', Arial, sans-serif;
  --font-mono: ui-monospace, 'Cascadia Mono', 'SF Mono', Menlo, Consolas,
               monospace;

  /* Page */
  --bg: #0d1219;
  --bg-2: #10151c;
  /* The app's own surfaces */
  --surface: #14171c;
  --raised: #1d222a;
  --hover: #272e38;
  --line: #212832;
  --line-2: #2f3742;
  /* Inputs need their own, lighter, border. --line-2 reads at 2.1:1 against
     the field background, and since the field background is within 1.03:1 of
     the page there is nothing else marking where the control is - so that
     border IS the control's boundary and WCAG 1.4.11 wants 3:1 for it. */
  --field-line: #5a6478;
  /* Ink */
  --text: #e9edf2;
  --muted: #8b95a4;
  /* Raised from #69737f, which sat at 3.3-3.9:1 on every background it was
     used on and so failed WCAG 2.1 AA (4.5:1) for normal text - and it was
     used for real text: footer navigation, form help, form notes, demo
     labels. It is now close to --muted, which is the honest consequence of
     the constraint: on a #0d1219 ground there is not room for three distinct
     greys that all clear 4.5:1. Hierarchy below --muted is carried by size
     and weight instead of by a third colour, which is better typography than
     it was anyway. */
  --dim: #8792a0;
  /* Brand */
  --accent: #4ec9b0;
  --accent-deep: #35a48e;
  --accent-wash: rgba(78, 201, 176, 0.09);
  /* Severity - also straight from the app */
  --major: #ff6b6b;
  --moderate: #ffb454;
  --minor: #7ea6d8;

  --radius: 12px;
  --radius-sm: 8px;
  --shell: 1120px;
  --gutter: clamp(20px, 5vw, 40px);

  /* One shadow, used for anything that floats. */
  --lift: 0 1px 2px rgba(0, 0, 0, .3), 0 18px 40px -12px rgba(0, 0, 0, .65);

  --ease: cubic-bezier(.22, .61, .36, 1);
}

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

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
  /* Anchored sections must clear the sticky nav. */
  scroll-padding-top: 88px;
}
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: .01ms !important;
    transition-duration: .01ms !important;
  }
}

html { scroll-behavior: smooth; }
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font: 400 16px/1.65 var(--font-ui);
  /* Tabular figures site-wide. See the note on the type stack above. */
  font-variant-numeric: tabular-nums;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

img { max-width: 100%; display: block; height: auto; }
a { color: inherit; }

h1, h2, h3, h4 {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 600;
  line-height: 1.12;
  /* Optical tracking: the display face needs more negative tracking at hero
     sizes than at h3, and applying one value to all four left the small
     headings looking cramped. */
  letter-spacing: -0.022em;
  text-wrap: balance;
}
h1 { letter-spacing: -0.034em; }
h2 { letter-spacing: -0.026em; }
h1 {
  font-size: clamp(2.2rem, 5.6vw, 3.65rem);
  /* Let the browser even out the lines rather than hard-coding a <br>: a
     fixed break that reads well at 1440px turns into a widow at 1100px. */
  text-wrap: balance;
}
h2 { font-size: clamp(1.6rem, 3.4vw, 2.3rem); text-wrap: balance; }
h3 { font-size: 1.06rem; letter-spacing: -0.015em; }
p { margin: 0; }

::selection { background: rgba(78, 201, 176, .26); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

.skip {
  position: absolute;
  left: -9999px;
  top: 8px;
  z-index: 200;
  padding: 10px 16px;
  background: var(--accent);
  color: #06231d;
  border-radius: var(--radius-sm);
  font-weight: 600;
  text-decoration: none;
}
.skip:focus { left: 12px; }

/* -------------------------------------------------------------- structure */
.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

section { position: relative; }

.band { padding-block: clamp(64px, 9vw, 112px); }
.band + .band { border-top: 1px solid var(--line); }
.band--tint { background: linear-gradient(180deg, var(--bg-2), var(--bg)); }

.section-head { max-width: 620px; margin-bottom: clamp(32px, 5vw, 52px); }
.section-head.center { margin-inline: auto; text-align: center; }

.eyebrow {
  margin: 0 0 14px;
  font-size: .74rem;
  font-weight: 600;
  letter-spacing: .13em;
  text-transform: uppercase;
  color: var(--accent);
}
.lede {
  margin-top: 18px;
  text-wrap: pretty;
  font-size: clamp(1rem, 1.6vw, 1.14rem);
  line-height: 1.62;
  color: var(--muted);
}

/* ------------------------------------------------------------------- nav */
.nav {
  position: sticky;
  top: 0;
  z-index: 100;
  border-bottom: 1px solid transparent;
  background: rgba(13, 18, 25, .78);
  backdrop-filter: blur(14px) saturate(150%);
  -webkit-backdrop-filter: blur(14px) saturate(150%);
  transition: border-color .25s var(--ease), background .25s var(--ease);
}
.nav[data-scrolled='true'] {
  border-bottom-color: var(--line);
  background: rgba(13, 18, 25, .92);
}
.nav-in {
  display: flex;
  align-items: center;
  gap: 12px;
  height: 68px;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* The wordmark is the brand. It is an image, not type, so it is never
   re-created in CSS - only sized. */
.brand { display: flex; align-items: center; text-decoration: none; margin-right: auto; }
.brand img { height: 22px; width: auto; }
.brand:hover { opacity: .82; }

.nav-links {
  display: flex;
  align-items: center;
  gap: 4px;
  list-style: none;
  margin: 0;
  padding: 0;
}
.nav-links a {
  display: block;
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  color: var(--muted);
  font-size: .92rem;
  font-weight: 500;
  text-decoration: none;
  transition: color .16s, background .16s;
}
.nav-links a:hover { color: var(--text); background: var(--raised); }
.nav-links a[aria-current='page'] { color: var(--text); }

.nav-cta { margin-left: 8px; }

.nav-toggle {
  display: none;
  width: 40px; height: 40px;
  padding: 0;
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text);
  cursor: pointer;
}
.nav-toggle svg { margin: auto; }

@media (max-width: 860px) {
  .nav-toggle { display: flex; }
  .nav-panel {
    position: absolute;
    inset-inline: 0;
    top: 100%;
    display: none;
    padding: 12px var(--gutter) 20px;
    border-bottom: 1px solid var(--line);
    background: var(--bg);
  }
  .nav-panel[data-open='true'] { display: block; }
  .nav-links { flex-direction: column; align-items: stretch; gap: 2px; }
  .nav-links a { padding: 12px; font-size: 1rem; }
  .nav-cta { margin: 12px 0 0; }
  .nav-cta .btn { width: 100%; }
}
@media (min-width: 861px) {
  .nav-panel { display: contents; }
}

/* --------------------------------------------------------------- buttons */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 13px 22px;
  border: 1px solid transparent;
  border-radius: 10px;
  font: inherit;
  font-size: .95rem;
  font-weight: 600;
  letter-spacing: -0.01em;
  text-decoration: none;
  cursor: pointer;
  white-space: nowrap;
  transition: transform .15s var(--ease), background .18s, border-color .18s,
              box-shadow .18s, color .18s;
}
.btn:active { transform: translateY(1px); }

.btn--primary {
  background: linear-gradient(180deg, var(--accent), var(--accent-deep));
  color: #052b23;
  box-shadow: 0 1px 0 rgba(255, 255, 255, .18) inset,
              0 8px 24px -8px rgba(78, 201, 176, .55);
}
.btn--primary:hover {
  box-shadow: 0 1px 0 rgba(255, 255, 255, .22) inset,
              0 12px 30px -8px rgba(78, 201, 176, .7);
}
.btn--ghost {
  background: transparent;
  border-color: var(--line-2);
  color: var(--text);
}
.btn--ghost:hover { background: var(--raised); border-color: #3c4655; }
.btn--sm { padding: 9px 15px; font-size: .875rem; }
.btn--lg { padding: 16px 30px; font-size: 1.02rem; }
.btn--block { width: 100%; }

/* The line under the main call to action. Deliberately small: it is for the
   minority who already have the app, and must not compete with the download. */
.cta-sub {
  margin-top: 14px;
  font-size: .82rem;
  color: var(--dim);
}
.cta-sub a {
  color: var(--muted);
  text-decoration: underline;
  text-decoration-color: rgba(139, 149, 164, .45);
  text-underline-offset: 3px;
  transition: color .16s, text-decoration-color .16s;
}
.cta-sub a:hover { color: var(--accent); text-decoration-color: var(--accent); }

.cta-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}
/* Centring a flex row needs justify-content; the `text-align: center` on the
   hero does nothing for flex children. The hero was missing this and its two
   buttons sat 175px left of centre inside a centred 780px block - close enough
   to look like a mistake rather than a choice. */
.center .cta-row,
.hero .cta-row { justify-content: center; }

/* ------------------------------------------------------------------ hero */
.hero {
  position: relative;
  padding-block: clamp(56px, 9vw, 104px) clamp(28px, 4vw, 44px);
  text-align: center;
  overflow: hidden;
}
/* A single soft wash behind the headline. Cheap, and it keeps the top of the
   page from reading as a flat black rectangle. */
.hero::before {
  content: '';
  position: absolute;
  top: -340px;
  left: 50%;
  width: 900px;
  height: 620px;
  transform: translateX(-50%);
  background: radial-gradient(50% 50% at 50% 50%,
              rgba(78, 201, 176, .16), transparent 72%);
  pointer-events: none;
}
.hero-in { position: relative; max-width: 780px; margin-inline: auto; }

/* The pitch and the download sit in a second .hero block below the demo, so
   the headline can lead straight into the thing it describes. That block wants
   the hero's centring and width but none of its top padding - it follows a
   stage, not a nav bar - and none of its glow, which belongs to the headline
   alone and would otherwise appear twice on one page. */
.hero--tail { padding-block: 0 clamp(48px, 7vw, 88px); }
.hero--tail::before { content: none; }

.pill-tag {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 26px;
  padding: 6px 8px 6px 6px;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  background: var(--surface);
  font-size: .8rem;
  color: var(--muted);
}
.pill-tag b {
  padding: 2px 9px;
  border-radius: 999px;
  background: var(--accent-wash);
  color: var(--accent);
  font-weight: 600;
  font-size: .74rem;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.hero h1 .accent { color: var(--accent); }
.hero .lede { max-width: 620px; margin-inline: auto; }
.hero .cta-row { margin-top: 34px; }

.hero-meta {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px 20px;
  margin-top: 30px;
  font-size: .81rem;
  color: var(--dim);
}
.hero-meta span { display: inline-flex; align-items: center; gap: 7px; }
.hero-meta svg { flex: none; color: var(--accent); }

/* ----------------------------------------------------------- demo stage */
/* Tightened from clamp(56px, 8vw, 96px): the demo used to be followed by a
   section with its own top padding, and now it is followed by the pitch, which
   has none. */
.stage-wrap { padding-bottom: clamp(28px, 4vw, 44px); }

/* The abstract document the overlay floats above. Deliberately abstract:
   inventing a patient chart - even an obviously fake one - to sell a clinical
   tool is a bad idea, so this suggests a document and says nothing. */
.stage {
  position: relative;
  border: 1px solid var(--line);
  border-radius: 16px;
  background:
    linear-gradient(180deg, rgba(255, 255, 255, .022), transparent 40%),
    var(--surface);
  box-shadow: var(--lift);
  overflow: hidden;
}
.stage-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  background: rgba(255, 255, 255, .014);
}
.stage-dots { display: flex; gap: 6px; }
.stage-dots i {
  width: 9px; height: 9px;
  border-radius: 50%;
  background: var(--line-2);
}
.stage-label {
  margin-left: 6px;
  font-size: .75rem;
  color: var(--dim);
  letter-spacing: .02em;
}
.stage-body {
  position: relative;
  min-height: 560px;
  padding: 34px clamp(18px, 4vw, 46px);
}
/* "Illustration", stated in the chrome rather than left to be inferred. The
   backdrop is now recognisable enough as a clinical system that saying so is
   worth the eight characters. */
.stage-tag {
  margin-left: auto;
  font-size: .62rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dim);
  border: 1px solid var(--line);
  border-radius: 3px;
  padding: 2px 6px;
  opacity: .7;
}

/* The application underneath.

   Every value here is tuned to lose. It carries the *shape* of a clinical
   system - rail, tabs, toolbar, two columns - at an opacity and contrast that
   keep it firmly behind the overlay, because the moment a visitor starts
   reading the backdrop the demo has failed. The shapes are large and few for
   the same reason: enough to say "an application", not enough to look at. */
.ghost-app {
  display: flex;
  gap: 0;
  max-width: 760px;
  border: 1px solid var(--line);
  border-radius: 10px;
  overflow: hidden;
  background: rgba(255, 255, 255, .012);
  opacity: .46;
  user-select: none;
}

.ghost-rail {
  flex: 0 0 46px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 14px 0;
  border-right: 1px solid var(--line);
  background: rgba(255, 255, 255, .016);
}
.ghost-rail i {
  width: 17px; height: 17px;
  border-radius: 5px;
  background: var(--raised);
}
.ghost-rail i.dot { border-radius: 50%; background: var(--hover); }

.ghost-main { flex: 1 1 auto; min-width: 0; }

.ghost-tabs {
  display: flex;
  gap: 4px;
  padding: 10px 14px 0;
  border-bottom: 1px solid var(--line);
}
.ghost-tabs i {
  height: 11px;
  width: 58px;
  border-radius: 4px 4px 0 0;
  background: var(--raised);
  opacity: .6;
}
.ghost-tabs i.on { background: var(--hover); opacity: 1; width: 74px; }

.ghost-tools {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 9px 14px;
  border-bottom: 1px solid var(--line);
}
.ghost-tools i.btn {
  height: 13px; width: 30px;
  border-radius: 3px;
  background: var(--raised);
}
.ghost-tools i.grow { flex: 1 1 auto; }

.ghost-cols { display: flex; gap: 20px; padding: 16px 14px 20px; }
.ghost-col { flex: 1 1 auto; display: flex; flex-direction: column; gap: 11px; min-width: 0; }
.ghost-col.narrow { flex: 0 0 34%; }
.ghost-col i {
  height: 8px;
  border-radius: 4px;
  background: linear-gradient(90deg, var(--raised), rgba(29, 34, 42, .3));
}
.ghost-col i.h { height: 12px; width: 52%; background: var(--hover); }
.ghost-col i.s { width: 64%; }
.ghost-col i.m { width: 86%; }
.ghost-col i.gap { background: none; height: 9px; }
.ghost-col i.card {
  height: 54px;
  border-radius: 7px;
  border: 1px solid var(--line);
  background: rgba(255, 255, 255, .014);
}

/* The coach mark.

   Anchored to the stage rather than the overlay so it cannot cover the thing
   it is pointing at, and `pointer-events: none` on the body so it can never
   swallow a click meant for the demo - only its dismiss button takes one. */
.demo-coach {
  position: absolute;
  left: clamp(18px, 4vw, 46px);
  bottom: 22px;
  z-index: 4;
  display: flex;
  align-items: center;
  gap: 10px;
  max-width: min(330px, calc(100% - 36px));
  padding: 10px 10px 10px 14px;
  border: 1px solid var(--accent-line, var(--line));
  border-radius: 9px;
  background: var(--raised);
  box-shadow: var(--lift);
  font-size: .82rem;
  line-height: 1.45;
  color: var(--text);
  pointer-events: none;
  opacity: 0;
  transform: translateY(6px);
  transition: opacity .32s ease, transform .32s ease;
}
.demo-coach.show { opacity: 1; transform: none; }
.demo-coach[hidden] { display: none; }
.demo-coach-text { flex: 1 1 auto; min-width: 0; }
.demo-coach-text[hidden], .demo-coach-go[hidden] { display: none; }

/* The actionable step. It has to look pressable without looking like the
   page's primary call to action - the thing being sold is below, and a hint
   that outshouts it would be working against the page it is helping. So:
   the accent on the text and the border, not a filled button. */
.demo-coach-go {
  flex: 1 1 auto;
  min-width: 0;
  pointer-events: auto;
  text-align: left;
  font: inherit;
  color: var(--text);
  background: rgba(255, 255, 255, .02);
  border: 1px solid var(--line-2);
  border-radius: 6px;
  padding: 7px 11px;
  cursor: pointer;
  transition: background .18s ease, border-color .18s ease, transform .18s ease;
}
.demo-coach-go:hover {
  background: var(--hover);
  border-color: var(--accent);
}
.demo-coach-go:active { transform: translateY(1px); }
.demo-coach-go:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.demo-coach-go b { color: var(--accent); }
@media (prefers-reduced-motion: reduce) {
  .demo-coach-go { transition: none; }
  .demo-coach-go:active { transform: none; }
}
.demo-coach b { color: var(--accent); font-weight: 600; }
.demo-coach kbd {
  font: inherit;
  color: var(--accent);
  border: 1px solid var(--line-2);
  border-radius: 3px;
  padding: 0 5px;
}
.demo-coach-x {
  pointer-events: auto;
  flex: 0 0 auto;
  width: 22px; height: 22px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 5px;
  background: none;
  color: var(--dim);
  font-size: .72rem;
  cursor: pointer;
}
.demo-coach-x:hover { background: var(--hover); color: var(--text); }
.demo-coach-x:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }

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

@media (max-width: 760px) {
  .stage-body { min-height: 0; padding: 22px 16px 26px; }
  .ghost-app { display: none; }
  .stage-tag { display: none; }
  /* Below the overlay rather than over it: on a phone the stage is barely
     taller than the window itself, and a floating hint would land on the
     search box it is asking you to use. */
  .demo-coach {
    position: static;
    max-width: none;
    margin: 14px 0 0;
    transform: none;
  }
}

/* ------------------------------------------------ the overlay replica --
   A faithful copy of the app's chrome: 1px border as the window frame, a
   #14171c card, 34px header, 20px footer. Sizes track main.py's constants
   (DEFAULT_W 350, HEADER_H 34, FOOTER_H 20, PILL_SIZE 54, GUTTER 10). */
.rx {
  position: absolute;
  top: 58px;
  right: clamp(18px, 5vw, 62px);
  width: 350px;
  padding: 1px;
  border-radius: 7px;
  background: var(--line-2);
  box-shadow: 0 2px 6px rgba(0, 0, 0, .45), 0 26px 60px -18px rgba(0, 0, 0, .85);
  font-size: 13px;
  transition: opacity .25s var(--ease);
}
.rx * { box-sizing: border-box; }
.rx-card {
  display: flex;
  flex-direction: column;
  border-radius: 6px;
  background: var(--rx-bg, #14171c);
  overflow: hidden;
}

/* Light theme, driven by the demo's own gear menu. Same values as
   THEMES["light"] in main.py. */
.rx[data-theme='light'] {
  background: #ccd5de;
  --rx-bg: #fbfcfd;
  --rx-elev: #eef2f6;
  --rx-hover: #dee5ec;
  --rx-line: #ccd5de;
  --rx-text: #1a2029;
  --rx-muted: #5f6b7a;
  --rx-accent: #0d7d69;
  --rx-grip: #b6c1cc;
  --rx-major: #c62828;
  --rx-moderate: #a85800;
  --rx-minor: #2b6cb0;
}
.rx {
  --rx-bg: #14171c;
  --rx-elev: #1d222a;
  --rx-hover: #272e38;
  --rx-line: #2f3742;
  --rx-text: #e9edf2;
  --rx-muted: #8b95a4;
  --rx-accent: #4ec9b0;
  --rx-grip: #3a434f;
  --rx-major: #ff6b6b;
  --rx-moderate: #ffb454;
  --rx-minor: #7ea6d8;
}

.rx-head {
  display: flex;
  align-items: center;
  height: 34px;
  padding-inline: 10px;
  flex: none;
}
.rx-mark { color: var(--rx-accent); font-size: 15px; font-weight: 700; }
.rx-name {
  margin-left: 7px;
  color: var(--rx-text);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .01em;
}
.rx-head-sp { margin-left: auto; }
.rx-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 26px; height: 24px;
  border: 0;
  border-radius: 4px;
  background: transparent;
  color: var(--rx-muted);
  font: inherit;
  font-size: 12px;
  cursor: pointer;
  transition: background .14s, color .14s;
}
.rx-btn:hover { background: var(--rx-hover); color: var(--rx-text); }
.rx-btn[aria-expanded='true'] { background: var(--rx-hover); color: var(--rx-text); }

.rx-search {
  display: flex;
  align-items: center;
  gap: 6px;
  margin: 0 10px;
  padding: 7px 9px;
  border-radius: var(--radius-sm);
  background: var(--rx-elev);
}
.rx-search svg { flex: none; color: var(--rx-muted); }
.rx-search input {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: none;
  color: var(--rx-text);
  font: inherit;
  font-size: 13.5px;
  outline: none;
}
/* The demo's search box is the main interactive element on the landing page,
   and it had no keyboard focus indicator at all. `.rx-search input` sets
   `outline: none` unconditionally, and at (0,1,1) it outranks the global
   `:focus-visible` rule at (0,1,0) - so the ring never applied. Restored here
   at matching specificity, inset so it does not spill out of the simulated
   window chrome. */
.rx-search input:focus-visible {
  outline: 2px solid var(--rx-accent);
  outline-offset: -1px;
  border-radius: 3px;
}
.rx-search input::placeholder { color: var(--rx-muted); }
.rx-clear {
  border: 0; background: none; padding: 0 2px;
  color: var(--rx-muted); cursor: pointer; font-size: 12px;
}

/* Suggestions are placed over the card in the app, not packed into it. */
.rx-drop {
  position: absolute;
  z-index: 4;
  left: 10px; right: 10px;
  margin-top: 3px;
  max-height: 216px;
  overflow-y: auto;
  border: 1px solid var(--rx-line);
  border-radius: var(--radius-sm);
  background: var(--rx-elev);
  box-shadow: 0 14px 30px -10px rgba(0, 0, 0, .8);
}
.rx-drop[hidden] { display: none; }
/* Selector follows the markup: the suggestion rows became role="option"
   divs rather than buttons, because a listbox may not contain buttons and the
   buttons were unreachable by keyboard anyway. See demo.js showSuggestions. */
.rx-drop [role='option'] {
  display: block;
  width: 100%;
  padding: 7px 11px;
  border: 0;
  background: none;
  color: var(--rx-text);
  font: inherit;
  font-size: 13.5px;
  text-align: left;
  cursor: pointer;
}
.rx-drop [role='option'] small { color: var(--rx-muted); }
.rx-drop [role='option'][aria-selected='true'] { background: var(--rx-hover); }
.rx-drop [role='option'][aria-selected='true'],
.rx-drop [role='option'][aria-selected='true'] small { color: var(--rx-accent); }

.rx-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px 0;
}
/* An author `display` beats the user agent's rule for [hidden], so without
   this the attribute is inert. The app hides this row on its welcome screen
   (main.py, _show_welcome) and the demo should match it. */
.rx-bar[hidden] { display: none; }
.rx-title {
  color: var(--rx-text);
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.015em;
  margin-right: auto;
}
.rx-copy {
  border: 0;
  border-radius: 5px;
  padding: 4px 8px;
  background: var(--rx-elev);
  color: var(--rx-accent);
  font: inherit; font-size: 11px; font-weight: 700;
  cursor: pointer;
}
.rx-copy:hover { background: var(--rx-hover); }

.rx-pane {
  flex: 1 1 auto;
  min-height: 0;
  max-height: 300px;
  overflow-y: auto;
  padding: 6px 10px 0;
  scrollbar-width: thin;
  scrollbar-color: var(--rx-line) transparent;
}
.rx-pane::-webkit-scrollbar { width: 6px; }
.rx-pane::-webkit-scrollbar-thumb { background: var(--rx-line); border-radius: 3px; }
.rx-pane p { margin: 0; }
.rx-sub { color: var(--rx-accent); font-size: 12.5px; margin-bottom: 2px; }
.rx-sec {
  margin: 11px 0 4px;
  color: var(--rx-muted);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .04em;
}
.rx-sec:first-child { margin-top: 4px; }
.rx-li { color: var(--rx-text); font-size: 12.5px; padding-left: 13px; text-indent: -11px; }
.rx-li + .rx-li { margin-top: 3px; }
.rx-note {
  color: var(--rx-muted);
  font-size: 12px;
  padding-left: 13px;
  margin: 1px 0 6px;
}
.rx-sev { font-size: 11px; font-weight: 700; letter-spacing: .03em; }
.rx-sev[data-l='major'] { color: var(--rx-major); }
.rx-sev[data-l='moderate'] { color: var(--rx-moderate); }
.rx-sev[data-l='minor'] { color: var(--rx-minor); }
.rx-sev + span { color: var(--rx-text); font-size: 12.5px; }
.rx-dim { color: var(--rx-muted); font-size: 12px; }
.rx-hint { color: var(--rx-muted); font-size: 12.5px; padding: 2px 0 4px; }

.rx-more {
  flex: none;
  margin: 5px 10px 3px;
  padding: 5px;
  border: 0;
  border-radius: 5px;
  background: var(--rx-elev);
  color: var(--rx-accent);
  font: inherit; font-size: 11.5px; font-weight: 700;
  cursor: pointer;
}
.rx-more:hover { background: var(--rx-hover); }

.rx-foot {
  display: flex;
  align-items: center;
  gap: 5px;
  height: 20px;
  padding-inline: 10px;
  flex: none;
  font-size: 10px;
  color: var(--rx-muted);
}
.rx-foot .badge { color: var(--rx-accent); font-weight: 700; }
.rx-foot a { color: var(--rx-muted); text-decoration: underline; }
.rx-foot a:hover { color: var(--rx-accent); }
.rx-foot .grip { margin-left: auto; color: var(--rx-grip); }

/* The gear menu, its own floating panel - as in the app, where it is a real
   Toplevel so the card behind it never resizes. */
.rx-menu {
  position: absolute;
  z-index: 5;
  top: 32px; right: 8px;
  width: 205px;
  border: 1px solid var(--rx-line);
  border-radius: var(--radius-sm);
  background: var(--rx-elev);
  box-shadow: 0 16px 34px -12px rgba(0, 0, 0, .85);
}
.rx-menu[hidden] { display: none; }
.rx-menu-row {
  display: flex;
  align-items: center;
  padding: 9px 10px;
  font-size: 12px;
  color: var(--rx-muted);
}
.rx-menu-row + .rx-menu-row { border-top: 1px solid var(--rx-line); }
.rx-menu-row .sp { margin-left: auto; display: flex; gap: 4px; }
.rx-opt {
  border: 0;
  border-radius: 4px;
  padding: 3px 8px;
  background: none;
  color: var(--rx-muted);
  font: inherit; font-size: 12px; font-weight: 700;
  cursor: pointer;
}
.rx-opt[aria-pressed='true'] { background: var(--rx-hover); color: var(--rx-accent); }

/* Collapsed: the ℞ pill. In the app it lands exactly where the minimise
   button was, so opening and closing are the same click. */
.rx-pill {
  position: absolute;
  top: 58px;
  right: clamp(18px, 5vw, 62px);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 54px; height: 54px;
  border: 2px solid var(--accent);
  border-radius: 50%;
  background: var(--surface);
  color: var(--accent);
  font-size: 21px;
  font-weight: 700;
  cursor: pointer;
  box-shadow: 0 4px 10px rgba(0, 0, 0, .5), 0 0 0 6px rgba(78, 201, 176, .07);
  transition: transform .2s var(--ease), box-shadow .2s var(--ease);
}
.rx-pill:hover { transform: scale(1.06); }
.rx-pill[hidden], .rx[hidden] { display: none; }

@media (max-width: 760px) {
  .rx, .rx-pill {
    position: relative;
    top: 0; right: 0;
    width: 100%;
    max-width: 380px;
    margin-inline: auto;
  }
  .rx-pill { width: 54px; }
}

/* -------------------------------------------------------- demo controls */
.demo-aside {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-top: 22px;
}
.demo-aside .label { font-size: .82rem; color: var(--dim); }
.chip {
  border: 1px solid var(--line-2);
  border-radius: 999px;
  padding: 6px 14px;
  background: var(--surface);
  color: var(--muted);
  font: inherit;
  font-size: .83rem;
  cursor: pointer;
  transition: color .16s, border-color .16s, background .16s;
}
.chip:hover { color: var(--accent); border-color: var(--accent); background: var(--accent-wash); }

.demo-foot {
  margin-top: 18px;
  font-size: .78rem;
  line-height: 1.6;
  color: var(--dim);
}
.demo-foot a { color: var(--muted); text-decoration: underline; text-underline-offset: 2px; }
.demo-foot a:hover { color: var(--accent); }

/* ----------------------------------------------------------------- grids */
.grid { display: grid; gap: 16px; }
.grid--3 { grid-template-columns: repeat(auto-fit, minmax(270px, 1fr)); }
.grid--2 { grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); }

.card {
  padding: 26px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  transition: border-color .2s, background .2s, transform .2s var(--ease);
}
.card:hover { border-color: var(--line-2); }
.card h3 { margin-bottom: 9px; }
.card p { color: var(--muted); font-size: .94rem; }

.card-ico {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 38px; height: 38px;
  margin-bottom: 16px;
  border: 1px solid var(--line-2);
  border-radius: 10px;
  background: var(--accent-wash);
  color: var(--accent);
}

/* Numbered steps */
.steps { counter-reset: step; }
.step { position: relative; padding-left: 56px; }
.step::before {
  counter-increment: step;
  content: counter(step);
  position: absolute;
  left: 0; top: 0;
  display: grid;
  place-items: center;
  width: 34px; height: 34px;
  border: 1px solid var(--line-2);
  border-radius: 50%;
  background: var(--surface);
  color: var(--accent);
  font-size: .86rem;
  font-weight: 700;
}
.step h3 { margin-bottom: 8px; }
.step p { color: var(--muted); font-size: .94rem; }

/* --------------------------------------------------------- source table */
/* Each row used to be its own grid with an `auto` third column, and .licence
   is nowrap - so a longer pill widened that row's third track and stole the
   width from its middle column. "Graded against FDA labelling" needs about
   11rem where "Public domain" needs 6, and only the curated row was squeezed,
   which is why the prose in it wrapped differently from its neighbours.

   The columns are declared on the container now and the rows adopt them, so
   every row is measured against the widest pill in the set and all four line
   up. The fallback below fixes the third track wide enough for the longest
   pill; subgrid then makes the number unnecessary where it is supported. */
.sources {
  display: grid;
  gap: 0;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  overflow: hidden;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 2fr) minmax(11.5rem, auto);
}
.source {
  display: grid;
  grid-column: 1 / -1;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 2fr) minmax(11.5rem, auto);
  gap: 8px 22px;
  align-items: baseline;
  padding: 20px 24px;
  background: var(--surface);
}
@supports (grid-template-columns: subgrid) {
  .source { grid-template-columns: subgrid; }
}
.source + .source { border-top: 1px solid var(--line); }
.source h3 { font-size: 1rem; }
.source .count { display: block; margin-top: 5px; font-size: .8rem; color: var(--accent); font-weight: 600; }
.source p { color: var(--muted); font-size: .89rem; }
.source .licence {
  justify-self: end;
  white-space: nowrap;
  padding: 4px 10px;
  border: 1px solid var(--line-2);
  border-radius: 999px;
  font-size: .72rem;
  color: var(--dim);
}
@media (max-width: 780px) {
  /* The container's three tracks include an 11.5rem minimum for the widest
     pill, which on a phone would be wider than the screen - and .sources
     clips rather than scrolls, so it would cut the text off. Both the
     container and the rows collapse to one column here. */
  .sources { grid-template-columns: 1fr; }
  .source { grid-template-columns: 1fr; }
  .source .licence { justify-self: start; }
}

/* --------------------------------------------------------- honesty band */
.plain { list-style: none; margin: 0; padding: 0; display: grid; gap: 14px; }
.plain li {
  display: grid;
  grid-template-columns: 20px 1fr;
  gap: 12px;
  color: var(--muted);
  font-size: .95rem;
}
.plain svg { margin-top: 5px; color: var(--accent); }
.plain b { color: var(--text); font-weight: 600; }

/* ------------------------------------------------------------ page heads */
.page-head {
  max-width: 720px;
  padding-block: clamp(46px, 7vw, 76px) clamp(26px, 4vw, 38px);
  margin-inline: auto;
  padding-inline: var(--gutter);
  text-align: center;
}
main > .page-head + * { margin-top: 0; }

/* ------------------------------------------------------------- download */
.dl {
  max-width: 620px;
  margin: 0 auto;
  padding: clamp(28px, 4vw, 40px);
  border: 1px solid var(--line-2);
  border-radius: 16px;
  background:
    radial-gradient(120% 90% at 50% -20%, rgba(78, 201, 176, .1), transparent 62%),
    var(--surface);
  box-shadow: var(--lift);
  text-align: center;
}
.dl h2 { font-size: 1.5rem; }
.dl .os {
  display: inline-flex; align-items: center; gap: 8px;
  margin-bottom: 18px;
  font-size: .8rem; color: var(--muted);
}
.dl .btn { margin-top: 22px; }
.dl-facts {
  display: flex; flex-wrap: wrap; justify-content: center;
  gap: 6px 18px;
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid var(--line);
  font-size: .81rem; color: var(--dim);
}

/* Editions */
.editions { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.edition { display: flex; flex-direction: column; padding: 26px; border: 1px solid var(--line); border-radius: var(--radius); background: var(--surface); }
.edition[data-featured='true'] { border-color: rgba(78, 201, 176, .45); background: linear-gradient(180deg, var(--accent-wash), var(--surface) 60%); }
.edition .tag { align-self: flex-start; margin-bottom: 14px; padding: 3px 10px; border-radius: 999px; background: var(--accent-wash); color: var(--accent); font-size: .7rem; font-weight: 700; letter-spacing: .07em; text-transform: uppercase; }
.edition h3 { font-size: 1.2rem; }
.edition .price { margin: 10px 0 4px; font-size: 1.9rem; font-weight: 700; letter-spacing: -0.03em; }
.edition .price small { font-size: .8rem; font-weight: 500; color: var(--muted); letter-spacing: 0; }
.edition > p { color: var(--muted); font-size: .9rem; }
.edition ul { list-style: none; margin: 20px 0 24px; padding: 0; display: grid; gap: 10px; }
.edition li { display: grid; grid-template-columns: 17px 1fr; gap: 10px; font-size: .9rem; color: var(--muted); }
.edition li svg { margin-top: 4px; color: var(--accent); }
.edition li[data-no='true'] svg { color: var(--dim); }
.edition .btn { margin-top: auto; }

/* ------------------------------------------------------------------ FAQ */
.faq { border-top: 1px solid var(--line); }
.faq details { border-bottom: 1px solid var(--line); }
.faq summary {
  display: flex; align-items: center; gap: 14px;
  padding: 20px 4px;
  cursor: pointer;
  font-weight: 500;
  list-style: none;
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: '+';
  margin-left: auto;
  color: var(--accent);
  font-size: 1.2rem;
  font-weight: 400;
  transition: transform .2s var(--ease);
}
.faq details[open] summary::after { content: '−'; }
.faq summary:hover { color: var(--accent); }
.faq .answer { padding: 0 4px 22px; color: var(--muted); font-size: .94rem; max-width: 70ch; }
.faq .answer p + p { margin-top: 12px; }

/* ----------------------------------------------------------------- prose */
.prose { max-width: 720px; margin-inline: auto; padding: 0 var(--gutter) clamp(56px, 8vw, 90px); }
.prose-block + .prose-block { margin-top: 34px; padding-top: 34px; border-top: 1px solid var(--line); }
.prose h2 { font-size: 1.12rem; letter-spacing: -0.01em; margin-bottom: 12px; }
.prose p {
  color: var(--muted);
  font-size: .96rem;
  line-height: 1.72;
  /* Stops a paragraph ending on a single orphaned word, which the policy
     pages produce constantly - they are long and full of short clauses. */
  text-wrap: pretty;
}
.prose p + p { margin-top: 14px; }
.prose ul {
  color: var(--muted);
  font-size: .96rem;
  line-height: 1.72;
  padding-left: 20px;
  text-wrap: pretty;
}
/* The retention schedule and the lawful-basis list are the two places on the
   site where a reader is scanning for one line among many, so the list markers
   are pulled back to the measure and the rows given room to separate. */
.prose li { padding-left: 2px; }
.prose li + li { margin-top: 8px; }
.prose a { color: var(--accent); text-decoration: underline; text-underline-offset: 3px; }
.prose code, .ui-ref {
  padding: 1px 6px;
  border: 1px solid var(--line-2);
  border-radius: 5px;
  background: var(--surface);
  color: var(--text);
  font-size: .88em;
}
.prose code { font-family: var(--font-mono); }

/* ------------------------------------------------------------------ form */
.form {
  max-width: 560px;
  margin-inline: auto;
  padding: clamp(24px, 4vw, 34px);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.field + .field { margin-top: 18px; }
.field label { display: block; margin-bottom: 7px; font-size: .86rem; font-weight: 500; }
.field label .req { color: var(--accent); }
.field .help { margin-top: 6px; font-size: .78rem; color: var(--dim); }
.field input, .field select, .field textarea {
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--field-line);
  border-radius: var(--radius-sm);
  background: var(--bg-2);
  color: var(--text);
  font: inherit;
  font-size: .94rem;
  transition: border-color .16s, background .16s;
}
.field input:focus, .field select:focus, .field textarea:focus {
  outline: none;
  border-color: var(--accent);
  background: var(--bg);
}
/* ...but not for the keyboard. The rule above is more specific than the
   global :focus-visible ring and comes after it, so it was removing the
   outline for keyboard users as well and leaving a one-pixel border tint as
   the only sign of where you were. Tabbing through the registration form was
   very nearly invisible. */
.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.check input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.field textarea { resize: vertical; min-height: 92px; }
.field select { appearance: none; background-image: linear-gradient(45deg, transparent 50%, var(--muted) 50%), linear-gradient(135deg, var(--muted) 50%, transparent 50%); background-position: calc(100% - 19px) 50%, calc(100% - 14px) 50%; background-size: 5px 5px, 5px 5px; background-repeat: no-repeat; }
.check { display: grid; grid-template-columns: 18px 1fr; gap: 11px; margin-top: 22px; font-size: .86rem; color: var(--muted); line-height: 1.55; }
.check input { width: 18px; height: 18px; margin-top: 2px; accent-color: var(--accent); }
.form .btn { margin-top: 24px; }
.page-meta {
  margin: 14px 0 0;
  font-size: .82rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

.form-note { margin-top: 16px; font-size: .78rem; color: var(--dim); text-align: center; }

.alert {
  margin-bottom: 22px;
  padding: 14px 16px;
  border: 1px solid var(--line-2);
  border-left: 2px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--bg-2);
  font-size: .88rem;
  color: var(--muted);
}
.alert[data-tone='warn'] { border-left-color: var(--moderate); }
.alert b { color: var(--text); }
.alert[hidden] { display: none; }

/* ---------------------------------------------------------------- footer */
.foot { border-top: 1px solid var(--line); padding-block: 52px 34px; }
.foot-top {
  display: grid;
  grid-template-columns: minmax(220px, 1.4fr) repeat(auto-fit, minmax(140px, 1fr));
  gap: 34px;
  padding-bottom: 34px;
  border-bottom: 1px solid var(--line);
}
.foot-brand img { height: 20px; width: auto; margin-bottom: 14px; }
.foot-brand p { font-size: .85rem; color: var(--dim); max-width: 30ch; }
.foot-col h4 { margin-bottom: 12px; font-size: .74rem; font-weight: 600; letter-spacing: .11em; text-transform: uppercase; color: var(--muted); }
.foot-col ul { list-style: none; margin: 0; padding: 0; display: grid; gap: 9px; }
.foot-col a { color: var(--dim); font-size: .88rem; text-decoration: none; }
.foot-col a:hover { color: var(--accent); }
.foot-bottom {
  display: flex; flex-wrap: wrap; gap: 10px 22px; align-items: center;
  padding-top: 24px;
  font-size: .78rem; color: var(--dim);
}
.foot-bottom .spacer { margin-left: auto; }
.foot-bottom a { color: var(--dim); }
.foot-bottom a:hover { color: var(--accent); }

/* Site-wide standing note. Not a cookie banner - a clinical one. */
.safety {
  padding: 16px 0;
  border-top: 1px solid var(--line);
  font-size: .78rem;
  line-height: 1.6;
  color: var(--dim);
}
.safety b { color: var(--muted); font-weight: 600; }

/* ------------------------------------------------------------- reveal-in */
[data-reveal] {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity .55s var(--ease), transform .55s var(--ease);
}
[data-reveal].in { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  [data-reveal] { opacity: 1; transform: none; }
}

/* ------------------------------------------------------- account & licences */
/* Sign-in is a two-step form in one card: ask for the address, then for the
   code. Both steps live in the markup and one is hidden, so the transition is
   not a page load and a failed code does not lose the address. */
.step-pane[hidden] { display: none; }

.otp {
  letter-spacing: .5em;
  text-align: center;
  font-size: 1.35rem !important;
  font-variant-numeric: tabular-nums;
}

.linkish {
  border: 0;
  background: none;
  padding: 0;
  color: var(--muted);
  font: inherit;
  font-size: .82rem;
  text-decoration: underline;
  text-underline-offset: 3px;
  cursor: pointer;
}
.linkish:hover { color: var(--accent); }

.row-between { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; }
.row-between .spacer { margin-left: auto; }

.stack { display: grid; gap: 14px; }

/* One licence. The status dot carries the meaning, so it is never the only
   signal - the word is right beside it. */
.lic {
  padding: 20px 22px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}
.lic[data-status='active'] { border-color: rgba(78, 201, 176, .38); }
.lic[data-status='expired'], .lic[data-status='revoked'] { opacity: .8; }
.lic-head { display: flex; flex-wrap: wrap; gap: 8px 14px; align-items: baseline; }
.lic-head h3 { margin-right: auto; font-size: 1.05rem; }
.lic-status {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: .78rem; font-weight: 600; letter-spacing: .03em;
  text-transform: uppercase;
}
.lic-status::before {
  content: ''; width: 7px; height: 7px; border-radius: 50%;
  background: currentColor;
}
[data-status='active'] .lic-status { color: var(--accent); }
[data-status='pending'] .lic-status { color: var(--moderate); }
[data-status='expired'] .lic-status { color: var(--muted); }
[data-status='revoked'] .lic-status { color: var(--major); }
.lic-meta {
  display: flex; flex-wrap: wrap; gap: 4px 18px;
  margin-top: 12px;
  font-size: .82rem; color: var(--dim);
}
.lic-meta b { color: var(--muted); font-weight: 500; }
.lic-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 18px; }

.empty {
  padding: 34px 24px;
  border: 1px dashed var(--line-2);
  border-radius: var(--radius);
  text-align: center;
  color: var(--muted);
  font-size: .93rem;
}
.empty .btn { margin-top: 18px; }

/* The account page's own header strip: who you are, and the way out. */
.who {
  display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: center;
  padding: 16px 20px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: .88rem;
}
.who .avatar {
  display: grid; place-items: center;
  width: 34px; height: 34px;
  border-radius: 50%;
  background: var(--accent-wash);
  color: var(--accent);
  font-weight: 700;
}
.who .name { font-weight: 600; }
.who .sub { color: var(--dim); font-size: .8rem; }

.spinner {
  display: inline-block;
  width: 13px; height: 13px;
  border: 2px solid rgba(255, 255, 255, .25);
  border-top-color: var(--accent);
  border-radius: 50%;
  animation: spin .7s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

/* Citations under a claim in the demo card. Quieter than the note, because
   they exist to be checked rather than read every time. */
.rx-cite {
  padding-left: 13px;
  margin: 1px 0 7px;
  color: var(--rx-muted);
  font-size: 11px;
  line-height: 1.5;
}
.rx-link { color: var(--rx-accent); text-decoration: underline; }
.rx-link:hover { text-decoration: none; }
.rx-major {
  color: var(--rx-major);
  font-size: 12px;
  font-weight: 600;
  margin-bottom: 6px;
}

/* ---------------------------------------------------- tier comparison table */
/* Its own scroller: three columns of prose do not fit a phone, and the page
   body must never be what scrolls sideways. */
.scroll-x { overflow-x: auto; margin-bottom: 22px; }
.compare {
  width: 100%;
  min-width: 520px;
  border-collapse: collapse;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  font-size: .92rem;
}
.compare th {
  padding: 14px 16px;
  border-bottom: 1px solid var(--line-2);
  background: var(--raised);
  color: var(--text);
  font-size: .95rem;
  font-weight: 600;
  text-align: left;
}
.compare td {
  padding: 12px 16px;
  border-bottom: 1px solid var(--line);
  color: var(--muted);
  vertical-align: top;
}
.compare tr:last-child td { border-bottom: 0; }
.compare td:first-child { color: var(--text); font-weight: 500; }
.compare svg { vertical-align: -2px; }
.compare td:nth-child(2) svg { color: var(--accent); }
.compare td:nth-child(3) svg { color: var(--caution); }
.compare td[data-no] svg, .compare svg[data-no] { color: var(--dim); }

/* "Not yet available — no price set" is a long price line. Below the card
   breakpoint the qualifier drops to its own line rather than wrapping mid-dash. */
@media (max-width: 520px) {
  .edition .price { font-size: 1.5rem; }
  .edition .price small { display: block; margin-top: 4px; }
}

/* ---------------------------------------------------------------- stats.html
   The analytics dashboard. Deliberately plain: bars are divs with a height,
   because the entire dataset is a few dozen integers and a charting library
   would be larger than every other asset on the site combined. */
.stat-ranges { display: flex; gap: 8px; margin-bottom: 10px; }
.stat-ranges .btn.is-on {
  border-color: var(--accent);
  color: var(--accent);
  background: var(--accent-wash);
}

.stat-figures {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin: 20px 0 34px;
}
.stat-figure {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-2);
  padding: 18px 20px;
}
.stat-label {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--dim);
}
.stat-value {
  font-size: 1.9rem;
  font-weight: 600;
  margin-top: 8px;
  /* Digits in a row of cards must line up as the numbers change. */
  font-variant-numeric: tabular-nums;
}
.stat-note { font-size: 0.8rem; color: var(--muted); margin-top: 4px; }

.stat-block { margin: 0 0 34px; }
.stat-block h2 { font-size: 1.05rem; margin: 0 0 14px; }

.stat-chart {
  display: flex;
  align-items: flex-end;
  gap: 3px;
  height: 140px;
  padding: 10px 12px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-2);
  /* Ninety columns will not fit on a phone, so the chart scrolls rather than
     the page - the body must never scroll sideways. */
  overflow-x: auto;
}
.stat-col {
  flex: 1 0 6px;
  height: 100%;
  display: flex;
  align-items: flex-end;
}
.stat-bar {
  width: 100%;
  min-height: 2px;
  border-radius: 2px 2px 0 0;
  background: var(--accent-deep);
}
.stat-col:hover .stat-bar { background: var(--accent); }
.stat-axis {
  display: flex;
  justify-content: space-between;
  font-size: 0.75rem;
  color: var(--dim);
  margin-top: 8px;
  font-variant-numeric: tabular-nums;
}

.stat-table { width: 100%; border-collapse: collapse; font-size: 0.9rem; }
.stat-table th,
.stat-table td {
  padding: 9px 12px;
  border-bottom: 1px solid var(--line);
  text-align: left;
}
.stat-table th {
  font-size: 0.72rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--dim);
  font-weight: 500;
}
.stat-table .num { text-align: right; font-variant-numeric: tabular-nums; }
.stat-table tbody tr:hover { background: var(--surface); }

/* --------------------------------------------------- hero blurb + demo jump
   Sits between the headline and the demo, so it has to be readable without
   competing with either. Smaller than .lede, which carries the fuller
   description below the demo. */
/* The accent rule is scoped to .hero h1 .accent, so the blurb needs its own.
   Same token either way - the brand colour must not fork into two teals. */
.hero-sub .accent { color: var(--accent); }
.hero-sub {
  /* Wider than the 58ch a paragraph wants, because this one is a single
     sentence rather than a paragraph: the lead is 36 characters and the
     longest phrase is 44, so anything under ~80ch drops the cycling phrase
     onto a line of its own and the sentence stops reading as one. Capped at
     100% so a narrow viewport still wraps rather than overflowing - and the
     stacked ghosts keep the height stable when it does. */
  max-width: min(80ch, 100%);
  margin: 18px auto 0;
  font-size: clamp(1rem, 1.6vw, 1.08rem);
  line-height: 1.65;
  color: var(--muted);
  text-align: center;
}
/* Text for listeners only. Distinct from .skip, which is a skip link and
   comes back on focus - this must never be focusable or visible. */
.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;
  border: 0;
}

/* The cycling phrase.

   This reserved the width of the longest phrase so the line never reflowed,
   which worked and looked wrong: with a short phrase showing, thirty
   characters of reserved emptiness sat to its right and the whole sentence
   read as shoved left of centre.

   Those two properties cannot both hold. A line that is always centred has
   to resize as the phrase does, and a line that never resizes cannot stay
   centred. Centred wins - it is a hero, it is meant to be looked at, and the
   resizing reads as typing rather than as a fault.

   The ghosts stay in the markup because the script reads the phrase list out
   of them, and `display: none` leaves textContent perfectly readable. They
   just no longer reserve anything.

   What this costs: at the widest phrase the sentence is 80 characters, so on
   a narrow viewport it wraps and the wrap point moves as the phrase grows.
   That is a line of vertical movement on a phone, against a block that is
   permanently off-centre everywhere. The trade is worth it. */
.type-slot {
  display: inline;
  /* Baseline, so the phrase sits on the same line as the words either side
     of it rather than a couple of pixels below them. */
  vertical-align: baseline;
}
.type-ghost { display: none; }
.type-live { color: var(--accent); font-weight: 500; }

/* A caret that blinks only between keystrokes. While characters are being
   added or removed it holds steady, which is what a real cursor does - a
   caret blinking through its own typing reads as two animations fighting. */
.type-caret {
  display: inline-block;
  width: 2px;
  height: 1.05em;
  margin-left: 2px;
  vertical-align: text-bottom;
  background: var(--accent);
  animation: type-blink 1.05s steps(1, end) infinite;
}
.type-live.is-busy .type-caret { animation: none; opacity: 1; }

@keyframes type-blink {
  0%, 48% { opacity: 1; }
  49%, 100% { opacity: 0; }
}

/* Reduced motion: no typing, no blinking, and the sentence states all four
   outright rather than holding one and implying the rest. Somebody who has
   asked for less movement should get more information, not less. */
@media (prefers-reduced-motion: reduce) {
  .type-caret { display: none; }
  .type-slot { display: none; }
  /* ...and the sentence that was for listeners becomes the sentence for
     everybody. Without this the line ends at "without" and simply stops:
     the script does not start, so the live span stays empty, and every
     other copy of the phrases is hidden. A reduced-motion preference should
     cost the animation, not the words. */
  .hero-static {
    position: static;
    width: auto; height: auto;
    margin: 0; overflow: visible;
    clip: auto;
    clip-path: none;
    white-space: normal;
    color: var(--accent);
    font-weight: 500;
  }
}

.hero-jump { margin: 16px 0 0; text-align: center; }
.hero-jump a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  font-size: 0.94rem;
  font-weight: 500;
  color: var(--accent);
  text-decoration: none;
  border-bottom: 1px solid transparent;
  padding-bottom: 1px;
}
.hero-jump a:hover,
.hero-jump a:focus-visible { border-bottom-color: var(--accent); }
/* The arrow points at where the link goes, so it moves the way the page will. */
.hero-jump svg { transition: transform 0.18s ease; }
.hero-jump a:hover svg { transform: translateY(2px); }
@media (prefers-reduced-motion: reduce) {
  .hero-jump svg { transition: none; }
  .hero-jump a:hover svg { transform: none; }
}

/* ------------------------------------------------------------- demo heading */
.stage-head { max-width: 780px; margin: 0 auto 20px; text-align: center; }
.stage-head h2 {
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.13em;
  color: var(--dim);
  margin: 0;
}
.stage-note {
  margin: 8px 0 0;
  font-size: 0.82rem;
  line-height: 1.55;
  color: var(--dim);
}
.stage-note b { color: var(--muted); font-weight: 600; }

/* ------------------------------------------------------ the licence gate
   A checkbox the download waits on. Sized for a real pointer target rather
   than the browser default, because it is the one control on the page that
   must not be missed. */
.consent {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  max-width: 52ch;
  margin: 0 auto 16px;
  padding: 12px 14px;
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  background: var(--bg-2);
  font-size: 0.86rem;
  line-height: 1.5;
  color: var(--muted);
  cursor: pointer;
  transition: border-color 0.18s ease, background 0.18s ease;
}
.consent:hover { border-color: var(--accent); }
.consent input {
  flex: 0 0 auto;
  width: 17px;
  height: 17px;
  margin-top: 1px;
  accent-color: var(--accent);
  cursor: pointer;
}
.consent a { color: var(--accent); }

/* Flashed when a gated button is clicked without it. The animation is the
   whole explanation, so it is skipped under reduced motion in favour of the
   border colour alone. */
.consent--asked {
  border-color: var(--moderate);
  background: var(--surface);
  animation: consent-nudge 0.4s ease;
}
@keyframes consent-nudge {
  0%, 100% { transform: translateX(0); }
  25%      { transform: translateX(-4px); }
  75%      { transform: translateX(4px); }
}
@media (prefers-reduced-motion: reduce) {
  .consent--asked { animation: none; }
}

/* A gated button reads as not-yet-available rather than broken. */
.btn.is-blocked { opacity: 0.55; }

/* The edition boundary under the download call to action. Quiet but not
   hidden: it is the sentence that keeps the page, the licence and the
   intended-use statement telling the same story. */
.cta-scope {
  max-width: 62ch;
  margin: 18px auto 0;
  padding: 12px 16px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--bg-2);
  font-size: 0.83rem;
  line-height: 1.6;
  color: var(--muted);
  text-align: center;
}
.cta-scope b { color: var(--text); font-weight: 600; }
.cta-scope a { color: var(--accent); }

/* The product name in body copy. One class, so the treatment is the same on
   every page instead of a hand-placed span here and there.

   Deliberately not applied in fine print - the footer strapline, the safety
   line, the demo captions - where an accent colour on a 0.78rem line reads as
   noise rather than emphasis. Nor inside the landing page's demo, which is a
   facsimile of the app's own window: the app does not colour its name there,
   and a mock-up that did would misrepresent it. */
.brandname { color: var(--accent); }

/* ------------------------------------------------------- licence review queue
   stats.html only. Built from the existing tokens rather than new colours:
   --field-line for anything that is the visible edge of a control (3:1, see
   the note on that token), --muted and above for anything that is text. */
.req-all {
  display: flex;
  align-items: center;
  gap: 9px;
  margin-bottom: 14px;
  font-size: .86rem;
  color: var(--muted);
}
.req-all input { width: 17px; height: 17px; accent-color: var(--accent); }
.req-all label { cursor: pointer; }

.req-batch {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  padding: 11px 14px;
  margin-bottom: 16px;
  border: 1px solid var(--field-line);
  border-radius: var(--radius-sm);
  background: var(--raised);
}
.req-batch[hidden] { display: none; }
.req-count {
  font-size: .86rem;
  font-weight: 600;
  color: var(--text);
  font-variant-numeric: tabular-nums;
}

.req-list { display: flex; flex-direction: column; gap: 10px; }

.req {
  border: 1px solid var(--line-2);
  border-radius: var(--radius-sm);
  background: var(--surface);
}
.req-head {
  display: flex;
  align-items: center;
  gap: 11px;
  padding: 12px 14px;
  flex-wrap: wrap;
}
.req-head input[type='checkbox'] {
  width: 17px; height: 17px; accent-color: var(--accent); flex: 0 0 auto;
}

/* The address is the disclosure control. A button rather than a div with a
   click handler, so it is reachable and operable from the keyboard without
   any tabindex of our own. */
.req-email {
  flex: 1 1 auto;
  min-width: 0;
  border: 0;
  background: none;
  padding: 0;
  text-align: left;
  font: inherit;
  font-size: .95rem;
  font-weight: 600;
  color: var(--text);
  cursor: pointer;
  overflow-wrap: anywhere;
}
.req-email::before {
  content: '\25B8';                       /* a right-pointing marker */
  display: inline-block;
  margin-right: 8px;
  color: var(--muted);
  transition: transform .15s var(--ease);
}
.req-email[aria-expanded='true']::before { transform: rotate(90deg); }
.req-email:hover { color: var(--accent); }

.req-meta {
  font-size: .82rem;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}
.req-actions { display: flex; gap: 8px; margin-left: auto; }

.req-detail {
  padding: 0 14px 14px;
  border-top: 1px solid var(--line);
  margin-top: 2px;
}
.req-detail[hidden] { display: none; }
.req-fields {
  display: grid;
  grid-template-columns: minmax(90px, max-content) 1fr;
  gap: 6px 16px;
  margin: 13px 0 0;
  font-size: .87rem;
}
.req-fields dt { color: var(--muted); }
.req-fields dd { margin: 0; color: var(--text); overflow-wrap: anywhere; }
.req-detail h4 {
  margin: 16px 0 6px;
  font-size: .8rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  color: var(--muted);
}
/* Free text somebody typed into a form. pre-wrap keeps their line breaks
   without letting the content lay out the page. */
.req-use {
  margin: 0;
  font-size: .89rem;
  line-height: 1.65;
  color: var(--text);
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

@media (max-width: 560px) {
  .req-actions { margin-left: 0; width: 100%; }
  .req-actions .btn { flex: 1 1 auto; }
}

/* ==========================================================================
   The online version (app.html)
   --------------------------------------------------------------------------
   Namespaced rxa- rather than rx-: the landing-page demo owns rx-, and three
   of its class names - card, sec, sev - would otherwise collide here.
   ========================================================================== */

.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  margin: -1px; padding: 0;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

.rxa-app-top { padding-top: 48px; }
.rxa-app-top h1 { margin: 6px 0 12px; }

.rxa-app-note {
  margin: 22px 0 0;
  padding: 14px 16px;
  border: 1px solid var(--line-2);
  border-left: 3px solid var(--accent);
  border-radius: var(--radius-sm);
  background: var(--accent-wash);
  color: var(--text);
  font-size: 14px;
  line-height: 1.6;
  max-width: 72ch;
}

.rxa-app {
  position: relative;
  margin: 28px 0 72px;
}

/* ----------------------------------------------------------------- search */
.rxa-searchbar {
  position: relative;
  display: flex;
  align-items: center;
  gap: 12px;
}

.rxa-searchbar input {
  flex: 1 1 auto;
  min-width: 0;
  padding: 15px 17px;
  font: inherit;
  font-size: 17px;
  color: var(--text);
  background: var(--surface);
  border: 1px solid var(--field-line);
  border-radius: var(--radius);
  outline: none;
}
.rxa-searchbar input::placeholder { color: var(--muted); }
.rxa-searchbar input:focus-visible {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-wash);
}
.rxa-searchbar input:disabled { opacity: .6; cursor: progress; }

.rxa-count {
  flex: 0 0 auto;
  color: var(--dim);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.rxa-status {
  margin: 10px 2px 0;
  color: var(--dim);
  font-size: 13.5px;
}
.rxa-status.is-error { color: var(--major); }

/* ---------------------------------------------------------------- results */
.rxa-results {
  position: absolute;
  z-index: 30;
  left: 0; right: 0;
  margin: 6px 0 0;
  padding: 5px;
  list-style: none;
  background: var(--raised);
  border: 1px solid var(--line-2);
  border-radius: var(--radius);
  box-shadow: var(--lift);
  max-height: 58vh;
  overflow-y: auto;
}

.rxa-hit {
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  cursor: pointer;
}
.rxa-hit:hover, .rxa-hit.is-on { background: var(--hover); }

.rxa-hit-name { color: var(--text); font-size: 15px; font-weight: 600; }
.rxa-hit-class {
  color: var(--dim);
  font-size: 12.5px;
  margin-left: auto;
  text-align: right;
  /* The class is context, not the answer: it may be clipped, the name may
     never be. */
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  max-width: 45%;
}

/* ------------------------------------------------------------------- tags */
.rxa-tag {
  flex: 0 0 auto;
  padding: 2px 7px;
  border-radius: 999px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.rxa-tag--curated { color: var(--accent); background: var(--accent-wash); }
.rxa-tag--fda { color: var(--dim); background: var(--hover); }

/* ------------------------------------------------------------------- card */
.rxa-cardwrap { margin-top: 26px; }

.rxa-card {
  padding: 26px clamp(18px, 4vw, 32px) 30px;
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
}

.rxa-card-head {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 12px;
}
.rxa-card-head h2 {
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(22px, 3.4vw, 29px);
  line-height: 1.2;
}

.rxa-card-class {
  margin: 6px 0 0;
  color: var(--accent);
  font-size: 14.5px;
  font-weight: 600;
}
.rxa-card-meta {
  margin: 9px 0 0;
  color: var(--dim);
  font-size: 13px;
}

.rxa-sec { margin-top: 26px; }
.rxa-sec h3 {
  margin: 0 0 8px;
  color: var(--muted);
  font-size: 11.5px;
  font-weight: 700;
  letter-spacing: .07em;
  text-transform: uppercase;
}
.rxa-sec p {
  margin: 0 0 10px;
  color: var(--text);
  font-size: 14.5px;
  line-height: 1.68;
  max-width: 76ch;
}

/* A boxed warning is the most serious thing an FDA label carries, and it
   should not be one more grey heading among several. */
.rxa-sec--boxed {
  padding: 16px 18px;
  border: 1px solid var(--major);
  border-radius: var(--radius-sm);
  background: rgba(255, 107, 107, .07);
}
.rxa-sec--boxed h3 { color: var(--major); }

.rxa-ix { margin: 0; padding: 0; list-style: none; }
.rxa-ix li {
  display: flex;
  gap: 10px;
  align-items: baseline;
  padding: 7px 0;
  border-top: 1px solid var(--line);
  color: var(--text);
  font-size: 14.5px;
  line-height: 1.55;
}
.rxa-ix li:first-child { border-top: 0; }

.rxa-sev {
  flex: 0 0 auto;
  min-width: 66px;
  font-size: 10.5px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.rxa-sev--major { color: var(--major); }
.rxa-sev--moderate { color: var(--moderate); }
.rxa-sev--minor { color: var(--minor); }

.rxa-card-source {
  margin: 24px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--line);
  color: var(--dim);
  font-size: 12.5px;
}

/* --------------------------------------------------------- professional */
.rxa-pro {
  margin-top: 26px;
  padding: 20px 22px;
  border: 1px solid var(--accent-deep);
  border-radius: var(--radius);
  background: var(--accent-wash);
}
.rxa-pro h2 { margin: 0 0 6px; font-size: 17px; }
.rxa-pro p { margin: 0; color: var(--text); font-size: 14px; }

.rxa-app-foot {
  margin: 30px 0 0;
  color: var(--dim);
  font-size: 12.5px;
  line-height: 1.6;
  max-width: 76ch;
}

@media (max-width: 560px) {
  .rxa-searchbar { flex-wrap: wrap; }
  .rxa-count { order: 2; width: 100%; }
  .rxa-hit-class { display: none; }
  .rxa-hit { gap: 8px; }
}

/* The online-version offer, in the demo's header. Sits with the note that
   says the demo is a small slice, because that is the sentence it answers. */
.stage-online {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 10px 14px;
  margin: 14px 0 0;
}
.stage-online span {
  color: var(--dim);
  font-size: 13.5px;
}
