/* =====================================================================
 * The panel does not animate, and nothing moves or changes colour under the
 * pointer.
 *
 * These rules undo the interactive treatments in
 * common/assets/brand/css/brand.css, which is shared with the public site and
 * keeps them. The prefix is `.admin-body` (on the panel's <body>) rather than
 * !important: brand.css loads after this file, so the extra element selector is
 * what wins the cascade — and it also means the override cannot leak.
 *
 * Hover still gives feedback, but through an underline rather than a colour or
 * a shift: the operator needs to know what is clickable without the row moving
 * out from under the pointer, which is what a lifting card does to a grid.
 * ===================================================================== */

.admin-body *,
.admin-body *::before,
.admin-body *::after {
    transition: none !important;
    animation: none !important;
}

.admin-body .brand-card,
.admin-body .brand-card:hover {
    box-shadow: var(--brand-shadow);
    transform: none;
}

/* The accent rule that wiped in along a card's top edge. */
.admin-body .brand-card-accent::before,
.admin-body .brand-card-accent:hover::before {
    display: none;
}

.admin-body .dash-tile:hover,
.admin-body .admin-sidebar-link:hover,
.admin-body a.admin-sidebar-link:hover {
    background-color: transparent;
    color: inherit;
    transform: none;
    text-decoration: underline;
}

/* The current section keeps its steady highlight — that is state, not hover. */
.admin-body .admin-sidebar-link.is-active {
    background-color: var(--bs-primary-bg-subtle);
    color: var(--bs-primary-text-emphasis);
    text-decoration: none;
}

.admin-body .btn:active,
.admin-body .btn:hover {
    transform: none;
}

/* =====================================================================
 * Panel shell: fixed brand bar on top, sticky section menu on the left.
 *
 * Colours come from the brand tokens in common/assets/brand/css/brand.css,
 * which are emitted per request from common/config/brand.php. Nothing here
 * hardcodes a hex.
 * ===================================================================== */

.admin-body {
    /* Height of the fixed navbar; used by the offsets below so there is one
       number to change if the bar ever grows. */
    --admin-topbar-h: 58px;
    --admin-sidebar-w: 250px;
}

.admin-shell {
    display: flex;
    align-items: flex-start;
    gap: 0;
    padding-top: var(--admin-topbar-h);
    flex: 1 0 auto;
}

.admin-sidebar {
    flex: 0 0 var(--admin-sidebar-w);
    width: var(--admin-sidebar-w);
    align-self: stretch;
    /* No side padding: entries run the full width of the column, so the active
       row's highlight and its lime edge marker sit against the border rather
       than floating inside an inset box. */
    padding: .5rem 0 1.5rem;
    background-color: var(--brand-surface);
    border-right: 1px solid var(--brand-line);
    /* Sticks under the navbar and scrolls independently, so a long menu never
       pushes the page content down. */
    position: sticky;
    top: var(--admin-topbar-h);
    max-height: calc(100vh - var(--admin-topbar-h));
    overflow-y: auto;
}

.admin-content {
    flex: 1 1 auto;
    min-width: 0; /* lets wide tables scroll instead of stretching the layout */
    padding: 1.5rem 1.5rem 3rem;
    /* Stretched and column-flow so a page can push something to its foot. */
    align-self: stretch;
    display: flex;
    flex-direction: column;
}

/* The dashboard's brand line belongs at the bottom of the page, not trailing
   the last card. */
.site-index {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
}

.site-index-brand {
    margin-top: auto;
    padding-top: 2rem;
}

.admin-sidebar-section + .admin-sidebar-section {
    margin-top: .75rem;
}

/*
 * The section heading is the toggle. Styled as the label it already was — a
 * button that looked like a button would read as an action rather than as the
 * name of the group under it.
 */
.admin-sidebar-heading {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .5rem;
    width: 100%;
    border: 0;
    background: none;
    text-align: left;
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--brand-on-surface-muted);
    padding: .3rem 1rem;
}

