/* Goja Smiles CRM
   Colour values are sampled from the reference screenshots, not estimated.
   No hard-coded colour may appear outside :root — add a token instead. */

:root{
  --primary:#06B8B7;
  --primary-bright:#01C6C1;
  --primary-soft:#C6EBEA;
  --bg:#F6F6F6;
  --bg-tint:#F4FBFB;
  --surface:#FFFFFF;
  --border:#EAEBEF;
  --line:#E5E7E8;
  --text:#333333;
  --text-muted:#8D8D8D;

  --accent-orange:#F08C3C;
  --tooth-filled:#06B8B7;
  --tooth-crown:#FA7800;
  --tooth-implant:#0078FA;
  --tooth-missing:#C8C8C8;
  --wa-green:#25D366;      /* WhatsApp brand */
  --wa-green-dark:#1DA851;
  --tooth-fissure:#7C8288;          /* grooves, cool to match the enamel */
  --tooth-fissure-on:rgba(0,0,0,.26); /* over a state colour */
  --danger:#E5342A;
  --ok:#50D25A;

  --chip-orange:#FFCEBB;
  --chip-teal:#C6EBEA;
  --chip-purple:#E7E6FB;
  --chip-green:#DCF5E8;
  --chip-red:#F7C4C1;

  /* Visit status. Green = still open, you can work on it. Faded red =
     finished. Deliberately not the usual green-is-good/red-is-bad reading:
     here the colour says "actionable" versus "closed". */
  --visit-open-bar:#50D25A;
  --visit-open-bg:#F2FBF5;
  --visit-done-bar:#E5342A;
  --visit-done-bg:#FDF1F0;

  /* appointment blocks — sampled from the reference calendar */
  --appt-teal:#CFEFED;
  --appt-blue:#B2EDFF;

  --brand-navy:#283890;
  --brand-blue:#4098C0;

  --on-primary:#FFFFFF;
  --enamel-top:#FAFBFC;      /* crown: cool white, not cream */
  --enamel-bottom:#E4E2DC;   /* root: duller and warmer than the crown */
  --enamel-edge:#B9BDC2;     /* outline: grey, so the shape stays crisp */

  --radius:8px;
  --shadow:0 1px 3px rgba(0,0,0,.08);
  --header-h:48px;
  --nav-h:44px;
}

*,*::before,*::after{box-sizing:border-box}
html,body{height:100%}
body{
  margin:0;background:var(--bg);color:var(--text);
  font:400 14px/1.45 -apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;
  -webkit-font-smoothing:antialiased;
}
a{color:var(--primary);text-decoration:none}
button{font:inherit}

/* ---------- header ---------- */
.hdr{
  height:var(--header-h);background:var(--primary);
  display:flex;align-items:center;justify-content:space-between;
  padding:0 20px;position:relative;z-index:20;
}
.hdr__logo{height:28px;width:auto;display:block}
.hdr__user{display:flex;align-items:center;gap:8px;color:var(--on-primary);cursor:pointer;position:relative}
.hdr__avatar{
  width:30px;height:30px;border-radius:50%;object-fit:cover;
  border:2px solid rgba(255,255,255,.65);background:var(--primary-soft);
  display:grid;place-items:center;font-size:12px;font-weight:700;color:var(--primary);
}
.hdr__meta{line-height:1.15}
.hdr__name{font-weight:600;font-size:13px}
.hdr__role{font-size:11px;opacity:.85}
.hdr__caret{font-size:10px;opacity:.9;margin-left:2px}

/* Settings beside the avatar. Hidden on desktop, where the top nav lists it. */
.hdr__settings{display:none}

.menu{
  position:absolute;top:calc(100% + 6px);right:0;min-width:170px;
  background:var(--surface);border-radius:var(--radius);box-shadow:0 4px 16px rgba(0,0,0,.16);
  padding:6px;display:none;
}
.menu[data-open="true"]{display:block}
.menu button{
  display:block;width:100%;text-align:left;background:none;border:0;
  padding:8px 10px;border-radius:6px;font-size:13px;color:var(--text);cursor:pointer;
}
.menu button:hover{background:var(--bg)}

/* ---------- nav ---------- */
.nav{
  height:var(--nav-h);background:var(--surface);border-bottom:1px solid var(--border);
  display:flex;align-items:stretch;padding:0 20px;gap:22px;position:sticky;top:0;z-index:10;
}
.nav__spacer{margin-left:auto}
.nav__item{
  display:inline-flex;align-items:center;gap:6px;font-size:13px;
  color:var(--text-muted);height:100%;border-bottom:2px solid transparent;
  white-space:nowrap;cursor:pointer;background:none;border-left:0;border-right:0;border-top:0;
}
.nav__item:hover{color:var(--text)}
.nav__item[aria-current="page"]{color:var(--primary);border-bottom-color:var(--primary)}
.nav__ico{width:14px;height:14px;flex:none;opacity:.75}
.nav__item[aria-current="page"] .nav__ico{opacity:1}

/* ---------- layout ---------- */
.page{padding:18px 20px 40px}
.card{background:var(--surface);border-radius:var(--radius);box-shadow:var(--shadow)}
.h1{font-size:17px;font-weight:600;color:var(--primary);margin:0 0 14px}

.split{display:grid;grid-template-columns:230px 1fr;gap:18px;align-items:start}
/* Visit editor reverses the ratio: chart wide on the left, treatments right.
   A class, not an inline style, so the media queries below can still win. */
.split--visit{grid-template-columns:minmax(0,1fr) 320px}

/* ---------- patient profile card ---------- */
.profile{padding:18px 16px;text-align:center}
.profile__avatar{
  width:96px;height:96px;border-radius:50%;margin:0 auto 10px;
  border:3px solid var(--primary);object-fit:cover;background:var(--primary-soft);
  display:grid;place-items:center;font-size:30px;font-weight:700;color:var(--primary);
}
.profile__name{font-size:16px;font-weight:600}
.profile__cap{font-size:12px;color:var(--primary);margin-bottom:12px}
.profile__head{
  display:flex;align-items:center;justify-content:space-between;gap:8px;
  text-align:left;font-size:13px;font-weight:600;padding:2px 0 8px;
}
.profile__rows{text-align:left;border-top:1px solid var(--line);padding-top:12px}

/* Label and value share a line, label in teal — as the reference does. */
.frow{margin-bottom:10px;font-size:12.5px;line-height:1.35}
.frow__label{color:var(--primary);margin-right:4px}
.frow__value{color:var(--text);word-break:break-word}
.frow--danger .frow__value{color:var(--danger)}

/* Stacked variant for the visit editor's info strip. */
.frow--stack .frow__label{display:block;font-size:11px;margin:0 0 1px}

/* ---------- KPI chips ---------- */
.kpis{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-bottom:14px}
.kpi{display:flex;align-items:center;gap:8px;padding:8px 10px}
.kpi__well{
  width:26px;height:26px;border-radius:7px;flex:none;
  display:grid;place-items:center;font-size:12px;
}
.kpi__value{font-size:14px;font-weight:700;line-height:1.15}
.kpi__label{font-size:9.5px;color:var(--text-muted);line-height:1.15;display:block}

/* ---------- table ---------- */
.tbl{width:100%;border-collapse:collapse;font-size:13px}
.tbl th{
  text-align:left;font-weight:600;font-size:12px;color:var(--text-muted);
  padding:11px 14px;border-bottom:1px solid var(--line);white-space:nowrap;
}
.tbl td{padding:7px 14px;border-bottom:1px solid var(--line);vertical-align:middle}
.tbl tr:last-child td{border-bottom:0}
.tbl__sub{display:block;font-size:11px;line-height:1.25;color:var(--primary)}
.tbl__actions{display:flex;gap:12px;align-items:center;justify-content:flex-end}
.linkbtn{background:none;border:0;padding:0;color:var(--primary);font-size:13px;cursor:pointer}
.linkbtn--danger{color:var(--danger)}
.linkbtn--report{color:var(--accent-orange);white-space:nowrap}
.linkbtn[disabled]{opacity:.45;cursor:not-allowed}

