/* ========================================================================
   CALLIA · Espace Patient · Design System
   Harmonized with callia.ai — mint primary #23CCAB, near-white canvas,
   Bebas Neue for brand moments, editorial serif for warm display, clean sans body
   ======================================================================== */

:root {
  /* Ink & paper — lighter, cooler canvas that matches the marketing site */
  --ink:         #181C18;
  --ink-soft:    #2A3431;
  --ink-mute:    #6B7380;
  --ink-quiet:   #9CA3AF;
  --paper:       #FAFCFC;
  --paper-up:    #FFFFFF;
  --paper-deep:  #F5FBFA;
  --paper-mint:  #E6F5F0;
  --line:        #E5E7EB;
  --line-soft:   #F0F2F5;
  --line-loud:   #CBD5DB;

  /* Primary — Callia mint/teal (brand) */
  --primary:      #23CCAB;
  --primary-hover:#1FB59B;
  --primary-deep: #159078;
  --primary-ink:  #0E6B57;   /* text-on-wash — darker for WCAG AA (5.0:1) */
  --primary-soft: #2AC5A6;
  --primary-tint: #BAE7DB;
  --primary-wash: #E6F9F4;
  --on-primary:   #FFFFFF;   /* foreground for text/icons sitting on --primary */

  /* Red for danger / cancellation. Cool-leaning so it sits cleanly next to
     the mint primary instead of muddying into terracotta. */
  --warn:         #DC5552;
  --warn-deep:    #B4372D;
  --warn-tint:    #FBE1DF;
  --warn-wash:    #FEF4F3;

  /* Warm amber for pending / needs-attention states — distinct from the
     danger red so "à confirmer" doesn't read as "cancelled". */
  --info:         #C08A15;
  --info-deep:    #7F5A0C;
  --info-tint:    #F4DDB1;
  --info-wash:    #FCF4E3;

  /* Neutral gray for archived / transitional states. */
  --muted:        #8A92A3;
  --muted-deep:   #4F5668;   /* text-on-wash — WCAG AA (6.7:1) */
  --muted-tint:   #E9EBEF;
  --muted-wash:   #F5F6F8;

  /* Secondary blue (from site CSS, used very sparingly) */
  --blue:         #3083DC;

  /* Type — two-font system.
     · Fraunces owns every display moment: big numerals (date, stats), headlines,
       italic accents, time display, section titles. Used at light weights
       (300) for big numbers so they feel editorial, not chunky.
     · Inter Tight 600 uppercase carries every small label / eyebrow / status
       chip for legibility. */
  --font-display: 'Fraunces', 'Times New Roman', Georgia, serif;
  --font-body:    'Inter Tight', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-mono:    'JetBrains Mono', 'SF Mono', ui-monospace, monospace;

  /* Radii */
  --r-xs: 4px;
  --r-sm: 8px;
  --r-md: 14px;
  --r-lg: 22px;
  --r-xl: 32px;

  /* Shadows — used sparingly */
  --lift-sm:  0 1px 0 rgba(24,28,24,0.03), 0 2px 10px -4px rgba(24,28,24,0.06);
  --lift:     0 1px 0 rgba(24,28,24,0.04), 0 10px 32px -14px rgba(24,28,24,0.10);
  --lift-lg:  0 1px 0 rgba(24,28,24,0.05), 0 24px 60px -24px rgba(24,28,24,0.16);
  --lift-mint: 0 1px 0 color-mix(in oklab, var(--primary) 10%, transparent), 0 12px 36px -16px color-mix(in oklab, var(--primary) 28%, transparent);

  /* Motion */
  --ease: cubic-bezier(0.2, 0.7, 0.2, 1);
  --ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);

  /* Layout */
  --pad: clamp(20px, 5vw, 40px);
  --content-max: 720px;
  --content-max-wide: 980px;
}

/* ==========================================================================
   Reset / base
   ========================================================================== */

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

html {
  -webkit-text-size-adjust: 100%;
  -moz-text-size-adjust: 100%;
  text-size-adjust: 100%;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100svh;
  background: var(--paper);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.55;
  font-feature-settings: "ss01", "cv11";
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  text-rendering: optimizeLegibility;
  position: relative;
  overflow-x: hidden;
}

/* Grain overlay — fixed, non-interactive */
/* Subtle ambient grain — much lighter than v1, keeps things from feeling
   sterile without adding warmth that conflicts with the clean brand. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 1000;
  opacity: 0.35;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='220' height='220'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 0.09  0 0 0 0 0.11  0 0 0 0 0.10  0 0 0 0.03 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}

img, svg { max-width: 100%; display: block; }

button {
  font: inherit;
  color: inherit;
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  -webkit-tap-highlight-color: transparent;
}

input, button, select, textarea { font-family: inherit; }

a {
  color: var(--ink);
  text-decoration: none;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  text-decoration-color: var(--line-loud);
  transition: text-decoration-color 200ms var(--ease), color 200ms var(--ease);
}
a:hover { text-decoration-color: var(--primary-deep); }

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

/* Keyboard focus ring — brand-colored, applied to every focusable element.
   Outline follows the element's own border-radius in modern browsers, so we
   don't override the element shape here. */
:focus-visible {
  outline: 2px solid var(--primary-deep);
  outline-offset: 3px;
}

/* ==========================================================================
   Typography scale
   ========================================================================== */

.t-eyebrow {
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-mute);
  line-height: 1;
}

.t-display {
  font-family: var(--font-display);
  font-weight: 400;
  font-variation-settings: "opsz" 144, "SOFT" 30;
  letter-spacing: -0.02em;
  line-height: 1;
  color: var(--ink);
}

.t-serif {
  font-family: var(--font-display);
  font-weight: 400;
  font-variation-settings: "opsz" 24, "SOFT" 20;
  letter-spacing: -0.01em;
}

.num {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum", "ss01";
}

/* ==========================================================================
   Shared · page shell
   ========================================================================== */

.page {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
  min-height: 100svh;
  padding: 0 var(--pad);
}

.page > main { flex: 1; }

/* ==========================================================================
   Login page
   ========================================================================== */

.login {
  min-height: 100vh;
  min-height: 100svh;
  display: grid;
  grid-template-columns: minmax(0, 1fr);  /* prevents auto columns from expanding past the viewport */
  grid-template-rows: auto 1fr auto;
  padding: 20px var(--pad);
  position: relative;
  /* Clip horizontally so the decorative orb doesn't cause horizontal scroll,
     but leave the vertical axis visible so the page scrolls normally when
     the viewport is shorter than the content (e.g. landscape phones, small
     laptop windows). */
  overflow-x: clip;
}

/* decorative mark behind hero — sized relative to the viewport so it never
   becomes heavier than the content. clamp keeps it prominent on desktop
   and subtle on mobile where horizontal real-estate is scarce. */
.login::after {
  content: "";
  position: absolute;
  top: -120px;
  right: clamp(-200px, -18vw, -80px);
  width: clamp(280px, 48vw, 520px);
  height: clamp(280px, 48vw, 520px);
  background: radial-gradient(closest-side, color-mix(in oklab, var(--primary) 22%, transparent), transparent 70%);
  z-index: 0;
  pointer-events: none;
  filter: blur(8px);
}

.login-top {
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px 16px;
  position: relative;
  z-index: 1;
  padding-top: 8px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 0;
  color: var(--ink);
  text-decoration: none;
  line-height: 0;
}
.brand-logo {
  height: 30px;
  width: auto;
  color: var(--ink);
  transition: opacity 180ms var(--ease);
  display: block;
}
.brand:hover .brand-logo { opacity: 0.8; }
.brand-mark-svg {
  height: 28px;
  width: auto;
  color: var(--ink);
  flex-shrink: 0;
}
/* Legacy fallback kept in case .brand-mark is still referenced somewhere */
.brand-mark {
  width: 28px;
  height: 28px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  background: var(--ink);
  color: var(--paper-up);
  font-family: var(--font-display);
  font-size: 14px;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0;
  padding-bottom: 1px;
}

.login-help {
  font-size: 13px;
  color: var(--ink-mute);
  margin: 0;
  /* Prevents the help sentence from forcing a horizontal overflow on narrow
     screens. The surrounding `flex-wrap` lets it drop under the logo if the
     row is too tight. */
  min-width: 0;
}
.login-help a { color: var(--ink-soft); }

/* Hide the help line on phones — the brand link + email address don't fit
   alongside the CALLIA logo. The same info is reachable from the footer
   contact link. */
@media (max-width: 520px) {
  .login-help { display: none; }
}

.login-hero {
  /* Grid items default to justify-self: stretch which overrides max-width
     in some engines; justify-self: center lets max-width cap the width and
     margin:auto centers the box inside its column. */
  justify-self: center;
  align-self: center;
  width: 100%;
  max-width: 440px;
  min-width: 0;
  padding: clamp(24px, 6vh, 56px) 0 clamp(24px, 4vh, 40px);
  position: relative;
  z-index: 1;
}

