/* ==========================================================================
   Yusra — design system.

   Loaded after css/tokens.css. Mobile-first throughout: every base rule
   describes a 375px handset and every media query is `min-width`, so a wider
   viewport only ever adds capability.

   Written in CSS logical properties (margin-inline, padding-block,
   inset-inline-start, border-start-start-radius…) so that flipping
   <html dir="rtl"> for Arabic mirrors the whole system with no second sheet
   and no per-component overrides.

    1  base + reset
    2  layout: container, section, grid
    3  typography: display, headings, eyebrow, prose
    4  media: the warm image treatment
    5  buttons
    6  forms: input, select, textarea, checkbox, radio
    7  chips + choice cards
    8  cards: treatment, dentist, testimonial, appointment, stat, fee, document
    9  badges + alerts
   10  progress: stepper, bar, tasklist, timeline
   11  booking: calendar, time slots, file upload
   12  overlays: modal, bottom sheet, toast
   13  states: empty, success, loading, skeleton
   14  navigation: header, drawer, footer
   15  portal: shell, rail, tab bar
   16  motion + reveal
   17  accessibility utilities
   18  RTL corrections
   ========================================================================== */

/* ==========================================================================
   1  base + reset
   ========================================================================== */

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

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

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

body {
  background: var(--background);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--fs-body);
  line-height: var(--lh-body);
  font-weight: var(--fw-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

/* Inherited from the previous build: <html> and <body> both carried
   overflow-x:hidden, which made <body> its own scroll container and gave the
   page a second scrollbar. `clip` does the same job without ever creating a
   scroll container. `hidden` stays first as the fallback for old engines. */
html,
body {
  overflow-x: hidden;
  overflow-x: clip;
}

img,
picture,
svg,
video {
  max-inline-size: 100%;
  block-size: auto;
  display: block;
}

/* The browser's own `[hidden] { display: none }` is an element-level rule, so
   ANY class here that sets a display — .ds-stack, .ds-cluster, .ds-grid,
   .ds-stepper, .ds-slots and a dozen others — silently outranks it and the
   element stays on screen with `hidden` set. Since the booking flow and the
   portal both toggle `hidden` constantly, this has to win outright.
   The !important is deliberate and is the only one in the design system. */
[hidden] {
  display: none !important;
}

/* Long treatment names and German compounds have no natural break point and
   set a floor no column can meet at 320px. */
h1, h2, h3, h4, h5, h6,
p, li, a, span, div, td, th, label, figcaption, button {
  overflow-wrap: break-word;
}

:root[lang="de"] p,
:root[lang="de"] li,
:root[lang="de"] h1,
:root[lang="de"] h2,
:root[lang="de"] h3,
:root[lang="de"] h4 { hyphens: auto; }

/* One focus treatment for the entire product. Visible, high contrast, and
   never suppressed — :focus-visible keeps it off mouse clicks. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: none;
  box-shadow: var(--focus-ring);
  border-radius: var(--radius-sm);
}

::selection {
  background: var(--primary-tint);
  color: var(--text-primary);
}

/* ==========================================================================
   2  layout
   ========================================================================== */

.ds-container {
  inline-size: 100%;
  max-inline-size: var(--container);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.ds-container--wide { max-inline-size: var(--container-wide); }
.ds-container--text { max-inline-size: var(--container-text); }

.ds-section {
  padding-block: var(--section-y);
}

.ds-section--tight  { padding-block: var(--section-y-tight); }
.ds-section--flush-top    { padding-block-start: 0; }
.ds-section--flush-bottom { padding-block-end: 0; }

.ds-section--cream   { background: var(--surface-secondary); }
.ds-section--blush   { background: var(--accent-blush); }
.ds-section--lavender{ background: var(--accent-lavender); }
.ds-section--inverse {
  background: var(--surface-inverse);
  color: var(--text-inverse);
}
.ds-section--inverse .ds-eyebrow { color: var(--text-inverse-muted); }
.ds-section--inverse .ds-lead,
.ds-section--inverse p { color: var(--text-inverse-muted); }
.ds-section--inverse :is(h1, h2, h3) { color: var(--text-inverse); }

/* A vertical stack with a single rhythm knob. Used instead of margin
   utilities sprinkled through the markup. */
.ds-stack       { display: flex; flex-direction: column; gap: var(--space-4); }
.ds-stack--xs   { gap: var(--space-2); }
.ds-stack--sm   { gap: var(--space-3); }
.ds-stack--lg   { gap: var(--space-6); }
.ds-stack--xl   { gap: var(--space-10); }

.ds-cluster {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

/* Auto-fitting grid. --min is the point a column may not shrink past, so the
   grid drops to fewer columns instead of squeezing. */
.ds-grid {
  display: grid;
  gap: var(--space-4);
  grid-template-columns: repeat(auto-fit, minmax(min(100%, var(--min, 260px)), 1fr));
}

.ds-grid--gap-lg { gap: var(--space-6); }

/* Explicit two-column editorial split; single column until there is room. */
.ds-split {
  display: grid;
  gap: var(--space-8);
  align-items: center;
}

@media (min-width: 62rem) {
  .ds-split { grid-template-columns: 1fr 1fr; gap: var(--space-16); }
  .ds-split--media-lead  { grid-template-columns: 1.15fr 1fr; }
  .ds-split--text-lead   { grid-template-columns: 1fr 1.15fr; }
  /* Subtle asymmetry: the media column steps out of the text baseline. */
  .ds-split--offset > :last-child { transform: translateY(var(--space-10)); }
}

/* ==========================================================================
   3  typography
   ========================================================================== */

:is(h1, h2, h3, h4, h5, h6) {
  font-family: var(--font-display);
  font-variation-settings: "SOFT" var(--display-soft), "WONK" var(--display-wonk);
  font-weight: var(--fw-display);
  color: var(--text-primary);
  line-height: var(--lh-heading);
  letter-spacing: var(--ls-heading);
  text-wrap: balance;
  margin-block: 0 var(--space-4);
}

h1 { font-size: var(--fs-h1); }
h2 { font-size: var(--fs-h2); }
h3 { font-size: var(--fs-h3); line-height: var(--lh-h3); }
h4 { font-size: var(--fs-h4); line-height: var(--lh-h3); }

/* The signature move, taken from the reference boards: headline set in
   terracotta rather than charcoal, with one or two words in true italic. */
.ds-display {
  font-family: var(--font-display);
  font-variation-settings: "SOFT" var(--display-soft), "WONK" var(--display-wonk);
  font-size: var(--fs-display);
  font-weight: var(--fw-display-light);
  line-height: var(--lh-display);
  letter-spacing: var(--ls-display);
  color: var(--primary);
  text-wrap: balance;
  margin-block: 0 var(--space-6);
}

.ds-title-primary { color: var(--primary); }

/* Used sparingly — one phrase per headline, never a whole line. */
.ds-italic {
  font-style: italic;
  font-variation-settings: "SOFT" 60, "WONK" 1;
}

/* Arabic has no italic; emphasis shifts to weight so the intent survives. */
:root[lang="ar"] .ds-italic {
  font-style: normal;
  font-weight: var(--fw-semibold);
}

/* Numbered section label — "(01) About us" from the reference boards. */
.ds-eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-body);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin-block-end: var(--space-4);
}

.ds-eyebrow__num {
  color: var(--primary-on-tint);
  font-variant-numeric: tabular-nums;
}

.ds-eyebrow--center { justify-content: center; }

.ds-lead {
  font-size: var(--fs-lead);
  line-height: var(--lh-lead);
  color: var(--text-secondary);
  max-inline-size: 56ch;
  margin-block: 0 var(--space-6);
}

.ds-prose { max-inline-size: var(--container-text); }
.ds-prose p { margin-block: 0 var(--space-4); color: var(--text-secondary); }
.ds-prose :is(h2, h3) { margin-block-start: var(--space-10); }
.ds-prose :is(ul, ol) {
  margin-block: 0 var(--space-4);
  padding-inline-start: var(--space-6);
  color: var(--text-secondary);
}
.ds-prose li { margin-block-end: var(--space-2); }
.ds-prose strong { color: var(--text-primary); font-weight: var(--fw-semibold); }

.ds-meta {
  font-size: var(--fs-caption);
  letter-spacing: var(--ls-caption);
  color: var(--text-tertiary);
}

/* Big serif numeral, the stat treatment from the reference boards. */
.ds-stat__value {
  font-family: var(--font-display);
  font-variation-settings: "SOFT" var(--display-soft);
  font-size: var(--fs-stat);
  font-weight: var(--fw-display-light);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--primary);
  font-variant-numeric: tabular-nums lining-nums;
  display: block;
}

