/* ============================================================
   Qlinic — shared stylesheet (marketing page + logged-in app)
   Monochrome + one accent color, Apple-product-page inspired.
   ============================================================ */

:root {
  --accent: #0071e3;
  --accent-dark: #0058b0;
  --chip-text: var(--accent-dark);
  --black: #1d1d1f;
  --grey-900: #2b2b2d;
  --grey-700: #4a4a4c;
  --grey-500: #86868b;
  --grey-300: #d2d2d7;
  --grey-100: #f5f5f7;
  --white: #ffffff;
  --success: #1e8e3e;
  --success-bg: #e6f4ea;
  --warning: #b26a00;
  --warning-bg: #fdf1dc;
  --danger: #c5221f;
  --danger-bg: #fce8e6;
  --whatsapp: #1fa855;
  --whatsapp-bg: #f0fbf4;
  --font: "Inter", -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", Roboto, Helvetica, Arial, sans-serif;

  /* ---- Design tokens: visual polish pass (see robust-questing-walrus.md) ---- */
  --space-1: 4px;  --space-2: 8px;  --space-3: 12px; --space-4: 16px;
  --space-5: 20px; --space-6: 24px; --space-7: 32px; --space-8: 40px; --space-9: 48px;

  --radius-sm: 8px;     /* inputs, .btn-sm, chips, dropdown menus — unchanged, matches un-tokenized 8px elements (.time-picker-trigger etc) sitewide */
  --radius-md: 14px;    /* .btn (primary/large actions) */
  --radius-lg: 20px;    /* card surfaces: .login-card, .panel, .stat-card — the "big rounded rectangle" look */
  --radius-pill: 999px; /* clock-pill, status pills, badges */

  --text-xs: 12px;   --text-sm: 13px;   --text-base: 14px; --text-md: 15px;
  --text-lg: 17px;   --text-xl: 20px;   --text-2xl: 24px;  --text-3xl: 30px;

  /* Resting elevation for card surfaces — today's shadows only fire on
     :hover, so .login-card/.panel look flat until touched. Deliberately
     bold enough to actually read as "lifted" at a glance against the
     grey-100 page background, not just technically present. */
  --shadow-resting: 0 2px 8px rgba(0, 0, 0, 0.08), 0 20px 48px rgba(0, 0, 0, 0.12);
  --shadow-hover: 0 28px 64px rgba(0, 0, 0, 0.18);
  /* Fixed dark-surface colors for floating chrome that stays dark
     regardless of the day/night toggle (the toast) — deliberately NOT the
     same variables as --black/--white/--grey-*, which flip in dark mode. */
  --dark-surface-bg: #1d1d1f;

  /* Marketing-page-only accent palette (the logged-in app keeps its single
     --accent blue; the landing page uses this wider set for use-case cards,
     feature icons, and hero decoration). */
  --mkt-teal: #0d9488;
  --mkt-teal-bg: #ccfbf1;
  --mkt-blue: #2563eb;
  --mkt-blue-bg: #dbeafe;
  --mkt-purple: #7c3aed;
  --mkt-purple-bg: #ede9fe;
  --mkt-coral: #f97316;
  --mkt-coral-bg: #ffedd5;
  --mkt-pink: #db2777;
  --mkt-pink-bg: #fce7f3;
  /* Five more, added for the Dashboard's stat-card row once it grew past
     five cards — distinct enough from the original five (and from each
     other) that a 10-card grid never has to repeat a color. */
  --mkt-indigo: #4f46e5;
  --mkt-amber: #b45309;
  --mkt-green: #15803d;
  --mkt-cyan: #0e7490;
  --mkt-rose: #be123c;
  --mkt-sky: #0369a1;
}

/* Day/Night toggle (Settings page) — a personal, local-device preference
   for the logged-in app only (reception/doctor/dashboard/settings). The
   marketing site, login/signup, and the waiting-room display board are
   intentionally unaffected: the display board's dark look is a fixed
   product/design choice for a TV screen, not a "night mode" preference. */
:root[data-theme="dark"] {
  --black: #f2f2f4;
  --grey-900: #3a3a3c;
  --grey-700: #c7c7cc;
  --grey-500: #98989d;
  --grey-300: #48484a;
  --grey-100: #232325;
  --white: #1c1c1e;
  --success-bg: rgba(30, 142, 62, 0.22);
  --warning-bg: rgba(178, 106, 0, 0.24);
  --danger-bg: rgba(197, 34, 31, 0.22);
  --mkt-teal-bg: rgba(13, 148, 136, 0.22);
  --mkt-blue-bg: rgba(37, 99, 235, 0.24);
  --mkt-purple-bg: rgba(124, 58, 237, 0.24);
  --mkt-coral-bg: rgba(249, 115, 22, 0.22);
  --mkt-pink-bg: rgba(219, 39, 119, 0.22);
  /* accent-dark's navy reads fine on the light --mkt-blue-bg chip, but
     loses too much contrast once that same background goes translucent-
     dark — needs a lighter blue for any text sitting directly on it. */
  --chip-text: #8ab4ff;

  /* Low-opacity black shadows read as invisible against a dark surface —
     brighter/more-opaque so resting elevation still shows in dark mode. */
  --shadow-resting: 0 2px 8px rgba(0, 0, 0, 0.40), 0 20px 48px rgba(0, 0, 0, 0.50);
  --shadow-hover: 0 28px 64px rgba(0, 0, 0, 0.60);
}

* { box-sizing: border-box; }

/* The browser's own calendar icon on a date input is drawn dark by
   default — invisible against a dark-mode input background otherwise. */
:root[data-theme="dark"] input[type="date"]::-webkit-calendar-picker-indicator {
  filter: invert(1);
}

html { scroll-behavior: smooth; }

body {
  margin: 0;
  font-family: var(--font);
  color: var(--black);
  background: var(--white);
  -webkit-font-smoothing: antialiased;
}

a { color: inherit; }

/* ---------------- Marketing page ---------------- */

.mkt-nav {
  position: sticky;
  top: 0;
  z-index: 50;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 18px 6vw;
  background: rgba(255, 255, 255, 0.85);
  backdrop-filter: saturate(180%) blur(14px);
  border-bottom: 1px solid var(--grey-300);
}

.mkt-nav .brand {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: -0.02em;
  text-decoration: none;
  color: var(--black);
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  transition: transform 0.15s ease;
}
.mkt-nav .brand:hover { transform: scale(1.04); }

.mkt-nav-links { display: flex; align-items: center; gap: 24px; }

/* Below ~700px the nav's five items (four links + Log in) don't fit next to
   the brand on one line -- previously an inline style with no wrap, so
   "Log in" ran off the right edge of the screen entirely. Wrapping the
   whole link group onto its own centered row fixes that without needing a
   hamburger menu for five items. */
@media (max-width: 700px) {
  .mkt-nav { flex-wrap: wrap; row-gap: 12px; }
  .mkt-nav-links { flex-wrap: wrap; justify-content: center; width: 100%; gap: 12px 20px; }
}

/* Nav links grow slightly on hover, and the current page's link gets a
   permanent underline, so the nav gives feedback instead of sitting flat. */
.mkt-nav > div > a:not(.btn) {
  position: relative;
  display: inline-block;
  transition: transform 0.15s ease, color 0.15s ease;
}
.mkt-nav > div > a:not(.btn):hover {
  transform: scale(1.1);
  color: var(--accent) !important;
}
.mkt-nav-current {
  color: var(--accent) !important;
}
.mkt-nav-current::after {
  content: '';
  position: absolute;
  left: 0;
  right: 0;
  bottom: -8px;
  height: 2px;
  background: var(--accent);
  border-radius: 2px;
}
.brand-top {
  display: flex;
  align-items: center;
}
.brand-tagline {
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0;
  color: var(--grey-500);
  margin-top: 2px;
}
/* The sidebar is much narrower than the marketing nav, so the tagline
   needs its own smaller size to stay on one line instead of wrapping. */
.app-sidebar .brand-tagline {
  font-size: 11px;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* ClinVision's nav wordmark, sitewide. Same Fraunces/weight/tracking as
   the real hero headline (.mkt-h1 inside .hero-stage) so the wordmark
   reads as the same typographic voice as the rest of the page, not a
   bolted-on logo font. */
.brand-word-wrap {
  display: inline-block;
}
.brand-word {
  display: block;
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-optical-sizing: auto;
  font-weight: 600;
  letter-spacing: -0.02em;
  color: #1e1b4b;
}
.brand-word-bar {
  display: block;
  width: 2em;
  height: 3px;
  border-radius: 2px;
  background: #c9973e;
  margin: 2px auto 5px;
}

.btn {
  display: inline-block;
  font-family: var(--font);
  font-size: var(--text-md);
  font-weight: 600;
  padding: var(--space-3) var(--space-6);
  border-radius: var(--radius-md);
  text-decoration: none;
  border: none;
  cursor: pointer;
  transition: transform 0.15s ease, background 0.15s ease, box-shadow 0.15s ease;
}

.btn-accent {
  background: var(--accent);
  color: var(--white);
}
.btn-accent:hover { background: var(--accent-dark); }

.btn-ghost {
  background: transparent;
  color: var(--black);
  border: 1px solid var(--grey-300);
}
.btn-ghost:hover { border-color: var(--black); }

.btn-whatsapp {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--white);
  color: var(--whatsapp);
  border: 1.5px solid var(--whatsapp);
}
.btn-whatsapp:hover { background: var(--whatsapp-bg); }
.btn-whatsapp svg { flex-shrink: 0; }

.btn-large {
  font-size: 18px;
  padding: 14px 32px;
}

.mkt-section {
  padding: 130px 6vw;
  max-width: 1180px;
  margin: 0 auto;
  text-align: center;
}

.mkt-section.tight { padding-top: 70px; padding-bottom: 70px; }
.mkt-section.dark {
  background: var(--black);
  color: var(--white);
  max-width: none;
  border-radius: 0;
}
.mkt-section.grey { background: var(--grey-100); max-width: none; }

/* A plain .mkt-section is capped at 1180px and centered, which is right
   for text but wrong for decoration: blobs placed inside it read as a
   visible rectangle on any screen wider than that, since the color never
   reaches the real edges of the page. Wrapping the section in this
   full-bleed container instead lets absolutely-positioned blobs spread
   across the actual viewport, while the section itself still centers its
   text content normally. */
.mkt-fullbleed { position: relative; overflow: hidden; }

/* Blobs floating anywhere in a section will eventually land behind body
   copy on some viewport width or other -- there's no fixed position that
   stays clear of text that reflows. This instead confines the color to a
   masked band pinned to the top of the section, fading to fully
   transparent well above where paragraph text starts, so paragraphs can
   never end up visually behind a blob. A slow drift keeps it from
   looking like a flat screenshot. */
.mkt-wash {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 340px;
  overflow: hidden;
  -webkit-mask-image: linear-gradient(to bottom, black 0%, black 20%, transparent 75%);
  mask-image: linear-gradient(to bottom, black 0%, black 20%, transparent 75%);
  pointer-events: none;
  z-index: 0;
}
.mkt-wash .hero-blob { animation: mkt-wash-drift 16s ease-in-out infinite alternate; }
@keyframes mkt-wash-drift {
  from { transform: translate(0, 0); }
  to { transform: translate(0, 26px); }
}

.eyebrow {
  display: inline-block;
  font-size: 14px;
  font-weight: 600;
  color: var(--accent);
  letter-spacing: 0.04em;
  text-transform: uppercase;
  margin-bottom: 18px;
}

.mkt-h1 {
  font-size: clamp(40px, 7vw, 88px);
  font-weight: 700;
  line-height: 1.05;
  letter-spacing: -0.03em;
  margin: 0 0 24px;
}

.mkt-h2 {
  font-size: clamp(30px, 4.5vw, 52px);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin: 0 0 20px;
}

.mkt-sub {
  font-size: clamp(18px, 2.2vw, 26px);
  color: var(--grey-700);
  font-weight: 400;
  max-width: 720px;
  margin: 0 auto 40px;
  line-height: 1.4;
}
.mkt-section.dark .mkt-sub { color: var(--grey-300); }

.mkt-cta-row {
  display: flex;
  gap: 16px;
  justify-content: center;
  flex-wrap: wrap;
  margin-top: 8px;
}

/* Apple-style vertical step flow (how-it-works.html) — one big
   statement per full-width section, read top to bottom rather than
   scanned as a grid. */
.step-flow-num {
  font-size: clamp(44px, 6vw, 68px);
  font-weight: 700;
  line-height: 1;
  margin-bottom: 14px;
  font-variant-numeric: tabular-nums;
}

.mkt-stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 32px;
  margin-top: 60px;
}
.mkt-stat .big { font-size: clamp(32px, 4.5vw, 52px); font-weight: 700; color: var(--accent); white-space: nowrap; }
.mkt-stat .label { font-size: 15px; color: var(--grey-500); margin-top: 6px; }
.mkt-section.dark .mkt-stat .label { color: var(--grey-300); }

.mkt-footer {
  padding: 50px 6vw;
  text-align: center;
  color: var(--grey-500);
  font-size: 13px;
  border-top: 1px solid var(--grey-300);
}
.mkt-footer a { color: var(--grey-500); text-decoration: underline; }

/* ---------------- Hero ---------------- */

.hero-preline {
  font-size: clamp(17px, 2vw, 22px);
  font-weight: 500;
  color: var(--grey-500);
  max-width: 680px;
  line-height: 1.4;
  margin: 0 auto 20px;
}
.hero-blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(50px);
  opacity: 0.4;
  z-index: 0;
}

/* ---------------- Colored eyebrows, stats, use-case cards, feature icons ---------------- */

.eyebrow-coral { color: var(--mkt-coral); }
.eyebrow-coral::before { background: var(--mkt-coral); }
.eyebrow-blue { color: var(--mkt-blue); }
.eyebrow-blue::before { background: var(--mkt-blue); }
.eyebrow-purple { color: var(--mkt-purple); }
.eyebrow-purple::before { background: var(--mkt-purple); }
.eyebrow-pink { color: var(--mkt-pink); }
.eyebrow-pink::before { background: var(--mkt-pink); }
.eyebrow-teal { color: var(--mkt-teal); }
.eyebrow-teal::before { background: var(--mkt-teal); }

.stat-teal { color: var(--mkt-teal) !important; }
.stat-coral { color: var(--mkt-coral) !important; }
.stat-purple { color: var(--mkt-purple) !important; }


.feature-icon {
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 22px;
  margin-bottom: 16px;
}
.icon-teal { background: var(--mkt-teal-bg); }
.icon-blue { background: var(--mkt-blue-bg); }
.icon-coral { background: var(--mkt-coral-bg); }
.icon-purple { background: var(--mkt-purple-bg); }
.icon-pink { background: var(--mkt-pink-bg); }

/* ---------------- Premium marketing pass ----------------
   A second, display-only typeface (Fraunces, a warm variable serif) reserved
   for headlines and big numerals across index/how-it-works/whats-inside/
   who-its-for/contact -- Inter alone at hero size reads as "template SaaS";
   Inter keeps doing every other job (nav, body copy, buttons, data) so the
   pairing stays deliberate rather than replacing the whole system. Scoped to
   these classes precisely because grep confirms .mkt-h1/.mkt-h2/.eyebrow/
   .mkt-stat/.step-flow-num are marketing-only -- no logged-in app page uses
   them, so this can't leak into the product itself. */
.mkt-h1, .mkt-h2 {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-optical-sizing: auto;
}
.mkt-stat .big, .step-flow-num {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-optical-sizing: auto;
  font-weight: 600;
}

/* A chosen, slightly warm off-white for hero-adjacent surfaces -- pure
   --white next to a serif headline read flat; this is a considered neutral,
   not the page background default (which stays --white everywhere else). */
:root { --mkt-paper: #faf8f4; }

/* Hero, v2: headline+CTA on the left, a real (illustrative, labeled)
   clinic-scene image on the right -- replaced the earlier phone/queue-card
   mockup after review found it read as exposing the actual product screen,
   and replaced abstract color blobs before that. Classes below are scoped
   under .hero-stage specifically so the entrance-sequence treatment (the
   centered eyebrow, the oversized serif lines) can't leak onto this same
   .eyebrow/.mkt-h1 markup used unstyled-by-this-block elsewhere on the page
   and on the other 4 marketing pages -- confirmed via grep that
   .hero-stage/.hero-fx/.hero-glow/.hero-line* are index.html-only. */
.hero-stage {
  position: relative;
  display: grid;
  grid-template-columns: 0.95fr 1.1fr;
  align-items: start;
  gap: 56px;
  padding: 40px 6vw 30px;
  overflow: hidden;
}
.hero-stage .content { max-width: 560px; text-align: left; }
@media (max-width: 900px) {
  .hero-stage { grid-template-columns: 1fr; text-align: center; }
  .hero-stage .content { max-width: 640px; margin: 0 auto; text-align: center; }
  .hero-stage .hero-sub { margin: 34px auto 0; }
  .hero-stage .hero-visual { order: -1; max-width: 480px; margin: 0 auto; }
}

.hero-glow {
  position: absolute;
  width: 900px;
  height: 900px;
  border-radius: 50%;
  top: -420px;
  left: 50%;
  transform: translateX(-50%);
  background: radial-gradient(circle, rgba(0, 113, 227, 0.10) 0%, rgba(0, 113, 227, 0) 68%);
  animation: hero-breathe 9s ease-in-out infinite;
  pointer-events: none;
}
@keyframes hero-breathe { 0%, 100% { transform: translateX(-50%) scale(1); } 50% { transform: translateX(-50%) scale(1.08); } }

/* Entrance sequence -- driven by JS adding .show to each element in turn
   (see the inline script at the bottom of index.html), not CSS
   animation-delay: animation-delay proved unreliable for headline spans
   on first paint in testing. This mirrors the .reveal/.visible pattern
   already used elsewhere on the site, just staged on a timer instead of
   scroll intersection. */
.hero-fx { opacity: 0; transform: translateY(20px); transition: opacity 0.6s cubic-bezier(0.19,1,0.22,1), transform 0.6s cubic-bezier(0.19,1,0.22,1); }
.hero-fx.show { opacity: 1; transform: translateY(0); }
.hero-fx.hero-fx-pop { transform: translateY(20px) scale(0.97); }
.hero-fx.hero-fx-pop.show { transform: translateY(0) scale(1); }

.hero-stage .eyebrow {
  display: flex;
  width: max-content;
  max-width: none;
  align-items: center;
  justify-content: flex-start;
  text-align: left;
  gap: 10px;
  margin-bottom: 32px;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.03em;
  color: var(--grey-700);
  padding-left: 0;
  /* Toned down so it recedes behind the headline instead of competing
     with it for attention right above three bold statements -- the
     entrance-fade .hero-fx.show rule above sets opacity:1 at the same
     specificity, so this wins on source order and becomes the eyebrow's
     actual resting opacity once shown. */
  opacity: 0.65;
}
/* The shared .eyebrow::before dot is positioned for a left-aligned label --
   left:0 reads as a stray floating dot once this one specific eyebrow is
   centered, so it's dropped here only; the flag icon already marks it. */
.hero-stage .eyebrow::before { display: none; }
.hero-flag { flex-shrink: 0; }

.hero-stage .mkt-cta-row { justify-content: flex-start; margin-top: 38px; }

/* These two overrides must stay below the base .eyebrow/.mkt-cta-row rules
   above -- both sides have equal selector specificity, so whichever comes
   later in source order wins regardless of the media query; a version of
   this block once sat above the base rules and silently never applied. */
@media (max-width: 900px) {
  .hero-stage .eyebrow { width: 100%; justify-content: center; text-align: center; }
  .hero-stage .mkt-cta-row { justify-content: center; }
}

.hero-stage .mkt-h1 { margin: 0; line-height: 1.16; font-weight: 600; letter-spacing: -0.02em; }
.hero-line { display: block; font-size: clamp(24px, 3vw, 38px); margin-bottom: 0.42em; }
.hero-line.hero-line-last { margin-bottom: 0; }
.hero-line-resolve {
  display: inline-block;
  margin-top: 0.55em;
  color: var(--accent);
  font-size: clamp(28px, 3.7vw, 46px);
  font-weight: 700;
  white-space: nowrap;
}
@media (max-width: 600px) {
  .hero-line { font-size: clamp(22px, 6vw, 30px); }
  .hero-line-resolve { font-size: clamp(26px, 7.5vw, 36px); }
}

.hero-sub {
  margin: 34px 0 0;
  font-size: clamp(16px, 1.7vw, 19px);
  color: var(--grey-700);
  line-height: 1.55;
  max-width: 520px;
  font-weight: 400;
}

/* Nudges the illustration's top edge down to the midpoint of the eyebrow's
   margin-bottom (21px eyebrow height + half of its fixed 32px
   margin-bottom = 37px) so it lines up with the gap between the eyebrow
   and the headline's first line, instead of sitting flush with the
   eyebrow's own top. Both those figures are fixed (eyebrow font-size and
   margin-bottom don't change with viewport width in this range), so this
   holds steady from 901px up. Scoped with its own min-width query rather
   than relying on source order to beat the max-width:900px block below --
   that ordering trap is exactly what silently broke the eyebrow's mobile
   centering earlier. Below 901px the image reorders above the text
   entirely (see that block's order:-1), where this offset wouldn't mean
   anything, so it's confined to widths where the two columns actually
   sit side by side. */
@media (min-width: 901px) {
  .hero-stage .hero-visual { margin-top: 37px; }
}

.hero-visual img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-hover);
}
.hero-visual-caption { margin-top: 14px; font-family: var(--font); font-size: 13px; color: var(--grey-500); text-align: center; }

