/* BRM CUSTOM — mobile layer for the Ramumo backend (Easy!Appointments).
 *
 * Linked at the end of backend_header.php, after that file's inline <style>,
 * so it cascades last over EA core CSS and our own overrides without needing
 * !important. A few rules still need ID-level specificity to beat EA's own
 * two-ID selectors; those are called out where they appear.
 *
 * Audience: therapists working from a phone between sessions. The design
 * rules that follow from that:
 *   1. The primary action is always reachable with a thumb (pinned footers).
 *   2. One screen does one job — list and detail are separate views, not a
 *      single 3000px scroll.
 *   3. The page itself never scrolls sideways. Only deliberate scrollers do
 *      (week calendar, rooms grid), and they keep a sticky context column.
 *   4. Readable density beats decorative spacing. Wide letter-spaced display
 *      type is dropped below 768px where it costs whole lines.
 *
 * Breakpoints match Bootstrap 5. EA's own layout only starts behaving at
 * min-width 768, so nearly everything below that needs work.
 *
 * Contents
 *   1  Base + typography
 *   2  Header / navigation
 *   3  Page shell + page headers
 *   4  Master–detail flow (customers, services, providers, …)
 *   5  Calendar
 *   6  Rooms plan
 *   7  Schedule
 *   8  Journal
 *   9  Settings
 *   10 Modals (all dialogs)
 *   11 Recurring series block
 *   12 Overlays: select2, flatpickr, dropdowns, tooltips, notifications
 *   13 Feedback dock
 */

/* ============================================================
   1. Base + typography
   ============================================================ */

@media (max-width: 767.98px) {
    /* Several EA grids are wider than the viewport. Without this the document
       scrolls sideways instead of just the offending element. Sections 5 and 6
       opt their own scrollers back in.
       Deliberately on <html> only. The layout puts Bootstrap's `h-100` on
       <body>, so adding overflow-x there gave body a fixed 100% height AND —
       because a non-visible value on one axis forces the other to `auto` —
       made it its own scroll container. The result: main grew to 2099px,
       body.scrollHeight to 2135, but html.scrollHeight stayed at the viewport
       height, so the window itself never scrolled. Touch dragging still moved
       the body, which is why it looked fine, but window.scrollTo() became a
       no-op and silently broke the master-detail scroll reset. */
    html {
        overflow-x: hidden;
    }

    /* iOS Safari zooms the viewport when a focused control is under 16px. The
       backend uses 14px controls throughout, so every tap into a field shifted
       the layout. */
    .backend-page input:not([type='checkbox']):not([type='radio']),
    .backend-page select,
    .backend-page textarea,
    .modal input:not([type='checkbox']):not([type='radio']),
    .modal select,
    .modal textarea {
        font-size: 16px;
    }

    /* Touch targets. Kept off .btn-sm and icon-only buttons so dense toolbars
       don't balloon. */
    .backend-page .btn,
    .modal .btn {
        min-height: 42px;
    }

    .backend-page .btn-sm,
    .modal .btn-sm {
        min-height: 34px;
    }

    /* Checkboxes are the main hit target in the schedule and series lists. */
    .backend-page input[type='checkbox'],
    .modal input[type='checkbox'] {
        width: 20px;
        height: 20px;
    }

    /* Text inputs and selects were landing at 35px — the calendar's provider
       filter is the clearest case, and it is the first control on the busiest
       screen. Match the 42px used for buttons. */
    .backend-page .form-control,
    .backend-page .form-select,
    .modal .form-control,
    .modal .form-select {
        min-height: 42px;
    }

    /* …but not the small variants used inside dense list rows, and not
       textareas, whose height is meaningful. */
    .backend-page .form-control-sm,
    .backend-page .form-select-sm,
    .modal .form-control-sm,
    .modal .form-select-sm {
        min-height: 34px;
    }

    /* The theme sets .btn-sm to 10px type. That is below the readable floor for
       a control label on a phone — "Pridėti pertrauką" in the working-plan
       exception dialog is a real action, not a hint. */
    .backend-page .btn-sm,
    .modal .btn-sm {
        font-size: 12px;
    }

    /* Standalone actions are marked .btn-sm even when they are not in a dense
       row — "Pridėti pertrauką", "Remove company logo", "Reset company colour".
       Lift the floor for page-level small buttons, then put it back down for
       the ones that really do sit inside a packed table row or chip strip,
       where 38px would wreck the layout. */
    .backend-page .btn-sm {
        min-height: 38px;
    }

    .backend-page td .btn-sm,
    .backend-page th .btn-sm,
    .backend-page .jr-quick .btn-sm {
        min-height: 32px;
    }

    .modal .working-plan-exceptions-add-break,
    .backend-page .add-break,
    .backend-page .add-working-plan-exception {
        min-height: 40px;
    }

    /* The service/category colour picker renders 32px swatches in a wrapping
       grid. They are the only way to set a colour, and there is room to grow
       them. */
    .backend-page .color-selection-option,
    .modal .color-selection-option {
        width: 38px;
        height: 38px;
    }

    /* Switches and checkboxes are 20px; their label is the practical target,
       so give it height. (The backend-page case is handled in section 7; this
       covers the dialogs.)
       Bootstrap floats .form-check-input and indents the label, which combined
       with the label's vertical padding left the box sitting above the text
       baseline. Laying the pair out as a centred flex row aligns them properly
       and keeps the 38px target. */
    .modal .form-check {
        display: flex;
        align-items: center;
        gap: 8px;
        padding-left: 0;
        margin-bottom: 0;
        min-height: 38px;
    }

    .modal .form-check .form-check-input {
        float: none;
        margin: 0;
        flex: 0 0 auto;
    }

    .modal .form-check-label {
        display: flex;
        align-items: center;
        padding-top: 0;
        padding-bottom: 0;
        margin: 0;
        min-height: 38px;
        line-height: 1.25;
    }

    .modal .form-check-input {
        width: 20px;
        height: 20px;
    }

    .modal .form-switch .form-check-input {
        width: 36px;
    }

    .backend-page textarea.form-control,
    .modal textarea.form-control {
        min-height: 70px;
    }

    /* The uppercase + 0.2em display headings cost two or three lines each at
       375px ("K L I E N T A I"). Keep the character, drop the cost. */
    .backend-page h1,
    .backend-page h2,
    .backend-page h3,
    .backend-page h4 {
        letter-spacing: 0.03em;
        word-break: break-word;
        line-height: 1.25;
    }
}

/* ============================================================
   1b. Login / recovery (account_layout)
   ============================================================
   These render inside #login-frame.frame-container — no .backend-page and no
   .modal — so every rule in section 1 misses them. They are the first screens
   a therapist meets on a phone, so they get the same control sizing, touch
   targets and contrast floor as the rest of the app. */

@media (max-width: 767.98px), (max-height: 500px) {
    .frame-container {
        max-width: 100%;
        padding: 20px 16px calc(20px + env(safe-area-inset-bottom, 0px));
        margin: 0 auto;
    }

    .frame-container input:not([type='checkbox']):not([type='radio']),
    .frame-container select,
    .frame-container .form-control {
        font-size: 16px;
        min-height: 44px;
    }

    .frame-container .btn {
        min-height: 46px;
    }

    /* The sign-in button is the one thing on the screen; give it the width. */
    .frame-container #login,
    .frame-container button[type='submit'] {
        width: 100%;
        border-radius: 10px;
    }

    /* "Forgot your password?" and the submit button share a flex row that gets
       tight at 375px once the button is full width. */
    .frame-container .d-flex.justify-content-between {
        flex-direction: column;
        align-items: stretch;
        gap: 14px;
    }

    .frame-container .forgot-password {
        display: inline-block;
        padding: 10px 0;
        text-align: center;
        color: #2f6c5b;
    }

    .frame-container .form-label {
        margin-bottom: 4px;
    }

    /* The layout's own spacing (mb-5 between fields) is desktop-scaled. */
    .frame-container .mb-5 {
        margin-bottom: 1.25rem !important;
    }

    .frame-container .mt-5 {
        margin-top: 1.5rem !important;
    }
}

/* ============================================================
   2. Header / navigation
   ============================================================ */

@media (max-width: 991.98px) {
    /* The collapsed menu is the only way to move between sections on a phone,
       so give the items real height and separators instead of a cramped list. */
    #header-menu .navbar-nav .nav-link {
        padding: 12px 4px;
        font-size: 15px;
    }

    #header-menu .navbar-nav > .nav-item + .nav-item {
        border-top: 1px solid rgba(255, 255, 255, 0.12);
    }

    /* Dropdown sections (Services / Users / account) render inline in the
       collapsed menu; indent them so the hierarchy survives.
       Making the panel transparent lets the dark navbar show through, but
       .dropdown-item keeps Bootstrap's near-black #343a40 — which on that
       background is 1.29:1, i.e. invisible. Settings / Account / Log Out were
       unreadable. The items must be recoloured with the panel. */
    #header-menu .dropdown-menu {
        border: 0;
        background: transparent;
        padding-left: 18px;
    }

    #header-menu .dropdown-item {
        padding: 10px 4px;
        color: #fff;
        background: transparent;
    }

    #header-menu .dropdown-item:hover,
    #header-menu .dropdown-item:focus,
    #header-menu .dropdown-item:active,
    #header-menu .dropdown-item.active {
        color: #fff;
        background: rgba(255, 255, 255, 0.12);
    }

    #header-menu .dropdown-divider {
        border-top-color: rgba(255, 255, 255, 0.22);
    }

    /* Menu can outgrow the screen once every section is visible. */
    #header-menu {
        max-height: 78vh;
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
    }
}

