/* ═══════════════════════════════════════════════════════════
   العيادة الذكية — Patient dashboard

   Palette, radii, shadows, easings, the icon sizing rule, the
   focus ring and the reduced-motion reset all live in
   tokens.css, which this file assumes is already loaded. That
   block used to be duplicated verbatim here and in landing.css,
   and the two copies had already drifted — the status colours
   existed only here, so landing.css open-coded them.

   Direction is handled with logical properties plus --dir.
   ═══════════════════════════════════════════════════════════ */

:root {
    --topbar-h: 62px;
    --side-w: 244px;
}

body {
    margin: 0;
    min-height: 100vh;
    background: var(--ground);
    color: var(--ink);
    font-family: 'Outfit', 'Cairo', system-ui, sans-serif;
    font-size: 15px;
    line-height: 1.6;
    -webkit-font-smoothing: antialiased;
    transition: background-color .25s ease, color .25s ease;
}
html[lang="ar"] body { font-family: 'Cairo', system-ui, sans-serif; }

.font-lora { font-family: 'Lora', 'Cairo', Georgia, serif; }
html[lang="ar"] .font-lora { font-family: 'Cairo', system-ui, sans-serif; }
.font-mono { font-family: 'DM Mono', ui-monospace, monospace; }

/* ═══════════════════════════════════════════════════════════
   Buttons, inputs, shared atoms
   ═══════════════════════════════════════════════════════════ */
.btn {
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    padding: 11px 20px; border-radius: var(--r-pill);
    font-weight: 600; font-size: 14.5px; border: 1px solid transparent;
    transition: transform .18s var(--ease-out), box-shadow .22s var(--ease-out),
                background .2s ease, color .2s ease, border-color .2s ease, opacity .2s ease;
}
.btn-primary { background: linear-gradient(140deg, var(--terra), var(--deep-terra)); color: #fff; box-shadow: var(--shadow-btn); }
.btn-primary:hover:not(:disabled) { box-shadow: var(--shadow-btn-hi); transform: translateY(-1px); }
.btn-ghost { background: transparent; border-color: var(--line); color: var(--ink); }
.btn-ghost:hover:not(:disabled) { background: var(--ground); border-color: var(--terra); color: var(--terra); }
.btn-danger { background: transparent; border-color: var(--bad-line); color: var(--bad); }
.btn-danger:hover:not(:disabled) { background: var(--bad-bg); border-color: var(--bad); }
.btn-sm { padding: 7px 14px; font-size: 13px; }
.btn-lg { padding: 14px 28px; font-size: 16px; }
.btn-block { width: 100%; }
.btn:disabled { opacity: .55; cursor: not-allowed; box-shadow: none; transform: none; }

.field { display: grid; gap: 6px; margin-bottom: 16px; }
.field > label { font-size: 13.5px; font-weight: 600; color: var(--ink); }
.field .hint { font-size: 12px; color: var(--ink-soft); }
/* Half-width field. The birth-date input used to carry an inline
   max-width:calc(50% - 9px), which hardcoded .grid-2's 18px gap in a
   second place — changing the gap silently misaligned the field. */
.field-half { max-width: calc(50% - (var(--grid-gap, 18px) / 2)); }

input[type="text"], input[type="email"], input[type="tel"], input[type="date"],
input[type="time"], input[type="number"], input[type="search"], input[type="file"],
select, textarea {
    width: 100%; padding: 11px 14px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-lg); color: var(--ink);
    font: inherit; font-size: 14.5px;
    transition: border-color .2s ease, box-shadow .2s ease;
}
input[type="file"] { padding: 9px 12px; }
textarea { resize: vertical; min-height: 84px; }
input:focus, select:focus, textarea:focus {
    outline: none; border-color: var(--terra);
    box-shadow: 0 0 0 3px var(--terra-ring);
}
input::placeholder, textarea::placeholder { color: var(--ink-soft); opacity: .8; }
input.invalid, select.invalid, textarea.invalid,
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] {
    border-color: var(--bad); box-shadow: 0 0 0 3px var(--bad-bg);
}
select {
    appearance: none;
    background-image: linear-gradient(45deg, transparent 50%, var(--ink-soft) 50%),
                      linear-gradient(135deg, var(--ink-soft) 50%, transparent 50%);
    background-position: calc(100% - 19px) 50%, calc(100% - 14px) 50%;
    background-size: 5px 5px, 5px 5px;
    background-repeat: no-repeat;
    padding-inline-end: 34px;
}
html[dir="rtl"] select {
    background-position: 14px 50%, 19px 50%;
    background-image: linear-gradient(135deg, transparent 50%, var(--ink-soft) 50%),
                      linear-gradient(45deg, var(--ink-soft) 50%, transparent 50%);
}

.grid-2 { --grid-gap: 18px; display: grid; grid-template-columns: 1fr 1fr; gap: 0 var(--grid-gap); }

