/* El atributo hidden lo pisa cualquier regla de autor que declare display:
   la regla del navegador ([hidden] { display: none }) viene de la hoja de
   estilos del user agent y pierde contra las nuestras. Sin esto, más abajo
   `button { display: inline-block }` hacía que un <button hidden> se viera
   igual. Va con !important porque tiene que ganarle a todo. */
[hidden] {
    display: none !important;
}

:root {
    /* Tema "claro" (default) — fondo blanco con tarjetas celestes. */
    --color-bg: #ffffff;
    --color-surface: #e4f3fa;
    --color-border: #a9d7ec;
    --color-text: #163140;
    --color-text-muted: #5a7684;
    --color-primary: #1e93c9;
    --color-primary-dark: #146a94;
    --color-navy: #123b53;
    --color-navy-dark: #0b2635;
    --color-gold: #d4a017;
    --color-danger: #b3493f;
    --radius: 8px;
    --shadow: 0 1px 2px rgba(20, 30, 40, 0.08);
    --transition: 0.15s ease;

    --color-badge-neutral-bg: #e6e9e6;
    --color-badge-success-bg: #e3f1ea;
    --color-badge-success-text: var(--color-primary-dark);
    --color-badge-warning-bg: #f3e6d6;
    --color-badge-warning-text: #8a5a25;
    --color-badge-info-bg: #eaf0f8;
    --color-badge-info-text: #3a5a8a;
}

[data-theme="pastel"] {
    /* Fondo blanco con tarjetas rosa pastel. */
    --color-bg: #ffffff;
    --color-surface: #f8d9ec;
    --color-border: #f0b8d9;
    --color-text: #4a3350;
    --color-text-muted: #8d7793;
    --color-primary: #c07bc2;
    --color-primary-dark: #9c5aa0;
    --color-navy: #7c5aa8;
    --color-navy-dark: #5f3f85;
    --color-gold: #e3a8c7;
    --color-danger: #c1667a;
    --shadow: 0 1px 3px rgba(150, 60, 130, 0.14);

    --color-badge-neutral-bg: #f3e3ee;
    --color-badge-success-bg: #dcf0e2;
    --color-badge-success-text: #3f7a5c;
    --color-badge-warning-bg: #fbe4d6;
    --color-badge-warning-text: #9c5a2e;
    --color-badge-info-bg: #f0e0f5;
    --color-badge-info-text: #7c4a94;
}

[data-theme="oscuro"] {
    --color-bg: #14181b;
    --color-surface: #1d2226;
    --color-border: #2b3237;
    --color-text: #e7ecec;
    --color-text-muted: #9aa7a7;
    --color-primary: #45b3a1;
    --color-primary-dark: #327f72;
    --color-navy: #8fb4e0;
    --color-navy-dark: #bcd4f0;
    --color-gold: #d7b46f;
    --color-danger: #e0776a;
    --shadow: 0 1px 3px rgba(0, 0, 0, 0.35);

    --color-badge-neutral-bg: #2b3237;
    --color-badge-success-bg: #1f3a30;
    --color-badge-success-text: #7fd9b0;
    --color-badge-warning-bg: #3a2f1f;
    --color-badge-warning-text: #e0b87a;
    --color-badge-info-bg: #1f2f3a;
    --color-badge-info-text: #7fb3e0;
}

* {
    box-sizing: border-box;
}

@media (prefers-reduced-motion: reduce) {
    * {
        transition: none !important;
        animation: none !important;
    }
}

body {
    margin: 0;
    font-family: -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
    background: var(--color-bg);
    color: var(--color-text);
    line-height: 1.5;
    transition: background-color var(--transition), color var(--transition);
}

a {
    color: var(--color-primary);
    text-decoration: none;
    transition: color var(--transition);
}

a:hover {
    text-decoration: underline;
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

h1, h2, h3 {
    line-height: 1.25;
    margin: 0 0 0.6em;
}

h1 {
    font-size: 1.6rem;
}

h2 {
    font-size: 1.15rem;
    color: var(--color-text-muted);
    margin-top: 1.8em;
}

/* Subheading inside a section — used where one <h2> covers two lists that
   still need telling apart. Smaller than the h2 above it so the nesting is
   obvious (the browser default is larger, which reads as the opposite), and
   with enough space above to break the run of list rows. The landing page's
   .feature h3 sets its own size, colour and margin, so it is unaffected. */
h3 {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-text-muted);
    margin-top: 1.4em;
}

/* Header */

.site-header {
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    padding: 0.75rem 1rem;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.6rem;
    position: sticky;
    top: 0;
    z-index: 50;
    transition: background-color var(--transition), border-color var(--transition);
}

.site-header-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}

.nav-toggle {
    display: inline-flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    background: none;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    width: 40px;
    height: 36px;
    padding: 0;
    cursor: pointer;
    flex-shrink: 0;
}

.nav-toggle:hover {
    background: var(--color-bg);
    transform: none;
    box-shadow: none;
}