.admin-body .admin-sidebar-heading:hover {
    /* Underline only, like every other hover in the panel. */
    text-decoration: underline;
    background: none;
    color: var(--brand-on-surface-muted);
}

.admin-sidebar-caret {
    font-size: .6rem;
    /* The caret turns to point at what it does. No transition: the panel does
       not animate, and a rotating chevron is decoration, not feedback. */
    transform: rotate(0deg);
}

.admin-sidebar-section.is-closed .admin-sidebar-caret {
    transform: rotate(-90deg);
}

.admin-sidebar-list {
    list-style: none;
    margin: 0;
    padding: 0;
}

.admin-sidebar-link {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .45rem 1rem;
    color: var(--brand-on-surface);
    text-decoration: none;
    font-size: .9rem;
    line-height: 1.3;
}

.admin-sidebar-link.is-active {
    background-color: var(--bs-primary-bg-subtle);
    color: var(--bs-primary-text-emphasis);
    font-weight: 500;
    box-shadow: inset 3px 0 0 var(--brand-lime);
}

.admin-sidebar-icon {
    width: 1.25rem;
    text-align: center;
    flex: 0 0 auto;
}

/*
 * Icon-only buttons. Fixed square so a row of them lines up whatever glyph each
 * carries, and so the click target stays a comfortable size once the label is
 * no longer padding it out.
 */
.btn-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    line-height: 1;
    font-size: 1rem;
}

.btn-icon.btn-sm {
    width: 1.9rem;
    height: 1.9rem;
    font-size: .875rem;
}

/* Grid footer: row count on the left, pager on the right, aligned on one line
   instead of the summary and the pagination stacking awkwardly. */
/* =====================================================================
 * Create / edit forms.
 *
 * One shape for every form in the panel: a titled strip, the fields, and a
 * footer holding the actions. The card carries no padding of its own so the
 * three bands can be separated by rules that run edge to edge — which is what
 * makes the footer read as a place where the form ends rather than as two more
 * buttons floating after the last field.
 * ===================================================================== */
.admin-form {
    padding: 0;
    overflow: hidden;
}

.admin-form-head {
    padding: 1rem 1.25rem;
    border-bottom: 1px solid var(--brand-line);
}

.admin-form-head h1,
.admin-form-head h2 {
    margin: 0;
    font-size: 1.05rem;
    font-weight: 600;
}

.admin-form-head p {
    margin: .25rem 0 0;
    font-size: .82rem;
    color: var(--brand-on-surface-muted);
}

.admin-form-body {
    padding: 1.25rem;
}

.admin-form-foot {
    display: flex;
    gap: .5rem;
    padding: .85rem 1.25rem;
    border-top: 1px solid var(--brand-line);
    background-color: var(--brand-surface-2, rgba(0, 0, 0, .015));
}

/* Labels sit close to their field and stay quieter than the value. */
.admin-form .form-label,
.admin-form label {
    margin-bottom: .25rem;
    font-size: .8rem;
    font-weight: 500;
    color: var(--brand-on-surface-muted);
}

/*
 * Yii marks a required field's wrapper with .required. Showing it is worth more
 * than the note some forms carry above the fields, because it says WHICH ones.
 */
.admin-form .form-group.required > label::after {
    content: ' *';
    color: var(--bs-danger);
}

.admin-form .form-control,
.admin-form .form-select {
    border-color: var(--brand-line);
    /* No transition: the panel does not animate. */
    transition: none;
}

.admin-form .form-control:focus,
.admin-form .form-select:focus {
    border-color: var(--brand-primary, var(--bs-primary));
    box-shadow: 0 0 0 .2rem var(--bs-primary-bg-subtle);
}

.admin-form .form-control[readonly] {
    background-color: rgba(0, 0, 0, .03);
}

.admin-form .invalid-feedback {
    font-size: .78rem;
}