.login-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 7px 12px 6px 10px;
  background: var(--paper-up);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--ink-soft);
  font-weight: 600;
  line-height: 1;
  margin-bottom: 28px;
}
.login-eyebrow .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--primary-deep);
  box-shadow: 0 0 0 3px var(--primary-wash);
  animation: livePulse 2.6s var(--ease-in-out) infinite;
}
@keyframes livePulse {
  0%, 100% { box-shadow: 0 0 0 3px var(--primary-wash); }
  50% { box-shadow: 0 0 0 5px transparent; }
}

.login-title {
  font-family: var(--font-display);
  font-weight: 300;
  font-variation-settings: "opsz" 144, "SOFT" 40;
  /* Lower min (32px) so "Votre rendez-vous" fits inside 320px content width
     on a 360px viewport. 9vw scales fluidly up to the 54px cap. */
  font-size: clamp(32px, 9vw, 54px);
  line-height: 1.04;
  letter-spacing: -0.025em;
  margin: 0 0 16px;
  color: var(--ink);
  /* Allow graceful wrapping on rare narrow cases. */
  overflow-wrap: break-word;
}
.login-title em {
  font-style: italic;
  font-weight: 300;
  color: var(--primary-deep);
}

.login-sub {
  font-size: 15px;
  color: var(--ink-mute);
  margin: 0 0 32px;
  line-height: 1.55;
  max-width: 400px;
}

/* DOB code entry */
.dob {
  display: flex;
  align-items: flex-end;
  gap: 10px;
  padding: 14px;
  background: var(--paper-up);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  box-shadow: var(--lift-sm);
  transition: border-color 220ms var(--ease), box-shadow 220ms var(--ease), transform 220ms var(--ease);
  min-width: 0;   /* never let the native input sizes push the hero wider than its column */
}
.dob:focus-within {
  border-color: var(--primary-deep);
  box-shadow: 0 0 0 4px var(--primary-wash), var(--lift-sm);
}
.dob.is-error {
  border-color: var(--warn);
  box-shadow: 0 0 0 4px var(--warn-tint), var(--lift-sm);
  animation: shake 420ms var(--ease-in-out);
}
@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-6px); }
  40% { transform: translateX(5px); }
  60% { transform: translateX(-3px); }
  80% { transform: translateX(2px); }
}

.dob-field {
  flex: 1;
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.dob-field label {
  font-size: 10px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--ink-mute);       /* lifted from --ink-quiet (2.47:1) for WCAG AA */
  font-weight: 500;
  padding-left: 2px;
}
.dob-field input {
  border: 0;
  background: transparent;
  font-family: var(--font-display);
  font-variation-settings: "opsz" 48, "SOFT" 30;
  font-weight: 400;
  font-size: 28px;
  line-height: 1;
  letter-spacing: -0.01em;
  color: var(--ink);
  padding: 2px;
  min-width: 0;
  width: 100%;
  text-align: left;
  font-variant-numeric: tabular-nums;
}
.dob-field input::placeholder {
  color: var(--line-loud);
  font-weight: 300;
}
.dob-field input:focus { outline: none; }
.dob-field.year { flex: 1.6; }

.dob-sep {
  font-family: var(--font-display);
  font-size: 28px;
  color: var(--line-loud);
  padding-bottom: 2px;
  font-weight: 300;
  user-select: none;
}

.login-meta {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  margin: 16px 2px 0;
  font-size: 13px;
  color: var(--ink-mute);
  line-height: 1.5;
}
.login-meta svg { flex-shrink: 0; margin-top: 3px; }
.login-meta strong { color: var(--ink-soft); font-weight: 500; white-space: nowrap; }
.login-meta span { min-width: 0; }

.login-error {
  display: none;
  margin-top: 14px;
  padding: 10px 14px;
  background: var(--warn-wash);
  border: 1px solid var(--warn-tint);
  border-radius: var(--r-sm);
  font-size: 13px;
  color: var(--warn-deep);
}
.login-error.is-visible { display: block; }

.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 16px 22px;
  background: var(--primary);
  color: var(--on-primary);
  /* Layered text-shadow to increase perceived contrast of white-on-mint.
     Automated WCAG doesn't credit text-shadow, so this passes the
     human-readability bar while the calculated ratio remains 2.04:1 — a
     documented trade-off to preserve the brand's bright teal CTA. */
  text-shadow:
    0 1px 1px color-mix(in oklab, var(--primary-ink) 65%, transparent),
    0 0 6px color-mix(in oklab, var(--primary-ink) 35%, transparent);
  border-radius: var(--r-md);
  font-weight: 600;
  font-size: 15px;
  letter-spacing: -0.005em;
  transition: background 220ms var(--ease), transform 180ms var(--ease), box-shadow 220ms var(--ease), color 220ms var(--ease);
  box-shadow: var(--lift-mint);
  width: 100%;
  min-height: 56px;
  position: relative;
  overflow: hidden;
  cursor: pointer;
}
.btn::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.4), transparent 50%);
  pointer-events: none;
  opacity: 0.6;
}
.btn:hover { background: var(--primary-hover); box-shadow: 0 1px 0 color-mix(in oklab, var(--primary) 20%, transparent), 0 16px 44px -18px color-mix(in oklab, var(--primary) 50%, transparent); }
.btn:active { transform: translateY(1px); }
.btn .arrow {
  transition: transform 220ms var(--ease);
}
.btn:hover .arrow { transform: translateX(3px); }

.btn-submit { margin-top: 24px; }

.btn-secondary {
  background: var(--paper-up);
  color: var(--ink);
  text-shadow: none;
  border: 1px solid var(--line);
}
.btn-secondary:hover {
  background: var(--paper-deep);
  border-color: var(--line-loud);
}

.login-legal {
  margin-top: 28px;
  font-size: 12px;
  color: var(--ink-mute);
  line-height: 1.5;
}
.login-legal a { color: var(--ink-mute); }

.login-foot {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: 12px;
  align-items: center;
  justify-content: space-between;
  padding: 24px 0 12px;
  border-top: 1px solid var(--line-soft);
  font-size: 12px;
  color: var(--ink-mute);
}
.login-foot a { color: var(--ink-soft); }
.login-foot-links {
  display: flex;
  gap: 18px;
  flex-wrap: wrap;
  justify-content: center;
}

.powered-by {
  display: inline-flex;
  align-items: baseline;  /* align logo to text baseline, not vertical center */
  gap: 9px;
  color: var(--ink-mute);
  font-size: 11px;
  letter-spacing: 0.02em;
  text-decoration: none;
  transition: color 200ms var(--ease);
  flex-shrink: 0;
  white-space: nowrap;
  line-height: 1;
}
.powered-by > span { white-space: nowrap; }
.powered-by:hover { color: var(--ink); }
.powered-by-logo {
  height: 13px;  /* match the "Propulsé par" caps height for optical balance */
  width: auto;
  opacity: 0.9;
  transition: opacity 200ms var(--ease);
  flex-shrink: 0;
  /* Inline-level so it participates in baseline alignment. SVG's default
     baseline is its bottom edge, which matches text descender height. */
  display: inline-block;
  vertical-align: baseline;
}
.powered-by:hover .powered-by-logo { opacity: 1; }
/* Fallback when text "Callia" is inline (the real logo is preferred) */
.powered-by strong {
  font-family: var(--font-display);
  font-weight: 500;
  color: var(--ink);
  letter-spacing: -0.01em;
  font-size: 13px;
}

/* Reveal — JS-driven soft fade-in. Default state is visible; JS only
   hides + reveals if it runs. Short, subtle, and mostly in-place. */
@keyframes reveal {
  from { opacity: 0; transform: translateY(4px); }
  to   { opacity: 1; transform: translateY(0); }
}
html.js-reveal .login-hero > * {
  animation: reveal 320ms var(--ease) both;
}
html.js-reveal .login-hero > *:nth-child(1) { animation-delay: 0ms; }
html.js-reveal .login-hero > *:nth-child(2) { animation-delay: 30ms; }
html.js-reveal .login-hero > *:nth-child(3) { animation-delay: 60ms; }
html.js-reveal .login-hero > *:nth-child(4) { animation-delay: 90ms; }
html.js-reveal .login-hero > *:nth-child(5) { animation-delay: 120ms; }

/* ==========================================================================
   Dashboard
   ========================================================================== */

.topbar {
  position: sticky;
  top: 0;
  z-index: 20;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 16px var(--pad);
  background: rgba(250, 252, 252, 0.82);
  -webkit-backdrop-filter: saturate(1.2) blur(16px);
  backdrop-filter: saturate(1.2) blur(16px);
  border-bottom: 1px solid var(--line-soft);
}
/* Logo size is intentionally the same across login and dashboard headers */
.topbar .brand-logo { height: 30px; }

.avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--primary-deep);
  color: var(--paper-up);
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  cursor: pointer;
  transition: transform 180ms var(--ease);
  position: relative;
}
.avatar:hover { transform: scale(1.04); }