.ds-link {
  color: var(--primary-on-tint);
  text-decoration: underline;
  text-underline-offset: 0.2em;
  text-decoration-thickness: 1px;
  transition: color var(--dur-fast) var(--ease-out);
}
.ds-link:hover { color: var(--primary-hover); }

/* ==========================================================================
   4  media — the warm image treatment

   The supplied photography is lit cool: blue gloves, white coats, clinical
   daylight. Dropping it straight onto an ivory ground fights the palette.
   .ds-media grades it warm instead of asking for a reshoot:

     · a low-opacity terracotta multiply pass pulls the neutrals warm
     · a blush screen pass lifts the shadows so it is warm, not muddy
     · saturate/contrast keep it from going flat under the two passes

   Every slot is a fixed aspect-ratio frame with object-fit: cover, so
   swapping in real lifestyle photography later needs no markup change.
   ========================================================================== */

.ds-media {
  position: relative;
  overflow: hidden;
  border-radius: var(--radius-xl);
  background: var(--surface-secondary);
  isolation: isolate;
}

.ds-media img {
  inline-size: 100%;
  block-size: 100%;
  object-fit: cover;
  filter: saturate(0.86) contrast(1.02) brightness(1.01);
  transition: transform var(--dur-slow) var(--ease-out);
}

.ds-media::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background:
    linear-gradient(0deg, rgba(var(--primary-rgb), 0.14), rgba(var(--primary-rgb), 0.14)),
    linear-gradient(0deg, rgba(244, 230, 223, 0.20), rgba(244, 230, 223, 0.20));
  mix-blend-mode: multiply;
  z-index: 1;
}

/* Second pass: lifts the blacks so the multiply above reads as warm light
   rather than a dark filter. */
.ds-media::before {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: rgba(234, 223, 206, 0.16);
  mix-blend-mode: screen;
  z-index: 1;
}

.ds-media--plain::before,
.ds-media--plain::after { content: none; }   /* opt out: before/after galleries */

.ds-media--soft::after  { opacity: 0.6; }    /* lighter grade for portraits */

/* aspect frames */
.ds-media--hero     { aspect-ratio: 4 / 5; border-radius: var(--radius-hero); }
.ds-media--wide     { aspect-ratio: 16 / 10; }
.ds-media--square   { aspect-ratio: 1 / 1; }
.ds-media--portrait { aspect-ratio: 3 / 4; }
.ds-media--tall     { aspect-ratio: 2 / 3; }
.ds-media--card     { aspect-ratio: 3 / 2; border-radius: var(--radius-lg); }

@media (min-width: 62rem) {
  .ds-media--hero { aspect-ratio: 5 / 6; }
}

a:hover .ds-media img,
.ds-card:hover .ds-media img { transform: scale(1.03); }

/* Small floating stat card over hero media, as on the reference board. */
.ds-media__badge {
  position: absolute;
  inset-block-end: var(--space-5);
  inset-inline-start: var(--space-5);
  z-index: 2;
  background: var(--surface);
  border-radius: var(--radius-md);
  padding: var(--space-4) var(--space-5);
  box-shadow: var(--shadow-md);
  max-inline-size: 15rem;
}

/* ==========================================================================
   5  buttons

   One primary action per section. .ds-btn--primary is the only filled
   terracotta button; everything beside it is line or ghost, so visual weight
   always points at the single next step.
   ========================================================================== */

.ds-btn {
  --btn-bg: transparent;
  --btn-fg: var(--text-primary);
  --btn-bd: transparent;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  min-block-size: var(--touch-min);
  padding: 0.8125rem 1.625rem;
  border: 1px solid var(--btn-bd);
  border-radius: var(--radius-pill);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-family: var(--font-body);
  font-size: var(--fs-ui);
  font-weight: var(--fw-semibold);
  line-height: 1.2;
  text-decoration: none;
  text-align: center;
  cursor: pointer;
  transition:
    background-color var(--dur-fast) var(--ease-out),
    border-color     var(--dur-fast) var(--ease-out),
    color            var(--dur-fast) var(--ease-out),
    transform        var(--dur-instant) var(--ease-out);
}

.ds-btn:active { transform: translateY(1px); }

.ds-btn--primary {
  --btn-bg: var(--primary);
  --btn-fg: var(--text-on-primary);
  --btn-bd: var(--primary);
}
.ds-btn--primary:hover { --btn-bg: var(--primary-hover); --btn-bd: var(--primary-hover); }

.ds-btn--secondary {
  --btn-bd: var(--border-strong);
  --btn-fg: var(--text-primary);
}
.ds-btn--secondary:hover { --btn-bd: var(--text-primary); --btn-bg: var(--surface); }

.ds-btn--ghost { --btn-fg: var(--primary-on-tint); }
.ds-btn--ghost:hover { --btn-bg: var(--primary-tint); }

.ds-btn--inverse {
  --btn-bg: var(--surface);
  --btn-fg: var(--text-primary);
  --btn-bd: var(--surface);
}
.ds-btn--inverse:hover { --btn-bg: var(--accent-blush); --btn-bd: var(--accent-blush); }