/*
 * The flags, gathered into one bordered block at the end rather than scattered
 * among the text fields in schema order. A lone checkbox between two inputs is
 * easy to miss, and `requires_prepayment` is not a field anybody should miss.
 */
.admin-form-flags {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem 1.5rem;
    padding: .85rem 1rem;
    border: 1px solid var(--brand-line);
    border-radius: .5rem;
    background-color: rgba(0, 0, 0, .012);
}

.admin-form-flags .form-group {
    margin-bottom: 0;
}

.admin-form-flags .form-check-label {
    font-size: .87rem;
    color: var(--brand-on-surface);
}

/*
 * The service picker. Each service is a full-width row you click anywhere on,
 * with the price in a column of its own — reception reads down that column
 * while quoting, so it has to line up.
 */
/*
 * The picker's own tab styling is gone: the strip is backend\components\Tabs
 * like every other one in the panel, so it needs no CSS here.
 */

/* One service per row now: the row carries a name, a doctor and a price. */
.svc-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: .35rem;
}

.svc-option {
    display: flex;
    align-items: center;
    gap: .6rem;
    padding: .4rem .75rem;
    border: 1px solid var(--brand-line);
    border-radius: .5rem;
    /* No transition; the checked state is a state, not an effect. */
    background-color: #fff;
}

.svc-option:hover {
    border-color: var(--brand-on-surface-muted);
}

/*
 * One doctor for the whole category, above its services. Which person carries
 * the work out is decided by the kind of service, not by each line: two blood
 * tests on the same visit are run by the same technician.
 */
.svc-panel-doctor {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin-bottom: .5rem;
}

.svc-panel-doctor label {
    font-size: .8rem;
    font-weight: 500;
    color: var(--brand-on-surface-muted);
    margin: 0;
    flex: 0 0 auto;
}

.svc-panel-doctor .form-select {
    width: 18rem;
    max-width: 100%;
}

.svc-panel-doctor .form-select:disabled {
    /* Visible but plainly inert until something in the category is chosen. */
    background-color: rgba(0, 0, 0, .03);
    color: var(--brand-on-surface-muted);
}

.svc-option-name {
    flex: 1 1 auto;
    font-size: .87rem;
    min-width: 0;
}

.svc-option-price {
    flex: 0 0 auto;
    font-size: .85rem;
    font-variant-numeric: tabular-nums;
    color: var(--brand-on-surface-muted);
}

/* :has is what lets the whole row respond to its own checkbox without JS. */
.svc-option:has(input:checked) {
    border-color: var(--bs-primary);
    background-color: var(--bs-primary-bg-subtle);
}

.svc-option:has(input:checked) .svc-option-price {
    color: var(--bs-primary-text-emphasis);
}

.svc-option input {
    flex: 0 0 auto;
    margin: 0;
}

/*
 * Running total. The desk quotes a price out loud while ticking boxes; adding
 * them up in your head is where the wrong number comes from.
 */
.svc-total {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 1rem;
    margin-top: .75rem;
    padding: .6rem .85rem;
    border: 1px solid var(--brand-line);
    border-radius: .5rem;
    background-color: rgba(0, 0, 0, .02);
    font-size: .87rem;
}