/* ============================================================
   3. Page shell + page headers
   ============================================================ */

@media (max-width: 767.98px) {
    .backend-page {
        padding-left: 12px !important;
        padding-right: 12px !important;
    }

    /* Page title + primary action share one row and collide once the title
       wraps ("MANO DARBO GRAFIKAS" ran under the save button). schedule.php,
       account.php and every settings page build that row from the same utility
       combo, so target it directly and let it wrap instead of forcing a column
       — a short title keeps its action alongside.
       (An earlier version of this rule targeted `#schedule-page .rp-topbar`
       and an invented `.brm-page-head`; neither exists. `rp-` markup is
       rooms-only.) */
    .backend-page .d-flex.justify-content-between.align-items-center.border-bottom {
        flex-wrap: wrap;
        gap: 8px;
    }

    #rooms-page .rp-topbar {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: 10px;
    }

    #rooms-page .rp-topbar-left,
    #rooms-page .rp-topbar-right {
        width: 100%;
    }

    #rooms-page .rp-title {
        font-size: 1.15rem;
        letter-spacing: 0.04em;
    }
}

/* ============================================================
   4. Master–detail flow
   ============================================================
   Shared by customers, services, service categories, providers, secretaries,
   admins, webhooks and blocked periods — every one of them is
   .filter-records + .record-details inside .backend-page.

   Stacked, these become one very long page: you scroll past the whole list to
   reach the form, and tapping a row silently changes a pane that is off
   screen. brm_mobile.js turns them into two views and sets .brm-mv-detail on
   the page container; this styles both states. */

/* Both controls are injected into the DOM on every viewport, so their default
   hidden state must live OUTSIDE the media query — scoping `display: none` to
   max-width:768 left them falling back to a button's default `inline-block`
   and showing up on desktop. */
.brm-mv-back,
.brm-mv-add {
    display: none;
}

/* Injected controls inherit no focus ring from EA's stylesheet. Keyboard and
   switch-control users need one; :focus-visible keeps it off pointer taps. */
.brm-mv-back:focus-visible,
.brm-mv-add:focus-visible,
.brm-sticky-save .btn:focus-visible {
    outline: 2px solid #2f4f4f;
    outline-offset: 2px;
}

@media (max-width: 767.98px) {
    .backend-page .filter-records,
    .backend-page .record-details {
        width: 100%;
        max-width: 100%;
    }

    /* Two-view mode: show one pane at a time. */
    .brm-mobile-views .filter-records,
    .brm-mobile-views .record-details {
        transition: none;
    }

    .brm-mobile-views:not(.brm-mv-detail) .record-details {
        display: none;
    }

    .brm-mobile-views.brm-mv-detail .filter-records {
        display: none;
    }

    /* Back control, injected by brm_mobile.js. Tokens match the public booking
       UI in registracija-v2.php (--b-primary #2F4F4F, --b-bg-body #F6F8F7,
       --b-border rgba(47,79,79,.1), --b-radius-btn 10px) so the backend reads
       as the same product. */
    .brm-mv-back {
        display: none;
        align-items: center;
        gap: 8px;
        width: 100%;
        margin-bottom: 10px;
        padding: 10px 12px;
        border: 1px solid rgba(47, 79, 79, 0.1);
        border-radius: 10px;
        background: #f6f8f7;
        color: #2f4f4f;
        font-size: 15px;
        font-weight: 600;
        text-align: left;
    }

    .brm-mobile-views.brm-mv-detail .brm-mv-back {
        display: flex;
    }

    /* The real create button lives inside .record-details, which is hidden
       while the list shows — without this proxy there is no way to add a
       record on a phone at all. */
    .brm-mv-add {
        display: none;
        width: 100%;
        margin-bottom: 10px;
    }

    .brm-mobile-views:not(.brm-mv-detail) .brm-mv-add {
        display: block;
    }

    /* Rows are the primary navigation on these screens — make them feel like
       tappable list items rather than text. */
    .backend-page .filter-records .entry {
        padding: 10px;
        border-radius: 8px;
        border-bottom: 1px solid rgba(47, 79, 79, 0.1);
    }

    .backend-page .filter-records .entry:active,
    .backend-page .filter-records .entry.selected {
        background: #e8f0ee;
    }

    /* EA appends an <hr> after every record, which now doubles up with the
       border-bottom above — two rules 11px apart. Dropping the <hr> also
       reclaims 11px per row (1px + 5px margins top and bottom), which on a
       long client list is most of a screen. */
    .backend-page .filter-records .results hr {
        display: none;
    }

    /* A chevron marks these as "leads somewhere", which is exactly what they
       now do on a phone. */
    .brm-mobile-views .filter-records .entry {
        position: relative;
        padding-right: 26px;
    }

    .brm-mobile-views .filter-records .entry::after {
        content: '';
        position: absolute;
        top: 50%;
        right: 10px;
        width: 7px;
        height: 7px;
        margin-top: -4px;
        border-right: 2px solid #637070;
        border-bottom: 2px solid #637070;
        transform: rotate(-45deg);
        opacity: 0.55;
    }

    .backend-page .filter-records .entry strong,
    .backend-page .filter-records .entry .text-muted {
        overflow-wrap: anywhere;
    }

    /* Long emails and notes were forcing horizontal scroll. */
    .backend-page .record-details,
    .backend-page .filter-records {
        overflow-wrap: anywhere;
    }

    /* Empty read-only fields, collapsed by brm_mobile.js. They reappear the
       moment the pane switches to edit mode. */
    .brm-mobile-views .record-details .mb-3.brm-empty {
        display: none;
    }

    /* Links inside a detail pane are standalone actions, not prose — a
       customer's appointment history entries (19px) and the "Booking Link" on
       services and providers (16px). Give them a real vertical target. */
    .backend-page .appointment-row a,
    .backend-page .record-details a:not(.btn) {
        display: inline-flex;
        align-items: center;
        min-height: 38px;
        padding-top: 6px;
        padding-bottom: 6px;
    }

    .backend-page .appointment-row {
        padding: 4px 0;
    }

    /* EA's detail forms use col-md-6 pairs that stack; the default spacing
       leaves a full empty line under every label. */
    .backend-page .record-details .form-label,
    .backend-page .record-details label {
        margin-bottom: 4px;
    }

    .backend-page .record-details .form-control,
    .backend-page .record-details .form-select {
        margin-bottom: 12px;
    }

    /* Add / edit / delete is the toolbar on every one of these pages. As a
       btn-group at 375px the labels truncate; let it wrap into full buttons. */
    .backend-page .record-details .btn-toolbar {
        gap: 8px;
    }

    .backend-page #add-edit-delete-group,
    .backend-page #save-cancel-group {
        display: flex;
        width: 100%;
        gap: 8px;
    }

    .backend-page #add-edit-delete-group > .btn,
    .backend-page #save-cancel-group > .btn {
        flex: 1 1 0;
        /* btn-group rounds off inner corners; these are separate buttons now. */
        border-radius: 6px !important;
    }
}

/* ============================================================
   5. Calendar
   ============================================================ */