/* Restored -- the earlier removal blamed this element for the dead gap,
   but the real cause was the hero's own oversized padding (fixed above).
   Now that the gap between hero and trust is tight, this sits right
   below the CTA row as intended, not stranded in empty space. */
.hero-scroll-cue {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  margin-top: 40px;
  font-family: var(--font);
  font-size: 11px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--grey-500);
}
.hero-scroll-cue .dot { width: 1px; height: 26px; background: var(--grey-300); position: relative; overflow: hidden; }
.hero-scroll-cue .dot::after { content: ''; position: absolute; top: -100%; left: 0; width: 100%; height: 100%; background: var(--grey-700); animation: hero-trickle 1.8s ease-in-out infinite; animation-delay: 3.4s; }
@keyframes hero-trickle { 0% { top: -100%; } 60% { top: 100%; } 100% { top: 100%; } }

/* Reduced motion should kill genuinely gratuitous, looping decoration
   (the ambient glow, the scroll-cue trickle) -- it should not also erase
   the one-time entrance sequence, which is meaningful content pacing,
   not a parallax/vestibular-trigger effect. */
@media (prefers-reduced-motion: reduce) {
  .hero-glow, .hero-scroll-cue .dot::after { animation: none !important; }
}

/* Trust band, v2 -- replaces the dark-surface version above. Same
   --mkt-paper canvas as the hero (no section-to-section color switch, so
   scrolling from hero into this reads as one continuous surface), side by
   side not stacked, no cards anywhere: five columns separated only by a
   hairline, each anchored by a big Fraunces numeral -- this genuinely is
   an enumerated list of five facts, so numbering carries real information
   here, not decoration. Every claim is real and checkable today (RLS
   isolation, Billing Audit, the ABDM schema work in progress, the
   existing name-search check-in flow) -- no fabricated stats, since there
   are no paying customers on record yet to quote honestly. Confirmed via
   grep that no other page uses .trust/.trust-grid/.trust-item/.trust-icon,
   so the old dark version's classes below are safely fully replaced, not
   left as orphaned dead rules alongside these. */
.trust {
  position: relative;
  background: var(--mkt-paper);
  padding: 50px 6vw 130px;
  border-top: 1px solid var(--grey-300);
  overflow: hidden;
}
.trust-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 85% 90% at 50% 45%, rgba(21, 128, 61, 0.12) 0%, rgba(21, 128, 61, 0.05) 45%, rgba(21, 128, 61, 0) 80%);
}
.trust-head { position: relative; z-index: 1; max-width: 640px; margin: 0 auto 64px; text-align: center; }
.trust-eyebrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  font-size: 18px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #3a7d55;
  margin-bottom: 18px;
}
.trust-h2 {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
  font-size: clamp(30px, 3.6vw, 44px);
  margin: 0;
  color: var(--black);
  font-optical-sizing: none;
  font-variation-settings: "opsz" 20;
}
.trust-row {
  position: relative;
  z-index: 1;
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: 0;
}
.trust-item {
  padding: 0 28px;
  text-align: left;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s cubic-bezier(0.19, 1, 0.22, 1), transform 0.6s cubic-bezier(0.19, 1, 0.22, 1);
}
.trust-item.show { opacity: 1; transform: translateY(0); }
.trust-item + .trust-item { border-left: 1px solid var(--grey-300); }
.trust-num {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  font-size: 40px;
  line-height: 1;
  color: #227a4c;
  opacity: 0.65;
  margin-bottom: 22px;
  font-variant-numeric: tabular-nums;
  font-optical-sizing: none;
  font-variation-settings: "opsz" 30;
}
.trust-lead {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--black);
  font-size: 20px;
  line-height: 1.32;
  margin: 0;
  font-optical-sizing: none;
  font-variation-settings: "opsz" 14;
}
.trust-support {
  font-family: var(--font);
  font-weight: 700;
  color: var(--grey-700);
  font-size: 14.5px;
  line-height: 1.5;
  margin: 10px 0 0;
}
@media (max-width: 1100px) {
  .trust-row { grid-template-columns: repeat(3, 1fr); row-gap: 48px; }
  .trust-item:nth-child(3n+1) { border-left: none; }
}
@media (max-width: 680px) {
  .trust-row { grid-template-columns: 1fr; row-gap: 40px; }
  .trust-item { border-left: none !important; padding: 0 4px; text-align: center; }
  .trust-num { margin-left: auto; margin-right: auto; }
}

/* Full Suite, v1: six alternating text/illustration rows on the same paper
   canvas as Trust, with a warm amber ambient glow (Trust's is green,
   the hero's is blue -- each "chapter" of the page gets its own accent
   on a shared neutral ground). Top padding deliberately kept modest
   (70px, against Trust's own 130px bottom) rather than reusing this
   mockup's original standalone 110px -- stacked on top of Trust's own
   bottom padding, 110 would have reproduced the exact "too much space
   between sections" mistake from the hero-to-trust port. Verified via
   getBoundingClientRect after shipping: gap between Trust's last row
   and this section's eyebrow is well short of the several-hundred-px
   dead zone that triggered that fix. */
.suite {
  position: relative;
  background: var(--mkt-paper);
  /* Bottom padding cut from 130px -- stacked against Compare's own
     70px top padding right below, that read as ~200px of dead space
     between the CTA row and "Without Qlinic vs With Qlinic" ("ultra
     cheap" per feedback), more than any other section-to-section seam
     on the page. */
  padding: 70px 6vw 70px;
  border-top: 1px solid var(--grey-300);
  overflow: hidden;
}
.suite-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 90% 60% at 50% 0%, rgba(180, 83, 9, 0.14) 0%, rgba(180, 83, 9, 0.05) 45%, rgba(180, 83, 9, 0) 75%);
}
.suite-head { position: relative; z-index: 1; max-width: 640px; margin: 0 auto 96px; text-align: center; }
.suite-eyebrow {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  /* Trust's own eyebrow is 18px/700 -- this one is deliberately bigger,
     not just matching it. */
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: #8a4008;
  margin-bottom: 18px;
}
.suite-h2 {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
  margin: 0;
  color: var(--black);
  font-optical-sizing: none;
  font-variation-settings: "opsz" 20;
  /* This headline runs long (65 characters) -- too long for Trust's own
     640px header column at any readable size. width:max-content lets it
     escape that cap (same trick as the hero eyebrow); the actual
     centering is done via left:50%/translateX(-50%) rather than
     margin:auto, since auto margins can't center a box that's already
     wider than its parent (that's what caused the real "pushed right of
     center" bug caught in mockup review -- margin:auto was overridden
     with a redundant max-width:100% that silently clamped the box back
     to 640px while the nowrap text overflowed past its right edge,
     unclipped and unmeasured by a plain getBoundingClientRect check on
     the box; there is no max-width here for exactly that reason). The
     2.2vw ratio is conservative on purpose: needed-width and
     available-width both scale linearly with viewport, so one ratio
     holds the line at every width from ~700px up, confirmed with a
     Range-based measurement of the actual painted text (not just the
     element's box) at 1024px and 1920px. */
  font-size: clamp(22px, 2.2vw, 34px);
  white-space: nowrap;
  width: max-content;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
}
@media (max-width: 700px) {
  /* Below 700px there's no sane font-size that keeps 65 characters on
     one line and stays readable -- let it wrap normally instead,
     matching how Trust's own (much shorter) h2 already behaves. */
  .suite-h2 {
    white-space: normal;
    width: auto;
    max-width: 100%;
    font-size: clamp(24px, 6vw, 32px);
    position: static;
    left: auto;
    transform: none;
  }
}
.suite-rows {
  position: relative;
  z-index: 1;
  max-width: 1180px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 130px;
}
.suite-row {
  display: flex;
  /* Top-aligned, not centered: centering let the shorter column (almost
     always the text block) drift below the taller one's top edge. */
  align-items: flex-start;
  gap: 40px;
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s cubic-bezier(0.19, 1, 0.22, 1), transform 0.6s cubic-bezier(0.19, 1, 0.22, 1);
}
.suite-row.show { opacity: 1; transform: translateY(0); }
.suite-row.reverse { flex-direction: row-reverse; }
.suite-row .text-col,
.suite-row .art-col {
  /* Equal flex-basis 0 + flex-grow 1 on both sides forces a strict 50/50
     split every time, so a row's illustration always lines up under the
     row above's text column and vice versa -- one consistent
     two-column skeleton, not independently-sized pairs per row. */
  flex: 1 1 0;
  min-width: 0;
}
.suite-num {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  /* Matches Trust's own big-numeral treatment (its .trust-num is 40px). */
  font-size: 44px;
  letter-spacing: 0;
  color: var(--mkt-amber);
  opacity: 0.75;
  margin-bottom: 10px;
  line-height: 1;
  font-variant-numeric: tabular-nums;
  font-optical-sizing: none;
  font-variation-settings: "opsz" 30;
}
.suite-title {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--black);
  font-size: clamp(28px, 2.8vw, 36px);
  line-height: 1.25;
  margin: 0 0 16px;
  font-optical-sizing: none;
  font-variation-settings: "opsz" 16;
}
.suite-desc {
  font-size: 19px;
  line-height: 1.6;
  color: var(--grey-700);
  margin: 0;
  max-width: 480px;
}
.art-col img {
  display: block;
  width: 100%;
  height: auto;
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-hover);
}
@media (max-width: 900px) {
  .suite-rows { gap: 90px; }
  .suite-row, .suite-row.reverse { flex-direction: column; text-align: center; }
  .suite-row .text-col, .suite-row .art-col { flex: 1 1 auto; width: 100%; }
  .suite-desc { margin-left: auto; margin-right: auto; }
}

/* Comparison, v1: "Without Qlinic vs. With Qlinic". Sits between Full
   Suite and Explore Qlinic. Top padding kept modest (70px) against Full
   Suite's own 130px bottom padding, same reasoning as Full Suite's own
   port: stacking two full paddings here would reproduce the "too much
   space between sections" mistake from the hero-to-trust port.
   Ambient glow reuses Hero's own blue (rgba(0,113,227,...)) -- without
   one, this section shared the exact same flat paper tone as Full
   Suite right above it with nothing to mark the seam between them, so
   the two blended together. Structured like Trust/Full Suite's own
   glow (an ellipse spanning the section via inset:0) rather than
   Hero's compact top-anchored circle, since this section is a full
   multi-row block like those two, not a single hero viewport. */
.compare {
  position: relative;
  background: var(--mkt-paper);
  /* Top padding cut from 70px alongside Suite's own bottom-padding cut
     just above -- see that section's comment for why. */
  padding: 50px 6vw 130px;
  border-top: 1px solid var(--grey-300);
  /* No overflow:hidden here, unlike Trust/Suite -- this section's
     intro column is position:sticky, and a clipped ancestor breaks
     sticky positioning entirely. Not needed for containment anyway:
     the glow below is inset:0, exactly the same box as this section,
     so there's nothing for it to overflow. */
}
.compare-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 90% 60% at 50% 0%, rgba(0, 113, 227, 0.14) 0%, rgba(0, 113, 227, 0.05) 45%, rgba(0, 113, 227, 0) 75%);
}
.compare-inner {
  position: relative;
  z-index: 1;
  max-width: 1400px;
  margin: 0 auto;
  display: grid;
  /* 380px, not a smaller number -- "Without Qlinic" alone needs ~342px
     at this column's largest font-size (measured via canvas during
     mockup review), so anything narrower forces it to wrap mid-phrase
     instead of breaking cleanly at the "vs." line the explicit <br>s
     intend. */
  grid-template-columns: 380px 1fr;
  gap: 56px;
  align-items: start;
}
.compare-intro { position: sticky; top: 100px; }
.compare-intro h2 {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.2;
  font-size: clamp(34px, 4.2vw, 50px);
  margin: 0 0 40px;
  color: var(--black);
  font-optical-sizing: none;
  font-variation-settings: "opsz" 20;
}
.compare-intro p {
  font-size: clamp(18px, 2vw, 22px);
  line-height: 1.65;
  color: var(--grey-700);
  margin: 0;
}

/* Two genuinely separate cards, not one shared box with a divider line --
   a real gap plus each card's own color-matched border is what actually
   reads as "two things" instead of one merged block. Built as a single
   CSS grid with subgrid rows so every row's height still comes from
   whichever side's sentence is longer (same fix as Trust's subheads),
   while each side still LOOKS like its own bordered card. */
.compare-columns {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: repeat(7, auto);
  column-gap: 40px;
}
.compare-col {
  display: grid;
  grid-template-rows: subgrid;
  grid-row: 1 / span 7;
  background: var(--white);
  border: 2px solid var(--grey-300);
  border-radius: var(--radius-lg);
  overflow: hidden;
  /* Scroll-triggered reveal, same opacity/translateY transition curve
     as Trust's items and Full Suite's rows -- this section had none
     yet, unlike everything else on the page. */
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s cubic-bezier(0.19, 1, 0.22, 1), transform 0.6s cubic-bezier(0.19, 1, 0.22, 1);
}
.compare-col.show { opacity: 1; transform: translateY(0); }
.compare-col.without { grid-column: 1; border-color: var(--danger); }
.compare-col.with { grid-column: 2; border-color: var(--success); }
.compare-head {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 700;
  font-size: 21px;
  padding: 22px 28px;
  border-bottom: 1px solid var(--grey-300);
  font-optical-sizing: none;
  font-variation-settings: "opsz" 18;
}
.compare-head.without { color: var(--danger); background: var(--danger-bg); }
.compare-head.with { color: var(--success); background: var(--success-bg); }
.compare-row {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 18px 28px;
  font-size: 17px;
  line-height: 1.5;
  color: var(--black);
  border-bottom: 1px solid var(--grey-100);
}
.compare-col > .compare-row:last-child { border-bottom: none; }
.compare-col.with .compare-text { font-weight: 600; }
.compare-icon {
  /* Bumped up from the mockup's 24px/14px -- explicit ask when porting:
     the check/cross needed to read clearly at a glance, not just be
     technically present. */
  flex-shrink: 0;
  width: 30px;
  height: 30px;
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 18px;
  font-weight: 700;
  margin-top: -1px;
}
.compare-icon.x { background: var(--danger-bg); color: var(--danger); }
.compare-icon.check { background: var(--success-bg); color: var(--success); }
@media (max-width: 900px) {
  .compare-inner { grid-template-columns: 1fr; gap: 40px; }
  .compare-intro { position: static; text-align: center; }
  /* Stacked, the two cards no longer need to share row tracks -- with
     only one column left, both cards trying to occupy the same
     grid-row: 1 / span 7 would overlap directly on top of each other.
     Drop the subgrid/shared-row setup entirely here and let each card
     flow as its own independent block instead, same as how Full Suite's
     own rows fall back to plain stacking on mobile. */
  .compare-columns { display: flex; flex-direction: column; gap: 32px; }
  .compare-col { display: block; grid-template-rows: none; grid-row: auto; }
}

/* ---------------- FAQ ---------------- */
.faq {
  position: relative;
  background: var(--mkt-paper);
  padding: 70px 6vw 130px;
  border-top: 1px solid var(--grey-300);
}
.faq-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 90% 60% at 50% 0%, rgba(0, 113, 227, 0.14) 0%, rgba(0, 113, 227, 0.05) 45%, rgba(0, 113, 227, 0) 75%);
}
.faq-inner {
  position: relative;
  z-index: 1;
  max-width: 1200px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: 340px 1fr;
  gap: 64px;
  align-items: start;
}
.faq-heading {
  position: sticky;
  top: 100px;
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
  font-size: clamp(34px, 4.2vw, 50px);
  margin: 0;
  color: var(--black);
  font-optical-sizing: none;
  font-variation-settings: "opsz" 20;
}
.faq-list { display: flex; flex-direction: column; border-top: 1px solid var(--grey-300); }
.faq-item { border-bottom: 1px solid var(--grey-300); }
.faq-question {
  display: flex;
  width: 100%;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  padding: 24px 4px;
  background: none;
  border: none;
  text-align: left;
  font-family: var(--font);
  font-size: 18px;
  font-weight: 600;
  color: var(--black);
  cursor: pointer;
}
.faq-chevron {
  flex-shrink: 0;
  width: 20px;
  height: 20px;
  color: var(--grey-500);
  transition: transform 0.3s ease, color 0.3s ease;
}
.faq-item.open .faq-chevron { transform: rotate(180deg); color: var(--accent); }
.faq-answer { max-height: 0; overflow: hidden; transition: max-height 0.3s ease; }
.faq-answer-inner { padding: 0 4px 24px; font-size: 16px; line-height: 1.65; color: var(--grey-700); max-width: 680px; }
@media (max-width: 900px) {
  .faq-inner { grid-template-columns: 1fr; gap: 32px; }
  .faq-heading { position: static; text-align: center; }
}

/* ---------------- Final CTA band ---------------- */
.final-cta {
  position: relative;
  background: var(--mkt-paper);
  padding: 110px 6vw;
  border-top: 1px solid var(--grey-300);
}
.final-cta-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 90% 60% at 50% 0%, rgba(0, 113, 227, 0.14) 0%, rgba(0, 113, 227, 0.05) 45%, rgba(0, 113, 227, 0) 75%);
}
.final-cta-inner { position: relative; z-index: 1; max-width: 1180px; margin: 0 auto; }
.final-cta h2 {
  /* Same family/weight as the FAQ heading (Fraunces, 600, not 700) --
     "large font, not bold" per feedback, matching Razorpay's own
     reference where the closing headline is big but not heavy.
     Capped a bit lower than the hero's own 88px max -- "reduce the
     font a little" feedback after seeing it at full width. */
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
  font-size: clamp(38px, 6vw, 76px);
  margin: 0 0 32px;
  color: var(--black);
  font-optical-sizing: none;
  font-variation-settings: "opsz" 20;
}
/* Sitewide .btn-large (18px/14px 32px, used everywhere else) reads as
   tiny next to an 88px headline -- this section's button gets its own
   scaled-up size so it complements the heading instead of looking like
   an afterthought underneath it. */
.final-cta .btn { font-size: 22px; padding: 20px 44px; }
@media (max-width: 900px) {
  .final-cta { text-align: center; }
}

/* ---------------- Explore Qlinic ----------------
   Restyled off its old flat grey block onto the same paper+glow pattern
   as every other section. Purple, not blue -- Hero, Compare, FAQ, and
   the Final CTA band are already all blue, and this section sits right
   in the middle of that run (Compare -> Explore -> FAQ -> Final CTA),
   so a blue glow here would have made four sections in a row the same
   color. Purple was already in the palette and already used on this
   section's own "What's inside" icon before this restyle, so it ties
   back rather than introducing a new hue cold. */
.explore {
  position: relative;
  background: var(--mkt-paper);
  padding: 100px 6vw 130px;
  border-top: 1px solid var(--grey-300);
  overflow: hidden;
}
.explore-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 85% 70% at 50% 0%, rgba(124, 58, 237, 0.13) 0%, rgba(124, 58, 237, 0.05) 45%, rgba(124, 58, 237, 0) 75%);
}
.explore-head { position: relative; z-index: 1; max-width: 640px; margin: 0 auto 64px; text-align: center; }
.explore-eyebrow {
  font-size: 20px;
  font-weight: 700;
  letter-spacing: 0.03em;
  text-transform: uppercase;
  color: var(--mkt-purple);
  margin-bottom: 18px;
}
.explore-h2 {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  letter-spacing: -0.02em;
  line-height: 1.15;
  font-size: clamp(30px, 3.6vw, 44px);
  margin: 0;
  color: var(--black);
  font-optical-sizing: none;
  font-variation-settings: "opsz" 20;
}
.explore-grid {
  position: relative;
  z-index: 1;
  max-width: 1180px;
  margin: 0 auto;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 28px;
}
.explore-card {
  background: var(--white);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-lg);
  padding: 38px 34px 34px;
  display: flex;
  flex-direction: column;
  /* Scroll-triggered reveal, staggered per card -- same pattern as the
     Comparison section's two columns. */
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 0.6s cubic-bezier(0.19, 1, 0.22, 1), transform 0.6s cubic-bezier(0.19, 1, 0.22, 1), box-shadow 0.2s ease, border-color 0.2s ease;
}
.explore-card.show { opacity: 1; transform: translateY(0); }
.explore-card:hover { box-shadow: 0 16px 36px rgba(124, 58, 237, 0.12); border-color: #d8c8fb; }
.explore-card-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 26px;
}
/* Razorpay's own card pattern: the product name sits small and plain up
   top -- it's a label, not the point -- while the sentence underneath
   carries the actual claim, so that's the one built bold. Inverts this
   card's own previous weighting (bold h3 / plain p). */
.explore-label {
  font-size: 18px;
  font-weight: 500;
  color: var(--grey-700);
  letter-spacing: -0.01em;
  line-height: 1;
}
.explore-icon {
  flex-shrink: 0;
  width: 44px;
  height: 44px;
  border-radius: 11px;
  background: var(--mkt-purple-bg);
  color: var(--mkt-purple);
  display: flex;
  align-items: center;
  justify-content: center;
}
.explore-icon svg { width: 22px; height: 22px; display: block; }
.explore-lead {
  font-size: 21px;
  font-weight: 700;
  letter-spacing: -0.01em;
  line-height: 1.45;
  color: var(--black);
  margin: 0 0 26px;
  flex: 1;
}
.explore-lead .hl { color: var(--mkt-purple); }
.explore-link {
  font-size: 16px;
  font-weight: 600;
  color: var(--mkt-purple);
  text-decoration: none;
  display: inline-block;
  transition: transform 0.15s ease;
}
.explore-link:hover { text-decoration: underline; transform: scale(1.06); }
@media (max-width: 900px) {
  .explore-grid { grid-template-columns: 1fr; }
}

