/*
 * Clinifyd marketing site.
 *
 * Deliberately plain CSS in one file. A landing page that needs a build step
 * is a landing page nobody edits, and the whole thing is smaller than the
 * framework it would otherwise pull in.
 *
 * Tokens follow the product's own slate palette rather than the guide's
 * suggested teal, so the site and the software look like one thing.
 */
/*
 * Figtree, self-hosted.
 *
 * The site wore the system font, which reads as "not designed yet". One
 * variable file, 20KB, weights 300-900 — served from /brand because the CSP
 * says font-src 'self' and means it. Chosen for the same reason the palette
 * is calm: it is the healthcare register — open, round-cornered, legible —
 * without being a hospital.
 */
@font-face {
  font-family: 'Figtree';
  src: url('/brand/fonts/figtree-var.woff2') format('woff2');
  font-weight: 300 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --ink: #0f172a;
  --ink-soft: #475569;
  /* Was #94a3b8 at 2.56:1, which is not a colour so much as a rumour of one.
     5.45:1 on white and 4.97:1 on the sunk surface keeps it clearly quieter than --ink-soft while remaining readable. */
  --ink-faint: #5b6b7f;
  --surface: #ffffff;
  --surface-soft: #f8fafc;
  --surface-sunk: #f1f5f9;
  --line: #e2e8f0;
  --brand: #0f172a;
  /* The brand teal. Fills, borders, dots — anywhere WCAG does not ask for
     legibility. */
  --accent: #0d9488;
  /* The same teal, dark enough to read. 5.47:1 on white against 3.74:1, which
     is the difference between passing AA and only looking like it does. Used
     for every piece of text and every white-on-teal fill. */
  --accent-text: #0f766e;
  --accent-soft: #f0fdfa;
  --warn: #b45309;
  --radius: 14px;
  --radius-lg: 22px;
  /*
   * Elevation in two layers: a contact shadow that says "this sits on the
   * page" and an ambient one that says "softly". One heavy blur said neither.
   */
  --shadow: 0 1px 2px rgb(15 23 42 / 4%), 0 10px 30px -6px rgb(15 23 42 / 8%);
  --shadow-lift: 0 2px 4px rgb(15 23 42 / 5%), 0 18px 44px -10px rgb(15 23 42 / 13%);
  --measure: 66ch;
}

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

html {
  scroll-behavior: smooth;
}

/* Motion is decoration here. Anybody who has asked for less gets none. */
@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    transition-duration: 0.01ms !important;
  }
}

body {
  margin: 0;
  font-family:
    'Figtree', -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
  color: var(--ink);
  background: var(--surface);
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

h1,
h2,
h3 {
  line-height: 1.15;
  letter-spacing: -0.025em;
  font-weight: 700;
  margin: 0;
}

p {
  margin: 0;
  max-width: var(--measure);
}

a {
  color: inherit;
}

img {
  max-width: 100%;
  height: auto;
}

.wrap {
  width: min(100% - 3rem, 72rem);
  margin-inline: auto;
}

/* Every interactive thing shows where the keyboard is. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
summary:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: 6px;
}

/* Skip link — visible the moment it is focused, invisible otherwise. */
.skip {
  position: absolute;
  left: -9999px;
}
.skip:focus {
  left: 1rem;
  top: 1rem;
  z-index: 100;
  background: var(--ink);
  color: #fff;
  padding: 0.75rem 1rem;
  border-radius: 8px;
}

/* ------------------------------------------------------------------ header */

.site-header {
  position: sticky;
  top: 0;
  z-index: 40;
  background: rgb(255 255 255 / 92%);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}

.site-header .wrap {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.85rem 0;
}

/*
 * The real logo now, not the name set in type.
 *
 * Sized to the height the text wordmark occupied — about 34px of cap height at
 * 1.6rem — so the header keeps the shape it had and nothing below it moves.
 * The old rules stay because they still describe the fallback: if the image
 * fails, the alt text renders and should look like it belonged.
 */
.wordmark img {
  display: block;
  height: 2rem;
  width: auto;
}

@media (max-width: 640px) {
  .wordmark img {
    height: 1.7rem;
  }
}

.wordmark {
  font-weight: 650;
  font-size: 1.6rem;
  letter-spacing: -0.03em;
  text-decoration: none;
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

/* Only drawn if the text mark is ever used again — the logo has its own. */
.wordmark .dot {
  width: 0.8rem;
  height: 0.8rem;
  border-radius: 999px;
  background: var(--accent);
}

.site-nav {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 1.5rem;
}

/* A label never folds inside itself — "In practice" on two lines is not a
   link, it is a typesetting accident. If the row runs out of room, the row
   is what gives way, below. */
.site-nav a {
  white-space: nowrap;
}

/*
 * The tablet band. Seven items and a wordmark fit at 1025px and fit at
 * 760px by wrapping — between the two they used to squeeze, and every
 * two-word label snapped in half. Tighter gaps first; and if the row still
 * cannot hold, the whole nav drops under the wordmark as one clean line
 * rather than crumpling in place.
 */
@media (min-width: 761px) and (max-width: 1024px) {
  .site-header .wrap {
    flex-wrap: wrap;
    row-gap: 0.15rem;
  }

  .site-nav {
    gap: 1rem;
  }

  .site-nav a:not(.btn) {
    font-size: 0.95rem;
  }

  .site-nav .btn {
    min-height: 44px;
    padding: 0.55rem 1.1rem;
  }
}

/*
 * Scoped away from buttons deliberately. `.site-nav a` is a class plus a type
 * selector, which outranks `.btn-primary` — so without the `:not()` the
 * primary button in the header rendered slate grey on near-black and was
 * effectively invisible. Specificity, not colour choice, was the bug.
 */
.site-nav a:not(.btn) {
  text-decoration: none;
  color: var(--ink-soft);
  font-size: 1rem;
  font-weight: 500;
}

.site-nav a:not(.btn):hover {
  color: var(--ink);
}

@media (max-width: 760px) {
  /*
   * No hamburger: a menu you have to open is a menu nobody opens. The nav
   * wraps under the wordmark instead.
   *
   * A wrapping row rather than a fixed grid, because the link count stopped
   * being three — Help and Contact joined, and the old three-column grid
   * pushed them BELOW the buttons, splitting the page links around the pair
   * of actions. Flex lets any number of links fill rows naturally, and the
   * two actions always come last, as one row split a third and two thirds.
   */
  .site-header .wrap {
    flex-wrap: wrap;
    row-gap: 0.25rem;
  }

  .site-nav {
    order: 3;
    width: 100%;
    margin-left: 0;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    column-gap: 0.9rem;
    /* Row rhythm comes from the links' own 44px height, not from gap — the
       buttons are pinned to a distant explicit row, and any row-gap would
       multiply across the empty rows between. */
    row-gap: 0;
    padding-bottom: 0.5rem;
  }

  /* The page links keep a 44px target without looking like buttons. However
     many there are, they fill rows of three; the pair of actions below never
     interleaves with them. */
  .site-nav a:not(.btn):not(.nav-signin) {
    display: flex;
    align-items: center;
    min-height: 44px;
  }

  /* Log in stops being a text link and becomes the ghost half of the pair —
     the action we want somebody to take gets the wider half. Row 20 is
     "after any plausible number of link rows"; the rows between are empty
     and zero-height. */
  .site-nav a.nav-signin {
    grid-row: 20;
    grid-column: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 48px;
    margin-top: 0.4rem;
    padding: 0.7rem 1rem;
    border: 1px solid var(--line);
    border-radius: 12px;
    background: var(--surface);
    font-weight: 600;
    color: var(--ink);
  }

  .site-nav .btn-primary {
    grid-row: 20;
    grid-column: 2 / -1;
    margin-top: 0.4rem;
  }
}

/* ------------------------------------------------------------------ buttons */

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  /* 44px minimum target, as the brief asks. */
  min-height: 48px;
  padding: 0.7rem 1.5rem;
  border-radius: 12px;
  font-size: 1rem;
  font-weight: 600;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition:
    background 0.15s ease,
    border-color 0.15s ease,
    transform 0.15s ease,
    box-shadow 0.15s ease;
}

/* Press states: the button acknowledges the hand. Lift on hover, settle on
   press — a millimetre each way, never a jump. */
.btn:active {
  transform: translateY(0);
}

.btn-primary {
  background: var(--brand);
  color: #fff;
  box-shadow: 0 1px 2px rgb(15 23 42 / 25%), inset 0 1px 0 rgb(255 255 255 / 9%);
}
.btn-primary:hover {
  background: #1e293b;
  transform: translateY(-1px);
  box-shadow: 0 4px 12px rgb(15 23 42 / 22%), inset 0 1px 0 rgb(255 255 255 / 9%);
}

.btn-ghost {
  background: var(--surface);
  color: var(--ink);
  border-color: var(--line);
  box-shadow: 0 1px 2px rgb(15 23 42 / 5%);
}
.btn-ghost:hover {
  background: var(--surface-soft);
  border-color: #cbd5e1;
  transform: translateY(-1px);
}

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

/* -------------------------------------------------------------------- hero */

.hero {
  padding: 5rem 0 4rem;
  /*
   * A wash, not a colour. The page opened on flat white with a lot of air,
   * which read as unfinished rather than calm. Two faint radial pools of the
   * product's own hues give the top of the page a temperature without giving
   * it a background — body text never sits on either.
   */
  background:
    radial-gradient(52rem 26rem at 88% -6rem, rgb(13 148 136 / 7%), transparent 70%),
    radial-gradient(40rem 22rem at -10% 12rem, rgb(2 132 199 / 5%), transparent 70%);
}

/* A chip rather than a floating line of capitals — the page's first small
   proof that things here are made, not typed. */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.78rem;
  font-weight: 650;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--accent-text);
  background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent) 22%, transparent);
  border-radius: 999px;
  padding: 0.35rem 0.9rem;
  margin-bottom: 1.4rem;
}

.eyebrow::before {
  content: '';
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 999px;
  background: var(--accent);
}

.hero h1 {
  font-size: clamp(2.3rem, 5.4vw, 3.65rem);
  font-weight: 800;
  max-width: 19ch;
}

/* The chip's two lengths: full clause where there is room, the short one on
   phones. A chip that wraps is a badge that broke, and a chip shrunk until
   it fits is a badge nobody can read. */
.eyebrow-short {
  display: none;
}

@media (max-width: 560px) {
  .eyebrow {
    font-size: 0.72rem;
    letter-spacing: 0.04em;
    padding: 0.32rem 0.8rem;
  }
  .eyebrow-full {
    display: none;
  }
  .eyebrow-short {
    display: inline;
  }
}

/*
 * Scoped to the hero when it was written, and used on four other sections
 * since — where it rendered as ordinary body text and nobody noticed, because
 * a paragraph that is meant to be larger only looks wrong beside one that is.
 */
.hero p.lede,
p.lede {
  margin-top: 1.25rem;
  font-size: clamp(1.1rem, 2vw, 1.28rem);
  line-height: 1.6;
  color: var(--ink-soft);
}

/* The lead under a section heading sits closer to it than a hero's does. */
.day > p.lede,
.showcase-close p.lede {
  margin-top: 0.9rem;
  max-width: 44rem;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-top: 2rem;
}

@media (max-width: 520px) {
  .hero-actions .btn {
    width: 100%;
  }
}

.assurance {
  margin-top: 1rem;
  font-size: 0.9rem;
  color: var(--ink-faint);
}

/* ------------------------------------------------------------ product frame */