.ds-btn--danger {
  --btn-bd: var(--error);
  --btn-fg: var(--error);
}
.ds-btn--danger:hover { --btn-bg: var(--error); --btn-fg: #fff; }

.ds-btn--sm { padding: 0.5rem 1rem; font-size: var(--fs-sm); min-block-size: 2.25rem; }
.ds-btn--lg { padding: 1.0625rem 2.25rem; font-size: 1rem; }
.ds-btn--block { inline-size: 100%; }

.ds-btn[disabled],
.ds-btn[aria-disabled="true"] {
  opacity: 0.45;
  cursor: not-allowed;
  pointer-events: none;
}

/* Loading: the label stays in place (so the button does not resize) and is
   hidden from both sight and assistive tech while the spinner announces. */
.ds-btn[data-loading="true"] { pointer-events: none; position: relative; color: transparent; }
.ds-btn[data-loading="true"]::after {
  content: "";
  position: absolute;
  inline-size: 1.125rem;
  block-size: 1.125rem;
  border: 2px solid currentColor;
  border-block-start-color: transparent;
  border-radius: 50%;
  color: var(--btn-fg);
  animation: ds-spin 0.7s linear infinite;
}

@keyframes ds-spin { to { transform: rotate(360deg); } }

/* Arrow-in-circle affordance from the reference boards. */
.ds-btn__arrow {
  flex: none;
  inline-size: 1rem;
  block-size: 1rem;
  transition: transform var(--dur-fast) var(--ease-out);
}
.ds-btn:hover .ds-btn__arrow { transform: translate(2px, -2px); }
:root[dir="rtl"] .ds-btn:hover .ds-btn__arrow { transform: translate(-2px, -2px); }

/* ==========================================================================
   6  forms
   ========================================================================== */

.ds-field { display: flex; flex-direction: column; gap: var(--space-2); }

.ds-label {
  font-size: var(--fs-ui);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
}

.ds-label__optional {
  font-weight: var(--fw-body);
  color: var(--text-tertiary);
  font-size: var(--fs-sm);
}

.ds-hint {
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.ds-input,
.ds-textarea,
.ds-select {
  inline-size: 100%;
  min-block-size: var(--touch-min);
  padding: 0.75rem 1rem;
  font-family: var(--font-body);
  /* 16px minimum: iOS Safari zooms the viewport on focus below this. */
  font-size: 1rem;
  line-height: var(--lh-ui);
  color: var(--text-primary);
  background: var(--surface);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  transition: border-color var(--dur-fast) var(--ease-out),
              box-shadow  var(--dur-fast) var(--ease-out);
}

.ds-input::placeholder,
.ds-textarea::placeholder { color: var(--text-tertiary); }

.ds-input:hover,
.ds-textarea:hover,
.ds-select:hover { border-color: var(--text-tertiary); }

.ds-input:focus-visible,
.ds-textarea:focus-visible,
.ds-select:focus-visible {
  border-color: var(--focus);
  box-shadow: var(--focus-ring);
}

.ds-textarea { min-block-size: 7rem; resize: vertical; }

/* The vendor sheet used a PNG arrow that could not mirror in RTL. This is an
   inline SVG in a logical position, so it follows the writing direction. */
.ds-select {
  appearance: none;
  padding-inline-end: 2.75rem;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='%236B5F55' stroke-width='1.75' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  background-size: 1rem;
}

:root[dir="rtl"] .ds-select { background-position: left 1rem center; }

.ds-field[data-invalid="true"] :is(.ds-input, .ds-textarea, .ds-select) {
  border-color: var(--error);
  background: var(--error-tint);
}

/* Error carries an icon as well as colour, so the state is never conveyed by
   colour alone. */
.ds-error {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  font-size: var(--fs-sm);
  font-weight: var(--fw-medium);
  color: var(--error);
}
.ds-error::before {
  content: "";
  flex: none;
  inline-size: 1rem;
  block-size: 1rem;
  margin-block-start: 0.15rem;
  background: currentColor;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M8 1L15 14H1L8 1zm0 5v4m0 2v.5' fill='none' stroke='black' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* --- checkbox + radio ---------------------------------------------------
   Custom control, native input. The input keeps its own semantics, focus
   and keyboard behaviour; only the box is redrawn.                        */

.ds-check {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  min-block-size: var(--touch-min);
  padding-block: var(--space-2);
  cursor: pointer;
}

.ds-check input {
  flex: none;
  appearance: none;
  inline-size: 1.375rem;
  block-size: 1.375rem;
  margin: 0.125rem 0 0;
  border: 1.5px solid var(--border-strong);
  background: var(--surface);
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color     var(--dur-fast) var(--ease-out);
}

.ds-check input[type="checkbox"] { border-radius: 6px; }
.ds-check input[type="radio"]    { border-radius: 50%; }

.ds-check input:checked {
  background-color: var(--primary);
  border-color: var(--primary);
}

.ds-check input[type="checkbox"]:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l3.5 3.5L13 5'/%3E%3C/svg%3E");
  background-size: 0.875rem;
  background-position: center;
  background-repeat: no-repeat;
}

.ds-check input[type="radio"]:checked {
  box-shadow: inset 0 0 0 4px var(--surface);
}

.ds-check input:focus-visible { box-shadow: var(--focus-ring); }

.ds-check__text { font-size: var(--fs-ui); line-height: var(--lh-ui); }
.ds-check__hint { display: block; font-size: var(--fs-sm); color: var(--text-secondary); }

/* ==========================================================================
   7  chips + choice cards
   ========================================================================== */

/* Chip — multi-select comfort preferences, filters, tags. */
.ds-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  min-block-size: var(--touch-min);
  padding: 0.5rem 1.125rem;
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-pill);
  background: var(--surface);
  color: var(--text-primary);
  font-size: var(--fs-ui);
  font-weight: var(--fw-medium);
  font-family: var(--font-body);
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color     var(--dur-fast) var(--ease-out),
              color            var(--dur-fast) var(--ease-out);
}

.ds-chip:hover { border-color: var(--primary); color: var(--primary-on-tint); }

/* The tick is added on selection, so the state is not colour-only. */
.ds-chip[aria-pressed="true"],
.ds-chip[data-selected="true"] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--text-on-primary);
}

.ds-chip[aria-pressed="true"]::before,
.ds-chip[data-selected="true"]::before {
  content: "";
  inline-size: 0.875rem;
  block-size: 0.875rem;
  flex: none;
  background: currentColor;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='2.25' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l3.5 3.5L13 5'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Static reassurance chip — not interactive. */
.ds-chip--static {
  cursor: default;
  background: var(--surface);
  border-color: transparent;
  font-weight: var(--fw-medium);
  color: var(--text-secondary);
}
.ds-chip--static:hover { border-color: transparent; color: var(--text-secondary); }

.ds-chip__icon { flex: none; inline-size: 1rem; block-size: 1rem; color: var(--primary); }

/* --- choice card --------------------------------------------------------
   The workhorse of the whole product: symptom chooser, booking reason,
   dentist preference, comfort level. A real radio/checkbox sits inside so
   keyboard and assistive-tech behaviour is native; the card is the label. */

.ds-choice {
  position: relative;
  display: flex;
  align-items: flex-start;
  gap: var(--space-4);
  padding: var(--space-5);
  background: var(--surface);
  border: 1.5px solid var(--border);
  border-radius: var(--radius-lg);
  cursor: pointer;
  text-align: start;
  inline-size: 100%;
  font-family: var(--font-body);
  transition: border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out);
}

.ds-choice:hover { border-color: var(--primary); }

/* The real radio/checkbox stays in the document and keeps every native
   behaviour — arrow-key group navigation, form submission, the accessibility
   tree entry. It is hidden with the clip technique rather than opacity:0,
   because a zero-opacity control is ambiguous to some testing tools and can
   be reported as invisible even though browsers keep it accessible. */