/* Segmented buttons above the visits table. */
.segbar{display:flex;align-items:center;gap:10px;margin-bottom:12px}
.seg{
  height:32px;padding:0 16px;border-radius:6px;font-size:13px;cursor:pointer;
  border:1px solid var(--border);background:var(--surface);color:var(--text-muted);
  display:inline-flex;align-items:center;gap:6px;
}
.seg[aria-pressed="true"]{background:var(--primary);border-color:var(--primary);color:var(--on-primary)}

.toolbar{display:flex;gap:10px;align-items:center;margin-bottom:14px;flex-wrap:wrap}
.input,.select{
  height:34px;padding:0 10px;border:1px solid var(--border);border-radius:6px;
  background:var(--surface);font-size:13px;color:var(--text);min-width:0;
}
.input:focus,.select:focus{outline:2px solid var(--primary-soft);border-color:var(--primary)}
.input--search{flex:1;max-width:280px}

.btn{
  height:34px;padding:0 16px;border-radius:6px;border:1px solid transparent;
  background:var(--primary);color:var(--on-primary);font-size:13px;font-weight:500;cursor:pointer;
}
.btn:hover{background:var(--primary-bright)}
.btn--ghost{background:var(--surface);color:var(--primary);border-color:var(--primary)}
.btn--ghost:hover{background:var(--bg-tint)}
.btn[disabled]{opacity:.5;cursor:not-allowed}

.empty{padding:40px 20px;text-align:center;color:var(--text-muted);font-size:13px}
.pager{display:flex;gap:8px;align-items:center;justify-content:flex-end;padding:12px 14px;font-size:12px;color:var(--text-muted)}

/* ---------- odontogram ---------- */
.jawtabs{display:flex;gap:8px;margin-bottom:14px}
.jawtab{
  height:30px;padding:0 14px;border-radius:6px;border:1px solid var(--primary);
  background:var(--surface);color:var(--primary);font-size:13px;cursor:pointer;
}
.jawtab[aria-pressed="true"]{background:var(--primary);color:var(--on-primary)}

.odo{overflow-x:auto;padding-bottom:4px}
.odo__inner{min-width:560px}
.odo__row{display:grid;grid-template-columns:repeat(16,1fr);gap:2px;align-items:center}
.odo__row--nums{margin:2px 0}
.odo__num{text-align:center;font-size:10px;color:var(--text-muted);user-select:none}
.odo__gap{height:8px}

.tooth{
  background:none;border:0;padding:1px;cursor:pointer;display:block;width:100%;
  /* Stop the OS text-selection callout and magnifier hijacking a long press. */
  -webkit-touch-callout:none;-webkit-user-select:none;user-select:none;
  -webkit-tap-highlight-color:transparent;touch-action:pan-x pan-y;
}
/* Grows under the finger so a long press feels like it is registering. */
.tooth--pressing{transform:scale(1.12);transition:transform .45s ease-out}
.tooth[disabled]{cursor:default}
.toothsvg{display:block;width:100%;height:auto;max-height:58px;margin:0 auto}

/* Enamel gradient is faked with two flat fills — cheaper than a real
   gradient and indistinguishable at this size. */
.toothsvg__root{fill:var(--enamel-bottom);stroke:var(--enamel-edge);stroke-width:.6}
.toothsvg__crown{fill:var(--enamel-top);stroke:var(--enamel-edge);stroke-width:.7}

/* Depth layers. These sit on top of the crown and carry no colour of their
   own, so a filled, carious or crowned tooth keeps its clinical hue and still
   looks solid. Not clickable — the crown underneath takes the tap. */
.toothsvg__shade,
.toothsvg__gloss,
.toothsvg__rootshade{stroke:none}

/* Fissures across the biting surface. Thin and low-contrast: they should
   suggest anatomy at 40px wide, not draw the eye away from the state colour. */
.toothsvg__groove{
  fill:none;stroke:var(--tooth-fissure);stroke-opacity:.30;
  stroke-width:.9;stroke-linecap:round;
}

/* On a coloured tooth the brown fissure would muddy the hue, so it turns into
   a dark wash of the colour already there. */
.tooth:not([data-state="healthy"]) .toothsvg__groove{stroke:var(--tooth-fissure-on)}

/* A planned treatment is an outline only — shading a hollow shape looks like
   a rendering fault. */
.tooth[data-state="planned"] .toothsvg__shade,
.tooth[data-state="planned"] .toothsvg__gloss,
.tooth[data-state="planned"] .toothsvg__groove{display:none}
.toothsvg__x{stroke:var(--tooth-missing);stroke-width:3;stroke-linecap:round}

/* State tints the crown only — roots stay enamel-coloured, as in the reference. */
.tooth[data-state="filled"]     .toothsvg__crown{fill:var(--tooth-filled);stroke:var(--tooth-filled)}
.tooth[data-state="crown"]      .toothsvg__crown{fill:var(--tooth-crown);stroke:var(--tooth-crown)}
.tooth[data-state="implant"]    .toothsvg__crown{fill:var(--tooth-implant);stroke:var(--tooth-implant)}
.tooth[data-state="root_canal"] .toothsvg__crown{fill:var(--tooth-implant);stroke:var(--tooth-implant)}
.tooth[data-state="root_canal"] .toothsvg__root{fill:var(--tooth-implant);opacity:.55}
.tooth[data-state="caries"]     .toothsvg__crown{fill:var(--danger);stroke:var(--danger)}
.tooth[data-state="bridge"]     .toothsvg__crown{fill:var(--tooth-crown);stroke:var(--tooth-crown);opacity:.75}
.tooth[data-state="planned"]    .toothsvg__crown{fill:none;stroke:var(--primary);stroke-width:1.6;stroke-dasharray:3 2}
.tooth[data-state="extracted"]  .toothsvg__crown,
.tooth[data-state="extracted"]  .toothsvg__root{opacity:.28}

.tooth[aria-pressed="true"]{background:var(--primary-soft);border-radius:6px}

/* surface marker */
.surfbtn{background:none;border:0;padding:1px;cursor:pointer;display:block;width:100%}
.surfbtn[disabled]{cursor:default}
.surf{display:block;width:16px;height:16px;margin:0 auto}
.surf__quad{fill:var(--line);stroke:var(--surface);stroke-width:1.2}
.surf__core{fill:var(--tooth-missing);stroke:var(--surface);stroke-width:1.2}
.surfbtn[data-state="filled"]     .surf__quad,.surfbtn[data-state="filled"]     .surf__core{fill:var(--tooth-filled)}
.surfbtn[data-state="crown"]      .surf__quad,.surfbtn[data-state="crown"]      .surf__core{fill:var(--tooth-crown)}
.surfbtn[data-state="implant"]    .surf__quad,.surfbtn[data-state="implant"]    .surf__core{fill:var(--tooth-implant)}
.surfbtn[data-state="root_canal"] .surf__quad,.surfbtn[data-state="root_canal"] .surf__core{fill:var(--tooth-implant)}
.surfbtn[data-state="caries"]     .surf__quad,.surfbtn[data-state="caries"]     .surf__core{fill:var(--danger)}
.surfbtn[data-state="bridge"]     .surf__quad,.surfbtn[data-state="bridge"]     .surf__core{fill:var(--tooth-crown)}
.surfbtn[data-state="extracted"]  .surf__quad,.surfbtn[data-state="extracted"]  .surf__core{fill:var(--tooth-missing)}
.surfbtn[data-state="planned"]    .surf__quad{fill:none;stroke:var(--primary)}
.surfbtn[data-state="planned"]    .surf__core{fill:none;stroke:var(--primary)}