@media (max-width: 767.98px) {
    /* EA sets `#calendar-actions .btn { width: 100% }` below 768px, so add /
       sync / table-view each claim a full row — roughly 350px of screen spent
       before any calendar shows. */
    #calendar-page #calendar-toolbar {
        padding: 10px 0;
        margin-bottom: 10px;
    }

    #calendar-page #calendar-filter {
        margin-bottom: 10px;
    }

    #calendar-page #calendar-actions {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 8px;
    }

    #calendar-page #calendar-actions .btn,
    #calendar-page #calendar-actions > .btn-group,
    #calendar-page #calendar-actions > .dropdown {
        width: auto;
        margin-bottom: 0;
        flex: 0 0 auto;
    }

    #calendar-page #calendar-actions .btn {
        min-width: 44px;
    }

    #calendar-page #calendar {
        font-size: 13px;
    }

    /* Header: date title and the view switcher each on their own line, both
       centred, instead of a three-way split that wraps unpredictably. */
    #calendar-page .fc-toolbar.fc-header-toolbar {
        display: flex;
        flex-wrap: wrap;
        justify-content: center;
        gap: 8px;
        margin-bottom: 0.75rem;
    }

    /* FullCalendar lays the toolbar out as three chunks; at 375px the title
       gets squeezed between them. Give it its own full-width line above the
       controls — the standard mobile calendar arrangement. */
    #calendar-page .fc-toolbar-title {
        font-size: 1.05rem;
        letter-spacing: 0.05em;
        flex: 1 0 100%;
        order: -1;
        text-align: center;
    }

    #calendar-page .fc-toolbar.fc-header-toolbar > .fc-toolbar-chunk {
        display: flex;
        justify-content: center;
        gap: 6px;
    }

    #calendar-page .fc-button {
        min-height: 40px;
    }

    /* Month view squeezes 7 columns into 375px — cells end up ~49px wide, so
       every event was truncated to "Val…". Titles wrap onto a second line, and
       the chip is kept as tight as it can be while staying readable: at 28px
       tall only two fitted a cell, at ~21px a third appears without the day
       growing. Type is deliberately small here; these are glanceable chips and
       tapping one opens the full record. */
    #calendar-page .fc-daygrid-event {
        white-space: normal;
        line-height: 1.1;
        font-size: 9px;
        /* 1px all round: the vertical padding stops the time and name sitting
           hard against the chip edge. Applied to every chip, so remote and
           normal stay the same height. */
        padding: 1px;
        margin: 1px 0;
        border-width: 0;
    }

    /* 4px of rounding on a 43x20 chip eats visibly into the corners at this
       size; 2px keeps the softened edge without stealing text room. */
    #calendar-page .fc-event,
    #calendar-page .fc-daygrid-event,
    #calendar-page .fc-timegrid-event,
    #calendar-page .fc-daygrid-event-harness > .fc-daygrid-event {
        border-radius: 2px;
    }

    #calendar-page .fc-daygrid-day-events {
        margin-top: 0;
        margin-bottom: 0;
    }

    #calendar-page .fc-daygrid-event-harness + .fc-daygrid-event-harness {
        margin-top: 1px;
    }

    /* --- Squeeze every last pixel out of a month cell ------------------
       At 320px a day column is ~40px, and the chip was only getting 31px of
       that: 4px to its own side margins, 4px to padding, 2px to the title's
       padding. Reclaiming all of it plus the page gutter takes usable text
       width from 31px to ~40px — about a third more characters. */
    #calendar-page .fc-daygrid-event-harness {
        margin-left: 0 !important;
        margin-right: 0 !important;
    }

    #calendar-page .fc-daygrid-day-number {
        padding: 1px 2px;
    }

    /* The calendar is the one page that should run edge to edge. Bootstrap's
       .row carries a negative margin of half the gutter; once the page padding
       drops to 4px that negative margin pokes 2px past the viewport, so the
       gutter has to go to zero with it. */
    #calendar-page.backend-page {
        padding-left: 4px !important;
        padding-right: 4px !important;
    }

    #calendar-page .row {
        --bs-gutter-x: 0;
    }

    #calendar-page #calendar {
        margin-bottom: 8px;
    }

    /* The dashed "remote" marker was a real border, so it added its width to
       the box on all four sides: 4px of inner width, and 2px of extra height
       that made remote chips visibly taller than the rest of the grid (title
       line boxes measured identical at 10px — it was purely the border).
       An outline draws the same dashed ring but is outside layout entirely, so
       remote and normal chips now occupy exactly the same space.
       `outline-offset: -1px` pulls it inside the box so it sits where the
       border did rather than bleeding into the neighbouring cell. */
    #calendar-page .brm-remote {
        border-width: 0 !important;
        outline: 1px dashed rgba(255, 255, 255, 0.8);
        outline-offset: -1px;
    }

    /* Both glyphs down from 1em, and the gaps around them tightened: the
       series marker reserved 1.35em of right padding that the client name
       could not use. */
    #calendar-page .brm-remote .fc-event-title::before {
        width: 0.8em;
        height: 0.8em;
        margin-right: 2px;
        vertical-align: -1px;
    }

    #calendar-page .brm-in-series .fc-event-title {
        padding-right: 0.95em;
    }

    #calendar-page .brm-in-series .fc-event-title::after {
        width: 0.8em;
        height: 0.8em;
        right: 0;
    }

    /* Each day cell is ~46px wide, so even "15:00" was being clipped to
       "15:0". Drop the time's own padding/weight and let it use the full cell
       rather than sharing a nowrap line with the title. */
    #calendar-page .fc-daygrid-event .fc-event-time {
        font-size: 9.5px;
        font-weight: 700;
        padding: 0;
        overflow: visible;
        flex: 0 0 auto;
    }

    /* FullCalendar lays time and title side by side on one nowrap line. In a
       46px cell the time consumes it all and the title was left breaking one
       character per line down the side. Stack them instead: time first, title
       on its own full-width line under it. */
    #calendar-page .fc-daygrid-event .fc-event-main-frame {
        display: flex;
        flex-direction: column;
        min-width: 0;
    }

    /* A ~40px cell can't fit "Domas" and a wrap turns it into "Dom / as", so
       the name is clipped on one line — but with `clip`, not `ellipsis`. The
       "…" was consuming roughly three characters' worth of a forty-pixel chip
       to tell you something the cut-off edge already says. Letting the text
       run to the edge shows more of the actual name. */
    #calendar-page .fc-daygrid-event .fc-event-title-container,
    #calendar-page .fc-daygrid-event .fc-event-title {
        min-width: 0;
        padding: 0;
        white-space: nowrap;
        overflow: hidden;
        text-overflow: clip;
        font-size: 9px;
        line-height: 1.1;
    }

    /* The day number sits above the chips and was taking more height than it
       needed to. */
    #calendar-page .fc-daygrid-day-top {
        margin-bottom: 0;
    }

    #calendar-page .fc-daygrid-event-harness {
        margin-right: 0 !important;
    }

    #calendar-page .fc-daygrid-day-number {
        font-size: 12px;
        padding: 2px 4px;
    }

    #calendar-page .fc-daygrid-day-frame {
        min-height: 64px;
    }

    /* Week view can't be made readable at 375px by shrinking type — seven
       columns plus a gutter needs real width. Give it one and scroll. */
    /* Week view can't be made readable at 375px by shrinking type — seven
       columns plus a gutter needs real width. 580px keeps roughly four days
       plus the hour gutter on screen at once (see the note below on why the
       gutter can't be pinned), so a therapist scanning the week pans once
       rather than losing their place. */
    #calendar-page .fc-timeGridWeek-view .fc-view-harness,
    #calendar-page .fc-timeGridWeek-view > table {
        min-width: 580px;
    }

    #calendar-page .fc-view-harness {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    /* Narrower time gutter buys ~40px of column width in day view. */
    #calendar-page .fc-timegrid-axis,
    #calendar-page .fc-timegrid-slot-label {
        font-size: 11px;
    }

    /* The hour column scrolls away with the grid, which is why week view gets
       a deliberately modest min-width above: at 580px roughly four days plus
       the gutter are visible at once, so you rarely pan far enough to lose the
       times.
       A sticky gutter is not achievable here. `position: sticky` does apply to
       the cells, but a sticky element resolves against its nearest scrollport,
       and FullCalendar wraps the grid in .fc-scroller with `overflow-x:
       hidden` — that counts as a scrollport and never scrolls horizontally,
       while the element that does scroll (.fc-view-harness) sits outside it.
       Forcing the scroller's overflow to visible breaks FullCalendar's own
       height management, so day view stays the recommended phone view and
       week view stays a scan. */

    /* Events are the tap target for opening an appointment. */
    #calendar-page .fc-timegrid-event {
        min-height: 26px;
    }

    /* The column header is a link that jumps to that day — a real navigation
       target, but only 25px tall. */
    #calendar-page .fc-col-header-cell-cushion {
        display: inline-block;
        padding-top: 9px;
        padding-bottom: 9px;
    }

    /* Table view (?view=table) is a wide multi-provider grid. */
    #calendar-page #calendar-table,
    #calendar-page .calendar-view {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }
}

/* ============================================================
   6. Rooms plan
   ============================================================
   .rp-table is `table-layout: fixed; width: 100%`, so at 375px each of the
   seven day columns lands at ~44px and provider names break one character per
   line ("anas tasij a kami nski ene"). Give the grid a usable width and let
   the room card scroll horizontally, with the hour gutter pinned so you never
   lose the time while panning. */