.menu {
  position: absolute;
  top: calc(100% + 10px);
  right: 0;
  min-width: 220px;
  background: var(--paper-up);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  padding: 6px;
  box-shadow: var(--lift-lg);
  opacity: 0;
  transform: translateY(-6px) scale(0.98);
  pointer-events: none;
  transition: opacity 180ms var(--ease), transform 180ms var(--ease);
  z-index: 30;
}
.menu.is-open {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}
.menu-head {
  padding: 12px 12px 10px;
  border-bottom: 1px solid var(--line-soft);
  margin-bottom: 4px;
}
.menu-head .name {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  margin: 0;
  color: var(--ink);
}
.menu-head .mail {
  font-size: 12px;
  color: var(--ink-mute);
  margin: 2px 0 0;
}
.menu-item {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 10px 12px;
  border-radius: var(--r-sm);
  font-size: 14px;
  color: var(--ink-soft);
  cursor: pointer;
  width: 100%;
  text-align: left;
  transition: background 160ms var(--ease);
}
.menu-item:hover { background: var(--paper-deep); }
.menu-item svg { color: var(--ink-mute); }
.menu-item.logout { color: var(--warn); }
.menu-item.logout svg { color: var(--warn); }

/* Main */
.dash {
  max-width: calc(var(--content-max-wide) + var(--pad) * 2);
  margin: 0 auto;
  padding: 8px var(--pad) 120px;
  width: 100%;
  box-sizing: border-box;
}

.section {
  padding: clamp(32px, 5vw, 48px) 0;
  border-bottom: 1px solid var(--line-soft);
}
.section:last-of-type { border-bottom: 0; }

.section-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 8px 16px;
  margin-bottom: 20px;
  flex-wrap: wrap;
}
.section-head h2 {
  font-family: var(--font-display);
  font-weight: 400;
  font-variation-settings: "opsz" 48, "SOFT" 30;
  font-size: clamp(20px, 4vw, 28px);
  letter-spacing: -0.015em;
  margin: 0;
}
.section-head .countdown { font-size: 11px; }

.section-num {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 400;
  font-variation-settings: "opsz" 24, "SOFT" 40;
  color: var(--primary-deep);
  font-size: 18px;
  letter-spacing: -0.005em;
  margin-right: 12px;
  vertical-align: 0.04em;
}

/* Greeting */
.greet {
  padding-top: clamp(36px, 8vw, 64px);
  padding-bottom: clamp(20px, 4vw, 32px);
  border-bottom: 1px solid var(--line-soft);
}
.greet-eye {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--primary-ink);
  font-weight: 600;
  margin-bottom: 14px;
  line-height: 1;
}
.greet-eye::before {
  content: "";
  width: 26px;
  height: 2px;
  background: var(--primary);
  display: inline-block;
  border-radius: 1px;
}
.greet h1 {
  font-family: var(--font-display);
  font-weight: 300;
  font-variation-settings: "opsz" 144, "SOFT" 40;
  font-size: clamp(38px, 8vw, 64px);
  line-height: 1;
  letter-spacing: -0.028em;
  margin: 0 0 10px;
}
.greet h1 em {
  font-style: italic;
  font-weight: 300;
  color: var(--primary-deep);
}
.greet-sub {
  font-size: 15px;
  color: var(--ink-mute);
  margin: 0;
  max-width: 520px;
}

/* Hero appointment card */
.appt {
  position: relative;
  background: var(--paper-up);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: clamp(22px, 4vw, 32px);
  box-shadow: var(--lift);
  overflow: hidden;
  isolation: isolate;
}
.appt::before {
  content: "";
  position: absolute;
  top: -60px;
  right: -60px;
  width: 260px;
  height: 260px;
  background: radial-gradient(closest-side, var(--primary-wash), transparent 70%);
  z-index: -1;
  opacity: 0.7;
  pointer-events: none;
}

.appt-top {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 24px;
  flex-wrap: wrap;
}

.status {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 12px 6px 10px;
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 600;
  line-height: 1;
  border-radius: 999px;
  background: var(--primary-wash);
  color: var(--primary-ink);
  border: 1px solid transparent;
  transition: background-color 280ms var(--ease), color 280ms var(--ease), border-color 280ms var(--ease);
}
.status .dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: currentColor;
  /* Ring inherits the chip's text color so it tracks each status rather than
     always being teal. Fallback first for browsers without color-mix. */
  box-shadow: 0 0 0 3px rgba(140, 140, 140, 0.28);
  box-shadow: 0 0 0 3px color-mix(in oklab, currentColor 22%, transparent);
  animation: statusPulse 2.6s var(--ease-in-out) infinite;
}
.status.pending    { background: var(--info-wash);    color: var(--info-deep);    border-color: var(--info-tint);    }
.status.confirmed  { background: var(--primary-wash); color: var(--primary-ink);  border-color: var(--primary-tint); }
.status.cancelled  { background: var(--warn-wash);    color: var(--warn-deep);    border-color: var(--warn-tint);    }
.status.rescheduled{ background: var(--muted-wash);   color: var(--muted-deep);   border-color: var(--muted-tint);   }
/* Terminal / transitional states don't pulse — they're not "live". */
.status.cancelled .dot,
.status.rescheduled .dot { animation: none; }

@keyframes statusPulse {
  0%, 100% {
    box-shadow: 0 0 0 3px rgba(140, 140, 140, 0.28);
    box-shadow: 0 0 0 3px color-mix(in oklab, currentColor 22%, transparent);
  }
  50% { box-shadow: 0 0 0 5px transparent; }
}

.countdown {
  font-size: 12px;
  color: var(--ink-mute);
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.countdown strong {
  font-family: var(--font-display);
  font-weight: 500;
  color: var(--ink);
  font-size: 14px;
  letter-spacing: -0.01em;
}

.appt-body {
  display: grid;
  grid-template-columns: 1fr;
  gap: 20px;
  align-items: start;
}

.date-block {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: start;
  gap: 4px 14px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--line-soft);
  min-width: 0;
}
.date-block .date-weekday {
  grid-column: 1 / -1;
  margin-bottom: 2px;
}
.date-block .date-day {
  grid-column: 1;
  grid-row: 2;
}
.date-block .date-month {
  grid-column: 2;
  grid-row: 2;
  align-self: end;
  padding-bottom: 10px;
}
.date-day {
  font-family: var(--font-display);
  font-weight: 300;
  font-variation-settings: "opsz" 144, "SOFT" 50;
  font-size: clamp(76px, 17vw, 132px);
  line-height: 0.84;
  letter-spacing: -0.04em;
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}
.date-month {
  font-family: var(--font-display);
  font-style: italic;
  font-weight: 300;
  font-size: clamp(18px, 4vw, 24px);
  color: var(--primary-ink);
  letter-spacing: -0.005em;
}
.date-weekday {
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--ink-mute);
  font-weight: 600;
  line-height: 1;
}

.appt-detail {
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-width: 0;
}
.appt-time {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(24px, 5vw, 32px);
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--ink);
}
.appt-time span {
  color: var(--ink-mute);
  font-weight: 300;
}
.appt-doc {
  margin: 0;
  font-size: 15px;
  color: var(--ink-soft);
  line-height: 1.45;
}
.appt-doc strong {
  font-weight: 500;
  color: var(--ink);
}
.appt-doc .spec {
  color: var(--ink-mute);
  display: block;
  font-size: 13px;
  margin-top: 2px;
}
.appt-addr {
  margin: 0;
  font-size: 14px;
  color: var(--ink-mute);
  display: flex;
  align-items: flex-start;
  gap: 8px;
  line-height: 1.5;
  min-width: 0;
}
.appt-addr svg { flex-shrink: 0; margin-top: 2px; color: var(--ink-mute); }
.appt-addr a { color: var(--ink-soft); }

/* Optional map preview — third column of .appt-body on wide viewports.
   Fixed 360px width; capped at 200px height and bottom-aligned in its grid
   cell so any extra vertical room sits above the map. */
.appt-map {
  display: none;
  position: relative;
  width: 360px;
  height: 100%;
  max-height: 200px;
  min-height: 140px;
  align-self: end;
  border-radius: 12px;
  overflow: hidden;
  border: 1px solid var(--line);
  background: var(--paper-up);
  transition: transform 240ms var(--ease), box-shadow 240ms var(--ease), border-color 240ms var(--ease);
  isolation: isolate;
}
.appt-map:hover {
  transform: translateY(-1px);
  box-shadow: var(--lift-sm);
  border-color: var(--line-loud);
}
.appt-map:focus-visible {
  outline: 2px solid var(--primary-deep);
  outline-offset: 2px;
}
/* Tiles are absolutely positioned <img> children; only tiles intersecting
   the visible area are mounted, so no hidden fetches happen. <img srcset>
   lets the browser pick the 1x (256 px) vs @2x (512 px) source based on
   devicePixelRatio, giving pixel-perfect retina rendering. */
.appt-map .tile-grid {
  position: absolute;
  top: 0; left: 0;
  width: 0;
  height: 0;
  will-change: transform;
}
.appt-map .tile {
  position: absolute;
  display: block;
  width: 128px;
  height: 128px;
  max-width: none;  /* override global `img { max-width: 100% }` — parent grid is 0×0 */
  max-height: none;
  background-color: var(--paper-up);
}
/* A mint dot with an outward-only beacon ripple. A pseudo-element is scaled
   up with border-radius: 50%, so the ripple stays perfectly round (box-shadow
   spread can render square on some browsers at large radii). */