/* legend */
.legend{display:flex;flex-wrap:wrap;gap:12px;margin-top:12px;font-size:11px;color:var(--text-muted);align-items:center}
.legend span{display:inline-flex;align-items:center;gap:5px}
.legend__hint{color:var(--primary)}
.legend__dot{width:10px;height:10px;border-radius:50%;background:var(--line);flex:none}
.legend__dot[data-state="filled"]{background:var(--tooth-filled)}
.legend__dot[data-state="crown"]{background:var(--tooth-crown)}
.legend__dot[data-state="implant"],.legend__dot[data-state="root_canal"]{background:var(--tooth-implant)}
.legend__dot[data-state="caries"]{background:var(--danger)}
.legend__dot[data-state="extracted"]{background:var(--tooth-missing)}

/* state picker */
.picker{
  position:fixed;z-index:60;background:var(--surface);border-radius:var(--radius);
  box-shadow:0 6px 24px rgba(0,0,0,.22);padding:10px;min-width:214px;
}
.picker__title{font-size:11px;color:var(--text-muted);margin-bottom:8px}
.picker__grid{display:grid;grid-template-columns:1fr 1fr;gap:3px}
.picker__opt{
  display:flex;align-items:center;gap:7px;background:none;border:0;cursor:pointer;
  padding:7px 8px;border-radius:6px;font-size:12px;color:var(--text);text-align:left;
  min-height:34px;
}
.picker__opt:hover{background:var(--bg)}
.picker__opt[aria-checked="true"]{background:var(--primary-soft);font-weight:600}
.picker__dot{width:12px;height:12px;border-radius:50%;flex:none;border:1px solid var(--enamel-edge);background:var(--enamel-top)}
.picker__dot[data-state="filled"]{background:var(--tooth-filled);border-color:var(--tooth-filled)}
.picker__dot[data-state="crown"]{background:var(--tooth-crown);border-color:var(--tooth-crown)}
.picker__dot[data-state="implant"],.picker__dot[data-state="root_canal"]{background:var(--tooth-implant);border-color:var(--tooth-implant)}
.picker__dot[data-state="caries"]{background:var(--danger);border-color:var(--danger)}
.picker__dot[data-state="bridge"]{background:var(--tooth-crown);border-color:var(--tooth-crown);border-radius:3px}
.picker__dot[data-state="extracted"]{background:var(--tooth-missing);border-color:var(--tooth-missing)}
.picker__dot[data-state="planned"]{background:none;border-color:var(--primary);border-width:2px}

/* ---------- forms ---------- */
.formgrid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px 16px}
.field--wide{grid-column:1/-1}
@media (max-width:1023px){.formgrid{grid-template-columns:repeat(2,1fr)}}
@media (max-width:767px){.formgrid{grid-template-columns:1fr}}

/* ---------- visit editor ---------- */
.infostrip{display:grid;grid-template-columns:repeat(5,1fr);gap:12px 18px;padding:14px 16px;margin-bottom:14px}
.entry{display:grid;grid-template-columns:1fr 110px 1fr auto;gap:12px;align-items:end;padding:14px 16px}
.field{display:flex;flex-direction:column;gap:4px;min-width:0}
.field__label{font-size:11px;color:var(--primary)}

.txlist{list-style:none;margin:0;padding:0}
.tx{display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid var(--line)}
.tx:last-child{border-bottom:0}
.tx__badge{
  width:26px;height:26px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--chip-teal);color:var(--primary);font-size:11px;font-weight:700;
}
.tx__body{flex:1;min-width:0}
.tx__name{font-size:13px}
.tx__teeth{font-size:11px;color:var(--text-muted)}
.tx__price{
  background:var(--primary);color:var(--on-primary);font-size:11px;font-weight:600;
  padding:2px 7px;border-radius:4px;white-space:nowrap;
}
.total{display:flex;align-items:center;justify-content:flex-end;gap:10px;padding:12px 14px;font-size:13px}
.total__value{font-size:16px;font-weight:700}
.actions{display:flex;gap:10px;justify-content:flex-end;padding:0 14px 14px}

.tabs{display:flex;gap:6px;padding:10px 14px 0}
.tab{
  background:none;border:0;border-bottom:2px solid transparent;padding:6px 8px;
  font-size:13px;color:var(--text-muted);cursor:pointer;
}
.tab[aria-selected="true"]{color:var(--primary);border-bottom-color:var(--primary)}


/* ---------- settings ---------- */
.tabs--settings{
  padding:0 0 12px;border-bottom:1px solid var(--border);margin-bottom:16px;
  /* Five tabs exceed a 320px phone. Scroll the strip rather than letting it
     push the whole page sideways. */
  overflow-x:auto;scrollbar-width:none;
}
.tabs--settings::-webkit-scrollbar{display:none}
.tabs--settings .tab{flex:0 0 auto;white-space:nowrap}
.hint{font-size:11px;color:var(--text-muted);margin-top:6px}
.logorow{display:flex;gap:16px;align-items:flex-start;margin-top:8px;flex-wrap:wrap}
.logobox{
  width:180px;height:64px;border:1px dashed var(--border);border-radius:var(--radius);
  display:grid;place-items:center;background:var(--bg);flex:none;overflow:hidden;
}
.logobox__img{max-width:96%;max-height:88%;object-fit:contain}
.logobox__empty{font-size:11px;color:var(--text-muted)}

/* ---------- login ---------- */
.login{min-height:100%;display:grid;place-items:center;background:var(--bg-tint);padding:20px}
.login__card{width:100%;max-width:360px;padding:28px 26px;text-align:center}
.login__logo{max-width:200px;height:auto;margin:0 auto 22px;display:block}
.login__field{text-align:left;margin-bottom:12px}
.login__field .input{width:100%}
.login__err{color:var(--danger);font-size:12px;min-height:16px;margin:4px 0 8px}
.login__remember{
  display:flex;align-items:center;gap:8px;text-align:left;
  font-size:13px;cursor:pointer;margin-top:4px;
}
.login__remember input{width:16px;height:16px;accent-color:var(--primary);cursor:pointer}
.login__hint{text-align:left;margin:4px 0 0}



.withbtn{display:flex;gap:6px}
.withbtn .input{flex:1;min-width:0}
.withbtn .btn{flex:none;white-space:nowrap}

.tills{display:grid;grid-template-columns:repeat(5,1fr);gap:10px;margin-bottom:14px}
.tills--3{grid-template-columns:repeat(3,1fr)}
.till{padding:12px 14px;border-left:4px solid var(--border)}
.till__label{display:block;font-size:10px;color:var(--text-muted);margin-bottom:3px}
.till__value{font-size:17px;font-weight:700}
.till--in{border-left-color:var(--visit-open-bar)}
.till--in .till__value{color:var(--ok)}
.till--out{border-left-color:var(--visit-done-bar)}
.till--out .till__value{color:var(--danger)}
.till--net{border-left-color:var(--primary)}
.till--drawer{border-left-color:var(--tooth-crown)}
.till--debt{border-left-color:var(--accent-orange)}
.till--debt .till__value{color:var(--accent-orange)}

.splits{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:14px}
.split{padding:12px 14px}
.split__title{font-size:11px;color:var(--primary);font-weight:600;margin-bottom:8px}
.split__row{display:flex;justify-content:space-between;font-size:12px;padding:3px 0;
  border-bottom:1px solid var(--line)}
.split__row:last-child{border-bottom:0}

@media (max-width:1023px){
  .tills{grid-template-columns:repeat(3,1fr)}
  .splits{grid-template-columns:1fr}
}
@media (max-width:767px){
  .tills{grid-template-columns:repeat(2,1fr)}
}

/* ---------- checkout ---------- */
.checkout__who{display:flex;flex-direction:column;margin-bottom:2px}
.checkout__lines{margin:12px 0;border-top:1px solid var(--line);padding-top:10px}
.checkout__line{display:flex;justify-content:space-between;gap:12px;font-size:13px;padding:4px 0}
.checkout__row{display:flex;justify-content:space-between;font-size:13px;padding:6px 0;
  border-top:1px solid var(--line)}