.alert {
    display: flex; align-items: flex-start; gap: 10px;
    padding: 12px 16px; border-radius: var(--r-lg);
    font-size: 13.5px; margin-bottom: 16px;
    border: 1px solid var(--line); background: var(--ground); color: var(--ink);
}
.alert .icon { margin-top: 3px; }
/* Borders read from the same tokens as the text, so the dark theme
   moves all three together. They used to be literal rgba() values, so
   dark mode changed the fill and the ink and left the outline behind. */
.alert.ok   { background: var(--ok-bg);   border-color: var(--ok-line);   color: var(--ok); }
.alert.bad  { background: var(--bad-bg);  border-color: var(--bad-line);  color: var(--bad); }
.alert.warn { background: var(--warn-bg); border-color: var(--warn-line); color: var(--warn); }

.pill {
    display: inline-flex; align-items: center; gap: 5px;
    font-size: 11.5px; font-weight: 700; padding: 4px 11px;
    border-radius: var(--r-pill); white-space: nowrap;
}
.pill.s-pending     { background: var(--warn-bg); color: var(--warn); }
.pill.s-confirmed   { background: var(--ok-bg);   color: var(--ok); }
/* Tokenised, so dark mode no longer needs two override rules to undo
   a pair of hardcoded light-mode rgba() tints. */
.pill.s-in_progress { background: var(--terra-12); color: var(--terra); }
.pill.s-completed   { background: var(--pill-neutral, rgba(42, 24, 16, .08)); color: var(--ink-soft); }
.pill.s-cancelled   { background: var(--bad-bg);  color: var(--bad); }
.pill.s-no_show     { background: var(--bad-bg);  color: var(--bad); }
html[data-theme="dark"] { --pill-neutral: rgba(255, 255, 255, .08); }

.spinner {
    width: 15px; height: 15px; border-radius: 50%; flex: none;
    border: 2px solid rgba(255, 255, 255, .4); border-top-color: #fff;
    animation: spin .7s linear infinite;
}
.spinner.dark { border-color: var(--terra-20); border-top-color: var(--terra); }
@keyframes spin { to { transform: rotate(360deg); } }

.empty {
    text-align: center; padding: 44px 20px; color: var(--ink-soft); font-size: 14px;
}
.empty .icon { font-size: 32px; display: block; margin: 0 auto 12px; color: var(--line); }

/* ═══════════════════════════════════════════════════════════
   Login gate
   ═══════════════════════════════════════════════════════════ */
.auth-wrap {
    min-height: 100vh; display: grid; place-items: center; padding: 24px;
    background:
        radial-gradient(900px 460px at 50% -5%, rgba(212, 151, 74, .28), transparent 68%),
        linear-gradient(180deg, var(--warm-white), var(--sand));
}
.auth-card {
    width: 100%; max-width: 430px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-3xl); padding: 38px 34px;
    box-shadow: var(--shadow-deep);
    animation: cardIn .6s var(--ease-out);
}
@keyframes cardIn { from { opacity: 0; transform: translateY(18px); } }
.auth-brand { display: flex; align-items: center; gap: 11px; justify-content: center; margin-bottom: 24px; }
.brand-mark {
    width: 40px; height: 40px; border-radius: var(--r-lg); flex: none;
    display: grid; place-items: center; color: #fff; font-size: 20px;
    background: linear-gradient(140deg, var(--terra), var(--deep-terra));
    box-shadow: var(--shadow-btn);
}
.auth-brand .name { font-size: 19px; font-weight: 700; }
.auth-card h1 { font-size: 23px; margin: 0 0 7px; text-align: center; letter-spacing: -.01em; }
html[lang="ar"] .auth-card h1 { letter-spacing: 0; }
.auth-card .sub { margin: 0 0 26px; text-align: center; font-size: 14px; color: var(--ink-soft); }
.auth-foot { margin-top: 20px; text-align: center; font-size: 13px; color: var(--ink-soft); }
.auth-foot a { color: var(--terra); font-weight: 600; }

/* Status disc above a terminal auth message (denied / error). Replaces
   two long inline style attributes that carried the same declaration. */
.auth-mark {
    width: 60px; height: 60px; border-radius: 50%; margin: 0 auto 16px;
    display: grid; place-items: center; font-size: 28px;
}
.auth-mark.bad { background: var(--bad-bg); color: var(--bad); }

.otp-input {
    text-align: center; font-family: 'DM Mono', ui-monospace, monospace;
    font-size: 26px; letter-spacing: .42em; padding-inline-start: .42em;
}
.link-btn { background: none; border: 0; color: var(--terra); font-size: 13px; font-weight: 600; text-decoration: underline; padding: 0; }

/* ═══════════════════════════════════════════════════════════
   Shell: topbar + sidebar
   ═══════════════════════════════════════════════════════════ */