.appt-map .pin {
  position: absolute;
  left: 50%;
  top: 50%;
  width: 11px;
  height: 11px;
  transform: translate(-50%, -50%);
  z-index: 2;
}
.appt-map .pin::before,
.appt-map .pin::after {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  background: var(--primary);
}
.appt-map .pin::before {
  animation: pinBeacon 2.2s cubic-bezier(0.2, 0.7, 0.3, 1) infinite;
  transform-origin: center;
}
@keyframes pinBeacon {
  from { transform: scale(1);   opacity: 0.55; }
  to   { transform: scale(2.6); opacity: 0; }
}
.appt-map .attrib {
  position: absolute;
  bottom: 4px; right: 6px;
  font-size: 8px;
  color: rgba(24, 28, 24, 0.4);
  letter-spacing: 0.02em;
  line-height: 1;
  text-shadow: 0 0 2px rgba(255, 255, 255, 0.8);
  z-index: 2;
  pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
  .appt-map .pin { animation: none; }
}


/* Quick actions */
.actions {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
  margin-top: 24px;
  padding-top: 24px;
  border-top: 1px solid var(--line-soft);
}

.action {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 14px 16px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  font-size: 14px;
  font-weight: 500;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background-color 220ms var(--ease), border-color 220ms var(--ease), color 220ms var(--ease), transform 220ms var(--ease), box-shadow 220ms var(--ease);
  min-height: 52px;
  position: relative;
  overflow: hidden;
}
.action:hover {
  background: var(--paper-up);
  border-color: var(--line-loud);
  color: var(--ink);
  transform: translateY(-1px);
  box-shadow: var(--lift-sm);
}
.action:active { transform: translateY(0); }
.action svg {
  transition: transform 220ms var(--ease);
  color: var(--ink-mute);
}
.action:hover svg { color: var(--primary-deep); }

.action.primary {
  grid-column: 1 / -1;
  background: var(--primary);
  color: var(--on-primary);
  /* Layered text-shadow to increase perceived contrast of white-on-mint.
     Automated WCAG doesn't credit text-shadow, so this passes the
     human-readability bar while the calculated ratio remains 2.04:1 — a
     documented trade-off to preserve the brand's bright teal CTA. */
  text-shadow:
    0 1px 1px color-mix(in oklab, var(--primary-ink) 65%, transparent),
    0 0 6px color-mix(in oklab, var(--primary-ink) 35%, transparent);
  border-color: var(--primary);
  font-size: 15px;
  font-weight: 600;
  min-height: 56px;
  box-shadow: var(--lift-mint);
}
/* Subtle top highlight to match .btn (login submit / modal primary). */
.action.primary::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.4), transparent 50%);
  pointer-events: none;
  opacity: 0.6;
}
.action.primary > * { position: relative; z-index: 1; }
.action.primary svg { color: var(--on-primary); filter: drop-shadow(0 1px 1px color-mix(in oklab, var(--primary-ink) 55%, transparent)); }
.action.primary:hover {
  background: var(--primary-hover);
  border-color: var(--primary-hover);
  color: var(--on-primary);
  transform: translateY(-1px);
  box-shadow: 0 1px 0 color-mix(in oklab, var(--primary) 20%, transparent), 0 16px 44px -18px color-mix(in oklab, var(--primary) 50%, transparent);
}
.action.primary:hover svg { color: var(--on-primary); }

.action.primary.is-confirmed {
  background: var(--primary-wash);
  color: var(--primary-ink);
  text-shadow: none;
  border-color: var(--primary-tint);
  cursor: default;
}
.action.primary.is-confirmed svg { color: var(--primary-ink); filter: none; }
.action.primary.is-confirmed:hover { transform: none; box-shadow: none; }

.action.danger:hover {
  background: var(--warn-tint);
  border-color: var(--warn);
  color: var(--warn);
}
.action.danger:hover svg { color: var(--warn); }

.action.is-cancelled {
  pointer-events: none;
  opacity: 0.5;
}

/* Document cards */
.docs {
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}

.doc {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: 14px;
  padding: 14px 16px;
  background: var(--paper-up);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  text-decoration: none;
  color: var(--ink);
  transition: background-color 220ms var(--ease), border-color 220ms var(--ease), transform 220ms var(--ease), box-shadow 220ms var(--ease);
  cursor: pointer;
  text-align: left;
  width: 100%;
}
.doc:hover {
  border-color: var(--line-loud);
  background: var(--paper);
  transform: translateX(2px);
  box-shadow: var(--lift-sm);
}
.doc-icon {
  width: 44px;
  height: 52px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 3px;
  display: grid;
  place-items: center;
  position: relative;
  flex-shrink: 0;
}
.doc-icon::before {
  content: "";
  position: absolute;
  top: -1px; right: -1px;
  width: 10px; height: 10px;
  background: var(--paper);
  border-left: 1px solid var(--line);
  border-bottom: 1px solid var(--line);
  transform: skew(0deg);
}
.doc-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}
.doc-title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 16px;
  letter-spacing: -0.01em;
  color: var(--ink);
  line-height: 1.25;
}
.doc-sub {
  font-size: 12px;
  color: var(--ink-mute);
  display: flex;
  gap: 4px 10px;
  flex-wrap: wrap;
  min-width: 0;
}
.doc-sub span:not(:last-child)::after {
  content: "·";
  margin-left: 10px;
  color: var(--line-loud);
}
.doc-meta {
  min-width: 0;
  overflow: hidden;
}
.doc-title { overflow: hidden; text-overflow: ellipsis; }

.doc-action {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 10px;
  color: var(--ink-mute);
  border-radius: var(--r-sm);
  font-size: 12px;
  font-weight: 500;
  letter-spacing: 0.02em;
  transition: color 180ms var(--ease);
}
.doc:hover .doc-action {
  color: var(--primary-deep);
}

/* Email-me-the-documents — single-row inline strip below the docs list.
   Uses the mint-wash palette so it reads as a distinct "send" surface
   rather than another document card.

   Mobile-first: stacked column. On wide viewports (≥ 720px) flips to a
   single row with the label on the left and the input + button paired on
   the right. No flex-wrap so there are no in-between "button jumped to the
   next line on its own" states. */
.docs-mail {
  margin-top: 20px;
  padding: 14px 18px;
  background: var(--primary-wash);
  border: 1px solid var(--primary-tint);
  border-radius: var(--r-md);
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: 12px;
}
.docs-mail-title {
  margin: 0;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-body);
  font-size: 12px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--primary-ink);
  line-height: 1;
}
/* 14px icon matches the caps height of the 12px uppercase label — slight
   optical nudge up so the visual midpoint aligns with the letterforms. */
.docs-mail-icon {
  flex-shrink: 0;
  color: var(--primary-ink);
  margin-top: -1px;
}

.docs-mail-title { align-self: flex-start; }

.docs-mail input[type="email"] {
  min-width: 0;
  width: 100%;
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.2;
  padding: 9px 12px;
  background: var(--paper);
  border: 1px solid var(--primary-tint);
  border-radius: var(--r-sm);
  color: var(--ink);
  transition: border-color 200ms var(--ease), box-shadow 200ms var(--ease);
}
.docs-mail input[type="email"]::placeholder { color: var(--ink-quiet); }
.docs-mail input[type="email"]:hover { border-color: var(--primary); }
.docs-mail input[type="email"]:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--primary) 22%, transparent);
}
/* Only flag as invalid once the user has actually typed something. The
   `placeholder` attribute is what enables :placeholder-shown, so when the
   field is empty the placeholder is visible and we skip the red state. */
.docs-mail input[type="email"]:not(:placeholder-shown):invalid:not(:focus) {
  border-color: var(--warn);
}

.docs-mail-send {
  align-self: flex-start;   /* fits content width when stacked */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  padding: 10px 18px;
  background: var(--primary);
  color: var(--on-primary);
  /* Layered text-shadow to increase perceived contrast of white-on-mint.
     Automated WCAG doesn't credit text-shadow, so this passes the
     human-readability bar while the calculated ratio remains 2.04:1 — a
     documented trade-off to preserve the brand's bright teal CTA. */
  text-shadow:
    0 1px 1px color-mix(in oklab, var(--primary-ink) 65%, transparent),
    0 0 6px color-mix(in oklab, var(--primary-ink) 35%, transparent);
  border-radius: var(--r-sm);
  font-family: var(--font-body);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: background 200ms var(--ease), transform 160ms var(--ease), box-shadow 200ms var(--ease);
  box-shadow: var(--lift-mint);
  position: relative;
  overflow: hidden;
  white-space: nowrap;
}
.docs-mail-send::before {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(180deg, rgba(255,255,255,0.35), transparent 50%);
  pointer-events: none;
  opacity: 0.6;
}
.docs-mail-send > * { position: relative; z-index: 1; }
.docs-mail-send svg {
  filter: drop-shadow(0 1px 1px color-mix(in oklab, var(--primary-ink) 55%, transparent));
  transition: transform 200ms var(--ease);
}
.docs-mail-send:hover {
  background: var(--primary-hover);
  transform: translateY(-1px);
}
.docs-mail-send:hover svg { transform: translateX(3px); }
.docs-mail-send:active { transform: translateY(0); }
.docs-mail.is-sent .docs-mail-send {
  background: var(--paper);
  color: var(--primary-ink);
  text-shadow: none;
  box-shadow: none;
  cursor: default;
  pointer-events: none;
  border: 1px solid var(--primary-tint);
}
.docs-mail.is-sent .docs-mail-send::before { display: none; }
.docs-mail.is-sent .docs-mail-send svg { filter: none; }

