/* Baztavan — RTL clinic reservation UI. Bootstrap 5 RTL handles the grid/components;
   this file adds the IranYekanWeb font and the clinic's calm teal identity. */

/* IranYekanWeb — path is configurable via CLINIC_FONT_PATH (passed in from the layout).
   Files are expected under public{CLINIC_FONT_PATH}. If absent, we fall back gracefully. */
@font-face {
    font-family: 'IRANYekanWeb';
    src: url('/fonts/iranyekan/IRANYekanWebRegular.woff2') format('woff2'),
         url('/fonts/iranyekan/IRANYekanWebRegular.woff') format('woff');
    font-weight: 400;
    font-display: swap;
}
@font-face {
    font-family: 'IRANYekanWeb';
    src: url('/fonts/iranyekan/IRANYekanWebBold.woff2') format('woff2'),
         url('/fonts/iranyekan/IRANYekanWebBold.woff') format('woff');
    font-weight: 700;
    font-display: swap;
}

:root {
    --brand: #0d9488;          /* teal 600 */
    --brand-dark: #0f766e;     /* teal 700 */
    --brand-soft: #ccfbf1;     /* teal 100 */
    --ink: #1f2937;
    --muted: #6b7280;
    --line: #e5e7eb;
    --bg: #f4f6f8;
}

* { font-family: 'IRANYekanWeb', 'Vazirmatn', Tahoma, system-ui, sans-serif; }

body {
    background: var(--bg);
    color: var(--ink);
    font-size: 0.95rem;
}

/* ---- Shell ---- */
.app-shell { display: flex; min-height: 100vh; }
.sidebar {
    width: 258px;
    background: #fff;
    border-inline-start: 1px solid var(--line);
    padding: 1.25rem 1rem;
    position: sticky;
    top: 0;
    height: 100vh;
    overflow-y: auto;
    flex-shrink: 0;
}
.sidebar .brand {
    display: flex; align-items: center; gap: .6rem;
    font-weight: 700; font-size: 1.15rem; color: var(--brand-dark);
    padding: .25rem .5rem 1rem;
}
/* The brand is one image now, so the tinted square that used to hold an
   icon beside the word is gone with it. */