.ds-choice input {
  position: absolute;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

.ds-choice:has(input:checked),
.ds-choice[data-selected="true"] {
  border-color: var(--primary);
  background: var(--primary-tint);
}

.ds-choice:has(input:focus-visible) { box-shadow: var(--focus-ring); }

.ds-choice__icon {
  flex: none;
  inline-size: 2.75rem;
  block-size: 2.75rem;
  display: grid;
  place-items: center;
  border-radius: var(--radius-md);
  background: var(--accent-blush);
  color: var(--primary);
}

.ds-choice:has(input:checked) .ds-choice__icon { background: var(--surface); }

.ds-choice__body { flex: 1; min-inline-size: 0; }

.ds-choice__title {
  display: block;
  font-size: var(--fs-ui);
  font-weight: var(--fw-semibold);
  color: var(--text-primary);
  margin-block-end: var(--space-1);
}

.ds-choice__desc {
  display: block;
  font-size: var(--fs-sm);
  color: var(--text-secondary);
  line-height: 1.5;
}

/* Tick appears on selection — again, not colour alone. */
.ds-choice__tick {
  flex: none;
  inline-size: 1.375rem;
  block-size: 1.375rem;
  border-radius: 50%;
  border: 1.5px solid var(--border-strong);
  display: grid;
  place-items: center;
  background: var(--surface);
}

.ds-choice:has(input:checked) .ds-choice__tick {
  background: var(--primary);
  border-color: var(--primary);
}

.ds-choice:has(input:checked) .ds-choice__tick::after {
  content: "";
  inline-size: 0.75rem;
  block-size: 0.75rem;
  background: #fff;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M3 8.5l3.5 3.5L13 5'/%3E%3C/svg%3E") center / contain no-repeat;
}

/* Compact variant for dense grids. */
.ds-choice--compact { padding: var(--space-4); gap: var(--space-3); }
.ds-choice--compact .ds-choice__icon { inline-size: 2.25rem; block-size: 2.25rem; }

/* Link variant — the symptom chooser. Same card, but it navigates rather
   than selecting, so the trailing affordance is a chevron, not a tick. */
.ds-choice--link {
  text-decoration: none;
  color: inherit;
  block-size: 100%;
  align-items: center;
}

.ds-choice--link:hover { background: var(--primary-tint); }

.ds-choice__go {
  flex: none;
  inline-size: 1rem;
  block-size: 1rem;
  color: var(--primary-on-tint);
  transition: transform var(--dur-fast) var(--ease-out);
}

.ds-choice--link:hover .ds-choice__go { transform: translateX(3px); }
:root[dir="rtl"] .ds-choice__go { transform: scaleX(-1); }
:root[dir="rtl"] .ds-choice--link:hover .ds-choice__go { transform: scaleX(-1) translateX(3px); }

/* ==========================================================================
   8  cards

   Soft surfaces, minimal borders, no floating shadows. Separation comes from
   the surface being a shade off the section behind it.
   ========================================================================== */

.ds-card {
  display: flex;
  flex-direction: column;
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
  transition: transform var(--dur-base) var(--ease-out),
              background-color var(--dur-base) var(--ease-out);
}

.ds-card--blush  { background: var(--accent-blush); }
.ds-card--cream  { background: var(--surface-secondary); }
.ds-card--lavender { background: var(--accent-lavender); }
.ds-card--outline { background: transparent; border: 1px solid var(--border); }
.ds-card--flush  { padding: 0; overflow: hidden; }

a.ds-card,
.ds-card--interactive { text-decoration: none; color: inherit; cursor: pointer; }
a.ds-card:hover,
.ds-card--interactive:hover { transform: translateY(-3px); }

/* --- treatment card -----------------------------------------------------
   Serif title, short sans description, photo anchored at the bottom of the
   card — the composition from the reference board.                        */

.ds-treatment {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  padding: var(--space-6);
  background: var(--accent-blush);
  border-radius: var(--radius-lg);
  text-decoration: none;
  color: inherit;
  block-size: 100%;
  transition: background-color var(--dur-base) var(--ease-out),
              transform var(--dur-base) var(--ease-out);
}

.ds-treatment:hover { transform: translateY(-3px); }
.ds-treatment:nth-child(even) { background: var(--surface-secondary); }

.ds-treatment__title {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  font-weight: var(--fw-display);
  line-height: var(--lh-h3);
  /* The card is always blush or cream, and at the small end of the clamp this
     is 22px - below the 24px where 3:1 would be enough. */
  color: var(--primary-on-tint);
  margin: 0;
}

.ds-treatment__desc {
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--text-secondary);
  margin: 0;
  flex: 1;
}

.ds-treatment__media { margin-block-start: auto; }

.ds-treatment__from {
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  color: var(--text-tertiary);
  letter-spacing: var(--ls-caption);
}

/* Corner arrow, as on the reference board. */
.ds-treatment__arrow {
  position: absolute;
  inset-block-start: var(--space-5);
  inset-inline-end: var(--space-5);
  inline-size: 1.25rem;
  block-size: 1.25rem;
  color: var(--primary-on-tint);
  transition: transform var(--dur-fast) var(--ease-out);
}
.ds-treatment:hover .ds-treatment__arrow { transform: translate(3px, -3px); }
:root[dir="rtl"] .ds-treatment:hover .ds-treatment__arrow { transform: translate(-3px, -3px); }

/* --- dentist card ------------------------------------------------------ */

.ds-dentist {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  text-decoration: none;
  color: inherit;
}

.ds-dentist__name {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  color: var(--text-primary);
  margin: 0 0 var(--space-1);
}

.ds-dentist__role {
  font-size: var(--fs-sm);
  font-weight: var(--fw-semibold);
  color: var(--primary-on-tint);
  letter-spacing: var(--ls-caption);
}

.ds-dentist__bio {
  font-size: var(--fs-sm);
  line-height: 1.6;
  color: var(--text-secondary);
}

.ds-dentist__facts {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  font-size: var(--fs-caption);
  color: var(--text-tertiary);
}

/* --- testimonial ------------------------------------------------------- */

.ds-quote {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-8);
  background: var(--surface);
  border-radius: var(--radius-xl);
  block-size: 100%;
}

.ds-quote__text {
  font-family: var(--font-display);
  font-size: clamp(1.25rem, 1.1rem + 0.7vw, 1.625rem);
  line-height: 1.4;
  color: var(--text-primary);
  margin: 0;
  flex: 1;
}

.ds-quote__footer {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.ds-quote__avatar {
  flex: none;
  inline-size: 3rem;
  block-size: 3rem;
  border-radius: 50%;
  object-fit: cover;
}

.ds-quote__name { font-weight: var(--fw-semibold); font-size: var(--fs-ui); }
.ds-quote__treatment { font-size: var(--fs-caption); color: var(--text-tertiary); }

/* Rating: the number is rendered as text for assistive tech; stars decorate. */
.ds-rating { display: inline-flex; align-items: center; gap: 0.125rem; color: var(--primary); }
.ds-rating svg { inline-size: 1rem; block-size: 1rem; }

/* --- stat card --------------------------------------------------------- */

.ds-stat {
  padding: var(--space-8) var(--space-6);
  background: var(--accent-blush);
  border-radius: var(--radius-lg);
  text-align: start;
}

.ds-stat__label {
  display: block;
  margin-block-start: var(--space-3);
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

/* --- appointment card -------------------------------------------------- */

.ds-appt {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  padding: var(--space-6);
  background: var(--surface);
  border-radius: var(--radius-lg);
  border: 1px solid var(--border);
}

.ds-appt--next {
  background: var(--primary-tint);
  border-color: transparent;
}

.ds-appt__when {
  font-family: var(--font-display);
  font-size: var(--fs-h3);
  color: var(--text-primary);
  margin: 0;
}

.ds-appt__rows { display: flex; flex-direction: column; gap: var(--space-2); }

.ds-appt__row {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  font-size: var(--fs-ui);
  color: var(--text-secondary);
}

.ds-appt__row svg { flex: none; inline-size: 1.125rem; block-size: 1.125rem; color: var(--text-tertiary); margin-block-start: 0.15rem; }

.ds-appt__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }

/* --- fee row ----------------------------------------------------------- */

.ds-fee {
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-2) var(--space-6);
  padding-block: var(--space-4);
  border-block-end: 1px solid var(--border);
}

.ds-fee:last-child { border-block-end: none; }
.ds-fee__name { font-weight: var(--fw-medium); }
.ds-fee__note { display: block; font-size: var(--fs-sm); color: var(--text-secondary); font-weight: var(--fw-body); }
.ds-fee__price {
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  /* Fee tables almost always sit on a cream card, where --primary is 4.43:1
     and this is 19px - just under the bar. */
  color: var(--primary-on-tint);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

/* --- document row ------------------------------------------------------ */

.ds-doc {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  background: var(--surface);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: inherit;
  transition: background-color var(--dur-fast) var(--ease-out);
}

.ds-doc:hover { background: var(--accent-blush); }

.ds-doc__icon {
  flex: none;
  inline-size: 2.5rem;
  block-size: 2.5rem;
  display: grid;
  place-items: center;
  border-radius: var(--radius-sm);
  background: var(--accent-blush);
  color: var(--primary-on-tint);
}

.ds-doc__body { flex: 1; min-inline-size: 0; }
.ds-doc__name { font-weight: var(--fw-medium); font-size: var(--fs-ui); }
.ds-doc__meta { font-size: var(--fs-caption); color: var(--text-tertiary); }

/* --- accordion ----------------------------------------------------------
   Behaviour comes from js/components.js, which was carried over from the
   previous build — it is accessible, dependency-free and already correct.
   Only the appearance is redefined here, because the vendor stylesheet that
   used to style it is no longer loaded. */

.accordion { border-block-start: 1px solid var(--border); }

.accordion-section-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  inline-size: 100%;
  min-block-size: var(--touch-min);
  padding-block: var(--space-5);
  border: 0;
  border-block-end: 1px solid var(--border);
  background: transparent;
  color: var(--text-primary);
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  font-weight: var(--fw-display);
  line-height: var(--lh-h3);
  text-align: start;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out);
}