/* ---------------- Shared colorful accents (used across every logged-in page) ----------------
   Same 5-color palette as the landing page, applied consistently: each doctor
   gets a stable color (by their position in the doctors list) shown as a top
   border wherever their queue is referenced, so "this doctor's stuff" reads
   the same way on reception, the doctor view, and the waiting-room board.
   Semantic status colors (success/warning/danger badges, status pills) are
   untouched — this palette is identity/category color, not meaning. */

.panel.accent-teal { border-top: 4px solid var(--mkt-teal); }
.panel.accent-blue { border-top: 4px solid var(--mkt-blue); }
.panel.accent-purple { border-top: 4px solid var(--mkt-purple); }
.panel.accent-coral { border-top: 4px solid var(--mkt-coral); }
.panel.accent-pink { border-top: 4px solid var(--mkt-pink); }
.panel.accent-danger { border-top: 4px solid var(--danger); }

/* Stat cards use a left bar instead of a top stripe — same per-metric
   color mapping, just moved to the reading edge so it reads as a clear
   marker rather than a thin line easy to miss above the number. */
.stat-card.accent-teal { border-left: 4px solid var(--mkt-teal); }
.stat-card.accent-blue { border-left: 4px solid var(--mkt-blue); }
.stat-card.accent-purple { border-left: 4px solid var(--mkt-purple); }
.stat-card.accent-coral { border-left: 4px solid var(--mkt-coral); }
.stat-card.accent-pink { border-left: 4px solid var(--mkt-pink); }
.stat-card.accent-danger { border-left: 4px solid var(--danger); }
.stat-card.accent-indigo { border-left: 4px solid var(--mkt-indigo); }
.stat-card.accent-amber { border-left: 4px solid var(--mkt-amber); }
.stat-card.accent-green { border-left: 4px solid var(--mkt-green); }
.stat-card.accent-cyan { border-left: 4px solid var(--mkt-cyan); }
.stat-card.accent-rose { border-left: 4px solid var(--mkt-rose); }
.stat-card.accent-sky { border-left: 4px solid var(--mkt-sky); }
/* A unit label inline with a stat card's big number (e.g. "3 patients in
   queue") — smaller and lighter than .value so it doesn't compete with
   the number itself. */
.stat-unit { font-size: 13px; font-weight: 500; color: var(--grey-500); }

.value-teal { color: var(--mkt-teal); }
.value-blue { color: var(--mkt-blue); }
.value-purple { color: var(--mkt-purple); }
.value-coral { color: var(--mkt-coral); }
.value-pink { color: var(--mkt-pink); }
.value-danger { color: var(--danger); }

/* flex-wrap so a panel-header that grows a variable-width middle item
   (Revenue/Directory's active-filter-chips row) wraps to a second line
   on a narrow viewport instead of forcing Reset filters off-screen. */
.panel-header { display: flex; align-items: center; gap: 12px; margin-bottom: 16px; flex-wrap: wrap; }
.panel .panel-header h2 { margin: 0; }

.board-doc-dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  margin-right: 6px;
  vertical-align: middle;
}
.dot-teal { background: var(--mkt-teal); }
.dot-blue { background: var(--mkt-blue); }
.dot-purple { background: var(--mkt-purple); }
.dot-coral { background: var(--mkt-coral); }
.dot-pink { background: var(--mkt-pink); }

/* ---------------- Login page ---------------- */

.login-wrap {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  background: var(--grey-100);
  padding: 24px;
  position: relative;
  overflow: hidden;
}

.login-blob {
  position: absolute;
  border-radius: 50%;
  filter: blur(55px);
  opacity: 0.4;
  z-index: 0;
}
.login-blob-teal { width: 280px; height: 280px; background: var(--mkt-teal); top: -70px; left: -70px; }
.login-blob-coral { width: 240px; height: 240px; background: var(--mkt-coral); bottom: -60px; right: -50px; }
.login-blob-purple { width: 200px; height: 200px; background: var(--mkt-purple); bottom: 60px; left: -60px; }

.login-card {
  position: relative;
  z-index: 1;
  background: var(--white);
  border: 1px solid var(--grey-300);
  border-radius: 24px;
  box-shadow: var(--shadow-resting);
  padding: 64px 56px;
  width: 100%;
  max-width: 480px;
}

/* The auth-card family (login/signup/forgot-reset-password/queue-status)
   is the one page context with nothing else competing for space, so it
   gets its own bigger scale on top of the shared .field/.btn tokens
   rather than bumping those tokens globally (which would also inflate
   every dense in-app form). Scoped to .login-card so it doesn't touch
   any other page using the same .field/.btn classes. */
.login-card .field { margin-bottom: 12px; }
.login-card .field label { font-size: 14px; margin-bottom: 8px; }
.login-card .field input, .login-card .field select { padding: 16px 18px; font-size: 17px; }
.login-card .btn { padding: 17px 28px; font-size: 17px; border-radius: 16px; }
.login-card .login-hint { font-size: 14px; margin-top: 26px; }
.login-card .login-error { font-size: 14px; }

/* queue.html only — wider than the auth-card default so the merged
   appointment sentence has room to breathe instead of wrapping tightly. */
.login-card-wide { max-width: 560px; }

/* queue.html's redesigned status card: clinic identity now leads (big,
   bold) instead of small grey caps, the doctor/appointment context is
   one sentence instead of three stacked lines, and "currently being
   served" gets its own bordered, tinted cell — big enough to actually
   read at a glance, with the time it was called so someone at home has
   a sense of how long that consult has been running. */
.queue-clinic-name { text-align: center; font-size: 22px; font-weight: 700; letter-spacing: -0.01em; margin-bottom: 10px; }
.queue-appt-line { text-align: center; font-size: 15.5px; font-weight: 600; line-height: 1.45; margin-bottom: 10px; }
/* The status a patient checks most anxiously deserves to read as a
   fact, not a footnote — a solid pill instead of plain text. */
.queue-status-msg { text-align: center; margin-bottom: 14px; }
.queue-status-msg .pill {
  display: inline-block; font-size: 13.5px; font-weight: 700; color: var(--chip-text);
  background: var(--mkt-blue-bg); padding: 7px 16px; border-radius: var(--radius-pill);
}
.queue-status-msg.is-waiting .pill { color: var(--warning); background: var(--warning-bg); }
/* Plain grey italic was too easy to skim past for a line worth actually
   reading — accent blue instead, still calm (not a warning color), but
   with real contrast against white. */
.queue-advisory { margin-top: 10px; text-align: center; }
.queue-advisory .text { font-size: 14px; color: var(--chip-text); line-height: 1.4; font-weight: 600; font-style: italic; }
.queue-doctor-status {
  text-align: center; font-size: 13.5px; font-weight: 600; color: var(--warning);
  background: var(--warning-bg); border-radius: var(--radius-sm);
  padding: 8px 12px; margin-bottom: 16px; line-height: 1.4;
}
/* The doctor's own typed reason ("Going out for an emergency") sits
   inside the templated sentence above — set apart in the page's plain
   text color instead of the surrounding amber, so it reads as a direct
   quote from the doctor rather than more system-generated copy. */
.queue-doctor-status .doc-note-quote { color: var(--black); font-weight: 700; font-style: italic; }
/* Patient-facing language toggle, reusing doctor.html's filter-seg pill
   control so the same "pick one" pattern feels familiar everywhere it
   shows up in the product. Pinned into the card's own top-right padding
   (login-card already reserves 64px/56px there) instead of taking its
   own full-width row, so it costs the page nothing - the very thing
   that made a short viewport need to scroll before reaching content. */
.lang-toggle-wrap { position: absolute; top: 22px; right: 24px; z-index: 2; }
.lang-toggle-wrap .filter-seg { margin-bottom: 0; padding: 2px; }
.lang-toggle-wrap .filter-seg button { padding: 5px 12px; font-size: 11.5px; }
.queue-nowserving-cell {
  border: 1.5px solid var(--accent); background: var(--mkt-blue-bg);
  border-radius: var(--radius-md); padding: 14px 16px; text-align: center; margin-bottom: 16px;
}
.queue-nowserving-eyebrow { font-size: 11px; font-weight: 700; color: var(--chip-text); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 6px; }
.queue-nowserving-num { font-size: 34px; font-weight: 700; color: var(--chip-text); line-height: 1.1; }
.queue-nowserving-meta { font-size: 12.5px; color: var(--grey-700); margin-top: 4px; }

/* Doctor View's "Today's full schedule" modal: Active/Booked/Done tabs
   so the doctor never has to scroll past a morning's worth of Done
   patients to see who's actually waiting right now. */
.filter-seg { display: inline-flex; background: var(--grey-100); border-radius: var(--radius-pill); padding: 3px; gap: 2px; margin-bottom: 16px; }
.filter-seg button {
  font-family: var(--font); font-size: 13px; font-weight: 700; color: var(--grey-700);
  background: transparent; border: none; padding: 8px 16px; border-radius: var(--radius-pill); cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
}
.filter-seg button.active { background: var(--white); color: var(--accent-dark); box-shadow: var(--shadow-resting); }
.filter-seg .count { font-size: 11px; font-weight: 800; background: var(--grey-300); color: var(--white); border-radius: var(--radius-pill); padding: 1px 7px; }
.filter-seg button.active .count { background: var(--accent); }

/* Analytics' own group tabs (Revenue/Patients/Scheduling/...) - scoped by
   id rather than changed on .filter-seg itself, since that class is
   shared with Doctor View's schedule-modal tabs and the language toggle,
   neither of which asked for this treatment. A gradient active pill
   (instead of .filter-seg's flat white) and a raised track make this
   read as the page's primary navigation, not just another filter. */
/* Spans the full width instead of sitting compact near the left edge -
   each button keeps its own natural, single-line width (white-space:
   nowrap) and the extra room is spent as space-between gaps, not by
   stretching any one label's box (a flex:1 approach was tried first but
   force-equal-width columns made the longer labels below wrap to two
   lines). */
#trendGroupSeg {
  display: flex; justify-content: space-between; width: 100%;
  background: linear-gradient(180deg, var(--grey-100), var(--white));
  border: 1px solid var(--grey-300); border-radius: var(--radius-pill); padding: 4px; gap: 2px;
  margin-bottom: 20px; box-shadow: var(--shadow-resting), inset 0 1px 0 rgba(255, 255, 255, 0.5);
}
#trendGroupSeg button {
  font-family: var(--font); font-size: 13.5px; font-weight: 700; letter-spacing: 0.01em; color: var(--grey-700);
  background: transparent; border: 1.5px solid transparent; padding: 9px 18px; border-radius: var(--radius-pill); cursor: pointer;
  white-space: nowrap;
  transition: background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
#trendGroupSeg button:hover:not(.active) { color: var(--accent-dark); }
/* Crisp white outline around the active pill - picked over a glossy
   highlight/self-tone edge/glow-ring alternative (see gradient-pill-
   border-options mockup) as the clearest of the four at a glance. Base
   button already reserves a 1.5px transparent border so this doesn't
   shift the pill's size when it activates. */
#trendGroupSeg button.active {
  background: linear-gradient(135deg, var(--accent), var(--accent-dark)); color: var(--white);
  border-color: rgba(255, 255, 255, 0.9); box-shadow: 0 3px 10px rgba(0, 113, 227, 0.35);
}

/* Booking load chart, inside the schedule modal's Booked tab only -
   one hue (a sky-to-brand-blue gradient) throughout, current hour marked
   with an outline rather than a second clashing color. */
.chart-block {
  background: var(--white); border: 1px solid var(--grey-100); border-radius: var(--radius-md);
  padding: 18px 20px 14px; margin-bottom: 18px; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
}
.chart-hero { display: flex; align-items: flex-end; justify-content: space-between; gap: 14px; }
.chart-eyebrow {
  font-size: 10.5px; font-weight: 800; letter-spacing: 0.07em; text-transform: uppercase;
  color: var(--grey-500); margin-bottom: 5px;
}
.chart-stat-num {
  font-size: 34px; font-weight: 800; color: var(--black); line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: -0.01em;
}
.chart-hero-caption { text-align: right; font-size: 12.5px; color: var(--grey-700); line-height: 1.55; max-width: 220px; }
.chart-hero-caption .muted { color: var(--grey-500); font-size: 11.5px; }
.chart-divider { border: none; border-top: 1px solid var(--grey-100); margin: 14px 0 12px; }
.chart-subhead { display: flex; align-items: center; justify-content: space-between; margin-bottom: 8px; }
.chart-subhead .label { font-size: 12px; font-weight: 700; color: var(--grey-700); }
.now-chip {
  font-size: 11px; font-weight: 700; color: var(--accent-dark);
  background: rgba(0, 113, 227, 0.1); border-radius: var(--radius-pill); padding: 3px 10px;
  display: inline-flex; align-items: center; gap: 5px;
}
.now-chip .dot { width: 5px; height: 5px; border-radius: 50%; background: var(--accent-dark); }
.chart-canvas-wrap { position: relative; height: 128px; }
.chart-note { font-size: 11.5px; font-style: italic; color: var(--grey-500); margin: 10px 2px 0; }

/* Smaller and outlined so it reads as a tappable action next to the
   now-serving cell, not another filled info panel the same shape. */
.queue-details-btn {
  font-family: var(--font); font-size: 13px; font-weight: 700; color: var(--accent);
  background: var(--white); border: 1.5px solid var(--accent); border-radius: var(--radius-pill);
  padding: 8px 18px; cursor: pointer;
}
.queue-nearby-heading { text-align: center; font-size: 16px; font-weight: 800; margin-bottom: 10px; }
.queue-nearby-sub { text-align: center; font-weight: 400; color: var(--grey-500); font-size: 13px; line-height: 1.5; margin: 8px 0 0; }
/* Replaces the old "Updated hh:mm:ss" timestamp with a heartbeat —
   matches the same live indicator inside the queue-details popup, so
   both read as one consistent "this is live" language on the page. */
.queue-live-line { display: flex; align-items: center; justify-content: center; gap: 6px; font-size: 13px; font-weight: 700; color: var(--success); margin-top: 20px; }
.queue-live-line .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--success); animation: queue-pulse 1.4s infinite; }
@keyframes queue-pulse { 0%, 100% { opacity: 1; } 50% { opacity: 0.25; } }

/* Queue-details popup: same confirmDialog/modal-card look used
   elsewhere in the app, plus a 3-up stat grid for the scoped counts. */
.queue-details-scope { font-size: 13px; color: var(--grey-700); line-height: 1.5; margin: 0 0 16px; }
.queue-details-live { display: inline-flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 700; color: var(--success); margin-bottom: 18px; }
.queue-details-live .dot { width: 6px; height: 6px; border-radius: 50%; background: var(--success); animation: queue-pulse 1.4s infinite; }
.queue-stat-grid { display: grid; grid-template-columns: 1fr 1fr 1fr; gap: 10px; }
.queue-stat-cell { text-align: center; background: var(--white); border: 1px solid var(--grey-300); border-radius: var(--radius-md); padding: 14px 6px; }
.queue-stat-cell .num { font-size: 26px; font-weight: 800; color: var(--black); line-height: 1.1; }
.queue-stat-cell .label { font-size: 11px; font-weight: 600; color: var(--grey-700); text-transform: uppercase; letter-spacing: 0.02em; margin-top: 6px; line-height: 1.35; }
.queue-stat-cell.arrived { border-color: var(--success); background: var(--success-bg); }
.queue-stat-cell.arrived .num { color: var(--success); }
.queue-stat-cell.notyet { border-color: var(--warning); background: var(--warning-bg); }
.queue-stat-cell.notyet .num { color: var(--warning); }

/* queue.html's visit-complete screen: a gradient banner (cancels out
   .login-card-wide's own padding via negative margins to go full-bleed)
   instead of a plain white background with a pale, easy-to-miss struck-
   through token. Same structure doubles for no-show via .is-noshow,
   just muted (amber, not celebratory green) since that isn't good news. */
.queue-done-banner {
  margin: -64px -56px 0; padding: 34px 40px 40px;
  background: linear-gradient(135deg, var(--mkt-teal), var(--accent));
  border-radius: 24px 24px 0 0;
  text-align: center; position: relative;
}
.queue-done-banner.is-noshow { background: linear-gradient(135deg, var(--warning), var(--mkt-coral)); }
.queue-done-clinic { color: rgba(255, 255, 255, 0.85); font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; }
.queue-done-check {
  width: 64px; height: 64px; border-radius: 50%; background: var(--white);
  display: flex; align-items: center; justify-content: center; font-size: 32px;
  margin: 16px auto -52px; box-shadow: var(--shadow-resting); position: relative; z-index: 2;
}
.queue-done-body { padding-top: 60px; text-align: center; }
.queue-done-headline { font-size: 24px; font-weight: 700; margin: 0 0 10px; }
.queue-done-sub { font-size: 15px; color: var(--grey-700); line-height: 1.6; margin: 0; }
.queue-done-token {
  margin: 22px auto; display: inline-flex; flex-direction: column; align-items: center; gap: 6px;
  background: var(--success-bg); border-radius: var(--radius-md); padding: 16px 32px;
}
.queue-done-banner.is-noshow ~ .queue-done-body .queue-done-token { background: var(--warning-bg); }
.queue-done-token .label { font-size: 13px; font-weight: 700; color: var(--success); text-transform: uppercase; letter-spacing: 0.03em; }
.queue-done-banner.is-noshow ~ .queue-done-body .queue-done-token .label { color: var(--warning); }
.queue-done-token .num { font-size: 38px; font-weight: 800; color: var(--success); text-decoration: line-through; text-decoration-thickness: 3px; text-decoration-color: var(--danger); }
.queue-done-banner.is-noshow ~ .queue-done-body .queue-done-token .num { color: var(--warning); }
.queue-done-footer { text-align: center; font-size: 14px; color: var(--grey-500); margin: 18px 0 0; padding-top: 16px; border-top: 1px solid var(--grey-100); }

/* Registration has 10 fields (address split into 3 rows) where every
   other login-card page has 1-4, so it alone gets a denser tier on top
   of the shared login-card scale — not applied to login/forgot/reset,
   which don't have a scrolling problem to solve. Reuses the app's own
   base .field-input tier (12px/16px padding, 15px font) rather than
   inventing new numbers. */
.login-card.login-card-compact { padding: 48px 48px; }
.login-card.login-card-compact .field { margin-bottom: 10px; }
.login-card.login-card-compact .field label { font-size: 13px; margin-bottom: 6px; }
.login-card.login-card-compact .field input, .login-card.login-card-compact .field select {
  padding: 11px 14px;
  font-size: 15px;
}
.login-card.login-card-compact .btn { padding: 12px 24px; font-size: 15px; border-radius: var(--radius-md); }
/* Every other page (marketing nav, app sidebar) shows the ticking clock
   icon and tagline next to "Qlinic" in the top-left corner of the page,
   not inside the content card itself — the auth pages get the same
   treatment: a corner brand mark over the login-wrap, left-aligned,
   with the card below starting directly at its own heading. */
.login-brand-corner {
  position: absolute;
  top: 28px;
  left: 32px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  text-decoration: none;
}
.login-brand-corner .brand-top {
  font-size: 19px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--black);
}
.login-brand-corner .brand-clock {
  width: 22px;
  height: 22px;
  margin-right: 8px;
}
.login-brand-corner .brand-tagline {
  font-size: 13px;
  margin-top: 2px;
}
/* On a narrow/short viewport the card grows nearly full-bleed (see
   .login-wrap's padding:24px), so a fixed top-left corner mark would sit
   underneath it. Drop out of absolute positioning back into normal flow,
   centered above the card, rather than overlapping or disappearing. */
@media (max-width: 480px) {
  .login-wrap { flex-direction: column; }
  .login-brand-corner {
    position: static;
    align-items: center;
    margin-bottom: 16px;
  }
}

.login-card h1 {
  font-size: 24px;
  font-weight: 600;
  text-align: center;
  margin: 0 0 36px;
  color: var(--grey-700);
}

.field { margin-bottom: 18px; }
.field label {
  display: block;
  font-size: 13px;
  font-weight: 600;
  color: var(--grey-700);
  margin-bottom: 6px;
}
.field input, .field select {
  background: var(--white);
  color: var(--black);
}
.field input, .field select {
  width: 100%;
  box-sizing: border-box;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-md);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-family: var(--font);
}
.field input:focus, .field select:focus { outline: 2px solid var(--accent); border-color: var(--accent); }

/* Inline "ghost text" autocomplete: the real input sits on top with a
   transparent background so the suggestion (rendered by a second,
   identically-padded/sized element positioned directly underneath)
   shows through in the space after what's actually been typed. The
   typed-so-far portion of the ghost text is present but invisible —
   it's there only to push the suggestion to line up exactly where the
   real caret is, not to be seen. */
.autocomplete-wrap { position: relative; }
.autocomplete-wrap input {
  position: relative;
  z-index: 1;
  background: transparent;
}
.autocomplete-ghost {
  position: absolute;
  inset: 0;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-md);
  font-family: var(--font);
  border: 1px solid transparent;
  box-sizing: border-box;
  white-space: pre;
  overflow: hidden;
  pointer-events: none;
}
.autocomplete-ghost .typed { visibility: hidden; }
.autocomplete-ghost .suggestion { color: var(--grey-500); }