.nav-toggle .bar {
    display: block;
    width: 18px;
    height: 2px;
    background: var(--color-navy-dark);
    border-radius: 2px;
    transition: background-color var(--transition);
}

.nav-panel {
    display: none;
    flex-direction: column;
    gap: 0.75rem;
}

.nav-panel.open {
    display: flex;
}

.brand {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--color-navy-dark);
}

.brand-logo {
    height: 32px;
    width: 32px;
    display: block;
    color: var(--color-navy-dark);
}

.brand-logo svg {
    width: 100%;
    height: 100%;
    display: block;
}

.site-nav {
    display: flex;
    justify-content: center;
    gap: 1rem 1.5rem;
    flex-wrap: wrap;
    width: 100%;
}

.site-nav a {
    color: var(--color-text);
    font-weight: 500;
    position: relative;
}

.site-nav a:hover {
    color: var(--color-primary);
    text-decoration: none;
}

.header-user {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    width: 100%;
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

.header-user form {
    margin: 0;
}

.theme-switch select {
    width: auto;
    padding: 0.3rem 0.5rem;
    font-size: 0.85rem;
}

/* Layout */

/* Flex rather than a grid with a fixed first column: the agenda drops the
   sidebar entirely, and with one child flex simply gives it everything. A
   grid would leave a column-shaped hole. */
.layout {
    display: flex;
    align-items: flex-start;
}

.container {
    max-width: 880px;
    margin: 0 auto;
    padding: 1rem 1rem 2.5rem;
    /* Sits beside the sidebar, so it must be allowed to shrink; without this
       the widest table inside it pushes the sidebar off screen. */
    /* Without this the reading column refuses to shrink below the widest
       thing inside it and pushes the sidebar off screen. */
    flex: 1 1 auto;
    min-width: 0;
}

.container.container-wide {
    max-width: 1200px;
}

/* Patient sidebar
   Hidden by default and switched on at a wide breakpoint further down. The
   phone gets .patient-bar instead — same ?patient=, one line rather than a
   column. */

.sidebar {
    display: none;
}

/* A row of the sticky header, bled out to the window edges past the header's
   own padding. It has to stay on screen while you scroll a list: it is the
   answer to "who am I working on", and it was scrolling away. */
.patient-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    margin: 0 -1rem -0.75rem;
    padding: 0.45rem 1rem;
    background: var(--color-bg);
    border-top: 1px solid var(--color-border);
    font-size: 0.9rem;
}