.accordion-section-title:hover { color: var(--primary-on-tint); }
.accordion-section-title.active { color: var(--primary-on-tint); }

/* Plus that becomes a minus. Rotation rather than a swapped glyph, so the
   transition is continuous and there is nothing to preload. */
.accordion-section-title::after {
  content: "";
  flex: none;
  inline-size: 1.25rem;
  block-size: 1.25rem;
  background: currentColor;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round'%3E%3Cpath d='M12 5v14M5 12h14'/%3E%3C/svg%3E") center / contain no-repeat;
  transition: transform var(--dur-base) var(--ease-out);
}

.accordion-section-title.active::after { transform: rotate(135deg); }

.accordion-section-content {
  padding-block: var(--space-2) var(--space-6);
  border-block-end: 1px solid var(--border);
}

.accordion-section-content p {
  margin: 0 0 var(--space-3);
  color: var(--text-secondary);
  max-inline-size: 68ch;
}

.accordion-section-content p:last-child { margin-block-end: 0; }

/* ==========================================================================
   9  badges + alerts
   ========================================================================== */

.ds-badge {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 0.3125rem 0.75rem;
  border-radius: var(--radius-pill);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caption);
  background: var(--surface-secondary);
  color: var(--text-secondary);
  white-space: nowrap;
}

.ds-badge svg { inline-size: 0.875rem; block-size: 0.875rem; flex: none; }

.ds-badge--success { background: var(--success-tint); color: var(--success); }
.ds-badge--warning { background: var(--warning-tint); color: var(--warning-on-tint); }
.ds-badge--error   { background: var(--error-tint);   color: var(--error); }
.ds-badge--info    { background: var(--info-tint);    color: var(--info); }
.ds-badge--primary { background: var(--primary-tint); color: var(--primary-on-tint); }

.ds-alert {
  display: flex;
  gap: var(--space-4);
  padding: var(--space-5);
  border-radius: var(--radius-md);
  background: var(--info-tint);
  color: var(--text-primary);
  border-inline-start: 3px solid var(--info);
}

.ds-alert__icon { flex: none; inline-size: 1.25rem; block-size: 1.25rem; color: var(--info); margin-block-start: 0.15rem; }
.ds-alert__title { font-weight: var(--fw-semibold); margin: 0 0 var(--space-1); font-family: var(--font-body); font-size: var(--fs-ui); }
.ds-alert__body { font-size: var(--fs-sm); color: var(--text-secondary); margin: 0; }

.ds-alert--success { background: var(--success-tint); border-color: var(--success); }
.ds-alert--success .ds-alert__icon { color: var(--success); }
.ds-alert--warning { background: var(--warning-tint); border-color: var(--warning); }
.ds-alert--warning .ds-alert__icon { color: var(--warning); }
.ds-alert--error   { background: var(--error-tint);   border-color: var(--error); }
.ds-alert--error .ds-alert__icon { color: var(--error); }

/* Urgent-symptom guidance in booking. Deliberately the loudest surface in
   the product, and the only one that uses a filled error background. */
.ds-alert--urgent {
  background: var(--error);
  color: #fff;
  border: none;
  border-radius: var(--radius-md);
}
.ds-alert--urgent .ds-alert__icon,
.ds-alert--urgent .ds-alert__body { color: #fff; }
.ds-alert--urgent .ds-alert__body { opacity: 0.92; }

/* ==========================================================================
   10  progress
   ========================================================================== */

/* --- stepper ------------------------------------------------------------
   On a phone this collapses to "Step 3 of 10" plus a bar; the full dot rail
   only appears when there is width for it.                                */

.ds-stepper { display: flex; flex-direction: column; gap: var(--space-3); }

.ds-stepper__meta {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: var(--space-4);
  font-size: var(--fs-sm);
}

.ds-stepper__count { font-weight: var(--fw-semibold); color: var(--text-primary); }
.ds-stepper__label { color: var(--text-secondary); }

.ds-stepper__track {
  block-size: 4px;
  border-radius: var(--radius-pill);
  background: var(--surface-tertiary);
  overflow: hidden;
}

.ds-stepper__fill {
  block-size: 100%;
  border-radius: var(--radius-pill);
  background: var(--primary);
  transition: inline-size var(--dur-slow) var(--ease-out);
}

.ds-stepper__dots { display: none; }

@media (min-width: 48rem) {
  .ds-stepper__dots {
    display: flex;
    align-items: center;
    gap: var(--space-2);
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .ds-stepper__dot {
    flex: 1;
    block-size: 4px;
    border-radius: var(--radius-pill);
    background: var(--surface-tertiary);
    transition: background-color var(--dur-base) var(--ease-out);
  }
  .ds-stepper__dot[data-state="done"],
  .ds-stepper__dot[data-state="current"] { background: var(--primary); }
  .ds-stepper__dot[data-state="current"] { box-shadow: 0 0 0 3px var(--primary-tint); }
  .ds-stepper__track { display: none; }
}

/* --- progress bar (pre-visit, treatment plan) --------------------------- */

.ds-progress { display: flex; flex-direction: column; gap: var(--space-2); }

.ds-progress__meta {
  display: flex;
  justify-content: space-between;
  gap: var(--space-4);
  font-size: var(--fs-sm);
  color: var(--text-secondary);
}

.ds-progress__track {
  block-size: 8px;
  border-radius: var(--radius-pill);
  background: var(--surface-tertiary);
  overflow: hidden;
}

.ds-progress__fill {
  block-size: 100%;
  background: var(--primary);
  border-radius: var(--radius-pill);
  transition: inline-size var(--dur-slow) var(--ease-out);
}

/* --- task checklist ----------------------------------------------------- */

.ds-tasks { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }

.ds-task {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-4);
  background: var(--surface);
  border-radius: var(--radius-md);
  text-decoration: none;
  color: inherit;
  transition: background-color var(--dur-fast) var(--ease-out);
}

.ds-task:hover { background: var(--accent-blush); }

.ds-task__state {
  flex: none;
  inline-size: 1.5rem;
  block-size: 1.5rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  border: 1.5px solid var(--border-strong);
  background: var(--surface);
}

.ds-task[data-state="done"] .ds-task__state {
  background: var(--success);
  border-color: var(--success);
  color: #fff;
}

.ds-task[data-state="attention"] .ds-task__state {
  background: var(--warning-tint);
  border-color: var(--warning);
  color: var(--warning);
}

.ds-task__label { flex: 1; font-size: var(--fs-ui); font-weight: var(--fw-medium); }
.ds-task__state svg { inline-size: 0.875rem; block-size: 0.875rem; }

/* --- timeline (treatment plan stages) ----------------------------------- */

.ds-timeline { list-style: none; margin: 0; padding: 0; }

.ds-timeline__item {
  position: relative;
  display: flex;
  gap: var(--space-5);
  padding-block-end: var(--space-8);
}

.ds-timeline__item:last-child { padding-block-end: 0; }

/* Connector line between markers. */
.ds-timeline__item:not(:last-child)::before {
  content: "";
  position: absolute;
  inset-block-start: 2rem;
  inset-block-end: 0;
  inset-inline-start: 0.9375rem;
  inline-size: 2px;
  background: var(--border);
}

.ds-timeline__item[data-state="done"]:not(:last-child)::before { background: var(--success); }

.ds-timeline__marker {
  position: relative;
  z-index: 1;
  flex: none;
  inline-size: 2rem;
  block-size: 2rem;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--surface);
  border: 2px solid var(--border-strong);
  color: var(--text-tertiary);
  font-size: var(--fs-caption);
  font-weight: var(--fw-bold);
}