/* Wide viewports: single clean row. Label hugs left, input + button pair
   on the right. No flex-wrap, and the threshold is calibrated so the three
   items (title ≈ 243 + input 260 + button ≈ 109 + 2×18 gap = 648) always
   fit inside the form's content box — the form needs ≥ 686 px outer, which
   requires a viewport ≥ ~766 px. We use 780 for a safety margin; below this
   the default stacked column kicks in. */
@media (min-width: 780px) {
  .docs-mail {
    flex-direction: row;
    align-items: center;
    gap: 18px;
    padding: 14px 18px 14px 20px;
  }
  .docs-mail-title {
    align-self: auto;
    flex-shrink: 0;
    margin-right: auto;       /* pushes the input+button pair to the right */
  }
  .docs-mail input[type="email"] {
    width: 260px;
    flex-shrink: 0;
  }
  .docs-mail-send {
    align-self: auto;
    flex-shrink: 0;
  }
}

/* Practical info */
.practical {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
}
.info-card {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 14px;
  padding: 16px;
  background: var(--paper-up);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
}
.info-icon {
  width: 38px;
  height: 38px;
  border-radius: var(--r-sm);
  background: var(--primary-wash);
  display: grid;
  place-items: center;
  color: var(--primary-deep);
  flex-shrink: 0;
  border: 1px solid var(--primary-tint);
}
.info-title {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: 500;
  letter-spacing: -0.005em;
  margin: 0 0 2px;
}
.info-body {
  font-size: 13px;
  color: var(--ink-mute);
  margin: 0;
  line-height: 1.5;
}
.info-body a { color: var(--ink-soft); }

/* Help section */
.help {
  padding: clamp(24px, 4vw, 32px);
  background: var(--paper-up);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  display: flex;
  flex-direction: column;
  gap: 16px;
  position: relative;
  overflow: hidden;
}
.help::after {
  content: "";
  position: absolute;
  bottom: -50px;
  left: -50px;
  width: 180px;
  height: 180px;
  background: radial-gradient(closest-side, var(--warn-wash), transparent 70%);
  pointer-events: none;
  opacity: 0.6;
}
.help-title {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(20px, 4vw, 24px);
  letter-spacing: -0.015em;
  margin: 0;
  line-height: 1.15;
  position: relative;
}
.help-title em {
  font-style: italic;
  color: var(--primary-deep);
  font-weight: 300;
}
.help-body {
  color: var(--ink-mute);
  font-size: 14px;
  margin: 0;
  max-width: 520px;
  line-height: 1.55;
  position: relative;
}
.help-actions {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
  position: relative;
}
.help-action {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 12px 16px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  font-size: 14px;
  font-weight: 500;
  color: var(--ink);
  transition: background-color 200ms var(--ease), border-color 200ms var(--ease), color 200ms var(--ease), box-shadow 200ms var(--ease);
}
.help-action:hover {
  background: var(--primary);
  color: var(--on-primary);
  /* Layered text-shadow to increase perceived contrast of white-on-mint.
     Automated WCAG doesn't credit text-shadow, so this passes the
     human-readability bar while the calculated ratio remains 2.04:1 — a
     documented trade-off to preserve the brand's bright teal CTA. */
  text-shadow:
    0 1px 1px color-mix(in oklab, var(--primary-ink) 65%, transparent),
    0 0 6px color-mix(in oklab, var(--primary-ink) 35%, transparent);
  border-color: var(--primary);
  box-shadow: var(--lift-mint);
}
.help-action svg { color: var(--ink-mute); transition: color 200ms var(--ease); }
.help-action:hover svg { color: var(--on-primary); filter: drop-shadow(0 1px 1px color-mix(in oklab, var(--primary-ink) 55%, transparent)); }

/* Callia swag band */
.swag {
  margin-top: clamp(32px, 5vw, 56px);
  padding: clamp(24px, 5vw, 40px);
  border-radius: var(--r-lg);
  background: var(--ink);
  color: var(--paper-up);
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
  position: relative;
  overflow: hidden;
}
.swag::before {
  content: "";
  position: absolute;
  top: -80px;
  right: -80px;
  width: 360px;
  height: 360px;
  background: radial-gradient(closest-side, color-mix(in oklab, var(--primary) 35%, transparent), transparent 70%);
  pointer-events: none;
}
.swag::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='240' height='240'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2' stitchTiles='stitch'/><feColorMatrix values='0 0 0 0 1  0 0 0 0 1  0 0 0 0 1  0 0 0 0.05 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  pointer-events: none;
  mix-blend-mode: overlay;
}
.swag-inner { position: relative; z-index: 1; }
.swag-eye {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  color: var(--primary);
  font-weight: 600;
  margin-bottom: 16px;
  line-height: 1;
}
.swag-eye::before {
  content: "";
  width: 26px;
  height: 2px;
  background: var(--primary);
  display: inline-block;
  border-radius: 1px;
}
.swag-eye .dot {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--primary-soft);
}
.swag-title {
  font-family: var(--font-display);
  font-weight: 300;
  font-variation-settings: "opsz" 144, "SOFT" 40;
  font-size: clamp(26px, 5vw, 38px);
  line-height: 1.1;
  letter-spacing: -0.025em;
  margin: 0 0 10px;
  max-width: 560px;
}
.swag-title em {
  font-style: italic;
  color: var(--primary-soft);
}
.swag-body {
  font-size: 14px;
  line-height: 1.55;
  color: rgba(246, 242, 235, 0.75);
  max-width: 520px;
  margin: 0 0 18px;
}
.swag-link {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 14px;
  font-weight: 500;
  color: var(--paper-up);
  border-bottom: 1px solid rgba(246, 242, 235, 0.4);
  padding-bottom: 3px;
  text-decoration: none;
  transition: border-color 200ms var(--ease), gap 200ms var(--ease);
}
.swag-link:hover {
  border-color: var(--primary-soft);
  gap: 12px;
}

.swag-stats {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 2px;
  margin-top: 28px;
  padding-top: 24px;
  border-top: 1px solid rgba(246, 242, 235, 0.12);
  position: relative;
  z-index: 1;
}

/* Narrow mobile: stack stats vertically. At 3-columns below ~480px, "nouveaux
   patients" and "heures gagnées" wrap to 2 lines while "conversations" stays
   on one, producing uneven row heights and a visible left-alignment drift.
   A vertical stack sidesteps the problem entirely — each stat gets the full
   row, labels wrap only if they truly need to, alignment is consistent. */
@media (max-width: 520px) {
  .swag-stats {
    grid-template-columns: 1fr;
    gap: 18px;
    padding-top: 22px;
    margin-top: 22px;
  }
}
.stat-num {
  font-family: var(--font-display);
  font-weight: 300;
  font-size: clamp(24px, 5vw, 34px);
  line-height: 1;
  letter-spacing: -0.02em;
  color: var(--paper-up);
  display: block;
  margin-bottom: 4px;
  font-variant-numeric: tabular-nums;
}
.stat-label {
  font-family: var(--font-body);
  font-size: 11px;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: rgba(255, 255, 255, 0.55);
  font-weight: 500;
}

/* Footer — one harmonious row on desktop (copy · privacy · propulsé par),
   stacks on mobile. Matches .dash sizing so inner edges align with the
   sections above. */
.footer {
  padding: 32px var(--pad) 60px;
  font-size: 12px;
  color: var(--ink-mute);
  line-height: 1.6;
  max-width: calc(var(--content-max-wide) + var(--pad) * 2);
  margin: 0 auto;
  width: 100%;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 14px;
  border-top: 1px solid var(--line-soft);
}
.footer-copy { margin: 0; }
.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: 4px 18px;
  font-size: 12px;
}
.footer-links a { color: var(--ink-soft); }

@media (min-width: 640px) {
  .footer {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: 20px 32px;
    flex-wrap: wrap;
  }
  .footer-copy { flex: 1 1 auto; }
}

/* Modal */
.modal-scrim {
  position: fixed;
  inset: 0;
  background: rgba(14, 21, 18, 0.35);
  -webkit-backdrop-filter: blur(8px);
  backdrop-filter: blur(8px);
  display: grid;
  place-items: center;
  padding: 20px;
  z-index: 100;
  opacity: 0;
  pointer-events: none;
  transition: opacity 240ms var(--ease);
}
.modal-scrim.is-open {
  opacity: 1;
  pointer-events: auto;
}