.topbar {
    position: fixed; inset-inline: 0; top: 0; z-index: 60; height: var(--topbar-h);
    display: flex; align-items: center; gap: 14px; padding-inline: 20px;
    background: var(--topbar-bg, rgba(255, 250, 245, .82));
    border-bottom: 1px solid var(--line);
}
html[data-theme="dark"] { --topbar-bg: rgba(46, 28, 18, .82); }
/* The blur is what makes an 82%-opaque bar legible over scrolling
   content; without support the bar has to be fully opaque instead. */
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
    .topbar {
        backdrop-filter: blur(18px) saturate(1.4);
        -webkit-backdrop-filter: blur(18px) saturate(1.4);
    }
}
@supports not ((backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px))) {
    .topbar { background: var(--surface); }
}

.topbar-brand { display: flex; align-items: center; gap: 10px; font-weight: 700; font-size: 16px; }
.topbar-brand .brand-mark { width: 32px; height: 32px; font-size: 16px; border-radius: var(--r-md); }
.topbar-actions { margin-inline-start: auto; display: flex; align-items: center; gap: 8px; }
.icon-btn {
    width: 38px; height: 38px; border-radius: var(--r-md); flex: none;
    display: grid; place-items: center; font-size: 17px;
    background: transparent; border: 1px solid transparent; color: var(--ink-soft);
    transition: background .2s ease, color .2s ease, border-color .2s ease; position: relative;
}
.icon-btn:hover { background: var(--ground); color: var(--terra); border-color: var(--line); }
.lang-btn {
    background: transparent; border: 1px solid var(--line); border-radius: var(--r-pill);
    padding: 7px 13px; font-size: 12.5px; font-weight: 700; color: var(--ink-soft);
    transition: border-color .2s ease, color .2s ease;
}
.lang-btn:hover { border-color: var(--terra); color: var(--terra); }
.user-chip {
    display: flex; align-items: center; gap: 9px; padding: 5px 6px 5px 5px;
    border: 1px solid var(--line); border-radius: var(--r-pill); background: var(--surface);
    font-size: 13px; max-width: 210px;
}
html[dir="rtl"] .user-chip { padding: 5px 5px 5px 6px; }
.user-chip .av {
    width: 27px; height: 27px; border-radius: 50%; flex: none; display: grid; place-items: center;
    background: linear-gradient(140deg, var(--gold-light), var(--gold));
    color: var(--on-gold, var(--brick)); font-weight: 700; font-size: 12px;
}
/* The gold gradient does not change between themes, so the initials on
   top of it must not either — the dark --brick drops to ~1.9:1 there. */
html[data-theme="dark"] { --on-gold: var(--charcoal); }
.user-chip .em { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--ink-soft); }

.notif-dot {
    position: absolute; top: 6px; inset-inline-end: 6px;
    min-width: 16px; height: 16px; padding: 0 4px; border-radius: var(--r-pill);
    background: var(--terra); color: #fff; font-size: 10px; font-weight: 700;
    display: grid; place-items: center; line-height: 1;
}

/* Fixed, not absolute. The panel is a sibling of the fixed .topbar with
   no positioned ancestor, so `absolute` resolved against the document:
   scroll anywhere and the panel opened off-screen above the fold. */
.notif-panel {
    position: fixed; top: calc(var(--topbar-h) - 6px); inset-inline-end: 14px; z-index: 70;
    width: min(360px, calc(100vw - 28px));
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-2xl); box-shadow: var(--shadow-deep);
    overflow: hidden;
    animation: popIn .25s var(--ease-out);
}
@keyframes popIn { from { opacity: 0; transform: translateY(-8px); } }
.notif-head {
    display: flex; align-items: center; gap: 10px;
    padding: 14px 16px; border-bottom: 1px solid var(--line); background: var(--ground);
    font-weight: 700; font-size: 14.5px;
}
.notif-head .link-btn { margin-inline-start: auto; }
.notif-list { max-height: 62vh; overflow-y: auto; }
.notif-row { display: flex; gap: 12px; padding: 13px 16px; border-bottom: 1px solid var(--line); }
.notif-row:last-child { border-bottom: 0; }
.notif-row.unread { background: var(--terra-05); }
.notif-row .ic {
    width: 32px; height: 32px; border-radius: var(--r-md); flex: none; display: grid; place-items: center;
    background: var(--terra-10); color: var(--terra); font-size: 15px;
}
.notif-row .t { font-weight: 600; font-size: 13.5px; }
.notif-row .m { font-size: 12.5px; color: var(--ink-soft); }
.notif-row .w { font-size: 11px; color: var(--ink-soft); margin-top: 3px; }

.shell { display: grid; grid-template-columns: var(--side-w) 1fr; padding-top: var(--topbar-h); }