.patient-bar-name {
    font-weight: 600;
    color: var(--color-text);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.patient-bar-actions {
    display: flex;
    gap: 0.75rem;
    flex-shrink: 0;
}

.patient-bar-none {
    color: var(--color-text-muted);
    font-weight: 400;
}

/* Says a list is short because of the sidebar and not because it is empty.
   Deliberately not a .stat-note: it is the standing state of the page
   talking, not a comment about the rows. */
.selection-note {
    margin: 0 0 1rem;
    padding: 0.5rem 0.75rem;
    background: var(--color-badge-info-bg);
    color: var(--color-badge-info-text);
    border-radius: var(--radius);
    font-size: 0.85rem;
}

.selection-note a {
    color: inherit;
    text-decoration: underline;
}

.site-footer {
    max-width: 880px;
    margin: 0 auto;
    padding: 1rem 1rem 2rem;
    border-top: 1px solid var(--color-border);
    color: var(--color-text-muted);
    font-size: 0.85rem;
    text-align: center;
    transition: border-color var(--transition), color var(--transition);
}

.site-footer a {
    color: inherit;
}

section {
    margin-bottom: 1.5rem;
}

/* Install banner */

.install-banner {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 0.5rem 1rem;
    background: var(--color-surface);
    border-bottom: 1px solid var(--color-border);
    padding: 0.6rem 1rem;
    transition: background var(--transition), border-color var(--transition);
}

.install-banner-text {
    margin: 0;
    font-size: 0.9rem;
    color: var(--color-text);
}

.install-banner-actions {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.install-banner-actions button {
    font-size: 0.9rem;
    padding: 0.35rem 0.9rem;
}

/* Messages */

.messages {
    list-style: none;
    margin: 1rem 0 0;
    padding: 0;
}

.messages li {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-left: 4px solid var(--color-primary);
    border-radius: var(--radius);
    padding: 0.6rem 0.9rem;
    margin-bottom: 0.5rem;
}

/* Buttons */

.btn, button, input[type="submit"] {
    display: inline-block;
    background: var(--color-primary);
    color: #fff;
    border: none;
    border-radius: var(--radius);
    padding: 0.5rem 1rem;
    font-size: 0.95rem;
    cursor: pointer;
    transition: background-color var(--transition), transform var(--transition), box-shadow var(--transition);
}

.btn:hover, button:hover, input[type="submit"]:hover {
    background: var(--color-primary-dark);
    text-decoration: none;
    transform: translateY(-1px);
    box-shadow: 0 3px 8px rgba(0, 0, 0, 0.12);
}

.btn:active, button:active, input[type="submit"]:active {
    transform: translateY(0);
    box-shadow: none;
}

.btn-link {
    background: none;
    color: var(--color-primary);
}

.btn-link:hover {
    background: none;
    text-decoration: underline;
    transform: none;
    box-shadow: none;
}

.btn-danger {
    background: var(--color-danger);
}

.btn-danger:hover {
    background: var(--color-danger);
    filter: brightness(0.9);
}

.actions {
    display: flex;
    gap: 0.75rem;
    align-items: center;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}

.filter-bar {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.6rem;
    margin-bottom: 1rem;
}

.filter-bar label {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    font-size: 0.9rem;
    color: var(--color-text-muted);
}

/* Desde y Hasta van pegados: si el wrap de la barra los manda a filas
   distintas, el rango deja de leerse como un rango. */
.filter-range {
    display: flex;
    flex-direction: column;
    gap: 0.6rem;
}

/* An empty full-width flex item, which in a wrapping flex row means "start a
   new line here". Sits before the date range so the bar always reads as
   selects on top, then the range and the button underneath, instead of the
   range trailing the selects or not, depending on how wide the patient names
   of the day happen to make them. Below 640px everything is stacked anyway
   and it costs nothing. */
.filter-break {
    flex-basis: 100%;
    height: 0;
}

/* Tabs (patient page) */

/* Scrolls sideways rather than wrapping: four tabs on a narrow phone would
   otherwise break onto two rows and stop reading as one bar. */
.tabs {
    display: flex;
    gap: 0.25rem;
    margin: 0 0 1.5rem;
    border-bottom: 1px solid var(--color-border);
    overflow-x: auto;
    scrollbar-width: none;
}

.tabs::-webkit-scrollbar {
    display: none;
}

.tabs a {
    flex-shrink: 0;
    padding: 0.6rem 0.9rem;
    color: var(--color-text-muted);
    font-weight: 500;
    white-space: nowrap;
    /* Transparent rather than absent so switching tabs does not shift the
       row by the height of the border. */
    border-bottom: 2px solid transparent;
    margin-bottom: -1px;
    transition: color var(--transition), border-color var(--transition);
}

.tabs a:hover {
    color: var(--color-text);
    text-decoration: none;
}

.tabs a.is-current {
    color: var(--color-primary);
    border-bottom-color: var(--color-primary);
}

.tab-count {
    display: inline-block;
    min-width: 1.5em;
    padding: 0 0.4em;
    border-radius: 999px;
    background: var(--color-badge-neutral-bg);
    color: var(--color-text-muted);
    font-size: 0.75rem;
    font-weight: 600;
    text-align: center;
}

.tabs a.is-current .tab-count {
    background: var(--color-primary);
    color: var(--color-bg);
}

/* Cards / list */

.card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.25rem;
    margin-bottom: 1rem;
    transition: background-color var(--transition), border-color var(--transition);
}

.list {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
}

.list-item {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 0.75rem 1rem;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: center;
    gap: 0.4rem 1rem;
    transition: background-color var(--transition), border-color var(--transition), transform var(--transition), box-shadow var(--transition);
}

.list-item:hover {
    border-color: var(--color-primary);
    transform: translateY(-1px);
    box-shadow: 0 3px 10px rgba(0, 0, 0, 0.06);
}

.list-item a {
    font-weight: 500;
}

.list-item-paid {
    background: var(--color-badge-success-bg);
    border-left: 4px solid var(--color-badge-success-text);
}

.list-item-pending {
    background: var(--color-badge-warning-bg);
    border-left: 4px solid var(--color-badge-warning-text);
}

.list-item-partial, .list-item-scheduled {
    background: var(--color-badge-info-bg);
    border-left: 4px solid var(--color-badge-info-text);
}

/* The quick actions on a row (marcar paga, marcar falta) travel together.
   Each one is its own <form>, so without this they are two flex children of
   the row and the row's space-between gap pushes them apart.

   nowrap and flex-shrink:0 keep the pair side by side always: allowed to
   wrap, the leftover width on a phone puts one button under the other and
   the row grows a whole line taller. They are kept narrow enough (compact
   type just below) that the pair still shares a line with the badges. */
.list-item-actions {
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    gap: 0.9rem;
    flex-shrink: 0;
}

/* Row actions only: the pair has to fit next to the badges on a 375px
   screen, and at the full button size it does not. Horizontal padding goes
   and the type shrinks; the vertical padding stays, because narrower is
   fine but shorter would hurt the tap target. */
.list-item-actions .btn-link {
    font-size: 0.85rem;
    padding-left: 0;
    padding-right: 0;
}

/* Session rows: the tags line up in columns instead of landing wherever the
   patient's name happens to end.

   A row holds a link of wildly varying length, an optional "Falta sin aviso",
   a payment badge and the actions. Under the default space-between each of
   those sits at a different x on every row, and the eye has nothing to scan
   down. Putting a grid on the row itself does not fix it: every row would
   size its own columns from its own content and stagger just the same. So
   the list owns the columns and each row subscribes with subgrid — measured
   once from the widest row, applied to all of them.

   Content-sized rather than fixed widths, which means a list with no falta
   sin aviso anywhere spends no width at all on that column.

   Measured at a 1280px window: the link column gets 392px, and six typical
   rows come to 396px against 408px before, because today a long name pushes
   the badges onto a second line and that costs more than the occasional
   wrapped link does. Below 820px four columns do not fit and the rows stay
   as they were. Without subgrid the rows also stay as they were — every
   current browser has it, and the fallback is the old look, not a broken
   one. */
.row-slot {
    display: flex;
    align-items: center;
}

/* Off the grid an empty slot would only contribute a stray gap. It has to
   survive on the grid though, or the payment badge slides into the column
   the no-show tag was holding. Needs the template to emit the span with
   nothing whatsoever inside it — a stray newline defeats :empty. */
.row-slot:empty {
    display: none;
}

/* Stacked on a phone: the link takes the first line, tags and actions flow
   under it. Packed left, because space-between throws "Falta sin aviso" and
   the payment badge to opposite edges with a hole between them that reads as
   a bug. The third line a no-show row needs is unavoidable at 375px — tags
   and actions together measure 377px against the 311px available. */
.list-session .list-item {
    justify-content: flex-start;
}

.list-session .list-item > a {
    flex-basis: 100%;
}

@supports (grid-template-columns: subgrid) {
    @media (min-width: 820px) {
        .list-session {
            display: grid;
            grid-template-columns: minmax(0, 1fr) auto auto auto;
            column-gap: 0.75rem;
        }

        .list-session .list-item {
            grid-column: 1 / -1;
            display: grid;
            grid-template-columns: subgrid;
            align-items: center;
        }

        .list-session .row-slot:empty {
            display: block;
        }

        /* Last column, so the row ends on a straight edge whether or not
           "Marcar paga" is there to widen it. */
        .list-session .list-item-actions {
            justify-content: flex-end;
        }
    }
}

.list-empty {
    color: var(--color-text-muted);
    font-style: italic;
}

/* Lista de texto simple (ej. página de Ayuda) — a diferencia de .list,
   no es un contenedor flex de filas tipo link+badge, es prosa con viñeta. */
.help-list {
    margin: 0 0 1rem;
    padding-left: 1.25rem;
}

.help-list li {
    margin-bottom: 0.6rem;
    line-height: 1.5;
}

.help-list li:last-child {
    margin-bottom: 0;
}

/* Definition list (detail pages) */

.detail-grid {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.1rem 1.25rem;
    display: grid;
    grid-template-columns: 1fr;
    gap: 0.1rem 1.5rem;
    margin: 0;
}

.detail-grid dt {
    color: var(--color-text-muted);
    font-size: 0.85rem;
    margin-top: 0.6rem;
}

.detail-grid dt:first-child {
    margin-top: 0;
}

.detail-grid dd {
    margin: 0;
}

/* Badges */

.badge {
    display: inline-block;
    border-radius: 999px;
    padding: 0.15rem 0.6rem;
    font-size: 0.78rem;
    font-weight: 600;
    background: var(--color-badge-neutral-bg);
    color: var(--color-text-muted);
    transition: background-color var(--transition), color var(--transition);
}

.badge-active, .badge-paid, .badge-done, .badge-delivered {
    background: var(--color-badge-success-bg);
    color: var(--color-badge-success-text);
}

.badge-inactive, .badge-pending {
    background: var(--color-badge-warning-bg);
    color: var(--color-badge-warning-text);
}

.badge-partial, .badge-scheduled, .badge-info {
    background: var(--color-badge-info-bg);
    color: var(--color-badge-info-text);
}

/* Forms */

form p {
    margin: 0 0 0.9rem;
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
}

form label {
    font-size: 0.85rem;
    color: var(--color-text-muted);
}

.helptext {
    font-size: 0.8rem;
    color: var(--color-text-muted);
}

input, select, textarea {
    width: 100%;
    font: inherit;
    padding: 0.45rem 0.6rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    transition: outline-color var(--transition), border-color var(--transition), background-color var(--transition), color var(--transition);
}

input:focus, select:focus, textarea:focus {
    outline: 2px solid var(--color-primary);
    outline-offset: 1px;
}

input[type="checkbox"] {
    width: fit-content;
}

ul.errorlist {
    list-style: none;
    margin: 0 0 1rem;
    padding: 0.6rem 0.9rem;
    background: #fbeceb;
    border: 1px solid var(--color-danger);
    border-radius: var(--radius);
    color: var(--color-danger);
}

.formset {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1rem 1.25rem;
    margin-bottom: 1rem;
}

.formset-row {
    border-bottom: 1px solid var(--color-border);
    padding-bottom: 0.75rem;
    margin-bottom: 0.75rem;
}

.formset-row:last-child {
    border-bottom: none;
    margin-bottom: 0;
    padding-bottom: 0;
}

.formset-row-invalid {
    background: #fbeceb;
    border-radius: var(--radius);
    padding: 0.6rem 0.75rem 0.75rem;
    margin-left: -0.75rem;
    margin-right: -0.75rem;
}

.formset-row-invalid select,
.formset-row-invalid input {
    border-color: var(--color-danger);
}

/* Tables */

.table-scroll {
    overflow-x: auto;
}

table {
    width: 100%;
    min-width: 320px;
    border-collapse: collapse;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    overflow: hidden;
}

th, td {
    text-align: left;
    padding: 0.6rem 0.9rem;
    border-bottom: 1px solid var(--color-border);
}

th {
    background: var(--color-bg);
    color: var(--color-text-muted);
    font-size: 0.85rem;
}

tr:last-child td {
    border-bottom: none;
}

tbody tr, table tr:not(:first-child) {
    transition: background-color var(--transition);
}

tbody tr:hover, table tr:not(:first-child):hover {
    background: var(--color-bg);
}

/* Catch-up screen */

.catch-up .col-tick {
    width: 2.5rem;
    text-align: center;
}

.catch-up .col-money {
    text-align: right;
    white-space: nowrap;
}

.catch-up .col-date {
    width: 11rem;
}

/* The inputs sit inside table cells, where the standing form styles leave
   them far too tall to read fifty rows of. */
.catch-up td input[type="date"],
.catch-up td input[type="text"] {
    width: 100%;
    min-width: 7rem;
    margin: 0;
    padding: 0.35rem 0.5rem;
}

.catch-up td.col-money input {
    text-align: right;
}

.catch-up tbody tr.is-selected {
    background: var(--color-bg);
}

/* The ticked rows need to be findable while scrolling a year of sessions, and
   the row background alone is already the hover colour. */
.catch-up tbody tr.is-selected td:first-child {
    box-shadow: inset 3px 0 0 var(--color-primary);
}

/* Sticky so the running total stays readable while you are ticking rows far
   down a long table — which is the whole point of having it. */
.catch-up-tally {
    position: sticky;
    bottom: 0;
    z-index: 1;
    display: flex;
    flex-wrap: wrap;
    gap: 0.3rem 1rem;
    margin: 0.75rem 0 0;
    padding: 0.6rem 0.9rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    color: var(--color-text);
    font-weight: 600;
}

.tally-part {
    white-space: nowrap;
}

.catch-up-method {
    margin-top: 1rem;
}

.catch-up-actions {
    display: grid;
    gap: 1rem;
    margin-bottom: 1rem;
}

.catch-up-action {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 1.25rem;
}

.catch-up-action h2 {
    margin-top: 0;
}

.catch-up-action p {
    margin: 0 0 0.75rem;
}

/* Side by side once there is room: the two are alternatives, and reading them
   one under the other makes the second look like a further step. */
@media (min-width: 820px) {
    .catch-up-actions {
        grid-template-columns: 1fr 1fr;
        align-items: start;
    }
}

/* Pagination */

.pagination {
    display: flex;
    flex-wrap: wrap;
    gap: 1rem;
    align-items: center;
    margin-top: 1rem;
    color: var(--color-text-muted);
    font-size: 0.9rem;
}

.auth-page {
    max-width: 360px;
    margin: 0 auto;
}

.auth-page > h1,
.auth-page > p {
    text-align: center;
}

.auth-page > .actions {
    justify-content: center;
}

/* Aviso para leer antes de apretar un botón — no es un error, es una
   advertencia. Reusa los colores de badge de advertencia para que acompañe
   los tres temas sin definir nada nuevo. Se combina con .card:
   <div class="card notice-warning">. */
.notice-warning {
    background: var(--color-badge-warning-bg);
    border-left: 4px solid var(--color-badge-warning-text);
}

.notice-warning p,
.notice-warning .stat-note,
.notice-warning strong {
    color: var(--color-badge-warning-text);
}

/* Portada pública (sesiona.uy sin cuenta). Mobile-first como el resto: acá
   va todo en una columna y el bloque de 640px de más abajo se encarga de la
   grilla y de los tamaños grandes. */

.landing-hero {
    text-align: center;
    padding: 1.5rem 0 2rem;
}

/* El original venía con fondo blanco opaco. Acá va la versión recortada y
   con el fondo hecho transparente, en webp: así no aparece un recuadro
   blanco en el tema oscuro y pesa 66 KB en vez de 400.
   El margin auto es lo que lo centra: con display block no alcanza el
   text-align del contenedor. */
.landing-logo {
    display: block;
    width: min(220px, 62vw);
    height: auto;
    margin: 0 auto;
}

.landing-name {
    margin: 0.75rem 0 0;
    font-size: 2.4rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-navy-dark);
}