.modal {
  background: var(--paper-up);
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  padding: clamp(24px, 4vw, 32px);
  max-width: 440px;
  width: 100%;
  box-shadow: var(--lift-lg);
  transform: translateY(12px) scale(0.98);
  transition: transform 320ms var(--ease);
}
.modal-scrim.is-open .modal { transform: translateY(0) scale(1); }

.modal-eye {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 4px 10px;
  background: var(--warn-tint);
  color: var(--warn);
  border-radius: 999px;
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  font-weight: 500;
  margin-bottom: 14px;
}

.modal h3 {
  font-family: var(--font-display);
  font-weight: 400;
  font-size: clamp(22px, 4vw, 28px);
  letter-spacing: -0.015em;
  margin: 0 0 10px;
  line-height: 1.15;
}

.modal p {
  color: var(--ink-mute);
  font-size: 14px;
  line-height: 1.55;
  margin: 0 0 8px;
}
.modal p.note {
  padding: 10px 12px;
  background: var(--paper-deep);
  border-radius: var(--r-sm);
  margin-top: 14px;
  font-size: 13px;
  color: var(--ink-soft);
}

.modal-actions {
  display: flex;
  gap: 8px;
  margin-top: 24px;
  flex-direction: column;
}
.modal .btn { min-height: 52px; }
.modal .btn-secondary { background: transparent; }

/* Toast */
.toast {
  position: fixed;
  left: 50%;
  bottom: 24px;
  transform: translateX(-50%) translateY(20px);
  background: var(--ink);
  color: var(--paper-up);
  padding: 12px 18px;
  border-radius: 999px;
  font-size: 14px;
  font-weight: 500;
  display: flex;
  align-items: center;
  gap: 10px;
  box-shadow: var(--lift-lg);
  opacity: 0;
  pointer-events: none;
  transition: transform 320ms var(--ease), opacity 240ms var(--ease);
  z-index: 200;
  max-width: calc(100vw - 32px);
  white-space: nowrap;
}
.toast.is-visible {
  transform: translateX(-50%) translateY(0);
  opacity: 1;
}
.toast svg { color: var(--primary-soft); }

/* Dashboard reveal — short, tight stagger. The whole page is settled in ~500ms. */
html.js-reveal .greet,
html.js-reveal .dash > .section,
html.js-reveal .dash > .swag {
  animation: reveal 340ms var(--ease) both;
}
html.js-reveal .greet                          { animation-delay: 0ms; }
html.js-reveal .dash > .section:nth-of-type(2) { animation-delay: 40ms; }
html.js-reveal .dash > .section:nth-of-type(3) { animation-delay: 80ms; }
html.js-reveal .dash > .section:nth-of-type(4) { animation-delay: 110ms; }
html.js-reveal .dash > .section:nth-of-type(5) { animation-delay: 140ms; }
html.js-reveal .dash > .section:nth-of-type(6) { animation-delay: 170ms; }
html.js-reveal .dash > .swag                   { animation-delay: 200ms; }

/* ==========================================================================
   Responsive — breakpoints
   ========================================================================== */

@media (min-width: 480px) {
  .actions {
    grid-template-columns: 1fr 1fr;
  }
  .action.primary { grid-column: 1 / -1; }
  .modal-actions { flex-direction: row; justify-content: flex-end; }
  .modal-actions .btn { width: auto; min-width: 140px; }
  .login-foot { flex-direction: row; }
}

@media (min-width: 640px) {
  .practical { grid-template-columns: 1fr 1fr; }
}

@media (min-width: 760px) {
  .actions {
    grid-template-columns: 2fr 1fr 1fr;
  }
  .action.primary { grid-column: 1 / 2; }
  .docs { grid-template-columns: 1fr 1fr; }
  .swag { grid-template-columns: minmax(0, 1.3fr) 1fr; padding: 48px; align-items: center; }
  .swag-stats { margin-top: 0; padding-top: 0; border-top: 0; border-left: 1px solid rgba(246, 242, 235, 0.12); padding-left: 32px; grid-template-columns: 1fr; gap: 20px; }
}

@media (min-width: 560px) {
  /* Re-enable side-by-side date/detail once we have horizontal room */
  .appt-body {
    grid-template-columns: minmax(140px, auto) minmax(0, 1fr);
    gap: clamp(20px, 4vw, 36px);
  }
  .date-block {
    padding-bottom: 0;
    padding-right: clamp(16px, 3vw, 32px);
    border-bottom: 0;
    border-right: 1px solid var(--line);
    gap: 4px;
    align-self: start;
  }
  .date-block .date-weekday { grid-column: 1 / -1; margin-bottom: 6px; }
  .date-block .date-day { grid-column: 1 / -1; grid-row: 2; }
  .date-block .date-month {
    grid-column: 1 / -1;
    grid-row: 3;
    align-self: auto;
    padding-bottom: 0;
    margin-top: 6px;
  }
  .date-day { font-size: clamp(72px, 15vw, 120px); }
}

/* Map preview becomes a 3rd column of .appt-body on wide viewports.
   Its height is driven by align-items: stretch so the map matches the
   detail-column's natural height — no extra vertical space added. */
@media (min-width: 960px) {
  .appt-body {
    grid-template-columns: minmax(140px, auto) minmax(0, 1fr) 360px;
    align-items: stretch;
  }
  .appt-map.is-ready { display: block; }
}

@media (min-width: 980px) {
  .help { flex-direction: row; align-items: center; justify-content: space-between; gap: 32px; }
  .help-main { flex: 1; }
  .help-actions { flex-shrink: 0; }
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }
}

/* Headless / screenshot detection: virtual-time-budget flag surfaces in UA
   string on headless Chrome. Skip reveal entirely. */
html.no-reveal .login-hero > *,
html.no-reveal .greet,
html.no-reveal .dash > .section,
html.no-reveal .dash > .swag {
  animation: none !important;
  opacity: 1 !important;
  transform: none !important;
}

/* Utility */
.hidden { display: none !important; }
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ==========================================================================
   Expired page · calm "this rendez-vous is past" view
   Reuses the login shell (.login, .login-top, .login-hero, .login-foot) and
   the main .login-* typography. Only the eyebrow color and the timeline
   decoration are specific to this page.
   ========================================================================== */

.login-eyebrow.is-muted {
  color: var(--muted-deep);
}
.login-eyebrow.is-muted .dot {
  background: var(--muted);
  box-shadow: 0 0 0 3px var(--muted-wash);
  animation: none;  /* expired isn't "live" — do not pulse */
}

/* Two-point timeline decoration. The past appointment sits on the left,
   today sits on the right; the gap between them *shows* the elapsed time,
   which reinforces the "déjà passé" message without any extra copy. */
.timeline {
  position: relative;
  margin: 32px 0 28px;
  padding: 26px 12px 6px;
  min-height: 110px;
}
.timeline-line {
  position: absolute;
  left: 12px;
  right: 12px;
  top: 32px;
  height: 1px;
  background: linear-gradient(to right,
    var(--muted-tint) 0%,
    var(--line) 45%,
    var(--primary-tint) 100%);
}
.timeline-point {
  position: absolute;
  top: 22px;
  left: var(--pos, 50%);
  transform: translateX(-50%);
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 14px;
  width: 110px;
}
.timeline-dot {
  width: 14px;
  height: 14px;
  border-radius: 50%;
  position: relative;
  flex-shrink: 0;
}
.timeline-point.is-past .timeline-dot {
  background: var(--muted);
  box-shadow: 0 0 0 4px var(--paper);
}
.timeline-point.is-today .timeline-dot {
  background: var(--primary);
  box-shadow: 0 0 0 4px var(--paper), 0 0 0 6px color-mix(in oklab, var(--primary) 30%, transparent);
  animation: timelinePulse 2.4s var(--ease-in-out) infinite;
}
@keyframes timelinePulse {
  0%, 100% { box-shadow: 0 0 0 4px var(--paper), 0 0 0 6px color-mix(in oklab, var(--primary) 30%, transparent); }
  50%      { box-shadow: 0 0 0 4px var(--paper), 0 0 0 10px color-mix(in oklab, var(--primary) 0%, transparent); }
}
.timeline-label {
  display: flex;
  flex-direction: column;
  gap: 4px;
  align-items: center;
  text-align: center;
  line-height: 1.15;
}
.timeline-label-eye {
  font-family: var(--font-body);
  font-size: 10px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 600;
  color: var(--ink-mute);
  line-height: 1;
}
.timeline-label-date {
  font-family: var(--font-display);
  font-size: 14px;
  font-style: italic;
  font-weight: 400;
  letter-spacing: -0.005em;
  color: var(--ink-soft);
  line-height: 1.2;
  white-space: nowrap;
}
.timeline-point.is-today .timeline-label-date { color: var(--primary-ink); }

@media (prefers-reduced-motion: reduce) {
  .timeline-point.is-today .timeline-dot { animation: none; }
}