@media (max-width: 767.98px) {
    /* max-width is the part that actually binds. As a flex item with
       `flex: 1 1 100%` and `min-width: 0` this should already resolve to the
       container's 351px, but the 620px min-width on the table inside still
       stretched the box, so the scroller never engaged. Capping the width
       forces the overflow to happen inside the box instead. */
    #rooms-page .rp-room {
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        flex: 1 1 100%;
        max-width: 100%;
        min-width: 0;
    }

    #rooms-page .rp-table {
        min-width: 620px;
    }

    /* The room name lives inside the scroller, so a centred title drifts off
       to the right over the 620px grid. Pin it to the left edge. */
    #rooms-page .rp-roomname,
    #rooms-page .rp-roomname--static {
        position: sticky;
        left: 0;
        width: -moz-fit-content;
        width: fit-content;
        text-align: left;
        padding-left: 2px;
        /* It is a button (renames the room), so it needs a real target. */
        min-height: 38px;
    }

    /* Booking blocks are positioned and were painting over the pinned hour
       column as they scrolled past it, so raise the gutter above them and keep
       its background fully opaque. */
    #rooms-page .rp-table th.rp-th-time,
    #rooms-page .rp-table .rp-time {
        position: sticky;
        left: 0;
        z-index: 6;
        background: #fff;
    }

    #rooms-page .rp-cell {
        font-size: 11px;
        line-height: 1.15;
        overflow-wrap: normal;
        word-break: normal;
        hyphens: none;
    }

    #rooms-page .rp-rooms {
        gap: 18px;
    }

    /* Legend wraps rather than overflowing. */
    #rooms-page .rp-legend {
        display: flex;
        flex-wrap: wrap;
        gap: 6px 12px;
    }
}

/* ============================================================
   7. Schedule
   ============================================================ */

@media (max-width: 767.98px) {
    /* Day / start / end is only three columns, but at 320px they were badly
       balanced: the two time fields took 97px and 84px (uneven, for identical
       "13:30" content) leaving 114px for the day. That is enough for English
       "Wednesday" but not for Lithuanian — "Ketvirtadienis" alone measures 99px
       before the 20px checkbox beside it, so a therapist's rows would wrap.
       Pin the time columns to an equal, sufficient 74px each and give every
       pixel left over to the day name. */
    #schedule-page .working-plan {
        width: 100%;
        table-layout: fixed;
    }

    #schedule-page .working-plan td,
    #schedule-page .working-plan th {
        padding: 5px 3px;
    }

    #schedule-page .working-plan th:nth-child(2),
    #schedule-page .working-plan th:nth-child(3),
    #schedule-page .working-plan td:nth-child(2),
    #schedule-page .working-plan td:nth-child(3) {
        width: 74px;
    }

    #schedule-page .working-plan input[type='text'] {
        min-width: 0;
        width: 100%;
        padding-left: 4px;
        padding-right: 4px;
        font-size: 15px;
        text-align: center;
    }

    /* The day cell is checkbox + label on one line; keep them from wrapping
       apart and let the label use the space the time columns gave back. */
    #schedule-page .working-plan td:first-child {
        white-space: nowrap;
    }

    #schedule-page .working-plan label {
        font-size: 13.5px;
    }

    /* The day checkbox is 20px and its label ("Pirmadienis") only 21px tall.
       The label is correctly associated, so it already toggles the box — it
       just needs enough height to be a comfortable target. Padding the label
       rather than the box keeps the tick aligned with the times beside it. */
    #schedule-page .working-plan label,
    .backend-page .form-check-label {
        display: inline-block;
        padding-top: 9px;
        padding-bottom: 9px;
        line-height: 20px;
    }

    /* Breaks, date exceptions and remote-only windows all have four columns.
       A horizontal scroller technically contained them, but at 320px the
       action column was off screen and the remote day/time controls collapsed
       to a few characters. Render each row as a labelled card instead: actions
       share the first line with the day/date, and times stay side by side
       underneath. brm_mobile.js supplies the labels from each table's real
       headings, so translations stay intact. */
    #schedule-page .breaks,
    #schedule-page .working-plan-exceptions,
    #schedule-page .online-windows {
        display: block;
        width: 100%;
        overflow: visible;
        white-space: normal;
        margin-bottom: 1rem;
    }

    #schedule-page .breaks thead,
    #schedule-page .working-plan-exceptions thead,
    #schedule-page .online-windows thead {
        display: none;
    }

    #schedule-page .breaks tbody,
    #schedule-page .working-plan-exceptions tbody,
    #schedule-page .online-windows tbody {
        display: grid;
        gap: 10px;
        width: 100%;
    }

    #schedule-page .breaks tbody tr,
    #schedule-page .working-plan-exceptions tbody tr,
    #schedule-page .online-windows tbody tr {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        grid-template-areas:
            'schedule-day schedule-actions'
            'schedule-start schedule-end';
        gap: 9px 10px;
        width: 100%;
        padding: 11px;
        border: 1px solid #d7dfdf;
        border-radius: 10px;
        background: #f8fafa;
        box-shadow: 0 1px 2px rgba(47, 79, 79, 0.04);
    }

    #schedule-page .breaks tbody td,
    #schedule-page .working-plan-exceptions tbody td,
    #schedule-page .online-windows tbody td {
        display: flex;
        flex-direction: column;
        justify-content: flex-end;
        min-width: 0;
        padding: 0;
        border: 0;
        /* Bootstrap's striped-table accent paints each grid cell separately;
           that looks like unrelated grey boxes once the row becomes a card. */
        background-color: transparent !important;
        box-shadow: none !important;
        vertical-align: top;
    }

    #schedule-page .breaks tbody td:nth-child(1),
    #schedule-page .working-plan-exceptions tbody td:nth-child(1),
    #schedule-page .online-windows tbody td:nth-child(1) {
        grid-area: schedule-day;
    }

    #schedule-page .breaks tbody td:nth-child(2),
    #schedule-page .working-plan-exceptions tbody td:nth-child(2),
    #schedule-page .online-windows tbody td:nth-child(2) {
        grid-area: schedule-start;
    }

    #schedule-page .breaks tbody td:nth-child(3),
    #schedule-page .working-plan-exceptions tbody td:nth-child(3),
    #schedule-page .online-windows tbody td:nth-child(3) {
        grid-area: schedule-end;
    }

    #schedule-page .breaks tbody td:nth-child(4),
    #schedule-page .working-plan-exceptions tbody td:nth-child(4),
    #schedule-page .online-windows tbody td:nth-child(4) {
        grid-area: schedule-actions;
        flex-direction: row;
        justify-content: flex-end;
        align-items: center;
        gap: 7px;
        align-self: center;
        min-height: 44px;
    }

    #schedule-page .breaks tbody td:not(:nth-child(4))::before,
    #schedule-page .working-plan-exceptions tbody td:not(:nth-child(4))::before,
    #schedule-page .online-windows tbody td:not(:nth-child(4))::before {
        content: attr(data-brm-label);
        display: block;
        margin-bottom: 3px;
        color: #637070;
        font-size: 11px;
        font-weight: 700;
        line-height: 1.2;
        letter-spacing: 0.06em;
        text-transform: uppercase;
    }

    #schedule-page .breaks tbody td form,
    #schedule-page .breaks tbody td select,
    #schedule-page .breaks tbody td input,
    #schedule-page .working-plan-exceptions tbody td form,
    #schedule-page .working-plan-exceptions tbody td select,
    #schedule-page .working-plan-exceptions tbody td input,
    #schedule-page .online-windows tbody td select,
    #schedule-page .online-windows tbody td input {
        width: 100% !important;
        min-width: 0 !important;
        max-width: none;
    }

    #schedule-page .online-windows .online-day,
    #schedule-page .online-windows .online-start,
    #schedule-page .online-windows .online-end {
        min-height: 42px;
        font-size: 15px;
    }

    #schedule-page .breaks tbody td:nth-child(4) .btn,
    #schedule-page .working-plan-exceptions tbody td:nth-child(4) .btn,
    #schedule-page .online-windows tbody td:nth-child(4) .btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 44px;
        min-height: 44px;
        margin: 0;
    }

    /* Let the long admin heading wrap instead of cutting its last word off.
       The save action stays immediately below it and is also mirrored by the
       fixed bar, so neither discoverability nor reachability is lost. */
    #schedule-page fieldset > .d-flex:first-child {
        display: grid !important;
        justify-items: start;
        gap: 10px;
    }

    #schedule-page fieldset > .d-flex:first-child h4 {
        max-width: 100%;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    /* The fixed save bar is already present and always reachable. Once it has
       been created, showing the original header button as well wastes a large
       part of the first 320px viewport. The class is added only after the
       working proxy exists, so there is still a fallback if JavaScript fails. */
    #schedule-page.brm-has-sticky-save #save-schedule {
        display: none;
    }

    /* schedule.php already ships its own static #save-schedule-bottom that
       proxies to the header button. With the fixed bar from section 12b that
       makes three save controls on one page — drop the static one on mobile. */
    #schedule-page #save-schedule-bottom {
        display: none;
    }

    /* The intro paragraph and the reset button pushed the actual working plan
       most of a screen down at 320px. Tighten the run-up without hiding
       anything. */
    #schedule-page .backend-page > .row > div > p,
    #schedule-page p.text-muted,
    #schedule-page .jr-mode-note {
        margin-bottom: 0.6rem;
        font-size: 13.5px;
    }

    #schedule-page #reset-working-plan {
        margin-bottom: 0.5rem !important;
    }

    #schedule-page h4,
    #schedule-page h5 {
        margin-bottom: 0.35rem;
    }
}