.ds-timeline__item[data-state="done"] .ds-timeline__marker {
  background: var(--success);
  border-color: var(--success);
  color: #fff;
}

.ds-timeline__item[data-state="current"] .ds-timeline__marker {
  background: var(--primary);
  border-color: var(--primary);
  color: #fff;
  box-shadow: 0 0 0 4px var(--primary-tint);
}

.ds-timeline__body { flex: 1; min-inline-size: 0; padding-block-start: 0.125rem; }
.ds-timeline__title { font-family: var(--font-display); font-size: var(--fs-h4); margin: 0 0 var(--space-1); }
.ds-timeline__meta { font-size: var(--fs-caption); color: var(--text-tertiary); margin-block-end: var(--space-2); }
.ds-timeline__desc { font-size: var(--fs-sm); color: var(--text-secondary); margin: 0; }

/* ==========================================================================
   11  booking: calendar, time slots, upload
   ========================================================================== */

.ds-calendar {
  background: var(--surface);
  border-radius: var(--radius-lg);
  padding: var(--space-5);
}

.ds-calendar__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  margin-block-end: var(--space-4);
}

.ds-calendar__month {
  font-family: var(--font-display);
  font-size: var(--fs-h4);
  margin: 0;
}

.ds-calendar__nav {
  inline-size: var(--touch-min);
  block-size: var(--touch-min);
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text-primary);
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out);
}

.ds-calendar__nav:hover:not([disabled]) { background: var(--accent-blush); }
.ds-calendar__nav[disabled] { opacity: 0.35; cursor: not-allowed; }

.ds-calendar__grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: var(--space-1);
}

.ds-calendar__dow {
  text-align: center;
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  color: var(--text-tertiary);
  padding-block: var(--space-2);
}

.ds-calendar__day {
  aspect-ratio: 1;
  min-block-size: 2.5rem;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--fs-ui);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  display: grid;
  place-items: center;
  position: relative;
  transition: background-color var(--dur-fast) var(--ease-out);
}

.ds-calendar__day:hover:not([disabled]) { background: var(--accent-blush); }

.ds-calendar__day[aria-pressed="true"] {
  background: var(--primary);
  color: var(--text-on-primary);
  font-weight: var(--fw-semibold);
}

.ds-calendar__day[disabled] { color: var(--text-tertiary); opacity: 0.4; cursor: not-allowed; }

/* Availability dot — paired with the aria-label, never the only signal. */
.ds-calendar__day[data-available="true"]:not([aria-pressed="true"])::after {
  content: "";
  position: absolute;
  inset-block-end: 0.3125rem;
  inline-size: 4px;
  block-size: 4px;
  border-radius: 50%;
  background: var(--primary);
}

.ds-calendar__day[data-today="true"] { box-shadow: inset 0 0 0 1.5px var(--border-strong); }

/* --- time slots --------------------------------------------------------- */

.ds-slots {
  display: grid;
  gap: var(--space-2);
  grid-template-columns: repeat(auto-fill, minmax(5.5rem, 1fr));
}

.ds-slot {
  min-block-size: var(--touch-min);
  padding: var(--space-3);
  border: 1px solid var(--border-strong);
  border-radius: var(--radius-md);
  background: var(--surface);
  color: var(--text-primary);
  font-family: var(--font-body);
  font-size: var(--fs-ui);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  transition: background-color var(--dur-fast) var(--ease-out),
              border-color var(--dur-fast) var(--ease-out);
}

.ds-slot:hover:not([disabled]) { border-color: var(--primary); color: var(--primary-on-tint); }

.ds-slot[aria-pressed="true"] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--text-on-primary);
  font-weight: var(--fw-semibold);
}

.ds-slot[disabled] {
  opacity: 0.4;
  cursor: not-allowed;
  text-decoration: line-through;
}

.ds-slots__group-label {
  grid-column: 1 / -1;
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-caption);
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin-block-start: var(--space-3);
}

/* --- file upload --------------------------------------------------------- */

.ds-upload {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-10) var(--space-6);
  border: 1.5px dashed var(--border-strong);
  border-radius: var(--radius-lg);
  background: var(--surface);
  text-align: center;
  cursor: pointer;
  transition: border-color var(--dur-fast) var(--ease-out),
              background-color var(--dur-fast) var(--ease-out);
}

.ds-upload:hover,
.ds-upload[data-dragover="true"] { border-color: var(--primary); background: var(--primary-tint); }
.ds-upload input[type="file"] { position: absolute; opacity: 0; pointer-events: none; }
.ds-upload__icon { inline-size: 2rem; block-size: 2rem; color: var(--primary); }
.ds-upload__title { font-weight: var(--fw-semibold); font-size: var(--fs-ui); }
.ds-upload__hint { font-size: var(--fs-sm); color: var(--text-secondary); }

.ds-upload__list { list-style: none; margin: var(--space-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); }

/* ==========================================================================
   12  overlays
   ========================================================================== */

.ds-modal {
  border: none;
  padding: 0;
  background: transparent;
  max-inline-size: min(34rem, calc(100vw - 2 * var(--gutter)));
  inline-size: 100%;
  margin: auto;
}

.ds-modal::backdrop {
  background: rgba(33, 28, 25, 0.45);
  backdrop-filter: blur(2px);
}

.ds-modal__panel {
  background: var(--surface);
  border-radius: var(--radius-xl);
  padding: var(--space-8);
  box-shadow: var(--shadow-lg);
}

.ds-modal__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: var(--space-4);
  margin-block-end: var(--space-4);
}

.ds-modal__title { font-size: var(--fs-h3); margin: 0; }

.ds-modal__close {
  flex: none;
  inline-size: var(--touch-min);
  block-size: var(--touch-min);
  border: none;
  border-radius: 50%;
  background: var(--surface-secondary);
  color: var(--text-primary);
  cursor: pointer;
  display: grid;
  place-items: center;
  transition: background-color var(--dur-fast) var(--ease-out);
}

.ds-modal__close:hover { background: var(--surface-tertiary); }
.ds-modal__actions { display: flex; flex-wrap: wrap; gap: var(--space-3); margin-block-start: var(--space-6); }

/* On a phone a centred dialog fights the thumb; it becomes a bottom sheet. */
@media (max-width: 47.99rem) {
  .ds-modal {
    max-inline-size: 100%;
    margin: auto 0 0;
    inline-size: 100%;
  }
  .ds-modal__panel {
    border-start-start-radius: var(--radius-xl);
    border-start-end-radius: var(--radius-xl);
    border-end-start-radius: 0;
    border-end-end-radius: 0;
    padding: var(--space-6) var(--gutter) calc(var(--space-8) + env(safe-area-inset-bottom));
    box-shadow: var(--shadow-sheet);
  }
  /* Grab handle, so the sheet reads as a sheet. */
  .ds-modal__panel::before {
    content: "";
    display: block;
    inline-size: 2.5rem;
    block-size: 4px;
    border-radius: var(--radius-pill);
    background: var(--surface-tertiary);
    margin: 0 auto var(--space-5);
  }
}