/* ==========================================================================
   Code login variant · 2x4 alphanumeric input
   Reuses .dob container/focus grammar. Adds uppercase typography, wider
   tracking, and balances both fields equally (no year flex).
   ========================================================================== */

.dob.code {
  /* The field has no inner labels (bullet placeholders do the work), so
     center inputs vertically within the container rather than bottom-align
     as the DOB variant does. */
  align-items: center;
}
.dob.code .dob-field.code-part { flex: 1; }
.dob.code .code-part input {
  text-transform: uppercase;
  font-variation-settings: "opsz" 48, "SOFT" 20;
  letter-spacing: 0.18em;
  font-size: clamp(22px, 5vw, 28px);
  text-align: center;
  padding: 10px 2px;
}
.dob.code .code-part input::placeholder {
  color: var(--line-loud);
  font-weight: 300;
  letter-spacing: 0.18em;
}

/* Em-dash separator between the two parts. Sized to match the inputs'
   optical center. */
.dob.code > .dob-sep {
  font-size: 22px;
  color: var(--line-loud);
  padding-bottom: 0;
  align-self: center;
}

/* ==========================================================================
   OTP · 6 single-char boxes with a visual gap in the middle
   Independent component from .dob because each character gets its own
   visually distinct box — the grammar is different (one cell per digit).
   ========================================================================== */

.otp {
  display: flex;
  align-items: center;
  gap: 8px;
  min-width: 0;
}
.otp-box {
  flex: 1 1 0;
  min-width: 0;
  max-width: 56px;
  height: clamp(54px, 12vw, 64px);
  padding: 0;
  text-align: center;
  font-family: var(--font-display);
  font-variation-settings: "opsz" 48, "SOFT" 30;
  font-weight: 400;
  font-size: clamp(22px, 6vw, 28px);
  line-height: 1;
  color: var(--ink);
  background: var(--paper-up);
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  box-shadow: var(--lift-sm);
  transition: border-color 200ms var(--ease), box-shadow 200ms var(--ease), background-color 200ms var(--ease);
  font-variant-numeric: tabular-nums;
  caret-color: var(--primary-deep);
}
.otp-box:hover { border-color: var(--line-loud); }
.otp-box:focus {
  outline: none;
  border-color: var(--primary-deep);
  box-shadow: 0 0 0 4px var(--primary-wash), var(--lift-sm);
}
/* No filled-state background tint: boxes stay white to match the DOB and
   code inputs. The typed digit itself provides the visual cue, with the
   focus ring marking the active cell. */
.otp-sep {
  width: 8px;
  height: 1px;
  background: var(--line-loud);
  flex-shrink: 0;
  margin: 0 2px;
}
.otp.is-error .otp-box {
  border-color: var(--warn);
  box-shadow: 0 0 0 3px var(--warn-tint), var(--lift-sm);
  animation: shake 420ms var(--ease-in-out);
}

.otp-resend {
  margin: 18px 2px 0;
  font-size: 13px;
  color: var(--ink-mute);
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px 10px;
  line-height: 1.5;
}
.otp-resend-btn {
  display: inline-flex;
  align-items: baseline;
  gap: 4px;
  color: var(--primary-ink);
  font: inherit;
  font-weight: 600;
  padding: 0;
  background: none;
  border: 0;
  cursor: pointer;
  transition: color 180ms var(--ease);
}
.otp-resend-btn:disabled {
  color: var(--ink-mute);
  cursor: default;
  font-weight: 500;
}
.otp-resend-btn:not(:disabled):hover {
  color: var(--primary-deep);
  text-decoration: underline;
  text-decoration-thickness: 1px;
  text-underline-offset: 3px;
}

/* ==========================================================================
   Chat (dashboard-chat.html only)
   Three states managed by body classes on the button/panel:
   · closed     → only .chat-fab visible
   · open       → .chat-panel visible, .chat-fab hidden
   · minimized  → .chat-pill visible, others hidden
   ========================================================================== */

/* Shared values */
:root {
  --chat-edge: 20px;
  --chat-width: 380px;
  --chat-height: min(560px, calc(100dvh - 48px));
  --chat-radius: 20px;
}

/* FAB — single-purpose entry point. Circular, icon-only, sized to feel
   like a peer to the .avatar in the topbar (40 → 56 for touch). */
.chat-fab {
  position: fixed;
  right: var(--chat-edge);
  bottom: calc(var(--chat-edge) + env(safe-area-inset-bottom, 0px));
  z-index: 90;
  width: 56px;
  height: 56px;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--primary);
  color: var(--on-primary);
  box-shadow: var(--lift-mint);
  cursor: pointer;
  transition: transform 220ms var(--ease), box-shadow 220ms var(--ease), background 200ms var(--ease), opacity 200ms var(--ease);
}
.chat-fab:hover {
  background: var(--primary-hover);
  transform: translateY(-2px);
  box-shadow: 0 1px 0 color-mix(in oklab, var(--primary) 20%, transparent),
              0 18px 44px -16px color-mix(in oklab, var(--primary) 50%, transparent);
}
.chat-fab:active { transform: translateY(0); }
.chat-fab-icon {
  filter: drop-shadow(0 1px 1px color-mix(in oklab, var(--primary-ink) 55%, transparent));
}

body.chat-open .chat-fab,
body.chat-minimized .chat-fab {
  opacity: 0;
  pointer-events: none;
  transform: translateY(8px);
}

/* Minimized pill — appears when panel was explicitly minimized. Smaller,
   less attention-grabbing than the FAB, but still obviously clickable. */
.chat-pill {
  position: fixed;
  right: var(--chat-edge);
  bottom: calc(var(--chat-edge) + env(safe-area-inset-bottom, 0px));
  z-index: 90;
  display: none;
  align-items: center;
  gap: 12px;
  padding: 10px 14px 10px 12px;
  background: var(--paper-up);
  color: var(--ink);
  border: 1px solid var(--line);
  border-radius: 999px;
  box-shadow: var(--lift);
  font-family: var(--font-body);
  cursor: pointer;
  transition: transform 220ms var(--ease), box-shadow 220ms var(--ease), border-color 220ms var(--ease);
  text-align: left;
}
body.chat-minimized .chat-pill { display: inline-flex; }
.chat-pill:hover {
  border-color: var(--primary-tint);
  transform: translateY(-2px);
  box-shadow: var(--lift-lg);
}
/* Minimized pill keeps the Callia mark in its native logo colors: the C is
   ink-dark and the wave bars are mint — same treatment as the brand logo in
   the topbar. */
.chat-pill-mark {
  width: 24px;
  height: 22px;
  display: grid;
  place-items: center;
  color: var(--ink);
  flex-shrink: 0;
}
.chat-pill-mark svg {
  width: 100%;
  height: 100%;
  /* Optical centering: the crescent C's opening is on the right, so
     mathematical centering looks left-heavy. Nudge the mark rightward. */
  transform: translate(2px, 0);
}
.chat-pill-mark .callia-bars rect { fill: var(--primary); }
.chat-pill-text {
  display: flex;
  flex-direction: column;
  gap: 1px;
  line-height: 1.1;
}
.chat-pill-title {
  font-family: var(--font-display);
  font-weight: 500;
  font-size: 14px;
  letter-spacing: -0.01em;
  color: var(--ink);
}
.chat-pill-sub {
  font-size: 11px;
  color: var(--ink-mute);
  letter-spacing: 0.06em;
}
.chat-pill-expand {
  color: var(--ink-mute);
  transition: transform 200ms var(--ease);
}
.chat-pill:hover .chat-pill-expand { transform: translateY(-2px); color: var(--primary-deep); }

/* Scrim · dims the page behind the panel on mobile where the sheet takes
   over most of the viewport. Kept inactive on desktop so the dashboard
   stays interactive alongside the chat (closer to a docked assistant than
   a modal dialog). */
.chat-scrim {
  position: fixed;
  inset: 0;
  background: rgba(14, 21, 18, 0.28);
  -webkit-backdrop-filter: blur(4px);
  backdrop-filter: blur(4px);
  opacity: 0;
  pointer-events: none;
  z-index: 85;
  transition: opacity 240ms var(--ease);
}
@media (max-width: 640px) {
  body.chat-open .chat-scrim {
    opacity: 1;
    pointer-events: auto;
  }
}

/* Panel — anchored bottom-right on desktop, full-width bottom sheet on
   mobile (handled by the media query further down). */
.chat-panel {
  position: fixed;
  right: var(--chat-edge);
  bottom: calc(var(--chat-edge) + env(safe-area-inset-bottom, 0px));
  z-index: 95;
  width: var(--chat-width);
  max-width: calc(100vw - var(--chat-edge) * 2);
  height: var(--chat-height);
  display: grid;
  grid-template-rows: auto 1fr auto auto auto;
  background: var(--paper-up);
  border: 1px solid var(--line);
  border-radius: var(--chat-radius);
  box-shadow: var(--lift-lg);
  overflow: hidden;
  opacity: 0;
  transform: translateY(16px) scale(0.98);
  transform-origin: bottom right;
  pointer-events: none;
  transition: opacity 260ms var(--ease), transform 260ms var(--ease);
  isolation: isolate;
}
body.chat-open .chat-panel {
  opacity: 1;
  transform: translateY(0) scale(1);
  pointer-events: auto;
}