/* A bare .field select (not inside .inline-form/.form-grid, which
   already style their own selects) previously fell through to only
   background/color above and rendered with the browser's default select
   chrome — no padding, tiny font, thin border — visibly out of place
   next to the text inputs beside it. Custom chevron matches the one
   already used on Revenue's filters. */
.field select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  cursor: pointer;
  padding-right: 36px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%234a4a4c' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 13px;
}
:root[data-theme="dark"] .field select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23c7c7cc' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}

/* Fee fields are typed amounts, not counters, so the browser's default
   step-by-1 spinner arrows are more clutter than help. */
input[type="number"]::-webkit-outer-spin-button,
input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}
input[type="number"] { -moz-appearance: textfield; }

/* Browsers render autofilled/saved-password field values with their own
   font and a tinted background by default, which clashes with the site's
   font until the field is edited. Forcing these keeps the font (and
   background) consistent whether the value was typed or autofilled. */
.field input:-webkit-autofill,
.field input:-webkit-autofill:hover,
.field input:-webkit-autofill:focus,
.field input:-webkit-autofill:active {
  -webkit-text-fill-color: var(--black) !important;
  -webkit-box-shadow: 0 0 0px 1000px var(--white) inset !important;
  box-shadow: 0 0 0px 1000px var(--white) inset !important;
  font-family: var(--font) !important;
  font-size: 15px !important;
  font-weight: 400 !important;
  caret-color: var(--black);
  transition: background-color 9999s ease-in-out 0s !important;
}

.login-hint {
  margin-top: 18px;
  font-size: 13px;
  color: var(--grey-500);
  background: var(--grey-100);
  border-radius: 10px;
  padding: 12px 14px;
  line-height: 1.5;
}
.login-hint a { color: var(--accent); font-weight: 700; text-decoration: underline; }
.login-hint a:hover { color: var(--accent-dark); }

.login-error {
  color: var(--danger);
  font-size: 13px;
  margin-bottom: 14px;
  display: none;
}

/* ---------------- Auth pages (login / signup / forgot / reset password) ----------------
   Razorpay-inspired two-pane layout, scoped under its own .auth-*
   classes rather than touching .login-wrap/.login-blob/.login-card
   above -- queue.html and account-suspended.html still use those for
   their own single-card layouts, untouched by this redesign. */
.auth-shell { position: relative; display: flex; min-height: 100vh; }

/* fixed, not absolute -- it overlays the sticky illustration pane
   above, and on signup.html's much taller page, absolute (positioned
   against .auth-shell, which scrolls with the document) would have
   scrolled it away from that pane after the first 28px, while the pane
   itself stayed pinned. Fixed keeps both stuck to the viewport together. */
.auth-corner-brand {
  position: fixed;
  top: 28px;
  left: 32px;
  z-index: 5;
  display: flex;
  /* Column now that there's no icon sitting beside the wordmark --
     word and tagline stack, same as every other page's brand corner. */
  flex-direction: column;
  align-items: flex-start;
  text-decoration: none;
}
.auth-corner-brand .brand-word { font-size: 19px; }
.auth-corner-brand .tagline { font-size: 13px; color: var(--grey-500); margin-top: 2px; }

/* Ambient glow reuses the exact hero-glow blue rather than inventing a
   new color, so these pages don't feel like a different product from
   the marketing site behind them. Ends on a still-tinted blue, never
   fading to white, so the seam with the white form pane on the right
   reads as a real edge instead of one wash bleeding into the other. */
/* sticky + height:100vh, not just position:relative -- signup.html's
   form runs well past one viewport tall, and without this the
   illustration pane (a flex sibling) stretched to match that full
   scroll height, leaving its own centered content stranded partway
   down a much taller box instead of centered on screen like the other
   three (shorter) auth pages. Pinning it to the viewport keeps it
   looking the same everywhere regardless of how tall the form next to
   it grows. Reset back to normal flow in the 900px mobile stack below,
   where it's a compact banner above the form, not a fixed-height pane
   beside it. */
.auth-illustration {
  position: sticky;
  top: 0;
  height: 100vh;
  flex: 1 1 66%;
  background: linear-gradient(160deg, #dceafc 0%, #eaf3fd 55%, #eaf3fd 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  padding: 60px;
}
.auth-glow {
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(ellipse 70% 60% at 50% 30%, rgba(0, 113, 227, 0.18) 0%, rgba(0, 113, 227, 0.06) 45%, rgba(0, 113, 227, 0) 75%);
}
/* Black base with a moving light band clipped to the text itself
   ("diamond shines" per feedback) rather than a static color -- the
   gradient's own stops carry the color, so background-clip:text
   doubles as both the black fill and the sweeping highlight in one
   property instead of layering a separate glow effect on top. */
.auth-headline {
  position: relative;
  z-index: 1;
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 700;
  font-size: clamp(44px, 4.8vw, 62px);
  line-height: 1.22;
  letter-spacing: -0.01em;
  text-align: center;
  max-width: 480px;
  /* Narrower band, and its peak is a mid-grey (#6b6b6f) rather than
     near-white -- the previous white/near-white peak washed a big
     chunk of a 3-line headline out to the point of being unreadable
     against the light background. Grey keeps every word legible at
     every point in the sweep, just visibly brighter as it passes. */
  background: linear-gradient(110deg, #1d1d1f 44%, #6b6b6f 50%, #1d1d1f 56%);
  background-size: 220% 100%;
  background-position: 200% 0;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  /* will-change hints the browser to keep this on its own compositing
     layer up front, rather than deciding dynamically whether a
     background-position animation is "worth" promoting -- without it,
     browsers sometimes demote it back to the main thread mid-session
     under other page work, which reads as the effect stalling and
     restarting rather than running continuously. alternate (playing
     the keyframes forward then in reverse, not jumping back to the
     start) is what actually keeps the sweep's speed and direction
     consistent loop to loop -- forward ends where reverse begins, so
     there's no snap at the loop boundary either. */
  will-change: background-position;
  animation: auth-headline-shine 9s ease-in-out infinite alternate;
}
@keyframes auth-headline-shine {
  0%, 25% { background-position: 200% 0; }
  75%, 100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .auth-headline { animation: none; background-position: 0 0; }
}

/* Flat white, no separate bordered card inside it -- the pane itself
   reads as the card, matching Razorpay's own right column. border-left
   + a soft shadow give the two panes a real seam ("looks inseparable"
   was the exact complaint against an earlier pass without them). */
.auth-form-pane {
  position: relative;
  z-index: 1;
  flex: 1 1 34%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 48px;
  background: var(--white);
  border-left: 1px solid var(--grey-300);
  box-shadow: -24px 0 48px rgba(0, 0, 0, 0.04);
}
/* signup.html's form runs to 9+ fields (address split into building/
   area/landmark, city/state, phone, logo upload) and was briefly given
   its own wider 50/50 pane for breathing room -- reverted per explicit
   feedback: every auth page uses the identical 66/34 split and 420px
   form column, full stop, rather than one page looking different from
   the other three. */
.auth-form-inner { width: 100%; max-width: 420px; }

.auth-eyebrow { font-size: 20px; font-weight: 600; color: var(--grey-500); margin-bottom: 8px; }
.auth-eyebrow b { color: var(--black); }
.auth-h1 {
  font-family: "Fraunces", "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  font-weight: 600;
  font-size: 32px;
  letter-spacing: -0.01em;
  line-height: 1.2;
  margin: 0 0 28px;
  color: var(--black);
}
.auth-sub {
  font-size: 14px;
  color: var(--grey-700);
  line-height: 1.5;
  margin: -18px 0 22px;
}

/* Fields inside the auth form pane get a slightly bigger radius/border
   than the sitewide bare .field default, matching the approved mockup
   -- scoped here rather than touching .field itself, same pattern
   .login-card-compact already uses for its own field-size tweaks. */
.auth-form-pane .field input {
  border: 1.5px solid var(--grey-300);
  border-radius: var(--radius-md);
  transition: border-color 0.15s ease;
}
.auth-form-pane .field input:focus { outline: none; border-color: var(--accent); }

/* Gradient pill toggle -- Qlinic's own idea, not lifted from Razorpay
   (their reference page merges email/phone into one field). Two
   genuinely different flows deserve two visibly separate tabs. */
.id-pill {
  position: relative;
  display: flex;
  background: var(--grey-100);
  border-radius: 999px;
  padding: 4px;
  margin-bottom: 20px;
}
.id-pill-thumb {
  position: absolute;
  top: 4px;
  left: 4px;
  width: calc(50% - 4px);
  height: calc(100% - 8px);
  border-radius: 999px;
  background: linear-gradient(135deg, var(--accent), var(--accent-dark));
  transition: transform 0.28s cubic-bezier(0.65, 0, 0.35, 1);
  box-shadow: 0 4px 14px rgba(0, 113, 227, 0.35);
}
.id-pill.mode-email .id-pill-thumb { transform: translateX(100%); }
.id-pill button {
  position: relative;
  z-index: 1;
  flex: 1;
  border: none;
  background: none;
  padding: 10px 0;
  font-family: var(--font);
  font-size: 14.5px;
  font-weight: 600;
  color: var(--grey-500);
  cursor: pointer;
  transition: color 0.2s ease;
}
.id-pill button.active { color: var(--white); }

.remember-row { display: flex; align-items: center; gap: 8px; margin: 4px 0 22px; }
.remember-row input[type="checkbox"] { width: 17px; height: 17px; accent-color: var(--accent); cursor: pointer; }
.remember-row label { font-size: 14px; color: var(--grey-700); cursor: pointer; }

.auth-hint {
  margin-top: 24px;
  padding-top: 20px;
  border-top: 1px solid var(--grey-300);
  font-size: 14px;
  color: var(--grey-700);
  line-height: 1.7;
}
.auth-hint a { color: var(--accent); font-weight: 600; text-decoration: none; }
.auth-hint a:hover { text-decoration: underline; }

@media (max-width: 900px) {
  .auth-shell { flex-direction: column; }
  /* Same fallback the real .login-brand-corner already uses on a
     narrow viewport: out of absolute positioning and into normal
     flow, so it can't sit underneath (or collide with) the stacked
     illustration pane's own top padding. */
  .auth-corner-brand { position: static; margin: 20px 0 0 24px; }
  .auth-illustration { position: static; height: auto; flex: none; padding: 40px 24px; }
  .auth-headline { font-size: 30px; }
  .auth-form-pane { flex: none; padding: 40px 24px; border-left: none; box-shadow: none; border-top: 1px solid var(--grey-300); }
}

/* ---------------- App shell (dashboard / reception / doctor) ---------------- */

.app-shell { display: flex; height: 100vh; }

.app-sidebar {
  width: 224px;
  flex-shrink: 0;
  background: var(--white);
  border-right: 1px solid var(--grey-300);
  color: var(--black);
  padding: 24px 14px;
  display: flex;
  flex-direction: column;
  overflow-y: auto;
}

.app-sidebar .brand {
  font-size: 17px;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: var(--black);
  text-decoration: none;
  padding: 0 10px;
  margin-bottom: 28px;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  transition: transform 0.15s ease;
}
.app-sidebar .brand:hover { transform: scale(1.04); }

.app-sidebar nav { display: flex; flex-direction: column; gap: 2px; flex: 1; }

.app-sidebar a.nav-link {
  padding: 9px 12px;
  border-radius: var(--radius-sm);
  color: var(--grey-700);
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  border-left: 2px solid transparent;
  transition: background 0.12s ease, color 0.12s ease, transform 0.12s ease, border-color 0.12s ease;
}
/* Gated to real pointer devices: on touchscreens there's no mouse-leave
   event after a tap, so a plain :hover rule here would stay "stuck" on
   whatever link was last tapped (this is exactly what happened, visible
   on Settings after navigating to it on a phone). */
@media (hover: hover) and (pointer: fine) {
  .app-sidebar a.nav-link:hover {
    background: var(--grey-100);
    color: var(--accent);
    border-left-color: var(--accent);
    transform: translateX(3px);
  }
}
.app-sidebar a.nav-link.active {
  background: var(--grey-100);
  color: var(--accent);
  font-weight: 600;
  border-left-color: var(--accent);
}

.app-sidebar a.nav-link.pinned-bottom {
  margin-top: auto;
  border-top: 1px solid var(--grey-300);
}

.app-sidebar .clinic-name-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 0 10px;
  margin-bottom: 18px;
}
/* Was a 12px grey caption — read as an afterthought once the logo
   beside it grew to its real size (see .clinic-logo-thumb below). A
   clinic's own name is identity, not a footnote, so it gets real
   weight now. flex/min-width/ellipsis keep a long name from ever
   overflowing the fixed-width sidebar now that it's bigger. */
.app-sidebar .clinic-name {
  font-size: 15px;
  font-weight: 700;
  color: var(--black);
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* Height-capped, width-flexible instead of a forced square with
   object-fit:cover — a real clinic logo is rarely square (a wide
   icon+wordmark lockup is the common case), and cover was cropping most
   of it away to force-fit a square box. contain keeps the whole logo
   visible, just scaled to fit the same nav-row height as before. */
.clinic-logo-thumb {
  height: 28px;
  width: auto;
  max-width: 130px;
  object-fit: contain;
  flex-shrink: 0;
}
/* A clinic's uploaded logo is whatever colors they chose — often
   designed against a white background, so it can vanish against the
   sidebar's own background once that goes dark. A fixed white chip
   behind it keeps it visible regardless of the logo's own colors. */
:root[data-theme="dark"] .clinic-logo-thumb {
  background: #fff;
  border-radius: var(--radius-sm);
  padding: 3px;
}

/* Settings' upload/change/remove row and the matching field at
   registration (signup.html) share this look — a small preview plus a
   button, not a full dropzone, since this is a one-off logo pick rather
   than a repeated file-management task. Same contain-not-cover
   reasoning as .clinic-logo-thumb above: the box caps height and width,
   but the logo itself is never cropped to force it into a square. */
/* .logo-upload-row (signup's compact logo picker) stays side-by-side,
   button-height preview box. Clinic Settings uses .logo-upload-col
   instead: the logo gets its own row so it can be shown at a real
   size, with the actions row and hint stacked underneath it —
   side-by-side there previously forced either a cramped logo or a
   lopsided gap next to the shorter button column. */
.logo-upload-row { display: flex; align-items: center; gap: 18px; }
.logo-upload-col { display: flex; flex-direction: column; align-items: flex-start; gap: 14px; }
.logo-preview {
  height: 64px;
  max-width: 220px;
  border-radius: var(--radius-md);
  border: 1px solid var(--grey-300);
  overflow: hidden;
  flex-shrink: 0;
  background: var(--grey-100);
  display: flex;
  align-items: center;
  justify-content: center;
}
.logo-preview img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; display: block; }
.logo-preview.empty { width: 32px; height: 32px; border-radius: var(--radius-sm); }
/* Clinic Settings' logo now sits alone on its own row with room to
   spare, so it gets a bigger footprint than signup's button-height
   box — dashed border marks the empty state as a placeholder. */
.logo-upload-col .logo-preview { height: 96px; max-width: 280px; }
.logo-upload-col .logo-preview.empty { width: 96px; height: 96px; border-style: dashed; }
.logo-actions { display: flex; gap: 8px; }
.logo-hint { font-size: 12px; color: var(--grey-500); }

.app-main {
  flex: 1;
  background: var(--grey-100);
  padding: 40px 48px;
  min-width: 0;
  overflow-y: auto;
}

.app-topbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 32px;
  flex-wrap: wrap;
  gap: 12px;
}
/* Analytics only: the page has no subtitle/actions sharing this row with
   the "Analytics" h1 the way most pages do, so the base 32px gap before
   "Period" read as an oversized dead zone. Scoped by id rather than
   shrinking .app-topbar itself, which every other page still relies on
   at its default size. */
#trendsTopbar { margin-bottom: 14px; }

.app-topbar h1 {
  font-size: var(--text-2xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  margin: 0;
}

.breadcrumb {
  font-size: 13px;
  color: var(--grey-500);
  margin-bottom: 4px;
}
.breadcrumb a { color: var(--grey-500); text-decoration: none; }
.breadcrumb a:hover { color: var(--accent); }
.breadcrumb span { margin: 0 4px; }

.doctor-search-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 16px;
}
.doctor-search-input {
  flex: 1;
  max-width: 320px;
  padding: 10px 14px;
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-family: var(--font);
  font-size: 14px;
  background: var(--white);
  color: var(--black);
}

.clock-pill {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--white);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-pill);
  padding: 8px 8px 8px 16px;
  font-size: 14px;
}
.clock-pill .time { font-weight: 700; }
.clock-pill button {
  border: none;
  background: var(--grey-100);
  border-radius: var(--radius-pill);
  padding: 6px 14px;
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
}
.clock-pill button:hover { background: var(--grey-300); }

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 16px;
  margin-bottom: 28px;
}

/* Settings hub: same grid idea as .card-grid, but for full .panel cards
   (title + description + a button) rather than compact stat tiles - a
   wider minmax so a card's description/button don't get squeezed. */
.settings-card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 18px;
}
/* .panel's own margin-bottom would double up with the grid's gap here
   (extra space below every card, uneven vs. the 18px gap between
   columns) - the grid's gap already spaces every card, in both axes. */
.settings-card-grid .panel { margin-bottom: 0; }
/* A grid row stretches every card to the tallest one's height by
   default, but a card's own content (description text, then a button)
   doesn't know to use that extra room - it just leaves it as blank
   space below the button, so buttons in the same row land at different
   heights depending on how much description text sits above them
   (e.g. Doctors' extra "5 active of 5 total" line vs. Clinic Settings'
   single line). Turning the card into a flex column and pushing
   whichever element comes last (the link/button, or the inline
   form/toggle for Display screen/Appearance) down with margin-top:auto
   puts every card's action on the same bottom edge regardless of how
   much text precedes it. */
/* align-items:flex-start overrides flex's default "stretch," which was
   sizing every card's button (and the Appearance toggle) to the full
   card width - only the vertical placement needed fixing, not the
   button's own width, so children now keep their natural content
   width and just get positioned by the column layout below. */
.settings-card-grid .panel { display: flex; flex-direction: column; align-items: flex-start; }
.settings-card-grid .panel > *:last-child { margin-top: auto; }

.stat-card {
  background: var(--white);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-resting);
  padding: 20px 22px;
}
/* Opens a per-doctor breakdown popup — same hover lift as a real button,
   so it reads as clickable rather than just decorative. */
.stat-card.clickable { cursor: pointer; transition: transform 0.15s ease, box-shadow 0.15s ease; }
.stat-card.clickable:hover { transform: translateY(-2px); box-shadow: var(--shadow-hover); }
.stat-card .value { font-size: 30px; font-weight: 700; letter-spacing: -0.01em; }
.stat-card .label { font-size: 13px; color: var(--grey-500); margin-top: 4px; }
.stat-card .stat-sub { font-size: 12px; color: var(--grey-500); margin-top: 4px; }
.stat-card .top-row { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
/* Semantic (good/bad), not tied to the card's own accent color — a rise
   in footfall and a drop in wait time are both "good" even though one
   trends up and the other down, so the color follows meaning, not arrow
   direction. */
.trend-chip { font-size: 11px; font-weight: 700; padding: 3px 8px; border-radius: var(--radius-pill); white-space: nowrap; margin-top: 3px; }
.trend-chip.good { background: var(--mkt-teal-bg); color: var(--mkt-teal); }
.trend-chip.bad { background: var(--danger-bg); color: var(--danger); }

.panel {
  background: var(--white);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-resting);
  padding: 26px 28px;
  margin-bottom: 20px;
}
/* Doctor View: the one thing a doctor shouldn't have to scroll to find
   is when their next patient is due — same light-blue tint already
   used for .badge-in-consult, not a new color introduced just for
   this banner. */
.next-appt-callout { display: flex; align-items: center; gap: 14px; background: var(--mkt-blue-bg); }
.next-appt-icon { font-size: 22px; }
.next-appt-eyebrow { font-size: 12px; font-weight: 600; letter-spacing: 0.03em; text-transform: uppercase; color: var(--chip-text); }
.next-appt-line { font-size: 17px; font-weight: 600; }
.doctor-identity { margin-bottom: 14px; }
.doctor-identity-name { font-size: 15px; font-weight: 700; }
.doctor-identity-specialty { font-size: 13px; color: var(--grey-500); }
#statusSummaryLines { font-size: 14px; margin-bottom: 14px; }
#statusSummaryLines div { margin-bottom: 4px; }

.billing-option-card { transition: transform 0.12s ease, box-shadow 0.12s ease, border-color 0.12s ease; }
@media (hover: hover) and (pointer: fine) {
  .billing-option-card:hover {
    transform: translateY(-2px);
    border-color: var(--accent);
    box-shadow: 0 6px 18px rgba(0, 0, 0, 0.08);
  }
}
/* The only billing type that actually works today needs to read as the
   obvious choice next to one that doesn't, not just differ by a hover
   effect nobody's triggered yet. */
.billing-option-active { border: 2px solid var(--accent); }
.billing-option-active h2 { font-weight: 700; }
.billing-option-disabled {
  position: relative;
  opacity: 0.55;
  overflow: hidden;
}
.coming-soon-badge {
  position: absolute;
  top: 16px;
  right: 16px;
  background: var(--grey-300);
  color: var(--grey-700);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
}
.panel h2 {
  font-size: 16px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 16px;
}