.frame {
  margin-top: 3.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  background: var(--surface-soft);
  /* The one deep shadow on the page — the frame is the hero's picture, and a
     breath of the brand teal in the ambient layer keys it to the wash above. */
  box-shadow:
    0 2px 4px rgb(15 23 42 / 4%),
    0 24px 64px -16px rgb(13 148 136 / 14%),
    0 20px 48px -12px rgb(15 23 42 / 12%);
  overflow: hidden;
}

.frame-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.7rem 1rem;
  border-bottom: 1px solid var(--line);
  background: var(--surface);
}

.frame-bar .pip {
  width: 0.6rem;
  height: 0.6rem;
  border-radius: 999px;
  background: var(--line);
}

.frame-bar .label {
  margin-left: 0.5rem;
  font-size: 0.8rem;
  color: var(--ink-faint);
}

/*
 * The sample diary.
 *
 * The frame used to hold four stat tiles, which said "we count things". The
 * diary is the product, so the frame shows the diary: a morning drawn at the
 * proportions of the real screen, colour meaning appointment kind the way the
 * app teaches, and a day view and a week view taking turns the way the real
 * view switcher does.
 *
 * The day view sits in normal flow and gives the stage its height; the week
 * view is laid over it. The whole rotation is two opacity keyframes — no
 * script, nothing to fail, and with animations off the day view simply stays,
 * which is also what reduced-motion gets.
 */
.diary-stage {
  position: relative;
}

.dview-day {
  padding: 1.25rem 1.5rem 1.5rem;
}

.dview-week,
.dview-month {
  position: absolute;
  inset: 0;
  padding: 1.25rem 1.5rem 1.5rem;
  opacity: 0;
  background: var(--surface-soft);
}

/* Three views, six seconds each, one shared 18-second clock. */
.dview-day   { animation: dview-a 18s ease-in-out infinite; }
.dview-week  { animation: dview-b 18s ease-in-out infinite; }
.dview-month { animation: dview-c 18s ease-in-out infinite; }

@keyframes dview-a {
  0%, 29%   { opacity: 1; }
  33%, 96%  { opacity: 0; }
  100%      { opacity: 1; }
}

@keyframes dview-b {
  0%, 29%   { opacity: 0; }
  33%, 62%  { opacity: 1; }
  66%, 100% { opacity: 0; }
}

@keyframes dview-c {
  0%, 62%   { opacity: 0; }
  66%, 96%  { opacity: 1; }
  100%      { opacity: 0; }
}

/* The view switcher, echoed. Not buttons — the frame is a picture, and a
   control that does nothing is a lie. They light in step with the views. */
.frame-tabs {
  margin-left: auto;
  display: flex;
  gap: 0.25rem;
}

.ftab {
  font-size: 0.72rem;
  font-weight: 600;
  padding: 0.15rem 0.6rem;
  border-radius: 999px;
  color: var(--ink-faint);
}

.ftab-day {
  background: var(--accent-soft);
  color: var(--accent-text);
  animation: ftab-a 18s ease-in-out infinite;
}

.ftab-week {
  animation: ftab-b 18s ease-in-out infinite;
}

.ftab-month {
  animation: ftab-c 18s ease-in-out infinite;
}

@keyframes ftab-a {
  0%, 29%   { background: var(--accent-soft); color: var(--accent-text); }
  33%, 96%  { background: transparent; color: var(--ink-faint); }
  100%      { background: var(--accent-soft); color: var(--accent-text); }
}

@keyframes ftab-b {
  0%, 29%   { background: transparent; color: var(--ink-faint); }
  33%, 62%  { background: var(--accent-soft); color: var(--accent-text); }
  66%, 100% { background: transparent; color: var(--ink-faint); }
}

@keyframes ftab-c {
  0%, 62%   { background: transparent; color: var(--ink-faint); }
  66%, 96%  { background: var(--accent-soft); color: var(--accent-text); }
  100%      { background: transparent; color: var(--ink-faint); }
}

/* --- the day --- */

.d-grid {
  display: grid;
  grid-template-columns: 3.2rem repeat(3, 1fr);
  gap: 0.4rem 0.6rem;
  align-items: stretch;
}

.d-head {
  font-size: 0.75rem;
  font-weight: 600;
  color: var(--ink-soft);
  padding-bottom: 0.15rem;
}

.d-time {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--ink-faint);
  text-align: right;
  padding: 0.45rem 0.35rem 0 0;
  font-variant-numeric: tabular-nums;
}

.d-slot {
  position: relative;
  min-height: 2.3rem;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.25rem 0.4rem;
  padding: 0.35rem 0.65rem 0.35rem 0.8rem;
  border-radius: 8px;
  font-size: 0.78rem;
  background: color-mix(in srgb, var(--hue) 9%, var(--surface));
  overflow: hidden;
}

.d-slot::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--hue);
}

.d-slot b {
  font-weight: 600;
  color: var(--ink);
}

.d-slot i {
  font-style: normal;
  color: var(--ink-soft);
}

.d-tick {
  font-style: normal;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--accent-text);
  background: var(--accent-soft);
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
  white-space: nowrap;
}

/* The note, because an appointment is more than its booking: written during
   the morning, signed behind the ones already seen. Quieter than the arrival
   tick — a record, not an event. */
.d-note {
  font-style: normal;
  font-size: 0.68rem;
  font-weight: 600;
  color: var(--ink-soft);
  background: var(--surface-sunk);
  border-radius: 999px;
  padding: 0.05rem 0.45rem;
  white-space: nowrap;
}

/* Lunch runs across every practitioner, the way a closed hour does. */
.d-slot.d-break {
  grid-column: 2 / -1;
  justify-content: center;
  background: transparent;
  border: 1px dashed var(--line);
  color: var(--ink-faint);
  font-weight: 550;
}

.d-slot.d-break::before {
  display: none;
}

/* The class spans two slots, because a class does. */
.d-tall {
  grid-row: span 2;
}

/* The gap, and the proof the diary already knows who fills it. */
.d-slot.d-free {
  background: transparent;
  border: 1px dashed var(--accent);
  color: var(--accent-text);
  font-weight: 600;
}

.d-slot.d-free::before {
  display: none;
}

/* --- the week --- */

.w-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 0.6rem;
  height: 100%;
}

.w-col {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  min-height: 0;
}

.w-head {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--ink-faint);
  padding-bottom: 0.15rem;
}

.w-col i {
  display: block;
  border-radius: 5px;
  background: color-mix(in srgb, var(--hue) 55%, var(--surface));
}

.w-col .h1 { flex: 2; }
.w-col .h2 { flex: 3; }
.w-col .h3 { flex: 4; }
.w-col .h4 { flex: 6; }

.w-col .w-free {
  background: transparent;
  border: 1px dashed var(--line);
}

/* --- the month --- */

.m-grid {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  grid-template-rows: auto repeat(4, 1fr);
  gap: 0.3rem 0.35rem;
  height: 100%;
}

.m-cell {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  gap: 0.2rem;
  padding: 0.3rem 0.45rem;
  border: 1px solid var(--line);
  border-radius: 6px;
  background: var(--surface);
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
  color: var(--ink-faint);
  min-height: 0;
}

/* Today, ringed the way the app rings it. */
.m-cell.m-today {
  border-color: var(--accent);
  box-shadow: 0 0 0 1px var(--accent);
}

.m-cell.m-today > span:first-child {
  color: var(--accent-text);
  font-weight: 650;
}

.m-dots {
  display: flex;
  flex-wrap: wrap;
  gap: 3px;
}

.m-dots i {
  width: 6px;
  height: 6px;
  border-radius: 999px;
  background: color-mix(in srgb, var(--hue) 70%, var(--surface));
}

@media (prefers-reduced-motion: reduce) {
  /* The global rule shrinks durations to nothing, which for an infinite
     opacity loop means flicker. These stop properly: the day view stays. */
  .dview-day,
  .dview-week,
  .dview-month,
  .ftab-day,
  .ftab-week,
  .ftab-month {
    animation: none;
  }
}

@media (max-width: 560px) {
  /* The names and the pills go before the grid does — kind and colour still
     carry it, and three columns on a phone have no room for a badge. */
  .d-slot i,
  .d-slot .d-tick,
  .d-slot .d-note {
    display: none;
  }
  .d-grid {
    grid-template-columns: 2.4rem repeat(3, 1fr);
    gap: 0.35rem 0.4rem;
  }
  .d-slot {
    padding: 0.35rem 0.45rem 0.35rem 0.6rem;
    font-size: 0.72rem;
  }
  .dview-day,
  .dview-week,
  .dview-month {
    padding: 1rem;
  }
  /* The tabs take their own row rather than folding the label beside them. */
  .frame-bar {
    flex-wrap: wrap;
    row-gap: 0.35rem;
  }
  .frame-tabs {
    margin-left: 0;
    width: 100%;
  }
}

/* ---------------------------------------------------------------- sections */

section {
  padding: 5.5rem 0;
}

section.soft {
  background: var(--surface-soft);
  border-block: 1px solid var(--line);
}

.section-head {
  max-width: var(--measure);
  margin-bottom: 3rem;
}

.section-head h2 {
  font-size: clamp(1.8rem, 3.6vw, 2.5rem);
  text-wrap: balance;
}

.section-head p {
  margin-top: 0.85rem;
  color: var(--ink-soft);
}

/* ---------------------------------------------------------------- workflow */

.steps {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  list-style: none;
  padding: 0;
  margin: 0;
  counter-reset: step;
}

.steps li {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.6rem;
}

.steps li h3 {
  font-size: 1.08rem;
  margin-top: 0.7rem;
  letter-spacing: -0.01em;
}

.steps li p {
  margin-top: 0.5rem;
  font-size: 0.97rem;
  color: var(--ink-soft);
}

.step-no {
  display: inline-grid;
  place-items: center;
  width: 1.75rem;
  height: 1.75rem;
  border-radius: 8px;
  background: var(--accent-soft);
  color: var(--accent-text);
  font-size: 0.8rem;
  font-weight: 650;
}

/* ---------------------------------------------------------------- features */

.bands {
  display: grid;
  gap: 5rem;
}

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

@media (min-width: 900px) {
  .band {
    grid-template-columns: 1fr 1fr;
    gap: 3.5rem;
  }
  /* Alternating sides, but source order never changes — a screen reader
     hears the heading before its evidence either way. */
  .band:nth-child(even) .band-media {
    order: -1;
  }
}

.band h3 {
  font-size: 1.5rem;
}

.band > div > p {
  margin-top: 0.75rem;
  color: var(--ink-soft);
}

.ticks {
  list-style: none;
  padding: 0;
  margin: 1.5rem 0 0;
  display: grid;
  gap: 0.75rem;
}

.ticks li {
  display: flex;
  gap: 0.7rem;
  font-size: 1rem;
  color: var(--ink-soft);
}

.ticks svg {
  flex: none;
  width: 1.1rem;
  height: 1.1rem;
  margin-top: 0.2rem;
  color: var(--accent-text);
}

.band-media {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 1.25rem;
  display: grid;
  gap: 0.75rem;
  align-content: start;
}

.row {
  display: flex;
  align-items: center;
  gap: 0.85rem;
  padding: 0.8rem 0.95rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  font-size: 0.88rem;
}

.row .grow {
  flex: 1;
  min-width: 0;
}

.row .muted {
  color: var(--ink-faint);
  font-size: 0.8rem;
}

.pill {
  font-size: 0.72rem;
  font-weight: 600;
  padding: 0.15rem 0.5rem;
  border-radius: 999px;
  white-space: nowrap;
}