.svc-total-amount {
    font-size: 1.05rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

.admin-form-legend {
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .1em;
    text-transform: uppercase;
    color: var(--brand-on-surface-muted);
    margin-bottom: .4rem;
}

/*
 * Split payment: one amount box per method, because a patient regularly pays
 * part in cash and finishes by card. Laid out as a small grid so the three
 * amounts line up and can be read down.
 */
.split-pay-row {
    display: grid;
    grid-template-columns: 10rem 1fr;
    gap: .5rem;
    align-items: center;
}

.split-pay-row + .split-pay-row { margin-top: .35rem; }

.split-pay-label {
    font-size: .82rem;
    color: var(--brand-on-surface);
    margin: 0;
}

.split-pay-foot {
    display: flex;
    align-items: baseline;
    gap: .5rem;
    margin-top: .6rem;
    padding-top: .6rem;
    border-top: 1px solid var(--brand-line);
}

.split-pay-total {
    font-size: 1.05rem;
    font-variant-numeric: tabular-nums;
}

/* More entered than is owed — the server refuses it, this says so sooner. */
.split-pay.is-over .split-pay-total { color: var(--bs-danger); }

@media (max-width: 575.98px) {
    .split-pay-row { grid-template-columns: 1fr; }
}

/*
 * Cash desk summary tiles: what has been taken today, by each of the three
 * ways money arrives, plus what is still owed. Read at a glance from across
 * the room, which is why the figure is large and the caption is not.
 */
.pos-tiles {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: .75rem;
}

@media (min-width: 768px) {
    .pos-tiles { grid-template-columns: repeat(5, 1fr); }
}

.pos-tile {
    padding: .75rem 1rem;
    border: 1px solid var(--brand-line);
    border-radius: .5rem;
    background-color: #fff;
}

.pos-tile-label {
    font-size: .72rem;
    letter-spacing: .04em;
    text-transform: uppercase;
    color: var(--brand-on-surface-muted);
}

.pos-tile-value {
    font-size: 1.25rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: 1.4;
}

/* The day's total and the money still owed are the two the eye should find. */
.pos-tile-total {
    border-color: var(--bs-primary);
    background-color: var(--bs-primary-bg-subtle);
}

.pos-tile-owed .pos-tile-value { color: var(--bs-danger); }

/*
 * A tab strip is a row of outline buttons — backend\components\Tabs — so it
 * needs no CSS of its own. There used to be a `.crud-tab` set here drawing
 * folder tabs with a bottom rule, which meant the panel had two visual languages
 * for "pick one of these" depending on which screen you were on.
 */

/*
 * The filter row under the headings. Set apart from the data with a tint and a
 * heavier rule, so it does not read as a first row of records.
 */
.crud-filter-row > td {
    padding: .4rem .5rem;
    background-color: rgba(0, 0, 0, .02);
    border-bottom: 2px solid var(--brand-line);
}

.crud-filter-row .form-control,
.crud-filter-row .form-select {
    border-color: var(--brand-line);
    transition: none;
    min-width: 6rem;
}

.crud-filter-row .form-control:focus,
.crud-filter-row .form-select:focus {
    border-color: var(--brand-primary, var(--bs-primary));
    box-shadow: 0 0 0 .15rem var(--bs-primary-bg-subtle);
}

.crud-pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    border-top: 1px solid var(--brand-line);
}

.crud-pager .summary {
    color: var(--brand-on-surface-muted);
    font-size: .875rem;
    margin: 0;
}

.crud-pager .pagination {
    --bs-pagination-color: var(--bs-link-color);
    --bs-pagination-hover-color: var(--bs-link-hover-color);
    --bs-pagination-hover-bg: var(--bs-primary-bg-subtle);
    --bs-pagination-active-bg: var(--brand-primary);
    --bs-pagination-active-border-color: var(--brand-primary);
    --bs-pagination-focus-color: var(--bs-link-hover-color);
    --bs-pagination-focus-bg: var(--bs-primary-bg-subtle);
    --bs-pagination-border-color: var(--brand-line);
}

/*
 * Bootstrap's own card, given the panel's card look.
 *
 * Some screens wrap a panel in .brand-card and some in Bootstrap's .card with a
 * .card-header — the second is the better markup when the panel has a title bar,
 * and rewriting every one of them into hand-rolled divs would be churn for no
 * gain. So the two are made to look the same instead: no outline, the same
 * radius and the same shadow. Background is deliberately left alone, or the rule
 * would beat .bg-light on the tiles that are meant to be tinted.
 */
.admin-body .card:not([class*="border-"]) {
    border: 0;
    border-radius: var(--bs-border-radius-lg);
    box-shadow: var(--brand-shadow);
}

.admin-body .card > .card-header:not([class*="bg-"]) {
    background-color: transparent;
    border-bottom: 1px solid var(--brand-line);
    font-weight: 600;
}