/* --- toast --------------------------------------------------------------- */

.ds-toast-region {
  position: fixed;
  inset-block-end: calc(var(--space-6) + env(safe-area-inset-bottom));
  inset-inline: var(--gutter);
  z-index: 90;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  pointer-events: none;
}

@media (min-width: 48rem) {
  .ds-toast-region { inset-inline: auto var(--space-8); max-inline-size: 24rem; }
}

.ds-toast {
  pointer-events: auto;
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4) var(--space-5);
  background: var(--surface-inverse);
  color: var(--text-inverse);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  font-size: var(--fs-ui);
  animation: ds-toast-in var(--dur-base) var(--ease-entry);
}

@keyframes ds-toast-in {
  from { opacity: 0; transform: translateY(0.5rem); }
  to   { opacity: 1; transform: none; }
}

/* ==========================================================================
   13  states

   Every flow in the product needs these. Kept as components rather than
   one-offs so an empty Documents page and an empty Appointments page look
   like the same product.
   ========================================================================== */

.ds-state {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  gap: var(--space-4);
  padding: var(--space-16) var(--space-6);
  background: var(--surface);
  border-radius: var(--radius-lg);
}

.ds-state__art {
  inline-size: 4.5rem;
  block-size: 4.5rem;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--accent-blush);
  color: var(--primary-on-tint);
}

.ds-state__title { font-size: var(--fs-h3); margin: 0; }
.ds-state__body { font-size: var(--fs-ui); color: var(--text-secondary); max-inline-size: 40ch; margin: 0; }

.ds-state--success .ds-state__art { background: var(--success-tint); color: var(--success); }

/* Success screen after booking — celebratory but calm. */
.ds-success {
  text-align: center;
  padding-block: var(--space-16);
}

.ds-success__mark {
  inline-size: 5rem;
  block-size: 5rem;
  margin: 0 auto var(--space-6);
  border-radius: 50%;
  background: var(--success-tint);
  color: var(--success);
  display: grid;
  place-items: center;
  animation: ds-pop var(--dur-slow) var(--ease-entry);
}

@keyframes ds-pop {
  from { transform: scale(0.85); opacity: 0; }
  to   { transform: none; opacity: 1; }
}

/* --- skeleton ------------------------------------------------------------ */

.ds-skeleton {
  background: linear-gradient(90deg,
    var(--surface-secondary) 25%,
    var(--surface-tertiary) 37%,
    var(--surface-secondary) 63%);
  background-size: 400% 100%;
  border-radius: var(--radius-sm);
  animation: ds-shimmer 1.4s ease-in-out infinite;
}

@keyframes ds-shimmer {
  from { background-position: 100% 0; }
  to   { background-position: 0 0; }
}

@media (prefers-reduced-motion: reduce) {
  .ds-skeleton { animation: none; background: var(--surface-secondary); }
}

/* ==========================================================================
   14  navigation
   ========================================================================== */

.ds-header {
  position: sticky;
  inset-block-start: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--background) 88%, transparent);
  backdrop-filter: saturate(1.4) blur(12px);
  border-block-end: 1px solid transparent;
  transition: border-color var(--dur-base) var(--ease-out),
              background-color var(--dur-base) var(--ease-out);
}

.ds-header[data-scrolled="true"] { border-block-end-color: var(--border); }

.ds-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  min-block-size: var(--header-h);
}

.ds-logo {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-family: var(--font-display);
  font-size: 1.375rem;
  font-weight: var(--fw-display);
  color: var(--primary-on-tint);
  text-decoration: none;
  letter-spacing: -0.02em;
  flex: none;
}

.ds-logo__mark { inline-size: 1.75rem; block-size: 1.75rem; }

/* Desktop nav is hidden until there is genuinely room for it. */
.ds-nav { display: none; }

.ds-header__actions { display: flex; align-items: center; gap: var(--space-2); }

.ds-header__login { display: none; }

.ds-menu-btn {
  inline-size: var(--touch-min);
  block-size: var(--touch-min);
  border: 1px solid var(--border-strong);
  border-radius: 50%;
  background: transparent;
  color: var(--text-primary);
  display: grid;
  place-items: center;
  cursor: pointer;
}

@media (min-width: 64rem) {
  .ds-nav {
    display: flex;
    align-items: center;
    gap: var(--space-1);
    list-style: none;
    margin: 0;
    padding: 0;
  }
  .ds-header__login { display: inline-flex; }
  .ds-menu-btn { display: none; }
}

.ds-nav__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-pill);
  font-size: var(--fs-ui);
  font-weight: var(--fw-medium);
  color: var(--text-primary);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.ds-nav__link:hover { background: var(--accent-blush); }
.ds-nav__link[aria-current="page"] { color: var(--primary); font-weight: var(--fw-semibold); }

/* --- dropdown ------------------------------------------------------------ */

.ds-nav__item { position: relative; }

.ds-nav__panel {
  position: absolute;
  inset-block-start: calc(100% + var(--space-2));
  inset-inline-start: 0;
  min-inline-size: 16rem;
  background: var(--surface);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-md);
  padding: var(--space-3);
  list-style: none;
  margin: 0;
  opacity: 0;
  visibility: hidden;
  transform: translateY(-0.25rem);
  transition: opacity var(--dur-fast) var(--ease-out),
              transform var(--dur-fast) var(--ease-out),
              visibility var(--dur-fast);
}

.ds-nav__item:hover .ds-nav__panel,
.ds-nav__item:focus-within .ds-nav__panel,
.ds-nav__panel[data-open="true"] {
  opacity: 1;
  visibility: visible;
  transform: none;
}

.ds-nav__panel a {
  display: flex;
  align-items: center;
  /* Was 42px from padding alone, which is under the 44px target. */
  min-block-size: var(--touch-min);
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  font-size: var(--fs-ui);
  color: var(--text-primary);
  text-decoration: none;
  transition: background-color var(--dur-fast) var(--ease-out);
}

.ds-nav__panel a:hover { background: var(--accent-blush); color: var(--primary-on-tint); }

/* --- mobile drawer ------------------------------------------------------- */

.ds-drawer {
  position: fixed;
  inset: 0;
  z-index: 100;
  background: var(--background);
  display: flex;
  flex-direction: column;
  padding: var(--gutter);
  padding-block-end: calc(var(--gutter) + env(safe-area-inset-bottom));
  overflow-y: auto;
  transform: translateX(100%);
  visibility: hidden;
  transition: transform var(--dur-base) var(--ease-out), visibility var(--dur-base);
}

:root[dir="rtl"] .ds-drawer { transform: translateX(-100%); }

.ds-drawer[data-open="true"] { transform: none; visibility: visible; }

.ds-drawer__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-block-size: var(--header-h);
  margin-block-end: var(--space-4);
}

.ds-drawer__nav { list-style: none; margin: 0; padding: 0; flex: 1; }

.ds-drawer__link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  min-block-size: 3.25rem;
  padding-block: var(--space-3);
  border-block-end: 1px solid var(--border);
  font-family: var(--font-display);
  font-size: 1.5rem;
  color: var(--text-primary);
  text-decoration: none;
}

.ds-drawer__link[aria-current="page"] { color: var(--primary); }
.ds-drawer__sub { list-style: none; margin: 0 0 var(--space-3); padding: 0; }
.ds-drawer__sub a {
  display: block;
  padding: var(--space-2) 0 var(--space-2) var(--space-4);
  font-size: var(--fs-ui);
  color: var(--text-secondary);
  text-decoration: none;
}
.ds-drawer__foot { display: flex; flex-direction: column; gap: var(--space-3); margin-block-start: var(--space-8); }

/* --- sticky mobile CTA ---------------------------------------------------
   Book is never more than a thumb away on a phone.                        */