.landing-tagline {
    margin: 0.5rem 0 0;
    font-size: 1.2rem;
    color: var(--color-text);
}

.landing-lede {
    margin: 1rem auto 0;
    max-width: 44ch;
    color: var(--color-text-muted);
}

.landing-cta {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem;
    justify-content: center;
    margin-top: 1.5rem;
}

.btn-lg {
    padding: 0.7rem 1.5rem;
    font-size: 1.05rem;
}

/* Segundo botón de una pareja de acciones: mismo peso visual que el
   primario pero sin competir con él. */
.btn-secondary {
    background: transparent;
    color: var(--color-primary);
    border: 1px solid var(--color-border);
}

.btn-secondary:hover {
    background: var(--color-surface);
    color: var(--color-primary-dark);
}

.landing-note {
    margin: 0.75rem 0 0;
    font-size: 0.9rem;
    color: var(--color-text-muted);
}

.landing-section {
    margin-bottom: 2.5rem;
}

.landing-section > h2 {
    font-size: 1.35rem;
    margin-bottom: 1rem;
}

.feature-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

.feature {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 1.1rem;
    transition: background-color var(--transition), border-color var(--transition);
}

.feature h3 {
    margin: 0 0 0.4rem;
    font-size: 1.02rem;
    color: var(--color-navy-dark);
}