.checkout__row--prev{color:var(--accent-orange)}
.checkout__row--due{font-size:16px;font-weight:700;border-top:2px solid var(--primary);
  padding-top:10px;margin-top:4px}
.checkout__amount{font-size:22px;font-weight:700;height:52px;text-align:right}
.checkout__quick{display:flex;gap:8px;margin-top:10px;flex-wrap:wrap}
.checkout__after{display:flex;justify-content:space-between;align-items:center;
  margin-top:14px;padding:10px 12px;border-radius:var(--radius);background:var(--bg);font-size:13px}
.checkout__remaining{font-size:17px;font-weight:700;color:var(--ok)}
.checkout__remaining[data-owing="true"]{color:var(--danger)}

/* ---------- patient ledger ---------- */
.ledger{display:flex;align-items:center;gap:10px;padding:10px 14px;border-radius:var(--radius);
  font-size:13px;margin-bottom:12px;border-left:4px solid transparent}
.ledger--owes{background:var(--visit-done-bg);border-left-color:var(--visit-done-bar)}
.ledger--settled{background:var(--visit-open-bg);border-left-color:var(--visit-open-bar)}
.ledger--credit{background:var(--bg-tint);border-left-color:var(--primary)}
.ledger__amount{font-size:16px;font-weight:700;margin-left:auto}
.ledger--owes .ledger__amount{color:var(--danger)}

/* ---------- visit status colouring ---------- */
/* An inset shadow, not border-left: the table is border-collapse:collapse,
   which resolves away a cell's own left border. */
.vrow--open td:first-child{box-shadow:inset 4px 0 0 var(--visit-open-bar)}
.vrow--done td:first-child{box-shadow:inset 4px 0 0 var(--visit-done-bar)}
.vrow--open{background:var(--visit-open-bg)}
.vrow--done{background:var(--visit-done-bg)}
.vrow--done td{opacity:.82}

.vstatus{
  display:flex;align-items:center;gap:8px;margin:0 0 14px;padding:9px 14px;
  border-radius:var(--radius);font-size:13px;border-left:4px solid transparent;
}
.vstatus__dot{width:9px;height:9px;border-radius:50%;flex:none}
.vstatus--open{background:var(--visit-open-bg);border-left-color:var(--visit-open-bar)}
.vstatus--open .vstatus__dot{background:var(--visit-open-bar)}
.vstatus--done{background:var(--visit-done-bg);border-left-color:var(--visit-done-bar)}
.vstatus--done .vstatus__dot{background:var(--visit-done-bar)}

/* Mobile cards get the bar on the card edge instead of the first cell. */
@media (max-width:767px){
  .vrow td:first-child{box-shadow:none}
  .vrow{border-radius:4px}
  .vrow--open{box-shadow:inset 4px 0 0 var(--visit-open-bar)}
  .vrow--done{box-shadow:inset 4px 0 0 var(--visit-done-bar)}
}

/* ---------- two-step add visit ---------- */
.steps{display:flex;gap:8px;align-items:center;margin-bottom:14px;flex-wrap:wrap}
.steps__item{font-size:12px;color:var(--text-muted);background:var(--surface);
  border:1px solid var(--border);border-radius:20px;padding:5px 12px;cursor:default}
button.steps__item{cursor:pointer}
button.steps__item:hover{border-color:var(--primary);color:var(--primary)}
.steps__item--on{background:var(--primary);border-color:var(--primary);color:var(--on-primary);font-weight:600}
.cal__slot--picked{background:var(--primary-soft);box-shadow:inset 0 0 0 2px var(--primary)}

/* ---------- appointments calendar ---------- */
.calsplit{display:grid;grid-template-columns:200px 1fr;gap:16px;align-items:start}
.calside{position:sticky;top:calc(var(--nav-h) + 12px)}
.calwrap{padding:0;overflow:hidden}
.cal__range{font-size:13px;font-weight:600;min-width:210px;text-align:center}
.modebar{display:flex;gap:6px;flex-wrap:wrap}

/* mini month picker */
.mini__head{display:flex;align-items:center;justify-content:space-between;
  background:var(--primary);border-radius:6px;padding:5px 8px;margin-bottom:8px}
.mini__nav{background:none;border:0;color:var(--on-primary);font-size:15px;cursor:pointer;padding:0 4px}
.mini__title{text-align:center;line-height:1.15;color:var(--on-primary)}
.mini__month{display:block;font-size:13px;font-weight:600}
.mini__year{display:block;font-size:10px;opacity:.85}
.mini__grid{display:grid;grid-template-columns:repeat(7,1fr);gap:1px}
.mini__dow{font-size:8px;color:var(--text-muted);text-align:center;padding:2px 0}
.mini__day{background:none;border:0;font-size:11px;padding:3px 0;border-radius:4px;
  cursor:pointer;color:var(--text)}
.mini__day:hover{background:var(--bg)}
.mini__day--out{color:var(--border)}
.mini__day--we{color:var(--danger)}
.mini__day--today{font-weight:700;color:var(--primary)}
.mini__day--sel{background:var(--primary);color:var(--on-primary)}
.mini__day--sel.mini__day--we,.mini__day--sel.mini__day--today{color:var(--on-primary)}

/* doctor filter */
.doclist__row{display:flex;align-items:center;gap:7px;padding:4px 0;font-size:12px;cursor:pointer}
.doclist__dot{width:8px;height:8px;border-radius:50%;background:var(--primary);flex:none}
.doclist__name{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}

/* day grid */
.cal{overflow-x:auto}
.cal__head{display:grid;position:sticky;top:0;background:var(--surface);z-index:2;
  border-bottom:1px solid var(--border)}
.cal__corner{border-right:1px solid var(--line)}
.cal__doc{padding:8px 6px;text-align:center;border-right:1px solid var(--line);
  display:flex;flex-direction:column;align-items:center;gap:2px}
.cal__docavatar{width:30px;height:30px;border-radius:50%;background:var(--primary-soft);
  color:var(--primary);display:grid;place-items:center;font-size:11px;font-weight:700}
.cal__docname{font-size:12px;font-weight:600}
.cal__docspec{font-size:10px;color:var(--primary)}
.cal__body{display:grid;position:relative}
.cal__gutter{border-right:1px solid var(--line)}
.cal__time{font-size:9px;color:var(--text-muted);text-align:right;padding-right:6px;
  border-bottom:1px solid transparent}
.cal__time--hour{color:var(--text);border-bottom-color:var(--line)}
.cal__col{position:relative;border-right:1px solid var(--line)}
.cal__slot{position:absolute;left:0;right:0;background:none;border:0;border-bottom:1px solid var(--line);
  cursor:pointer;padding:0}
.cal__slot--hour{border-bottom-color:var(--border)}
.cal__slot:hover{background:var(--bg-tint)}
.cal__appt{position:absolute;left:2px;right:2px;border:0;border-radius:4px;cursor:pointer;
  padding:3px 5px;text-align:left;overflow:hidden;display:flex;align-items:baseline;gap:5px;
  background:var(--appt-teal);border-left:3px solid var(--primary)}
/* Name and time sit on one line. Stacked, a 15-minute appointment is only
   about 20px tall — the time took the second line and the name, the thing you
   actually need to read, was clipped away entirely. The name gets the spare
   room and the time gives way first, because a half-read name is still useful
   and the exact minutes are in the tooltip. */
.cal__apptname{font-size:11px;font-weight:600;white-space:nowrap;overflow:hidden;
  text-overflow:ellipsis;flex:1 1 auto;min-width:0}
.cal__appttime{font-size:9px;color:var(--text-muted);white-space:nowrap;
  flex:0 1 auto;min-width:0;overflow:hidden}
.cal__appt--arrived{background:var(--appt-blue);border-left-color:var(--tooth-implant)}
.cal__appt--done{background:var(--chip-green);border-left-color:var(--ok)}
.cal__appt--cancelled{background:var(--bg);border-left-color:var(--text-muted);opacity:.65}
.cal__appt--cancelled .cal__apptname{text-decoration:line-through}