.pill-green {
  background: #ecfdf5;
  color: #047857;
}
.pill-amber {
  background: #fffbeb;
  color: var(--warn);
}
.pill-slate {
  background: var(--surface-sunk);
  color: var(--ink-soft);
}

.swatch {
  width: 0.55rem;
  height: 2rem;
  border-radius: 4px;
  flex: none;
}

/* ------------------------------------------------------------------- lists */

.grid-cards {
  display: grid;
  gap: 1.25rem;
  grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
}

.card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 1.6rem;
}

.card h3 {
  font-size: 1.05rem;
}

.card p {
  margin-top: 0.6rem;
  font-size: 0.97rem;
  color: var(--ink-soft);
}

.card ul {
  margin: 0.75rem 0 0;
  padding-left: 1.1rem;
  font-size: 0.9rem;
  color: var(--ink-soft);
}

.card li {
  margin-top: 0.3rem;
}

/* -------------------------------------------------------------------- FAQ */

details {
  border-bottom: 1px solid var(--line);
  padding: 1.4rem 0;
}

summary {
  cursor: pointer;
  font-weight: 550;
  list-style: none;
  display: flex;
  justify-content: space-between;
  gap: 1rem;
  align-items: center;
}

summary::-webkit-details-marker {
  display: none;
}

summary::after {
  content: '+';
  color: var(--ink-faint);
  font-size: 1.2rem;
  flex: none;
}

details[open] summary::after {
  content: '−';
}

details p {
  margin-top: 0.75rem;
  color: var(--ink-soft);
}

/* ------------------------------------------------------------------- forms */

.form-card {
  background: var(--surface);
  border: 1px solid var(--line);
  border-radius: var(--radius-lg);
  padding: clamp(1.25rem, 4vw, 2rem);
  box-shadow: var(--shadow);
}

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

/* A persistent label, never a placeholder standing in for one. */
.field > span {
  display: block;
  font-size: 0.88rem;
  font-weight: 550;
  margin-bottom: 0.35rem;
}

.field input,
.field select,
.field textarea {
  width: 100%;
  min-height: 44px;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--line);
  border-radius: 10px;
  font: inherit;
  font-size: 0.95rem;
  color: var(--ink);
  background: var(--surface);
}

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

.field .hint {
  display: block;
  font-size: 0.8rem;
  color: var(--ink-faint);
  margin-top: 0.3rem;
  font-weight: 400;
}

.two-up {
  display: grid;
  gap: 1rem;
}

@media (min-width: 620px) {
  .two-up {
    grid-template-columns: 1fr 1fr;
  }
  .two-up .field {
    margin-top: 0;
  }
}

/* The honeypot. Hidden from sight and from screen readers, since no human
   should ever be offered it. */
.trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.consent {
  margin-top: 1.25rem;
  font-size: 0.85rem;
  color: var(--ink-faint);
}

.form-status {
  margin-top: 1rem;
  padding: 0.75rem 1rem;
  border-radius: 10px;
  font-size: 0.92rem;
}

.form-status.ok {
  background: #ecfdf5;
  color: #065f46;
}

.form-status.bad {
  background: #fef2f2;
  color: #991b1b;
}

.form-status[hidden] {
  display: none;
}

/* ------------------------------------------------------------------ footer */

.site-footer {
  border-top: 1px solid var(--line);
  /* Sunk a shade below the page, so the end of the page reads as a floor
     rather than as more page that happens to have run out of words. */
  background: var(--surface-soft);
  padding: 3rem 0 2.5rem;
  font-size: 0.9rem;
  color: var(--ink-faint);
}

.site-footer .wrap {
  display: grid;
  /*
   * Four columns that become two, then one — by asking for a minimum width
   * rather than naming breakpoints. A footer is the last thing anybody tunes
   * and the first thing that breaks on a phone.
   */
  grid-template-columns: repeat(auto-fit, minmax(11rem, 1fr));
  gap: 2rem;
  align-items: start;
}

/* The first column carries the mark and the sentence, so it takes the room. */
.site-footer .wrap > .foot-col:first-child {
  grid-column: span 2;
  max-width: 22rem;
}

@media (max-width: 560px) {
  /*
   * Two link columns abreast, not four stacked. Every link is a 44px thumb
   * target, which is right — but single file that made the footer a
   * thousand pixels of scrolling past three words at a time. The phone has
   * the width for two columns; only the blurb needs the whole line.
   */
  .site-footer .wrap {
    grid-template-columns: 1fr 1fr;
    gap: 1.5rem 1.25rem;
  }

  .site-footer .wrap > .foot-col:first-child {
    grid-column: span 2;
  }

  /* Product is the tall column; letting it span two rows means Sign in and
     Clinifyd stack beside it instead of leaving its length as dead space. */
  .site-footer .wrap > .foot-col:nth-child(2) {
    grid-row: span 2;
  }
}

.foot-col {
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
  align-items: flex-start;
}

/* Nudged down so a column of links starts level with the wordmark beside it,
   which is an image and sits lower than a line of text does. */
.foot-head {
  margin: 0.35rem 0 0.15rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.foot-note {
  margin: 0;
  font-size: 0.88rem;
  line-height: 1.6;
  color: var(--ink-faint);
}

/* Said plainly and once. A flag and a full stop, not a badge. */
.foot-made {
  margin: 0;
  font-size: 0.88rem;
  color: var(--ink-soft);
}

.foot-legal {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem 1.5rem;
  margin-top: 2.5rem;
  padding-top: 1.25rem;
  border-top: 1px solid var(--line);
  font-size: 0.82rem;
  color: var(--ink-faint);
}

.site-footer a {
  color: var(--ink-soft);
  text-decoration: none;
}

.site-footer a:hover {
  color: var(--ink);
}



@media (max-width: 620px) {
  .site-footer .right {
    margin-left: 0;
  }
}

/* --------------------------------------------------------------- utilities */

.badge-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  margin-top: 1.5rem;
}

.badge {
  font-size: 0.82rem;
  padding: 0.35rem 0.75rem;
  border-radius: 999px;
  border: 1px solid var(--line);
  color: var(--ink-soft);
  background: var(--surface);
}

.note {
  border-left: 3px solid var(--accent);
  padding-left: 1rem;
  color: var(--ink-soft);
  font-size: 0.95rem;
}


/* ---------------------------------------------------------------- the nav */

/*
 * Signing in, at the top where customers look for it.
 *
 * Quieter than Register interest on purpose. Both are at the top now, and if
 * they shouted equally a visitor would have to read both to work out which one
 * is for them — the one selling and the one serving should not look alike.
 */
.nav-signin {
  font-weight: 600;
  border: 1px solid var(--line);
  border-radius: 0.55rem;
  padding: 0.4rem 0.85rem;
  text-decoration: none;
}

.nav-signin:hover {
  background: var(--surface-sunk);
}

/* Where you are, marked rather than guessed at. */
.site-nav a.here {
  color: var(--ink);
  font-weight: 650;
  text-decoration: underline;
  text-underline-offset: 0.35rem;
}

@media (max-width: 640px) {
  .wordmark {
    font-size: 1.35rem;
  }
  /* The nav's phone layout lives in the 760px block above — a flex gap set
     here once overrode that grid's row-gap and opened 150px of nothing
     between the links and the buttons. One breakpoint owns the nav. */
}


/* A card that is a link should say so before it is hovered. */
a.card {
  text-decoration: none;
  display: block;
  transition:
    border-color 0.2s ease,
    transform 0.2s ease,
    box-shadow 0.2s ease;
}

a.card:hover {
  border-color: var(--accent-text);
  transform: translateY(-3px);
  box-shadow: var(--shadow-lift);
}

a.card h3::after {
  content: ' →';
  color: var(--accent-text);
}

/* The arrow keeps the card's hue where one is declared, so the invitation to
   click speaks the same colour as the icon above it. */
a.card[data-hue] h3::after {
  color: var(--hue);
}

a.card[data-hue]:hover {
  border-color: color-mix(in srgb, var(--hue) 55%, transparent);
}

/*
 * The icon chip on the home page's map cards.
 *
 * The same stroke icons the features page shows at rail size, here in a tinted
 * square of the part's own hue — the roadmap's colour vocabulary, spoken one
 * page earlier. The tint stays under 12% so the icon reads as a marker, not a
 * button.
 */
.card-icon {
  display: inline-grid;
  place-items: center;
  width: 2.5rem;
  height: 2.5rem;
  margin-bottom: 0.95rem;
  border-radius: 10px;
  background: color-mix(in srgb, var(--hue, var(--accent)) 11%, transparent);
  color: var(--hue, var(--accent-text));
}

.card-icon svg {
  width: 1.3rem;
  height: 1.3rem;
}

/* ------------------------------------------------------------- the flow --
 *
 * Five stages in one row — the compressed clinic day. Deliberately not the
 * clinic-day page's card grid: two pages using one shape read as one page.
 * The single line IS the claim: nothing is retyped between the stages.
 */
.flow {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.75rem 0.6rem;
}

.flow li {
  display: inline-flex;
  align-items: center;
}

/* The arrow between stages carries meaning — order — but reads as noise
   aloud, so it is written with empty alternative text. */
.flow li + li::before {
  content: '→' / '';
  color: var(--ink-faint);
  margin-right: 0.6rem;
}

/*
 * Where there is room, the row takes all of it.
 *
 * Five pills huddled on the left read as a list; five spread across the
 * width with a line running between them read as a path — which is the
 * claim. Each connector wears the hue of the stage it leads into, so the
 * line changes colour as the appointment moves. On a phone the pills wrap
 * and the arrows come back, because a stretched line across a wrapped row
 * points at nothing.
 */
@media (min-width: 700px) {
  .flow {
    flex-wrap: nowrap;
    justify-content: space-between;
  }

  .flow li + li {
    flex: 1;
  }

  .flow li + li::before {
    content: '' / '';
    flex: 1;
    height: 2px;
    border-radius: 1px;
    margin: 0 0.85rem;
    background: color-mix(in srgb, var(--hue) 45%, var(--line));
  }
}

.flow-step {
  display: inline-flex;
  align-items: center;
  gap: 0.55rem;
  padding: 0.6rem 1.1rem;
  border: 1px solid color-mix(in srgb, var(--hue) 32%, var(--line));
  border-radius: 999px;
  background: color-mix(in srgb, var(--hue) 6%, var(--surface));
  font-size: 0.97rem;
  font-weight: 600;
  color: var(--ink);
  white-space: nowrap;
}

.flow-dot {
  width: 0.55rem;
  height: 0.55rem;
  border-radius: 999px;
  background: var(--hue);
}

.flow-note {
  margin-top: 1.75rem;
  font-size: 0.97rem;
}

.flow-note a {
  color: var(--accent-text);
  font-weight: 550;
  text-decoration: underline;
  text-underline-offset: 0.25rem;
}

.flow-note a:hover {
  color: var(--ink);
}

/* ------------------------------------------------------------ the close --
 *
 * The page's last word, centred because it is the only section with one
 * thing to say. The facts row carries the three promises the software is
 * built around — each argued in full elsewhere, stated plainly here.
 */
.home-close {
  text-align: center;
}

.home-close h2 {
  font-size: clamp(1.75rem, 3.6vw, 2.45rem);
}

.home-close p.lede {
  margin-inline: auto;
  max-width: 44rem;
}

