/* Live demo UI: the site's tokens on voicely.au, with literal fallbacks so /try renders on its own. */

/* The calendar card's font, served from here: behind a Google Fonts sheet, phones first showed bare buttons. */
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/source-sans-3-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Source Sans 3";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/source-sans-3-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* The notification stack lives on the body (demo.js), so the tokens are declared there too. */
.vd,
.vd-toasts,
/* Lifted onto the body (demo.js) to clear the orb's canvas, so each carries its own palette. */
.vd-clinic,
.vd-turn,
.vd-foot--detached {
  --vd-bg:      var(--bg, #f6f3ec);
  --vd-surface: var(--surface, #fffdf8);
  --vd-text:    var(--text, #1a2b29);
  --vd-muted:   var(--muted, #5f6f6a);
  --vd-line:    var(--line, rgba(26, 43, 41, 0.14));
  --vd-accent:  var(--accent, #1f7a5c);
  --vd-ink:     var(--accent-ink, #f6f3ec);
  /* One curve for everything that moves: a long, flat tail that decelerates late. */
  --vd-ease:    cubic-bezier(0.32, 0.72, 0, 1);
}

.vd {
  position: relative;
  display: grid;
  place-items: center;
  /* Packed and centred as a group; implicit rows would otherwise stretch. */
  align-content: center;
  /* No min-height: the stage centres it and /try's section sets the height (a % would collapse here). */
  padding: clamp(20px, 5vw, 56px);
  font-family: var(--font-body, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif);
  color: var(--vd-text);
  text-align: center;
}

/* One panel per phase; only the active one is in flow. */
.vd-panel { position: relative; z-index: 2; display: none; width: min(560px, 100%); }
.vd[data-phase="choose"]   .vd-choose,
.vd[data-phase="building"] .vd-building,
.vd[data-phase="review"]   .vd-review,
.vd[data-phase="calling"]  .vd-calling,
.vd[data-phase="ended"]    .vd-ended,
.vd[data-phase="error"]    .vd-error { display: block; }

/* The orb is behind the panel in a call, so the calling copy keeps clear of the middle. */
.vd[data-phase="calling"] .vd-calling { display: grid; gap: 22px; justify-items: center; }

/* ── the contents arriving ────────────────────────────────────────────────── */
/* A panel's rows rise in one after another. Leaving display:none restarts it, so it replays on every
   phase change, and on the landing page on every open (body.is-demo starts the rule matching). */
@keyframes vd-panel-in {
  from { opacity: 0; transform: translate3d(0, 9px, 0); }
  to   { opacity: 1; transform: none; }
}
body.is-demo .vd-panel > *,
.try-stage .vd-panel > * {
  /* `backwards`, never `both`: `both` pins `transform: none` afterwards and kills .vd-btn's hover lift. */
  animation: vd-panel-in 0.46s var(--vd-ease) var(--vd-row-delay) backwards;
}
/* The stagger. The landing page sets --vd-panel-delay to sit behind the orb's glide. */
.vd-panel > *              { --vd-row-delay: calc(var(--vd-panel-delay, 0s) + 0.24s); }
.vd-panel > *:nth-child(1) { --vd-row-delay: var(--vd-panel-delay, 0s); }
.vd-panel > *:nth-child(2) { --vd-row-delay: calc(var(--vd-panel-delay, 0s) + 0.06s); }
.vd-panel > *:nth-child(3) { --vd-row-delay: calc(var(--vd-panel-delay, 0s) + 0.12s); }
.vd-panel > *:nth-child(4) { --vd-row-delay: calc(var(--vd-panel-delay, 0s) + 0.18s); }

/* With the diary card up, the call controls leave the centred stack, where they'd push the card off
   centre (and the orb tracks the card), and hang off the CARD, not 50% of the container (/try's
   padding is asymmetric): --vd-orb-y and --vd-appt-h come from focusOrb's own rect. */
.vd-appt:not([hidden]) ~ .vd-calling {
  position: absolute;
  top: calc(var(--vd-orb-y, 50%) + var(--vd-appt-h, 322px) / 2 + 18px);
  left: 50%;
  transform: translateX(-50%);
  width: auto;
  gap: 12px;
}
/* Before the diary, on a phone: the controls rise with the orb (--vd-lift, aimOrb in demo.js). */
.vd-appt[hidden] ~ .vd-calling {
  transform: translateY(calc(-1 * var(--vd-lift, 0px)));
  transition: transform 340ms var(--vd-ease);
}
/* No clock next to the card: the visitor is reading a diary entry. */
.vd-appt:not([hidden]) ~ .vd-calling .vd-timer { display: none; }

/* On a phone that position lands ON the orb's glow (the card shrinks, the orb doesn't), so the
   controls go to the floor of the screen above the recording note, where Call again sits after. */
@media (max-width: 720px) {
  .vd-appt:not([hidden]) ~ .vd-calling {
    top: auto;
    bottom: calc(var(--vd-foot-h, 44px) + 12px);
    gap: 8px;
  }
  /* In the takeover .vd is only as tall as its content, so a bottom offset anchors to the viewport. */
  body.is-demo .vd-appt:not([hidden]) ~ .vd-calling { position: fixed; }
}

.vd h2 {
  margin: 0 0 8px;
  font-family: var(--font-display, inherit);
  font-size: var(--fs-h3, 1.3rem);
  font-weight: 650;
  letter-spacing: -0.01em;
}

.vd-sub {
  margin: 0 0 18px;
  color: var(--vd-muted);
  font-size: var(--fs-body, 0.96rem);
  line-height: 1.5;
}

/* The choose panel, sized to the orb's clear centre: radius min(230px, 31vw, 39vh). */
.vd-choose h2 { margin-bottom: 18px; }
.vd-choose .vd-btn,
.vd-url {
  box-sizing: border-box;
  height: 40px;
  padding-block: 0;
  white-space: nowrap;
}
.vd-or {
  margin: 16px 0 10px;
  color: var(--vd-muted);
  font-size: var(--fs-caption, 0.86rem);
  line-height: 1.5;
}
.vd-form {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  justify-content: center;
  max-width: 280px;
  margin: 0 auto;
}
.vd-form > * { flex: 1 1 100%; }
.vd-url {
  min-width: 0;
  padding-inline: 18px;
  border: 1px solid var(--vd-line);
  border-radius: 999px;
  background: var(--vd-surface);
  color: var(--vd-text);
  font: inherit;
  font-size: var(--fs-body, 0.96rem);
  text-align: center;
}
.vd-url:focus-visible { outline: 2px solid var(--vd-accent); outline-offset: 1px; }

/* Phones and short windows */
@media (max-width: 599px), (max-height: 475px) {
  .vd-choose h2 {
    max-width: 9.5em;
    margin: 0 auto 12px;
    font-size: 1.06rem;
    line-height: 1.2;
    text-wrap: balance;
  }
  .vd-choose .vd-btn,
  .vd-url { height: 36px; font-size: 0.875rem; }
  .vd-choose .vd-btn { padding-inline: 12px; }
  .vd-or { margin: 12px 0 8px; font-size: 0.78rem; }
  .vd-form { max-width: 204px; gap: 6px; }
}

/* Portrait phones: the heading doesn't fit the clear centre, so it is left to screen readers */
@media (max-width: 444px) and (orientation: portrait) {
  .vd-choose h2 {
    position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
    overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
  }
}

/* iOS zooms the page into fields under 16px */
@media (pointer: coarse) {
  .vd-url,
  .vd-field input,
  .vd-field select { font-size: 16px; }
}

/* Phone keyboard up (fitKeyboard in demo.js): only the visible area */
.vd.vd--kb {
  position: fixed;
  inset: var(--vd-vv-top, 0px) 0 auto;
  height: var(--vd-vv-h, 100%);
  min-height: 0;
  padding: 12px var(--gutter, 16px);
  overflow-y: auto;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.vd--kb .vd-panel { margin-block: auto; }
.vd--kb .vd-choose h2 { display: none; }

/* ── building ─────────────────────────────────────────────────────────────── */

/* One line per step as it completes, so the wait reads as work. */
.vd-progress {
  display: inline-grid;
  gap: 10px;
  margin: 8px 0 0;
  padding: 0;
  list-style: none;
  text-align: left;
  font-size: var(--fs-caption, 0.86rem);
}
.vd-progress li {
  display: flex;
  gap: 10px;
  align-items: baseline;
  color: var(--vd-muted);
  animation: vd-panel-in 0.32s var(--vd-ease) backwards;
}
.vd-progress li::before { content: "\2713"; color: var(--vd-accent); font-size: 0.85em; }
.vd-progress li.is-warn::before { content: "\2013"; color: var(--vd-muted); }

/* ── review ───────────────────────────────────────────────────────────────── */

/* Taller than the orb's clear centre, so a card of its own over the orb, in the clinic card's clothes. */
.vd-review {
  width: min(380px, 100%);
  padding: 22px 20px 20px;
  border: 1px solid var(--vd-line);
  border-radius: 18px;
  background: color-mix(in srgb, var(--vd-surface) 86%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  backdrop-filter: blur(14px) saturate(1.4);
  box-shadow: 0 1px 2px rgba(26, 43, 41, 0.05), 0 14px 34px -20px rgba(26, 43, 41, 0.42);
}
.vd-note {
  margin: 0 0 16px;
  color: var(--vd-muted);
  font-size: var(--fs-caption, 0.86rem);
  line-height: 1.5;
}
.vd-fields { display: grid; gap: 10px; margin: 0 0 18px; text-align: left; }
.vd-field { display: grid; gap: 4px; }
.vd-field span { margin-left: 2px; color: var(--vd-muted); font-size: 0.78rem; font-weight: 560; }
.vd-field input,
.vd-field select {
  width: 100%;
  padding: 9px 12px;
  border: 1px solid var(--vd-line);
  border-radius: 10px;
  background: var(--vd-surface);
  color: var(--vd-text);
  font: inherit;
  font-size: var(--fs-body, 0.96rem);
}
.vd-field input:focus-visible,
.vd-field select:focus-visible { outline: 2px solid var(--vd-accent); outline-offset: 1px; }
.vd-start { width: 100%; }

/* Phones and short windows */
@media (max-width: 599px), (max-height: 640px) {
  .vd-review { padding: 18px 16px 16px; }
  .vd-review h2 { margin-bottom: 4px; font-size: 1.06rem; }
  .vd-note { margin-bottom: 12px; font-size: 0.78rem; line-height: 1.4; }
  .vd-fields { gap: 8px; margin-bottom: 14px; }
  .vd-field { gap: 3px; }
  .vd-field span { font-size: 0.72rem; }
  .vd-field input,
  .vd-field select { padding: 7px 11px; }
  .vd-start { padding-block: 10px; }
}

/* ── the clinic card ──────────────────────────────────────────────────────── */
/* Who the call reaches. Top left on a desktop; on a phone or short window the name and note with View
   more, docked under the orb on a phone (aimOrb). A slot and a clip, so it moves like a notification. */
.vd-clinic {
  --vd-dock: top;           /* both read by demo.js */
  --vd-clinic-in: 0;
  position: fixed;
  top: calc(clamp(18px, 3vw, 30px) + env(safe-area-inset-top, 0px));
  left: clamp(18px, 4vw, 40px);
  /* Over the canvas (122) and the stage (120), under the notifications (130). */
  z-index: 129;
  /* Narrows on a small desktop to clear the notifications: 396px = their 316 + the close's 44 + 3 gaps. */
  width: min(264px, calc(100vw - 2 * clamp(18px, 4vw, 40px) - 396px));
  display: grid;
  grid-template-rows: 0fr;
  pointer-events: none;
  font-family: var(--font-body, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif);
  color: var(--vd-text);
  text-align: left;
  transition: grid-template-rows 520ms var(--vd-ease), opacity 0.5s var(--ease-out, ease-out);
}
.vd-clinic-clip {
  overflow: hidden;
  min-height: 0;
  opacity: 0;
  transform: translate3d(14px, 0, 0) scale(0.97);
  transition: opacity 380ms var(--vd-ease), transform 520ms var(--vd-ease);
}
.vd-clinic:is([data-phase="calling"], [data-phase="ended"]) { --vd-clinic-in: 1; grid-template-rows: 1fr; }
.vd-clinic:is([data-phase="calling"], [data-phase="ended"]) .vd-clinic-clip {
  opacity: 1;
  transform: none;
  pointer-events: auto;
}
/* Same exits as the band: fades with the takeover, then goes. */
body.is-demo-out .vd-clinic { opacity: 0; pointer-events: none; }
body:not(.is-demo):not(.is-demo-out):not(.is-try) .vd-clinic { display: none; }

/* The card itself, in a notification's clothes */
.vd-clinic-box {
  padding: 12px;
  border: 1px solid var(--vd-line);
  border-radius: 13px;
  background: color-mix(in srgb, var(--vd-surface) 86%, transparent);
  -webkit-backdrop-filter: blur(14px) saturate(1.4);
  backdrop-filter: blur(14px) saturate(1.4);
  box-shadow: 0 1px 2px rgba(26, 43, 41, 0.05), 0 14px 34px -20px rgba(26, 43, 41, 0.42);
}

.vd-clinic-head { margin: 0 2px 10px; }
.vd-clinic-eyebrow {
  margin: 0;
  font-size: var(--fs-micro, 0.72rem);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--vd-accent);
}
.vd-clinic-name {
  margin: 2px 0 0;
  font-family: var(--font-display, inherit);
  font-size: 1rem;
  font-weight: 650;
  letter-spacing: -0.01em;
  line-height: 1.25;
}

/* The fields, open on a desktop, behind View more on a phone. */
.vd-clinic-more {
  display: grid;
  grid-template-rows: 1fr;
  transition: grid-template-rows 340ms var(--vd-ease);
}
.vd-clinic-more > div { overflow: hidden; min-height: 0; }

.vd-clinic-field {
  padding: 8px 9px 9px;
  border-radius: 10px;
  background: var(--vd-surface);
  box-shadow: inset 0 0 0 1px color-mix(in srgb, var(--vd-line) 55%, transparent);
}
.vd-clinic-field + .vd-clinic-field { margin-top: 6px; }
.vd-clinic-label {
  margin: 0 1px 6px;
  color: var(--vd-muted);
  font-size: 0.7rem;
  font-weight: 560;
}
.vd-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 5px;
  margin: 0;
  padding: 0;
  list-style: none;
}
.vd-chip {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  height: 24px;
  padding: 0 9px;
  border-radius: 999px;
  background: var(--accent-dim, rgba(31, 122, 92, 0.1));
  color: var(--accent-deep, #155c44);
  font-size: 0.78rem;
  font-weight: 560;
  white-space: nowrap;
  max-width: 100%;
}
.vd-chip > span:last-child { overflow: hidden; text-overflow: ellipsis; }
.vd-chip:has(.vd-chip-face) { padding-left: 3px; }
.vd-chip-face {
  display: grid;
  place-items: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: linear-gradient(160deg, var(--accent-soft, #27946f), var(--vd-accent));
  color: var(--vd-ink);
  font-size: 0.56rem;
  font-weight: 700;
  letter-spacing: 0.03em;
}
.vd-chip--more { background: transparent; box-shadow: inset 0 0 0 1px var(--vd-line); color: var(--vd-muted); }

/* the summary's View more (.vd-toast-more) */
.vd-clinic-toggle {
  display: none;
  margin: 6px 2px 0;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-size: var(--fs-caption, 0.84rem);
  font-weight: 560;
  color: var(--vd-accent);
}
.vd-clinic-toggle:hover { text-decoration: underline; }

.vd-clinic-note {
  display: flex;
  align-items: flex-start;
  gap: 7px;
  margin: 10px 2px 0;
  padding-top: 10px;
  border-top: 1px solid var(--vd-line);
  font-size: 0.78rem;
  line-height: 1.4;
}
.vd-clinic-note svg { flex: none; width: 13px; height: 13px; margin-top: 1px; color: var(--vd-accent); }

/* Smaller screens need the room once the diary is drawn or the call is over, so the card goes. The
   query is the exact complement of a desktop: 1040×541 and up, or 721×900 and up. */
@media (max-width: 720px), (max-width: 1039px) and (max-height: 899px), (max-height: 540px) {
  .vd-clinic[data-phase="ended"],
  body:has(.vd-appt:not([hidden])) .vd-clinic { --vd-clinic-in: 0; grid-template-rows: 0fr; }
  .vd-clinic[data-phase="ended"] .vd-clinic-clip,
  body:has(.vd-appt:not([hidden])) .vd-clinic .vd-clinic-clip {
    opacity: 0;
    transform: translate3d(14px, 0, 0) scale(0.97);
    pointer-events: none;
  }
}
/* Narrow or short: the name and the note, View more opening the rest. */
@media (max-width: 720px), (max-height: 540px) {
  .vd-clinic-head {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 8px;
    margin-bottom: 0;
  }
  .vd-clinic-name { margin: 0; }
  .vd-clinic-more { grid-template-rows: 0fr; }
  .vd-clinic.is-open .vd-clinic-more { grid-template-rows: 1fr; }
  .vd-clinic-fields { padding-top: 10px; }
  .vd-clinic-toggle { display: inline; }
  .vd-clinic-note { margin-top: 8px; padding-top: 8px; }
}
/* A phone: under the orb, on top of the band. */
@media (max-width: 720px) {
  .vd-clinic {
    --vd-dock: bottom;
    top: auto;
    bottom: calc(var(--vd-foot-h, 44px) + 8px);
    left: 16px;
    right: 16px;
    width: auto;
  }
  /* side by side, so opening it costs the orb less room */
  .vd-clinic-fields {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px;
  }
  .vd-clinic-field { min-width: 0; }
  .vd-clinic-field + .vd-clinic-field { margin-top: 0; }
}

/* A small phone held sideways: this instead of the demo (demo.js) */
.vd-turn {
  position: fixed;
  inset: 0;
  z-index: 131;
  display: grid;
  place-items: center;
  padding: 24px;
  background: var(--vd-bg);
  color: var(--vd-text);
  font-family: var(--font-body, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif);
  text-align: center;
}
.vd-turn p { margin: 0; max-width: 26ch; font-size: 1.05rem; line-height: 1.5; text-wrap: balance; }
.vd-turn[hidden],
body:not(.is-demo):not(.is-try) .vd-turn { display: none; }

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

.vd-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 12px 22px;
  border: 1px solid var(--vd-line);
  border-radius: 999px;
  background: var(--vd-surface);
  color: var(--vd-text);
  font: inherit;
  font-size: var(--fs-body, 0.96rem);
  font-weight: 560;
  cursor: pointer;
  transition: transform 0.18s var(--ease-out, ease), background 0.18s ease, opacity 0.18s ease;
}
.vd-btn:hover { transform: translateY(-1px); }
.vd-btn:disabled { opacity: 0.55; cursor: default; transform: none; }

.vd-btn--primary { background: var(--vd-accent); border-color: transparent; color: var(--vd-ink); }
.vd-btn--ghost { background: transparent; }

.vd-close {
  position: absolute;
  /* The takeover's .demo__close inset and size (styles.css), so one offset places the notifications
     beside either; both carry the safe-area inset. */
  top: calc(clamp(18px, 3vw, 30px) + env(safe-area-inset-top, 0px));
  right: clamp(18px, 4vw, 40px);
  width: 44px;
  height: 44px;
  border: 1px solid var(--vd-line);
  border-radius: 999px;
  background: var(--vd-surface);
  color: var(--vd-text);
  font-size: 0.9rem;
  cursor: pointer;
}

.vd-turnstile { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ── calling ──────────────────────────────────────────────────────────────── */

.vd-status {
  margin: 0;
  min-height: 1.4em;
  color: var(--vd-muted);
  font-size: var(--fs-caption, 0.86rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.vd-timer {
  margin: 0;
  font-variant-numeric: tabular-nums;
  font-size: var(--fs-h3, 1.3rem);
  color: var(--vd-muted);
}
.vd-timer.is-warning { color: #a2372c; }

/* Stand-in for the three.js orb on /try, sized to hold the diary card; off where the real orb is behind. */
.vd-orb {
  display: none;
  position: absolute;
  top: var(--vd-orb-y, 50%);
  left: 50%;
  /* 98vw keeps the ring inside a phone's screen; the real orb's twin cap is orbCap() in demo.js. */
  width: min(var(--vd-orb-size, 700px), 125vmin, 98vw);
  aspect-ratio: 1;
  transform: translate(-50%, -50%);
  border-radius: 50%;
  pointer-events: none;
  z-index: 1;
  /* Clear to 70% of the radius, then a band: at ORB_DIAMETER (620, demo.js) a 217px clear centre
     against the card's 227px half-diagonal, so the corners sit just into the first band. 125vmin is
     the real orb's own cap (demoOrbScale, the website's orb-core.js). */
  background: radial-gradient(closest-side,
    transparent 70%,
    color-mix(in srgb, var(--vd-accent) 20%, transparent) 84%,
    color-mix(in srgb, var(--vd-accent) 30%, transparent) 93%,
    transparent 100%);
  animation: vd-pulse 3.4s ease-in-out infinite;
  transition: top 340ms var(--vd-ease), width 340ms var(--vd-ease);
}
/* Every phase, not just the call: /try opened on an empty screen otherwise. */
.vd[data-orb="css"] .vd-orb { display: block; }

@keyframes vd-pulse {
  0%, 100% { transform: translate(-50%, -50%) scale(1);    opacity: 0.75; }
  50%      { transform: translate(-50%, -50%) scale(1.04); opacity: 1; }
}

/* /try's whole page (nav and footer hidden, body.is-try), so the full viewport. Symmetric padding:
   .vd IS this element, and the orb centres on its midpoint. */
.try-stage {
  display: grid;
  align-items: center;
  min-height: 100dvh;
  padding-block: clamp(70px, 11vh, 120px);
}

/* ── notifications ────────────────────────────────────────────────────────── */
/* Top right of the VIEWPORT, above the takeover (z 120) and its close button (121). */

.vd-toasts {
  position: fixed;
  /* Level with the close button, to its left. --vd-close-gutter is the button's inset, width and a
     gap; the takeover's (.demo__close, 44px up to 40px in) is the bigger, so one value clears both. */
  --vd-close-gutter: calc(clamp(18px, 4vw, 40px) + 44px + 12px);
  top: calc(clamp(18px, 3vw, 30px) + env(safe-area-inset-top, 0px));
  right: var(--vd-close-gutter);
  z-index: 130;
  width: min(316px, calc(100vw - var(--vd-close-gutter) - clamp(14px, 2.2vw, 28px)));
  display: flex;
  flex-direction: column;
  align-items: stretch;
  pointer-events: none;
  font-family: var(--font-body, -apple-system, BlinkMacSystemFont, "Helvetica Neue", Arial, sans-serif);
  color: var(--vd-text);
  /* Leaves with the takeover rather than blinking out — see clearToasts. */
  transition: opacity 0.8s var(--ease-out, ease);
}
.vd-toasts.is-leaving { opacity: 0; }

/* The slot animates its height, so the notifications below a leaving one slide up. */
.vd-toast-slot {
  display: grid;
  grid-template-rows: 0fr;
  margin-bottom: 0;
  transition: grid-template-rows 520ms var(--vd-ease), margin-bottom 520ms var(--vd-ease);
}
.vd-toast-slot.is-in { grid-template-rows: 1fr; margin-bottom: 9px; }

/* No padding or border on the clipper, or the track never collapses past them. */
.vd-toast-clip {
  overflow: hidden;
  min-height: 0;
  opacity: 0;
  transform: translate3d(14px, 0, 0) scale(0.97);
  transition: opacity 380ms var(--vd-ease), transform 520ms var(--vd-ease);
}
.vd-toast-slot.is-in .vd-toast-clip { opacity: 1; transform: none; }

.vd-toast {
  display: flex;
  align-items: flex-start;
  gap: 9px;
  /* The right side leaves room for the X, which every notification carries. */
  padding: 12px 34px 12px 14px;
  border: 1px solid var(--vd-line);
  border-radius: 13px;
  background: color-mix(in srgb, var(--vd-surface) 86%, transparent);
  backdrop-filter: blur(14px) saturate(1.4);
  box-shadow: 0 1px 2px rgba(26, 43, 41, 0.05), 0 14px 34px -20px rgba(26, 43, 41, 0.42);
  text-align: left;
  pointer-events: auto;
  position: relative;
}

.vd-toast-dot {
  flex: none;
  width: 7px; height: 7px;
  margin-top: 6px;
  border-radius: 50%;
  background: var(--vd-accent);
}

.vd-toast-line {
  margin: 0;
  font-size: var(--fs-caption, 0.86rem);
  line-height: 1.45;
  color: var(--vd-text);
}

/* The summary carries more than the rest; it replaces them when the call ends. */
.vd-toast--summary { display: block; padding: 16px 34px 16px 16px; }
.vd-toast-x {
  /* Centred on the card's height: an X pinned to the top of one line reads as misaligned. */
  position: absolute; top: 50%; right: 8px;
  transform: translateY(-50%);
  width: 22px; height: 22px;
  display: grid; place-items: center;
  border: 0; border-radius: 999px;
  background: none; color: var(--vd-muted);
  font: inherit; font-size: 0.8rem; line-height: 1;
  cursor: pointer;
  opacity: 0.55;
  transition: opacity 200ms var(--vd-ease), background 200ms var(--vd-ease);
}
.vd-toast-x:hover { opacity: 1; background: var(--accent-dim, rgba(31, 122, 92, 0.1)); }
/* The summary is several lines deep, so its X stays in the corner. */
.vd-toast--summary .vd-toast-x { top: 8px; transform: none; }

.vd-toast-eyebrow {
  margin: 0 0 11px;
  font-size: var(--fs-micro, 0.72rem);
  letter-spacing: 0.13em;
  text-transform: uppercase;
  color: var(--vd-accent);
}
.vd-toast-intent {
  display: inline-block;
  padding: 3px 10px;
  border-radius: 999px;
  background: var(--accent-dim, rgba(31, 122, 92, 0.1));
  color: var(--vd-accent);
  font-size: var(--fs-caption, 0.84rem);
  font-weight: 560;
}
.vd-toast-intent[data-intent="cancellation"] { background: rgba(162, 55, 44, 0.1); color: #a2372c; }
.vd-toast-intent[data-intent="reschedule"]   { background: rgba(176, 129, 32, 0.12); color: #8a6512; }

.vd-toast-meta {
  margin: 9px 0 0;
  color: var(--vd-muted);
  font-size: var(--fs-caption, 0.84rem);
}
.vd-toast-summary { margin: 9px 0 0; line-height: 1.5; font-size: var(--fs-caption, 0.88rem); }
.vd-toast-facts {
  margin: 9px 0 0;
  padding-left: 16px;
  color: var(--vd-muted);
  font-size: var(--fs-caption, 0.82rem);
  line-height: 1.55;
}

/* The summary stays, and on a phone it's taller than the card: collapsed to about two notifications. */
.vd-toast-more {
  display: none;
  margin: 10px 0 0;
  padding: 0;
  background: none; border: 0; cursor: pointer;
  font: inherit; font-size: var(--fs-caption, 0.84rem); font-weight: 560;
  color: var(--vd-accent);
}
.vd-toast-more:hover { text-decoration: underline; }

@media (max-width: 720px) {
    /* 56px is the eyebrow and intent pill whole, so the cut lands in the margin below them. */
  .vd-toast--summary .vd-toast-body {
    max-height: 56px;
    overflow: hidden;
    transition: max-height 340ms var(--vd-ease);
  }
  .vd-toast--summary.is-open .vd-toast-body {
    max-height: 62vh;
    overflow-y: auto;
  }
  .vd-toast--summary .vd-toast-more { display: inline; }
}

/* ── ended ────────────────────────────────────────────────────────────────── */

/* `.vd-btn` sets a display, which beats the browser's [hidden] rule on equal specificity. */
.vd-btn[hidden] { display: none; }

.vd-error-text { margin: 0 0 20px; line-height: 1.55; }

/* ── recording note ───────────────────────────────────────────────────────── */

/* Bottom centre: absolute on /try, fixed in the takeover (its panel is only as tall as its
   content). Inside .vd, so the takeover's visibility toggle takes it on close. */
.vd-foot {
  position: absolute;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 0 16px calc(14px + env(safe-area-inset-bottom, 0px));
  pointer-events: none;
}
.vd-recording-note {
  margin: 0;
  max-width: calc(100vw - 32px);
  color: var(--vd-muted);
  font-size: var(--fs-micro, 0.72rem);
  opacity: 0.7;
  text-align: center;
}

body.is-demo .vd-foot { position: fixed; }

/* Lifted onto the body by demo.js to clear the orb's canvas; under the notifications (130). */
.vd-foot--detached {
  position: fixed; z-index: 129;
  transition: opacity 0.5s var(--ease-out, ease-out);
}
/* On the body, so on close it fades with the panel (.demo in styles.css, 0.5s). */
body.is-demo-out .vd-foot--detached { opacity: 0; pointer-events: none; }
body:not(.is-demo):not(.is-demo-out):not(.is-try) .vd-foot--detached { display: none; }

/* After a call the band is the way on (showNext in demo.js), above the recording note, outside the
   orb. OPAQUE on purpose: a short viewport's glow washed out the line and button through a fade. */
.vd-foot.is-continue {
  padding-top: 16px;
  background: var(--vd-bg);
  border-top: 1px solid var(--vd-line);
  pointer-events: auto;
}
.vd-continue-note {
  margin: 0;
  color: var(--vd-muted);
  font-size: var(--fs-caption, 0.84rem);
  text-align: center;
}
.vd-continue { width: min(320px, 100%); }
.vd-continue[hidden], .vd-continue-note[hidden] { display: none; }
.vd-foot.is-continue .vd-recording-note { margin-top: 2px; }

/* After the last call: home and pricing, side by side, at Call again's width. */
.vd-leave {
  display: flex;
  gap: 10px;
  width: min(380px, 100%);
}
.vd-leave[hidden] { display: none; }
.vd-leave .vd-btn { flex: 1; padding-inline: 14px; text-decoration: none; white-space: nowrap; }

/* ── the booking, drawn into the clinic's calendar ─────────────────────────── */
/* "Clinic Calendar.dc.html" from Claude Design, in its own palette and type: the clinic's system, not
   Voicely chrome. The wrapper is exactly the card's rect, which focusOrb measures to aim the orb. */
.vd-appt {
  position: relative;
  z-index: 2;
  display: grid;
  justify-items: center;
  width: min(320px, 100%);
  /* --vd-cal-scale (demo.js): 1 wherever the card fits the orb's clear core, less on a phone. It
     rides in the keyframes too, or the animation's transform would drop it. */
  transform: scale(var(--vd-cal-scale, 1));
  animation: vd-appt-in 620ms var(--vd-ease) both;
}
/* No bottom margin: `.vd` centres the card INCLUDING it, and the orb follows the card. `display:
   grid` beats the browser's [hidden] rule, as with .vd-btn[hidden]. */
.vd-appt[hidden] { display: none; }
.vd-appt-card { width: min(320px, 100%); }
/* a long practitioner title is cut short, not a wider column that pushes the card right */
.vd-appt, .vd-appt-card { min-width: 0; }

/* Wide enough for the glow to pass in FRONT of the card: the stand-in stops shrinking at 496 (620 /
   1.25), on both axes. The landing page does the same for the real orb (body.is-demo .orb-canvas). */
@media (min-width: 496px) and (min-height: 496px) {
  .vd-appt { z-index: 0; }
}

@keyframes vd-appt-in {
  from { opacity: 0; transform: translate3d(0, 14px, 0) scale(calc(var(--vd-cal-scale, 1) * 0.965)); }
  to   { opacity: 1; transform: scale(var(--vd-cal-scale, 1)); }
}

.vd-cal {
  --cal-accent:  #1E7053;
  --cal-surface: #FCFBF9;
  --cal-edge:    #E4E0D8;
  --cal-hair:    #EBE7DF;
  --cal-strip:   #FAF8F4;
  --cal-ink:     #232926;
  --cal-muted:   #63665F;
  --cal-gutter:  32px;

  overflow: hidden;
  border: 1px solid var(--cal-edge);
  border-radius: 10px;
  background: var(--cal-surface);
  color: var(--cal-ink);
  text-align: left;
  font-family: "Source Sans 3", -apple-system, BlinkMacSystemFont, "Helvetica Neue", Helvetica, Arial, sans-serif;
  box-shadow:
    0 1px 2px rgba(35, 41, 38, 0.05),
    0 6px 16px -8px rgba(35, 41, 38, 0.16),
    0 20px 44px -22px rgba(35, 41, 38, 0.30);
}
.vd-appt[data-state="moved"]     .vd-cal { --cal-accent: #8A6512; }
.vd-appt[data-state="cancelled"] .vd-cal { --cal-accent: #C4452F; }

/* the strip's spacer, before the status pill */
.vd-cal-gap { flex: 1; }

/* Practitioner strip, the top row, with the status pill */
.vd-cal-who {
  display: flex; align-items: center; gap: 7px;
  padding: 7px 9px;
  border-bottom: 1px solid var(--cal-hair);
  background: var(--cal-strip);
  min-width: 0;
}
.vd-cal-who b { font-size: 12px; font-weight: 700; white-space: nowrap; }
.vd-cal-role {
  font-size: 10.5px; color: var(--cal-muted);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* day header */
.vd-cal-days { display: grid; border-bottom: 1px solid var(--cal-edge); }
.vd-cal-corner { border-right: 1px solid var(--cal-hair); }
.vd-cal-dh {
  padding: 5px 0 6px; text-align: center;
  border-right: 1px solid var(--cal-hair);
}
.vd-cal-dh:last-child { border-right: 0; }
.vd-cal-dh i {
  display: block; font-style: normal;
  font-size: 8.5px; font-weight: 700; letter-spacing: 0.07em; color: #6E7169;
}
.vd-cal-dh b {
  display: block;
  font-size: 12px; font-weight: 600; margin-top: 1px; color: #3A403B;
  font-variant-numeric: tabular-nums;
}
.vd-cal-dh.is-booked { background: color-mix(in srgb, var(--cal-accent) 6%, var(--cal-surface)); }
.vd-cal-dh.is-booked i { color: #1A5A43; }
.vd-appt[data-state="moved"]     .vd-cal-dh.is-booked i,
.vd-appt[data-state="cancelled"] .vd-cal-dh.is-booked i { color: var(--cal-accent); }
.vd-cal-dh.is-booked b {
  margin: 1px auto 0; width: 20px; height: 17px;
  display: grid; place-items: center;
  border-radius: 999px; background: var(--cal-accent);
  color: #fff; font-size: 12px; font-weight: 700;
}

/* grid */
.vd-cal-body { position: relative; }
/* Quarter hours, behind everything and not clickable. */
.vd-cal-minor {
  position: absolute;
  inset: 0 0 0 var(--cal-gutter);
  pointer-events: none;
  background-image: repeating-linear-gradient(to bottom, #F0EDE6 0 1px, transparent 1px 10px);
}
.vd-cal-grid { display: grid; }
.vd-cal-gutter {
  position: relative;
  height: var(--cal-height, 240px);
  border-right: 1px solid var(--cal-hair);
}
.vd-cal-gutter span {
  position: absolute; right: 7px;
  font-size: 10px; font-weight: 600; color: #77756D;
  font-variant-numeric: tabular-nums;
}
.vd-cal-col {
  position: relative;
  height: var(--cal-height, 240px);
  border-right: 1px solid var(--cal-hair);
  background-image: repeating-linear-gradient(to bottom, transparent 0 39px, #E6E2DA 39px 40px);
}
.vd-cal-col:last-child { border-right: 0; }
.vd-cal-col.is-booked {
  background-color: color-mix(in srgb, var(--cal-accent) 4%, var(--cal-surface));
  background-image: repeating-linear-gradient(to bottom, transparent 0 43px, #E2E8E3 43px 44px);
}

/* appointments */
.vd-cal-appt {
  position: absolute; left: 2px; right: 2px;
  padding: 3px 5px;
  border-radius: 3px;
  overflow: hidden;
  background: #DCEDE4;
  border-left: 2px solid #1E7053;
}
.vd-cal-appt .vd-cal-at { display: block; font-size: 9.5px; line-height: 1.1; color: #27573F; }
.vd-cal-appt b {
  display: block; font-size: 10.5px; font-weight: 600; line-height: 1.2; color: #1A5A43;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vd-cal-appt.is-mine {
  z-index: 2;
  border-left: 0;
  border-radius: 4px;
  background: var(--cal-accent);
  box-shadow: 0 0 0 2px var(--cal-surface), 0 0 0 3.5px var(--cal-accent);
}
.vd-cal-appt.is-mine .vd-cal-at { color: #E2F2EA; }
.vd-cal-appt.is-mine b { color: #fff; }
.vd-cal-appt .vd-cal-what {
  display: block; font-size: 9.5px; line-height: 1.2; color: #D6EBE0;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.vd-appt[data-state="cancelled"] .vd-cal-appt.is-mine {
  background: transparent;
  border: 1px dashed var(--cal-accent);
  box-shadow: none;
}
.vd-appt[data-state="cancelled"] .vd-cal-appt.is-mine .vd-cal-at,
.vd-appt[data-state="cancelled"] .vd-cal-appt.is-mine .vd-cal-what { color: var(--cal-accent); }
.vd-appt[data-state="cancelled"] .vd-cal-appt.is-mine b {
  color: var(--cal-accent);
  text-decoration: line-through;
}

/* now */
.vd-cal-now {
  position: absolute; left: 0; right: 0; height: 0;
  border-top: 1px solid #C4452F;
  z-index: 3;
}
.vd-cal-now::before {
  content: ""; position: absolute; left: -3px; top: -3px;
  width: 6px; height: 6px; border-radius: 999px; background: #C4452F;
}

/* Booked / Moved / Cancelled, at the end of the practitioner strip */
.vd-cal-tag {
  height: 19px; padding: 0 8px;
  display: grid; place-items: center;
  border-radius: 6px;
  background: color-mix(in srgb, var(--cal-accent) 12%, transparent);
  color: var(--cal-accent);
  font-size: 10.5px; font-weight: 600; white-space: nowrap;
}

/* Narrow: the stack fills the width BESIDE the close control, at most two (maxToasts in demo.js), and
   the card comes down to its orb, so the two never meet. */
@media (max-width: 720px) {
  .vd-toasts {
    left: clamp(14px, 2.2vw, 28px);
    right: var(--vd-close-gutter);
    width: auto;
  }
}

@media (max-width: 720px) and (max-height: 560px) {
  .vd[data-phase="calling"] .vd-calling { gap: 10px; }
  .vd-timer { font-size: 1rem; }
  .vd-end { padding-block: 8px; }
}

@media (prefers-reduced-motion: reduce) {
  .vd-btn { transition: none; animation: none; }
  .vd-appt { animation: none; }
  /* The rows still arrive, fading where they used to lift. */
  @keyframes vd-panel-in { from { opacity: 0; } to { opacity: 1; } }
  .vd-orb { animation: none; transform: translate(-50%, -50%); }
  .vd-toast-slot, .vd-toast-clip { transition-duration: 1ms; }
  .vd-clinic, .vd-clinic-clip, .vd-clinic-more, .vd-calling { transition-duration: 1ms; }
}