/* Account & security: one card with icon-led sections instead of three
   separate white panels repeating the same shadow/border three times
   for what's really one page. The current value sits in the header
   itself (next to the section title) rather than its own "Current: "
   line below it. */
.account-section-header { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.account-section-header svg { color: var(--grey-500); flex-shrink: 0; }
.account-section-header h2 { margin: 0; }
.account-section-current { margin-left: auto; font-size: 13px; color: var(--grey-500); }
.account-section-divider { border-top: 1px solid var(--grey-100); margin: 24px 0; }

table.qtable { width: 100%; border-collapse: collapse; font-size: 14px; }
table.qtable th {
  text-align: left;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  font-weight: 700;
  color: var(--black);
  padding: 8px 10px;
  border-bottom: 1px solid var(--grey-300);
  /* Header labels are short by design — wrapping one to two lines (e.g.
     "Total visits" in a narrow fixed-width column) misaligns it against
     single-line neighbors more than it saves space; body cells still
     wrap normally via .qtable-wrap. */
  white-space: nowrap;
}
table.qtable td { padding: 12px 10px; border-bottom: 1px solid var(--grey-100); vertical-align: middle; }
table.qtable tr:last-child td { border-bottom: none; }

/* Plain .qtable auto-sizes each column to whatever's currently in it —
   fine for a static table, but on a table whose rows change under a
   filter (Revenue, Patient Directory), that means the columns
   themselves visibly shift width every time the filtered set changes,
   since the widest name/address in THIS view isn't the widest one in
   the last view. qtable-fixed pins column widths via a <colgroup>
   instead, so the grid itself stays put — only qtable-wrap cells (the
   ones genuinely likely to run long: names, addresses, doctor lists)
   wrap onto a second line rather than trying to widen their column. */
table.qtable.qtable-fixed { table-layout: fixed; }
table.qtable.qtable-fixed .qtable-wrap { overflow-wrap: break-word; word-break: break-word; }

/* Excel-style column-header filter: a small checklist dropdown anchored
   to a <th>, instead of a separate top-of-page dropdown per filterable
   column. th-filter-sort wraps the header label + icon so the click
   target and dropdown-anchor are unambiguous; the icon itself just
   flags whether a filter is currently narrowing this column. */
th.th-filterable { position: relative; }
.th-filter-trigger { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; user-select: none; white-space: nowrap; }
.th-filter-icon { width: 12px; height: 12px; flex-shrink: 0; opacity: 0.55; }
.th-filter-icon.active { opacity: 1; color: var(--accent); }
.filter-dropdown {
  position: absolute; top: 100%; left: 0; margin-top: 6px; z-index: 20;
  background: var(--white); border: 1px solid var(--grey-300); border-radius: var(--radius-sm);
  box-shadow: var(--shadow-hover); padding: 10px; min-width: 200px; max-height: 260px; overflow-y: auto;
  text-transform: none; letter-spacing: normal; font-weight: 400;
}
.filter-dropdown label {
  display: flex; align-items: center; gap: 8px; font-size: 13px; padding: 6px 4px;
  color: var(--black); cursor: pointer; border-radius: 6px;
}
.filter-dropdown label:hover { background: var(--grey-100); }
.filter-dropdown input[type="checkbox"] { width: auto; margin: 0; flex-shrink: 0; }
.filter-dropdown .fd-count { color: var(--grey-500); margin-left: auto; font-size: 12px; }

.stat-card.clickable { cursor: pointer; }
.stat-card.active-filter { outline: 2px solid var(--danger); outline-offset: 2px; }
/* Both chip variants sit inline in a .panel-header next to .btn-sm
   buttons (Export CSV/Reset filters) — same padding/font/radius as
   .btn-sm so they read as one consistent row of controls instead of a
   different-shaped pill dropped in among rectangular buttons. */
.active-filter-chip {
  display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600;
  color: var(--danger); background: var(--danger-bg); border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-4); border: 1px solid transparent;
}
.active-filter-chip button { border: none; background: none; color: inherit; font-weight: 700; cursor: pointer; font-size: 15px; padding: 0; line-height: 1; }
/* A row of chips, one per active column filter (Doctor/Type/Payment
   mode on Revenue, Doctor/Gender on Directory), so a filtered view is
   visibly and specifically flagged as filtered rather than looking
   identical to the unfiltered table. .filter-chip reuses
   .active-filter-chip's shape but in accent blue, not danger red —
   red stays reserved for the Outstanding-only chip's warning meaning
   (it already pairs with the Outstanding card's red outline), so a
   plain "you filtered by Doctor" chip doesn't read as an alert. */
.active-filter-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.filter-chip {
  display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 600;
  color: var(--accent-dark); background: rgba(0, 113, 227, 0.1); border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-4); border: 1px solid transparent;
}
.filter-chip button { border: none; background: none; color: inherit; font-weight: 700; cursor: pointer; font-size: 15px; padding: 0; line-height: 1; }

/* Qlinic.confirmDialog()'s modal — replaces every window.confirm() in
   the app. --white/--black/--grey-700 already flip under dark mode
   (redefined at the token level, not hardcoded here), so this needs no
   separate dark-theme block of its own. */
.modal-backdrop {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
  padding: 20px;
}
.modal-card {
  background: var(--white);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-hover);
  padding: 28px;
  max-width: 440px;
  width: 100%;
}
.modal-title { font-size: 18px; font-weight: 700; letter-spacing: -0.01em; color: var(--black); margin: 0 0 10px; }
.modal-message { font-size: 14px; color: var(--grey-700); line-height: 1.5; margin: 0 0 24px; white-space: pre-line; }
.modal-actions { display: flex; justify-content: flex-end; gap: 10px; }

.badge {
  display: inline-block;
  white-space: nowrap;
  font-size: 12px;
  font-weight: 600;
  line-height: 1.3;
  padding: 4px 10px;
  border-radius: var(--radius-pill);
}
.badge-waiting { background: var(--grey-100); color: var(--grey-700); }
/* Same shape/weight as the status badges, for a cell that shows a plain
   informational label (not a queue status) next to one — e.g. "Walk-in"
   sitting beside a "Waiting" badge. Matching the box, not just the
   position, is what actually keeps two different-shaped pieces of text
   reading as aligned, since bare text and a padded pill never share a
   glyph baseline exactly even when their boxes start at the same y. */
.badge-neutral { background: var(--grey-100); color: var(--grey-700); }
.badge-in-consult { background: #e8f0fe; color: var(--accent-dark); }
.badge-done { background: var(--success-bg); color: var(--success); }
.badge-no-show { background: var(--danger-bg); color: var(--danger); }
.badge-likely { background: var(--warning-bg); color: var(--warning); }
.badge-booked { background: var(--grey-100); color: var(--grey-500); }

/* Manage doctors: a self-contained form look (soft grey fill, no
   border) instead of reusing .field/.inline-form, which would have
   meant fighting .inline-form .field input's higher-specificity
   border/background just to turn it off. Shared by the Add-a-doctor
   form and the Edit-doctor dialog, so both read as the same page. */
.doctor-form { display: flex; gap: 16px; align-items: flex-end; flex-wrap: wrap; }
.doctor-form > .btn-sm { height: 38px; box-sizing: border-box; }
.doctor-form-field { display: flex; flex-direction: column; gap: 6px; }
.doctor-form-field label { font-size: 12px; font-weight: 600; color: var(--grey-500); }
.doctor-form-field input, .doctor-form-field select {
  height: 38px;
  border: 1px solid var(--grey-300);
  background: var(--grey-100);
  border-radius: var(--radius-sm);
  padding: 0 12px;
  font-size: 14px;
  font-family: var(--font);
  width: 100%;
  box-sizing: border-box;
}
.doctor-form-field input:focus, .doctor-form-field select:focus { outline: 2px solid var(--accent); border-color: var(--accent); }
/* Cancel reads as a plain "do nothing" button next to Save's solid
   fill without its own border — scoped to the edit-doctor dialog, not
   every dialog's Cancel, since that's a wider change nobody asked for. */
#editDoctorCancelBtn { border: 1px solid var(--grey-300); background: var(--white); }

/* All doctors: plain text rows (name/specialty/fees/status), never an
   input box, so the table doesn't look like a giant form — editing
   happens in the dialog .doctor-form-field opens, not inline. */
.status-dot-label { display: inline-flex; align-items: center; gap: 6px; font-size: 13px; color: var(--grey-700); }
.status-dot { width: 6px; height: 6px; border-radius: 50%; flex-shrink: 0; }
.status-dot.active { background: var(--success); }
.status-dot.inactive { background: var(--grey-500); }
/* .row-actions/.icon-btn: shared by any table row's edit/delete
   controls (Manage doctors, Closed dates, …), not doctor-specific
   despite living next to the doctor-only rules above. */
.row-actions { display: flex; gap: 4px; justify-content: flex-end; }
.icon-btn {
  width: 30px;
  height: 30px;
  border: none;
  background: transparent;
  border-radius: var(--radius-sm);
  color: var(--grey-500);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  cursor: pointer;
}
.icon-btn:hover { background: var(--grey-100); color: var(--black); }
.icon-btn.danger:hover { background: var(--danger-bg); color: var(--danger); }

.btn-sm {
  font-family: var(--font);
  font-size: var(--text-sm);
  font-weight: 600;
  padding: var(--space-2) var(--space-4);
  border-radius: var(--radius-sm);
  border: 1px solid transparent;
  background: var(--grey-100);
  color: var(--grey-700);
  cursor: pointer;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.btn-sm:disabled { opacity: 0.4; cursor: not-allowed; }
/* Hover still tracks the cursor on a disabled button even though clicks
   don't fire — the generic .btn-sm:hover lift/shadow reads as "this is
   still clickable," so it's cancelled here (doctor.html's "day closed"
   status lock: a floating hover tooltip was tried first, but at only
   102px wide these buttons sit too close together and too close under
   their panel's intro paragraph for a message long enough to be useful
   to fit without overlapping something — a persistent inline note plus
   a native title attribute replaced it instead). */
.btn-sm:disabled:hover { transform: none; box-shadow: none; }
.btn-sm:hover { background: var(--grey-300); color: var(--black); }
.btn-sm.primary { background: var(--accent); color: #ffffff; }
.btn-sm.primary:hover { background: var(--accent-dark); }
/* A real outlined rounded-rect (matching .accent-outline/.success-outline's
   shape) instead of bare colored text with no border — reads as a proper
   button (Delete/Deactivate/No-show/Remove) rather than a text link. */
.btn-sm.danger { background: transparent; color: var(--danger); border-color: var(--danger); }
.btn-sm.danger:hover { background: var(--danger-bg); }
.btn-sm.danger-solid { background: var(--danger); color: #ffffff; }
.btn-sm.danger-solid:hover { background: #a01b18; }
.btn-sm.accent-outline { background: var(--white); color: var(--accent); border-color: var(--accent); }
.btn-sm.accent-outline:hover { background: var(--accent); color: #ffffff; }
/* Same shape as accent-outline, green instead of blue — matches the
   on_time status pill's color, since this is the button that sets that
   exact status. */
.btn-sm.success-outline { background: var(--white); color: var(--success); border-color: var(--success); }
.btn-sm.success-outline:hover { background: var(--success); color: #ffffff; }
/* Same shape again, red — Doctor View's Emergency button, so it no longer
   shares accent-outline's blue with "On a break" (the two read as
   indistinguishable at a glance otherwise). */
.btn-sm.danger-outline { background: var(--white); color: var(--danger); border-color: var(--danger); }
.btn-sm.danger-outline:hover { background: var(--danger); color: #ffffff; }

.inline-form {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  align-items: flex-end;
}
/* Clinic profile's row mixes fields with a .field-hint underneath
   (GSTIN, HFR ID) and ones without (City, State, the Save button
   itself) - align-items: flex-end bottom-aligns every field to the
   tallest one's bottom edge, which pushes the shorter fields' whole
   label+input block down to match, making their labels sit visibly
   lower than GSTIN/HFR's. Top-aligning instead fixes exactly that,
   with no effect on this form's other rows (every field there is the
   same height already, so flex-start and flex-end produce the same
   result when there's no height difference to redistribute) - scoped
   to this one form rather than changed on .inline-form itself, which
   other pages rely on for their own flex-end alignment. */
#clinicForm.inline-form { align-items: flex-start; }

/* Team's "Add a staff member" form is deliberately two literal
   .inline-form rows (identity/credentials/phone, then role/doctor/the
   submit button) rather than one row left to .inline-form's own
   flex-wrap to break wherever it happens to once Phone pushed it past
   4 fields -- that would land the split at a different point depending
   on viewport width, not the grouping actually intended. */
#addStaffForm .inline-form + .inline-form { margin-top: 14px; }

/* Queue rules and Display screen rows read as cramped/undersized next
   to the rest of the app's controls (10px gap, small buttons and
   time-pickers): bigger boxes, a wider gap, and the Save button matched
   to the same height as the field beside it rather than the shorter
   default .btn-sm. */
/* flex-end (the .inline-form default) bottom-aligns every field's box,
   so a field whose .field-hint wraps to two lines pushes every shorter
   field's label+control down to match — the field with the longest hint
   sets everyone else's vertical position. flex-start instead aligns
   labels and controls in one straight row regardless of hint length;
   only the hints themselves end up ragged at the bottom, which reads as
   normal captioning rather than a broken layout. */
#rulesForm, #clinicControlsForm, #displayLanguageForm { gap: 16px; align-items: flex-start; }
#rulesForm .time-picker-trigger, #clinicControlsForm .time-picker-trigger, #clinicControlsForm select,
#followUpBufferInput, #clinicControlsForm .day-chip {
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-md);
}
#rulesForm .btn-sm, #clinicControlsForm .btn-sm {
  padding: var(--space-3) var(--space-6);
  font-size: var(--text-md);
}
/* Language select, Save, and the Appearance Day/Night toggle sit in the
   same visual row-height context across two panels — matched to
   .pill-select's own proven height (8px vertical padding, 13px text,
   1px border) rather than each control's own generic default, so all
   three read as one consistent size. Widths stay whatever each
   control's own content/padding naturally needs. */
/* .mode-btn.theme-toggle-btn (not .theme-toggle-btn alone): .mode-btn's
   own padding/font-size rule sits later in this file, and an
   equal-specificity class selector would lose to it by source order —
   stacking both classes on the same selector outranks .mode-btn alone
   regardless of where either rule sits. */
#displayLanguageForm .btn-sm, .mode-btn.theme-toggle-btn {
  padding-top: 8px;
  padding-bottom: 8px;
  font-size: 13px;
  line-height: 16px;
}
/* line-height alone doesn't work here: the Day/Night labels start with
   a color-emoji glyph, and browsers size a color emoji's line box off
   the emoji font's own oversized metrics — measured directly, it
   ignores an explicit line-height and inflates the button ~16px taller
   than a plain-text button with identical padding/font-size, no matter
   what line-height says. A hard height + flex-centering sidesteps the
   line-box calculation entirely instead of fighting it. */
.mode-btn.theme-toggle-btn {
  height: 34px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
/* #displayLanguageInput, not .pill-select alone: .inline-form .field
   select (below) is a compound selector with higher specificity than a
   single class, so it would otherwise win the padding/font-size/
   border-radius fight and silently undo .pill-select's sizing and pill
   shape. Re-asserts the exact same look under an ID, which always
   outranks it regardless of source order.
   line-height is taller than the other pill-selects on this page (20px
   vs 16px): Devanagari conjuncts/matras in "हिन्दी" sit taller than Latin
   text at the same font-size, and a 16px line-height was clipping the
   top of the script when Hindi was selected. */
#displayLanguageInput {
  padding: 8px 32px 8px 16px;
  font-size: 13px;
  line-height: 20px;
  border-radius: var(--radius-pill);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%234a4a4c' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 12px;
}
:root[data-theme="dark"] #displayLanguageInput {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23c7c7cc' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}


/* An action button sharing an .inline-form/.form-grid row with a real
   <input>/<select> field (wrapped in its own .field, same as the
   button) should match that field's height — .btn-sm's own smaller
   default padding/font (7px/13px) otherwise renders visibly shorter
   than the 10px-padding/14px-font control beside it. Scoped to .field >
   .btn-sm (not every .btn-sm in these rows) so standalone button
   toolbars with no field counterpart — e.g. Doctor View's status-pill
   row — are left at their normal compact size. Forms with their own
   bigger field sizing (#rulesForm/#clinicControlsForm/
   #displayLanguageForm above, Revenue's #singleDayFilters below)
   already override this via a higher-specificity selector. */
.inline-form .field > .btn-sm, .form-grid .field > .btn-sm {
  padding: var(--space-3) var(--space-6);
  font-size: var(--text-base);
}
.inline-form .field { margin-bottom: 0; min-width: 160px; flex: 1; }
.inline-form .field input, .inline-form .field select {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-family: var(--font);
}

/* Directory's date fields and period dropdown are the primary controls
   on that page (not a secondary filter bar like elsewhere inline-form
   is used), so they get a larger treatment than the standard
   inline-form sizing above. A subtle shadow lifts them off the page's
   grey-100 background, since a grey-300 border alone reads as
   washed-out against it. Applied as a class (not by ID) since the same
   treatment covers a growing set of fields: the period-preset dropdown
   and the custom-range month/year selects. Revenue's own #dateFilter
   used to be part of this selector too, but now matches Range mode's
   .pill-select shape instead (.pill-input, below) per explicit request
   for the two toggle modes to look consistent. */
/* Selectors are written as ".field select.big-control" (not just
   ".big-control") on purpose: a big-control select usually sits inside
   ".inline-form .field", and that context's own generic rule below
   (.inline-form .field select, 2 classes + a type = higher specificity
   than ".big-control" alone) would otherwise silently win and shrink
   it back down — matching that same specificity and relying on this
   block coming later in the file is what actually makes the override
   stick, not the class name by itself. */
.field select.big-control {
  padding: 13px 14px;
  font-size: 17px;
  font-weight: 500;
  border-color: var(--grey-300);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
}
/* Revenue's Single-day Date input + Today button, sized to match Range
   mode's .pill-select (Period dropdown) exactly — same box (padding,
   border, radius) so toggling between the two modes doesn't shift
   control height. .pill-input omits .pill-select's chevron
   background-image/right-padding since a date input has no dropdown. */
.pill-input {
  font-family: var(--font);
  font-size: 13px;
  font-weight: 600;
  /* 1px less than .pill-select/.pill-btn's 8px: a native <input
     type="date">'s built-in calendar-icon chrome adds ~2px of intrinsic
     height that identical padding/border/font alone doesn't cancel out
     — confirmed via getBoundingClientRect (37px vs. 35px at 8px/8px). */
  padding: 7px 16px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--grey-300);
  background: var(--white);
  color: var(--black);
  transition: border-color 0.15s ease;
}
.pill-input:hover { border-color: var(--grey-500); }
/* Same box as .pill-input/.pill-select, colored like .btn-sm.accent-outline
   so it still reads as a button, not a field. */
.pill-btn {
  font-family: var(--font);
  font-size: 13px;
  font-weight: 600;
  padding: 8px 16px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--accent);
  background: var(--white);
  color: var(--accent);
  cursor: pointer;
  transition: background 0.15s ease, color 0.15s ease;
}
.pill-btn:hover { background: var(--accent); color: #ffffff; }

/* Broadcast delay/Cancel sit next to a .time-picker-trigger (10px 12px /
   14px, no bold), not a plain field — they're nested one level deeper
   than a bare .field > .btn-sm (wrapped together so they stay close to
   each other, not spread across the row's 160px-min-width field gap),
   so the generic rule can't reach them and they'd otherwise fall back to
   .btn-sm's smaller default padding. */
#delayInputWrap .btn-sm {
  padding: var(--space-2) 12px;
  font-size: 14px;
  white-space: nowrap;
}
/* The optional Reason field sits below that same row and isn't inside
   .inline-form (it needs its own full-width line, not squeezed into the
   row alongside the picker/buttons), so it falls outside every existing
   sizing rule and would default to the bare .field input tier (12px 16px
   / 15px) — visibly bigger than its neighbors above. Matched to the same
   10px 12px / 14px as the rest of this panel instead.
   .autocomplete-ghost has to get the identical padding/font-size, not
   just the real input — the ghost overlay renders the same string
   ("typed" text made invisible, then the suggestion) on top of the real
   input, so any difference between the two boxes shifts the ghost text
   away from wherever the real caret actually is, which is exactly what
   makes a hint like "unch" (completing "l" to "Lunch") land nowhere
   near the "l" that's actually been typed. */
#delayInputWrap input[type="text"], #delayInputWrap .autocomplete-ghost {
  padding: 10px 12px;
  font-size: 14px;
}

/* Native select arrows render tiny and inconsistent across browsers; swap
   in a matching custom chevron so they don't look like unstyled form
   controls next to the rest of the page. */
.field select.big-control {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  cursor: pointer;
  padding-right: 40px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%234a4a4c' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 14px;
  transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.field select.big-control:hover {
  border-color: var(--grey-500);
  box-shadow: 0 3px 10px rgba(0, 0, 0, 0.1);
}
:root[data-theme="dark"] .field select.big-control {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 24 24' fill='none' stroke='%23c7c7cc' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}

/* Compact select styled exactly like .period-pill (same height, same
   pill shape) so a dropdown can sit inline with real period-pill
   toggles without a height mismatch — used for Doctor/Visit Type next
   to Revenue's Single day/Range toggle, and Directory's Doctor seen
   next to its period dropdown. */
.pill-select {
  font-family: var(--font);
  font-size: 13px;
  font-weight: 600;
  padding: 8px 32px 8px 16px;
  border-radius: var(--radius-pill);
  border: 1px solid var(--grey-300);
  background: var(--white);
  color: var(--black);
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  cursor: pointer;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%234a4a4c' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 12px center;
  background-size: 12px;
  transition: border-color 0.15s ease;
}
.pill-select:hover { border-color: var(--grey-500); }
/* Matches .field label exactly, for labeled pill-selects that
   deliberately sit outside .field (avoids .field's width:100%/flex
   rules, which collapse a select's width to min-content when it isn't
   getting a wide-enough flex-basis — see Revenue/Directory's Period and
   custom-range Month/Year selects). */
.pill-label { display: block; font-size: 13px; font-weight: 600; color: var(--grey-700); margin-bottom: 6px; }
#trendsPeriodField .pill-label { font-size: 15px; }
/* Revenue/No-shows' filter row: the pill toggle, Date field, Today,
   Custom dropdown and From/To pickers all sit on one line (see the
   row's own comment in revenue.html/no-shows.html) and need to look
   like one coherent row rather than a jumble of different-height
   boxes. .period-pill itself is the tallest thing here (9px vertical
   padding) and stays that size - everything below scales UP to meet
   it rather than the pill shrinking down to them.
   - The date picker replaced a native <input type="date"> that was
     never calibrated to match .pill-btn's height/shape - its default
     rectangular, grey-bordered look sat taller and squarer than
     "Today" beside it. Reshaped to the same pill here specifically,
     not globally - every other page's picker keeps the plain
     bordered-field look that matches its own neighbouring controls. */
#singleDayFilters .qdp-trigger { border-radius: var(--radius-pill); padding: 9px 16px; }
/* Today, and the Custom dropdown that replaces the Date field once
   Range is picked - both bumped from .pill-btn/.pill-select's usual
   8px to the Date field's 9px, so nothing in this row reads shorter
   than its neighbours. */
#singleDayFilters .pill-btn,
#rangePresetField .pill-select { padding: 9px 16px 9px 16px; }
#rangePresetField .pill-select { padding-right: 32px; }
:root[data-theme="dark"] .pill-select {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%23c7c7cc' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
}

/* Full pill shape (not the 10px-rounded rect this used to be) — the
   search bar is the primary, first-touched control on these pages, so
   it gets a distinct, more confident shape than a regular text field,
   closer to a familiar rounded search-bar treatment. */
#searchBox, #patientSearch, #directorySearch, #noShowSearch {
  display: block;
  width: 100%;
  box-sizing: border-box;
  padding: 14px 24px;
  font-size: 17px;
  font-weight: 500;
  font-family: var(--font);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-pill);
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.05);
  background: var(--white);
  color: var(--black);
  margin-bottom: 10px;
}
#searchBox:focus, #patientSearch:focus, #directorySearch:focus, #noShowSearch:focus { outline: 2px solid var(--accent); border-color: var(--accent); }