/* week */
.week{display:grid;grid-template-columns:repeat(7,1fr);gap:1px;background:var(--line)}
.week__day{background:var(--surface);min-height:150px;padding:6px}
.week__day--today{background:var(--bg-tint)}
.week__head{background:none;border:0;cursor:pointer;display:flex;flex-direction:column;
  align-items:center;width:100%;padding:2px 0 6px}
.week__dow{font-size:9px;color:var(--text-muted)}
.week__num{font-size:15px;font-weight:600}
.week__appt{display:block;width:100%;text-align:left;border:0;border-radius:4px;
  padding:4px 6px;margin-bottom:4px;cursor:pointer;background:var(--appt-teal);
  border-left:3px solid var(--primary)}
.week__time{font-size:9px;color:var(--text-muted);display:block}
.week__name{font-size:11px;font-weight:600;display:block;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.week__doc{font-size:9px;color:var(--primary);display:block}
.week__empty{text-align:center;color:var(--border);font-size:11px;padding-top:12px}

/* month */
.month{display:grid;grid-template-columns:repeat(7,1fr);gap:1px;background:var(--line)}
.month__dow{background:var(--surface);text-align:center;font-size:9px;color:var(--text-muted);padding:5px 0}
.month__cell{background:var(--surface);border:0;min-height:86px;padding:4px;cursor:pointer;
  display:flex;flex-direction:column;align-items:stretch;gap:2px;text-align:left}
.month__cell--out{background:var(--bg)}
.month__cell--out .month__num{color:var(--border)}
.month__cell--today .month__num{color:var(--primary);font-weight:700}
.month__num{font-size:11px}
.month__chip{font-size:9px;border-radius:3px;padding:1px 4px;overflow:hidden;
  text-overflow:ellipsis;white-space:nowrap;background:var(--appt-teal)}
.month__more{font-size:9px;color:var(--text-muted)}

/* booking modal */
.modal{position:fixed;inset:0;background:rgba(0,0,0,.35);display:grid;place-items:center;
  z-index:70;padding:16px}
.modal__box{background:var(--surface);border-radius:var(--radius);box-shadow:0 10px 40px rgba(0,0,0,.28);
  padding:18px 20px;width:100%;max-width:460px;max-height:90vh;overflow:auto}
.modal__title{font-size:15px;margin:0 0 14px;color:var(--primary)}
.modal__row{display:grid;grid-template-columns:1fr 1fr;gap:12px}
.modal__actions{display:flex;align-items:center;gap:8px;margin-top:16px;flex-wrap:wrap}
.chosen{font-size:13px;padding:7px 10px;background:var(--bg);border-radius:6px;margin-bottom:6px}
.picker__results{display:flex;flex-direction:column;gap:2px;margin-top:4px}

@media (max-width:1023px){
  .calsplit{grid-template-columns:1fr}
  .calside{position:static;display:grid;grid-template-columns:1fr 1fr;gap:12px}
  .calside .card{margin-top:0 !important}
}
@media (max-width:767px){
  .calside{grid-template-columns:1fr}
  .modal__row{grid-template-columns:1fr}
  .month__cell{min-height:64px}
  .week{grid-template-columns:1fr}
}

.rep2__tabs{display:flex;gap:22px;align-items:baseline;margin-bottom:14px}
.rep2__tab{font-size:14px;color:var(--text-muted)}
.rep2__tab--on{color:var(--primary);font-weight:600;text-decoration:underline;text-underline-offset:5px}

.rep2__grid{display:grid;grid-template-columns:1fr 1fr;gap:16px;align-items:start}
.rep2{padding:0;overflow:hidden}
.rep2__head{
  display:flex;align-items:center;justify-content:space-between;gap:10px;
  padding:12px 14px;border-bottom:1px solid var(--line);
}
.rep2__title{font-size:13px;font-weight:600}
.rep2__period{display:flex;align-items:center;gap:6px;font-size:12px}
.rep2__range{white-space:nowrap;color:var(--text-muted)}
.rep2__nav{
  background:none;border:0;color:var(--primary);font-size:15px;cursor:pointer;
  padding:0 2px;line-height:1;
}
.rep2__row{
  display:flex;align-items:center;gap:10px;padding:8px 14px;
  border-bottom:1px solid var(--line);font-size:13px;
}
.rep2__row:last-child{border-bottom:0}
.rep2__tick{
  width:18px;height:18px;border-radius:50%;flex:none;display:grid;place-items:center;
  background:var(--line);color:var(--surface);font-size:11px;
}
.rep2__tick--on{background:var(--primary)}
.rep2__tick--week.rep2__tick--on{background:var(--ok)}
.rep2__label{flex:1}
.rep2__amount{font-weight:600;white-space:nowrap}
.rep2__amount--zero{color:var(--text-muted);font-weight:400}
.rep2__total{
  display:flex;justify-content:space-between;padding:11px 14px;
  border-top:2px solid var(--primary);font-size:13px;background:var(--bg-tint);
}

@media (max-width:1023px){ .rep2__grid{grid-template-columns:1fr} }

/* ---------- medical report ---------- */
/* ------------------------------------------------------- medical report

   A clinical document, not an app screen. Every rule here is set for the
   printed page first: fit a patient's history onto as few sheets as possible
   without it reading as cramped.

   The largest saving is the label/value pair. Stacked — label above value —
   each of the thirteen pairs on this page stood 32px tall and the patient
   block alone ran to 270px for nine short facts. Set side by side they are
   about 18px, and the page reads like a form rather than a list of headings. */

.rep{padding:18px 20px;max-width:900px;margin:0 auto;color:var(--text)}

.rep__head{display:flex;justify-content:space-between;align-items:flex-start;gap:18px;
  padding-bottom:9px;border-bottom:2px solid var(--primary);margin-bottom:13px}
.rep__logo{max-height:46px;max-width:170px;object-fit:contain}
.rep__clinic{font-size:17px;font-weight:700;color:var(--primary);line-height:1.2}
.rep__clinicmeta{font-size:10.5px;color:var(--text-muted);line-height:1.45}

.rep__section{margin-bottom:13px}
.rep__h2{font-size:11px;font-weight:600;color:var(--primary);margin:0 0 6px;
  text-transform:uppercase;letter-spacing:.05em;
  padding-bottom:3px;border-bottom:1px solid var(--line)}

/* auto-fit, so the same markup gives three columns on paper and two on a
   phone without a breakpoint deciding it wrongly at some middle width. */
.rep__grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(215px,1fr));
  gap:2px 22px}

.rep__cell{font-size:11.5px;line-height:1.5;display:flex;gap:6px;align-items:baseline;
  border-bottom:1px dotted var(--line);padding:1px 0}
.rep__label{font-size:10.5px;color:var(--text-muted);flex:0 0 auto;min-width:74px}
.rep__value{color:var(--text);font-weight:500;min-width:0;overflow-wrap:anywhere}

.rep__allergy{margin-top:8px;padding:5px 9px;border-radius:5px;background:var(--bg);font-size:11.5px}
.rep__allergy--yes{background:var(--chip-red);color:var(--danger);font-weight:600}

/* A band, not a boxed panel: four figures did not need 100px and a border. */
.rep__summary{display:flex;flex-wrap:wrap;gap:4px 26px;
  padding:7px 10px;background:var(--bg-tint);border-radius:5px}
.rep__summary .rep__cell{border-bottom:0;padding:0}

.rep__visit{border:1px solid var(--line);border-radius:5px;padding:8px 10px;margin-bottom:7px;
  break-inside:avoid;page-break-inside:avoid}
.rep__visithead{display:flex;align-items:baseline;gap:9px;flex-wrap:wrap;margin-bottom:3px}
.rep__visitdate{font-weight:600;font-size:12px}
.rep__visitdoc{font-size:10.5px;color:var(--primary)}
.rep__badge{font-size:9.5px;padding:1px 6px;border-radius:9px;background:var(--bg);color:var(--text-muted)}
.rep__badge--done{background:var(--chip-green);color:var(--text)}
.rep__diag{font-size:11.5px;margin:2px 0;line-height:1.45}
.rep__none{font-size:10.5px;color:var(--text-muted);padding:2px 0}