@media (max-width: 359.98px) {
    /* On the smallest supported screen the floating feedback control covers
       an entire schedule time cell. Feedback remains available everywhere
       else; here the editing workflow gets the unobstructed width. */
    body:has(#schedule-page) #brm-fb-dock {
        display: none;
    }
}

/* ============================================================
   8. Journal
   ============================================================ */

@media (max-width: 767.98px) {
    /* Journal's layout is already sound — custom BRM markup (`jr-` prefix)
       built with narrow screens in mind. What it lacks is touch targets, and
       these are the therapist's most-repeated actions: open a session, mark
       what happened. Measured at 375px they came in at 28px, 22px and 20px.
       EA sizes them with `#journal-page .x` selectors, so matching specificity
       plus this file's load position is enough to override. */

    /* The ledger's column header is meant to be hidden on mobile — journal.php
       does exactly that at max-width 991px. But the very next rule re-shows it:
       for an admin the same element also carries .jr-line-grid--admin, which
       sets `display: grid` at identical specificity and later position. The
       result was a desktop header collapsing into overlapping nonsense
       ("SPECIALISTAS" printing on top of "STATUSAS") — and only ever for
       admins, which is why it survived earlier passes on a provider account.
       Two classes here outrank the single-class rule that resurrects it. */
    #journal-page .jr-head.jr-line-grid {
        display: none;
    }

    /* Provider filter and month navigation are siblings in .jr-topbar-right,
       already flex — they just do not fit 375px together and wrap onto two
       rows, costing a whole row of height for two small controls. Shrink both
       enough to share one line: the filter takes the slack and ellipses if a
       provider name is long, the month stepper keeps its natural width. */
    #journal-page .jr-topbar-right {
        flex-wrap: nowrap;
        gap: 8px;
        width: 100%;
    }

    /* …but only while the filter still says something. The month stepper is a
       fixed ~200px ("2026 m. Rugpjūtis" plus two arrows), so below ~360px the
       filter is squeezed to ~85px and reads "V…" — worse than useless. Give it
       its own row at those widths. */
    @media (max-width: 359.98px) {
        #journal-page .jr-topbar-right {
            flex-wrap: wrap;
        }

        #journal-page #jr-provider-filter {
            flex: 1 0 100%;
        }

        #journal-page .jr-month-nav {
            width: 100%;
            justify-content: space-between;
        }
    }

    #journal-page #jr-provider-filter {
        flex: 1 1 auto;
        min-width: 0;
        width: auto !important;
        text-overflow: ellipsis;
    }

    #journal-page .jr-month-nav {
        flex: 0 0 auto;
        gap: 4px;
    }

    #journal-page .jr-month-label {
        font-size: 14px;
        white-space: nowrap;
    }

    /* Month back/forward — 28x28 by default. 34px keeps them tappable while
       leaving room for the filter beside them. */
    #journal-page .jr-month-arrow {
        width: 34px;
        height: 34px;
    }

    /* Status chips ("Įvyko", "Atšaukta", "Neatvyko") — the core journal
       action, previously ~22px tall at 11px type. They already wrap to a
       second line, so extra height costs nothing. */
    #journal-page .jr-quick .jr-status-btn {
        min-height: 34px;
        padding: 7px 11px;
        font-size: 12px;
    }

    /* Row expander chevron — ~20px. Pad it out without shifting the glyph. */
    #journal-page .jr-open {
        min-width: 38px;
        min-height: 38px;
        padding: 8px 10px;
    }

    /* Controls inside an expanded row. */
    #journal-page .jr-dbtn {
        min-height: 38px;
    }

    /* Keep long client names and comments from widening the row. */
    #journal-page .jr-d-client,
    #journal-page .jr-d-names,
    #journal-page .jr-c-comment {
        min-width: 0;
        overflow-wrap: anywhere;
    }

    /* Expanded-row detail cells stack; keep long client names and comments
       from forcing the row wide. */
    .backend-page .jr-d-client,
    .backend-page .jr-d-names,
    .backend-page .jr-c-comment {
        min-width: 0;
        overflow-wrap: anywhere;
    }
}

/* ============================================================
   9. Settings
   ============================================================ */

@media (max-width: 767.98px) {
    /* The settings sidebar stacks above the form. As a plain vertical list it
       reads as page content; make it a compact horizontal scroller so the form
       stays near the top where it matters. */
    #settings-nav {
        flex-direction: row !important;
        flex-wrap: nowrap;
        gap: 6px;
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
        padding-bottom: 6px;
        margin-bottom: 14px;
        border-bottom: 1px solid #dee2e6;
    }

    #settings-nav .nav-item {
        margin-bottom: 0 !important;
        flex: 0 0 auto;
    }

    #settings-nav .nav-link {
        padding: 8px 12px !important;
        white-space: nowrap;
        border-radius: 8px;
        border: 1px solid rgba(47, 79, 79, 0.1);
        background: #f6f8f7;
        color: #2f4f4f;
        font-size: 14px;
    }

    #settings-nav .nav-link.active {
        background: #2f4f4f;
        color: #fff;
    }

    /* All nine settings screens (general, booking, business, legal, api,
       integrations, google/matomo analytics, ldap) lay out as
       `.col-sm-3.offset-sm-1` for the nav plus `.col-sm-6` for the form.
       Because those are *sm* columns they take effect from 576px — so between
       576 and 767 the nav is 25% wide and the form 50%, with another 8% thrown
       away on the offset. The nav scroller above would have been crammed into
       ~150px. Force both full width for the whole mobile range.
       (An earlier version of this rule used an invented `.settings-form`
       class, which matches nothing in EA.) */
    .backend-page .col-sm-3,
    .backend-page .col-sm-6 {
        flex: 0 0 100%;
        max-width: 100%;
        width: 100%;
    }

    .backend-page .offset-sm-1 {
        margin-left: 0;
    }
}

/* ============================================================
   10. Modals
   ============================================================
   Centred, margined dialogs waste the little room a phone has, and the footer
   scrolled out of reach — the save action on the appointment and series
   dialogs could sit below the fold with no way to get to it. Every dialog goes
   full-screen with a pinned header and footer. */

/* Applies to narrow screens AND to short ones: a phone in landscape is
   812x375, which is wider than 768, so the width-only query handed it EA's
   desktop dialog — footer rendered at y=477 on a 375px-tall viewport, reachable
   only by scrolling the overlay. The height clause covers that. */