/* `top` on a sticky element is measured against the SCROLLPORT, not against
   the parent's padding box — so `top: var(--topbar-h)` parks the panel
   exactly beneath the fixed topbar, and the matching `height` makes it fill
   the rest of the viewport. Both are load-bearing: with `max-height` the
   panel shrink-wraps to its items and the surface stops mid-column. */
.sidebar {
    position: sticky; top: var(--topbar-h); align-self: start;
    height: calc(100vh - var(--topbar-h));
    padding: 18px 12px; border-inline-end: 1px solid var(--line);
    background: var(--surface); overflow-y: auto;
}
.side-label {
    font-size: 10.5px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
    color: var(--ink-soft); padding-inline: 12px; margin-bottom: 9px;
}
html[lang="ar"] .side-label { letter-spacing: 0; text-transform: none; font-size: 11.5px; }
.side-item {
    display: flex; align-items: center; gap: 11px; width: 100%; text-align: start;
    padding: 10px 12px; border-radius: var(--r-md); margin-bottom: 3px;
    background: none; border: 0; color: var(--ink-soft); font-size: 14px;
    transition: background .2s ease, color .2s ease;
    position: relative;
}
.side-item .icon { font-size: 16px; }
.side-item:hover { background: var(--ground); color: var(--ink); }
.side-item.active { background: var(--terra-10); color: var(--terra); font-weight: 600; }
.side-item.active::before {
    content: ''; position: absolute; inset-inline-start: 0; top: 50%; transform: translateY(-50%);
    width: 3px; height: 20px; background: var(--terra); border-radius: 0 3px 3px 0;
}
html[dir="rtl"] .side-item.active::before { border-radius: 3px 0 0 3px; }
.side-item .count {
    margin-inline-start: auto; font-size: 11.5px; font-weight: 700;
    background: var(--ground); color: var(--ink-soft); padding: 2px 8px; border-radius: var(--r-pill);
}
.side-item.active .count { background: var(--terra); color: #fff; }

/* Capped and centred: the shell gives .content the whole 1fr track, so on
   a wide monitor the panels used to hug the inline-start edge and leave a
   dead void down the other side. */
.content { padding: 26px 28px 70px; min-width: 0; width: 100%; max-width: 1180px; margin-inline: auto; }
.panel { display: none; animation: fadeUp .4s var(--ease-out); }
.panel.active { display: block; }
@keyframes fadeUp { from { opacity: 0; transform: translateY(10px); } }

.page-head { margin-bottom: 22px; }
.page-head h2 { margin: 0 0 4px; font-size: 25px; letter-spacing: -.02em; }
html[lang="ar"] .page-head h2 { letter-spacing: 0; }
.page-head p { margin: 0; font-size: 14px; color: var(--ink-soft); }

.card {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-2xl); padding: 24px; box-shadow: var(--shadow-card);
    margin-bottom: 18px;
}
.card > h3 { margin: 0 0 4px; font-size: 17px; }
.card > .cap { margin: 0 0 20px; font-size: 13.5px; color: var(--ink-soft); }
.card-max { max-width: 780px; }

.success-mark {
    width: 62px; height: 62px; border-radius: 50%; display: grid; place-items: center;
    margin: 4px auto 16px; background: var(--ok-bg); color: var(--ok); font-size: 30px;
}

/* Date and time are the two halves of one decision — side by side they fit
   on screen together instead of forcing a scroll between picking a day and
   seeing what is free on it. */
@media (min-width: 1200px) {
    .card-max { max-width: none; }
    #bookFlow { display: grid; grid-template-columns: 1fr 1fr; gap: 0 18px; align-items: start; }
    #bookFlow > .card { grid-column: 1 / -1; }
    #bookFlow > .card.bk-half { grid-column: auto; }
}

.stat-row { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; margin-bottom: 20px; }
.stat {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-xl); padding: 16px 18px;
}
.stat .k { font-size: 12px; color: var(--ink-soft); display: flex; align-items: center; gap: 6px; }
.stat .v { font-size: 26px; font-weight: 700; line-height: 1.25; margin-top: 2px; }

/* ═══════════════════════════════════════════════════════════
   Booking: who-for toggle, calendar, slots
   ═══════════════════════════════════════════════════════════ */