/* Add-patient form: a grid (not flex-wrap) so a field that grows taller than
   its neighbors — e.g. the slot-availability hint — can never shove the other
   fields out of alignment. The hint and submit button live below the grid
   entirely, in their own row, for the same reason. */
.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  align-items: start;
}
.form-grid .field { margin-bottom: 0; }
.form-grid .field input, .form-grid .field select {
  width: 100%;
  padding: var(--space-3) var(--space-4);
  font-size: var(--text-base);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  font-family: var(--font);
}

/* The consultation billing form otherwise looked pale/unfinished next
   to the rest of the app; kept the same flat field-by-field layout
   (no grouped sections — that's extra visual structure for reception
   to parse, not extra clicking, but still unwanted here) and just gave
   its fields a real border color instead of the barely-there default. */
#billingFormPanel .form-grid .field input,
#billingFormPanel .form-grid .field select {
  border-color: var(--accent);
  border-width: 1.5px;
}

/* Custom time picker — a native <input type="time"> renders a different,
   unstylable scrolling wheel per browser/OS, and a plain <select> can't
   filter out past times or control where the list opens. This gives full
   control over both: past times are excluded entirely for today's date,
   and opening the list starts at a useful position instead of midnight. */
.time-picker { position: relative; }
/* Vertical padding matches .form-grid/.inline-form's real <input>/<select>
   fields (var(--space-3) = 12px) — this used to be 10px, rendering visibly
   shorter than the date input or doctor select sharing its row. */
.time-picker-trigger {
  width: 100%;
  padding: 12px 12px;
  font-size: 14px;
  font-family: var(--font);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--black);
  text-align: left;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
.time-picker-trigger.placeholder { color: var(--grey-500); }
.time-picker-trigger:hover { border-color: var(--grey-500); }
.time-picker-trigger:focus { outline: 2px solid var(--accent); border-color: var(--accent); }
.time-picker-caret { color: var(--grey-500); font-size: 11px; flex-shrink: 0; }
.time-picker-panel {
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  right: 0;
  max-height: 260px;
  overflow-y: auto;
  background: var(--white);
  border: 1px solid var(--grey-300);
  border-radius: 10px;
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.14);
  z-index: 50;
  padding: 6px;
}
.time-picker-option {
  padding: 9px 12px;
  font-size: 14px;
  border-radius: 6px;
  cursor: pointer;
}
.time-picker-option:hover { background: var(--grey-100); }
.time-picker-option.selected { background: var(--accent); color: #ffffff; font-weight: 600; }
.time-picker-empty { padding: 16px 12px; text-align: center; color: var(--grey-500); font-size: 13px; }

/* Reception's "Find a Patient" inline edit row: Name/Phone/Doctor were
   left as bare, unstyled inputs while Booked's date + time-picker got the
   normal polished treatment, so the row read as mismatched. Every editable
   cell now shares one small, rounded input style; #searchResults scoping
   (an ID, so it wins over .time-picker-trigger's own rule without relying
   on source order) keeps this deliberately smaller than the main
   Add-a-patient form's picker, since Booked stacks two controls (date
   above time) and a full-size picker there would make that one cell much
   taller than its single-line neighbors. vertical-align: top keeps every
   cell starting from the same line instead of centering around whichever
   cell happens to be tallest. Scoped to the edit row specifically
   (.search-edit-row) — the normal read-only row has no stacked cell, so
   it keeps the base .qtable td middle-alignment; forcing top there made
   Phone/Doctor/Booked sit flush at the top instead of centered next to
   Name's two-line name+address block. */
#searchResults .qtable tr.search-edit-row td { vertical-align: top; }
#searchResults .search-edit-name,
#searchResults .search-edit-phone,
#searchResults .search-edit-doctor,
#searchResults .search-edit-date,
#searchResults .time-picker-trigger {
  width: 100%;
  padding: 7px 9px;
  font-size: 13px;
  font-family: var(--font);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--black);
}
#searchResults .search-edit-name:focus,
#searchResults .search-edit-phone:focus,
#searchResults .search-edit-doctor:focus,
#searchResults .search-edit-date:focus,
#searchResults .time-picker-trigger:focus {
  outline: 2px solid var(--accent);
  border-color: var(--accent);
}
#searchResults .search-edit-date { display: block; margin-bottom: 4px; }
/* Mark arrived/Edit/Save/Cancel kept the default .btn-sm size (~32px
   tall) while every other cell in this table was shrunk to a ~24px
   compact scale, so the buttons visually dominated the row and made
   everything beside them read as randomly sized/misaligned even though
   every cell's content already starts at the same top and left offset. */
#searchResults .btn-sm { padding: 5px 10px; font-size: 12px; }

/* A row of toggleable day buttons — for picking a set of weekdays (e.g.
   which days a clinic is closed) where a native multi-select's ctrl/cmd-
   click gesture would be unclear to most reception/admin users. */
.day-chip-group { display: flex; flex-wrap: nowrap; gap: 6px; }
.day-chip {
  padding: 8px 10px;
  font-size: 13px;
  font-family: var(--font);
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-sm);
  background: var(--white);
  color: var(--black);
  cursor: pointer;
}
.day-chip:hover { border-color: var(--grey-500); }
.day-chip.active { background: var(--accent); border-color: var(--accent); color: #ffffff; font-weight: 600; }

.panel-note { font-size: 13px; color: var(--grey-500); margin: 0 0 14px; }

/* A one-line caption under a single field, for the short "what does this
   do" hint that used to live as one big paragraph under the whole form —
   attached to the field it explains instead of read separately. */
.field-hint { display: block; font-size: 12px; color: var(--grey-500); margin-top: 6px; }
.field-hint.error { color: var(--danger); font-weight: 600; }

/* Custom date picker (Qlinic.attachDatePicker), replacing the bare
   native <input type="date"> everywhere: a text trigger showing the
   picked date + Today/Tomorrow/In-a-week quick picks above a calendar.
   See the "Date Picker Options" mockup this was built from — a
   second "week strip" variant was tried for the always-reopened
   filters but didn't land, so every field uses this one shape now. */
.qdp { position: relative; display: inline-block; width: 100%; font-family: var(--font); }
.qdp-trigger {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  font-family: var(--font); font-size: 14px; font-weight: 400; color: var(--black);
  background: var(--white); border: 1px solid var(--grey-300); border-radius: var(--radius-sm);
  padding: 12px 13px; cursor: pointer; width: 100%;
}
.qdp-trigger:hover { border-color: var(--grey-500); }
.qdp-trigger.open { border-color: var(--accent); box-shadow: 0 0 0 3px rgba(0, 113, 227, 0.12); }
.qdp-trigger svg { color: var(--grey-500); flex-shrink: 0; }
.qdp-trigger-label.qdp-placeholder { color: var(--grey-500); font-weight: 500; }
/* Custom range's From/To pickers specifically - the default
   grey-300 border reads as barely-there, especially with the greyed-out
   "Pick a date" placeholder text inside it (unlike the single-day date
   field, whose dark filled-in text anchors the box's edges better on
   its own). Scoped to Revenue/No-shows' #customRangeFilters, Analytics'
   #trendsCustomRangeFilters, and Patient Directory's
   #customPeriodFilters rather than every .qdp-trigger app-wide.
   Also reshaped to the same full pill .qdp-trigger already gets on the
   single-day filter - left at the base 8px-radius rectangle before,
   these sat visibly taller and squarer than the pill-select/pill-input
   next to them (Period's dropdown, or Revenue/No-shows' own pill
   toggle). */
#customRangeFilters .qdp-trigger,
#trendsCustomRangeFilters .qdp-trigger,
#customPeriodFilters .qdp-trigger {
  border-color: var(--grey-500);
  border-radius: var(--radius-pill);
}
/* Revenue/No-shows: matches the row's pill/Date/Today/Custom-dropdown,
   all bumped to 9px above. Analytics/Patient Directory have no pill in
   this row, so their own From/To just match Period's unbumped 8px. */
#customRangeFilters .qdp-trigger { padding: 9px 16px; }
#trendsCustomRangeFilters .qdp-trigger,
#customPeriodFilters .qdp-trigger { padding: 8px 16px; }

.qdp-pop {
  position: absolute; top: calc(100% + 6px); z-index: 30;
  background: var(--white); border-radius: var(--radius-md); box-shadow: var(--shadow-resting);
  border: 1px solid var(--grey-300); padding: 14px; width: 264px; display: none;
}
.qdp-pop.open { display: block; }
.qdp-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 10px; }
.qdp-head-title { font-size: 14px; font-weight: 700; color: var(--black); }
/* Clicking "August 2026" drills into a year grid, then a month grid
   (see .qdp-yeargrid/.qdp-monthgrid below) - a button rather than the
   plain text it used to be, so long-distance date entry doesn't mean
   clicking the ‹ arrow one month at a time. */
.qdp-head .qdp-month-label {
  font-size: 14px; font-weight: 700; color: var(--black); background: none; border: none;
  font-family: var(--font); padding: 0; cursor: pointer; display: flex; align-items: center; gap: 4px;
}
.qdp-head .qdp-month-label:hover { color: var(--accent-dark); }
.qdp-head .qdp-month-label::after { content: '▾'; font-size: 10px; color: var(--grey-500); }
.qdp-back {
  font-family: var(--font); font-size: 13px; font-weight: 700; color: var(--grey-500); background: none;
  border: none; cursor: pointer; padding: 0;
}
.qdp-back:hover { color: var(--accent-dark); }
.qdp-yeargrid, .qdp-monthgrid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 6px; }
.qdp-grid-cell {
  font-family: var(--font); font-size: 13px; font-weight: 600; color: var(--black); background: transparent;
  border: none; border-radius: var(--radius-sm); padding: 10px 4px; cursor: pointer;
}
.qdp-grid-cell:hover { background: var(--grey-100); }
.qdp-grid-cell.selected { background: var(--accent); color: #fff; }
.qdp-nav { display: flex; gap: 4px; }
.qdp-nav button {
  width: 26px; height: 26px; border-radius: var(--radius-sm); border: none; background: var(--grey-100);
  color: var(--grey-700); cursor: pointer; font-size: 14px; font-family: var(--font); display: flex; align-items: center; justify-content: center;
}
.qdp-nav button:hover { background: var(--grey-300); }
.qdp-dow { display: grid; grid-template-columns: repeat(7, 1fr); text-align: center; font-size: 10.5px; font-weight: 700; color: var(--grey-500); margin-bottom: 4px; }
.qdp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 2px; }
.qdp-day {
  aspect-ratio: 1; display: flex; align-items: center; justify-content: center;
  font-size: 13px; font-weight: 500; color: var(--black); border-radius: 50%; cursor: pointer;
  border: none; background: transparent; font-family: var(--font); position: relative;
}
.qdp-day:hover:not(.disabled) { background: var(--grey-100); }
.qdp-day.muted { color: var(--grey-300); }
.qdp-day.today { color: var(--accent-dark); font-weight: 800; }
.qdp-day.today::after { content: ''; position: absolute; bottom: 3px; width: 4px; height: 4px; border-radius: 50%; background: var(--accent); }
.qdp-day.selected { background: var(--accent); color: #fff; }
.qdp-day.selected::after { display: none; }
.qdp-day.disabled { color: var(--grey-300); cursor: not-allowed; }

.qdp-quick { display: flex; gap: 6px; margin-bottom: 12px; flex-wrap: wrap; }
.qdp-quick button {
  font-family: var(--font); font-size: 11.5px; font-weight: 700; color: var(--accent-dark);
  background: rgba(0, 113, 227, 0.08); border: none; border-radius: var(--radius-pill); padding: 5px 11px; cursor: pointer;
}
.qdp-quick button:hover { background: rgba(0, 113, 227, 0.16); }
.qdp-quick button.selected { background: var(--accent); color: #fff; }

/* Reception's "a doctor has closed for the day" notice, sitting above the
   page heading so it's the first thing read, not a corner toast that
   fades. Deliberately neutral grey (not warning/danger) — closing for the
   day is routine, not an error. A flush top strip, not a boxed card: the
   negative margin pulls it out of .app-main's own padding so it sits
   flush against the true top of the page instead of floating in the
   padded gap above "Reception," and the matching horizontal padding
   keeps its text aligned with the page content below it. No border or
   radius — a card-shaped box here read as its own separate alert rather
   than page-level context. */
.closed-day-banner {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  background: var(--grey-100);
  padding: 6px 48px;
  margin: -40px -48px 6px;
  font-size: var(--text-base);
  color: var(--grey-700);
  line-height: 1.4;
}
.closed-day-banner .dot {
  flex-shrink: 0;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--grey-500);
}
.closed-day-banner strong { color: var(--black); font-weight: 600; }

.viewing-label {
  font-size: 13px;
  font-weight: 600;
  color: var(--grey-700);
  display: block;
  margin-bottom: 8px;
}
.doctor-select {
  padding: 10px 14px;
  border-radius: var(--radius-sm);
  border: 1px solid var(--grey-300);
  font-size: 14px;
  font-family: var(--font);
}
/* .inline-form .field select's width:100% (two classes + a type) beats
   .doctor-select (one class) in the specificity fight regardless of
   source order, so a plain override here doesn't stick — asserted by
   ID instead, which always wins. Both width:max-content and width:auto
   were tried here first and both still clipped the closing bracket on
   a long doctor label — Chrome's own intrinsic-sizing pass for a
   <select> doesn't reliably size to fit its own rendered option text.
   A fixed width sidesteps that measurement entirely instead of
   trusting it: comfortably wider than "Name, Specialty (N waiting,
   N booked)" ever needs to be, at the cost of some empty space for a
   short name. */
#queueDoctorFilter { width: 480px; max-width: 100%; }
.queue-filter-group { display: flex; align-items: flex-end; gap: 10px; }

/* Height pinned to match #queueDateFilter exactly (44px) rather than
   relying on padding/font-size alone to line up across two very
   different elements (a native date input vs a button) — the two
   families of padding/line-height maths just didn't land on the same
   pixel reliably. */
#queueDateFilter, #queueTodayBtn {
  height: 44px;
  box-sizing: border-box;
}
#queueTodayBtn {
  padding: 10px 14px;
  font-size: 14px;
}

.booked-section { margin-top: 22px; }
.booked-toggle {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  width: 100%;
  background: none;
  border: none;
  border-top: 1px solid var(--grey-100);
  padding: 14px 0 10px;
  font-size: 14px;
  font-weight: 700;
  color: var(--grey-700);
  cursor: pointer;
  text-align: left;
  font-family: var(--font);
}
.booked-toggle:hover { color: var(--black); }
.booked-body { padding-top: 6px; }

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding-top: 14px;
}
.pager-label { font-size: 13px; color: var(--grey-500); }
.pager-summary { font-size: 13px; color: var(--grey-500); }

/* Revenue's pager adds a "Showing X-Y of Z" summary the other .pager
   users (manage-doctors, reception) don't have, so it alone needs the
   summary pinned left and controls pinned right instead of the shared
   centered layout. */
#revenuePager { justify-content: space-between; }
#revenuePager .pager-controls { display: flex; align-items: center; gap: 14px; }

.empty-state { color: var(--grey-500); font-size: 14px; padding: 20px 0; text-align: center; }

/* ---------------- Trends page ---------------- */

/* Same gradient-track/gradient-pill treatment as Analytics' own group
   tabs (#trendGroupSeg in styles.css) - Revenue and No-shows share
   this Single day/Range toggle, and both pick up the restyle
   automatically since it's the shared .period-pill class, not scoped
   to one page. Previously each pill was its own individually-bordered
   button with no shared track; now the container itself is the raised
   track and the pills sit borderless inside it, matching Analytics
   exactly rather than approximating it. */
.period-pills {
  display: inline-flex; background: linear-gradient(180deg, var(--grey-100), var(--white));
  border: 1px solid var(--grey-300); border-radius: var(--radius-pill); padding: 4px; gap: 2px;
  margin-bottom: 20px; box-shadow: var(--shadow-resting), inset 0 1px 0 rgba(255, 255, 255, 0.5);
}
.period-pill {
  font-family: var(--font);
  font-size: 13.5px;
  font-weight: 700;
  letter-spacing: 0.01em;
  padding: 9px 18px;
  border-radius: var(--radius-pill);
  border: 1.5px solid transparent;
  background: transparent;
  color: var(--grey-700);
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.period-pill:hover:not(.active) { color: var(--accent-dark); }
/* Crisp white outline - same treatment as #trendGroupSeg's active pill,
   applied everywhere this gradient-pill pattern appears. */
.period-pill.active {
  background: linear-gradient(135deg, var(--accent), var(--accent-dark)); color: var(--white);
  border-color: rgba(255, 255, 255, 0.9); box-shadow: 0 3px 10px rgba(0, 113, 227, 0.35);
}

/* Trends charts: a fixed-height box for a Chart.js canvas
   (maintainAspectRatio:false relies on the parent having a real height),
   plus a collapsible drill-down area that expands directly below the
   chart it belongs to when a bar/segment is clicked. */
.trend-chart-box { position: relative; height: 260px; }
.trend-chart-box .empty-state { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; padding: 0; }
.trend-drill { display: none; margin-top: 18px; padding-top: 18px; border-top: 1px dashed var(--grey-300); }
.trend-drill.open { display: block; animation: trendDrillIn 0.2s ease; }
@keyframes trendDrillIn { from { opacity: 0; transform: translateY(-4px); } to { opacity: 1; transform: translateY(0); } }
.trend-drill-label { font-size: 13px; font-weight: 600; color: var(--grey-700); margin: 0 0 4px; display: flex; align-items: center; gap: 8px; }
.trend-drill-close { margin-left: auto; cursor: pointer; color: var(--grey-500); font-size: 16px; line-height: 1; padding: 2px 6px; border-radius: var(--radius-sm); }
.trend-drill-close:hover { color: var(--grey-700); background: var(--grey-100); }
.trend-drill-note { font-size: 12px; color: var(--grey-500); margin: 0 0 12px; line-height: 1.5; }
.donut-subheading { font-size: 13px; font-weight: 600; color: var(--grey-700); text-align: center; margin: 0 0 8px; }
.trend-drill-charts { display: grid; grid-template-columns: 1fr; gap: 16px; }
.trend-drill-charts.two-up { grid-template-columns: 1fr 1fr; }
@media (max-width: 620px) { .trend-drill-charts.two-up { grid-template-columns: 1fr; } }
.trend-drill-chart-box { height: 220px; position: relative; }
/* The one drill-down that's a donut (Revenue over time's per-doctor
   split) reads as a downgrade next to Visits per doctor's full-size
   ring if it's boxed any smaller — matches that height exactly. */
.trend-drill-chart-box.donut-size { height: 260px; }
.trend-drill-link { display: inline-block; margin-top: 12px; font-size: 13px; font-weight: 600; color: var(--accent); text-decoration: none; }
.trend-drill-link:hover { text-decoration: underline; }

/* A donut's own hover tooltip has nowhere safe to float: the ring is
   thin enough that a hover anywhere near its inner edge sits right on
   top of the center total. Pinned flush against the ring's own edge
   instead of following the cursor (top/left/right set from the arc's
   real pixel radius in JS, per hover), on whichever side is opposite
   the hovered half, so it reads as part of the chart rather than a
   banner stranded out at the edge of the box. */
.donut-tooltip {
  position: absolute; transform: translateY(-50%);
  display: flex; align-items: center; gap: 8px;
  background: var(--black); color: var(--white);
  border: 1px solid var(--grey-300); border-radius: var(--radius-sm);
  padding: 8px 12px; font-size: 12px; font-weight: 500;
  white-space: nowrap; pointer-events: none; z-index: 5;
  opacity: 0; transition: opacity 0.1s ease;
}
.donut-tooltip strong { font-weight: 700; }
.donut-tooltip-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }

