/*
 * LaPatio — responsive behaviour for phones and tablets.
 *
 * Loaded after material-dashboard.css and before rtl-logical.css, for every
 * page, in both languages.
 *
 * WHAT THIS FILE IS
 * -----------------
 * The desktop composition is already good and is not touched. This file states
 * what has to be true on a narrow screen, in one place, so that thirty-odd
 * Blade templates do not each invent their own answer. Where a screen genuinely
 * needs its own treatment — the dental chart, the calendar — the rules for it
 * are grouped under a heading below rather than scattered into the template.
 *
 * THE ONE RULE EVERYTHING ELSE SERVES
 * -----------------------------------
 * The *page* never scrolls sideways. Wide content — a table, the tooth chart,
 * a calendar — scrolls inside its own box. A page that slides horizontally
 * makes every tap land somewhere unintended, and on a clinical system that is
 * a patient's record opened by accident.
 *
 * DIRECTION
 * ---------
 * Every offset here is logical (`inline-start`/`inline-end`, `margin-inline`,
 * `padding-inline`, `inset-inline`) so one rule serves Arabic and English. A
 * physical `left`/`right` appears only where the property has no logical
 * equivalent, and is then paired with a `[dir="rtl"]` counterpart directly
 * beneath it. Nothing here assumes a direction.
 *
 * COLOUR
 * ------
 * The identity is unchanged and is referenced through the tokens declared in
 * resources/css/app.css:
 *   --brand-primary #064058   --brand-secondary #006697
 *   --brand-olive   #818940   --brand-accent    #D55636
 * No colour is invented in this file; the few that appear are neutrals for
 * scroll affordances and shadows.
 */


/* ==========================================================================
   1. PAGE-LEVEL OVERFLOW
   ========================================================================== */

html,
body {
    /*
     * `clip` rather than `hidden`: `hidden` on <body> makes the element a
     * scroll container, which breaks `position: sticky` descendants and the
     * browser's scroll-into-view when an input is focused. `clip` refuses the
     * overflow without creating a scroll port.
     *
     * Only the inline axis. Clipping the block axis would make the page
     * unscrollable.
     */
    overflow-x: clip;
    max-width: 100%;
}

@media (max-width: 991.98px) {

    /*
     * A flex or grid *item* defaults to `min-width: auto`, which means it
     * refuses to shrink below its content's intrinsic width. That single
     * default is the cause of most horizontal page scroll in this app: a wide
     * table inside a flex column pushes the column wider than the viewport,
     * and the `overflow-x: auto` on the wrapper never engages because the
     * wrapper was granted the width it asked for.
     *
     * Declaring `min-width: 0` on the layout containers lets them shrink, so
     * the overflow lands on the wrapper that knows how to scroll it.
     */
    .main-content,
    .container-fluid,
    .row > [class*="col-"],
    .card,
    .card-body {
        min-width: 0;
    }

    .main-content {
        max-width: 100vw;
    }

    /* Bootstrap's negative row gutters extend past the viewport once the
       container's own padding is reduced on small screens. */
    .container-fluid {
        padding-inline: 12px;
        overflow-x: clip;
    }
}


/* ==========================================================================
   2. SAFE AREAS
   ========================================================================== */

@media (max-width: 991.98px) {

    /*
     * The layout declares viewport-fit=cover so the page paints under the
     * notch and the home indicator. That is only correct if the content is
     * then put back inside the safe area, which is what these do. On a device
     * with no insets every env() here resolves to 0 and nothing changes.
     */
    .main-content {
        padding-inline-start: env(safe-area-inset-left);
        padding-inline-end: env(safe-area-inset-right);
    }

    .main-content > .container-fluid:last-child {
        padding-bottom: calc(24px + env(safe-area-inset-bottom));
    }
}


/* ==========================================================================
   3. TABLES
   ========================================================================== */

/*
 * Two treatments, and the choice between them is deliberate.
 *
 * (a) CONTROLLED SCROLL — the default for every table. The table keeps its
 *     shape and scrolls inside its own box. Correct for dense financial and
 *     operational grids where the columns are compared against each other and
 *     breaking them apart would destroy the comparison.
 *
 * (b) CARDS — opt in with `.table-cards` on the table. Each row becomes a
 *     stacked card labelled from `data-label` attributes on the cells. Correct
 *     for directories that are read one record at a time. Applied to the
 *     patient directory, which is read that way.
 */