.seg {
    display: inline-flex; gap: 4px; padding: 4px; margin-bottom: 20px;
    background: var(--ground); border: 1px solid var(--line); border-radius: var(--r-pill);
}
.seg button {
    display: inline-flex; align-items: center; gap: 7px;
    padding: 8px 18px; border: 0; border-radius: var(--r-pill);
    background: none; color: var(--ink-soft); font-size: 13.5px; font-weight: 600;
    transition: background .22s var(--ease-out), color .22s var(--ease-out);
}
.seg button.on { background: var(--terra); color: #fff; box-shadow: var(--shadow-btn); }

.cal {
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-xl); padding: 16px; user-select: none;
}
.cal-top { display: flex; align-items: center; gap: 10px; margin-bottom: 14px; }
.cal-title { font-weight: 700; font-size: 15px; flex: 1; text-align: center; }
.cal-nav {
    width: 32px; height: 32px; border-radius: var(--r-md); flex: none;
    display: grid; place-items: center; background: var(--ground);
    border: 1px solid var(--line); color: var(--ink-soft); font-size: 14px;
    transition: border-color .2s ease, color .2s ease;
}
.cal-nav:hover:not(:disabled) { border-color: var(--terra); color: var(--terra); }
.cal-nav:disabled { opacity: .35; cursor: not-allowed; }
.cal-nav .icon { transform: scaleX(var(--dir)); }
.cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }
.cal-dow {
    text-align: center; font-size: 11px; font-weight: 700; color: var(--ink-soft);
    padding-bottom: 6px;
}
.cal-day {
    aspect-ratio: 1; display: grid; place-items: center; position: relative;
    border: 1px solid transparent; border-radius: var(--r-md);
    background: none; font-size: 13.5px; color: var(--ink);
    transition: background .18s var(--ease-out), border-color .18s var(--ease-out);
}
.cal-day:hover:not(:disabled) { background: var(--ground); border-color: var(--line); }
.cal-day:disabled { color: var(--line); cursor: not-allowed; }
.cal-day.other { visibility: hidden; }
.cal-day.today { font-weight: 700; color: var(--terra); }
.cal-day.today::after {
    content: ''; position: absolute; bottom: 5px; width: 4px; height: 4px;
    border-radius: 50%; background: var(--terra);
}
.cal-day.sel {
    background: linear-gradient(140deg, var(--terra), var(--deep-terra));
    color: #fff; font-weight: 700; border-color: transparent;
    box-shadow: var(--shadow-btn);
}
.cal-day.sel::after { background: #fff; }
.cal-legend { display: flex; gap: 16px; flex-wrap: wrap; margin-top: 14px; font-size: 11.5px; color: var(--ink-soft); }
.cal-legend span { display: inline-flex; align-items: center; gap: 6px; }
.cal-legend i { width: 9px; height: 9px; border-radius: 50%; display: inline-block; }

/* ── Date picker ───────────────────────────────────────────────
   Replaces every plain <input type="date"> with a popover matching
   the rest of the site — a native date input's calendar is drawn by
   the OS and cannot be styled. Shared by app.html and admin.html;
   see assets/js/datepicker.js. The real <input> stays in the DOM as
   the value/events source, visually hidden under the label. */
.dp-wrap {
    position: relative; display: flex; align-items: center; gap: 10px;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-lg);
    padding: 11px 14px; cursor: pointer;
    transition: border-color .2s ease, box-shadow .2s ease;
}
.dp-wrap:hover { border-color: var(--terra); }
.dp-wrap:focus-within, .dp-wrap.dp-open {
    border-color: var(--terra); box-shadow: 0 0 0 3px var(--terra-ring);
}
.dp-input {
    position: absolute; inset: 0; opacity: 0; cursor: pointer;
    border: 0; padding: 0; margin: 0; background: none; font-size: 14.5px;
}
/* The invisible input sits on top of the label, so the wrapper's own
   :focus-within ring above is the focus affordance — the input must not
   draw a second one on top of it. */