.rep__table{width:100%;border-collapse:collapse;font-size:11.5px;margin-top:4px}
.rep__table th{text-align:left;font-size:9.5px;color:var(--text-muted);font-weight:600;
  padding:2px 5px;border-bottom:1px solid var(--line);text-transform:uppercase;letter-spacing:.03em}
.rep__table td{padding:2px 5px;border-bottom:1px dotted var(--line)}
.rep__table tr:last-child td{border-bottom:0}
.rep__visittotal{text-align:right;font-size:11.5px;margin-top:3px}

.rep__foot{display:flex;justify-content:space-between;align-items:flex-end;gap:20px;
  margin-top:16px;padding-top:9px;border-top:1px solid var(--line)}
.rep__issued{font-size:9.5px;color:var(--text-muted)}
.rep__sign{text-align:center}
.rep__signline{display:block;width:180px;border-bottom:1px solid var(--text-muted);margin-bottom:3px}

/* On paper the card chrome is noise, and the clinic letterhead has to survive
   the page break rather than repeat halfway down a sheet. */
@media print{
  .rep{padding:0;max-width:none}
  .rep__head{break-after:avoid;page-break-after:avoid}
  .rep__h2{break-after:avoid;page-break-after:avoid}
  .rep__section{break-inside:auto}
  .rep__foot{break-inside:avoid;page-break-inside:avoid}
}

@media (max-width:767px){
  .rep{padding:16px 14px}
  .rep__grid{grid-template-columns:1fr 1fr}
  .rep__summary{grid-template-columns:1fr 1fr}
  .rep__head{flex-direction:column-reverse;align-items:flex-start}
}

.syncbar{
  position:fixed;left:50%;transform:translateX(-50%);bottom:16px;z-index:55;
  display:flex;align-items:center;gap:10px;padding:8px 10px 8px 14px;
  background:var(--text);color:var(--on-primary);border-radius:24px;
  box-shadow:0 4px 18px rgba(0,0,0,.25);font-size:13px;
}
.syncbar .btn{height:28px;padding:0 12px}
.syncbar .linkbtn{color:var(--on-primary);opacity:.7;padding:0 4px}
@media (max-width:767px){
  /* Clear of the bottom tab bar. */
  .syncbar{bottom:64px;left:12px;right:12px;transform:none;justify-content:space-between}
}

/* ---------- toast ---------- */
.toasts{position:fixed;right:16px;bottom:16px;display:flex;flex-direction:column;gap:8px;z-index:50}
.toast{
  background:var(--text);color:var(--on-primary);font-size:13px;padding:10px 14px;
  border-radius:6px;box-shadow:0 4px 14px rgba(0,0,0,.2);max-width:320px;
}
.toast--err{background:var(--danger)}

/* ---------- bottom tab bar (mobile) ---------- */
.tabbar{display:none}

/* ---------- tablet ---------- */
@media (max-width:1023px){
  .split,.split--visit{grid-template-columns:minmax(0,1fr)}
  .kpis{grid-template-columns:repeat(3,1fr)}
  .nav{gap:14px;overflow-x:auto}
  .infostrip{grid-template-columns:repeat(3,1fr)}
  .entry{grid-template-columns:1fr 1fr;}
}

/* ---------- phone ---------- */
@media (max-width:767px){
  .page{padding:14px 12px 76px}
  /* Four date presets do not fit one line on a 320px phone. A 2x2 grid reads
     as deliberate, where wrapping left "This month" stranded on its own row. */
  .modebar{width:100%;display:grid;grid-template-columns:1fr 1fr;gap:6px}
  .modebar .seg{padding:0 8px;justify-content:center}

  /* Keep the date range on one line, with Print beside it. */
  .toolbar .input[type="date"]{flex:1 1 0;min-width:0}
  .nav{display:none}
  .kpis{grid-template-columns:repeat(2,1fr)}
  .infostrip{grid-template-columns:repeat(2,1fr)}
  .entry{grid-template-columns:1fr}
  .hdr__meta{display:none}

  /* tables become stacked cards */
  .tbl,.tbl tbody,.tbl tr,.tbl td{display:block;width:100%}
  .tbl thead{display:none}
  .tbl tr{border-bottom:8px solid var(--bg);padding:4px 0}
  .tbl td{
    border-bottom:0;display:flex;justify-content:space-between;gap:12px;
    padding:7px 14px;text-align:right;
  }
  .tbl td::before{
    content:attr(data-label);color:var(--text-muted);font-size:11px;
    text-align:left;flex:none;
  }
  .tbl__actions{justify-content:flex-end}

  .tabbar{
    display:grid;grid-auto-flow:column;grid-auto-columns:1fr;
    position:fixed;left:0;right:0;bottom:0;
    background:var(--surface);border-top:1px solid var(--border);z-index:30;
    padding-bottom:env(safe-area-inset-bottom);
  }
  .tabbar button{
    background:none;border:0;padding:8px 1px 7px;font-size:10px;color:var(--text-muted);
    display:flex;flex-direction:column;align-items:center;gap:4px;cursor:pointer;min-height:60px;
    /* Labels stay on one line rather than letting "Add Visit" wrap and shove
       the bar taller. */
    white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:100%;
  }
  .tabbar button[aria-current="page"]{color:var(--primary)}

  /* The icons are emoji, so they scale with font-size, not width/height.
     Sizing them by box left them rendering at the inherited 8.5px and looking
     like specks. Moving Settings into the header freed the width for this. */
  .tabbar .nav__ico{
    width:auto;height:auto;font-size:24px;line-height:1;opacity:1;
  }

  /* The gear moves up beside the profile circle, where account-level things
     belong. Sized for a fingertip, not a mouse. */
  .hdr__settings{
    display:inline-flex;align-items:center;justify-content:center;
    width:40px;height:40px;margin-left:auto;margin-right:4px;
    background:none;border:0;border-radius:50%;
    font-size:22px;line-height:1;cursor:pointer;
    -webkit-tap-highlight-color:transparent;
  }
  .hdr__settings[aria-current="page"]{background:rgba(255,255,255,.18)}
}

@media print{
  .hdr,.nav,.tabbar,.actions,.toolbar{display:none}
  body{background:var(--on-primary)}
  .card{box-shadow:none}
}

.hdr__logo--custom{max-width:190px;object-fit:contain}

/* A plain tick with its label — used for "treats patients" in Settings. */
.check{
  display:flex; align-items:center; gap:8px;
  font-size:13px; color:var(--text); cursor:pointer;
  padding:6px 0; align-self:end;
}
.check[hidden]{ display:none }
.check input{ width:16px; height:16px; accent-color:var(--primary); margin:0 }

/* First-run setup page. Shares the sign-in card, adds room for prose. */
.setup__title{ font-size:20px; font-weight:700; color:var(--text); margin:4px 0 8px }
.setup__lead{ font-size:13px; line-height:1.55; color:var(--text-muted); margin:0 0 12px }
.setup__list{ font-size:13px; line-height:1.7; color:var(--text-muted);
              margin:0 0 12px; padding-left:20px }
.setup__list code{ background:var(--bg-tint); padding:1px 5px; border-radius:4px;
                   font-size:12px; color:var(--text) }
.setup__detail{ font-size:11px; color:var(--text-muted); background:var(--bg);
                border:1px solid var(--border); border-radius:6px;
                padding:8px 10px; margin:0; word-break:break-word }

/* ------------------------------------------------------------ WhatsApp */

/* WhatsApp's own green. Used only for buttons that genuinely open WhatsApp,
   so the colour keeps meaning something. */
.btn--wa{
  background:var(--wa-green);color:var(--on-primary);display:inline-flex;align-items:center;
  gap:6px;white-space:nowrap;
}
.btn--wa:hover{background:var(--wa-green-dark)}
.btn--sm{padding:4px 10px;font-size:12px}