/* (a) Controlled scroll */
.table-responsive {
    /* Momentum scrolling on iOS, and a scrollbar that does not overlay the
       last row on desktop Safari. */
    -webkit-overflow-scrolling: touch;
    overflow-x: auto;
    max-width: 100%;
}

@media (max-width: 991.98px) {

    /*
     * A table with no wrapper still must not widen the page. This gives every
     * bare table the same scroll box the wrapped ones have, without needing to
     * edit thirty templates.
     */
    .card-body > table,
    .card > table {
        display: block;
        overflow-x: auto;
        max-width: 100%;
        -webkit-overflow-scrolling: touch;
    }

    /*
     * A faint edge that says "there is more this way". Direction-aware: the
     * fade belongs on the end the content runs off, which is the right in LTR
     * and the left in RTL.
     */
    .table-responsive {
        background:
            linear-gradient(to right, var(--surface-card, #fff) 30%, rgba(255, 255, 255, 0)),
            linear-gradient(to right, rgba(255, 255, 255, 0), var(--surface-card, #fff) 70%) 100% 0,
            radial-gradient(farthest-side at 0 50%, rgba(6, 64, 88, .12), rgba(0, 0, 0, 0)),
            radial-gradient(farthest-side at 100% 50%, rgba(6, 64, 88, .12), rgba(0, 0, 0, 0)) 100% 0;
        background-repeat: no-repeat;
        background-size: 40px 100%, 40px 100%, 14px 100%, 14px 100%;
        background-attachment: local, local, scroll, scroll;
    }

    /* Keep cells from collapsing to one word per line inside the scroller. */
    .table-responsive > .table > :not(caption) > * > * {
        white-space: nowrap;
    }
}

/* (b) Card mode */
@media (max-width: 767.98px) {

    .table-cards,
    .table-cards > tbody,
    .table-cards > tbody > tr,
    .table-cards > tbody > tr > td {
        display: block;
        width: 100%;
    }

    /*
     * The header is not hidden with `display: none` — a screen reader would
     * lose the column names along with it. Taken out of the flow instead, so
     * the accessible table structure survives while the visual one changes.
     */
    .table-cards > thead {
        position: absolute;
        width: 1px;
        height: 1px;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    .table-cards > tbody > tr {
        margin-bottom: 12px;
        padding: 12px 14px;
        border: 1px solid var(--border-subtle, #E3E8EB);
        border-radius: 14px;
        background: var(--surface-card, #fff);
        box-shadow: 0 1px 2px rgba(6, 64, 88, .06);
    }

    .table-cards > tbody > tr > td {
        display: grid;
        /* Label and value on one line, the value taking what is left. */
        grid-template-columns: minmax(6.5rem, 40%) 1fr;
        gap: 10px;
        align-items: baseline;
        padding: 6px 0;
        border: 0;
        text-align: start;
        white-space: normal;
    }

    .table-cards > tbody > tr > td + td {
        border-top: 1px solid rgba(227, 232, 235, .7);
    }

    .table-cards > tbody > tr > td::before {
        content: attr(data-label);
        color: var(--brand-primary, #064058);
        font-size: 11px;
        font-weight: 700;
        opacity: .75;
    }

    /* A cell with no label spans the full width — the name heading, and the
       action row at the foot of the card. */
    .table-cards > tbody > tr > td[data-label=""],
    .table-cards > tbody > tr > td:not([data-label]) {
        grid-template-columns: 1fr;
    }

    /*
     * An empty `attr(data-label)` still generates a box. In a grid cell it
     * collapses harmlessly, but `.cell-actions` is a flex row, where it becomes
     * a zero-width flex item that the `gap` still spaces — leaving a visible
     * indent before the first button. Removed where there is no label to show.
     */
    .table-cards > tbody > tr > td[data-label=""]::before,
    .table-cards > tbody > tr > td:not([data-label])::before {
        content: none;
    }

    /*
     * The record's identity leads the card. Without this the patient's name is
     * just the first of nine equal rows, and the card has no subject.
     */
    .table-cards > tbody > tr > td.cell-title {
        padding-top: 0;
        color: var(--brand-primary, #064058);
        font-size: 15px;
        font-weight: 700;
    }

    /*
     * Actions wrap instead of overlapping, and each one is big enough to hit.
     * This is the rule that stops the buttons at the end of a directory row
     * from stacking on top of each other.
     */
    .table-cards > tbody > tr > td.cell-actions {
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        margin-top: 4px;
        padding-top: 10px;
        border-top: 1px solid rgba(227, 232, 235, .9);
    }

    .table-cards > tbody > tr > td.cell-actions > * {
        flex: 1 1 auto;
        min-height: 40px;
        min-width: 44px;
    }
}


/* ==========================================================================
   4. TOUCH TARGETS, BUTTONS, FORMS
   ========================================================================== */

@media (max-width: 991.98px) {

    /*
     * ~44px is the size a finger can hit reliably. Applied as a minimum, not a
     * fixed size, so a button that is already larger keeps its proportions.
     */
    /*
     * Deliberately listed by class rather than as a bare `button` selector.
     *
     * A blanket `button { min-height: 40px }` reaches inside third-party
     * widgets — Selectize's remove/clear controls, FullCalendar's own chrome,
     * the modal close — and stretches chrome that is sized to its own icon.
     * Naming the application's own button classes leaves those alone, and the
     * few that do need a minimum get one explicitly below.
     */
    .btn,
    .nav-link,
    .page-link,
    .dropdown-item {
        min-height: 40px;
    }

    .btn-sm {
        min-height: 36px;
        padding-inline: 12px;
    }

    /*
     * An icon-only control has no text to give it width, so it collapses to
     * the glyph. Squared off explicitly.
     */
    .btn-icon-only,
    .btn.btn-link.p-0,
    .btn-close {
        min-width: 40px;
        min-height: 40px;
    }

    /*
     * 16px is not a style choice. iOS Safari zooms the page when a focused
     * input has a font size below 16px, and it does not zoom back out — the
     * user is left on a magnified, sideways-scrolled page. This is the fix for
     * "the keyboard destroys the layout".
     */
    .form-control,
    .form-select,
    input[type="text"],
    input[type="email"],
    input[type="tel"],
    input[type="number"],
    input[type="password"],
    input[type="date"],
    input[type="time"],
    input[type="search"],
    textarea,
    select,
    .selectize-input,
    .selectize-input input {
        font-size: 16px !important;
    }

    .form-control,
    .form-select,
    .selectize-input {
        min-height: 44px;
    }

    /*
     * Deliberately NOT touching `.col-md-*` / `.col-lg-*` here.
     *
     * Those already collapse on their own below their breakpoint — that is what
     * the breakpoint in the name means — so overriding them would only take
     * effect between 768px and 992px, where two columns on a tablet is right
     * and one would be a downgrade.
     *
     * The columns that genuinely need this are the breakpoint-less ones:
     * `.col-6` is half the row at *every* width, so on a 320px phone it is a
     * 160px field, which truncates the label and the value together. The
     * patient forms are built from these.
     */

    /*
     * A validation message belongs against its field. Bootstrap hides
     * `.invalid-feedback` until a sibling is `.is-invalid`, but this project
     * renders the message itself conditionally, so it has to be shown when it
     * is present at all.
     */
    .invalid-feedback {
        display: block;
        margin-top: 4px;
        font-size: 12px;
        text-align: start;
    }

    /* Button groups wrap rather than forcing the card wider. */
    .btn-group,
    .d-flex.gap-2,
    .card-header .d-flex {
        flex-wrap: wrap;
        gap: 8px;
    }
}

@media (max-width: 575.98px) {

    /*
     * The breakpoint-less columns, on phones only.
     *
     * `.col-6` holds half the row at every width, so the two-up field pairs in
     * the patient forms are 160px each at 320px — narrower than the labels
     * above them. Stacked below 576px, and left alone on tablets where two
     * columns still reads well.
     */
    .row > .col-6,
    .row > .col-4,
    .row > .col-3 {
        flex: 0 0 100%;
        max-width: 100%;
    }
}


/* ==========================================================================
   5. MODALS
   ========================================================================== */

/*
 * Two different narrow screens, and they do not want the same modal.
 *
 * A phone wants a sheet: edge to edge, using every pixel. A desktop window
 * that is merely *narrow* -- most often because the browser is zoomed, which
 * shrinks the CSS viewport into these same breakpoints -- still wants a
 * centred dialog. Width alone cannot tell the two apart, and treating a zoomed
 * desktop as a phone is what made the booking popup sprawl edge to edge across
 * an ordinary screen.
 *
 * `pointer: coarse` is the discriminator: a finger is coarse, a mouse stays
 * fine at any zoom level. So the behaviour that is right everywhere -- the body
 * scrolling internally, the footer staying reachable -- is applied on width
 * alone, and only the full-bleed sheet is gated on touch.
 */

@media (max-width: 767.98px) {

    .modal-dialog {
        /*
         * Still a dialog. min() keeps it comfortably inside a narrow window
         * without ever exceeding the width Bootstrap gives it on a roomy one,
         * so a zoomed desktop looks like a smaller version of the desktop
         * design rather than a different design.
         */
        max-width: min(500px, calc(100% - 32px));
        margin: 16px auto;

        /*
         * dvh, not vh: with a keyboard open a vh-sized dialog extends under it
         * and the footer -- where the save button is -- cannot be reached.
         */
        max-height: calc(100dvh - 32px);
    }

    .modal-content {
        max-height: calc(100dvh - 32px);
        /* Header and footer stay put; only the body moves. */
        display: flex;
        flex-direction: column;
        border-radius: 14px;
    }

    .modal-header,
    .modal-footer {
        flex: 0 0 auto;
        padding: 12px 16px;
    }

    /* This is what "the modal body scrolls internally" means. */
    .modal-body {
        flex: 1 1 auto;
        overflow-y: auto;
        overflow-x: hidden;
        -webkit-overflow-scrolling: touch;
        padding: 14px 16px;
    }

    .modal-footer {
        flex-wrap: wrap;
        gap: 8px;
        padding-bottom: calc(12px + env(safe-area-inset-bottom));
    }
}

/* The phone sheet. Touch only -- see the note above. */
@media (max-width: 767.98px) and (pointer: coarse) {

    .modal-dialog {
        max-width: calc(100% - 16px);
        margin: 8px;
    }

    /* Actions go full width and stack rather than being squeezed onto one line
       and clipped. Only worth the vertical space when aiming with a finger. */
    .modal-footer > .btn {
        flex: 1 1 100%;
        margin: 0;
    }
}

/* Edge to edge on a small phone, where even 8px of margin is wasted. */
@media (max-width: 480px) and (pointer: coarse) {

    .modal-dialog {
        margin: 0;
        max-width: 100%;
        max-height: 100dvh;
    }

    .modal-content {
        min-height: 100dvh;
        border-radius: 0;
    }
}


/* ==========================================================================
   6. SELECTIZE
   ========================================================================== */

/*
 * Selectize renders its dropdown into a positioned wrapper. Left alone it takes
 * the width of its content, which for a patient label like
 * "حيدر عواد — 07801234567" is wider than a phone.
 */
.selectize-control,
.selectize-dropdown {
    max-width: 100%;
}

/*
 * The dropdown is parented to <body> now (see the selectize wrapper in
 * layouts/base), which is what stops a rounded card's `overflow: hidden`
 * slicing the option list in half. The cost of leaving the card is that it also
 * leaves the card's stacking context, so it needs a z-index of its own or it
 * renders BEHIND anything layered above the page — most importantly the
 * appointment booking modal, whose pickers are the ones used most.
 *
 * Above Bootstrap's modal (1055) and SweetAlert (1060); below nothing this app
 * puts on top of a modal. Scoped to `body >` so a dropdown a screen has
 * deliberately kept inline keeps its own layering.
 */
body > .selectize-dropdown {
    z-index: 1090;
}

.selectize-dropdown {
    /* Never wider than the control it belongs to. */
    box-sizing: border-box;
}

.selectize-dropdown-content {
    max-height: 44vh;
    -webkit-overflow-scrolling: touch;
}

/* ==========================================================================
   SELECTIZE — THE CLEAR X, AND WHY IT SAT ON TOP OF THE NAME
   ==========================================================================

   Every selectize on every screen, fixed once here rather than per-screen.

   THE BUG
   -------
   The clear_button plugin positions its control with a PHYSICAL inset:

       .selectize-control.plugin-clear_button .clear        { right: calc(.75rem - 5px) }
       .selectize-control.plugin-clear_button.single .clear { right: calc(.75rem - 5px + 1.5rem) }

   In an RTL page `right` is where the line STARTS, so the x was pinned over the
   first characters of the value -- "د. بسمة محمد حمد" with the x sitting on
   "بسمة". It was never a stacking or z-index problem; the control was doing
   exactly what it was told, on the wrong side of a mirrored layout.

   Nothing reserved room for it either, so even on the correct side the text
   would have run underneath it.

   THE FIX
   -------
   Re-pin it with a LOGICAL inset so it follows the writing direction, and
   reserve padding on that side so a value can never reach it. The dropdown
   caret already occupies the inline end, so the x sits just inboard of it and
   the padding covers both.

   Scoped to `.plugin-clear_button`, so a multi-value picker's per-chip x --
   which is a different control, and legitimately belongs against its own chip
   -- is untouched.
   ========================================================================== */

.selectize-control.plugin-clear_button .clear,
.selectize-control.plugin-clear_button.single .clear {
    /*
     * Both selectors, and !important on the insets.
     *
     * The plugin ships a more specific rule for the single-value case --
     * `.selectize-control.plugin-clear_button.single .clear` (0,3,1) -- so a
     * plain override at (0,2,1) lost, and `right` kept its physical value while
     * the logical inset applied as well. An absolutely positioned box given
     * both `left` and `right` in an RTL containing block is over-constrained,
     * and RTL resolves that by ignoring `left` -- so the x stayed pinned to the
     * side the value starts on, which is the bug it was supposed to fix.
     *
     * Matching the plugin's own specificity and marking the insets important
     * settles it in one place instead of adding a third competing rule.
     */
    right: auto !important;
    left: auto !important;
    /* Inboard of the caret, which sits at the inline end. */
    inset-inline-end: 30px !important;

    top: 0;
    height: 100%;
    width: 22px;
    display: flex;
    align-items: center;
    justify-content: center;

    /*
     * The clear control ships at opacity .4 -- a grey x on a white field, which
     * is most of the way to invisible, and on a single select it is the only
     * way to unset a choice. Legible at rest, obvious on hover.
     */
    opacity: .55;
    color: var(--brand-primary, #064058);
    font-weight: 700;
    transition: opacity .15s ease, color .15s ease;
}

/* Room for the caret AND the x, so a long value is clipped by the field rather
   than sliding under either control. */
.selectize-control.plugin-clear_button .selectize-input {
    padding-inline-end: 56px !important;
}

/* The chosen value keeps to the room it has been given. */
.selectize-control.plugin-clear_button.single .selectize-input > .item {
    display: block;
    max-width: 100%;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
 * A single-value picker never shows the per-item x.
 *
 * `remove_button` draws its x INSIDE the selected chip, hard against the value
 * -- and in RTL, on top of it. On a control that holds one value it also does
 * the same job as the clear control at the field's edge, so the field carried
 * two x's for one action. The pickers that need it -- packages, services,
 * doctors on a service -- are multi-value and are not matched by `.single`.
 */
.selectize-control.single .selectize-input > .item > .remove {
    display: none !important;
}

.selectize-control.plugin-clear_button:hover .clear {
    opacity: .9;
}

.selectize-control.plugin-clear_button .clear:hover,
.selectize-control.plugin-clear_button .clear:focus-visible {
    opacity: 1;
    color: var(--brand-accent, #D55636);
}

@media (max-width: 991.98px) {

    .selectize-input {
        padding-block: 10px;
    }

    /* Options are tapped, so they are sized to be tapped. */
    .selectize-dropdown-content > .option,
    .selectize-dropdown .option {
        min-height: 44px;
        display: flex;
        align-items: center;
        padding-block: 10px;
        white-space: normal;
        line-height: 1.35;
    }

    /*
     * The remove/clear affordances sit at the inline end. In the shipped
     * Selectize CSS they are pinned with a physical `right`, so in Arabic they
     * landed on top of the text instead of at the end of the field.
     */
    .selectize-control.plugin-remove_button .item .remove {
        inset-inline-end: 0;
        inset-inline-start: auto;
        border-inline-start: 1px solid rgba(0, 0, 0, .06);
        border-inline-end: 0;
        min-width: 28px;
    }

    .selectize-control.plugin-clear_button .clear {
        inset-inline-end: 8px;
        inset-inline-start: auto;
        min-width: 28px;
        min-height: 28px;
        display: flex;
        align-items: center;
        justify-content: center;
    }
}

/* The dropdown arrow mirrors with the document. */
[dir="rtl"] .selectize-control.single .selectize-input:after {
    right: auto;
    left: 15px;
}


/* ==========================================================================
   7. FULLCALENDAR
   ========================================================================== */

/*
 * The calendar is the busiest screen in the app and the one most often opened
 * on a phone at the desk. Shrinking a month grid to 360px gives each day ~48px,
 * which fits a number and nothing else — so on a narrow screen the toolbar is
 * rebuilt rather than compressed, and the day/list views (which are legible at
 * that width) are put within one tap.
 */

.fc {
    max-width: 100%;
}

/* The calendar's own scroller, never the page's. */
.fc .fc-view-harness {
    max-width: 100%;
}

@media (max-width: 991.98px) {

    /*
     * The toolbar is one row of three groups on desktop. At 360px that is
     * eleven controls on one line. Reflowed into stacked, centred groups:
     * title first because it is what orients you, then the view switcher, then
     * navigation.
     */
    .fc .fc-toolbar.fc-header-toolbar {
        display: flex;
        flex-direction: column;
        gap: 10px;
        margin-bottom: 12px;
    }

    .fc .fc-toolbar-chunk {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        align-items: center;
        gap: 6px;
        width: 100%;
    }

    /* Title reads first, and at a size that is actually a title. */
    .fc .fc-toolbar-chunk:nth-child(2) {
        order: -1;
    }

    .fc .fc-toolbar-title {
        font-size: 17px;
        font-weight: 700;
        text-align: center;
    }

    /* Touch-sized navigation. The prev/next arrows were 28px squares. */
    .fc .fc-button {
        min-height: 42px;
        min-width: 42px;
        padding: 6px 12px;
        font-size: 13px;
        border-radius: 10px;
    }

    .fc .fc-button-group {
        flex-wrap: wrap;
        justify-content: center;
    }

    /*
     * No chevron override here, deliberately.
     *
     * FullCalendar already swaps the icon *class* per direction — verified in
     * the browser on this page: under `fc-direction-rtl` the prev button
     * carries `fc-icon-chevron-right` and next carries `fc-icon-chevron-left`,
     * which is correct. Re-flipping the glyph in CSS would double-flip it and
     * point "previous" forwards in Arabic. Left to the library.
     */

    /* Events stay readable rather than becoming coloured slivers. */
    .fc .fc-daygrid-event {
        font-size: 11px;
        line-height: 1.3;
        padding: 2px 4px;
        white-space: normal;
    }

    .fc .fc-daygrid-day-number,
    .fc .fc-col-header-cell-cushion {
        font-size: 12px;
        padding: 4px;
    }

    /* A day cell you can actually tap. */
    .fc .fc-daygrid-day-frame {
        min-height: 62px;
    }

    /* The list view is the most useful one at this width — give its rows room. */
    .fc .fc-list-event td {
        padding: 12px 10px;
        font-size: 13px;
    }

    .fc .fc-timegrid-slot {
        height: 2.4em;
    }
}

@media (max-width: 575.98px) {

    /*
     * Below this the month grid stops being informative — a cell shows the
     * date and a "+3 more" and nothing else. The grid still works and is still
     * reachable; this only makes it scroll inside its own box rather than
     * squeezing columns to illegibility.
     */
    .fc .fc-view-harness > .fc-daygrid,
    .fc .fc-view-harness > .fc-timegrid {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    .fc .fc-daygrid-body,
    .fc .fc-timegrid-body,
    .fc .fc-scrollgrid-sync-table,
    .fc .fc-col-header {
        min-width: 520px;
    }

    /* The list view is the exception: it is a column, so it fits natively and
       must not inherit the min-width above. */
    .fc .fc-list,
    .fc .fc-list-table {
        min-width: 0;
    }

    .fc .fc-toolbar-title {
        font-size: 15px;
    }

    .fc .fc-button {
        font-size: 12px;
        padding: 6px 9px;
    }
}


/* ==========================================================================
   8. DENTAL CHART
   ========================================================================== */

/*
 * The chart is the one place a horizontal scroll is correct: sixteen teeth per
 * arch, each large enough to tap accurately, is wider than a phone and cannot
 * honestly be made otherwise. Shrinking the teeth to fit would make selection
 * unreliable on the screen where a mis-tap is recorded as a clinical finding.
 *
 * So the scroll is kept, and confined: the arch scrolls, the page does not, and
 * everything around it — the detail panels, the finding controls — reflows
 * vertically instead of being dragged along.
 */

@media (max-width: 1023.98px) {

    /*
     * The scroller is a flex item (`flex-1`), so its default `min-width: auto`
     * let it be as wide as the sixteen teeth inside it. The wrapper was
     * therefore never narrower than its content and `overflow-x: auto` never
     * engaged — the whole page scrolled sideways instead of the arch. This is
     * the fix.
     */
    .dental-pro-map-scroll {
        min-width: 0;
        max-width: 100%;
        overflow-x: auto;
        overflow-y: hidden;
        -webkit-overflow-scrolling: touch;
        /* Snap so a drag settles on whole teeth rather than mid-tooth. */
        scroll-snap-type: x proximity;
        /* Room for the scrollbar so it does not sit on the lower arch. */
        padding-bottom: 6px;
    }

    /*
     * `margin: 0 auto` centres the arch, which on a narrow screen means it
     * opens scrolled to the middle of the mouth with the molars off both edges.
     * Start at the beginning of the arch instead — and "beginning" is
     * direction-aware, which `margin: 0 auto` cannot express.
     *
     * Matched on the arch's own class rather than on `> .flex`: the map used to
     * put the tooth rows directly inside the scroller, and now wraps each arch
     * in its own heading + row, so a structural selector had already stopped
     * matching what it was written for.
     */
    .dental-pro-map-scroll .dental-pro-teeth-row {
        margin-inline: 0;
        scroll-snap-align: start;
    }

    /* Each tooth is a snap point. */
    .dental-pro-map-scroll [data-tooth] {
        scroll-snap-align: center;
    }

    /*
     * The FDI number above each tooth is 9px, which is at the edge of legible
     * on a phone and is the only thing identifying what is being tapped.
     */
    .dental-pro-map-scroll [data-tooth] > span:first-child {
        font-size: 11px;
        font-weight: 700;
        color: var(--brand-primary, #064058);
    }

    /*
     * The teeth keep their 60×94 size deliberately — that is already a
     * comfortable touch target and shrinking it is what this section exists to
     * avoid. Only the selected state is strengthened, because on a small screen
     * a thin ring under a fingertip is not visible at the moment it matters.
     */
    .dental-pro-map-scroll [data-tooth] button:focus-visible,
    .dental-pro-map-scroll [data-tooth] button[aria-pressed="true"] {
        outline: 3px solid var(--brand-secondary, #006697);
        outline-offset: 2px;
    }

    /*
     * The surface/finding badges are absolutely positioned at the tooth's
     * inline end. In the shipped markup that is Tailwind's `end-0.5`, which is
     * already logical — this only enforces a minimum size so they do not become
     * microscopic dots.
     */
    .dental-pro-map-scroll [data-tooth] .rounded-full {
        min-width: 8px;
        min-height: 8px;
    }

    /*
     * The detail panels beside the chart stack under it. They are the readable
     * half of this screen — the findings, the treatment plan — and side by side
     * at 400px each column is too narrow for either.
     */
    .dental-detail-grid,
    .dental-panels {
        display: grid;
        grid-template-columns: 1fr;
        gap: 12px;
    }

    /* Any grid inside the chart form collapses to one column. */
    .dental-chart-screen .grid.grid-cols-2,
    .dental-chart-screen .grid.grid-cols-3,
    .dental-chart-screen .grid.grid-cols-4 {
        grid-template-columns: 1fr;
    }

    /* The chart's own tables scroll rather than widening the screen. */
    .dental-chart-screen table {
        display: block;
        overflow-x: auto;
        max-width: 100%;
        -webkit-overflow-scrolling: touch;
    }

    /* Finding and procedure controls are tapped, not clicked. */
    .dental-chart-screen .dental-selectize .selectize-input,
    .dental-chart-screen select,
    .dental-chart-screen .btn {
        min-height: 44px;
    }
}

@media (max-width: 640px) {

    /*
     * A sticky action bar, so "save" and "sign" do not require scrolling back
     * up past a full arch and two panels to reach.
     */
    .dental-sticky-actions {
        position: sticky;
        bottom: 0;
        z-index: 20;
        display: flex;
        flex-wrap: wrap;
        gap: 8px;
        margin-inline: -12px;
        padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
        border-top: 1px solid var(--border-subtle, #E3E8EB);
        background: var(--surface-card, #fff);
        box-shadow: 0 -2px 10px rgba(6, 64, 88, .07);
    }

    .dental-sticky-actions > .btn,
    .dental-sticky-actions > button {
        flex: 1 1 auto;
        min-height: 44px;
    }
}


/* ==========================================================================
   9. SIDEBAR / NAVIGATION
   ========================================================================== */

@media (max-width: 1199.98px) {

    /*
     * The off-canvas panel's *direction* is deliberately not touched here.
     *
     * components/navbars/sidebar.blade.php already handles it, correctly and
     * per-direction: `html[dir="rtl"] body:not(.g-sidenav-pinned)` translates
     * it off the right edge and `body.g-sidenav-pinned` brings it back to
     * translateX(0). Verified in the browser at 390px in Arabic — the open
     * panel sits fully inside the viewport. Adding an inset rule here would
     * fight a mechanism that works.
     *
     * The only thing worth stating is the width, so a 288px panel does not
     * take the whole of a 320px screen and leave nothing to tap to dismiss it.
     */
    .sidenav {
        max-width: min(288px, 88vw);
    }
}


/* ==========================================================================
   10. CARDS AND SPACING
   ========================================================================== */

@media (max-width: 767.98px) {

    /*
     * Desktop card padding is generous by design. At 360px it costs a quarter
     * of the line to whitespace on each side.
     */
    .card-body {
        padding: 14px;
    }

    .card-header {
        padding: 14px;
    }

    .card {
        margin-bottom: 14px;
        border-radius: 14px;
    }

    /* Headings scale rather than stepping, so 320 and 430 are both intended. */
    h1, .h1 { font-size: clamp(20px, 5.5vw, 28px); }
    h2, .h2 { font-size: clamp(18px, 5vw, 24px); }
    h3, .h3 { font-size: clamp(17px, 4.5vw, 21px); }
    h4, .h4 { font-size: clamp(15px, 4vw, 18px); }
    h5, .h5 { font-size: clamp(14px, 3.6vw, 16px); }

    /*
     * A long unbroken string — an email, a serial, a URL — is a single
     * unbreakable word to the layout engine and will widen its container past
     * the viewport on its own.
     */
    .card,
    .card-body,
    td,
    p {
        overflow-wrap: anywhere;
    }

    /* Pagination fits and is tappable. */
    .pagination {
        flex-wrap: wrap;
        gap: 4px;
        justify-content: center;
    }

    .pagination .page-link {
        min-width: 40px;
        min-height: 40px;
        display: flex;
        align-items: center;
        justify-content: center;
    }
}


/* ==========================================================================
   11. RTL CORRECTIONS FOR PHYSICALLY-COMPILED THIRD-PARTY CSS
   ========================================================================== */

/*
 * rtl-logical.css already remaps Bootstrap's compiled utilities. These are the
 * remaining components whose own stylesheets pin a physical side and therefore
 * land on the wrong edge in Arabic. Each is stated once, here, rather than
 * being patched inside whichever template noticed it first.
 */

[dir="rtl"] .modal-header .btn-close {
    /* Bootstrap's `.btn-close` is positioned with an auto margin on one side. */
    margin-inline-start: 0;
    margin-inline-end: auto;
}

[dir="rtl"] .dropdown-menu-end {
    --bs-position: start;
    right: auto;
    left: 0;
}

[dir="rtl"] .form-check {
    padding-inline-start: 1.5em;
    padding-inline-end: 0;
}

[dir="rtl"] .form-check .form-check-input {
    float: right;
    margin-inline-start: -1.5em;
    margin-inline-end: 0;
}

[dir="rtl"] .input-group > :not(:first-child) {
    /* The joined-corner rules are written with physical radii. */
    border-top-right-radius: 0;
    border-bottom-right-radius: 0;
    border-top-left-radius: var(--bs-border-radius);
    border-bottom-left-radius: var(--bs-border-radius);
}

/* Alerts and validation text read from the start of the line, either way. */
.alert,
.invalid-feedback,
.valid-feedback {
    text-align: start;
}


/* ==========================================================================
   12. PRINT
   ========================================================================== */

@media print {

    /* None of the above should follow a chart or an invoice onto paper. */
    .table-cards > thead {
        position: static;
        width: auto;
        height: auto;
        clip-path: none;
    }

    .table-cards,
    .table-cards > tbody,
    .table-cards > tbody > tr,
    .table-cards > tbody > tr > td {
        display: revert;
    }

    .table-cards > tbody > tr > td::before {
        content: none;
    }

    .dental-sticky-actions {
        display: none;
    }
}


/* ==========================================================================
   13. ESCAPED SCROLLBAR RAILS
   ========================================================================== */

/* PerfectScrollbar rails: no longer created (see layouts/base.blade.php). */