/*
 * A card that carries a colour — border-primary on the payment panel,
 * border-info on the ward lines — is saying something with it, so only the
 * shadow is added and the outline it chose is left in place.
 */
.admin-body .card[class*="border-"] {
    border-radius: var(--bs-border-radius-lg);
    box-shadow: var(--brand-shadow);
}

/*
 * The period control — @backend/views/_date-range.
 *
 * One shape wherever a screen is about a stretch of days: the two boxes on the
 * left, the shortcuts beside them. They wrap onto a second line together rather
 * than the row of shortcuts breaking up.
 */
.date-range {
    display: flex;
    align-items: center;
    gap: .75rem;
    flex-wrap: wrap;
}

.date-range-form {
    display: flex;
    align-items: center;
    gap: .4rem;
}

.date-range-form .form-control {
    width: 9.5rem;
    border-color: var(--brand-line);
    transition: none;
}

.date-range-dash {
    color: var(--brand-on-surface-muted);
}

.date-range-presets {
    display: flex;
    align-items: center;
    gap: .25rem;
    flex-wrap: wrap;
}

/*
 * Dashboard: one card per group of related screens.
 *
 * The sidebar is flat because it is a place to jump from; this is where someone
 * looks to see what the panel contains, and there the grouping is the point.
 */
.dash-group-title {
    color: var(--brand-on-surface-muted);
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .09em;
    text-transform: uppercase;
    padding-bottom: .5rem;
    margin-bottom: .5rem;
    border-bottom: 1px solid var(--brand-line);
}

.dash-tile {
    display: flex;
    align-items: center;
    gap: .65rem;
    padding: .4rem .5rem;
    border-radius: .4rem;
    color: var(--brand-on-surface);
    text-decoration: none;
    font-size: .92rem;
}

.dash-tile-icon {
    width: 1.4rem;
    flex: 0 0 auto;
    text-align: center;
    color: var(--bs-primary-text-emphasis);
}

/*
 * Below lg the sidebar is a Bootstrap collapse driven by the button in the
 * navbar. The !important is needed because .collapse sets display:none, and on
 * a wide screen the menu must always be there.
 */
@media (min-width: 992px) {
    .admin-sidebar.collapse:not(.show) {
        display: block !important;
    }
}

@media (max-width: 991.98px) {
    .admin-shell {
        flex-direction: column;
    }

    .admin-sidebar {
        position: static;
        width: 100%;
        flex-basis: auto;
        max-height: none;
        border-right: 0;
        border-bottom: 1px solid var(--brand-line);
    }

    .admin-content {
        padding: 1rem;
        width: 100%;
    }
}

.not-set {
    color: var(--bs-danger);
    font-style: italic;
}

/* add sorting icons to gridview sort links */
a.asc:after, a.desc:after {
    content: '';
    left: 3px;
    display: inline-block;
    width: 0;
    height: 0;
    border: solid 5px transparent;
    margin: 4px 4px 2px 4px;
    background: transparent;
}

a.asc:after {
    border-bottom: solid 7px var(--bs-body-color);
    border-top-width: 0;
}

a.desc:after {
    border-top: solid 7px var(--bs-body-color);
    border-bottom-width: 0;
}

.grid-view th {
    white-space: nowrap;
}

.hint-block {
    display: block;
    margin-top: 5px;
    color: var(--bs-secondary-color);
}

.error-summary {
    color: var(--bs-danger-text-emphasis);
    background: var(--bs-danger-bg-subtle);
    border-left: 3px solid var(--bs-danger-border-subtle);
    padding: 10px 20px;
    margin: 0 0 15px 0;
}

/* align navbar brand baseline with nav links */
.navbar > .container,
.navbar > .container-fluid {
    align-items: baseline;
}

/* style navbar logout link color, hover state, and mobile layout */
.navbar-nav .nav-link.logout {
    color: var(--bs-navbar-color);
}