.dp-input:focus-visible { outline: none; }
.dp-label {
    flex: 1; font-size: 14.5px; color: var(--ink); pointer-events: none;
    white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.dp-label.dp-empty { color: var(--ink-soft); }
.dp-icon { flex: none; color: var(--terra); pointer-events: none; width: 17px; height: 17px; }

.dp-pop {
    /* Above .veil (90) so the calendar is not trapped behind a modal's
       backdrop when a date field lives inside one, but below
       .toast-wrap (95) so confirmations still surface over it. */
    position: fixed; z-index: 92; min-width: 280px;
    background: var(--surface); border: 1px solid var(--line); border-radius: var(--r-2xl);
    padding: 14px; box-shadow: var(--shadow-deep);
    animation: dpIn .16s var(--ease-out);
}
@keyframes dpIn { from { opacity: 0; transform: translateY(-6px); } }
.dp-pop-top { display: flex; align-items: center; gap: 8px; margin-bottom: 10px; }
.dp-pop-title { flex: 1; text-align: center; font-weight: 700; font-size: 14.5px; }
.dp-nav {
    width: 30px; height: 30px; flex: none; border-radius: var(--r-md); border: 1px solid var(--line);
    background: var(--ground); color: var(--ink-soft); display: grid; place-items: center;
    transition: color .18s ease, border-color .18s ease;
}
.dp-nav:hover { color: var(--terra); border-color: var(--terra); }
.dp-nav .icon { width: 15px; height: 15px; }
.dp-nav.prev .icon { transform: scaleX(-1); }
html[dir="rtl"] .dp-nav.prev .icon { transform: none; }
html[dir="rtl"] .dp-nav.next .icon { transform: scaleX(-1); }

.dp-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 3px; }
.dp-dow { text-align: center; font-size: 10.5px; font-weight: 700; color: var(--ink-soft); padding-bottom: 5px; }
.dp-day {
    aspect-ratio: 1; display: grid; place-items: center; position: relative;
    border-radius: var(--r-md); font-size: 13px; background: none; border: 0;
    color: var(--ink); font-family: inherit; cursor: pointer;
    transition: background .16s ease, color .16s ease;
}
.dp-day:hover:not(:disabled) { background: var(--ground); }
.dp-day.other { visibility: hidden; }
.dp-day:disabled { color: var(--line); cursor: not-allowed; }
.dp-day.today { font-weight: 700; color: var(--terra); }
.dp-day.today::after {
    content: ''; position: absolute; bottom: 3px; width: 4px; height: 4px;
    border-radius: 50%; background: var(--terra);
}
.dp-day.sel {
    background: linear-gradient(140deg, var(--terra), var(--deep-terra));
    color: #fff; font-weight: 700; box-shadow: var(--shadow-btn);
}
.dp-day.sel::after { background: #fff; }

.dp-foot {
    display: flex; justify-content: space-between; margin-top: 10px; padding-top: 10px;
    border-top: 1px solid var(--line);
}
.dp-foot button {
    background: none; border: 0; color: var(--terra); font-weight: 600; font-size: 12.5px;
    cursor: pointer; font-family: inherit; padding: 4px;
}
.dp-foot button:hover:not(:disabled) { text-decoration: underline; }
.dp-foot button:disabled { color: var(--ink-soft); opacity: .5; cursor: not-allowed; }

/* auto-fill, so a lone remaining slot keeps the same width as every other
   slot instead of stretching across the whole row. */
.slots { display: grid; grid-template-columns: repeat(auto-fill, minmax(94px, 1fr)); gap: 9px; }
.slot {
    padding: 11px 8px; border-radius: var(--r-md); text-align: center;
    background: var(--surface); border: 1px solid var(--line);
    font-size: 13.5px; font-weight: 600; font-family: 'DM Mono', ui-monospace, monospace;
    transition: border-color .18s var(--ease-out), color .18s var(--ease-out), transform .18s var(--ease-out);
}
.slot:hover:not(:disabled) { border-color: var(--terra); color: var(--terra); transform: translateY(-2px); }
.slot.on {
    background: linear-gradient(140deg, var(--terra), var(--deep-terra));
    color: #fff; border-color: transparent; box-shadow: var(--shadow-btn);
}
.slot:disabled { opacity: .42; cursor: not-allowed; text-decoration: line-through; }
.slot-note { padding: 26px 12px; text-align: center; color: var(--ink-soft); font-size: 13.5px; grid-column: 1 / -1; }

/* Sits above the booking form so the price is known before the patient
   invests in filling anything in, not only once they reach the summary. */
.fee-banner {
    display: flex; align-items: center; gap: 14px;
    background: var(--terra-08); border: 1px solid var(--terra-30);
    border-radius: var(--r-xl); padding: 14px 18px; margin-bottom: 18px;
}
.fee-banner > .icon { font-size: 22px; color: var(--terra); }
.fee-banner > div { flex: 1; min-width: 0; }
.fee-k { font-weight: 700; font-size: 14px; }
.fee-n { font-size: 12.5px; color: var(--ink-soft); margin-top: 2px; }
.fee-v { flex: none; font-size: 20px; font-weight: 700; color: var(--terra); white-space: nowrap; }

.summary {
    background: var(--ground); border: 1px solid var(--line);
    border-radius: var(--r-xl); padding: 16px 18px; margin-bottom: 18px;
}
/* Each pair is its own row, so a long value wraps under its own label
   instead of drifting out of line with it. */
.summary dl { margin: 0; display: grid; grid-template-columns: auto 1fr; gap: 8px 18px; font-size: 13.5px; align-items: baseline; }
.summary dt { color: var(--ink-soft); }
.summary dd { margin: 0; font-weight: 600; text-align: end; overflow-wrap: anywhere; }

/* ═══════════════════════════════════════════════════════════
   Appointment / family / document rows
   ═══════════════════════════════════════════════════════════ */
.tabs { display: flex; gap: 6px; border-bottom: 1px solid var(--line); margin-bottom: 18px; }
.tab {
    padding: 10px 16px; border: 0; background: none; color: var(--ink-soft);
    font-size: 14px; font-weight: 600; position: relative;
    transition: color .2s ease;
}
.tab.on { color: var(--terra); }
.tab.on::after {
    content: ''; position: absolute; inset-inline: 0; bottom: -1px; height: 2px;
    background: var(--terra); border-radius: 2px 2px 0 0;
}
.tab .count { font-size: 11.5px; opacity: .75; }

.row {
    display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-xl); padding: 16px 18px; margin-bottom: 11px;
    transition: border-color .2s ease, box-shadow .2s ease;
}
.row:hover { border-color: var(--terra-30); box-shadow: var(--shadow-card); }
.row.past { opacity: .78; }
.row-date {
    width: 62px; flex: none; text-align: center; padding: 8px 4px;
    background: var(--ground); border-radius: var(--r-md);
}
.row-date .d { font-size: 20px; font-weight: 700; line-height: 1.1; }
.row-date .m { font-size: 11px; color: var(--ink-soft); }
.row-main { flex: 1; min-width: 150px; }
.row-main .t { font-weight: 600; font-size: 15px; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.row-main .s { font-size: 13px; color: var(--ink-soft); display: flex; align-items: center; gap: 6px; margin-top: 2px; flex-wrap: wrap; }
.row-acts { display: flex; gap: 8px; margin-inline-start: auto; flex-wrap: wrap; }

.fam-card {
    display: flex; align-items: center; gap: 14px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-xl); padding: 16px 18px; margin-bottom: 11px;
}
.fam-card .av {
    width: 42px; height: 42px; border-radius: 50%; flex: none; display: grid; place-items: center;
    background: linear-gradient(140deg, var(--gold-light), var(--gold));
    color: var(--on-gold, var(--brick)); font-weight: 700; font-size: 16px;
}
.fam-card .n { font-weight: 600; font-size: 15px; }
.fam-card .r { font-size: 12.5px; color: var(--ink-soft); display: flex; gap: 12px; flex-wrap: wrap; }