.facts {
  list-style: none;
  margin: 1.75rem 0 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.65rem 1.9rem;
  font-size: 0.95rem;
  color: var(--ink-soft);
}

.facts li {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
}

.facts svg {
  width: 1rem;
  height: 1rem;
  flex: none;
  color: var(--accent-text);
}

.home-close .hero-actions {
  justify-content: center;
  margin-top: 2.25rem;
}

/* ============================================================== showcase ==
 *
 * The features page. Six things, one screen at a time.
 *
 * Everything is visible by default and the animation is added by script, so a
 * failure to run it leaves a readable page rather than a blank one. That is
 * the whole rule for decoration: it may never be load-bearing.
 */

.showcase-lead {
  padding-block: 4rem 1rem;
  max-width: 46rem;
}

.showcase {
  padding-block: 4.5rem;
  /* The watermark lives inside the section and past its edges; nothing may
     leak into the neighbours. */
  position: relative;
  overflow: hidden;
}

/* The copy and the demo paint above the watermark, whatever the DOM order. */
.showcase > .wrap {
  position: relative;
}

/*
 * The section's own icon, blown up to a watermark.
 *
 * The roadmap already does this inside its tiles — the same stroke icon the
 * app uses, enlarged past the edges, faint enough to place the row without
 * competing with it. Here it is the section-sized version: each argument
 * carries the icon of the part of the product it argues for, in that
 * section's hue, at an opacity where it reads as texture rather than as a
 * picture. Each one leans out of a different corner, so the page does not
 * stamp seven copies of one arrangement.
 *
 * Deliberately still. The demos in front of it already move; a giant shape
 * drifting behind text is the kind of decoration a reader has to ignore.
 */
.showcase-mark {
  position: absolute;
  width: clamp(15rem, 28vw, 24rem);
  height: auto;
  color: var(--hue);
  opacity: 0.05;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.1;
  stroke-linecap: round;
  stroke-linejoin: round;
  pointer-events: none;
}

/* Corner by corner, deterministic but irregular — placed, not patterned. */
.showcase[data-hue='sky'] .showcase-mark     { right: -5rem;  top: -4rem;    transform: rotate(8deg); }
.showcase[data-hue='teal'] .showcase-mark    { left: -6rem;   bottom: -5rem; transform: rotate(-10deg); }
.showcase[data-hue='emerald'] .showcase-mark { right: -4rem;  bottom: -6rem; transform: rotate(12deg); }
.showcase[data-hue='rose'] .showcase-mark    { left: -5rem;   top: -3rem;    transform: rotate(-8deg); }
.showcase[data-hue='indigo'] .showcase-mark  { right: -6rem;  top: 50%;      transform: translateY(-50%) rotate(9deg); }
.showcase[data-hue='violet'] .showcase-mark  { left: -4rem;   top: -5rem;    transform: rotate(-12deg); }
.showcase[data-hue='amber'] .showcase-mark   { right: -5rem;  bottom: -4rem; transform: rotate(7deg); }

@media (max-width: 700px) {
  /* On a phone the corners are where the words are. The small icons in the
     capability grid keep doing this job at that size. */
  .showcase-mark {
    display: none;
  }
}

@media (prefers-contrast: more) {
  /* A 5% drawing behind text is exactly what this setting asks to be rid of. */
  .showcase-mark {
    display: none;
  }
}

.showcase.alt {
  background: var(--accent-soft);
}

.showcase-grid {
  display: grid;
  gap: 2.5rem;
  align-items: center;
  grid-template-columns: 1fr;
}

@media (min-width: 860px) {
  .showcase-grid {
    grid-template-columns: 1fr 1fr;
    gap: 4rem;
  }
}

.showcase-number {
  display: block;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  color: var(--accent-text);
}

.showcase-copy h2 {
  margin-top: 0.6rem;
  font-size: 1.75rem;
  letter-spacing: -0.02em;
}

.showcase-copy p {
  margin-top: 0.9rem;
  color: var(--ink-soft);
}

.showcase-note {
  font-size: 0.92rem;
  border-left: 2px solid var(--accent);
  padding-left: 0.9rem;
}

.showcase-close {
  padding-block: 5rem;
  text-align: center;
  max-width: 40rem;
}

.showcase-close .btn {
  margin-top: 1.5rem;
}

/* ------------------------------------------------------------ the demos */

.demo {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  padding: 1.4rem;
}

.demo-bar {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--accent-text);
  padding-bottom: 0.9rem;
  border-bottom: 1px solid var(--line);
}

.live-dot {
  width: 0.5rem;
  height: 0.5rem;
  border-radius: 999px;
  background: var(--accent);
  animation: pulse 1.8s ease-in-out infinite;
}

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

.demo-lines p {
  margin-top: 0.75rem;
  padding: 0.55rem 0.85rem;
  border-radius: 1rem;
  font-size: 0.92rem;
  max-width: 85%;
}

.from-them {
  background: var(--surface-sunk);
}

.from-her {
  background: var(--accent-text);
  color: #fff;
  margin-left: auto;
}

.from-her.booked {
  font-weight: 600;
}

/* Each line lands after the one before, so it reads as a conversation
   happening rather than a screenshot of one. */
.revealed .demo-lines p {
  animation: rise 0.5s ease both;
}

.revealed .demo-lines p:nth-child(1) { animation-delay: 0.1s; }
.revealed .demo-lines p:nth-child(2) { animation-delay: 0.7s; }
.revealed .demo-lines p:nth-child(3) { animation-delay: 1.3s; }
.revealed .demo-lines p:nth-child(4) { animation-delay: 1.9s; }

@keyframes rise {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: none; }
}

.ledger-row {
  display: flex;
  justify-content: space-between;
  padding: 0.6rem 0;
  border-bottom: 1px solid var(--line);
  font-variant-numeric: tabular-nums;
  font-size: 0.95rem;
}

.ledger-row.muted { color: var(--ink-soft); }

.ledger-row.total {
  font-weight: 700;
  border-bottom: none;
  color: var(--accent-text);
}

.ledger-note {
  margin-top: 0.9rem;
  font-size: 0.82rem;
  color: var(--ink-soft);
}

.demo-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
}

.chip {
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 0.45rem 0.95rem;
  font-size: 0.9rem;
  font-weight: 600;
  background: var(--surface);
}

.revealed .chip { animation: rise 0.4s ease both; }
.revealed .chip:nth-child(2) { animation-delay: 0.08s; }
.revealed .chip:nth-child(3) { animation-delay: 0.16s; }
.revealed .chip:nth-child(4) { animation-delay: 0.24s; }
.revealed .chip:nth-child(5) { animation-delay: 0.32s; }
.revealed .chip:nth-child(6) { animation-delay: 0.4s; }

.day-slot {
  padding: 0.7rem 0.9rem;
  border-radius: 0.6rem;
  margin-bottom: 0.5rem;
  font-size: 0.92rem;
  font-variant-numeric: tabular-nums;
}

.day-slot.filled { background: var(--surface-sunk); }

.day-slot.free {
  border: 1px dashed var(--accent);
  color: var(--accent-text);
  font-weight: 600;
}

.demo-map {
  position: relative;
  min-height: 9rem;
  display: grid;
  place-items: center;
}

.pin {
  width: 0.85rem;
  height: 0.85rem;
  border-radius: 999px;
  background: var(--accent);
  box-shadow: 0 0 0 0 rgba(13, 148, 136, 0.5);
  animation: ripple 2.2s ease-out infinite;
}

.pin-label {
  position: absolute;
  transform: translateY(1.7rem);
  font-size: 0.85rem;
  font-weight: 600;
  color: var(--ink-soft);
}

@keyframes ripple {
  to { box-shadow: 0 0 0 2.5rem rgba(13, 148, 136, 0); }
}

.demo-quote p {
  font-size: 1.4rem;
  font-weight: 650;
  letter-spacing: -0.02em;
  text-align: center;
  padding: 1.5rem 0;
}

/* ------------------------------------------------------------ revealing */

/*
 * Added by script, never by default. A page that starts invisible and depends
 * on JavaScript to appear is a page that is sometimes blank.
 */
.will-reveal {
  opacity: 0;
  transform: translateY(18px);
}

.will-reveal.revealed {
  opacity: 1;
  transform: none;
  transition: opacity 0.6s ease, transform 0.6s ease;
}

@media (prefers-reduced-motion: reduce) {
  .will-reveal,
  .revealed .demo-lines p,
  .revealed .chip {
    opacity: 1;
    transform: none;
    animation: none;
    transition: none;
  }

  .live-dot,
  .pin {
    animation: none;
  }
}

/* The hour that opened up, and who was waiting for it. */
.day-slot.vacated {
  border: 1px dashed var(--line);
  color: var(--ink-soft);
  text-decoration: line-through;
}

.waiting {
  margin: 0.5rem 0 0.75rem;
  padding: 0.75rem 0.9rem;
  border-radius: 0.6rem;
  background: rgba(13, 148, 136, 0.07);
  border: 1px solid rgba(13, 148, 136, 0.25);
  display: grid;
  gap: 0.4rem;
}

.waiting-head {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--accent-text);
}

.waiting-row {
  font-size: 0.88rem;
  color: var(--ink-soft);
}

/* It appears a beat after the cancellation, because that is the point being
   made: the gap and the answer arrive together. */
.revealed .waiting {
  animation: rise 0.5s ease both;
  animation-delay: 0.55s;
}

@media (prefers-reduced-motion: reduce) {
  .revealed .waiting {
    animation: none;
  }
}

/* ------------------------------------------------------ page headings ---
 *
 * The pages that are not the home page still need one h1, and it should not
 * inherit the hero's size — a section heading promoted to h1 for the document
 * outline should not suddenly shout.
 */
main > section > .wrap > h1,
main > section.wrap > h1 {
  font-size: clamp(1.9rem, 4vw, 2.5rem);
  letter-spacing: -0.02em;
}

/*
 * Anything clickable says so.
 *
 * A card that is a link, a summary that opens, a label that ticks a box — the
 * pointer is the cheapest possible signal that something will happen, and its
 * absence reads as a dead page.
 */
a,
button,
summary,
label,
input[type='checkbox'],
input[type='radio'] {
  cursor: pointer;
}

input[type='text'],
input[type='email'],
input[type='url'],
textarea,
select {
  cursor: auto;
}

/* Movement worth noticing, at a speed nobody has to wait for. Under 150ms
   reads as a flicker; over 300ms reads as lag. */
a,
.btn,
.card,
summary {
  transition:
    color 0.2s ease,
    background-color 0.2s ease,
    border-color 0.2s ease,
    transform 0.2s ease;
}

@media (prefers-reduced-motion: reduce) {
  a,
  .btn,
  .card,
  summary {
    transition: none;
  }
}

/* ------------------------------------------------------------ no sideways --
 *
 * A page that scrolls horizontally on a phone is the most common responsive
 * failure and the least often noticed, because it does not happen on the
 * machine it was built on. Cheap insurance: nothing may push the document
 * wider than the screen, and anything that would rather scroll inside itself.
 */
html,
body {
  max-width: 100%;
  overflow-x: hidden;
}

img,
svg,
video,
table {
  max-width: 100%;
  height: auto;
}

pre,
code {
  overflow-x: auto;
  word-break: break-word;
}

/* --------------------------------------------------------------- the track */