@media (max-width: 767.98px), (max-height: 500px) {
    /* Content-sized dialog, vertically centred — not a forced full screen and
       not pinned to the bottom.
       Previously every dialog was stretched to 100dvh, so "Add new event" —
       a question and two buttons — filled an entire phone screen with blank
       space. This sizes to its content and only grows as far as it needs to,
       capped at 92dvh so the page behind stays visible and it still reads as a
       layer on top. Tall dialogs (appointment, series) hit the cap, scroll
       internally, and keep their pinned header/footer. */
    .modal-dialog,
    .modal-dialog.modal-lg,
    .modal-dialog.modal-dialog-centered,
    .modal-dialog.modal-dialog-scrollable {
        position: absolute;
        inset: 0;
        margin: 0;
        max-width: 100%;
        min-height: 0;
        /* Bootstrap gives .modal-dialog-scrollable `height: calc(100% - 1rem)`.
           An explicit height beats the inset-derived one, leaving the box 16px
           short and the dialog sitting 16px above true centre. */
        height: auto;
        display: flex;
        align-items: center;
        justify-content: center;
        padding: 10px;
    }

    .modal-content {
        width: 100%;
        /* dvh tracks the visible viewport; iOS 100vh excludes the retracted
           URL bar and would push the footer below the fold. vh is the
           fallback for browsers without dvh. */
        max-height: 92vh;
        max-height: 92dvh;
        min-height: 0;
        border: 0;
        border-radius: 14px;
        box-shadow: 0 8px 32px rgba(47, 79, 79, 0.22);
    }

    /* The body is the only part that scrolls, so the sheet keeps its header
       and footer visible however tall the content gets. */
    .modal-content > .modal-body {
        overflow-y: auto;
        -webkit-overflow-scrolling: touch;
        min-height: 0;
    }

    .modal-header,
    .modal-footer {
        position: sticky;
        z-index: 3;
        padding: 12px 14px;
    }

    .modal-header {
        top: 0;
    }

    .modal-footer {
        bottom: 0;
        background: #fff;
        border-top: 1px solid #dee2e6;
        gap: 8px;
        /* Clears the iPhone home indicator. */
        padding-bottom: calc(12px + env(safe-area-inset-bottom, 0px));
    }

    .modal-body {
        padding: 14px;
        overflow-x: hidden;
    }

    /* backend_header.php carries a BRM CUSTOM rule that pins dialog controls to
       `padding: 6px 10px; font-size: 14px; min-height: 0`. Written with an ID
       (`#appointments-modal .form-control`) it outranks the generic
       `.modal .form-control` sizing in section 1, so every field in the two
       busiest dialogs measured 31.5px tall — well under a comfortable target,
       and 14px type is the size that triggers focus-zoom on iOS if the
       `user-scalable=no` in the layout is ever removed.
       Matching that specificity here (this file loads last) restores a real
       control size. The -sm variants inside the repeat/series rows are
       deliberately excluded: they live in dense lists where 42px would wreck
       the layout, and they get their own floor below. */
    #appointments-modal .form-control:not(.form-control-sm),
    #appointments-modal .form-select:not(.form-select-sm),
    #unavailabilities-modal .form-control:not(.form-control-sm),
    #unavailabilities-modal .form-select:not(.form-select-sm),
    #brm-series-modal .form-control:not(.form-control-sm),
    #brm-series-modal .form-select:not(.form-select-sm),
    #working-plan-exceptions-modal .form-control:not(.form-control-sm),
    #working-plan-exceptions-modal .form-select:not(.form-select-sm) {
        min-height: 42px;
        padding: 9px 12px;
        font-size: 16px;
    }

    #appointments-modal .form-control-sm,
    #appointments-modal .form-select-sm,
    #unavailabilities-modal .form-control-sm,
    #unavailabilities-modal .form-select-sm,
    #brm-series-modal .form-control-sm,
    #brm-series-modal .form-select-sm {
        min-height: 34px;
        font-size: 14px;
    }

    .modal-title {
        font-size: 1.05rem;
        letter-spacing: 0.03em;
    }

    /* Close control needs a real target, not a 12px glyph, and it was sitting
       flush against a long title instead of at the far right.
       (Every dialog uses Bootstrap 5's `.btn-close`; an earlier version of this
       rule also listed `.close`, which is Bootstrap 4 markup and appears
       nowhere in this codebase.) */
    .modal-header .btn-close {
        padding: 12px;
        margin: -12px -6px -12px auto;
        flex: 0 0 auto;
    }

    .modal-header .modal-title {
        flex: 1 1 auto;
        min-width: 0;
    }

    /* Bootstrap adds padding-right to .modal to compensate for the scrollbar it
       removes from <body>. With the sheet pinned left:0/right:0 inside that
       padding, the sheet stopped ~23px short of the right edge. */
    .modal {
        padding-left: 0 !important;
        padding-right: 0 !important;
        /* The sheet caps itself at 92dvh and scrolls inside .modal-body, so the
           outer container never needs to scroll — leaving it on `auto` just
           painted a second scrollbar down the side of the sheet. */
        overflow: hidden;
    }

    /* Footer: secondary and primary share one row rather than stacking, which
       keeps the sheet short — the whole point of the bottom sheet. Anything
       that is not a button (the "notify client by email" checkbox on the
       appointment dialog) takes a full row above them.
       The primary is ordered last so it sits on the right, under the thumb. */
    .modal-footer {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }

    /* `> button` as well as `> .btn`: the generic message dialog
       (App.Utils.Message) emits `class="btn-primary"` without the base `.btn`,
       so a `.btn`-only selector misses every button in it — which is how "Add
       new event" ended up with two stacked full-width blocks. */
    .modal-footer > .btn,
    .modal-footer > button {
        flex: 1 1 0;
        min-width: 0;
        margin: 0;
        min-height: 42px;
        border-radius: 8px;
    }

    .modal-footer > *:not(.btn):not(button) {
        flex: 1 0 100%;
        margin: 0;
    }

    /* The series dialog's save button is #brm-series-apply — an earlier version
       of this rule guessed #brm-series-save, which does not exist. */
    .modal-footer > .btn-primary,
    .modal-footer > .btn-success,
    .modal-footer > #save-appointment,
    .modal-footer > #brm-series-apply {
        order: 10;
    }

    /* Bootstrap's .modal-dialog-scrollable caps the content at 100% and makes
       the body scroll. That is exactly the sheet behaviour above, so it just
       needs to inherit the same cap rather than override it — an earlier
       version forced `max-height: none` here, which defeated the sheet. */
    .modal-dialog-scrollable .modal-content {
        max-height: 92vh;
        max-height: 92dvh;
    }

    .modal-dialog-scrollable .modal-body {
        overflow-y: auto;
    }
}

/* ============================================================
   11. Recurring series block (appointment + series dialogs)
   ============================================================ */

@media (max-width: 767.98px) {
    /* Pair the fields that are naturally short and read together, instead of
       one per row. EA builds these as grids and collapses them to one column
       below 576px; two columns save four rows in the dialog.
         .brm-customer-fields → first | last  (email, phone, notes span both)
       Anything from the third child on spans the full width, because emails,
       phone numbers and notes need the room. */
    #appointments-modal .brm-customer-fields {
        display: grid;
        grid-template-columns: 1fr 1fr;
        column-gap: 10px;
    }

    #appointments-modal .brm-customer-fields > .mb-3:nth-child(n + 3) {
        grid-column: 1 / -1;
    }

    /* Start/End are deliberately NOT paired at this width.
       When flatpickr initialises they are plain text inputs ("2026/08/03
       06:15") and fit a 165px half easily — but when it does not, the field
       falls back to a native datetime-local, which renders "27/10/2026, 12:00"
       plus a picker glyph and needs ~185-200px. That is browser- and
       locale-dependent, so it cannot be relied on: at 375px the End field was
       clipped off the right edge. One per row is the only rendering-independent
       answer here. They pair again below, once there is provably room. */
    #appointments-modal .brm-visit-time-fields .form-control {
        padding-left: 9px;
        padding-right: 9px;
    }

    #appointments-modal .brm-repeat,
    #brm-series-modal .brm-repeat {
        max-width: 100%;
        overflow-x: hidden;
    }

    /* The disclosure control that opens the whole repeat block ("Sukurti
       tęstines rezervacijas") measured 24px tall — the smallest target in the
       dialog, and the gateway to the entire recurring-booking flow. */
    #appointments-modal .brm-repeat-toggle,
    #brm-series-modal .brm-repeat-toggle {
        min-height: 44px;
        width: 100%;
    }

    /* The bulk time field is a bare <input> with no .form-control class, so
       the control sizing above skips it; EA pins it to 70x30 by ID. The bulk
       service select is .form-select-sm, which floors at 34px. Both are full
       width in this layout, so both get the same comfortable height as the
       buttons beside them. */
    /* Field takes the slack, Apply keeps its natural width beside it. */
    #appointments-modal #brm-repeat-bulk-time,
    #brm-series-modal #brm-series-bulk-time,
    #appointments-modal #brm-repeat-bulk-service,
    #brm-series-modal #brm-series-bulk-service {
        min-height: 40px;
        flex: 1 1 auto;
        width: auto;
        min-width: 0;
    }

    #appointments-modal .brm-repeat-tools .btn,
    #brm-series-modal .brm-series-tools .btn,
    #appointments-modal .brm-repeat-bulk-group .btn,
    #brm-series-modal .brm-series-bulk-group .btn {
        flex: 0 0 auto;
        width: auto;
        white-space: nowrap;
    }

    /* Bulk-apply buttons are .btn-sm inside the tools panel. They span the
       full width now, so there is room to make them properly tappable. */
    #appointments-modal .brm-repeat-tools .btn,
    #brm-series-modal .brm-series-tools .btn {
        min-height: 40px;
    }

    /* The bulk-apply rows keep label, control and button on one line. At 375px
       the button was pushed past the right edge — "PRITAIKYTI" was clipped and
       the service row's button was cut off entirely.
       Fully stacking all three fixed the clipping but cost three rows per
       control. Wrapping instead is the economical middle: the label takes its
       own line, then the field and its Apply button share the next one. */
    #appointments-modal .brm-repeat-bulk-group,
    #brm-series-modal .brm-repeat-bulk-group {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 6px;
        width: 100%;
        min-width: 0;
    }

    #appointments-modal .brm-repeat-bulk-group > label,
    #brm-series-modal .brm-repeat-bulk-group > label {
        flex: 1 0 100%;
    }

    #appointments-modal .brm-repeat-bulk-group > label,
    #brm-series-modal .brm-repeat-bulk-group > label {
        margin: 0;
        white-space: normal;
    }

    /* `flex: 1 1 150px` on the service select is right for a horizontal row,
       but in a column container flex-basis applies to the vertical axis and the
       select balloons to ~300px tall. EA writes that rule with two IDs, so the
       override has to match that specificity to win. */
    #appointments-modal .brm-repeat-bulk-group > *,
    #brm-series-modal .brm-repeat-bulk-group > * {
        flex: 0 0 auto;
    }

    #appointments-modal #brm-repeat-bulk-service,
    #brm-series-modal #brm-repeat-bulk-service,
    #appointments-modal #brm-repeat-bulk-time,
    #brm-series-modal #brm-repeat-bulk-time {
        flex: 0 0 auto;
        width: 100%;
        height: auto;
    }

    #appointments-modal .brm-repeat-bulk-group input,
    #appointments-modal .brm-repeat-bulk-group select,
    #appointments-modal .brm-repeat-bulk-group .btn,
    #brm-series-modal .brm-repeat-bulk-group input,
    #brm-series-modal .brm-repeat-bulk-group select,
    #brm-series-modal .brm-repeat-bulk-group .btn {
        width: 100%;
        min-width: 0;
        max-width: 100%;
        height: auto;
    }

    #appointments-modal .brm-repeat-list,
    #brm-series-modal .brm-repeat-list {
        max-width: 100%;
        overflow-x: hidden;
    }

    /* --- Series dialog bulk controls -------------------------------------
       The standalone series dialog does NOT reuse the `.brm-repeat-*` markup
       of the appointment dialog's repeat block. It has its own family:
       `.brm-series-tools` wrapping `.brm-series-bulk-group`, with
       #brm-series-bulk-time / #brm-series-bulk-service. Everything above
       therefore missed it entirely and the dialog kept the horizontal bulk row
       that overflows at 375px — the exact defect fixed for the appointment
       dialog. EA only ever gives it `flex-wrap: wrap` below 576px.
       (EA's own `#brm-series-modal .brm-repeat-tools` rule is likewise dead —
       series_modal.php contains no such class.) */
    #brm-series-modal .brm-series-tools {
        flex-direction: column;
        align-items: stretch;
        gap: 8px;
    }

    #appointments-modal .brm-series-bulk-group,
    #brm-series-modal .brm-series-bulk-group {
        display: flex;
        flex-direction: column;
        align-items: stretch;
        gap: 6px;
        width: 100%;
        min-width: 0;
        flex: 0 0 auto;
    }

    #appointments-modal .brm-series-bulk-group > label,
    #brm-series-modal .brm-series-bulk-group > label {
        margin: 0;
        white-space: normal;
    }

    #appointments-modal .brm-series-bulk-group > *,
    #brm-series-modal .brm-series-bulk-group > * {
        flex: 0 0 auto;
    }

    /* EA pins the time field to 70x30 with a two-ID selector, so the override
       has to match that specificity. */
    #appointments-modal #brm-series-bulk-time,
    #brm-series-modal #brm-series-bulk-time,
    #appointments-modal #brm-series-bulk-service,
    #brm-series-modal #brm-series-bulk-service {
        width: 100%;
        max-width: 100%;
        min-width: 0;
        height: auto;
        min-height: 38px;
        flex: 0 0 auto;
    }

    #brm-series-modal .brm-series-bulk-group .btn,
    #brm-series-modal #brm-series-bulk-apply,
    #brm-series-modal #brm-series-bulk-service-apply {
        width: 100%;
        min-width: 0;
    }

    /* The series list shares .brm-repeat-list, already handled above; its
       rows are .brm-series-row, handled in the 576px block below. */
    #brm-series-modal .brm-series-list,
    #brm-series-modal .brm-series-count,
    #brm-series-modal .brm-series-access-note {
        max-width: 100%;
        overflow-wrap: anywhere;
    }
}