.doc-card {
    display: flex; align-items: center; gap: 14px;
    background: var(--surface); border: 1px solid var(--line);
    border-radius: var(--r-xl); padding: 14px 18px; margin-bottom: 10px;
}
.doc-card .ic {
    width: 40px; height: 40px; border-radius: var(--r-md); flex: none; display: grid; place-items: center;
    background: var(--terra-10); color: var(--terra); font-size: 18px;
}
.doc-card .n { font-weight: 600; font-size: 14px; overflow-wrap: anywhere; }
.doc-card .s { font-size: 12px; color: var(--ink-soft); }

.drop {
    border: 2px dashed var(--line); border-radius: var(--r-xl);
    padding: 32px 20px; text-align: center; background: var(--ground);
    transition: border-color .22s var(--ease-out), background .22s var(--ease-out); margin-bottom: 18px;
}
.drop.over { border-color: var(--terra); background: var(--terra-08); }
.drop .icon { font-size: 30px; color: var(--terra); display: block; margin: 0 auto 10px; }
.drop .t { font-weight: 600; font-size: 15px; }
.drop .s { font-size: 12.5px; color: var(--ink-soft); margin-top: 4px; }

.bar { height: 6px; background: var(--ground); border-radius: 3px; overflow: hidden; margin-top: 14px; }
.bar > i { display: block; height: 100%; width: 0; background: linear-gradient(90deg, var(--terra), var(--gold)); transition: width .3s ease; }
/* Indeterminate, because supabase-js exposes no upload progress. The
   previous bar animated to fixed percentages that meant nothing. */
.bar.indeterminate > i {
    width: 40%; transition: none;
    animation: barSlide 1.1s var(--ease-out) infinite;
}
@keyframes barSlide {
    0%   { transform: translateX(calc(var(--dir) * -100%)); }
    100% { transform: translateX(calc(var(--dir) * 250%)); }
}

/* ═══════════════════════════════════════════════════════════
   Modal
   ═══════════════════════════════════════════════════════════ */
.veil {
    position: fixed; inset: 0; z-index: 90; display: grid; place-items: center; padding: 20px;
    background: rgba(42, 24, 16, .55); backdrop-filter: blur(3px);
    animation: fadeIn .2s ease;
}
@keyframes fadeIn { from { opacity: 0; } }
.modal {
    width: 100%; max-width: 460px; background: var(--surface);
    border: 1px solid var(--line); border-radius: var(--r-3xl); padding: 28px;
    box-shadow: var(--shadow-deep); animation: cardIn .3s var(--ease-out);
    max-height: 88vh; overflow-y: auto;
}
.modal h3 { margin: 0 0 6px; font-size: 19px; }
.modal .cap { margin: 0 0 20px; font-size: 13.5px; color: var(--ink-soft); }
.modal-acts { display: flex; gap: 10px; margin-top: 22px; }
.modal-acts .btn { flex: 1; }