.feature p {
    margin: 0;
    color: var(--color-text-muted);
    font-size: 0.95rem;
}

.landing-price {
    text-align: center;
}

.landing-price-amount {
    margin: 0 0 0.5rem;
    font-size: 2rem;
    font-weight: 800;
    color: var(--color-navy-dark);
}

.landing-price-amount span {
    font-size: 1rem;
    font-weight: 400;
    color: var(--color-text-muted);
}

.landing-closing {
    text-align: center;
}

/* Páginas de contenido: textos largos, asistentes y pantallas de ajustes —
   todo lo que no es un formulario corto de login. Van a lo ancho del
   contenedor en mobile y se limitan recién en desktop (ver el bloque de
   640px), donde una línea sin tope cruzaría la pantalla entera y el ojo se
   pierde al saltar de renglón. A diferencia de .auth-page, el texto va
   alineado a la izquierda: centrar párrafos de este largo se lee incómodo. */
.content-page {
    margin: 0 auto;
}

.content-page h2 {
    margin-top: 2rem;
    margin-bottom: 0.75rem;
}

.content-page ul {
    padding-left: 1.25rem;
}

.content-page li + li {
    margin-top: 0.4rem;
}

/* El link de referidos de la pantalla de suscripción es una URL entera
   dentro de un <code>. Sin esto no corta por ningún lado y empuja el ancho
   de la página, que en el celular se traduce en scroll horizontal. */