.ds-sticky-cta {
  position: fixed;
  inset-block-end: 0;
  inset-inline: 0;
  z-index: 45;
  padding: var(--space-3) var(--gutter) calc(var(--space-3) + env(safe-area-inset-bottom));
  background: color-mix(in srgb, var(--background) 92%, transparent);
  backdrop-filter: blur(12px);
  border-block-start: 1px solid var(--border);
  display: flex;
  gap: var(--space-3);
}

@media (min-width: 64rem) { .ds-sticky-cta { display: none; } }

body:has(.ds-sticky-cta) { padding-block-end: 5.5rem; }
@media (min-width: 64rem) { body:has(.ds-sticky-cta) { padding-block-end: 0; } }

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

.ds-footer {
  background: var(--surface-inverse);
  color: var(--text-inverse-muted);
  padding-block: var(--section-y) var(--space-8);
}

.ds-footer h2,
.ds-footer h3 { color: var(--text-inverse); }

.ds-footer__grid {
  display: grid;
  gap: var(--space-10);
  grid-template-columns: 1fr;
}

@media (min-width: 48rem) {
  .ds-footer__grid { grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: var(--space-8); }
}

.ds-footer__title {
  font-family: var(--font-body);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-inverse);
  margin-block-end: var(--space-4);
}

.ds-footer__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-3); }

.ds-footer__list a {
  color: var(--text-inverse-muted);
  text-decoration: none;
  font-size: var(--fs-ui);
  transition: color var(--dur-fast) var(--ease-out);
}

.ds-footer__list a:hover { color: var(--text-inverse); }

.ds-footer__bottom {
  margin-block-start: var(--space-12);
  padding-block-start: var(--space-6);
  border-block-start: 1px solid var(--border-inverse);
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4);
  justify-content: space-between;
  font-size: var(--fs-caption);
}

/* ==========================================================================
   15  portal

   Same tokens, same components, same voice as the public site — simply
   denser. Deliberately not a SaaS sidebar.
   ========================================================================== */

.ds-portal { display: block; }

.ds-portal__body {
  display: grid;
  gap: var(--space-8);
  padding-block: var(--space-8);
}

@media (min-width: 64rem) {
  .ds-portal__body {
    grid-template-columns: 15rem 1fr;
    gap: var(--space-16);
    padding-block: var(--space-12);
  }
}

.ds-rail { display: none; }

@media (min-width: 64rem) {
  .ds-rail {
    display: block;
    position: sticky;
    inset-block-start: calc(var(--header-h) + var(--space-8));
    align-self: start;
  }
}

.ds-rail__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-1); }

.ds-rail__link {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border-radius: var(--radius-md);
  color: var(--text-secondary);
  text-decoration: none;
  font-size: var(--fs-ui);
  font-weight: var(--fw-medium);
  transition: background-color var(--dur-fast) var(--ease-out),
              color var(--dur-fast) var(--ease-out);
}

.ds-rail__link svg { flex: none; inline-size: 1.125rem; block-size: 1.125rem; }
.ds-rail__link:hover { background: var(--accent-blush); color: var(--text-primary); }

.ds-rail__link[aria-current="page"] {
  background: var(--primary-tint);
  color: var(--primary-on-tint);
  font-weight: var(--fw-semibold);
}

/* Mobile: four destinations in a bottom bar, the rest under "More". */
.ds-tabbar {
  position: fixed;
  inset-block-end: 0;
  inset-inline: 0;
  z-index: 45;
  display: flex;
  background: color-mix(in srgb, var(--surface) 94%, transparent);
  backdrop-filter: blur(12px);
  border-block-start: 1px solid var(--border);
  padding-block-end: env(safe-area-inset-bottom);
}

@media (min-width: 64rem) { .ds-tabbar { display: none; } }

.ds-tabbar__link {
  flex: 1;
  min-block-size: var(--tabbar-h);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.25rem;
  padding-block: var(--space-2);
  color: var(--text-tertiary);
  text-decoration: none;
  font-size: 0.6875rem;
  font-weight: var(--fw-medium);
}

.ds-tabbar__link svg { inline-size: 1.375rem; block-size: 1.375rem; }
.ds-tabbar__link[aria-current="page"] { color: var(--primary); }

body:has(.ds-tabbar) { padding-block-end: calc(var(--tabbar-h) + 1rem); }
@media (min-width: 64rem) { body:has(.ds-tabbar) { padding-block-end: 0; } }

/* Portal page header */
.ds-portal__greeting {
  font-family: var(--font-display);
  font-size: var(--fs-h1);
  color: var(--text-primary);
  margin: 0 0 var(--space-2);
}

.ds-portal__section-title {
  font-family: var(--font-body);
  font-size: var(--fs-caption);
  font-weight: var(--fw-semibold);
  letter-spacing: var(--ls-eyebrow);
  text-transform: uppercase;
  color: var(--text-tertiary);
  margin-block-end: var(--space-4);
}

/* ==========================================================================
   16  motion + reveal

   One reveal utility for the whole site, driven by IntersectionObserver in
   js/ds/reveal.js. Elements are visible by default and only hidden once the
   script confirms it will animate them, so nothing is invisible if the
   script fails or is blocked.
   ========================================================================== */

[data-reveal] { will-change: opacity, transform; }

html[data-reveal-ready="true"] [data-reveal] {
  opacity: 0;
  transform: translateY(1rem);
  transition: opacity var(--dur-reveal) var(--ease-entry),
              transform var(--dur-reveal) var(--ease-entry);
  transition-delay: var(--reveal-delay, 0ms);
}

html[data-reveal-ready="true"] [data-reveal][data-revealed="true"] {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  html[data-reveal-ready="true"] [data-reveal] {
    opacity: 1;
    transform: none;
    transition: none;
  }
}

/* ==========================================================================
   17  accessibility utilities
   ========================================================================== */

.ds-visually-hidden {
  position: absolute !important;
  inline-size: 1px;
  block-size: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
}

/* Skip link — visible the moment it takes focus. */
.ds-skip {
  position: absolute;
  inset-block-start: -100%;
  inset-inline-start: var(--gutter);
  z-index: 200;
  padding: var(--space-3) var(--space-5);
  background: var(--primary);
  color: var(--text-on-primary);
  border-radius: 0 0 var(--radius-md) var(--radius-md);
  font-weight: var(--fw-semibold);
  text-decoration: none;
}

.ds-skip:focus { inset-block-start: 0; }

/* Anchored sections must clear the sticky header when jumped to. */
[id] { scroll-margin-block-start: calc(var(--header-h) + var(--space-6)); }

/* ==========================================================================
   18  RTL corrections

   Logical properties handle the layout. These are the few things they
   cannot express: glyphs that must physically mirror, and numerals that
   must not.
   ========================================================================== */

:root[dir="rtl"] .ds-btn__arrow,
:root[dir="rtl"] .ds-treatment__arrow,
:root[dir="rtl"] .ds-nav__chevron { transform: scaleX(-1); }

/* Times, prices, dates and phone numbers stay left-to-right inside Arabic
   copy, which is how they are actually written. */
:root[dir="rtl"] :is(.ds-slot, .ds-calendar__day, .ds-fee__price, .ds-stat__value, time, .ds-appt__when) {
  direction: ltr;
  unicode-bidi: isolate;
}

/* The drawer slides from the inline-end edge in both directions. */
:root[dir="rtl"] .ds-drawer { inset-inline-start: 0; }

/* Cards rendered by js/portal.js sit directly under the page h1, so their
   titles are h2 to avoid skipping a heading level. Visually they are still
   card-scale headings, not section headings. */
.ds-card > h2,
.ds-quote > h2 {
  font-size: var(--fs-h3);
}