.toast-wrap {
    position: fixed; inset-inline: 0; bottom: 22px; z-index: 95;
    display: grid; gap: 9px; justify-items: center; pointer-events: none; padding-inline: 16px;
}
.toast {
    display: flex; align-items: center; gap: 11px;
    background: var(--charcoal); color: var(--warm-white);
    padding: 13px 20px; border-radius: var(--r-pill);
    box-shadow: var(--shadow-deep); font-size: 14px; font-weight: 500;
    animation: toastIn .35s var(--ease-spring);
    max-width: min(460px, 100%);
}
/* --warm-white flips to a dark value in the dark theme, so the ink on this
   permanently-dark chip has to be restated there. */
html[data-theme="dark"] .toast { color: var(--ink); }
.toast.ok  { background: #2F5E39; }
.toast.bad { background: #8C2F1C; }
@keyframes toastIn { from { opacity: 0; transform: translateY(18px); } }

/* ═══════════════════════════════════════════════════════════
   Responsive
   ═══════════════════════════════════════════════════════════ */
@media (max-width: 980px) {
    .shell { grid-template-columns: 1fr; }
    .sidebar {
        position: sticky; top: var(--topbar-h); height: auto; z-index: 50;
        display: flex; gap: 6px; overflow-x: auto; padding: 10px 12px;
        border-inline-end: 0; border-bottom: 1px solid var(--line);
        scrollbar-width: none;
    }
    .sidebar::-webkit-scrollbar { display: none; }
    .side-label { display: none; }
    .side-item { width: auto; white-space: nowrap; margin-bottom: 0; padding: 9px 14px; border-radius: var(--r-pill); }
    .side-item.active::before { display: none; }
    .content { padding: 20px 16px 60px; }
    .stat-row { grid-template-columns: 1fr; }
    .user-chip .em { display: none; }
    .user-chip { max-width: none; }
}

@media (max-width: 640px) {
    body { font-size: 14.5px; }
    .card { padding: 18px; border-radius: var(--r-xl); }
    .grid-2 { grid-template-columns: 1fr; }
    .field-half { max-width: none; }
    .page-head h2 { font-size: 21px; }
    .row { padding: 14px; gap: 11px; }
    .row-acts { width: 100%; margin-inline-start: 0; }
    .row-acts .btn { flex: 1; }
    .slots { grid-template-columns: repeat(auto-fill, minmax(80px, 1fr)); }
    /* The amount keeps its own line here rather than being squeezed
       against the note text, which wraps to three or four lines. */
    .fee-banner { flex-wrap: wrap; padding: 14px; gap: 10px 12px; }
    .fee-banner > div { flex: 1 1 100%; order: 3; }
    .fee-v { margin-inline-start: auto; font-size: 18px; }
    .topbar { padding-inline: 12px; gap: 8px; }
    .topbar-brand .name { display: none; }
    .auth-card { padding: 28px 22px; }
    .modal { padding: 22px; }
}

/* ── Guest booking ────────────────────────────────────────────
   A guest session is an anonymous Supabase JWT: it can book and
   manage its own appointments, and nothing else — the policies on
   profiles, family members, notifications and the document bucket
   all require a non-anonymous token. These styles carry the two
   places that has to be visible: the separator on the login gate,
   and the standing notice plus locked-panel prompt inside. */

/* "or" rule between the email form and the guest button. */
.auth-sep {
    display: flex; align-items: center; gap: 12px;
    margin: 22px 0 16px;
    font-size: 12px; text-transform: uppercase; letter-spacing: .08em;
    color: var(--ink-soft);
}
.auth-sep::before, .auth-sep::after {
    content: ''; flex: 1; height: 1px; background: var(--line);
}

.guest-banner {
    display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap;
    padding: 14px 16px; margin-bottom: 22px;
    border: 1px solid var(--line);
    /* Warm rather than alarming: being a guest is a supported state, not an
       error, so this must not read like the .alert.bad treatment. */
    background: var(--sand, #F5EDE0);
    border-radius: var(--r-md, 12px);
}
.guest-banner > .icon { font-size: 20px; color: var(--terra); margin-top: 1px; flex: none; }
.guest-banner > div { flex: 1; min-width: 200px; }
.guest-banner .gb-t { font-weight: 600; font-size: 14px; margin-bottom: 3px; }
.guest-banner .gb-b { font-size: 13px; color: var(--ink-soft); line-height: 1.55; }
.guest-banner button { flex: none; align-self: center; }

/* Replaces the body of the profile / family / documents panels for a
   guest, instead of showing controls whose writes RLS would refuse. */
.guest-lock {
    text-align: center;
    padding: 40px 24px;
    border: 1px dashed var(--line);
    border-radius: var(--r-md, 12px);
}
.guest-lock .icon { font-size: 34px; color: var(--line); display: block; margin: 0 auto 14px; }
.guest-lock h3 { font-size: 17px; margin: 0 0 8px; }
.guest-lock p {
    margin: 0 auto 18px; max-width: 42ch;
    font-size: 14px; color: var(--ink-soft); line-height: 1.6;
}