.sidebar .nav-link {
    color: var(--ink); border-radius: 10px; padding: .6rem .8rem;
    display: flex; align-items: center; gap: .65rem; margin-bottom: .15rem;
    font-size: .92rem;
}
.sidebar .nav-link:hover { background: var(--bg); }
.sidebar .nav-link.active { background: var(--brand); color: #fff; }
.sidebar .nav-section { font-size: .72rem; color: var(--muted); padding: .9rem .8rem .3rem; }

.main { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.topbar {
    background: #fff; border-bottom: 1px solid var(--line);
    padding: .85rem 1.4rem; display: flex; align-items: center; justify-content: space-between;
}
.topbar .title { font-weight: 700; font-size: 1.05rem; }
.content { padding: 1.4rem; }

/* ---- Cards & bits ---- */
.card { border: 1px solid var(--line); border-radius: 14px; }
.card-header { background: #fff; border-bottom: 1px solid var(--line); font-weight: 700; }
.stat-card { border-radius: 14px; padding: 1.1rem 1.2rem; background: #fff; border: 1px solid var(--line); }
.stat-card .num { font-size: 1.7rem; font-weight: 700; }
.stat-card .lbl { color: var(--muted); font-size: .85rem; }
.stat-card .ico { width: 44px; height: 44px; border-radius: 12px; display: grid; place-items: center; font-size: 1.3rem; background: var(--brand-soft); color: var(--brand-dark); }

.btn-brand { background: var(--brand); border-color: var(--brand); color: #fff; }
.btn-brand:hover { background: var(--brand-dark); border-color: var(--brand-dark); color: #fff; }
.text-brand { color: var(--brand-dark); }

/* ---- Brand wordmark ----
   Loaded for every shell, because head_assets pulls app.css everywhere and
   family.css / admin.css only stack on top. Three sizes, set by height with
   width left to follow: the artwork is 2.8:1 and a fixed width would squash
   it the first time the file is re-exported at another size. */
.brand-logo { display: block; width: auto; height: 34px; }
.brand-logo--sm { height: 26px; }
.brand-logo--md { height: 34px; }
.brand-logo--lg { height: 44px; }

/* ---- Slot grid ---- */
.slot-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: .5rem; }
.slot {
    border: 1px solid var(--line); border-radius: 10px; padding: .55rem .3rem;
    text-align: center; cursor: pointer; background: #fff; font-size: .9rem; user-select: none;
    transition: all .12s;
}
.slot.available:hover { border-color: var(--brand); }
.slot.booked, .slot.past { background: #f3f4f6; color: #9ca3af; cursor: not-allowed; text-decoration: line-through; }
/* Last, and stated again for :disabled. A two-session visit selects BOTH of
   its half-hours, and the second is often not startable in its own right — no
   double could begin there — so it carries the disabled attribute while still
   being part of what was chosen. Selected must win; at equal specificity that
   is decided by order alone. */
.slot.selected,
.slot.selected:disabled { background: var(--brand); border-color: var(--brand); color: #fff; text-decoration: none; }
.slot .en { direction: ltr; display: inline-block; }

/* ---- Choosing a day, then a time ----
   Replaces the seven-column week grid. That showed every open slot at once,
   which reads well on a desk and badly on a phone: each day got a sliver too
   narrow for four digits, and Thursday sat off the edge with nothing to say so.

   Now the week is a strip of seven day buttons and only the chosen day's times
   are listed underneath. Both are radiogroups of real <button>s, so the flow
   still works from a keyboard.

   Lives in app.css rather than family.css because the public therapist page
   shares this markup and never loads the family stylesheet. */
.wk-nav { display: flex; align-items: center; justify-content: space-between; gap: .5rem; margin-bottom: .7rem; }
.wk-range { font-weight: 700; font-size: .88rem; }
.wk-arrow {
    width: 34px; height: 34px; border-radius: 11px; flex: 0 0 auto;
    display: grid; place-items: center;
    background: #fff; border: 1px solid var(--line);
    color: var(--brand-dark); text-decoration: none;
}
.wk-arrow:hover { border-color: var(--brand); color: var(--brand-dark); }
.wk-arrow.is-off { color: #c3cfcc; background: #f7f9f9; cursor: default; }

.daystrip { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); gap: .3rem; margin-bottom: 1rem; }
.daycell {
    display: grid; gap: .1rem; justify-items: center;
    padding: .5rem .1rem;
    border: 1px solid var(--line); border-radius: 14px;
    background: #fff; color: var(--ink);
    font: inherit; cursor: pointer; min-width: 0;
}
.daycell .dw { font-size: .62rem; color: var(--muted); }
.daycell .dn { font-size: 1rem; font-weight: 700; line-height: 1.2; }
.daycell .ds { font-size: .56rem; color: var(--muted); white-space: nowrap; }
.daycell.is-today { border-color: var(--brand); }
.daycell:hover:not(:disabled) { border-color: var(--brand); }
.daycell.selected {
    background: var(--brand); border-color: var(--brand); color: #fff;
}
.daycell.selected .dw, .daycell.selected .ds { color: rgba(255, 255, 255, .85); }
.daycell:disabled, .daycell.is-off { background: #f4f6f6; color: #a9b5b1; cursor: not-allowed; }
.daycell:disabled .dw, .daycell:disabled .ds { color: #b9c4c1; }
.daycell:focus-visible { outline: 2px solid var(--brand); outline-offset: 2px; }

.slotpanel-head { display: flex; align-items: baseline; justify-content: space-between; gap: .5rem; margin-bottom: .6rem; }
.slotpanel-head .t { font-weight: 700; font-size: .92rem; }
.slotpanel-head .m { font-size: .74rem; color: var(--muted); }
.slotpanel-empty { font-size: .8rem; color: var(--muted); margin: 0 0 .5rem; }

/* Three columns is what fits four Persian digits comfortably on a phone and
   still gives a desk enough density. */
.slotgrid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: .5rem; }

.slot-legend {
    display: flex; flex-wrap: wrap; gap: .4rem .9rem;
    margin-top: .8rem; font-size: .7rem; color: var(--muted);
}
.slot-legend span { display: inline-flex; align-items: center; gap: .3rem; }
.legend-dot { width: 11px; height: 11px; border-radius: 4px; display: inline-block; border: 1px solid var(--line); }
.legend-dot.is-selected { background: var(--brand); border-color: var(--brand); }
.legend-dot.is-free { background: #fff; }
.legend-dot.is-taken { background: #e9efed; border-color: #e9efed; }
.legend-dot.is-past { background: #f3f4f6; border-color: #e5e7eb; }

.hold-note {
    display: flex; align-items: center; gap: .5rem;
    margin-top: .9rem; padding: .6rem .8rem;
    background: #fef3c7; color: #92400e;
    border-radius: 12px; font-size: .76rem;
}

@media (max-width: 380px) {
    .daycell .ds { font-size: .5rem; }
}

/* The commit bar: what it costs, and the button that books it. Deliberately
   NOT sticky — the family panel already fixes its navigation to the bottom of
   the screen, and two stacked bars leave nothing to read between them. */
.booking-total {
    display: flex; align-items: center; justify-content: space-between;
    gap: .75rem; flex-wrap: wrap;
    padding: .85rem 1rem; border-radius: 16px;
    background: #fff; border: 1px solid var(--line);
}
.booking-total .bt-sum { display: grid; gap: .1rem; }
.booking-total .lbl { font-size: .72rem; color: var(--muted); }
.booking-total .val { font-size: 1.05rem; font-weight: 700; color: var(--brand-dark); }
.booking-total .pick { font-size: .72rem; color: var(--muted); }
.booking-total .btn:disabled { opacity: 1; background: #e9efed; border-color: #e9efed; color: #a9b5b1; }

/* The «۱ جلسه / ۲ جلسه» choice is a Bootstrap button group. Its default active
   state is a dark grey that reads as "disabled" next to a teal page, and its
   square corners sit badly among 14–20px radii. */
.btn-group > .btn { border-radius: 12px; }
.btn-group > .btn:not(:last-child) { margin-inline-end: .35rem; }
.btn-group > .btn.active {
    background: var(--brand);
    border-color: var(--brand);
    color: #fff;
}

/* The session segmented control. `flex: 1 1 0` rather than Bootstrap's
   `auto`, so the two halves are equal regardless of how long their labels
   are — unequal halves read as a bug, not a choice. Capped in width because
   stretched across a desktop it stops looking like one control. */
.seg { width: 100%; max-width: 460px; }
.seg > .btn { flex: 1 1 0; min-width: 0; }

/* status chips */
.chip { font-size: .78rem; padding: .18rem .6rem; border-radius: 999px; font-weight: 700; display: inline-block; }
.chip-pending { background: #fef3c7; color: #92400e; }
.chip-confirmed { background: #d1fae5; color: #065f46; }
.chip-rejected { background: #fee2e2; color: #991b1b; }
.chip-cancelled { background: #f3f4f6; color: #4b5563; }
.chip-paid { background: #d1fae5; color: #065f46; }
.chip-unpaid { background: #fef3c7; color: #92400e; }
.chip-refunded { background: #e0e7ff; color: #3730a3; }
.chip-on_account { background: #e0f2fe; color: #075985; }

[x-cloak] { display: none !important; }
.stars { color: #f59e0b; font-size: .9rem; white-space: nowrap; }
.rating-inline { display: inline-flex; align-items: center; gap: .3rem; font-size: .85rem; }

.en { direction: ltr; display: inline-block; unicode-bidi: embed; }
table td, table th { vertical-align: middle; }

@media (max-width: 768px) {
    .sidebar { position: fixed; inset-inline-start: 0; z-index: 1040; transform: translateX(100%); transition: transform .2s; }
    .sidebar.open { transform: translateX(0); }
    .app-shell { display: block; }
}

/* Manual payment states (M2) */
.chip-receipt_pending { background: #dbeafe; color: #1e40af; }
.chip-receipt_rejected { background: #fee2e2; color: #991b1b; }
.chip-approved { background: #d1fae5; color: #065f46; }

/* 24-hour Persian time picker, replacing <input type="time"> — the native
   control renders in the BROWSER's locale, so working hours showed an English
   "AM/PM" wheel regardless of the page language. See partials/time_select. */
/* One working range or break per line: badge · از · [time] · تا · [time] · 🗑 */
.time-row { overflow-x: auto; padding-bottom: .15rem; }
.time-row-label { color: #6b7280; font-size: .85rem; flex: 0 0 auto; }

.time-select { display: inline-block; }
.time-select select {
    width: auto;
    min-width: 6.5rem;   /* fits ۰۹:۰۰ plus the caret without ever wrapping */
    text-align: center;
    font-variant-numeric: tabular-nums;
}

/* Payment hold + cancellation (M17) */
/* Greyer than .chip-cancelled: nobody acted, the window just closed. */
.chip-expired { background: #e5e7eb; color: #6b7280; }
/* Amber, like every other "the clinic still owes something" state. */
.chip-refund_pending { background: #fef3c7; color: #92400e; }
.payment-countdown { margin-top: .25rem; white-space: nowrap; }

/* Attendance — a separate axis from reservation status (M7) */
.chip-completed { background: #e0e7ff; color: #3730a3; }
.chip-att-present { background: #d1fae5; color: #065f46; }
.chip-att-late { background: #fef3c7; color: #92400e; }
.chip-att-absent { background: #fee2e2; color: #991b1b; }
.chip-att-none { background: #f3f4f6; color: #6b7280; }

/* Slot / day cells are real <button>s now (M14 accessibility): strip the UA
   button chrome and give keyboard users a visible focus ring. */
.slot {
    font: inherit; color: inherit; appearance: none; width: 100%;
}
.slot:focus-visible {
    outline: 2px solid var(--brand); outline-offset: 2px;
}
.slot:disabled { cursor: not-allowed; }

/* ==== Authentication screens ==========================================
   One shell for every way into the system: the family's OTP flow and the
   staff email/password login (layouts/auth.blade.php).

   Shape: a teal hero at the top, then a white sheet with a large rounded
   top edge pulled up over it. Previously these were full-bleed teal pages
   with white-on-teal inputs and a yellow button; the palette below is
   sampled from the design export, and is deliberately softer than the
   app's --brand (#0d9488) used behind the login. Scoped to .auth-* so it
   cannot leak into the panels. */
.auth-page {
    --auth-teal-top: #4ca397;
    --auth-teal-bottom: #428e83;
    --auth-teal: #429085;
    --auth-teal-dark: #2f7a70;
    /* Given by the designer. Pixel-sampling the export read #f6f9f8, one step
       off — the exact value wins over anything measured off a render. */
    --auth-field: #F5F9F8;
    --auth-panel: #ecf6f4;
    --auth-tile: #d8ece7;
    --auth-disabled: #a9b5b1;
    --auth-ink: #1f2937;
    --auth-muted: #6b7c78;

    min-height: 100vh;
    background: var(--auth-panel);
    display: flex;
    justify-content: center;
    padding: 0;
}
.auth-shell {
    width: 100%;
    max-width: 430px;
    background: #fff;
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    box-shadow: 0 0 60px rgba(31, 41, 55, .08);
}

/* --- hero ------------------------------------------------------------- */
.auth-hero {
    position: relative;
    overflow: hidden;
    background: linear-gradient(160deg, var(--auth-teal-top), var(--auth-teal-bottom));
    color: #fff;
    padding: 1.5rem 1.5rem 3.5rem;
    text-align: center;
}
/* Decorative only — never announced, and they must not intercept taps. */
.auth-hero::before,
.auth-hero::after {
    content: "";
    position: absolute;
    border-radius: 50%;
    background: rgba(255, 255, 255, .07);
    pointer-events: none;
}
.auth-hero::before { width: 230px; height: 230px; top: -80px; inset-inline-start: -70px; }
.auth-hero::after  { width: 190px; height: 190px; top: 30px;  inset-inline-end: -60px; }
.auth-hero > * { position: relative; z-index: 1; }

.auth-badge {
    display: inline-block;
    background: rgba(255, 255, 255, .22);
    color: #fff;
    font-size: .78rem;
    font-weight: 700;
    padding: .3rem 1rem;
    border-radius: 999px;
    margin-bottom: .9rem;
}
/* Block-level, so the badge above it keeps its own line — as inline-flex the
   two sat side by side once the wordmark became an image narrower than the
   word it replaced. Shrink-to-fit and auto margins keep it centred without
   letting the pill variant stretch the full width of the hero. */
.auth-wordmark {
    display: flex; align-items: center; justify-content: center;
    width: fit-content; margin-inline: auto;
}
/* The white pill that used to sit under the staff wordmark is gone: a card
   behind a logo that is already a shape, on a hero built to be uninterrupted. */
.auth-hero h1 { font-size: 1.3rem; font-weight: 800; margin: 1.1rem 0 .4rem; }
.auth-hero p  { font-size: .88rem; margin: 0; color: rgba(255, 255, 255, .82); }

.auth-back {
    position: absolute; top: 1.4rem; inset-inline-start: 1.4rem; z-index: 2;
    width: 38px; height: 38px; border-radius: 50%;
    background: rgba(255, 255, 255, .2); color: #fff;
    display: grid; place-items: center; text-decoration: none; font-size: 1.1rem;
}
.auth-back:hover, .auth-back:focus-visible { background: rgba(255, 255, 255, .32); color: #fff; }

/* --- white sheet ------------------------------------------------------ */
.auth-sheet {
    background: #fff;
    border-radius: 28px 28px 0 0;
    margin-top: -2.25rem;
    padding: 1.6rem 1.5rem 2rem;
    flex: 1;
    display: flex;
    flex-direction: column;
    /* The hero paints after this in source order, so without its own stacking
       context the sheet is pulled up UNDER the hero and the first label is
       sliced in half by the teal edge. */
    position: relative;
    z-index: 2; /* above the hero's own positioned children, which sit at 1 */
}
.auth-sheet-body { flex: 1; }

.auth-alert {
    background: var(--auth-panel); color: var(--auth-teal-dark);
    border-radius: 12px; padding: .7rem 1rem; font-size: .86rem; margin-bottom: 1rem;
}

/* --- fields ----------------------------------------------------------- */
.auth-label {
    display: block; font-size: .84rem; color: var(--auth-muted);
    margin-bottom: .45rem; font-weight: 600;
}
.auth-field { position: relative; margin-bottom: 1rem; }
.auth-input {
    width: 100%; background: var(--auth-field); border: 1.5px solid transparent;
    border-radius: 14px; padding: .95rem 1rem; font-size: 1rem; color: var(--auth-ink);
    transition: border-color .15s ease, background-color .15s ease;
}
.auth-input::placeholder { color: #a8b5b1; }
.auth-input:focus {
    outline: none; background: #fff;
    border-color: var(--auth-teal); box-shadow: 0 0 0 .2rem rgba(66, 144, 133, .15);
}
.auth-input.is-invalid { border-color: #dc3545; background: #fff5f5; }

/* The tile sits OPPOSITE the side the value starts on, so it can never cover
   what was typed. These use physical sides on purpose: the page is always RTL,
   but several of these inputs carry dir="ltr" (a phone number, an email), and a
   logical property resolves against the INPUT's own direction — which put the
   padding on the right while the tile sat on the left, hiding the first digits. */
.auth-field--icon .auth-input { padding-left: 4rem; padding-right: 1rem; }
.auth-tile {
    position: absolute; left: .5rem; top: 50%; transform: translateY(-50%);
    width: 42px; height: 42px; border-radius: 12px;
    background: var(--auth-tile); color: var(--auth-teal-dark);
    display: grid; place-items: center; font-size: 1.05rem; pointer-events: none;
}

/* Latin fields (email) read left-to-right, so their text begins where the tile
   would be. Move it to the other side rather than pad around it. */
.auth-field--ltr .auth-input { padding-right: 4rem; padding-left: 1rem; }
.auth-field--ltr .auth-tile { left: auto; right: .5rem; }

/* The password eye is interactive, so it sits opposite the decorative tile. */
.auth-reveal {
    position: absolute; left: .9rem; top: 50%; transform: translateY(-50%);
    background: none; border: none; color: var(--auth-muted); font-size: 1.05rem; padding: .25rem;
    z-index: 2;
}
.auth-field--ltr.auth-field--reveal .auth-input { padding-left: 2.9rem; }

.auth-help  { font-size: .78rem; color: var(--auth-muted); margin: -.55rem 0 1rem; }
.auth-error { font-size: .82rem; color: #dc3545; margin: -.55rem 0 1rem; }

.auth-row { display: flex; align-items: center; justify-content: space-between; margin-bottom: 1.1rem; }
.auth-link { color: var(--auth-teal); font-weight: 700; text-decoration: none; }
.auth-link:hover { color: var(--auth-teal-dark); text-decoration: underline; }

/* --- primary action --------------------------------------------------- */
.auth-btn {
    display: block; width: 100%; border: none; border-radius: 16px;
    padding: 1rem; font-size: 1rem; font-weight: 800; color: #fff;
    background: linear-gradient(160deg, var(--auth-teal-top), var(--auth-teal));
    box-shadow: 0 8px 18px rgba(66, 144, 133, .25);
    transition: filter .15s ease;
}
.auth-btn:hover, .auth-btn:focus-visible { filter: brightness(.95); color: #fff; }
.auth-btn:disabled, .auth-btn.is-disabled {
    background: var(--auth-disabled); box-shadow: none; color: #f3f5f4; cursor: not-allowed;
}
.auth-btn--ghost {
    background: var(--auth-field); color: var(--auth-teal-dark);
    box-shadow: none; margin-top: .7rem;
}
.auth-btn--ghost:hover { background: var(--auth-tile); color: var(--auth-teal-dark); }

/* --- one-time code ---------------------------------------------------- */
.auth-code-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: .8rem; }
.auth-edit {
    font-size: .84rem; color: var(--auth-teal); text-decoration: none; font-weight: 700;
    display: inline-flex; align-items: center; gap: .3rem;
}
.auth-edit:hover { text-decoration: underline; color: var(--auth-teal-dark); }

.auth-boxes { display: flex; gap: .7rem; justify-content: space-between; }
.auth-box {
    flex: 1; height: 4.1rem; text-align: center; font-size: 1.6rem; font-weight: 800;
    background: var(--auth-panel); border: 2px solid transparent; border-radius: 16px;
    color: var(--auth-ink); min-width: 0;
}
.auth-box:focus { outline: none; background: #fff; border-color: var(--auth-teal); }
.auth-box.is-invalid { border-color: #dc3545; background: #fff5f5; color: #dc3545; }
.auth-fallback-input { text-align: center; letter-spacing: .5em; font-size: 1.3rem; }

.auth-cooldown {
    display: inline-flex; align-items: center; gap: .4rem;
    background: var(--auth-field); color: var(--auth-muted);
    border-radius: 999px; padding: .5rem 1rem; font-size: .84rem;
}
.auth-resend-wrap { margin: 1.1rem 0 1.4rem; text-align: center; min-height: 2.2rem; }
.auth-resend-btn {
    background: var(--auth-field); border: none; border-radius: 999px;
    padding: .5rem 1.2rem; font-size: .86rem; font-weight: 700; color: var(--auth-teal-dark);
}
.auth-resend-btn:hover { background: var(--auth-tile); }

/* --- reassurance strip ------------------------------------------------ */
.auth-chips {
    display: flex; background: var(--auth-panel); border-radius: 18px;
    padding: .9rem .5rem; margin-top: 1.5rem;
}
.auth-chip { flex: 1; text-align: center; padding: 0 .3rem; }
.auth-chip + .auth-chip { border-inline-start: 1px solid rgba(66, 144, 133, .18); }
.auth-chip i {
    display: grid; place-items: center; width: 34px; height: 34px; margin: 0 auto .4rem;
    border-radius: 50%; background: var(--auth-tile); color: var(--auth-teal-dark); font-size: .95rem;
}
.auth-chip b { display: block; font-size: .82rem; color: var(--auth-ink); font-weight: 700; }
.auth-chip span { display: block; font-size: .72rem; color: var(--auth-muted); }

.auth-foot { text-align: center; font-size: .86rem; color: var(--auth-muted); margin-top: 1.5rem; }

@media (max-width: 430px) {
    .auth-shell { box-shadow: none; }
    .auth-box { height: 3.6rem; font-size: 1.35rem; }
}

/* The design is a phone screen. Stretched to a desktop viewport that leaves a
   tall empty gap between the button and the footer line, which reads as a bug
   rather than as breathing room — so above phone width the shell becomes a
   centred card that is only as tall as its content. */
@media (min-width: 431px) {
    .auth-page { align-items: center; padding: 2.5rem 1rem; }
    .auth-shell {
        min-height: 0;
        border-radius: 24px;
        overflow: hidden;
    }
    .auth-sheet { padding-bottom: 1.75rem; }
    .auth-sheet-body { flex: 0 1 auto; }
}

.otp-links { margin-top: 2.25rem; font-size: .85rem; color: rgba(255, 255, 255, .85); }
.otp-links a { color: #fff; font-weight: 700; text-decoration: none; }
.otp-links a:hover { text-decoration: underline; }

@media (max-width: 380px) {
    .otp-box { width: 2.5rem; height: 3rem; font-size: 1.2rem; }
}

/* ==================================================================
   Intro carousel — /welcome
   Figma «۱٫۱ معرفی». Rides on the auth shell rather than a new one: the
   hero, the overlapping white sheet and the 431px card breakpoint are the
   same design, and a second copy of them would drift.
   ================================================================== */
.ob-page .auth-hero {
    /* Taller than a login hero, and weighted to the top: the wordmark sits
       high and the space under it is where the shapes live. Measured off the
       design at 390px — wordmark centred near y=100, sheet starting at 278,
       which the sheet's own -2.25rem overlap has to be added back to. */
    padding: 4.5rem 1.5rem 11.5rem;
}
.ob-page .auth-wordmark .brand-logo { height: 56px; }

/* The design's top-right shape is an outline, not a fill. The hero's own
   ::before is a filled disc, so it is redrawn here rather than a third
   element being stacked on top of it. */
.ob-page .auth-hero::before {
    width: 145px; height: 145px;
    top: 20px; inset-inline-start: -8px;
    background: transparent;
    border: 1.5px solid rgba(255, 255, 255, .17);
}

/* The two shapes the pseudo-elements do not cover.
   RTL TRAP: inset-inline-START is the RIGHT edge here. Written the other way
   round first, and both shapes came out on the wrong side — a mirror image of
   the design that reads as "roughly right" until you hold them side by side.
   The small dot is on the LEFT in the design, so it takes inline-END. */
.ob-orb {
    position: absolute;
    border-radius: 50%;
    background: rgba(255, 255, 255, .12);
    pointer-events: none;
}
.ob-orb-sm { width: 11px; height: 11px; top: 206px; inset-inline-end: 62px; }
.ob-orb-md { width: 74px; height: 74px; top: 184px; inset-inline-start: -16px; }

.ob {
    height: 100%;
    display: flex;
    flex-direction: column;
    text-align: center;
}
.ob-slides { padding-top: 1.1rem; }

.ob-title {
    font-size: 1.32rem;
    font-weight: 800;
    color: var(--ink);
    margin: 0 0 .9rem;
}
.ob-body {
    font-size: .92rem;
    line-height: 2.1;
    color: var(--auth-muted);
    margin: 0 auto;
    max-width: 21rem;
}

.ob-dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: .4rem;
    margin-top: 1.6rem;
}
.ob-dot {
    width: 8px; height: 8px;
    padding: 0;
    border: 0;
    border-radius: 999px;
    background: #cfdcd9;
    cursor: pointer;
    /* The active one stretches rather than recolouring alone, so the step you
       are on is legible without relying on telling two greens apart. */
    transition: width .18s ease, background-color .18s ease;
}
.ob-dot.is-active {
    width: 26px;
    background: var(--auth-teal);
}
.ob-dot:focus-visible { outline: 2px solid var(--auth-teal-dark); outline-offset: 3px; }

/* margin-top:auto pins these to the foot of the sheet on a phone, where the
   sheet is flex:1. Above 431px the shell hugs its content and auto resolves
   to nothing, which is why the padding is here and not left to the gap. */
.ob-actions { margin-top: auto; padding-top: 2.5rem; }

/* The sheet's own 2rem foot left the button sitting 12px higher than the
   design. Measured, not guessed: the export puts the button at y716–784 of
   844, and this is what lands it there. */
.ob-page .auth-sheet { padding-bottom: 1.2rem; }

.ob-next {
    display: block;
    width: 100%;
    border: 0;
    border-radius: 18px;
    padding: 1.4rem 1rem;
    background: linear-gradient(180deg, var(--auth-teal-top), var(--auth-teal-dark));
    color: #fff;
    font-size: 1rem;
    font-weight: 700;
    text-align: center;
    text-decoration: none;
    cursor: pointer;
}
.ob-next:hover, .ob-next:focus-visible { color: #fff; filter: brightness(.96); }

.ob-skip {
    display: block;
    margin-top: 1.1rem;
    font-size: .9rem;
    color: var(--auth-muted);
    text-decoration: none;
}
.ob-skip:hover, .ob-skip:focus-visible { color: var(--auth-teal-dark); }

/* ---- The clinic's own icon set ----
   Inlined SVG (App\Support\Icon), so the fill is currentColor and each one
   takes the colour of the text beside it. Loaded from app.css because every
   shell uses them and every shell loads this file.

   Sized in REM, not em. The rules these replaced set `font-size` on an <i>
   in rem, but a nav label is .66rem — so an em-based icon inherited that and
   came out at 14px where the old glyph was 20px. Every one of them shrank,
   and nothing in the diff said so. rem keeps an icon the size it looks on
   the page rather than the size of whatever text it sits beside.

   A size here is also load-bearing rather than cosmetic: an inline <svg>
   with no width attribute and no rule falls back to its own intrinsic box,
   which is how a 24px icon rendered at 47. */
.ic { width: 1.5rem; height: 1.5rem; display: block; flex: 0 0 auto; }
.ic--sm { width: 1.15rem; height: 1.15rem; }
.ic--lg { width: 2rem; height: 2rem; }

/* ---- «ممکن است زمان نوبت تغییر کند» ----------------------------------
   The dialog shown between choosing a time and committing to it. Lives in
   app.css and not family.css because the public therapist page renders the
   same booking partial and never loads the family stylesheet.

   Fixed to the viewport, not to the 430px shell: on a phone the panel should
   be able to sit in the middle of the screen, and the shell is a column
   inside it. */
.booking-confirm {
    position: fixed; inset: 0; z-index: 1080;
    display: flex; align-items: center; justify-content: center;
    padding: 1.1rem;
}
.bc-backdrop { position: absolute; inset: 0; background: rgba(15, 23, 42, .55); }
.bc-panel {
    position: relative; z-index: 1;
    width: 100%; max-width: 380px;
    background: #fff; border-radius: 20px; padding: 1.4rem 1.2rem 1.1rem;
    box-shadow: 0 20px 48px rgba(15, 23, 42, .28);
    text-align: center;
}
.bc-icon {
    width: 52px; height: 52px; margin: 0 auto .8rem;
    display: grid; place-items: center;
    border-radius: 50%; background: var(--brand-soft); color: var(--brand-dark);
    font-size: 1.5rem;
}
.bc-panel h2 { font-size: 1.02rem; font-weight: 700; margin: 0 0 .6rem; color: var(--ink); }
.bc-panel p { font-size: .82rem; line-height: 1.9; color: var(--muted); margin: 0; }
.bc-pick {
    margin-top: .9rem !important; padding: .55rem .7rem;
    background: #f8fafc; border: 1px solid var(--line); border-radius: 12px;
    color: var(--ink) !important; font-weight: 600;
}
/* Stacked, and the commit first: at this width two buttons side by side give
   each about 150px, and «متوجه شدم، ثبت درخواست» wraps to two lines inside it. */
.bc-actions { display: grid; gap: .5rem; margin-top: 1.1rem; }
.bc-actions .btn { width: 100%; }

/* ==========================================================================
   One control height: 40px
   --------------------------------------------------------------------------
   Every input, select and button on every screen — the admin panel, the
   family and therapist phone shells, and the sign-in pages — is exactly 40px
   tall. Before this they ran from 31 (btn-sm) through 38 (Bootstrap's
   default) to 56 (sign-in), and a btn-sm stretched by a flex row reached 52.

   Buttons are inline-flex so the label sits in the middle of the fixed height
   whatever padding a shell gives them. Flex drops the space characters
   between an icon, the label and a badge, so `gap` puts that space back.
   nowrap because a label that wrapped would spill out of a fixed 40px box.

   Deliberately NOT here: slot tiles, calendar day cells, toggle switches,
   menu rows and text-link buttons («خروج», btn-link). They are <button>s in
   the markup but components on screen, sized by their own layout. Textareas
   keep their rows.
   ========================================================================== */
.btn:not(.btn-link):not(.btn-close),
.auth-btn,
.auth-resend-btn,
.sched-copy {
    height: 40px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: .3em;
    padding-top: 0;
    padding-bottom: 0;
    white-space: nowrap;
}
/* The sign-in button is a full-width block. */
.auth-btn { display: flex; }

.form-control:not(textarea),
.form-select,
.auth-input,
.auth-box {
    height: 40px;
    min-height: 40px;
    padding-top: 0;
    padding-bottom: 0;
}

/* The field's icon tile has to fit inside the now-40px field. */
.auth-tile { width: 32px; height: 32px; border-radius: 10px; font-size: .95rem; left: .25rem; }
.auth-field--ltr .auth-tile { right: .25rem; }
.auth-field--icon .auth-input { padding-left: 3rem; }
.auth-field--ltr .auth-input { padding-right: 3rem; }
/* A 1.6rem digit does not fit a 40px box. */
.auth-box { font-size: 1.15rem; border-radius: 12px; }

/* ==========================================================================
   Live tables — see public/js/live-table.js
   ========================================================================== */
/* While the next rows load, the old ones dim instead of vanishing, so the
   page never jumps to empty between keystrokes. */
[data-live-region] { transition: opacity .15s ease; }
[data-live-region].is-loading { opacity: .5; pointer-events: none; }

/* A sortable header reads as a header, not as a blue link. */
.th-sort {
    color: inherit;
    text-decoration: none;
    display: inline-flex;
    align-items: center;
    gap: .3rem;
    white-space: nowrap;
}
.th-sort:hover { color: var(--brand-dark); }
.th-sort i { font-size: .65rem; opacity: .4; }
.th-sort.is-active { color: var(--brand-dark); }
.th-sort.is-active i { opacity: 1; }