@media (max-width: 767.98px) {
    .navbar-nav .nav-link.logout {
        display: block;
        text-align: left;
        width: 100%;
        padding: 10px 0;
    }
}

.navbar-nav .nav-link.logout:focus,
.navbar-nav .nav-link.logout:hover {
    color: var(--bs-navbar-hover-color);
}



/* login inputs: seamless icon inside input */
.login-split-card .input-group {
    border: var(--bs-border-width) solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
    overflow: hidden;
}

.login-split-card .input-group .input-group-text {
    background: transparent;
    border: 0;
    padding-left: 1rem;
    padding-right: .75rem;
    display: flex;
    align-items: center;
    justify-content: center;
}

.login-split-card .input-group .form-control {
    border: 0;
    background: transparent;
}

.login-split-card .input-group .form-control:focus {
    box-shadow: none;
}

.login-split-card .input-group:focus-within {
    border-color: var(--bs-primary);
    box-shadow: 0 0 0 .25rem rgba(var(--bs-primary-rgb), .25);
}

/* validation styles for browsers that support :has() */
@supports selector(.input-group:has(.is-invalid)) {
    /* show validation errors below the input-group */
    .login-split-card .input-group:has(.is-invalid) ~ .invalid-feedback {
        display: block;
        margin-top: .35rem;
        margin-bottom: .5rem;
    }

    /* red border on input-group when invalid */
    .login-split-card .input-group:has(.is-invalid) {
        border-color: var(--bs-danger);
    }

    .login-split-card .input-group:has(.is-invalid):focus-within {
        box-shadow: 0 0 0 .25rem rgba(var(--bs-danger-rgb), .25);
    }
}

/* fallback validation styles for browsers without :has() support */
@supports not selector(.input-group:has(.is-invalid)) {
    .login-split-card .invalid-feedback:not(:empty) {
        display: block;
        margin-top: .35rem;
        margin-bottom: .5rem;
    }

    .login-split-card .input-group .form-control.is-invalid {
        border: var(--bs-border-width) solid var(--bs-danger);
    }

    .login-split-card .input-group .form-control.is-invalid:focus {
        box-shadow: 0 0 0 .25rem rgba(var(--bs-danger-rgb), .25);
    }
}

/* login split card */
.login-split-card {
    border-radius: 1rem;
    box-shadow: 0 4px 24px rgba(0, 0, 0, .10);
    background-color: var(--bs-gray-100);
    width: 100%;
    max-width: 900px;
}

.login-brand-title {
    font-size: 1.75rem;
    line-height: 1.3;
}

.login-brand-text {
    font-size: .9rem;
}

/*
 * Colour for these lives in common/assets/brand/css/brand.css, which reads the
 * palette from common/config/brand.php. Only geometry is left here — the
 * template's original blue/orange gradients were off-brand hex values, and
 * brand.php is explicit that no hex belongs anywhere but in it.
 */
.login-brand-panel::before {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
}

.login-btn {
    font-weight: 600;
    letter-spacing: .02em;
}

.login-btn:hover {
    transform: translateY(-1px);
}

.login-btn:active {
    transform: translateY(0);
}

/* The site is light-only; there is no colour-mode toggle. See brand.css. */

/* dashboard welcome banner — gradient in brand.css */
.dashboard-banner {
    position: relative;
}

.dashboard-banner::before {
    content: '';
    position: absolute;
    inset: 0;
    border-radius: inherit;
    pointer-events: none;
}

/* centered page layout: error */
.site-index,
.site-error {
    flex: 1;
}

.site-error .site-error-content {
    width: 100%;
    max-width: 90%;
}

@media (min-width: 576px) {
    .site-error .site-error-content {
        max-width: 80%;
    }
}

@media (min-width: 768px) {
    .site-error .site-error-content {
        max-width: 60%;
    }
}

@media (min-width: 992px) {
    .site-error .site-error-content {
        max-width: 50%;
    }
}