.wa__row{
  display:grid;grid-template-columns:56px 1fr 1fr auto;align-items:center;
  gap:12px;padding:11px 14px;border-bottom:1px solid var(--line);
}
.wa__row:last-child{border-bottom:0}
/* Sent rows recede rather than disappear: the desk still needs to see that
   the appointment exists and was handled. */
.wa__row--done{opacity:.55}
.wa__time{font-weight:700;font-size:14px;color:var(--text)}
.wa__who{display:flex;flex-direction:column;min-width:0}
.wa__sub{font-size:12px;color:var(--text-muted);white-space:nowrap;
         overflow:hidden;text-overflow:ellipsis}
.wa__doc{font-size:13px;color:var(--text-muted)}
.wa__act{justify-self:end}
.wa__done{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--ok)}
.wa__none{font-size:12px;color:var(--text-muted)}

/* The share link, shown after it is created. */
.wa__link{
  display:flex;gap:8px;align-items:center;margin-top:10px;padding:10px;
  background:var(--bg-tint);border-radius:8px;font-size:12px;
}
.wa__link input{
  flex:1;min-width:0;border:1px solid var(--border);border-radius:6px;
  padding:6px 8px;font-size:12px;font-family:ui-monospace,Menlo,Consolas,monospace;
  background:var(--surface);color:var(--text);
}

@media (max-width:700px){
  /* Doctor drops out first: on a phone the name and the button are what the
     job needs, and four columns at 320px leaves room for none of it. */
  .wa__row{grid-template-columns:46px 1fr auto;gap:10px}
  .wa__doc{display:none}
}

/* The share control in the report toolbar. It grows into a link box once the
   link exists, so it must not be locked to the button's width. */
.wa__share{display:flex;flex-direction:column;gap:6px;align-items:flex-start}
.wa__share .wa__link{margin-top:0}
.wa__share .hint{margin:0}

@media print{ .wa__share{display:none} }

/* A number whose country nobody recorded. Marked, not hidden: the desk should
   be able to send it anyway, while knowing the prefix is the clinic's guess. */
.wa__sub--guess{color:var(--accent-orange)}
.wa__guess{font-weight:700;cursor:help}

/* Typed times. Narrow, because a time field given a text input's width looks
   like it wants a sentence. */
.input--time{width:auto;min-width:106px}
.chosen__len{font-size:12px;color:var(--text-muted);white-space:nowrap}

/* Date and time side by side on the visit, wrapping on a phone. */
.whenrow{display:flex;gap:10px;flex-wrap:wrap}
.whenrow .field{flex:1 1 130px;min-width:0}

/* ------------------------------------------------ draggable appointments */

.cal__appt{
  touch-action:none;          /* or the browser scrolls instead of dragging */
  cursor:grab;
  user-select:none;
}
.cal__appt--dragging{
  cursor:grabbing;opacity:.85;z-index:5;
  box-shadow:0 6px 18px rgba(0,0,0,.22);
  /* Invisible to hit-testing while it is being dragged. The column under the
     pointer is found with elementFromPoint, and the card sits directly under
     the pointer — so without this it always "finds" the column it is already
     in and a drag to the other dentist silently does nothing. */
  pointer-events:none;
}

/* The stretch handle. Deliberately a strip rather than the card's last few
   pixels: hit-testing the edge itself makes the whole card feel resizable. */
.cal__grip{
  position:absolute;left:0;right:0;bottom:0;height:7px;
  cursor:ns-resize;border-radius:0 0 4px 4px;
}
.cal__grip::after{
  content:'';position:absolute;left:50%;bottom:2px;width:18px;height:2px;
  transform:translateX(-50%);border-radius:2px;
  background:currentColor;opacity:.35;
}
.cal__appt:hover .cal__grip::after{opacity:.7}

/* Coarse pointers cannot hit a 7px strip reliably. */
@media (pointer:coarse){
  .cal__grip{height:12px}
}

/* ---------------------------------------------- database tab (Settings)

   Cards rather than one long form: backing up, restoring, exporting and
   wiping are separate decisions with very different consequences, and the
   destructive one is kept visually apart from the rest on purpose. */

.dbcard{padding:16px;margin-bottom:14px}
.dbcard .btn{margin-top:8px}
.dbcard--danger{border:1px solid var(--danger)}
.dbmeta{font-size:11.5px;color:var(--text-muted);margin:4px 0 10px}
.dbtable{margin-top:0}
.dbtable td{font-variant-numeric:tabular-nums}
.dbmig{display:flex;align-items:center;gap:7px;font-size:11.5px;padding:2px 0}
.dbrow{display:flex;gap:8px;flex-wrap:wrap;align-items:center;margin-top:8px}
.dbrow .input{flex:1 1 200px}
.dbrule{height:1px;background:var(--line);margin:14px 0 12px}
.btn--danger{background:var(--danger);color:var(--on-primary)}
.btn--danger:hover{filter:brightness(1.07)}

/* Outlined destructive action, for the delete button on a table row.
   Solid red on every row of a list shouts; the plain ghost says nothing about
   what the button does. Both classes together give an outline in the danger
   colour — unmistakably destructive, without a column of red blocks. */
.btn--ghost.btn--danger{background:var(--surface);color:var(--danger);
                        border-color:var(--danger)}
.btn--ghost.btn--danger:hover{background:var(--bg-tint);filter:none}

/* The deploy bar. Distinct from the data bar and not dismissable: refreshing
   the view cannot fix stale JavaScript, only reloading the page can. */
.syncbar--upgrade{background:var(--primary);color:var(--on-primary)}
.syncbar--upgrade .btn{background:var(--on-primary);color:var(--primary)}

/* A day the clinic is shut. Says so rather than showing an empty grid — the
   two look identical, and the difference is whether the patient you just
   booked arrives at a locked building. */
.closedday{padding:40px 20px;text-align:center}
.closedday__title{font-size:15px;font-weight:600;color:var(--text)}
.closedday__sub{font-size:12.5px;color:var(--text-muted);margin-top:6px}

/* The seven closed-day tick boxes, wrapping on a phone. */
.daysrow{display:flex;flex-wrap:wrap;gap:6px 18px;margin-top:8px}
.daysrow .check{padding:2px 0}

/* ------------------------------------------------- patient self-registration

   The QR shown at the desk, and the queue of what patients have sent in. */

.qr{display:flex;flex-direction:column;align-items:center;gap:12px;padding:6px 0}
.qr__img{width:min(260px,60vw);height:auto;display:block;border-radius:6px}
.qr__meta{width:100%;text-align:center}
.qr__url{font-size:11px;text-align:center;margin-top:6px}

.sub{padding:14px 16px;margin-bottom:12px}
.sub__head{display:flex;gap:12px;align-items:center;margin-bottom:10px}
.sub__photo{width:52px;height:52px;border-radius:50%;object-fit:cover;flex:none;
  border:2px solid var(--primary)}
.sub__photo--none{display:grid;place-items:center;background:var(--bg);
  color:var(--text-muted);border-color:var(--line)}
.sub__name{font-size:15px;font-weight:600}
.sub__grid{margin-bottom:8px}
.sub__allergy{font-size:12px;padding:6px 10px;border-radius:5px;
  background:var(--chip-red);color:var(--danger);margin:6px 0}
.sub__unverified{font-weight:400;font-style:italic}
.sub__actions{display:flex;align-items:center;gap:14px;margin-top:10px;
  padding-top:10px;border-top:1px solid var(--line)}