/* Start | End pair up only once a half-column can comfortably hold a native
   datetime-local (~185-200px including its picker glyph).
   Measured, not guessed: the dialog eats 10px padding a side, .modal-body
   another 14px a side, plus a 10px column gap — so a 430px viewport yields
   only 182px per half, still too tight. 460px is the first width that clears
   ~200px each. In practice that means phones always stack these two (correct —
   375-430 is the whole handset range) and only small tablets pair them. */
@media (min-width: 460px) and (max-width: 767.98px) {
    #appointments-modal .brm-visit-time-fields {
        display: grid;
        grid-template-columns: 1fr 1fr;
        column-gap: 10px;
    }

    #appointments-modal .brm-visit-time-fields > .mb-3:nth-child(n + 3) {
        grid-column: 1 / -1;
    }
}

/* The occurrence rows are a nowrap flex line of checkbox + date + time +
   weekday. At 375px the weekday was sliced in half ("Penktadier…"). */
@media (max-width: 575.98px) {
    #appointments-modal .brm-repeat-row,
    #brm-series-modal .brm-repeat-row {
        flex-wrap: wrap;
        gap: 2px 8px;
        font-size: 12.5px;
        padding: 8px 9px;
    }

    #appointments-modal .brm-repeat-row > *,
    #brm-series-modal .brm-repeat-row > * {
        min-width: 0;
        overflow-wrap: anywhere;
    }

    /* Series dialog rows use a grid whose fixed tracks (18/96/68/auto)
       overflow once the modal padding is removed. */
    #appointments-modal .brm-series-row,
    #brm-series-modal .brm-series-row {
        grid-template-columns: 18px minmax(0, 1fr) 56px auto;
        column-gap: 6px;
        font-size: 13px;
    }

    #appointments-modal .brm-series-row > *,
    #brm-series-modal .brm-series-row > * {
        min-width: 0;
        overflow-wrap: anywhere;
    }

    #appointments-modal .brm-series-cancel,
    #brm-series-modal .brm-series-cancel {
        white-space: normal;
        text-align: right;
    }
}

/* ============================================================
   12. Overlays
   ============================================================ */

@media (max-width: 767.98px) {
    /* Flatpickr renders inline/static inside the dialogs; at 375px the stock
       calendar is wider than the body. */
    .flatpickr-calendar {
        max-width: 100%;
    }

    .flatpickr-calendar.inline {
        width: 100% !important;
    }

    .flatpickr-days,
    .flatpickr-rContainer,
    .flatpickr-innerContainer {
        width: 100% !important;
        max-width: 100%;
    }

    .flatpickr-day {
        max-width: none;
        height: 38px;
        line-height: 38px;
    }

    /* Select2 opens a dropdown that can render off-screen inside a dialog. */
    .select2-container {
        max-width: 100%;
    }

    .select2-container .select2-selection--single {
        height: 42px;
    }

    .select2-container .select2-selection--single .select2-selection__rendered {
        line-height: 40px;
    }

    .select2-dropdown {
        max-width: 96vw;
    }

    .select2-results__option {
        padding: 10px 12px;
    }

    /* The appointment popover is the main calendar interaction — tap an event,
       read the details, edit or delete. Bootstrap's default 276px max-width
       plus the event's anchor position pushed it off the right edge, clipping
       the client's email and half the buttons. */
    .popover {
        max-width: calc(100vw - 16px) !important;
    }

    .popover .popover-body {
        padding: 10px 12px;
        overflow-wrap: anywhere;
    }

    .popover .popover-header {
        padding: 10px 12px;
    }

    /* EA's popover details are a label/value table that assumes desktop
       width. */
    .popover .popover-body table,
    .popover .popover-body td {
        max-width: 100%;
        white-space: normal;
        overflow-wrap: anywhere;
    }

    /* Action buttons inside the popover deserve the full width on a phone. */
    .popover .popover-body .btn {
        min-height: 40px;
    }

    /* Bootstrap dropdowns anchored to right-aligned toolbar buttons can spill
       past the viewport edge. */
    .dropdown-menu {
        max-width: calc(100vw - 24px);
    }

    .dropdown-item {
        padding: 10px 14px;
        white-space: normal;
    }

    /* Tippy tooltips are hover affordances; on touch they fire on tap and sit
       over the thing you just pressed. */
    [data-tippy-root] {
        display: none !important;
    }

    /* EA's flash message — "saved", "could not save" — is the only feedback a
       therapist gets after an action. The fixed element is `#notification
       .alert` (the wrapper itself is static, so an earlier version of this rule
       targeted the wrong node and did nothing).
       EA pins it bottom-right at z-index 200, i.e. underneath both the sticky
       save bar (1030) and the feedback dock (1085), and in the same corner as
       both — so on a phone the confirmation was hidden behind the very button
       that triggered it. Make it a full-width toast that clears the bar and
       sits above everything except dialogs. */
    #notification .alert {
        left: 8px;
        right: 8px;
        bottom: 8px;
        width: auto;
        max-width: none;
        z-index: 1090;
        font-size: 14px;
        border-radius: 10px;
    }

    .brm-has-sticky-save #notification .alert,
    body:has(.brm-sticky-save) #notification .alert {
        bottom: 86px;
    }
}

/* ============================================================
   12b. Sticky primary action (form pages)
   ============================================================
   Built by brm_mobile.js on account / schedule / settings, where the only
   save button lives in the page header three screens up. */

.brm-sticky-save {
    display: none;
}

@media (max-width: 767.98px) {
    .brm-sticky-save {
        display: block;
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 1030;
        padding: 8px 12px calc(8px + env(safe-area-inset-bottom, 0px));
        background: #fff;
        border-top: 1px solid rgba(47, 79, 79, 0.1);
        box-shadow: 0 -2px 12px rgba(47, 79, 79, 0.07);
    }

    .brm-sticky-save .btn {
        width: 100%;
        min-height: 46px;
        border-radius: 10px;
    }

    /* Keep the last field clear of the bar. */
    .brm-has-sticky-save {
        padding-bottom: 78px !important;
    }

    /* The feedback dock is also bottom-fixed; lift it above the bar. */
    body:has(.brm-sticky-save) #brm-fb-dock {
        bottom: 74px;
    }
}