code {
    overflow-wrap: anywhere;
}

.login-card {
    max-width: 360px;
    margin: 1.5rem auto 0;
}

/* Para formularios de varios campos (registro, tarifas). 360px es la medida
   justa para un login de dos campos, pero con once queda una columna
   larguísima y finita. No se estira más porque un input de texto muy ancho
   tampoco se lee bien: el aire extra lo aprovecha .field-grid poniendo los
   campos de a dos. */
.form-card {
    max-width: 620px;
    margin: 1.5rem auto 0;
}

/* Envuelve un {{ form.as_p }} y acomoda sus <p> de a dos en desktop. El
   margen inferior de cada <p> ya separa las filas, así que acá solo hace
   falta el hueco entre columnas. */
.field-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 0 1.25rem;
}

.login-brand {
    display: flex;
    flex-direction: column;
    align-items: center;
    margin-top: 2rem;
}

.login-logo {
    display: block;
    height: 96px;
    width: 96px;
    color: var(--color-navy-dark);
}

.login-logo svg {
    width: 100%;
    height: 100%;
    display: block;
}

.login-wordmark {
    margin: 0.5rem 0 0;
    font-size: 2.2rem;
    font-weight: 800;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--color-navy-dark);
}

.login-title {
    text-align: center;
    color: var(--color-text-muted);
    font-size: 1.1rem;
    font-weight: 500;
    margin-top: 0;
}

.dashboard-grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: 1rem;
}

.dashboard-grid .card {
    margin-bottom: 0;
    border-top: 3px solid var(--color-gold);
}

/* Dashboard */

.stat {
    font-size: 1.8rem;
    font-weight: 700;
    color: var(--color-navy-dark);
    margin: 0;
}

.stat-note {
    color: var(--color-text-muted);
    margin: 0.2rem 0 0;
}

/* Ayuda contextual — sin JS: se muestra con hover en desktop y con
   tap/foco en celular, porque tocar el botón lo enfoca. */

.help-tip {
    position: relative;
    display: inline-flex;
    vertical-align: middle;
    margin-left: 0.35rem;
}

.help-tip-trigger {
    width: 1.15rem;
    height: 1.15rem;
    padding: 0;
    border-radius: 50%;
    border: 1px solid var(--color-border);
    background: var(--color-surface);
    color: var(--color-text-muted);
    font-size: 0.7rem;
    line-height: 1;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    cursor: help;
    transition: border-color var(--transition), color var(--transition);
}