/* The public intake page. Standalone, like the sign-in screen. */
.intake{background:var(--bg)}
.intake__wrap{max-width:560px;margin:0 auto;padding:20px 16px 40px}
.intake__logo{display:block;max-height:46px;margin:6px auto 16px}
.intake__card{padding:18px 16px}
.intake__title{font-size:18px;font-weight:700;color:var(--primary);margin:0 0 6px}
.intake__lead{font-size:13px;color:var(--text-muted);margin:0 0 16px;line-height:1.5}
.intake__row{display:grid;grid-template-columns:1fr 1fr;gap:10px}
.intake__err{background:var(--chip-red);color:var(--danger);font-size:12.5px;
  padding:8px 10px;border-radius:5px;margin:0 0 12px}
.intake__consent{margin:14px 0 4px;align-items:flex-start;line-height:1.4}
.intake__submit{width:100%;margin-top:14px}
.intake__clinic{text-align:center;font-size:11px;color:var(--text-muted);margin-top:14px}
.intake__done,.intake__gone{text-align:center;padding:34px 20px}
.intake__tick{font-size:34px;color:var(--ok);margin-bottom:8px}

@media (max-width:420px){ .intake__row{grid-template-columns:1fr} }

/* The QR button in the header, beside the avatar. Grouped with the settings
   cog and the user menu so the three stay together at any width. */
.hdr__right{display:flex;align-items:center;gap:12px;margin-left:auto}
.hdr__qr{
  background:rgba(255,255,255,.18);border:0;border-radius:7px;cursor:pointer;
  width:30px;height:30px;display:grid;place-items:center;
  font-size:13px;color:var(--on-primary);line-height:1;padding:0;
}
.hdr__qr:hover{background:rgba(255,255,255,.3)}

/* Patients waiting to be accepted. Sits on the Patients tab so a submission
   is noticed while the desk is looking at something else entirely. */
.hdr__pending{position:relative;background:var(--danger);border:0;border-radius:9px;cursor:pointer;min-width:22px;height:22px;padding:0 6px;display:grid;place-items:center;color:var(--on-primary);font-size:11px;font-weight:700;line-height:1}
.hdr__pending[hidden]{display:none}
.nav__badge{
  display:inline-grid;place-items:center;min-width:17px;height:17px;padding:0 5px;
  margin-left:6px;border-radius:9px;background:var(--danger);color:var(--on-primary);
  font-size:10.5px;font-weight:700;line-height:1;
}
.nav__badge[hidden]{display:none}

/* A patient's own photo, where initials would otherwise be. Same circle, so
   a list of patients does not jump about depending on who has one. */
.profile__avatar--img{padding:0;object-fit:cover;display:block}

/* Photo on the intake form. The input itself is hidden: a phone's default
   file control says nothing about whether it opens the camera or the album,
   which is the one thing the patient needs to know. */
/* The language switch, top-right of the registration page. Two links, so it
   works with no JavaScript on a page a stranger reached from a QR code. */
.intake__lang{text-align:right;max-width:520px;margin:0 auto;padding:10px 16px 0}
.intake__lang a{color:var(--primary);font-size:14px;text-decoration:none}
.intake__lang a:hover{text-decoration:underline}

/* ------------------------------------------------- the day's work (Visits)

   Rows rather than a table: the desk reads this at a glance from across the
   room, and a table's columns fight that. */

.day__title{font-size:12px;font-weight:600;color:var(--primary);margin:0 0 6px;
  text-transform:uppercase;letter-spacing:.05em}
.day{padding:4px 0;margin-bottom:16px}
.day__none{padding:16px;color:var(--text-muted);font-size:13px;margin-bottom:16px}
.day__row{display:flex;align-items:center;gap:10px;padding:9px 14px;
  border-bottom:1px solid var(--line);flex-wrap:wrap}
.day__row:last-child{border-bottom:0}
.day__row--here{background:var(--visit-open-bg);
  box-shadow:inset 3px 0 0 var(--visit-open-bar)}
.day__row--owing{box-shadow:inset 3px 0 0 var(--accent-orange)}
.day__time{font-weight:600;font-size:13px;min-width:52px;font-variant-numeric:tabular-nums}
.day__who{display:flex;flex-direction:column;min-width:0}
.day__name{font-size:13.5px;font-weight:600}
.day__doc{font-size:11px;color:var(--primary)}
.day__badge{font-size:10px;font-weight:700;padding:2px 8px;border-radius:10px;
  background:var(--visit-open-bar);color:var(--on-primary);white-space:nowrap}
.day__due{font-weight:700;font-size:13px;color:var(--accent-orange);white-space:nowrap}
.btn--sm{height:28px;padding:0 12px;font-size:12px}
.day__histhead{display:flex;align-items:center;justify-content:space-between;
  gap:12px;flex-wrap:wrap;margin:22px 0 10px}

/* ============================================================ touchscreens

   Everything below applies on any device driven by a finger — a phone, a
   tablet, an iPad — and on nothing else. `pointer: coarse` asks the browser
   what the PRIMARY input actually is, so a desktop mouse never sees these
   rules, and neither does a laptop that merely happens to have a touchscreen
   alongside its trackpad.

   That is why this is a media query and not a separate stylesheet on a
   separate page: there is one application, and it grows to fit whatever is
   being used to drive it.

   34px controls are right for a mouse, which is pixel-accurate. They are not
   right for a fingertip, and they are certainly not right for a fingertip in
   a dental glove. */

/* Two conditions, either of which is enough.
   A real touch device answers `pointer: coarse` — its primary input is a
   finger — and also `hover: none`, because a finger cannot hover. Asking for
   both, with a comma, means a device only has to admit to one of them. A
   desktop with a mouse answers neither, and is left entirely alone. */
@media (pointer: coarse), (hover: none){

  /* Removes the ~300ms the browser spends deciding whether a tap is the first
     half of a double-tap. Without it every button feels broken rather than
     merely slow. */
  body{
    touch-action:manipulation;
    -webkit-text-size-adjust:100%;
    /* The browser paints its own grey flash over a tapped element; we draw our
       own :active states below, and two overlapping effects read as a glitch. */
    -webkit-tap-highlight-color:transparent;
  }

  /* ---- controls ----
     44px is Apple's documented minimum and Google's is 48. Take the larger:
     the people using this are often wearing gloves. */

  .btn{height:auto;min-height:48px;padding:0 20px;font-size:15px;border-radius:8px}
  /* 44, not 42. The small variant is still a button somebody has to hit, and
     two pixels is not worth being under the documented minimum for. */
  .btn--sm{height:auto;min-height:44px;padding:0 14px;font-size:14px}

  .tab{min-height:48px;padding:0 18px;font-size:15px}
  .nav__item{font-size:15px;gap:8px}

  /* A text link inside a table row is a 13px target. Given room to breathe it
     becomes something a thumb can hit without magnifying the page. */
  .linkbtn{min-height:44px;padding:0 4px;font-size:15px;display:inline-flex;align-items:center}

  /* 16px is not a style choice. Below it, iOS Safari zooms the entire page
     when a field takes focus, and the layout lurches on every single tap. On
     the cash register that is intolerable. */
  .input,.select,input,select,textarea{font-size:16px}
  .input,.select{height:48px;padding:0 12px}
  textarea{min-height:96px;padding:10px 12px;line-height:1.45}

  .check{min-height:44px;font-size:15px;padding:8px 0}
  .check input{width:22px;height:22px;flex:0 0 auto}

  /* ---- lists ---- */

  .tbl{font-size:14px}
  .tbl th,.tbl td{padding:14px 12px}
  .tbl__actions{gap:18px}

  /* ---- the tooth chart ----
     The one thing here that genuinely must be bigger: teeth are tapped
     repeatedly, through gloves, and a mis-tap writes to a medical record. The
     chart already handles long-press; this only makes the target fair. */

  .toothsvg{max-height:84px}
  .picker__opt{min-height:48px;font-size:15px}
  .picker__title{font-size:15px}

  /* ---- hover ----
     A tap leaves :hover stuck on the element until something else is tapped,
     so a button pressed a minute ago is still lit. Nothing with a coarse
     pointer should show a hover state at all. */

  .btn:hover{background:var(--primary)}
  .tbl tr:hover{background:transparent}
  .nav__item:hover{background:transparent}
}