/*
 * The roadmap, as a line rather than a grid of cards.
 *
 * It was six identical cards, which is the shape "In practice" already uses —
 * two pages that look alike read as one page you have already seen. A track
 * carries what a grid cannot: order, and what state each thing is in.
 *
 * **Colour does the work of a legend.** The diary already teaches that colour
 * means a kind of thing, and the Manage section already colours its groups —
 * so each item takes the hue of the part of the product it belongs to, and the
 * icon behind it is the same stroke icon that part uses in the app. Somebody
 * who has used Clinifyd for a week recognises the page before reading it.
 */
.track {
  list-style: none;
  margin: 2.5rem 0 0;
  padding: 0;
}

/* One variable per row. Everything below reads `--hue`, so a new colour is a
   data attribute rather than another block of rules. */
.track-item[data-hue='teal']    { --hue: #0d9488; }
.track-item[data-hue='sky']     { --hue: #0284c7; }
.track-item[data-hue='indigo']  { --hue: #4f46e5; }
.track-item[data-hue='violet']  { --hue: #7c3aed; }
.track-item[data-hue='emerald'] { --hue: #059669; }
.track-item[data-hue='amber']   { --hue: #b45309; }
.track-item[data-hue='rose']    { --hue: #e11d48; }
.track-item[data-hue='slate']   { --hue: #64748b; }

.track-item {
  position: relative;
  display: grid;
  grid-template-columns: 1.25rem 1fr 6.5rem;
  gap: 0 1.25rem;
  align-items: start;
  padding: 0 0 2.25rem;
}

/* The spine, drawn per item so the last one can stop rather than trail into
   nothing. It takes the row's colour, so the line changes as you read down. */
.track-item::before {
  content: '';
  position: absolute;
  left: 0.5rem;
  /* Starts under the dot rather than through it. */
  top: 1.55rem;
  bottom: -0.25rem;
  width: 2px;
  background: color-mix(in srgb, var(--hue) 28%, transparent);
}

.track-item:last-child::before {
  display: none;
}

.track-dot {
  position: relative;
  z-index: 1;
  width: 1.05rem;
  height: 1.05rem;
  /* On the state label's line, so the dot reads as marking the row rather
     than sitting between two of them. */
  margin-top: 0.28rem;
  border-radius: 999px;
  border: 2px solid var(--hue);
  background: var(--bg);
}

/* Filled means done, an outline means in progress, dashed means not started —
   legible before the label is read. */
.track-item.is-live .track-dot {
  background: var(--hue);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--hue) 14%, transparent);
}

.track-item.is-next .track-dot,
.track-item.is-maybe .track-dot {
  border-style: dashed;
  border-color: color-mix(in srgb, var(--hue) 55%, transparent);
}

.track-state {
  margin: 0 0 0.15rem;
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

/* Only the shipped ones get colour on the label. Everything coloured is
   nothing coloured. */
.track-item.is-live .track-state {
  color: var(--hue);
}

.track-body h3 {
  margin: 0 0 0.35rem;
  font-size: 1.15rem;
  letter-spacing: -0.01em;
}

.track-body p {
  margin: 0;
  color: var(--ink-soft);
  line-height: 1.65;
}

.track-art {
  position: relative;
  height: 4.5rem;
  /* Aligned to the cap-height of the state label beside it, not to the top of
     its line box — otherwise the tile floats a few pixels above the words and
     eleven rows all look very slightly wrong without saying why. */
  margin-top: 0.15rem;
  border-radius: 12px;
  background: color-mix(in srgb, var(--hue) 7%, transparent);
  overflow: hidden;
}

/*
 * The icon behind it, big and faint.
 *
 * The same stroke icon the Manage section uses for that part of the product,
 * blown past the edges of its tile. It is a watermark, not a picture: it says
 * which corner of the app this belongs to at a glance, and never competes with
 * the small thing moving in front of it.
 */
.art-mark {
  position: absolute;
  right: -18%;
  bottom: -22%;
  width: 78%;
  height: auto;
  color: var(--hue);
  opacity: 0.16;
  pointer-events: none;
}

@media (max-width: 700px) {
  /* The pictures go before the words do. A tile this size on a 360px screen
     is decoration competing with the sentence that matters. */
  .track-item {
    grid-template-columns: 1.25rem 1fr;
  }
  .track-art {
    display: none;
  }
}

/* ------------------------------------------------------------ the pictures */

/*
 * Every one is CSS on empty spans — transform and opacity only, so they run on
 * the compositor. No images to load, no canvas, no JavaScript loop, and
 * nothing to go wrong if one fails to paint.
 *
 * They were all the same rhythm at first, which read as one animation repeated
 * eleven times. Each of these now moves in a way that matches what it is: a
 * call rings outward, a day fills upward, a text goes and one comes back, a
 * claim rises, rows land, a door swings, sessions orbit, a pulse beats, rows
 * sort themselves.
 */
.art {
  position: absolute;
  inset: 0;
  display: block;
}

.art i {
  position: absolute;
  display: block;
  border-radius: 3px;
  background: var(--hue);
  will-change: transform, opacity;
}

/* A call arriving: rings going outward. */
.art-phone i {
  left: 32%;
  top: 50%;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  border-radius: 999px;
  background: none;
  border: 2px solid var(--hue);
  animation: art-ring 3s ease-out infinite;
}
.art-phone i:nth-child(2) { animation-delay: 1s; }
.art-phone i:nth-child(3) { animation-delay: 2s; }

@keyframes art-ring {
  0%   { transform: scale(0.35); opacity: 0.95; }
  100% { transform: scale(2.8); opacity: 0; }
}

/* A day filling up, bottom to top. */
.art-diary i {
  width: 16%;
  border-radius: 4px;
  transform-origin: bottom;
  animation: art-fill 4.5s ease-in-out infinite;
}
.art-diary i:nth-child(1) { left: 10%; bottom: 16%; height: 36%; }
.art-diary i:nth-child(2) { left: 31%; bottom: 16%; height: 58%; animation-delay: 0.45s; }
.art-diary i:nth-child(3) { left: 52%; bottom: 16%; height: 44%; animation-delay: 0.9s; }
.art-diary i:nth-child(4) { left: 73%; bottom: 16%; height: 70%; animation-delay: 1.35s; }

@keyframes art-fill {
  0%, 8%    { transform: scaleY(0); opacity: 0; }
  22%, 78%  { transform: scaleY(1); opacity: 0.85; }
  92%, 100% { transform: scaleY(0); opacity: 0; }
}

/* One out, one back — opposite directions, which is the whole point. */
.art-sms i { height: 11px; border-radius: 8px; }
.art-sms i:nth-child(1) {
  top: 26%; left: 10%; width: 56%;
  animation: art-out 4s ease-in-out infinite;
}
.art-sms i:nth-child(2) {
  top: 58%; right: 10%; width: 42%; opacity: 0.5;
  animation: art-back 4s ease-in-out infinite 1.6s;
}

@keyframes art-out {
  0%, 6%    { transform: translate3d(-20px, 0, 0); opacity: 0; }
  24%, 80%  { transform: none; opacity: 0.9; }
  96%, 100% { transform: translate3d(14px, 0, 0); opacity: 0; }
}
@keyframes art-back {
  0%, 6%    { transform: translate3d(20px, 0, 0); opacity: 0; }
  24%, 80%  { transform: none; opacity: 0.5; }
  96%, 100% { transform: translate3d(-14px, 0, 0); opacity: 0; }
}

/* A door swinging open. */
.art-portal i:nth-child(1) {
  inset: 16% 30% 16% 30%;
  border-radius: 7px 7px 2px 2px;
  background: none;
  border: 2px solid var(--hue);
  opacity: 0.45;
}
.art-portal i:nth-child(2) {
  inset: 22% 34% 16% 34%;
  border-radius: 5px 5px 1px 1px;
  transform-origin: left center;
  animation: art-open 4.4s ease-in-out infinite;
}

@keyframes art-open {
  0%, 14%   { transform: perspective(220px) rotateY(0deg); opacity: 0.85; }
  48%, 72%  { transform: perspective(220px) rotateY(-66deg); opacity: 0.4; }
  96%, 100% { transform: perspective(220px) rotateY(0deg); opacity: 0.85; }
}

/* A group session: three going round one centre. */
.art-orbit i {
  left: 50%;
  top: 50%;
  width: 9px;
  height: 9px;
  margin: -4.5px 0 0 -4.5px;
  border-radius: 999px;
  animation: art-orbit 6s linear infinite;
}
.art-orbit i:nth-child(2) { animation-delay: -2s; opacity: 0.7; }
.art-orbit i:nth-child(3) { animation-delay: -4s; opacity: 0.45; }

@keyframes art-orbit {
  from { transform: rotate(0deg) translateX(20px) rotate(0deg); }
  to   { transform: rotate(360deg) translateX(20px) rotate(-360deg); }
}

/* An import sorting itself into place. */
.art-sort i {
  left: 12%;
  height: 9px;
  border-radius: 4px;
  animation: art-sort 4.2s ease-in-out infinite;
}
.art-sort i:nth-child(1) { top: 24%; width: 40%; }
.art-sort i:nth-child(2) { top: 46%; width: 66%; animation-delay: 0.35s; opacity: 0.7; }
.art-sort i:nth-child(3) { top: 68%; width: 52%; animation-delay: 0.7s; opacity: 0.45; }

@keyframes art-sort {
  0%, 6%    { transform: translate3d(-26px, 0, 0) scaleX(0.3); opacity: 0; }
  26%, 78%  { transform: none; }
  96%, 100% { transform: translate3d(0, -8px, 0); opacity: 0; }
}

/* A claim going up and being answered. */
.art-claim i {
  left: 46%;
  width: 10px;
  height: 10px;
  margin-left: -5px;
  border-radius: 999px;
  animation: art-up 3.2s ease-in-out infinite;
}
.art-claim i:nth-child(2) { animation-delay: 0.55s; }
.art-claim i:nth-child(3) { animation-delay: 1.1s; }

@keyframes art-up {
  0%   { bottom: 6%; opacity: 0; transform: scale(0.5); }
  30%  { opacity: 0.9; }
  100% { bottom: 84%; opacity: 0; transform: scale(1.1); }
}

/* A card, and the tap that takes. */
.art-card i:nth-child(1) {
  inset: 26% 16% 32% 12%;
  border-radius: 6px;
  opacity: 0.22;
}
.art-card i:nth-child(2) {
  top: 44%;
  left: 20%;
  width: 32%;
  height: 8px;
  transform-origin: left center;
  animation: art-tap 2.6s ease-in-out infinite;
}

@keyframes art-tap {
  0%, 100% { transform: scaleX(0.25); opacity: 0.4; }
  50%      { transform: scaleX(1); opacity: 1; }
}

/* A heartbeat, for something a body does. */
.art-pulse i {
  bottom: 30%;
  width: 8px;
  height: 8px;
  border-radius: 999px;
  animation: art-beat 2.4s ease-in-out infinite;
}
.art-pulse i:nth-child(1) { left: 26%; }
.art-pulse i:nth-child(2) { left: 46%; animation-delay: 0.2s; }
.art-pulse i:nth-child(3) { left: 66%; animation-delay: 0.4s; }

@keyframes art-beat {
  0%, 100% { transform: translateY(0) scale(1); opacity: 0.45; }
  40%      { transform: translateY(-12px) scale(1.35); opacity: 1; }
}

/* Bars finding their height. */
.art-chart i {
  bottom: 18%;
  width: 13%;
  border-radius: 3px 3px 0 0;
  transform-origin: bottom;
  animation: art-grow 4.2s ease-in-out infinite;
}
.art-chart i:nth-child(1) { left: 12%; height: 34%; }
.art-chart i:nth-child(2) { left: 32%; height: 58%; animation-delay: 0.3s; }
.art-chart i:nth-child(3) { left: 52%; height: 26%; animation-delay: 0.6s; }
.art-chart i:nth-child(4) { left: 72%; height: 72%; animation-delay: 0.9s; }

@keyframes art-grow {
  0%, 6%    { transform: scaleY(0.12); opacity: 0.3; }
  28%, 76%  { transform: scaleY(1); opacity: 0.85; }
  96%, 100% { transform: scaleY(0.12); opacity: 0.3; }
}

/* An import landing, for the ones that are still just rows arriving. */
.art-box i {
  left: 12%;
  width: 76%;
  height: 9px;
  border-radius: 4px;
  animation: art-drop 3.6s ease-in-out infinite;
}
.art-box i:nth-child(1) { top: 24%; }
.art-box i:nth-child(2) { top: 48%; animation-delay: 0.4s; opacity: 0.6; }
.art-box i:nth-child(3) { top: 72%; animation-delay: 0.8s; opacity: 0.35; }

@keyframes art-drop {
  0%, 5%    { transform: translate3d(0, -12px, 0); opacity: 0; }
  24%, 80%  { transform: none; }
  96%, 100% { opacity: 0; }
}

/*
 * Nobody has to watch any of this.
 *
 * Vestibular disorders are real, and a page that ignores the setting is a page
 * somebody has to leave. All of it is decoration; stopping it costs the reader
 * nothing, and the watermark still says which part of the product each row is.
 */
@media (prefers-reduced-motion: reduce) {
  .art i {
    animation: none !important;
    opacity: 0.65;
    transform: none !important;
  }
}

/* -------------------------------------------------------- colour, sitewide */

/*
 * One colour vocabulary across the whole site.
 *
 * The roadmap gave each row a hue and the icon of the part of the product it
 * belongs to. That only works as a system if the rest of the site speaks it
 * too — a coloured page beside plain ones reads as an experiment rather than
 * a product.
 *
 * So: `data-hue` is read the same way everywhere, and the tint is applied
 * where it helps somebody scan — the number on a step, the rule above a
 * feature — and nowhere near body text, which stays the same near-black it
 * has always been. This is Clinifyd's own palette, the one the diary already
 * teaches: a colour means a kind of thing.
 */
[data-hue='teal']    { --hue: #0d9488; }
[data-hue='sky']     { --hue: #0284c7; }
[data-hue='indigo']  { --hue: #4f46e5; }
[data-hue='violet']  { --hue: #7c3aed; }
[data-hue='emerald'] { --hue: #059669; }
[data-hue='amber']   { --hue: #b45309; }
[data-hue='rose']    { --hue: #e11d48; }
[data-hue='slate']   { --hue: #64748b; }

/* --- the clinic day, step by step --- */

/*
 * The number takes the step's colour, and the card takes a sliver of it down
 * the left edge. Five identical white cards is a list you read from the top;
 * five with a spine of colour is a list you can re-enter halfway.
 */
.steps li[data-hue] {
  border-left: 3px solid var(--hue);
}

.steps li[data-hue] .step-no {
  background: color-mix(in srgb, var(--hue) 13%, transparent);
  color: var(--hue);
}

/* --- what it does, section by section --- */

/*
 * The number already there takes the section's colour, and gets a short rule
 * above it — rather than a tinted band behind the whole section. A full-width
 * wash on seven sections in a row is a page that flashes as you scroll; a rule
 * is a marker you notice once and then stop noticing.
 */
.showcase[data-hue] .showcase-number {
  color: var(--hue);
}

.showcase[data-hue] .showcase-number::before {
  content: '';
  display: block;
  width: 2.25rem;
  height: 3px;
  margin-bottom: 0.85rem;
  border-radius: 999px;
  background: var(--hue);
}

/* The alternating band picks up the section's own colour instead of the one
   accent, so the rhythm down the page is colour rather than on/off. */
.showcase.alt[data-hue] {
  background: color-mix(in srgb, var(--hue) 5%, transparent);
}

@media (prefers-contrast: more) {
  /* A 5% wash is decoration; at high contrast it is noise between text and
     background. Dropped rather than deepened. */
  .showcase.alt[data-hue] {
    background: transparent;
  }
}

/* ------------------------------------------------------ the capability map */

/*
 * The whole scope, before the arguments for it.
 *
 * Six columns somebody can scan in ten seconds, then the arguments underneath
 * for whoever wants them.
 *
 * Uncoloured, and headed by the software's own icons. The page used to open
 * with colour everywhere and then argue in colour too, which left nothing
 * quiet enough for the arguments to stand out from. Now the top half is grey
 * and structural and the seven sections below keep their hues.
 *
 * Plain lists, deliberately. Ticks would imply a comparison against something
 * unnamed, and a grid of ticks is the shape of a page that is arguing rather
 * than describing.
 */
.capability {
  padding-block: 1rem 3.5rem;
}

.capability-head {
  font-size: 1.05rem;
  letter-spacing: 0.02em;
  color: var(--ink-faint);
  font-weight: 600;
  margin-bottom: 1.5rem;
}

.capability-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: 1.75rem 2.5rem;
}

.cap h3 {
  display: flex;
  align-items: center;
  gap: 0.55rem;
  margin: 0 0 0.85rem;
  padding-bottom: 0.7rem;
  font-size: 1rem;
  border-bottom: 1px solid var(--line);
}

/* The software's own icon, at the size it is in the app. Not decoration —
   somebody who has seen a demo recognises the column before reading it. */
.cap-icon {
  width: 1.35rem;
  height: 1.35rem;
  flex: none;
  color: var(--ink-faint);
  /* Optically centred on the text rather than on its box — a stroke icon
     always reads a touch high against a cap-height. */
  transform: translateY(0.5px);
}

.cap ul {
  margin: 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: 0.4rem;
}

.cap li {
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--ink-soft);
  padding-left: 0.9rem;
  position: relative;
}

/* A dash rather than a tick. A tick claims somebody else does not have it. */
.cap li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.72em;
  width: 0.45rem;
  height: 2px;
  border-radius: 1px;
  background: #cbd5e1;
}

/* ----------------------------------------------------------------- the day */

/*
 * One real Tuesday, drawn as the diary.
 *
 * It was a vertical spine with dots, which is exactly what the roadmap is —
 * two pages using one shape read as one page. So this borrows the product's
 * own: an hour gutter down the left and blocks to the right of it, the way the
 * day actually looks on screen. The page about a clinic day now resembles a
 * clinic day, which is a better argument than any sentence about it.
 *
 * Grid rather than flex, so every time in the gutter lines up on the same
 * right edge whatever its length — "The night before" and "9:00 am" sit on one
 * axis, which is what makes a gutter read as a gutter.
 */
.day {
  padding-block: 4rem;
}

.daybook {
  margin-top: 2.5rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
  overflow: hidden;
}

.daybook-row {
  display: grid;
  grid-template-columns: 7.5rem 1fr;
  align-items: stretch;
  border-top: 1px solid var(--line);
}

.daybook-row:first-child {
  border-top: 0;
}

/* The gutter, right-aligned against the rule — the diary's own arrangement,
   and the reason the eye can run down the times without reading them. */
.daybook-time {
  display: flex;
  align-items: flex-start;
  justify-content: flex-end;
  padding: 1.35rem 1rem 1.35rem 1.25rem;
  border-right: 1px solid var(--line);
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.03em;
  color: var(--ink-faint);
  text-align: right;
  /*
   * Wraps rather than clipping.
   *
   * It was `nowrap` inside a parent with `overflow: hidden`, which is a
   * combination that can only ever cut a word in half — a label longer than
   * the gutter had nowhere to go. "Overnight" and "Monday" fit now, and this
   * is here so the next one that does not still reads.
   */
  overflow-wrap: anywhere;
  line-height: 1.35;
}

/* The block, tinted and edged like an appointment. */
.daybook-block {
  position: relative;
  padding: 1.35rem 1.5rem 1.35rem 1.6rem;
  background: color-mix(in srgb, var(--hue) 5%, transparent);
}

.daybook-block::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0;
  bottom: 0;
  width: 3px;
  background: var(--hue);
}

.daybook-block h3 {
  margin: 0 0 0.4rem;
  font-size: 1.08rem;
  letter-spacing: -0.01em;
}

.daybook-block p {
  margin: 0;
  max-width: 46rem;
  line-height: 1.7;
  color: var(--ink-soft);
}

@media (max-width: 620px) {
  /* The gutter becomes a label above the block. A 7.5rem column on a 360px
     screen leaves the sentence in a channel too narrow to read. */
  .daybook-row {
    grid-template-columns: 1fr;
  }
  .daybook-time {
    justify-content: flex-start;
    padding: 0.9rem 1.25rem 0;
    border-right: 0;
    color: var(--hue);
  }
  .daybook-block {
    padding-top: 0.6rem;
  }
}

/* ------------------------------------------------------------- the sidebar */

/*
 * The actual rail, at actual size.
 *
 * The strongest thing about this software is how little of it there is to
 * learn, and nobody believes that in a sentence. So it is shown: the real
 * icons, in the real order, uncoloured and undecorated. The argument is the
 * shortness of the list — nine things, and that is all of it.
 *
 * Deliberately not a feature grid. A feature grid says "look how much"; this
 * says "look how little", which is the harder and truer claim.
 */
.rail-strip {
  padding-block: 0 3.5rem;
}

/*
 * A grid, not a wrapping row.
 *
 * A flex row leaves whatever does not fit hanging off the left of a second
 * line, reading as an afterthought rather than as the end of a list. Even
 * columns put every item on the same rhythm and let a short last row simply
 * be a short last row.
 */
.rail {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(8.5rem, 1fr));
  gap: 0.35rem;
  list-style: none;
  margin: 0;
  padding: 1.25rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.rail li {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 0.85rem;
  border-radius: 10px;
  font-size: 0.92rem;
  color: var(--ink-soft);
  /* The hover is the app's own: this is a sidebar, and it should feel like
     one under the cursor rather than like a picture of one. */
  transition: background 0.15s ease, color 0.15s ease;
}

.rail li:hover {
  background: color-mix(in srgb, var(--accent) 8%, transparent);
  color: var(--ink);
}

.rail-icon {
  width: 1.45rem;
  height: 1.45rem;
  flex: none;
  color: var(--ink-faint);
  transform: translateY(0.5px);
  transition: color 0.2s ease, transform 0.4s cubic-bezier(0.22, 1, 0.36, 1);
}

.rail li:hover .rail-icon {
  color: var(--accent-text);
  transform: translateY(0.5px) scale(1.12);
}

/*
 * The icon redraws itself under the cursor.
 *
 * Every path carries `pathLength="100"` in the markup, which normalises them
 * all to one hundred units — so a single dash-offset redraws a two-line clock
 * and a nine-line slider bank at exactly the same speed. Without it, the long
 * paths crawl and the short ones snap, and eleven icons animate at eleven
 * different rates.
 *
 * The dash is only applied on hover. Set permanently it would force the
 * browser to measure every path on load, and a static icon has nothing to gain
 * from it.
 */
/*
 * Slower than it was.
 *
 * At 0.55s the icons made of one path — the dashboard's four squares, the
 * slider bank, the report bars — drew every stroke in the same sweep and
 * looked like a flicker rather than a line being drawn. `pathLength` keeps
 * them all at one speed; this makes that speed watchable.
 */
.rail li:hover .rail-icon path {
  animation: rail-draw 0.95s ease-out;
}

@keyframes rail-draw {
  from {
    stroke-dasharray: 100;
    stroke-dashoffset: 100;
  }
  to {
    stroke-dasharray: 100;
    stroke-dashoffset: 0;
  }
}

/* A stagger, so an icon of several strokes draws rather than flashes. */
.rail li:hover .rail-icon path:nth-child(2) { animation-delay: 0.1s; }
.rail li:hover .rail-icon path:nth-child(3) { animation-delay: 0.2s; }
.rail li:hover .rail-icon path:nth-child(4) { animation-delay: 0.3s; }

/*
 * Two that can do something better than redraw.
 *
 * The clock has a hand and the diary has a page, and both are single elements
 * inside their icon — so they get the movement the object actually makes.
 * The rest keep the draw, which suits a line that has no obvious motion.
 */
.rail li[data-icon='time']:hover .rail-icon path:nth-child(2) {
  /* `transform-box` matters: without it the origin is resolved against the
     path's own bounding box, so the hand pivots about its middle rather than
     about the centre of the clock face. */
  transform-box: view-box;
  transform-origin: 12px 12px;
  animation: rail-tick 0.85s cubic-bezier(0.34, 1.56, 0.64, 1);
}

@keyframes rail-tick {
  from { transform: rotate(-90deg); }
  to   { transform: rotate(0deg); }
}

.rail li[data-icon='chat']:hover .rail-icon {
  animation: rail-nudge 0.7s ease-out;
}

@keyframes rail-nudge {
  0%, 100% { transform: translateY(0.5px) scale(1.12); }
  40%      { transform: translateY(-2px) scale(1.12); }
}

@media (prefers-reduced-motion: reduce) {
  /* The colour and the size still answer the hover; only the movement goes. */
  .rail li:hover .rail-icon,
  .rail li:hover .rail-icon path {
    animation: none;
  }
}

.rail-note {
  margin: 0.9rem 0 0;
  font-size: 0.92rem;
  color: var(--ink-faint);
}

@media (max-width: 620px) {
  /* Labels go, icons stay. The point of the strip is the count, and nine
     icons still make it on a phone where nine labels would not — six across
     and three under, which still reads as one block. */
  .rail {
    grid-template-columns: repeat(6, 1fr);
    justify-items: center;
  }
  .rail li span {
    display: none;
  }
  .rail li {
    padding: 0.55rem;
    justify-content: center;
  }
}


/* ------------------------------------------------------- phone and tablet */

/*
 * The two sizes this is actually read on.
 *
 * A clinic owner looks at this on an iPad between patients, or on a phone in
 * the car park. Neither is the width anything was designed at, so both get
 * checked rather than assumed.
 */

@media (min-width: 761px) and (max-width: 1024px) {
  /* Two columns rather than three: at 15rem minimum a tablet fits three, and
     three columns of six short lines each is a lot of eye travel for a page
     whose point is that there is not much of it. */
  .capability-grid {
    grid-template-columns: repeat(2, 1fr);
    gap: 1.75rem 3rem;
  }

  /* The roadmap's tile takes room the sentence needs more. */
  .track-item {
    grid-template-columns: 1.25rem 1fr 5rem;
  }
}

@media (max-width: 620px) {
  /* Section rhythm tightens. The desktop spacing is generous on purpose and
     turns into scrolling past nothing on a phone. */
  .showcase {
    padding-block: 2.75rem;
  }
  .capability {
    padding-block: 0.5rem 2.25rem;
  }
  .day,
  .rail-strip {
    padding-block: 2.5rem;
  }

  /* One column, always. Two columns of body text on a 360px screen is four
     words a line. */
  .capability-grid {
    grid-template-columns: 1fr;
    gap: 1.5rem;
  }

  /* Headings step down with the space they have. */
  .showcase-copy h2 {
    font-size: 1.45rem;
  }

  .section-head h1,
  .showcase-lead h1 {
    font-size: clamp(1.75rem, 7vw, 2.1rem);
  }
}

/*
 * Every target a thumb has to find.
 *
 * 44px is the figure both platform guidelines land on, and a footer link at
 * 20px is the one everybody forgets — it is read on a phone more often than
 * anything else on the page.
 */
@media (hover: none) {
  .site-footer .foot-col a:not(.wordmark) {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
  }

  .rail li {
    min-height: 44px;
  }
}

/* ------------------------------------------------------- the headline word */

/*
 * A headline that finishes itself.
 *
 * One fixed clause and one word that changes, because the point is that the
 * same short answer covers all of them. A list would say the same thing and
 * take six lines to do it.
 *
 * The word is measured before anything moves and its box is held at the width
 * of the longest, so the line never reflows mid-sentence. A headline that
 * jumps while it is being read is worse than one that does not move.
 */
.hero-line {
  text-wrap: balance;
}

.typed {
  display: inline-flex;
  align-items: baseline;
  color: var(--accent-text);
}

.typed-word {
  /* Inherits the headline's size and weight — it is part of the sentence, not
     a badge stuck on the end of it. */
  font: inherit;
  letter-spacing: inherit;
}

/* A real caret: a block that blinks, sized off the text rather than guessed. */
.typed-caret {
  display: inline-block;
  width: 0.06em;
  min-width: 2px;
  height: 0.82em;
  margin-left: 0.06em;
  background: var(--accent);
  animation: caret-blink 1.05s steps(1) infinite;
}

@keyframes caret-blink {
  0%, 45%   { opacity: 1; }
  50%, 95%  { opacity: 0; }
  100%      { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  /*
   * The script does not start, so the first word simply stays. The caret goes
   * with it — a cursor blinking beside a word that will never change is a
   * promise the page is not keeping.
   */
  .typed-caret {
    display: none;
  }
}

/* ----------------------------------------------------------- who uses it */

/*
 * One clinic, named, with its own mark.
 *
 * Not a wall of grey logos from companies that have heard of us — a single
 * real name is worth more than six borrowed ones, and it is the only claim on
 * this page that can be checked. That this runs a practice every working day
 * is the whole argument for the rest of it.
 */
.partners {
  padding-block: 0 3.5rem;
}

.partners-head {
  margin: 0 0 1rem;
  font-size: 0.78rem;
  font-weight: 600;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: var(--ink-faint);
}

.partners-row {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.5rem 2.25rem;
  padding: 1.5rem 1.75rem;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--surface);
}

.partner {
  display: block;
  flex: none;
  line-height: 0;
}

.partner img {
  height: 3.4rem;
  width: auto;
  /* Their logo at their own colours. Greyscaling somebody else's mark to fit
     a page is a small discourtesy, and it makes the one real name on the page
     look like filler. */
  object-fit: contain;
}

.partners-note {
  margin: 0;
  flex: 1 1 18rem;
  font-size: 0.95rem;
  line-height: 1.65;
  color: var(--ink-soft);
}

@media (max-width: 560px) {
  .partners-row {
    padding: 1.25rem;
  }
  .partner img {
    height: 2.9rem;
  }
}

/* ================================================= help, contact, security */

.help-hero { padding: 64px 0 40px; background: linear-gradient(180deg, #f6f9f8, #fff); }
.help-hero .lede { max-width: 620px; }

.help-roles { padding: 32px 0 8px; }
.help-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); margin-top: 16px; }
.help-card {
  display: block; padding: 18px 20px; border: 1px solid #e2e8f0; border-radius: 14px;
  background: #fff; text-decoration: none; color: inherit;
  transition: border-color 0.15s ease, transform 0.15s ease;
}
.help-card:hover { border-color: #0f172a; transform: translateY(-2px); }
.help-card h3 { margin: 0 0 6px; font-size: 1.05rem; }
.help-card p { margin: 0; color: #64748b; font-size: 0.92rem; line-height: 1.5; }

.help-faq { padding: 40px 0 16px; max-width: 820px; }
.help-faq-topic { margin: 28px 0 6px; font-size: 1rem; }
.help-faq-topic a { color: inherit; }
.help-faq details {
  border-bottom: 1px solid #e2e8f0; padding: 10px 0;
}
.help-faq summary { cursor: pointer; font-weight: 600; padding: 4px 0; }
.help-faq details p { color: #475569; margin: 8px 0 4px; line-height: 1.6; }

.help-contact-band { margin: 48px 0 0; padding: 48px 0; background: #0f172a; color: #fff; text-align: center; }
.help-contact-band h2 { margin: 0 0 6px; }
.help-contact-band p { margin: 0 0 18px; color: rgba(255, 255, 255, 0.7); }

/* One readable column for a rendered handbook chapter. */
.help-article { padding: 40px 0 56px; max-width: 780px; }
.help-crumb { margin: 0 0 8px; font-size: 0.9rem; }
.help-body h1 { font-size: 2rem; margin: 8px 0 12px; }
.help-body h2 { margin: 36px 0 10px; padding-top: 12px; border-top: 1px solid #eef2f7; }
.help-body h3 { margin: 24px 0 8px; }
.help-body p, .help-body li { line-height: 1.65; color: #334155; }
.help-body table { border-collapse: collapse; width: 100%; margin: 14px 0; font-size: 0.94rem; display: block; overflow-x: auto; }
.help-body th, .help-body td { border: 1px solid #e2e8f0; padding: 8px 10px; text-align: left; vertical-align: top; }
.help-body th { background: #f8fafc; }
.help-body code { background: #f1f5f9; border-radius: 4px; padding: 1px 5px; font-size: 0.9em; }
.help-body blockquote { border-left: 3px solid #cbd5e1; margin: 14px 0; padding: 2px 16px; color: #475569; }
.help-body hr { border: 0; border-top: 1px solid #e2e8f0; margin: 28px 0; }
.help-body ol { counter-reset: step; padding-left: 0; }
.help-body ol > li { list-style: none; position: relative; padding-left: 44px; margin: 12px 0; }
.help-body ol > li::before {
  counter-increment: step; content: counter(step);
  position: absolute; left: 0; top: 0;
  width: 28px; height: 28px; border-radius: 50%;
  background: #0f172a; color: #fff; font-weight: 700; font-size: 0.85rem;
  display: grid; place-items: center;
}
/* The guided feel: each step rises in as it is reached. */
.help-step { opacity: 0; transform: translateY(10px); transition: opacity 0.45s ease, transform 0.45s ease; }
.help-step-seen { opacity: 1; transform: none; }
@media (prefers-reduced-motion: reduce) {
  .help-step { opacity: 1; transform: none; transition: none; }
}
.help-pager { display: flex; justify-content: space-between; gap: 16px; margin-top: 40px; padding-top: 16px; border-top: 1px solid #e2e8f0; font-size: 0.95rem; }

/* Contact */
.contact-body { display: grid; gap: 32px; padding: 40px 0 64px; grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr); align-items: start; }
@media (max-width: 760px) { .contact-body { grid-template-columns: 1fr; } }
.contact-form { display: grid; gap: 14px; }
.contact-form label { display: block; font-weight: 600; font-size: 0.95rem; }
.contact-form input, .contact-form textarea {
  display: block; width: 100%; margin-top: 6px; padding: 10px 12px;
  border: 1px solid #cbd5e1; border-radius: 10px; font: inherit;
}
.contact-form input:focus, .contact-form textarea:focus { outline: none; border-color: #0f172a; }
.contact-optional { color: #94a3b8; font-weight: 400; }
.contact-trap { position: absolute; left: -9999px; height: 0; width: 0; opacity: 0; }
.contact-error { color: #b91c1c; background: #fef2f2; border-radius: 10px; padding: 10px 12px; margin: 0; }
.contact-aside h2 { font-size: 1.05rem; margin: 0 0 6px; }
.contact-aside p { color: #64748b; line-height: 1.6; margin: 0 0 20px; }
.contact-done { grid-column: 1 / -1; text-align: center; padding: 32px; border: 1px solid #e2e8f0; border-radius: 14px; }

/* Security */
.sec-list { padding: 24px 0 64px; }
.sec-list h2 { margin: 36px 0 4px; }
.sec-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); margin-top: 14px; }
.sec-card { border: 1px solid #e2e8f0; border-radius: 14px; padding: 18px 20px; background: #fff; }
.sec-card h3 { margin: 0 0 8px; font-size: 1.02rem; }
.sec-card p, .sec-card li { color: #475569; line-height: 1.6; margin: 0; font-size: 0.95rem; }
.sec-card ul { margin: 10px 0; padding-left: 20px; }
.sec-card li { margin: 6px 0; }
.sec-roadmap { margin-top: 14px; background: #f8fafc; }
.sec-roadmap p { margin-bottom: 10px; }

/* The features → help band */
.features-help-band { margin-top: 48px; padding: 40px 0; background: #f6f9f8; text-align: center; }
.features-help-band h2 { margin: 0 0 6px; }
.features-help-band p { margin: 0 0 16px; color: #64748b; }

/* Screenshot galleries on help chapters. */
.help-shots { margin: 18px 0 8px; }
.help-shots-grid { display: grid; gap: 16px; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.help-shots figure { margin: 0; }
.help-shots img {
  width: 100%; height: auto; display: block; border-radius: 10px;
  border: 1px solid #e2e8f0; box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08);
}
.help-shots figcaption { margin-top: 6px; font-size: 0.85rem; color: #64748b; line-height: 1.45; }

/* ------------------------------------------------------------ chat bubble */
/* The corner bubble on every page. The panel is the placeholder message
   form; the bubble itself — pop-in, breathing ring, flickering typing dots —
   is the part built to outlast it. Motion sits behind a reduced-motion gate. */
#clini-chat { position: fixed; right: 20px; bottom: 20px; z-index: 60; font-family: inherit; }

/* Wordless on purpose: a 56px circle, brand teal, the icon alone. The words
   live in the aria-label; the animation is what says "somebody's here". */
.chat-bubble {
  position: relative; display: grid; place-items: center;
  width: 56px; height: 56px;
  border: 0; cursor: pointer; border-radius: 999px;
  background: linear-gradient(135deg, #0d9488, #0f766e);
  color: #fff;
  box-shadow: 0 6px 18px rgba(13, 148, 136, 0.35);
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.chat-bubble:hover { transform: translateY(-2px); box-shadow: 0 10px 24px rgba(13, 148, 136, 0.4); }
.chat-bubble:focus-visible { outline: 3px solid #99f6e4; outline-offset: 2px; }
.chat-bubble svg { display: block; }

/* Typing dots inside the speech bubble: three specks that take turns,
   in short runs with a rest between, so the corner feels staffed without
   nagging. Sits over the icon's mouth area. */
.chat-dots {
  position: absolute; left: 50%; top: 26px; transform: translateX(-58%);
  display: flex; gap: 3px;
}
.chat-dots i {
  width: 4px; height: 4px; border-radius: 999px; background: #fff; opacity: 0.35;
}
@keyframes chat-dot {
  0%, 6%, 100% { opacity: 0.35; transform: translateY(0); }
  3% { opacity: 1; transform: translateY(-2px); }
}
.chat-dots i:nth-child(1) { animation: chat-dot 6s infinite 0s; }
.chat-dots i:nth-child(2) { animation: chat-dot 6s infinite 0.35s; }
.chat-dots i:nth-child(3) { animation: chat-dot 6s infinite 0.7s; }

/* A ring that swells and fades every few seconds — the "we're here" pulse. */
.chat-ring {
  position: absolute; inset: 0; border-radius: 999px;
  border: 2px solid rgba(13, 148, 136, 0.55); pointer-events: none;
}
@keyframes chat-ring {
  0%, 55%, 100% { transform: scale(1); opacity: 0; }
  60% { opacity: 0.8; }
  85% { transform: scale(1.28); opacity: 0; }
}
.chat-ring { animation: chat-ring 7s infinite; }

/* Opening the panel quiets the bubble: the invitation has been accepted. */
.chat-bubble-open .chat-ring, .chat-bubble-open .chat-dots i { animation: none; }
.chat-bubble-open .chat-dots i { opacity: 0.35; }

.chat-panel {
  position: absolute; right: 0; bottom: calc(100% + 12px);
  width: min(340px, calc(100vw - 40px));
  border-radius: 16px; overflow: hidden; background: #fff;
  border: 1px solid var(--line);
  box-shadow: 0 18px 50px rgba(15, 23, 42, 0.22);
}
@keyframes chat-panel-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: none; } }
.chat-panel:not([hidden]) { animation: chat-panel-in 0.18s ease-out; }

.chat-head {
  display: flex; align-items: center; gap: 10px; flex-wrap: wrap;
  background: linear-gradient(135deg, #0d9488, #0f766e);
  color: #fff; padding: 14px 16px;
}
.chat-head img { display: block; }
.chat-head-note { font-size: 0.78rem; opacity: 0.9; flex: 1 1 100%; }
.chat-close {
  margin-left: auto; border: 0; background: rgba(255, 255, 255, 0.15);
  color: #fff; border-radius: 8px; width: 28px; height: 28px; cursor: pointer;
  font-size: 0.85rem; line-height: 1;
}
.chat-close:hover { background: rgba(255, 255, 255, 0.28); }

.chat-body { padding: 14px 16px 16px; display: grid; gap: 10px; }
.chat-hello { margin: 0; font-size: 0.86rem; color: var(--ink-soft); line-height: 1.5; }
.chat-body label { display: grid; gap: 4px; font-size: 0.78rem; font-weight: 600; color: var(--ink-soft); }
.chat-body input, .chat-body textarea {
  border: 1px solid var(--line); border-radius: 10px; padding: 8px 10px;
  font: inherit; font-size: 0.9rem; color: var(--ink); width: 100%;
}
.chat-body input:focus, .chat-body textarea:focus { outline: 2px solid #0d9488; outline-offset: 0; border-color: #0d9488; }
.chat-body textarea { resize: vertical; min-height: 66px; }
.chat-trap { position: absolute !important; left: -9999px; width: 1px; height: 1px; opacity: 0; }
.chat-error { margin: 0; font-size: 0.82rem; color: #b91c1c; }
.chat-send {
  border: 0; cursor: pointer; border-radius: 10px; padding: 10px 14px;
  background: #0d9488; color: #fff; font-weight: 600; font-size: 0.9rem;
}
.chat-send:hover { background: #0f766e; }
.chat-send:disabled { opacity: 0.5; cursor: default; }
.chat-done { padding: 22px 18px 26px; text-align: center; font-size: 0.9rem; color: var(--ink-soft); }
.chat-done-big { margin: 0 0 6px; font-size: 1.1rem; font-weight: 700; color: #0f766e; }

@media (prefers-reduced-motion: reduce) {
  .chat-ring, .chat-dots i { animation: none !important; }
  .chat-panel:not([hidden]) { animation: none; }
  .chat-bubble, .chat-bubble:hover { transition: none; transform: none; }
}

/* -------------------------------------------------------- chat, live side */
/* The thread the form turns into once the first message is sent. */
.chat-thread { display: grid; }
.chat-messages {
  max-height: 300px; min-height: 140px; overflow-y: auto;
  padding: 14px 14px 8px; display: grid; gap: 8px; align-content: start;
}
.chat-msg { display: grid; gap: 2px; max-width: 85%; }
.chat-msg-visitor { justify-self: end; }
.chat-msg-team { justify-self: start; }
.chat-msg-body {
  padding: 8px 12px; border-radius: 14px; font-size: 0.9rem; line-height: 1.45;
  white-space: pre-wrap; word-break: break-word;
}
.chat-msg-visitor .chat-msg-body {
  background: #0d9488; color: #fff; border-bottom-right-radius: 4px;
}
.chat-msg-team .chat-msg-body {
  background: var(--surface-sunk); color: var(--ink); border-bottom-left-radius: 4px;
}
.chat-msg-who { font-size: 0.7rem; font-weight: 600; color: #0f766e; padding-left: 4px; }
.chat-joined-line, .chat-over {
  margin: 0; padding: 6px 14px; text-align: center;
  font-size: 0.78rem; color: var(--ink-faint);
}
.chat-over { padding-bottom: 12px; }

/* Waiting for the team: three teal dots rising in turn — the same language
   as every messaging app's "someone is typing", which is exactly the hope
   it is expressing. */
.chat-wait {
  display: flex; align-items: center; gap: 10px;
  margin: 0 14px 10px; padding: 10px 12px;
  background: #f0fdfa; border: 1px solid #99f6e4; border-radius: 12px;
}
.chat-wait-dots { display: flex; gap: 4px; }
.chat-wait-dots i {
  width: 7px; height: 7px; border-radius: 999px; background: #0d9488; opacity: 0.3;
}
@keyframes chat-wait-dot {
  0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-4px); }
}
.chat-wait-dots i:nth-child(1) { animation: chat-wait-dot 1.4s infinite 0s; }
.chat-wait-dots i:nth-child(2) { animation: chat-wait-dot 1.4s infinite 0.2s; }
.chat-wait-dots i:nth-child(3) { animation: chat-wait-dot 1.4s infinite 0.4s; }
.chat-wait-text { font-size: 0.8rem; color: #0f766e; line-height: 1.4; }

.chat-say {
  display: flex; gap: 8px; padding: 10px 14px 14px; border-top: 1px solid var(--line);
}
.chat-say input {
  flex: 1; border: 1px solid var(--line); border-radius: 999px;
  padding: 9px 14px; font: inherit; font-size: 0.9rem; color: var(--ink); min-width: 0;
}
.chat-say input:focus { outline: 2px solid #0d9488; border-color: #0d9488; }
.chat-say button {
  border: 0; cursor: pointer; border-radius: 999px; width: 40px; height: 40px;
  background: #0d9488; color: #fff; font-size: 1rem; flex: none;
}
.chat-say button:hover { background: #0f766e; }
.chat-again {
  margin: 0 14px 14px; border: 1px solid var(--line); background: #fff;
  border-radius: 10px; padding: 9px; cursor: pointer; font: inherit;
  font-size: 0.85rem; color: var(--ink-soft);
}
.chat-again:hover { background: var(--surface-soft); }

/* A team reply arrived while the panel was shut. */
.chat-unread {
  position: absolute; top: -2px; right: -2px; width: 12px; height: 12px;
  border-radius: 999px; background: #dc2626; border: 2px solid #fff;
}

@media (prefers-reduced-motion: reduce) {
  .chat-wait-dots i { animation: none !important; opacity: 0.7; }
}

/* A team message wears a face: the sender's initial in a teal circle, the
   slot a real photograph can take later. Visitors' own bubbles stay bare —
   people know which side of the conversation they are. */
.chat-msg-row { display: flex; gap: 8px; align-items: flex-end; }
.chat-avatar {
  flex: none; width: 26px; height: 26px; border-radius: 999px;
  display: grid; place-items: center;
  background: linear-gradient(135deg, #0d9488, #0f766e); color: #fff;
  font-size: 0.75rem; font-weight: 700;
}
.chat-msg-row > div { display: grid; gap: 2px; min-width: 0; }