.help-tip-trigger:hover,
.help-tip-trigger:focus-visible {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

.help-tip-content {
    position: absolute;
    z-index: 20;
    bottom: calc(100% + 0.4rem);
    left: 50%;
    transform: translateX(-50%) translateY(4px);
    width: max-content;
    max-width: 220px;
    background: var(--color-navy-dark);
    color: #fff;
    font-size: 0.8rem;
    line-height: 1.35;
    padding: 0.5rem 0.7rem;
    border-radius: var(--radius);
    opacity: 0;
    pointer-events: none;
    transition: opacity var(--transition), transform var(--transition);
}

.help-tip-trigger:hover + .help-tip-content,
.help-tip-trigger:focus + .help-tip-content {
    opacity: 1;
    transform: translateX(-50%) translateY(0);
    pointer-events: auto;
}

/* Agenda */

.agenda-nav {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem 1rem;
    margin-bottom: 1rem;
}

.agenda-week {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
}

.agenda-day h2 {
    font-size: 0.95rem;
    text-transform: capitalize;
    color: var(--color-text-muted);
    margin: 0 0 0.5rem;
    display: flex;
    align-items: center;
    gap: 0.4rem;
}

.agenda-day-today {
    background: var(--color-badge-info-bg);
    border-radius: var(--radius);
    padding: 0.5rem;
}

.agenda-day-today h2 {
    color: var(--color-badge-info-text);
    font-weight: 700;
}

/* Desktop / wide-viewport enhancements (mobile-first base above) */

@media (min-width: 640px) {
    .container {
        padding: 1.5rem 1.25rem 3rem;
    }

    /* Ancho de lectura: alrededor de 80 caracteres por línea. Más angosto
       que el .container de 880px a propósito — el tope no es el ancho de la
       pantalla sino hasta dónde el ojo sigue un renglón sin cansarse. */
    .content-page {
        max-width: 820px;
    }

    .field-grid {
        grid-template-columns: 1fr 1fr;
    }

    /* Portada en desktop: la grilla pasa a dos columnas y el encabezado
       gana aire. Tres columnas quedarían con las tarjetas demasiado
       angostas dentro del .container de 880px. */
    .feature-grid {
        grid-template-columns: repeat(2, 1fr);
        gap: 1.25rem;
    }

    .landing-hero {
        padding: 2.5rem 0 3rem;
    }

    .landing-logo {
        width: 260px;
    }

    .landing-name {
        font-size: 3rem;
    }

    .landing-tagline {
        font-size: 1.45rem;
    }

    .site-header {
        flex-direction: row;
        align-items: center;
        gap: 1.5rem;
        padding: 0.75rem 1.25rem;
    }

    .nav-toggle {
        display: none;
    }

    .nav-panel {
        display: flex !important;
        flex-direction: row;
        align-items: center;
        flex: 1;
        gap: 1.5rem;
    }

    .site-nav {
        flex: 1;
        width: auto;
        justify-content: flex-start;
    }

    .header-user {
        width: auto;
    }

    .filter-bar {
        flex-direction: row;
        align-items: center;
        flex-wrap: wrap;
    }

    .filter-bar input,
    .filter-bar select {
        width: auto;
    }

    .filter-range {
        flex-direction: row;
        align-items: center;
    }

    .list-item-actions {
        gap: 1rem;
    }

    /* Between here and the 820px grid a session row still fits on one line,
       so it keeps the spread-to-the-edges look. Packing left would leave the
       whole right half of the row empty. */
    .list-session .list-item {
        justify-content: space-between;
    }

    .list-session .list-item > a {
        flex-basis: auto;
    }

    .detail-grid {
        grid-template-columns: max-content 1fr;
        gap: 0.4rem 1.5rem;
        padding: 1.25rem 1.5rem;
    }

    .detail-grid dt {
        margin-top: 0;
    }

    .dashboard-grid {
        grid-template-columns: repeat(auto-fit, minmax(220px, 1fr));
    }

    .agenda-week {
        flex-direction: row;
        align-items: flex-start;
        gap: 0.75rem;
    }

    .agenda-day {
        flex: 1;
        min-width: 0;
    }

    .agenda-day .list-item {
        flex-direction: column;
        align-items: flex-start;
    }
}

/* Patient sidebar — only once there is room for it beside the 880px reading
   column without squeezing it. Below this the phone's .patient-bar covers the
   same state in one line. */

@media (min-width: 1200px) {
    .patient-bar {
        display: none;
    }

    /* A wall of the window, not a card floating in the margin. With three
       patients a bordered box just read as a stray widget; flush to the edge
       and full height it reads as part of the furniture.

       Fixed rather than sticky. Sticky left its position at the mercy of how
       tall the page happened to be: it is laid out inside the flex row, so a
       short page left it hanging with a gap under it, and a long one shifted
       where it started. Fixed to the window, it is in the same place on every
       page, and --header-height is measured rather than guessed so it sits
       exactly under the header instead of near it. */
    .sidebar {
        display: flex;
        flex-direction: column;
        position: fixed;
        top: var(--header-height, 4.6rem);
        left: 0;
        bottom: 0;
        width: 15rem;
        z-index: 40;
        background: var(--color-surface);
        border-right: 1px solid var(--color-border);
        transition: width var(--transition);
    }

    /* Out of the flow, so the page has to be told to leave room. The class is
       set by the sidebar's own script, which means the agenda — the one page
       that drops the sidebar — never gets the padding. */
    body.has-sidebar .layout,
    body.has-sidebar .site-footer {
        padding-left: 15rem;
    }

    body.has-sidebar.sidebar-collapsed .layout,
    body.has-sidebar.sidebar-collapsed .site-footer {
        padding-left: 2.9rem;
    }

    .sidebar-head {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 0.5rem;
        padding: 0.5rem 0.5rem 0.5rem 0.75rem;
        border-bottom: 1px solid var(--color-border);
    }

    .sidebar-title {
        color: var(--color-text-muted);
        font-size: 0.8rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.04em;
        white-space: nowrap;
    }

    .sidebar-toggle {
        flex-shrink: 0;
        width: 1.75rem;
        height: 1.75rem;
        padding: 0;
        border: 1px solid var(--color-border);
        border-radius: var(--radius);
        background: none;
        color: var(--color-text-muted);
        line-height: 1;
        cursor: pointer;
    }

    .sidebar-toggle span[aria-hidden] {
        display: block;
        transition: transform var(--transition);
    }

    .sidebar-body {
        display: flex;
        flex-direction: column;
        flex: 1;
        min-height: 0;
    }

    .sidebar-filters {
        display: flex;
        flex-direction: column;
        gap: 0.4rem;
        padding: 0.6rem 0.75rem;
        border-bottom: 1px solid var(--color-border);
    }

    .sidebar-filters select {
        width: 100%;
        margin: 0;
        padding: 0.3rem 0.4rem;
        font-size: 0.85rem;
    }

    .sidebar-check {
        display: flex;
        align-items: center;
        gap: 0.4rem;
        color: var(--color-text-muted);
        font-size: 0.85rem;
    }

    .sidebar-check input {
        margin: 0;
        width: auto;
    }

    .sidebar-clear {
        margin: 0;
        padding: 0.5rem 0.75rem;
        border-bottom: 1px solid var(--color-border);
        font-size: 0.8rem;
    }

    .sidebar-list {
        list-style: none;
        margin: 0;
        padding: 0.35rem 0;
        /* Only this scrolls, so the search box and the foot stay put however
           long the list gets. */
        flex: 1;
        min-height: 0;
        overflow-y: auto;
    }

    .sidebar-row a {
        display: flex;
        align-items: baseline;
        justify-content: space-between;
        gap: 0.5rem;
        padding: 0.35rem 0.75rem;
        color: var(--color-text);
        font-size: 0.9rem;
    }

    .sidebar-row a:hover {
        background: var(--color-bg);
        text-decoration: none;
    }

    .sidebar-name {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    /* The number that makes the sidebar worth having open: who owes you, at a
       glance, without opening anybody. */
    .sidebar-balance {
        flex-shrink: 0;
        color: var(--color-badge-warning-text);
        font-size: 0.75rem;
        font-weight: 600;
    }

    .sidebar-row.is-selected a {
        background: var(--color-bg);
        font-weight: 600;
        box-shadow: inset 3px 0 0 var(--color-primary);
    }

    .sidebar-none {
        margin: 0;
        padding: 0.75rem;
        color: var(--color-text-muted);
        font-size: 0.85rem;
    }

    .sidebar-foot {
        display: flex;
        flex-direction: column;
        gap: 0.3rem;
        padding: 0.6rem 0.75rem;
        margin-top: auto;
        border-top: 1px solid var(--color-border);
        font-size: 0.85rem;
    }

    /* Search sits above the filters and gets the same compact treatment as
       the select next to it. */
    .sidebar-filters input[type="search"] {
        width: 100%;
        margin: 0;
        padding: 0.3rem 0.45rem;
        font-size: 0.85rem;
    }

    .sidebar-selected {
        display: flex;
        flex-direction: column;
        gap: 0.2rem;
        padding: 0.5rem 0.75rem;
        border-bottom: 1px solid var(--color-border);
        font-size: 0.8rem;
    }

    .sidebar-deselect {
        color: var(--color-text-muted);
    }

    /* Folded away: the head stays as the handle to bring it back, so the
       agenda needs no special case and any page can have the full width. */
    .sidebar.is-collapsed {
        width: 2.9rem;
    }

    .sidebar.is-collapsed .sidebar-body,
    .sidebar.is-collapsed .sidebar-title {
        display: none;
    }

    .sidebar.is-collapsed .sidebar-head {
        border-bottom: none;
        padding: 0.5rem;
        justify-content: center;
    }

    .sidebar.is-collapsed .sidebar-toggle span[aria-hidden] {
        transform: rotate(180deg);
    }
}

@media print {
    .site-header, .site-footer, .no-print {
        display: none !important;
    }

    .container {
        max-width: 100%;
        padding: 0;
    }

    .card, .list-item {
        break-inside: avoid;
        box-shadow: none;
    }
}