.trend-doctor-row { display: flex; align-items: center; gap: 10px; margin-bottom: 12px; }
.trend-doctor-row:last-child { margin-bottom: 0; }
.trend-doctor-name { width: 130px; font-size: 13px; color: var(--grey-700); flex-shrink: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.trend-doctor-track { flex: 1; background: var(--grey-100); border-radius: 6px; height: 14px; overflow: hidden; }
.trend-doctor-fill { height: 100%; background: var(--accent); border-radius: 6px; }
.trend-doctor-fill-warn { background: var(--danger); }
.trend-doctor-count { font-size: 13px; color: var(--grey-700); width: auto; min-width: 32px; text-align: right; flex-shrink: 0; }

.doctor-status-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  flex-wrap: wrap;
  padding: 16px 12px;
  margin: 0 -12px 8px;
  border-radius: 10px;
  border-bottom: 1px solid var(--grey-100);
  transition: background 0.15s ease;
}
.doctor-status-row:hover { background: var(--grey-100); }
.doctor-status-row:last-child { border-bottom: none; margin-bottom: 0; }
.doctor-status-row .doc-name { font-weight: 700; font-size: 15px; }
.doctor-status-row .doc-specialty { font-size: 13px; color: var(--grey-500); }
.doctor-status-row .doc-status-line { font-size: 13px; color: var(--grey-700); margin-top: 2px; }

/* Dashboard's "upcoming holidays" chip — hidden entirely (in the
   containing panel-header) whenever there's nothing upcoming, per
   #holidayChipWrap's default display:none in the markup. */