/* A dialog's own footer takes over as the primary action. */
body.modal-open .brm-sticky-save {
    display: none;
}

/* ============================================================
   12c. Colour + contrast (WCAG AA)
   ============================================================
   Measured with proper alpha compositing at 375px. Four colours in the
   dialogs and page chrome fell under the 4.5:1 AA floor for normal-size text.
   Replacements are existing brand tokens from registracija-v2.php, so nothing
   new is invented — they are simply the accessible members of the same
   palette. Ratios below are against white.

   Scoped to mobile because that is the brief; the same four values fail on
   desktop too, and lifting these rules out of the media query is all that is
   needed if you want them fixed everywhere. */

@media (max-width: 767.98px), (max-height: 500px) {
    /* Section headings inside dialogs and pages ("Vizito detalės",
       "Klientas"). rgba(0,0,0,.5) over white = 3.98:1 at 11px/300.
       --b-muted #637070 = 5.14:1. */
    .modal .text-black-50,
    .backend-page .text-black-50 {
        color: #637070 !important;
    }

    /* Required-field asterisk. #d9534f = 3.96:1.
       --b-error #c62828 = 5.62:1. */
    .modal .text-danger,
    .backend-page .text-danger {
        color: #c62828 !important;
    }

    /* "Atšaukti" — the escape hatch in every dialog, so it has to be legible.
       #3b8773 = 4.29:1, just under. #2f6c5b = 6.15:1 and reads as the same
       green. */
    .modal .btn-secondary,
    .modal-footer .btn-secondary {
        color: #2f6c5b;
    }

    /* Every .btn-outline-secondary in a dialog inherits #777, which lands at
       4.48:1 — fractionally under AA. That includes the series dialog's
       "Uždaryti", i.e. the way out of the screen. #5a6767 = 5.88:1 and keeps
       the muted, secondary feel. */
    .modal .btn-outline-secondary {
        color: #5a6767;
    }

    /* Calendar chips for blocked periods / unavailability get their colour
       inline from the event record (an admin picks it in settings), so the
       contrast of white-on-that-colour is not fixed and cannot be corrected by
       restyling the background without overriding a configurable value. The
       default holiday colour rgb(214,80,105) lands at 4.03:1 — legible but shy
       of AA. A shadow plus a heavier weight makes the label hold up on any
       mid-tone the admin chooses.
       Note: WCAG does not formally credit text-shadow, so if you want a
       guaranteed AA figure here, darken the blocked-period colour in settings
       instead — anything at or below rgb(190,60,85) clears 4.5:1. */
    #calendar-page .fc-blocked-period .fc-event-title,
    #calendar-page .fc-unavailability .fc-event-title,
    #calendar-page .fc-blocked-period .fc-event-time,
    #calendar-page .fc-unavailability .fc-event-time {
        font-weight: 600;
        text-shadow: 0 1px 2px rgba(0, 0, 0, 0.45);
    }

    /* Rooms: colleagues' bookings are white text on --rp-other #93a7a7, which
       is 2.52:1 — the single worst reading on any screen, and it is the main
       content of the page (who is in the room). #5b7676 = 4.89:1 and is still
       clearly lighter than your own hours (--rp-busy #2f4f4f, 8.93:1), so the
       "colleagues recede" hierarchy survives. Overriding the variable rather
       than the blocks catches every usage.
       --rp-bad (#a0523d, 5.57:1) and --rp-busy already pass. */
    #rooms-page {
        --rp-other: #5b7676;
    }

    /* Day headers, the hour gutter and the hint line all use #6b7b7b = 4.43:1,
       fractionally under AA. */
    #rooms-page .rp-table th,
    #rooms-page .rp-time,
    #rooms-page .rp-legend {
        color: #5a6767;
    }

    /* Journal uses the literal #8a9797 as its muted tone in nine places —
       3.02:1, well under AA, and it carries real information: the page title,
       every session date, the "planned" status and the summary figures. On a
       phone in a bright room these were the hardest things on screen to read.
       #637070 (--b-muted) = 5.14:1 keeps the same muted role.
       The "no payment" dash used #b0bcbc = 1.95:1, effectively invisible. */
    #journal-page .jr-title,
    #journal-page .jr-date,
    #journal-page .jr-hint,
    #journal-page .jr-st--planned,
    #journal-page .jr-ins-title,
    #journal-page .jr-ins-share,
    #journal-page .jr-stats-head small,
    #journal-page .jr-stat small,
    #journal-page .jr-pay-none {
        color: #637070;
    }

    /* The repeat/series "Pritaikyti" buttons: #777 at 10px = 4.48:1, and 10px
       is below the readable floor for a control label anyway. Brand primary
       #2f4f4f = 8.93:1. */
    #appointments-modal .brm-repeat-tools .btn,
    #brm-series-modal .brm-series-tools .btn,
    #appointments-modal #brm-repeat-bulk-apply,
    #appointments-modal #brm-repeat-bulk-service-apply,
    #brm-series-modal #brm-series-bulk-apply,
    #brm-series-modal #brm-series-bulk-service-apply {
        color: #2f4f4f;
        font-size: 12px;
    }
}

/* ============================================================
   13. Density
   ============================================================
   Phone screens are ~660px of usable height. EA's desktop rhythm (1.5rem
   gutters, 3rem section margins, 2rem headings) spends a third of that on
   whitespace before any content appears. These reclaim it. Deliberately last
   before the dock so it trims everything above. */

@media (max-width: 767.98px) {
    .backend-page {
        padding-top: 10px;
        padding-bottom: 10px;
    }

    /* Display headings: one line, not three. */
    .backend-page h1,
    .backend-page h2 {
        font-size: 1.2rem;
        margin-bottom: 0.5rem;
    }

    .backend-page h3,
    .backend-page h4 {
        font-size: 1.05rem;
        margin-bottom: 0.4rem;
    }

    .backend-page hr,
    .backend-page .border-bottom {
        margin-top: 0.6rem;
        margin-bottom: 0.6rem;
    }

    /* Controls: EA's default vertical padding is generous for mouse use. Keep
       the 42px touch height from section 1, take the slack from the margins. */
    .backend-page .form-control,
    .backend-page .form-select {
        padding-top: 0.4rem;
        padding-bottom: 0.4rem;
    }

    .backend-page .form-label,
    .backend-page label {
        margin-bottom: 3px;
        font-size: 14px;
    }

    /* Free-text areas default to 4-5 rows of empty space each. */
    .backend-page textarea.form-control {
        min-height: 70px;
    }

    /* Bootstrap spacing utilities are tuned for desktop; halve the big ones. */
    .backend-page .mb-4,
    .backend-page .mt-4 {
        margin-bottom: 1rem !important;
    }

    .backend-page .my-4,
    .backend-page .py-4 {
        margin-top: 0.75rem !important;
        margin-bottom: 0.75rem !important;
    }

    .backend-page .py-3 {
        padding-top: 0.5rem !important;
        padding-bottom: 0.5rem !important;
    }

    .backend-page .p-3 {
        padding: 0.6rem !important;
    }

    /* Cards (customer appointment history, journal groups) carry a lot of
       padding for the little they hold. */
    .backend-page .card,
    .backend-page .card-body {
        padding: 8px;
    }

    /* Row gutters: 1.5rem between stacked columns is a lot of dead space once
       everything is one column wide. */
    .backend-page .row {
        --bs-gutter-x: 0.75rem;
    }

    /* The footer is pure chrome; it does not need a third of a screen. */
    #footer {
        padding: 6px !important;
        font-size: 12px;
    }

    #footer .mb-3 {
        margin-bottom: 4px !important;
    }
}

/* ============================================================
   14. Feedback dock
   ============================================================ */

/* The dock is fixed bottom-right and covered the modal footer's save button.
   Bootstrap sets .modal-open on <body> whenever a dialog is showing. */
body.modal-open #brm-fb-dock,
body.modal-open #brm-fb-panel {
    display: none !important;
}

@media (max-width: 575.98px) {
    /* Collapse to the icon so it stops covering table rows and calendar
       events; the label returns on wider screens. */
    #brm-fb-dock .brm-fb-label {
        display: none;
    }

    #brm-fb-panel {
        left: 8px;
        right: 8px;
        width: auto;
        max-width: none;
        max-height: 80vh;
        overflow-y: auto;
    }

    /* The panel is pinned at bottom:18px, so on a page with the sticky save bar
       it opened straight over the save button. Lift it clear. */
    body:has(.brm-sticky-save) #brm-fb-panel {
        bottom: 86px;
        max-height: 70vh;
    }

    /* The minimise "x" is a 26x26 badge pinned to the dock's top-right corner —
       too small to hit reliably. Growing the element itself made it swallow the
       dock icon (the label is hidden at this width, so the dock is small), so
       extend only the touch area: a pseudo-element inset by -6px gives a ~38px
       target and forwards its taps to the button, with no visual change. */
    #brm-fb-min::after {
        content: '';
        position: absolute;
        inset: -6px;
        border-radius: 50%;
    }
}