/* Head */
.chat-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 16px 12px 16px 20px;
  background: var(--paper-up);
  border-bottom: 1px solid var(--line-soft);
  /* A hairline of mint along the top edge — the subtle brand moment, without
     the full-height gradient that felt heavy. */
  box-shadow: inset 0 2px 0 var(--primary-wash);
}
.chat-head-brand {
  display: flex;
  align-items: center;
  gap: 12px;
  min-width: 0;
}
.chat-head-mark {
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--primary-wash);
  display: grid;
  place-items: center;
  color: var(--primary-deep);
  flex-shrink: 0;
}
.chat-head-mark svg {
  width: 22px;
  height: 20px;
  /* Optical centering inside the disc: the crescent C opens to the right
     so the mark's visual mass sits on the left. A ~1/12-of-width nudge
     (validated against a test grid) brings the C's gap onto the center
     axis — mathematically off, optically right. */
  transform: translate(2px, 0);
}
.chat-head-mark .callia-bars rect { fill: var(--primary); }
.chat-head-text { min-width: 0; }
.chat-head-title {
  font-family: var(--font-display);
  font-size: 16px;
  font-weight: 500;
  letter-spacing: -0.01em;
  line-height: 1.1;
  margin: 0;
  color: var(--ink);
}
.chat-head-sub {
  font-size: 11px;
  color: var(--ink-mute);
  letter-spacing: 0.06em;
  margin: 2px 0 0;
  display: inline-flex;
  align-items: center;
  gap: 6px;
  line-height: 1;
}
.chat-head-live {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--primary-deep);
  box-shadow: 0 0 0 3px color-mix(in oklab, var(--primary) 22%, transparent);
  animation: livePulse 2.6s var(--ease-in-out) infinite;
  flex-shrink: 0;
}
.chat-head-actions {
  display: flex;
  gap: 2px;
  flex-shrink: 0;
}
.chat-icon-btn {
  width: 34px;
  height: 34px;
  border-radius: var(--r-sm);
  display: grid;
  place-items: center;
  color: var(--ink-mute);
  transition: background-color 180ms var(--ease), color 180ms var(--ease);
  cursor: pointer;
}
.chat-icon-btn:hover {
  background: var(--paper-deep);
  color: var(--ink);
}

/* Log */
.chat-log {
  overflow-y: auto;
  overflow-x: hidden;
  padding: 18px 16px 8px;
  display: flex;
  flex-direction: column;
  gap: 14px;
  scroll-behavior: smooth;
  scrollbar-width: thin;
  scrollbar-color: var(--line-loud) transparent;
}
.chat-log::-webkit-scrollbar { width: 6px; }
.chat-log::-webkit-scrollbar-thumb { background: var(--line-loud); border-radius: 3px; }
.chat-log::-webkit-scrollbar-track { background: transparent; }

.chat-msg {
  display: flex;
  gap: 8px;
  align-items: flex-end;
  max-width: 100%;
  min-width: 0;
  animation: chatReveal 320ms var(--ease) both;
}
@keyframes chatReveal {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.chat-msg.is-ai {
  align-self: flex-start;
  max-width: 85%;
}
.chat-msg.is-user {
  align-self: flex-end;
  flex-direction: row-reverse;
  max-width: 78%;
}
.chat-msg-mark {
  width: 26px;
  height: 26px;
  border-radius: 50%;
  background: var(--primary-wash);
  display: grid;
  place-items: center;
  color: var(--primary-deep);
  flex-shrink: 0;
  margin-bottom: 2px;
}
.chat-msg-mark svg {
  width: 16px;
  height: 15px;
  transform: translate(1.5px, 0);
}
.chat-msg-mark .callia-bars rect { fill: var(--primary); }
.chat-msg-bubble {
  padding: 10px 14px;
  border-radius: 16px;
  font-size: 14px;
  line-height: 1.5;
  color: var(--ink);
  min-width: 0;
  word-wrap: break-word;
  overflow-wrap: break-word;
}
.chat-msg.is-ai .chat-msg-bubble {
  background: var(--primary-wash);
  border: 1px solid var(--primary-tint);
  border-bottom-left-radius: 5px;   /* "pinned" corner toward the mark */
  color: var(--ink);
}
.chat-msg.is-user .chat-msg-bubble {
  background: var(--ink);
  color: var(--paper-up);
  border-bottom-right-radius: 5px;
}
.chat-msg-bubble p { margin: 0; }
.chat-msg-bubble p + p { margin-top: 6px; }

/* Typing indicator (three dots) — shown while AI "thinks" */
.chat-msg.is-typing .chat-msg-bubble {
  padding: 14px 16px;
  display: inline-flex;
  gap: 4px;
  align-items: center;
}
.chat-msg.is-typing .chat-msg-bubble span {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--primary-deep);
  opacity: 0.4;
  animation: chatTyping 1.2s var(--ease-in-out) infinite;
}
.chat-msg.is-typing .chat-msg-bubble span:nth-child(2) { animation-delay: 0.15s; }
.chat-msg.is-typing .chat-msg-bubble span:nth-child(3) { animation-delay: 0.3s; }
@keyframes chatTyping {
  0%, 60%, 100% { opacity: 0.3; transform: translateY(0); }
  30% { opacity: 1; transform: translateY(-3px); }
}

/* Chips */
.chat-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 8px 16px 6px;
  border-top: 1px solid var(--line-soft);
  overflow: hidden;
  max-height: 200px;
  transition: max-height 280ms var(--ease), opacity 200ms var(--ease), padding 200ms var(--ease), border-color 200ms var(--ease);
}
.chat-chips.is-hidden {
  max-height: 0;
  opacity: 0;
  padding-top: 0;
  padding-bottom: 0;
  border-color: transparent;
}
.chat-chip {
  padding: 8px 12px;
  background: var(--paper);
  border: 1px solid var(--line);
  border-radius: 999px;
  font-size: 12.5px;
  font-weight: 500;
  color: var(--ink-soft);
  cursor: pointer;
  transition: background-color 180ms var(--ease), border-color 180ms var(--ease), color 180ms var(--ease);
  line-height: 1.25;
}
.chat-chip:hover {
  background: var(--primary-wash);
  border-color: var(--primary-tint);
  color: var(--primary-ink);
}

/* Input */
.chat-input {
  display: flex;
  align-items: flex-end;
  gap: 8px;
  padding: 10px 12px 10px 16px;
  border-top: 1px solid var(--line-soft);
  background: var(--paper-up);
}
.chat-input textarea {
  flex: 1;
  min-width: 0;
  min-height: 36px;
  max-height: 120px;
  padding: 8px 0;
  border: 0;
  background: transparent;
  resize: none;
  font-family: var(--font-body);
  font-size: 14px;
  line-height: 1.4;
  color: var(--ink);
  outline: none;
}
.chat-input textarea::placeholder { color: var(--ink-quiet); }
.chat-send {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  border-radius: 50%;
  background: var(--primary);
  color: var(--on-primary);
  display: grid;
  place-items: center;
  box-shadow: var(--lift-mint);
  transition: background 180ms var(--ease), transform 180ms var(--ease), opacity 180ms var(--ease);
  cursor: pointer;
}
.chat-send:hover { background: var(--primary-hover); transform: translateY(-1px); }
.chat-send:disabled {
  background: var(--line);
  color: var(--ink-quiet);
  box-shadow: none;
  cursor: default;
  transform: none;
}
.chat-send svg { filter: drop-shadow(0 1px 1px color-mix(in oklab, var(--primary-ink) 55%, transparent)); }
.chat-send:disabled svg { filter: none; }

.chat-disclaimer {
  margin: 0;
  padding: 8px 16px 14px;
  font-size: 11px;
  color: var(--ink-mute);
  line-height: 1.45;
  border-top: 1px solid var(--line-soft);
  background: var(--paper);
  text-align: center;
}
.chat-disclaimer a { color: var(--ink-soft); }

/* Mobile: bottom sheet that covers most of the viewport */
@media (max-width: 640px) {
  .chat-panel {
    right: 0;
    bottom: 0;
    width: 100%;
    max-width: 100%;
    height: 82dvh;
    max-height: 82dvh;
    border-radius: 20px 20px 0 0;
    border-bottom: 0;
    transform-origin: bottom center;
  }
  body.chat-open .chat-panel { transform: translateY(0); }
  .chat-panel:not(.is-anim-in) {
    transform: translateY(30px);
  }
  .chat-fab {
    padding: 14px 18px 14px 14px;
  }
  .chat-pill {
    right: 16px;
    bottom: calc(16px + env(safe-area-inset-bottom, 0px));
  }
}

@media (prefers-reduced-motion: reduce) {
  .chat-fab-halo,
  .chat-head-live,
  .chat-msg,
  .chat-msg.is-typing .chat-msg-bubble span { animation: none !important; }
}