.holiday-chip-wrap { position: relative; }
.holiday-chip {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font);
  font-size: 13px;
  font-weight: 600;
  color: var(--chip-text);
  background: var(--mkt-blue-bg);
  border: none;
  border-radius: var(--radius-pill);
  padding: 8px 14px;
  cursor: pointer;
  white-space: nowrap;
}
.holiday-chip:hover { filter: brightness(0.97); }
:root[data-theme="dark"] .holiday-chip:hover { filter: brightness(1.2); }
.holiday-popover {
  position: absolute;
  top: calc(100% + 8px);
  right: 0;
  width: 300px;
  background: var(--white);
  border: 1px solid var(--grey-300);
  border-radius: 10px;
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.14);
  z-index: 50;
  padding: 6px;
  display: none;
}
.holiday-popover.open { display: block; }
.holiday-popover-header {
  font-size: 11px; font-weight: 700; color: var(--grey-500);
  text-transform: uppercase; letter-spacing: 0.04em;
  padding: 8px 10px 6px;
}
.holiday-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--radius-sm); }
.holiday-row .board-doc-dot { margin-right: 0; }
.holiday-row:hover { background: var(--grey-100); }
.holiday-row .info { flex: 1; min-width: 0; }
.holiday-row .doc-name { font-size: 13px; font-weight: 600; }
.holiday-row .doc-note { font-size: 12px; color: var(--grey-500); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.holiday-row .date-badge {
  font-size: 11.5px; font-weight: 700; color: var(--grey-700);
  background: var(--grey-100); border-radius: 6px; padding: 4px 7px;
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.holiday-row.soonest .date-badge { background: var(--mkt-blue-bg); color: var(--chip-text); }
.holiday-popover-footer { border-top: 1px solid var(--grey-300); margin-top: 4px; padding-top: 6px; }
.holiday-popover-footer a {
  display: block; text-align: center; font-size: 12.5px; font-weight: 600;
  color: var(--accent); text-decoration: none; padding: 7px; border-radius: var(--radius-sm);
}
.holiday-popover-footer a:hover { background: var(--grey-100); }

/* Reception's "who's waiting" chip - same shape/behavior as the
   .holiday-chip above (hidden entirely when empty, a shortcut instead
   of a count when there's exactly one), kept as its own class rather
   than reusing .holiday-chip since the two features are unrelated and
   independently editable. */
.waiting-chip-wrap { position: relative; }
.waiting-chip {
  display: inline-flex; align-items: center; gap: 8px; font-family: var(--font);
  font-size: 13px; font-weight: 600; color: var(--chip-text); background: var(--mkt-blue-bg);
  border: none; border-radius: var(--radius-pill); padding: 8px 14px; cursor: pointer; white-space: nowrap;
}
.waiting-chip:hover { filter: brightness(0.97); }
:root[data-theme="dark"] .waiting-chip:hover { filter: brightness(1.2); }
.waiting-popover {
  position: absolute; top: calc(100% + 8px); right: 0; width: 300px;
  background: var(--white); border: 1px solid var(--grey-300); border-radius: 10px;
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.14); z-index: 50; padding: 6px; display: none;
}
.waiting-popover.open { display: block; }
.waiting-popover-header {
  font-size: 11px; font-weight: 700; color: var(--grey-500);
  text-transform: uppercase; letter-spacing: 0.04em; padding: 8px 10px 6px;
}
.waiting-row { display: flex; align-items: center; gap: 10px; padding: 8px 10px; border-radius: var(--radius-sm); }
.waiting-row:hover { background: var(--grey-100); }
.waiting-dot { display: inline-block; width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.waiting-row .info { flex: 1; min-width: 0; }
.waiting-row .patient-name-line { display: flex; align-items: center; gap: 6px; }
.waiting-row .patient-name { font-size: 13px; font-weight: 600; }
.waiting-row .patient-sub { font-size: 12px; color: var(--grey-500); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.waiting-row .waiting-time-badge {
  font-size: 11.5px; font-weight: 700; color: var(--grey-700); background: var(--grey-100);
  border-radius: 6px; padding: 4px 7px; white-space: nowrap; font-variant-numeric: tabular-nums;
}
.waiting-emergency-badge {
  display: inline-flex; align-items: center; gap: 3px; font-size: 10px; font-weight: 700; letter-spacing: 0.02em;
  color: var(--danger); background: var(--danger-bg); border-radius: 999px; padding: 2px 7px;
  text-transform: uppercase; flex-shrink: 0;
}
/* Plain text, not a link like .holiday-popover-footer - Reception's own
   full multi-doctor queue already lives further down this same page,
   so there's nothing else to link to here. */
.waiting-popover-footer {
  border-top: 1px solid var(--grey-300); margin-top: 4px; padding: 8px 10px 2px;
  font-size: 12px; color: var(--grey-500); text-align: center;
}

/* Revenue's one-tap insights chip - same shape as .holiday-chip/
   .waiting-chip, its own class since it's an unrelated feature. Reuses
   the existing .trend-chip.good/.bad badge (defined above for
   Dashboard's stat cards) for the today-vs-yesterday arrow rather than
   inventing a second trend-badge look. */
.revenue-chip-wrap { position: relative; }
.revenue-chip {
  display: inline-flex; align-items: center; gap: 8px; font-family: var(--font);
  font-size: 13px; font-weight: 600; color: var(--chip-text); background: var(--mkt-blue-bg);
  border: none; border-radius: var(--radius-pill); padding: 8px 14px; cursor: pointer; white-space: nowrap;
}
.revenue-chip:hover { filter: brightness(0.97); }
:root[data-theme="dark"] .revenue-chip:hover { filter: brightness(1.2); }
.revenue-popover {
  position: absolute; top: calc(100% + 8px); right: 0; width: 320px;
  background: var(--white); border: 1px solid var(--grey-300); border-radius: 12px;
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.14); z-index: 50; padding: 4px; display: none;
}
.revenue-popover.open { display: block; }
.revenue-section { padding: 12px 14px; }
.revenue-section + .revenue-section { border-top: 1px solid var(--grey-100); }
.revenue-eyebrow {
  font-size: 10.5px; font-weight: 700; color: var(--grey-500);
  text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 8px;
}
.revenue-today-row { display: flex; align-items: baseline; justify-content: space-between; }
.revenue-today-num { font-size: 22px; font-weight: 700; }
.revenue-today-sub { font-size: 12px; color: var(--grey-500); margin-top: 2px; }
.revenue-daypair { display: flex; flex-direction: column; gap: 8px; }
.revenue-day-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
/* Fixed width (not just padding) so "Best" and the longer "Worst" tag
   take up the exact same space - otherwise the dates that follow start
   at two different x-positions depending on which tag came before them. */
.revenue-day-tag {
  font-size: 10.5px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
  border-radius: 999px; padding: 2px 8px; flex-shrink: 0; width: 46px; text-align: center;
}
.revenue-day-tag.best { background: var(--mkt-teal-bg); color: var(--mkt-teal); }
.revenue-day-tag.worst { background: var(--grey-100); color: var(--grey-700); }
.revenue-day-date { font-size: 12.5px; color: var(--grey-700); flex: 1; }
.revenue-day-amt { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
.revenue-doc-row { display: flex; align-items: center; gap: 10px; }
.revenue-doc-row + .revenue-doc-row { margin-top: 8px; }
.revenue-doc-period { font-size: 10.5px; font-weight: 700; color: var(--grey-500); text-transform: uppercase; width: 62px; flex-shrink: 0; }
.revenue-doc-dot { width: 8px; height: 8px; border-radius: 50%; flex-shrink: 0; }
.revenue-doc-info { flex: 1; min-width: 0; }
.revenue-doc-name { font-size: 13px; font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.revenue-doc-count { font-size: 13px; font-weight: 700; color: var(--grey-700); font-variant-numeric: tabular-nums; }
.revenue-outstanding-btn {
  width: 100%; display: flex; align-items: center; justify-content: space-between; gap: 10px;
  background: none; border: none; padding: 0; cursor: pointer; font-family: inherit; text-align: left;
}
.revenue-outstanding-btn:hover .revenue-outstanding-amt { text-decoration: underline; }
.revenue-outstanding-amt { font-size: 15px; font-weight: 700; color: var(--danger); }
.revenue-outstanding-count { font-size: 12px; color: var(--grey-500); margin-top: 2px; }
/* Bigger and accent-blue (the app's standard "this is interactive"
   color), not the same quiet grey as everything around it - at 13px
   grey it read as decoration, not a control worth noticing. */
.revenue-outstanding-arrow { font-size: 22px; line-height: 1; color: var(--accent); font-weight: 700; transition: transform 0.15s ease; }
.revenue-outstanding-arrow.open { transform: rotate(180deg); }
.revenue-outstanding-list { margin-top: 10px; flex-direction: column; gap: 8px; display: none; }
.revenue-outstanding-list.open { display: flex; }
.revenue-outstanding-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.revenue-outstanding-row .info { min-width: 0; }
.revenue-outstanding-row .name { font-size: 12.5px; color: var(--black); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.revenue-outstanding-row .phone { font-size: 11.5px; color: var(--grey-500); font-variant-numeric: tabular-nums; }
.revenue-outstanding-row .amt { font-size: 13px; color: var(--danger); font-weight: 700; font-variant-numeric: tabular-nums; flex-shrink: 0; }
.revenue-empty-note { font-size: 12.5px; color: var(--grey-500); font-style: italic; }

/* Analytics' anomaly chip - scans this-week-vs-last-week across revenue,
   footfall, no-shows and avg. consult duration, surfacing whichever
   moved most. Unlike Revenue/Reception's chip, this one's color/icon
   change with the finding itself (red for a bad move, teal for a good
   one, grey for "nothing stands out") rather than staying one fixed
   color, since the whole point is to catch the eye when something's
   actually worth looking at. Never hides - a calm week is itself the
   answer, not the absence of a check. */
.anomaly-chip-wrap { position: relative; }
.anomaly-chip {
  display: inline-flex; align-items: center; gap: 8px; font-family: var(--font);
  font-size: 13px; font-weight: 700; border: none; border-radius: var(--radius-pill);
  padding: 8px 14px; cursor: pointer; white-space: nowrap;
}
.anomaly-chip.bad { background: var(--danger-bg); color: var(--danger); }
.anomaly-chip.good { background: var(--mkt-teal-bg); color: var(--mkt-teal); }
.anomaly-chip.calm { background: var(--grey-100); color: var(--grey-700); font-weight: 600; }
.anomaly-popover {
  position: absolute; top: calc(100% + 8px); right: 0; width: 340px;
  background: var(--white); border: 1px solid var(--grey-300); border-radius: 12px;
  box-shadow: 0 16px 32px rgba(0, 0, 0, 0.14); z-index: 50; padding: 14px 16px; display: none;
}
.anomaly-popover.open { display: block; }
.anomaly-eyebrow { font-size: 10.5px; font-weight: 700; color: var(--grey-500); text-transform: uppercase; letter-spacing: 0.04em; margin-bottom: 10px; }
.anomaly-card { display: flex; gap: 12px; padding: 10px 0; }
.anomaly-card + .anomaly-card { border-top: 1px solid var(--grey-100); }
.anomaly-badge {
  flex-shrink: 0; width: 34px; height: 34px; border-radius: 50%; display: flex; align-items: center;
  justify-content: center; font-size: 16px;
}
.anomaly-badge.bad { background: var(--danger-bg); }
.anomaly-badge.good { background: var(--mkt-teal-bg); }
.anomaly-body { flex: 1; min-width: 0; }
.anomaly-headline { font-size: 13.5px; font-weight: 700; margin-bottom: 3px; }
.anomaly-headline .num.bad { color: var(--danger); }
.anomaly-headline .num.good { color: var(--mkt-teal); }
.anomaly-sub { font-size: 12px; color: var(--grey-500); line-height: 1.5; }
.anomaly-tab-link { display: inline-block; margin-top: 5px; font-size: 11.5px; font-weight: 700; color: var(--accent-dark); background: none; border: none; padding: 0; cursor: pointer; font-family: var(--font); }
.anomaly-tab-link:hover { text-decoration: underline; }
.anomaly-calm-body { display: flex; align-items: center; gap: 10px; padding: 4px 0 2px; }
.anomaly-calm-body .icon { font-size: 20px; }
.anomaly-calm-body .text { font-size: 13px; color: var(--grey-700); }

.status-pill {
  font-size: 13px;
  font-weight: 700;
  padding: 6px 14px;
  border-radius: var(--radius-pill);
}
.status-on_time { background: var(--success-bg); color: var(--success); }
.status-on_break { background: #ece9fc; color: #5b3ec9; }
.status-emergency { background: var(--danger-bg); color: var(--danger); }
/* Neutral, not warning/danger-toned — a doctor closing their day is the
   normal end of a shift, not something wrong. */
.status-closed { background: var(--grey-300); color: var(--grey-700); }

/* A doctor who isn't on time gets the whole row tinted + a left border
   in the same color as their pill, not just the small pill itself —
   findable at a glance scanning down the list, not only on close read. */
.doctor-status-row.row-status-on_break { background: #ece9fc; border-left: 4px solid #5b3ec9; padding-left: 8px; }
.doctor-status-row.row-status-emergency { background: var(--danger-bg); border-left: 4px solid var(--danger); padding-left: 8px; }
.doctor-status-row.row-status-closed { background: var(--grey-100); border-left: 4px solid var(--grey-500); padding-left: 8px; }
/* Same tint already used for the "In consultation" badge elsewhere -
   a doctor with someone in the chair right now is the one row worth
   spotting first while scanning the list. */
.doctor-status-row.row-in-consult { background: #e8f0fe; border-left: 4px solid var(--accent-dark); padding-left: 8px; }

.toast {
  position: fixed;
  bottom: 24px;
  right: 24px;
  background: var(--dark-surface-bg);
  color: #ffffff;
  padding: 12px 20px;
  border-radius: 10px;
  font-size: 14px;
  opacity: 0;
  transform: translateY(10px);
  transition: opacity 0.2s ease, transform 0.2s ease;
  pointer-events: none;
  z-index: 200;
}
.toast.show { opacity: 1; transform: translateY(0); }

/* ---------------- Waiting-room display screen ---------------- */

.display-body {
  background: var(--black);
  color: var(--white);
  min-height: 100vh;
  /* Top cut roughly in half (was 34px) -- the header block itself
     already carries enough breathing room via its own margin/padding,
     so this was just dead space above the wordmark. */
  padding: 18px 44px 44px;
  font-family: var(--font);
}
.display-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 26px;
  padding-bottom: 18px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
/* Column now, not a horizontal row -- the old layout was tuned for a
   single line of "ClinVision · live queue" text; now it's the full
   wordmark+bar+tagline stack every other page already has. */
.display-header .brand { display: flex; flex-direction: column; align-items: flex-start; }
/* White, not the usual navy ink -- this board's background is
   permanently dark, same reason the old icon needed inverting before
   the wordmark-only rebrand dropped icons entirely. Sized up from the
   nav's own 20px -- this is a TV board meant to be read across a room. */
.display-header .brand-word { color: #fff; font-size: 26px; }
.display-header .brand-tagline { font-size: 14px; margin-top: 5px; }
.display-header .clock { font-size: 28px; font-weight: 800; font-variant-numeric: tabular-nums; letter-spacing: -0.01em; color: var(--white); display: flex; align-items: center; }
/* Same green-dot-blinks pattern as queue.html's own .queue-live-line,
   not the old bare live-dot pulse this used to sit next to -- that one
   had no label and is redundant once this exists. Color is the
   brighter green already proven to work on this board's own fixed-dark
   background (the old live-dot's #34c759), not --success (#1e8e3e),
   which was tuned for light backgrounds and reads duller here. */
.display-live-line { display: flex; align-items: center; justify-content: flex-end; gap: 6px; font-size: 12px; font-weight: 700; color: #34c759; margin-top: 4px; }
.display-live-line .dot { width: 6px; height: 6px; border-radius: 50%; background: #34c759; animation: queue-pulse 1.4s infinite; }
.clock-date { font-size: 12px; color: var(--grey-500); text-align: right; margin-top: 2px; text-transform: uppercase; letter-spacing: 0.06em; }

.live-dot {
  display: inline-block;
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: #34c759;
  margin-right: 10px;
  vertical-align: middle;
  box-shadow: 0 0 0 0 rgba(52, 199, 89, 0.6);
  animation: live-pulse 1.8s ease-out infinite;
}
@keyframes live-pulse {
  0%   { box-shadow: 0 0 0 0 rgba(52, 199, 89, 0.55); }
  70%  { box-shadow: 0 0 0 10px rgba(52, 199, 89, 0); }
  100% { box-shadow: 0 0 0 0 rgba(52, 199, 89, 0); }
}

.section-label {
  font-size: 13px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.06em;
  color: var(--grey-500); margin: 0 0 12px; display: flex; align-items: center; gap: 12px;
}
.section-label .count { font-weight: 600; text-transform: none; letter-spacing: 0; opacity: 0.75; }

/* Departure-board style: one row per doctor, not a card grid — this is
   what actually got redesigned. Row order/content is exactly what
   renderDoctorStrip in display.html computes; this is purely the visual
   layer, none of the underlying refresh/fade/sort logic changed. */
.display-strip { border-radius: 14px; overflow: hidden; border: 1px solid rgba(255, 255, 255, 0.08); margin-bottom: 28px; }
.dboard-row {
  display: grid;
  grid-template-columns: minmax(190px, 0.9fr) 150px 220px 90px 1fr;
  align-items: center;
  background: var(--grey-900);
  padding: 16px 20px;
  gap: 18px;
  border-left: 4px solid transparent;
}
.dboard-row + .dboard-row { border-top: 1px solid rgba(255, 255, 255, 0.08); }
.dboard-row.accent-teal { border-left-color: var(--mkt-teal); }
.dboard-row.accent-blue { border-left-color: var(--mkt-blue); }
.dboard-row.accent-purple { border-left-color: var(--mkt-purple); }
.dboard-row.accent-coral { border-left-color: var(--mkt-coral); }
.dboard-row.accent-pink { border-left-color: var(--mkt-pink); }

.dboard-doc-name { font-size: 21px; font-weight: 800; letter-spacing: -0.01em; }
.dboard-doc-spec { font-size: 13px; color: var(--grey-500); margin-top: 2px; }

.dboard-pill {
  display: inline-flex; align-items: center; gap: 7px;
  font-size: 12px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em;
  padding: 6px 12px; border-radius: 999px; white-space: nowrap;
}
.dboard-pill .dot { width: 7px; height: 7px; border-radius: 50%; background: currentColor; }
.dboard-pill-ok { background: rgba(52, 199, 89, 0.16); color: #34c759; }
.dboard-pill-warn { background: rgba(255, 159, 10, 0.18); color: #ff9f0a; }

/* Now Serving: token above, full patient name below it on its own line
   (wraps rather than truncates — a name is the one thing a waiting
   patient is actually scanning for), call time last. */
.dboard-serving-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.07em; color: var(--grey-500); margin-bottom: 3px; }
.dboard-serving-token { font-size: 26px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1; letter-spacing: -0.02em; }
.dboard-serving-name { font-size: 15px; font-weight: 700; color: var(--white); line-height: 1.25; margin-top: 2px; overflow-wrap: break-word; }
.dboard-serving-idle { font-size: 18px; color: var(--grey-500); font-weight: 700; }
.dboard-serving-called { font-size: 12px; color: var(--grey-500); margin-top: 3px; }

.dboard-waiting { text-align: center; }
.dboard-waiting-num { font-size: 23px; font-weight: 800; font-variant-numeric: tabular-nums; line-height: 1; }
.dboard-waiting-lbl { font-size: 11px; color: var(--grey-500); text-transform: uppercase; letter-spacing: 0.06em; margin-top: 2px; }

.dboard-detail { min-width: 0; }
.dboard-detail-line { font-size: 14px; font-weight: 600; color: #ff9f0a; line-height: 1.4; }
.dboard-detail-line.dboard-detail-muted { color: var(--grey-500); font-weight: 500; }
.dboard-detail-reason { color: var(--grey-300); font-weight: 500; }
.dboard-next { display: flex; align-items: center; gap: 7px; flex-wrap: wrap; }
.dboard-next-label { font-size: 11px; color: var(--grey-500); text-transform: uppercase; letter-spacing: 0.06em; margin-right: 2px; }
.dboard-next-chip { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; background: rgba(255, 255, 255, 0.06); color: var(--grey-300); border: 1px solid rgba(255, 255, 255, 0.08); border-radius: 7px; padding: 3px 9px; }
/* Distinct from the plain token chips on purpose -- this one isn't a
   specific upcoming token, it's a count of everyone past the first 3,
   so it reads as its own category rather than a fourth token at a
   glance. Gold ties it to the brand accent already used for the
   wordmark's underline elsewhere. */
.dboard-next-chip.more { color: #c9973e; background: rgba(201, 151, 62, 0.14); border-color: rgba(201, 151, 62, 0.4); }

/* Airport-departures-style rotating board */
.board {
  background: var(--grey-900);
  border-radius: 18px;
  padding: 6px 0 20px;
}
.board-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 14px 20px 10px;
}
.board-page-indicator { display: flex; gap: 6px; }
.board-page-indicator .dot { width: 6px; height: 6px; border-radius: 50%; background: rgba(255, 255, 255, 0.12); transition: background 0.2s ease, width 0.2s ease; }
.board-page-indicator .dot.active { background: var(--mkt-teal); width: 18px; border-radius: 4px; }

.board-cols {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  gap: 10px;
  padding: 8px 20px;
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--grey-500);
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}

.board-rows {
  min-height: 300px;
  transition: opacity 0.3s ease, transform 0.3s ease;
}
.board-rows.flip-out { opacity: 0; transform: translateY(-8px); }

.board-row {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr 1fr;
  gap: 10px;
  align-items: center;
  padding: 13px 20px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  font-variant-numeric: tabular-nums;
}
.board-row:last-child { border-bottom: none; }
.board-pos { font-size: 17px; font-weight: 800; color: var(--grey-500); }
.board-name { font-size: 17px; font-weight: 600; display: flex; flex-direction: column; }
.board-name-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.board-priority {
  font-size: 11px; font-weight: 800; text-transform: uppercase; letter-spacing: 0.04em;
  color: #ff3b30; background: rgba(255, 59, 48, 0.18);
  border-radius: 999px; padding: 3px 9px; white-space: nowrap;
}
.board-sub { font-size: 12px; font-weight: 400; color: var(--grey-500); margin-top: 2px; }
.board-doc { font-size: 14px; color: var(--grey-300); }
.board-type { font-size: 13px; color: var(--grey-500); }
.board-empty { padding: 44px 0; text-align: center; color: var(--grey-500); font-size: 16px; }

/* Replaces the doctor strip + waiting board entirely once every doctor
   has closed for the day — a passerby glancing at an otherwise-quiet TV
   screen shouldn't have to guess whether it's broken or just genuinely
   nobody's here. Deliberately much bigger than anything else on this
   screen (.board-title is 18px) since it's meant to be read from across
   a waiting room, not up close. */
.display-all-closed {
  background: var(--grey-900);
  border-radius: 20px;
  padding: 80px 40px;
  text-align: center;
  margin-bottom: 28px;
}
.display-all-closed-title { font-size: 56px; font-weight: 700; color: var(--white); margin-bottom: 16px; letter-spacing: -0.01em; }
.display-all-closed-sub { font-size: 22px; color: var(--grey-300); }

@media (max-width: 720px) {
  .app-shell { flex-direction: column; }
  .app-sidebar { width: 100%; flex-direction: row; overflow-x: auto; align-items: center; }
  .app-sidebar nav { flex-direction: row; }
  .app-sidebar .clinic-name-row { display: none; }
  .app-main { padding: 24px 20px; }
  .closed-day-banner { padding: 6px 20px; margin: -24px -20px 6px; }
}

@media (max-width: 900px) {
  .board-cols { display: none; }
  .board-row { grid-template-columns: 40px 1fr; row-gap: 4px; }
  .board-doc, .board-type { grid-column: 2; font-size: 13px; }
}

/* ---------------- Small shared components: slot hints, name/address cells ---------------- */

.slot-hint {
  font-size: 13px;
  margin-top: 8px;
  line-height: 1.5;
  min-height: 20px;
}
.slot-hint.ok { color: var(--success); }
.slot-hint.warn { color: var(--warning); }
.slot-hint.error { color: var(--danger); font-weight: 600; }
.slot-hint .btn-sm { margin-left: 4px; padding: 3px 10px; font-size: 12px; }

/* Scaffolding, not a shipped feature: no SMS provider is connected yet
   (see queueBookingNotification in clinic-data.js), so this is the only
   way to actually reach a patient's queue link right now, for testing
   queue.html against real bookings. Dashed border + warning tint on
   purpose, so it visibly reads as temporary rather than blending in
   with the rest of the form. */
.dev-notification-preview {
  margin-top: 10px;
  padding: 10px 12px;
  border: 1px dashed var(--warning);
  background: var(--warning-bg);
  border-radius: var(--radius-sm);
  font-size: 13px;
  line-height: 1.5;
  color: var(--black);
}
.dev-notification-eyebrow {
  font-size: 11px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--warning);
  margin-bottom: 4px;
}
.dev-notification-preview a { color: var(--accent); font-weight: 600; word-break: break-all; }

.sub-line {
  font-size: 12px;
  color: var(--grey-500);
  margin-top: 2px;
}

/* Inline invoice-correction box on Reception's queue row (see
   billingCell in reception.html). Fixed width keeps the three controls
   aligned to the same edge instead of each sizing to its own content. */
.adj-box { display: flex; flex-direction: column; gap: 5px; width: 130px; }
.adj-box select, .adj-box input {
  width: 100%;
  box-sizing: border-box;
  font-size: 13px;
  padding: 5px 8px;
  border: 1px solid var(--grey-300);
  border-radius: 6px;
  font-family: var(--font);
}
.adj-actions { display: flex; gap: 4px; margin-top: 2px; }
.adj-actions .btn-sm { padding: 4px 10px; font-size: 12px; }

/* Add-patient mode toggle: walk-in vs. phoned appointment used to be two
   separate, near-identical forms — easy to fill in the wrong one. Now it's
   one form whose accent color and fields change with the chosen mode, so
   there's only one place to type and the choice has to be made on purpose. */
.patient-panel {
  border-width: 2px;
  transition: border-color 0.2s ease;
}
.patient-panel.mode-walkin { border-color: var(--grey-500); }
.patient-panel.mode-appointment { border-color: var(--accent); }

/* Same gradient-track/gradient-pill treatment as Analytics' group tabs
   (#trendGroupSeg) and Revenue/No-shows' Single day-Range pills
   (.period-pill) - the container is the raised track, buttons sit
   borderless inside it. Unlike those two, each active state here keeps
   its own distinct color (blue for a phoned-in appointment or the
   light theme choice, near-black for a walk-in or the dark theme
   choice) rather than one uniform accent gradient - that distinction
   is meaningful (walk-in vs. booked-ahead, light vs. dark) and predates
   this restyle, so it's carried forward as a matching pair of
   gradients instead of being flattened away. */
.mode-toggle {
  display: inline-flex;
  background: linear-gradient(180deg, var(--grey-100), var(--white));
  border: 1px solid var(--grey-300);
  border-radius: var(--radius-pill);
  padding: 4px;
  gap: 2px;
  margin-bottom: 16px;
  box-shadow: var(--shadow-resting), inset 0 1px 0 rgba(255, 255, 255, 0.5);
  flex-wrap: wrap;
}
.mode-btn {
  font-family: var(--font);
  font-size: 14px;
  font-weight: 700;
  letter-spacing: 0.01em;
  padding: 10px 18px;
  border-radius: var(--radius-pill);
  border: 1.5px solid transparent;
  background: transparent;
  color: var(--grey-700);
  cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.mode-btn:hover:not(.active) { color: var(--accent-dark); }
/* Crisp white outline - same treatment as #trendGroupSeg's active pill,
   applied everywhere this gradient-pill pattern appears. Works on both
   color variants below since white reads clearly against near-black too. */
.mode-btn.active[data-mode="walkin"], .mode-btn.active[data-theme-choice="dark"] {
  background: linear-gradient(135deg, var(--grey-900), var(--black)); color: #ffffff;
  border-color: rgba(255, 255, 255, 0.9); box-shadow: 0 3px 10px rgba(0, 0, 0, 0.3);
}
.mode-btn.active[data-mode="appointment"], .mode-btn.active[data-theme-choice="light"] {
  background: linear-gradient(135deg, var(--accent), var(--accent-dark)); color: #ffffff;
  border-color: rgba(255, 255, 255, 0.9); box-shadow: 0 3px 10px rgba(0, 113, 227, 0.35);
}

/* Doctor View's status row (Clear status/On a break/Emergency) - same
   gradient-track look as the toggles above, scoped by id rather than
   changed on .success-outline/.accent-outline/.danger-outline themselves
   (those are generic outline-button classes used elsewhere in the app
   that never asked for this treatment). Unlike a real toggle these three
   are independent actions, not mutually-exclusive selections, so there's
   no single "active" pill to highlight - each button stays outlined
   (green/blue/red, matching their existing outline colors) and only
   fills with its gradient on hover, so it reads as a real pressable
   control rather than three permanently-lit status lights. Disabled
   state (nothing to clear, or the day is closed) still dims normally via
   the base .btn-sm:disabled opacity rule - untouched here. */
#statusActionSeg {
  display: inline-flex; background: linear-gradient(180deg, var(--grey-100), var(--white));
  border: 1px solid var(--grey-300); border-radius: var(--radius-pill); padding: 4px; gap: 2px;
  box-shadow: var(--shadow-resting), inset 0 1px 0 rgba(255, 255, 255, 0.5);
}
/* Outlined by default (transparent fill, colored border+text) and only
   fills with the full gradient on hover — reads as a real pressable
   control rather than three permanently-lit status lights. Border stays
   1.5px on hover too (colored -> crisp white, never "none") so nothing
   shifts size; the white ring on fill matches the same treatment used
   on every other active gradient pill in the app (Analytics tabs, the
   mode toggles, Revenue/No-shows' day-range pills). */
#statusActionSeg .btn-sm {
  border: 1.5px solid transparent; border-radius: var(--radius-pill); font-weight: 700; letter-spacing: 0.01em;
  background: transparent;
  transition: background 0.16s ease, color 0.16s ease, box-shadow 0.16s ease, border-color 0.16s ease;
}
#statusActionSeg .btn-sm.success-outline { border-color: var(--success); color: var(--success); }
#statusActionSeg .btn-sm.success-outline:hover {
  border-color: rgba(255, 255, 255, 0.9); background: linear-gradient(135deg, var(--success), #166a2e); color: #ffffff; box-shadow: 0 3px 10px rgba(30, 142, 62, 0.3);
}
#statusActionSeg .btn-sm.accent-outline { border-color: var(--accent); color: var(--accent); }
#statusActionSeg .btn-sm.accent-outline:hover {
  border-color: rgba(255, 255, 255, 0.9); background: linear-gradient(135deg, var(--accent), var(--accent-dark)); color: #ffffff; box-shadow: 0 3px 10px rgba(0, 113, 227, 0.35);
}
#statusActionSeg .btn-sm.danger-outline { border-color: var(--danger); color: var(--danger); }
#statusActionSeg .btn-sm.danger-outline:hover {
  border-color: rgba(255, 255, 255, 0.9); background: linear-gradient(135deg, #e0433d, var(--danger)); color: #ffffff; box-shadow: 0 3px 10px rgba(197, 34, 31, 0.35);
}

.order-note {
  font-weight: 400;
  color: var(--grey-500);
  font-size: 12px;
  text-transform: none;
  letter-spacing: normal;
}

/* ---------------- Interactive polish: hover lift + micro-interactions ---------------- */

.panel, .stat-card, .mkt-feature-card {
  transition: transform 0.18s ease, box-shadow 0.18s ease, border-color 0.18s ease;
}
.stat-card:hover, .mkt-feature-card:hover {
  transform: translateY(-3px);
  box-shadow: var(--shadow-hover);
  border-color: var(--grey-300);
}

/* Gated to real pointer devices, same fix already applied to the
   sidebar nav links and billing option cards -- and the :active
   counter-transform below them is gone entirely, not just gated.
   With both a hover-lift and an active-flatten each transitioning on
   their own, clicking (mouse down applies :active, mouse up while
   still hovering re-applies :hover) played the lift animation
   backwards then forwards again in well under a second, which read as
   the button shaking rather than a clean press. The other two fixes
   solved a stuck-hover-on-tap bug and never had an :active rule to
   begin with; removing this one's :active brings it in line with
   that same pattern -- hover still lifts the button on a real pointer,
   nothing animates back down again on click. */
@media (hover: hover) and (pointer: fine) {
  .btn:hover, .btn-sm:hover { transform: translateY(-1px); box-shadow: 0 6px 18px rgba(0, 0, 0, 0.15); }
}

table.qtable tbody tr { transition: background 0.12s ease; }
table.qtable tbody tr:hover { background: var(--grey-100); }
table.qtable tbody tr.breakdown-row-link { cursor: pointer; }
table.qtable tbody tr.breakdown-row-link:hover { background: var(--mkt-blue-bg); }

.stat-card .value {
  transition: color 0.2s ease;
}

.eyebrow {
  position: relative;
  padding-left: 16px;
}
.eyebrow::before {
  content: '';
  position: absolute;
  left: 0;
  top: 50%;
  transform: translateY(-50%);
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
}

.reveal {
  opacity: 0;
  transform: translateY(24px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}
.reveal.visible {
  opacity: 1;
  transform: translateY(0);
}

/* ---------------- Billing receipt (print-only, sized for A4) ----------------
   The whole receipt is meant to fit on one A4 page (@media print below) -
   adding the GSTIN line and the GST-exempt line pushed a normal receipt
   past that by ~40-50px, spilling the signature/footer/exempt-line block
   onto a second printed page. Several margins/paddings below
   (.receipt-header, .receipt-meta-row, .receipt-info-grid,
   .receipt-items td, .receipt-totals-wrap, .receipt-signature-wrap,
   .receipt-footer, .receipt-exempt-line) were trimmed by a few px each to
   claw that back - deliberately tighter than they'd otherwise be, not an
   oversight. If a future addition needs more vertical room again, trim
   here first rather than letting the receipt silently split across
   pages. */

.receipt {
  display: none;
  font-size: 14px;
  line-height: 1.6;
  color: var(--black);
}

/* Centered, stacked hero block — the clinic's own identity is the first
   thing on a printed receipt, so it gets the same prominence a real
   letterhead would, not a small icon squeezed beside the receipt number.
   The logo is unconstrained (no forced square + object-fit:cover, which
   was cropping anything wider than it is tall down to an unrecognizable
   sliver) — max-height/max-width cap its footprint while keeping its
   real proportions intact. */
.receipt-header {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  border-bottom: 3px solid var(--accent);
  padding-bottom: 16px;
  margin-bottom: 8px;
}
.receipt-logo { max-height: 96px; max-width: 320px; width: auto; height: auto; object-fit: contain; margin-bottom: 12px; }
.receipt-clinic-name { font-size: 30px; font-weight: 700; letter-spacing: -0.01em; }
.receipt-clinic-address { color: var(--grey-700); margin-top: 6px; font-size: 13px; }
/* Centered under the address (inherits .receipt-header's own
   text-align: center) - shown only when Settings -> Clinic Settings
   has a GSTIN on file, entirely independent of the exemption line
   near the bottom (that one always prints, GSTIN or not). */
.receipt-clinic-gstin { color: var(--grey-500); margin-top: 3px; font-size: 12.5px; }
.receipt-number-block { text-align: right; }
.receipt-number-label { font-size: 12px; color: var(--grey-500); }
.receipt-number { font-size: 18px; font-weight: 700; color: var(--accent); }

.receipt-meta-row {
  display: flex;
  justify-content: space-between;
  color: var(--grey-500);
  font-size: 13px;
  margin-bottom: 24px;
}

.receipt-info-grid { width: 100%; border-collapse: collapse; margin-bottom: 20px; }
.receipt-info-grid td { width: 50%; padding: 0 20px 18px 0; vertical-align: top; }
.receipt-info-grid td + td { padding-left: 20px; border-left: 1px solid var(--grey-100); }
.receipt-label {
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--grey-500);
  margin-bottom: 4px;
}
.receipt-value { font-size: 15px; font-weight: 600; }

.receipt-items { width: 100%; border-collapse: collapse; margin-bottom: 4px; }
.receipt-items thead tr { border-bottom: 2px solid var(--black); }
.receipt-items th {
  text-align: left;
  font-size: 12px;
  font-weight: 700;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--grey-700);
  padding-bottom: 12px;
}
.receipt-items th:last-child, .receipt-items td:last-child { text-align: right; }
.receipt-items td { padding: 14px 0; border-bottom: 1px solid var(--grey-300); font-size: 15px; }

.receipt-totals-wrap { display: flex; justify-content: flex-end; margin-top: 16px; margin-bottom: 18px; }
.receipt-totals { width: 280px; }
.receipt-totals-row { display: flex; justify-content: space-between; padding: 8px 0; font-size: 15px; }
.receipt-totals-row span:first-child { color: var(--grey-700); }
.receipt-grand-total {
  display: flex;
  justify-content: space-between;
  padding-bottom: 12px;
  margin-bottom: 4px;
  border-bottom: 1px solid var(--grey-300);
  font-size: 17px;
  font-weight: 700;
}
/* Deliberately last and bolder than Grand total: the point of this
   layout is that whoever's reading top-to-bottom lands on what's
   actually still owed, not on a total that could be mistaken for
   "fully paid" just because it's the biggest number on the page. */
.receipt-balance-row {
  display: flex;
  justify-content: space-between;
  padding-top: 12px;
  margin-top: 4px;
  border-top: 1px solid var(--grey-300);
  font-size: 17px;
  font-weight: 700;
}
.receipt-payment-pill-wrap { text-align: right; margin-top: 10px; }
.receipt-payment-pill {
  display: inline-block;
  background: rgba(0, 113, 227, 0.1);
  color: var(--accent-dark);
  font-size: 13px;
  font-weight: 600;
  padding: 5px 14px;
  border-radius: 999px;
}

.receipt-signature-wrap { display: flex; justify-content: space-between; align-items: flex-end; margin-top: 22px; page-break-inside: avoid; }
.receipt-generated-note { font-size: 12px; color: var(--grey-500); max-width: 260px; }
.receipt-signature-line {
  width: 220px;
  text-align: center;
  border-top: 1px solid var(--grey-500);
  padding-top: 6px;
  font-size: 12px;
  color: var(--grey-700);
}

.receipt-footer {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 12px;
  text-align: left;
  color: var(--grey-500);
  margin-top: 12px;
  padding-top: 10px;
  border-top: 1px solid var(--grey-100);
  font-size: 13px;
  page-break-inside: avoid;
}
/* Big enough to actually read as the clinic's mark (not a favicon-sized
   afterthought) while staying well inside the space reclaimed above from
   .receipt-signature-wrap/.receipt-footer's own trimmed margins, so a
   normal-length receipt still prints on a single page. */
.receipt-footer-logo { max-height: 56px; max-width: 160px; width: auto; height: auto; object-fit: contain; }
.receipt-footer-address { font-size: 12px; margin-top: 2px; }
/* Plain small print, not a boxed callout - reads as an ordinary
   compliance footnote rather than something competing for attention
   with the amount actually charged higher up the page. */
.receipt-exempt-line { text-align: right; color: var(--black); font-style: italic; font-weight: 700; font-size: 10.5px; margin-top: 8px; }

@media print {
  @page { size: A4; margin: 15mm; }
  body * { visibility: hidden; }
  #printReceipt, #printReceipt * { visibility: visible; }
  #printReceipt {
    display: block;
    position: absolute;
    left: 0;
    top: 0;
    width: 100%;
  }
}
