/* ─────────────────────────────────────────────────────────────────────
 * Census — Saint Joseph Home for the Aged
 * Sober slate-blue / cream palette suited for a religious-sisters facility.
 * The on-screen UI may switch languages; the census grid and the print
 * output remain in English. Print rules at the bottom set landscape and
 * keep the legend on every page.
 * ───────────────────────────────────────────────────────────────────── */

:root {
    --paper:    #f7f2e6;
    --paper-2:  #ede5d0;
    --ink:      #2a2f3a;
    --ink-soft: #4a5163;
    --accent:   #3d4a5c;
    --accent-2: #6e7a90;
    --line:     #c8bda4;
    --line-2:   #a89b80;
    --rule:     #d6cdb6;
    --ok:       #4b6e3b;
    --warn:     #a35f1c;
    --error:    #9a2b2b;
}

*, *::before, *::after { box-sizing: border-box; }

html, body {
    margin: 0; padding: 0;
    background: var(--paper);
    color: var(--ink);
    font-family: 'Inter', system-ui, -apple-system, sans-serif;
    font-size: 15px;
    line-height: 1.45;
    min-height: 100vh;
}

h1, h2, h3, h4 {
    font-family: 'Cormorant Garamond', Georgia, serif;
    color: var(--accent);
    font-weight: 600;
    margin: 0 0 .4em;
}
h1 { font-size: 2.2rem; }
h2 { font-size: 1.55rem; }
h3 { font-size: 1.2rem;  }

a { color: var(--accent); text-decoration: underline; text-underline-offset: 2px; }
a:hover { color: var(--ink); }

.boot-screen { display: flex; align-items: center; justify-content: center; height: 100vh; color: var(--accent-2); }
.boot-mark { font-size: 4rem; opacity: .5; }

/* ─── shell ─── */
.app-root { min-height: 100vh; }
.app-shell {
    display: grid;
    grid-template-rows: auto 1fr auto;
    min-height: 100vh;
}
.header {
    background: var(--accent);
    color: var(--paper);
    padding: 1rem 1.5rem;
    display: flex; align-items: center; gap: 1.5rem;
    flex-wrap: wrap;
    border-bottom: 1px solid var(--line-2);
}
.header h1 { color: var(--paper); font-size: 1.4rem; margin: 0; font-weight: 600; }
.header .subtitle {
    font-size: .85rem; opacity: .8;
    font-family: 'Cormorant Garamond', Georgia, serif;
    font-style: italic;
}
.header .spacer { flex: 1; }

.nav {
    background: var(--paper-2);
    border-bottom: 1px solid var(--line);
    padding: .25rem 1.5rem;
    display: flex; gap: .5rem; flex-wrap: wrap;
}
.nav button {
    background: transparent; border: none; color: var(--ink-soft);
    padding: .6rem 1rem; font: inherit; cursor: pointer; border-radius: 4px;
}
.nav button:hover { background: var(--paper); color: var(--accent); }
.nav button.active {
    background: var(--paper); color: var(--accent); font-weight: 600;
    box-shadow: 0 -2px 0 var(--accent) inset;
}

main { padding: 1.5rem; max-width: 100%; overflow-x: auto; }
footer {
    background: var(--paper-2);
    border-top: 1px solid var(--line);
    padding: .75rem 1.5rem;
    font-size: .8rem;
    color: var(--ink-soft);
    text-align: center;
}

/* ─── hamburger ─── */
.hamburger { position: relative; }
.hamburger-btn {
    width: 2.5rem; height: 2.5rem;
    background: transparent;
    border: 1px solid var(--accent-2);
    border-radius: 4px;
    color: var(--paper);
    cursor: pointer;
    display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 4px;
    padding: 0;
}
.hamburger-btn span {
    display: block; width: 1.2rem; height: 2px;
    background: var(--paper); border-radius: 1px;
}
.hamburger-btn:hover { background: var(--accent-2); }
.hamburger-menu {
    position: absolute;
    top: calc(100% + .4rem);
    right: 0;
    min-width: 14rem;
    background: var(--paper);
    color: var(--ink);
    border: 1px solid var(--line);
    border-radius: 6px;
    box-shadow: 0 8px 24px rgba(0,0,0,.18);
    z-index: 50;
    padding: .25rem 0;
}
.hamburger-section {
    padding: .5rem .75rem;
    border-bottom: 1px solid var(--rule);
}
.hamburger-section:last-child { border-bottom: 0; }
.hamburger-label {
    font-size: .7rem; text-transform: uppercase; letter-spacing: .1em;
    color: var(--ink-soft);
    margin-bottom: .25rem;
}
.hamburger-user { display: flex; flex-direction: column; gap: .15rem; }
.hamburger-user .role {
    font-size: .7rem; color: var(--ink-soft);
    text-transform: uppercase; letter-spacing: .1em;
}
/* The selectors are deliberately nested under .hamburger-menu so they
   beat the generic `button:hover { background: var(--ink) }` rule on
   specificity. Without that the dropdown items invert to dark-on-dark
   on hover and the sign-out label disappears entirely. */
.hamburger-menu .hamburger-item {
    display: block; width: 100%; text-align: left;
    background: transparent; border: 0;
    padding: .4rem .5rem;
    font: inherit; cursor: pointer; color: var(--ink);
    border-radius: 4px;
}
.hamburger-menu .hamburger-item:hover  { background: var(--paper-2); color: var(--ink); }
.hamburger-menu .hamburger-item.active { background: var(--paper-2); font-weight: 600; color: var(--accent); }
.hamburger-menu .hamburger-item.danger { color: var(--error); background: transparent; }
.hamburger-menu .hamburger-item.danger:hover { background: #f3dada; color: var(--error); }

/* ─── login ─── */
.login-wrap {
    min-height: 100vh;
    display: flex; align-items: center; justify-content: center;
    padding: 2rem;
    background: linear-gradient(180deg, var(--paper) 0%, var(--paper-2) 100%);
}
.login-card {
    background: var(--paper);
    padding: 2.5rem;
    border: 1px solid var(--line);
    border-radius: 6px;
    max-width: 28rem; width: 100%;
    box-shadow: 0 6px 30px rgba(0,0,0,.08);
}
.login-card h1 { text-align: center; margin-bottom: .25rem; }
.facility-sub {
    text-align: center; color: var(--ink-soft); margin-bottom: 1.75rem;
    font-style: italic; font-family: 'Cormorant Garamond', Georgia, serif;
}
.login-ambiguous {
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: .75rem 1rem;
    margin-bottom: 1rem;
}
.login-ambiguous ul { margin: .5rem 0 0; padding-left: 1rem; }

/* ─── forms ─── */
label {
    display: block; font-size: .85rem; font-weight: 500;
    margin-bottom: .25rem; color: var(--ink-soft);
}
input[type=text], input[type=email], input[type=password], input[type=number], select, textarea {
    width: 100%;
    padding: .55rem .7rem;
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 4px;
    color: var(--ink);
    font: inherit;
}
input:focus, select:focus, textarea:focus {
    outline: 2px solid var(--accent-2);
    outline-offset: -1px;
    border-color: var(--accent-2);
}
.form-row  { margin-bottom: 1rem; }
.form-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(12rem, 1fr));
    gap: 1rem; margin-bottom: 1rem;
}

button, .btn {
    background: var(--accent); color: var(--paper);
    border: 1px solid var(--accent);
    padding: .55rem 1rem; font: inherit; border-radius: 4px;
    cursor: pointer;
}
button:hover, .btn:hover { background: var(--ink); border-color: var(--ink); }
button:disabled { opacity: .45; cursor: not-allowed; }
button.ghost {
    background: transparent; color: var(--accent);
    border: 1px solid var(--line);
}
button.ghost:hover { background: var(--paper-2); color: var(--ink); }
button.danger { background: var(--error); border-color: var(--error); }
button.danger:hover { background: #6f1e1e; border-color: #6f1e1e; }
button.small { padding: .3rem .6rem; font-size: .85rem; }

.flash {
    padding: .7rem 1rem; border-radius: 4px; margin-bottom: 1rem;
    border: 1px solid; position: relative;
}
.flash.error { background: #f3dada; color: #6f1e1e; border-color: #d49797; }
.flash.ok    { background: #dfe9d6; color: #355127; border-color: #a9c293; }
.flash.info  { background: var(--paper-2); color: var(--ink); border-color: var(--line); }
.flash-close { float: right; }

/* ─── tables ─── */
.table { width: 100%; border-collapse: collapse; background: var(--paper); border: 1px solid var(--line); }
.table th, .table td {
    padding: .55rem .7rem;
    border-bottom: 1px solid var(--rule);
    text-align: left;
    vertical-align: middle;
    font-size: .9rem;
}
.table thead th { background: var(--paper-2); color: var(--accent); font-weight: 600; border-bottom: 1px solid var(--line); }
.table tbody tr:hover td { background: var(--paper-2); }
.table .actions { text-align: right; white-space: nowrap; }

.card { background: var(--paper); border: 1px solid var(--line); border-radius: 6px; padding: 1.25rem 1.5rem; margin-bottom: 1.5rem; }
.card h2 { margin-top: 0; }

.page-title {
    display: flex; align-items: center; justify-content: space-between;
    gap: 1rem; margin-bottom: 1rem; flex-wrap: wrap;
}
.page-title h2 { margin: 0; }
.page-title .actions { display: flex; gap: .5rem; flex-wrap: wrap; align-items: center; }
/* Groups the page-title H2 with a primary action (e.g. "Add resident")
   so they always sit on the same row, with the filter toggles still
   free to wrap on their own. */
.title-with-add { display: flex; align-items: center; gap: .75rem; }

/* Resident-history page-title overrides .page-title's row layout so
   the back-button always sits on the first line (visible without
   scrolling, even when the resident name is long), and the name +
   Edit button sit on the second line — name on the left, Edit on
   the right. */
.history-title {
    flex-direction: column;
    align-items: stretch;
    gap: .35rem;
}
.history-title-back { display: flex; justify-content: flex-start; }
/* Back-link sitting above the page title on admin pages reached from
   the hamburger menu (Users / Settings / Audit). */
.page-back { margin-bottom: .75rem; }
.history-title-name {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: .75rem;
    flex-wrap: wrap;
}
.page-today {
    margin-left: auto;
    color: var(--ink-soft);
    font-size: .9rem;
    font-style: italic;
    align-self: center;
}

/* ─── month picker ─── */
.month-bar {
    display: flex; align-items: center; gap: 1rem; flex-wrap: wrap;
    margin-bottom: 1rem; padding: .75rem 1rem;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: 4px;
}
.month-bar select { width: auto; min-width: 12rem; }
.status-chip {
    padding: .2rem .6rem; border-radius: 999px; font-size: .75rem;
    text-transform: uppercase; letter-spacing: .1em;
    background: var(--paper); border: 1px solid var(--line);
}
.status-chip.open   { color: var(--ok);       border-color: var(--ok);   }
.status-chip.closed { color: var(--ink-soft); }

/* ─── census grid ─── */
.grid-wrap { overflow-x: auto; }
.census-grid {
    /* border-collapse: separate (not collapse) so position:sticky Room/
       Resident cells own their full border — collapsed borders are shared
       between neighbours, which causes the lines to misalign as day cells
       scroll under the sticky column. Every cell renders its right +
       bottom border; the leftmost column and the first thead row pick up
       the table's outer edges below. */
    border-collapse: separate;
    border-spacing: 0;
    width: 100%;
    font-size: .78rem;
    background: var(--paper);
    table-layout: fixed;
}
.census-grid col.col-room { width: 3.5rem; }
.census-grid col.col-name { width: 12rem;  }
.census-grid col.col-code { width: 1.6rem; }
.census-grid col.col-day  { width: 1.6rem; }
.census-grid col.col-doc  { width: 2.5rem; }
/* NY code headers also rotate on screen so the column is narrow there too. */
.census-grid th.code-header {
    padding: .1rem;
    vertical-align: bottom;
    height: 3.5rem;
}
.census-grid th.code-header .code-header-label {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    display: inline-block;
    white-space: nowrap;
    letter-spacing: .03em;
}

.census-grid th, .census-grid td {
    border-right:  1px solid var(--rule);
    border-bottom: 1px solid var(--rule);
    text-align: center;
    padding: .15rem .2rem;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
/* Outer edges: top border on the first thead row, left border on the
   leftmost column (Room header + each tbody row's first td). */
.census-grid > thead > tr:first-child > th { border-top: 1px solid var(--rule); }
.census-grid > thead > tr:first-child > th:first-child,
.census-grid > tbody > tr > td:first-child { border-left: 1px solid var(--rule); }

/* Group dividers — the heavier line moves to the right edge of the cell
   that comes BEFORE the divider, so it travels with the (sticky) name
   cell and degrades cleanly when NY codes are hidden:
     • th.name / td.name             → divides resident column from codes
     • last th.code-header / .code-cell → divides codes from days
   The rowspan=2 cells (name, code-header) carry the border down into
   the day-numbers row, so no separate row-2 rule is needed. */
.census-grid th.name,
.census-grid td.name,
.census-grid th.code-header:has(+ th:not(.code-header)),
.census-grid td.code-cell:has(+ td.day-cell) {
    border-right: 2px solid var(--accent);
}
.census-grid thead th {
    background: var(--paper-2);
    color: var(--accent);
    font-weight: 600;
    position: sticky;
    top: 0;
    z-index: 2;
}
.census-grid th.room, .census-grid th.name { text-align: left; padding-left: .5rem; }
.census-grid td.room { font-weight: 600; text-align: left; padding-left: .5rem; }
.census-grid td.name { text-align: left; padding-left: .5rem; }

/* Room + Resident columns stay pinned to the left while the operator
   scrolls horizontally through the days. The thead corner cells already
   stick to the top; combining sticky top + left makes them anchor at
   the corner with a higher z-index so they ride above both axes. The
   `left` offset on .name matches col-room's width (3.5rem). Sticky cells
   need an opaque background so day cells scrolling underneath don't
   show through — alt-row tint and the totals row each get their own
   opaque match below. */
.census-grid th.room,
.census-grid td.room {
    position: sticky;
    left: 0;
    z-index: 1;
    background: var(--paper);
}
.census-grid th.name,
.census-grid td.name {
    position: sticky;
    left: 3.5rem;
    z-index: 1;
    background: var(--paper);
}
.census-grid thead th.room,
.census-grid thead th.name { z-index: 3; background: var(--paper-2); }
.census-grid td.code-cell input {
    width: 100%; padding: .15rem; text-align: center;
    border: none; background: transparent;
    font: inherit; font-size: .85rem; text-transform: uppercase;
}
.census-grid td.code-cell input:focus { outline: 2px solid var(--accent-2); background: var(--paper-2); }
.census-grid td.day-cell.readonly { font-weight: 600; font-size: .85rem; }
.census-grid td.predicted { color: var(--accent-2); font-style: italic; font-weight: 500; }
/* Per-letter background colours come from <DayCodeStyles>, populated from
   the editable day_codes table. The dayofcare/alt rules stay static. */
.census-grid td.dayofcare { background: var(--paper-2); font-weight: 700; }
/* Pre-blended opaque equivalent of paper + rgba(0,0,0,.025) — needs to
   be opaque so sticky Room/Name cells stay solid over scrolled-under
   day cells. Visually identical to the previous tint. */
.census-grid tr.alt td { background: #f1ecdf; }
/* Heavier rule under every fifth resident — same convention as the
   printed DOH-5176 form so the on-screen layout reads in fives without
   counting individual rows. The totals row sits below and gets its
   own heavier top rule (see tr.totals-row), so they don't double up. */
.census-grid > tbody > tr:nth-child(5n):not(.totals-row) > td {
    border-bottom: 1.5px solid #555;
}
/* With border-collapse: separate the row above totals would stack its
   bottom border against the totals' heavier top border. Drop the row-
   above bottom so the totals divider stays a single dominant line —
   both the regular and the 5n variants. */
.census-grid > tbody > tr:has(+ tr.totals-row) > td,
.census-grid > tbody > tr:nth-child(5n):has(+ tr.totals-row):not(.totals-row) > td {
    border-bottom: 0;
}

/* ─── event recorder card ─── */
.event-recorder { background: var(--paper-2); padding-block: .65rem; }
.event-recorder.folded { padding-block: .4rem; margin-bottom: .75rem; }
.event-recorder.folded h3 { display: none; }
.event-recorder-toggle {
    background: transparent;
    border: none;
    color: var(--accent);
    font-family: 'Cormorant Garamond', Georgia, serif;
    font-size: 1.15rem;
    font-weight: 600;
    padding: .15rem 0;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}
.event-recorder-toggle:hover { background: transparent; color: var(--ink); }
.event-recorder-toggle .caret {
    display: inline-block;
    width: 1em; text-align: center;
    color: var(--accent-2);
}
.event-recorder-hint {
    color: var(--ink-soft);
    font-size: .85rem;
    margin-left: .75rem;
}

/* Future cells: blank, slightly dimmer background so it's clear the
   grid extends past the visible-data range. */
.census-grid td.day-cell.future {
    background: repeating-linear-gradient(
        45deg,
        transparent, transparent 3px,
        rgba(0,0,0,.04) 3px, rgba(0,0,0,.04) 6px
    );
}

/* ─── state badge ─── */
.state-badge {
    display: inline-block;
    min-width: 1.4em;
    padding: 0 .35em;
    border-radius: 3px;
    text-align: center;
    font-weight: 700;
    border: 1px solid var(--line);
    background: var(--paper-2);
}
/* Per-letter backgrounds come from <DayCodeStyles> (editable from Settings). */
.state-badge.predicted {
    font-style: italic;
    font-weight: 500;
    opacity: .8;
}
.state-badge.predicted::after {
    content: '*';
    color: var(--accent-2);
    font-weight: 700;
    margin-left: .15em;
}

/* ─── event history list ─── */
.event-list {
    max-height: 70vh;
    overflow-y: auto;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--paper);
}
.event-row {
    display: grid;
    grid-template-columns: 1fr auto 2fr auto;
    gap: 1rem;
    align-items: center;
    padding: .55rem .9rem;
    border-bottom: 1px solid var(--rule);
}
.event-row:last-child { border-bottom: 0; }
.event-when  { color: var(--ink); }
.event-who   { color: var(--ink-soft); font-size: .85rem; }
.event-status .state-badge { min-width: 1.6em; }

/* Totals row at the bottom of the grid: heavier top rule + bold to
   read as a summary line, but keep the alt-row tint off so day-code
   cells remain blank (no per-letter colour for a sum). */
.census-grid tr.totals-row td {
    border-top: 1.5px solid #333;
    font-weight: 700;
    background: var(--paper-2);
}
.census-grid tr.totals-row td.day-cell,
.census-grid tr.totals-row td.code-cell { text-align: center; }

/* Cross-hair selection over the grid. Clicking a cell highlights the
   whole row and the whole column with inset accent-coloured edges so
   the day-code background colour stays readable underneath. The
   intersection cell ends up with all four edges. Click the same cell
   again to clear (handled in JS). */
.census-grid td.day-cell,
.census-grid td.code-cell,
.census-grid td.dayofcare { cursor: pointer; }
.census-grid td.row-selected {
    box-shadow: inset 0 2px 0 var(--accent), inset 0 -2px 0 var(--accent);
}
.census-grid td.col-selected {
    box-shadow: inset 2px 0 0 var(--accent), inset -2px 0 0 var(--accent);
}
.census-grid td.row-selected.col-selected {
    box-shadow:
        inset 0 2px 0 var(--accent), inset 0 -2px 0 var(--accent),
        inset 2px 0 0 var(--accent), inset -2px 0 0 var(--accent);
}

/* Clickable resident name in the census grid — looks like text, behaves
   like a link to the event-history page. */
.row-name-link {
    background: transparent;
    border: 0;
    padding: 0;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}
.row-name-link:hover {
    background: transparent;
    color: inherit;
    text-decoration: underline;
}
.row-edit-btn {
    background: transparent;
    border: 0;
    padding: 0 .25rem;
    margin-left: .25rem;
    color: var(--ink-soft);
    font-size: .8rem;
    cursor: pointer;
    opacity: .55;
}
.row-edit-btn:hover {
    background: transparent;
    color: var(--accent);
    opacity: 1;
}

/* NY state-code checkboxes inside the resident-edit modal. Flex grid
   so AH / EHP / … each get their own row but still pack tight when the
   modal is wide. */
.resident-flags {
    display: flex;
    flex-wrap: wrap;
    gap: .25rem 1rem;
    padding: .25rem 0;
}
.resident-flag {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    font-size: .85rem;
}
.resident-flag input { width: auto; margin: 0; }

/* ─── legend (concise, sticky) ─── */
.legend {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: .35rem .75rem;
    font-size: .82rem;
}
.legend-section {
    display: flex; flex-wrap: wrap; gap: .15rem 1rem;
    align-items: center;
    padding: .15rem 0;
    border-bottom: 1px dotted var(--rule);
}
.legend-section:last-child { border-bottom: 0; }
.legend dt {
    display: inline-block;
    width: 1.3em; padding: 0 .15em;
    text-align: center; font-weight: 700;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: 3px;
    margin-right: .2em;
}
.legend-row { display: inline-flex; align-items: center; gap: .15em; }
.legend-foot { color: var(--ink-soft); font-size: .75em; margin-left: .25em; }

/* On screen the legend is hidden — the AH/EHP/… column headers carry
   their own tooltip, and the H/V/M/O/Y/E/R/N/D codes are part of the
   record-event dropdown's labels. The legend block is rendered only for
   the printout (see @media print below). */
.sticky-legend { display: none; }

/* Suppress iOS Safari's long-press callout (Copy / Look Up / Share) on
   tooltipped elements — it would interrupt the press-and-hold gesture
   that reveals our own tooltip. */
[data-tooltip] {
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}

/* ─── delegated cell tooltip layer ─── */
/* A single fixed-positioned bubble managed by <CellTooltipLayer/>. Any
   element with a [data-tooltip] attribute triggers it on hover (desktop)
   or tap (mobile, ~2.5s auto-hide). This avoids spinning up a React
   component per cell — important when the grid has ~1000 cells. */
.cell-tooltip {
    position: fixed;
    transform: translate(-50%, 0);
    background: var(--ink);
    color: var(--paper);
    padding: .4rem .65rem;
    border-radius: 4px;
    font-size: .82rem;
    font-weight: 500;
    line-height: 1.2;
    max-width: 80vw;
    text-align: center;
    z-index: 1100;
    box-shadow: 0 6px 18px rgba(0,0,0,.3);
    pointer-events: none;
    /* fade-in keeps touch users from feeling the bubble is jarring */
    animation: cell-tooltip-in 80ms ease-out;
}
.cell-tooltip.flip {
    transform: translate(-50%, -100%);
}
@keyframes cell-tooltip-in {
    from { opacity: 0; transform: translate(-50%, 4px); }
    to   { opacity: 1; }
}
@media (max-width: 700px) {
    .cell-tooltip { font-size: .9rem; padding: .5rem .75rem; }
}

/* Old per-instance tooltip styles, kept for the legacy <Tooltip>
   component (still used in a few non-cell places). */
.tooltip-wrap { position: relative; display: inline-block; }
.tooltip-bubble {
    position: absolute;
    top: calc(100% + .25rem);
    left: 50%;
    transform: translateX(-50%);
    background: var(--ink);
    color: var(--paper);
    padding: .35rem .55rem;
    border-radius: 4px;
    font-size: .75rem;
    font-weight: 500;
    white-space: nowrap;
    z-index: 30;
    box-shadow: 0 4px 14px rgba(0,0,0,.25);
    pointer-events: none;
}
.tooltip-bubble::before {
    content: '';
    position: absolute;
    top: -.3rem; left: 50%;
    transform: translateX(-50%);
    border: .3rem solid transparent;
    border-bottom-color: var(--ink);
}

/* ─── residents page (card grid) ─── */
.resident-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: .65rem;
}
.resident-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: .65rem .85rem;
    display: flex; flex-direction: column; gap: .25rem;
}
.resident-card.inactive { opacity: .55; }
.resident-card-head {
    display: flex; align-items: center; justify-content: space-between; gap: .5rem;
}
.resident-card-room {
    background: var(--paper-2);
    color: var(--accent);
    border: 1px solid var(--line);
    border-radius: 4px;
    padding: .15rem .55rem;
    font-weight: 700;
    font-size: .95rem;
    cursor: pointer;
}
.resident-card-room:hover { background: var(--line); color: var(--ink); }
.resident-card-name-row {
    display: flex; align-items: flex-start; gap: .35rem;
}
.resident-card-name {
    background: transparent;
    border: 0;
    text-align: left;
    color: var(--ink);
    font: inherit;
    padding: 0;
    cursor: pointer;
    word-break: break-word;
    flex: 1 1 auto;
}
/* The generic `button:hover` rule paints the bg dark and the text light;
   the name is a transparent text-link masquerading as a button, so we
   keep the bg transparent and just tint the link colour on hover. */
.resident-card-name:hover {
    background: transparent;
    color: var(--accent);
    text-decoration: underline;
}
.resident-card-edit {
    flex: 0 0 auto;
    background: transparent;
    border: 1px solid var(--line);
    color: var(--accent);
    padding: .1rem .4rem;
    font-size: .9rem;
    line-height: 1;
    border-radius: 4px;
    cursor: pointer;
}
.resident-card-edit:hover { background: var(--paper-2); color: var(--ink); }

/* Day-status chip filter on the Residents page. Off chips are pale
   so the active selection reads at a glance. */
.state-filter {
    display: flex; flex-wrap: wrap; align-items: center;
    gap: .35rem;
    margin: 0 0 .75rem;
}
.state-filter-chip {
    background: var(--paper-2);
    color: var(--accent);
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: .15rem .6rem;
    font: inherit;
    font-size: .8rem;
    font-weight: 700;
    letter-spacing: .03em;
    cursor: pointer;
    min-width: 1.8rem;
    line-height: 1.2;
}
.state-filter-chip:hover {
    background: var(--line);
    color: var(--ink);
    border-color: var(--line-2);
}
.state-filter-chip.on {
    background: var(--accent);
    color: var(--paper);
    border-color: var(--accent);
}
.state-filter-chip.on:hover {
    background: var(--ink);
    color: var(--paper);
    border-color: var(--ink);
}
/* Icon-style ✕ button to clear all state chips. Matches the size of
   the chips so the row reads as a single uniform strip. */
.state-filter-clear {
    background: transparent;
    color: var(--ink-soft);
    border: 1px solid var(--line);
    border-radius: 999px;
    padding: 0;
    width: 1.6rem; height: 1.6rem;
    line-height: 1;
    font-size: .85rem;
    cursor: pointer;
    margin-left: .25rem;
    display: inline-flex; align-items: center; justify-content: center;
}
.state-filter-clear:hover {
    background: var(--paper-2);
    color: var(--error);
    border-color: var(--line-2);
}
.resident-card-meta {
    color: var(--ink-soft); font-size: .8rem; min-height: 1em;
    display: flex; flex-direction: column; gap: .15rem;
}
/* NY-code letters the resident is flagged with (AH / EHP / …). */
.resident-card-flags {
    display: flex; flex-wrap: wrap; gap: .25rem;
    margin-top: .1rem;
}
.resident-card-flag {
    display: inline-block;
    padding: .05rem .4rem;
    font-size: .72rem;
    font-weight: 700;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: 999px;
    color: var(--accent);
    letter-spacing: .03em;
}
/* Per-user "hide NY codes on screen" toggle: collapses the resident-
   card chips and the AH/EHP columns on the screen census grid. The
   census-grid uses table-layout: fixed, so visibility:collapse on the
   <col> drops both header and body cells in one rule. The DOH-5176
   print form (.doh-form) renders independently, so print output keeps
   the codes regardless. */
body.hide-state-codes .resident-card-flags { display: none; }
body.hide-state-codes .census-grid col.col-code { visibility: collapse; }
/* Non-Y day-status counts in the currently open census. */
.resident-card-summary {
    display: flex; flex-wrap: wrap; gap: .25rem .5rem;
    font-size: .78rem;
}
.resident-card-stat { display: inline-flex; align-items: center; gap: .2rem; }
.resident-card-stat .state-badge {
    min-width: 1.3em;
    font-size: .78rem;
    padding: 0 .3em;
}
.resident-card-stat-n { color: var(--ink-soft); }
.resident-card-actions {
    margin-top: .25rem; display: flex; gap: .35rem; justify-content: flex-end; flex-wrap: wrap;
}

/* ─── code cards (day codes + state codes) ─── */
.code-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr));
    gap: .65rem;
}
.code-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: .7rem .9rem;
    display: flex; flex-direction: column; gap: .3rem;
}
.code-card.inactive { opacity: .6; }
.code-card-head {
    display: flex; align-items: center; justify-content: space-between; gap: .5rem;
}
.code-card-letter {
    display: inline-block;
    min-width: 1.8rem;
    padding: 0 .5rem;
    text-align: center;
    background: var(--paper-2);
    border: 1px solid var(--line);
    border-radius: 4px;
    font-weight: 700;
    color: var(--accent);
    font-size: .95rem;
}
.code-card-next {
    display: inline-flex;
    align-items: center;
    gap: .25rem;
    color: var(--ink-soft);
    font-size: .9rem;
}
.code-card-flags { display: flex; flex-wrap: wrap; gap: .25rem; justify-content: flex-end; margin-left: auto; }
.code-flag {
    font-size: .65rem; text-transform: uppercase; letter-spacing: .08em;
    padding: .1rem .45rem; border-radius: 999px;
    background: var(--paper-2); color: var(--ink-soft);
    border: 1px solid var(--line);
}
.code-flag.flag-counts   { color: var(--ok);    border-color: #a9c293; background: #e8efd9; }
.code-flag.flag-terminal { color: var(--error); border-color: #d49797; background: #f3dada; }
.code-flag.flag-single   { color: var(--warn);  border-color: #d4b283; background: #f1e6c6; }
.code-flag.flag-muted    { color: var(--ink-soft); }
.code-card-label   { font-weight: 600; color: var(--accent); }
.code-card-comment { color: var(--ink-soft); font-size: .85rem; }
.code-card-actions {
    margin-top: auto; padding-top: .25rem;
    display: flex; gap: .35rem; justify-content: flex-end; flex-wrap: wrap;
}

/* ─── users page (card grid) ─── */
.user-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
    gap: .8rem;
}
.user-card {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: .85rem 1.1rem;
    display: flex;
    flex-direction: column;
    gap: .35rem;
}
.user-card.inactive { opacity: .55; }
.user-card-head {
    display: flex; align-items: center; justify-content: space-between; gap: .5rem;
}
.user-card-name {
    font-weight: 600; font-size: 1.05rem; color: var(--accent);
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.user-card-self { color: var(--ink-soft); font-style: italic; font-weight: 400; }
.user-card-body { display: flex; flex-direction: column; gap: .15rem; }
.user-card-fullname { font-size: .95rem; }
.user-card-email    { font-size: .85rem; color: var(--ink-soft); }
.user-card-email.muted { color: var(--line-2); }
.user-card-meta     { font-size: .8rem;  color: var(--ink-soft); }
.user-card-meta.muted { color: var(--line-2); }
.user-card-needsetup {
    font-size: .8rem; font-weight: 600;
    color: var(--warn);
    background: #f1e6c6;
    border: 1px solid #c8b683;
    border-radius: 3px;
    padding: .15rem .5rem;
    margin-top: .15rem;
    align-self: flex-start;
}
.user-card-actions {
    margin-top: .35rem;
    display: flex; gap: .35rem; justify-content: flex-end; flex-wrap: wrap;
}

.role-pill {
    font-size: .68rem; text-transform: uppercase; letter-spacing: .08em;
    padding: .15rem .55rem; border-radius: 999px;
    background: var(--paper-2); color: var(--accent);
    border: 1px solid var(--line);
    white-space: nowrap;
}
.role-pill.role-superuser { background: var(--accent); color: var(--paper); border-color: var(--accent); }
.role-pill.role-censor    { background: #e3e9d2; color: var(--ok); border-color: #b9c899; }
.role-pill.role-viewer    { background: var(--paper-2); color: var(--ink-soft); }

/* Small explanatory text under a form field — used in modals where the
   field labels themselves are kept terse. */
.form-hint {
    color: var(--ink-soft);
    font-size: .78rem;
    line-height: 1.3;
    margin-top: .2rem;
}

/* Print-only span counterpart to .no-print: shown only in print so the
   on-screen version can be in the operator's language while the printout
   stays English. */
.print-only { display: none; }
@media print { .print-only { display: inline; } }

/* ─── idle-timeout warning ─── */
.idle-warning-overlay {
    position: fixed; inset: 0;
    background: rgba(20, 24, 32, 0.55);
    display: flex; align-items: center; justify-content: center;
    z-index: 1500;
    padding: 1rem;
}
.idle-warning {
    background: var(--paper);
    border: 1px solid var(--warn);
    border-radius: 8px;
    padding: 1.5rem 2rem;
    max-width: 22rem; text-align: center;
    box-shadow: 0 8px 30px rgba(0,0,0,.4);
}
.idle-warning h3 { color: var(--warn); margin: .25rem 0; }
.idle-warning-count {
    font-size: 3.5rem;
    font-weight: 700;
    color: var(--error);
    line-height: 1;
    font-family: 'Cormorant Garamond', Georgia, serif;
}

/* ─── modal ─── */
.modal-wide { max-width: 38rem; }
.modal-overlay {
    position: fixed; inset: 0;
    background: rgba(20,24,32,.55);
    z-index: 1000;
    display: flex; align-items: center; justify-content: center;
    padding: 1rem;
}
.modal {
    background: var(--paper);
    border: 1px solid var(--line);
    border-radius: 6px;
    padding: 1.5rem;
    max-width: 32rem; width: 100%;
    box-shadow: 0 8px 30px rgba(0,0,0,.25);
    max-height: 90vh; overflow-y: auto;
}
.modal h3 { margin-top: 0; color: var(--accent); }
.modal-body { margin-bottom: 1.25rem; color: var(--ink); }
.modal-body p:first-child { margin-top: 0; }
.modal-body ul { padding-left: 1.25rem; }
.modal-actions {
    display: flex; gap: .5rem; justify-content: flex-end;
}

.grid-hidden-hint {
    background: var(--paper-2);
    border: 1px dashed var(--line);
    color: var(--ink-soft);
    padding: .4rem .75rem;
    border-radius: 4px;
    margin-bottom: .5rem;
    font-size: .85rem;
}

/* ─── print: official NY DOH-5176 layout ────────────────────────────
   Page is letter landscape with thin margins. Each DOH form page is a
   self-contained table — 20 residents apiece — and gets its own page
   break. The screen layout (.grid-wrap inside CensusGrid) is hidden in
   print; the .doh-form block takes over. */
@page {
    size: landscape;
    margin: 0.3in;
}

/* The DOH form is print-only by default; .print-only flips it on at
   @media print below. */
.doh-form { display: none; }

/* ─── events log (print + on-screen overlay preview) ────────────────
   The events content is styled ONCE here (shared by the overlay preview
   and the printout) so the two never disagree. Hidden by default; the
   .print-overlay reveals it on screen and @media print reveals it on
   paper. Only ONE of .doh-form / .events-print is ever mounted (the
   census grid renders whichever printMode picks), so there's nothing
   for the browser to mis-snapshot. Sizes use pt/in — fine on screen
   (1pt≈1.33px, 1in=96px) and exact on paper. */
.events-print {
    display: none;
    font-family: Georgia, 'Times New Roman', serif;
    color: #000;
    font-size: 11pt;
    line-height: 1.35;
}
.events-print-header {
    text-align: center;
    border-bottom: 1.5pt solid #000;
    padding-bottom: .1in;
    margin-bottom: .18in;
}
.events-print-facility { font-size: 10pt; }
.events-print-title { font-size: 14pt; margin: .05in 0 0; font-weight: 700; }
.events-print-title-range {
    font-size: 10pt; font-weight: 400; color: #444;
    margin-left: .2in;
}
.events-print-day { margin-bottom: .12in; }
.events-print-day-title {
    font-size: 11pt; font-weight: 700; margin: 0 0 .04in;
    border-bottom: .5pt solid #666;
}
.events-print-day-note {
    font-size: 9pt; font-style: italic; color: #444; margin: 0 0 .06in;
}
.events-print-list { list-style: disc; margin: 0; padding-left: .28in; }
.events-print-list li { margin: .01in 0; }
.events-print-empty { font-style: italic; color: #444; }

/* On-screen preview overlay (shared by census + events printing). Covers
   the app so the operator reviews the document, then prints from its own
   button (a real tap gesture — the only thing mobile Safari/Chrome
   reliably honour). The DOM never changes during the print/Save flow; it
   reverts only when they tap Done. */
.print-overlay {
    position: fixed;
    inset: 0;
    z-index: 60;
    background: #fff;
    overflow: auto;
    padding: 1.5rem;
}
.print-overlay-bar {
    position: sticky;
    top: 0;
    display: flex;
    gap: .5rem;
    justify-content: flex-end;
    background: #fff;
    padding-bottom: 1rem;
    margin-bottom: .5rem;
    border-bottom: 1px solid var(--line);
}
/* Reveal each print document inside the overlay for on-screen preview
   (both are display:none by default so they never show in the normal
   views). */
.print-overlay .events-print {
    display: block;
    max-width: 7.5in;
    margin: 0 auto;
}
.print-overlay .doh-form { display: block; }
/* The DOH form is landscape and wide; let it scroll horizontally within
   the overlay on narrow screens rather than squashing. */
.print-overlay-doh { overflow-x: auto; }

/* ─── DOH-5176 census form: visual styling ──────────────────────────
   These rules describe how the form LOOKS and are shared by the print
   output and the on-screen overlay preview. They live in base CSS (not
   @media print) but are inert in normal views because .doh-form is
   display:none there — only the overlay and @media print reveal it. The
   pagination-only bits (@page, page-breaks, wrapper collapsing) stay in
   @media print below. Sizes use pt/in: exact on paper, close enough for
   the screen preview. */
.doh-form-page {
    font-size: 8pt;
    line-height: 1.15;
    color: #000;
}

/* Top banner: agency on the left, full report title on the right. */
.doh-form-banner {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    border-bottom: 1.5pt solid #000;
    padding-bottom: .08in;
    margin-bottom: .06in;
}
.doh-form-agency-main { font-size: 8pt; font-weight: 700; }
.doh-form-agency-sub  { font-size: 8pt; }
.doh-form-title { font-size: 13pt; font-weight: 700; text-align: right; }

/* The two field rows below the banner. Each "field" is label +
   underlined value, like the printed form. */
.doh-form-fields {
    display: flex;
    gap: .35in;
    font-size: 8pt;
    margin-bottom: .04in;
}
.doh-form-field { display: flex; align-items: baseline; gap: .08in; flex: 0 1 auto; }
.doh-form-field-wide { flex: 1 1 auto; }
.doh-form-field-label { font-weight: 700; white-space: nowrap; }
.doh-form-field-value {
    flex: 1; min-width: 1.2in;
    border-bottom: 0.5pt solid #000;
    padding: 0 .05in;
    white-space: nowrap;
}

/* The grid: room, name, level-of-care (6 cols), 31 day cols, DoC. */
.doh-form-grid {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
    font-size: 6.5pt;
    line-height: 1.05;
    /* Outer box matches the printed DOH-5176 — heavier than the
       hairline cell rules so the form reads with the same visual
       weight as the paper version. */
    border: 1.5pt solid #000;
}
.doh-form-grid col.doh-col-room { width: 0.55in; }
.doh-form-grid col.doh-col-name { width: 1.85in; }
.doh-form-grid col.doh-col-code { width: 0.18in; }
.doh-form-grid col.doh-col-day  { width: 0.19in; }
.doh-form-grid col.doh-col-doc  { width: 0.40in; }

.doh-form-grid th, .doh-form-grid td {
    border: 0.5pt solid #000;
    padding: 1pt 2pt;
    vertical-align: middle;
    overflow: hidden;
}

/* Heavier vertical dividers between the major column groups:
   Room | Name | Level of Care | Date | Days of Care. Marked
   !important because the cell baseline rule above (`border: 0.5pt`)
   wins specificity ties on the right edge of the neighboring cell
   under border-collapse, and we want the heavy line to come through
   regardless of which side of the shared edge set it. */
.doh-form-grid td.doh-name + td.doh-code,
.doh-form-grid td.doh-code + td.doh-day,
.doh-form-grid td.doh-day + td.doh-doc,
.doh-form-grid td.doh-day + td.doh-doc-head,
.doh-form-grid th.doh-vert + th:not(.doh-vert),
.doh-form-grid > thead > tr:first-child > th.doh-group-header,
.doh-form-grid > thead > tr:first-child > th.doh-col-doc-head,
.doh-form-grid > thead > tr > th.doh-vert:first-child,
.doh-form-grid > tfoot > tr > td.doh-occupied-spacer + td.doh-day,
.doh-form-grid > tfoot > tr > td.doh-occupied-caption + td.doh-day {
    border-left: 1.5pt solid #000 !important;
}
/* Heavier horizontal divider between thead and tbody — both the
   day-number row and the rowspan'd Room/Name/DoC cells need a
   thick bottom edge. */
.doh-form-grid > thead > tr:last-child > th { border-bottom: 1.5pt solid #000 !important; }
.doh-form-grid > thead > tr:first-child > th[rowspan] { border-bottom: 1.5pt solid #000 !important; }
/* And between tbody and tfoot (the Occupied block). */
.doh-form-grid > tbody > tr:last-child > td { border-bottom: 1.5pt solid #000 !important; }

/* Every fifth resident gets a heavier bottom rule, matching the
   printed DOH-5176 form — makes 20-row blocks easy to scan in
   fives without counting individual cells. We paint BOTH sides of
   the boundary (row 5's bottom and row 6's top) because Chrome's
   collapsed-border picker has been known to lose the 1.25pt vs
   0.5pt fight at print resolution and render the lighter edge. */
.doh-form-grid > tbody > tr:nth-child(5n) > td {
    border-bottom: 1.75pt solid #000 !important;
}
.doh-form-grid > tbody > tr:nth-child(5n+1) > td {
    border-top: 1.75pt solid #000 !important;
}
/* Row 1 is also nth-child(5n+1); restore its hairline top so we
   don't get a doubled thead/body divider. */
.doh-form-grid > tbody > tr:first-child > td {
    border-top: 0.5pt solid #000 !important;
}
.doh-form-grid thead th { background: #eee; font-weight: 700; }
.doh-form-grid .doh-group-header { padding: 1pt 3pt; }
.doh-form-grid .doh-group-title { font-size: 7.5pt; font-weight: 700; line-height: 1.05; }
.doh-form-grid .doh-group-sub   { font-size: 5.5pt; font-weight: 400; line-height: 1.05; color: #333; }

/* Vertically rotated NY-code header labels (AH / EHP / ALR / …). */
.doh-form-grid th.doh-vert { padding: 1pt 0; vertical-align: bottom; }
.doh-form-grid th.doh-vert span {
    writing-mode: vertical-rl;
    transform: rotate(180deg);
    display: inline-block;
    font-size: 6.5pt;
    white-space: nowrap;
    letter-spacing: .02em;
}

.doh-form-grid td.doh-room { text-align: center; font-size: 7.5pt; }
.doh-form-grid td.doh-name {
    font-size: 7.5pt;
    white-space: nowrap;
    text-overflow: ellipsis;
    padding-left: 3pt;
}
.doh-form-grid td.doh-code,
.doh-form-grid td.doh-day,
.doh-form-grid td.doh-doc { text-align: center; font-size: 7.5pt; }
.doh-form-grid td.doh-doc { font-weight: 700; }
/* Absences/exceptions (any day that isn't a plain present 'Y') print
   bold for visibility. Font-size and line-height are unchanged and the
   column is a fixed width (table-layout: fixed), so the weight change
   doesn't alter the cell's height or width. */
.doh-form-grid td.doh-day-alert { font-weight: 700; }

/* Empty pad rows still draw the cell borders so 20 boxes always
   show on the page. */
.doh-form-grid tr.doh-pad td { height: 11pt; }

/* Footer: "Occupied 11:59 p.m. Today" block. The header row above
   repeats the 1..31 day numbers and adds a Total cell. */
.doh-form-grid tfoot tr.doh-occupied-hdr td.doh-occupied-spacer { border: 0; }
.doh-form-grid tfoot tr.doh-occupied td.doh-occupied-caption {
    text-align: center;
    font-weight: 700;
    font-size: 7.5pt;
}
.doh-form-grid tfoot td { background: #f4f4f4; }

.doh-form-footnote {
    margin-top: .04in;
    font-size: 6.5pt;
    color: #555;
}

@media print {
    body { background: white; }
    .header, .nav, footer, .month-bar, .page-title, .card,
    .no-print, button, .hamburger, .flash { display: none !important; }

    /* Print the overlay's content; the overlay wrapper collapses to a
       plain flowing block (its fixed positioning / padding would
       otherwise interfere with pagination). */
    .print-overlay,
    .print-overlay-doh {
        position: static;
        overflow: visible;
        padding: 0;
        background: transparent;
        z-index: auto;
    }
    .events-print { display: block; }
    .events-print-day { page-break-inside: avoid; }

    /* Collapse every wrapper to content height so we don't reserve a
       full-viewport block during print. */
    html, body, .app-root {
        min-height: 0 !important;
        height: auto !important;
        margin: 0; padding: 0;
        overflow: visible !important;
    }
    .app-shell {
        display: block !important;
        min-height: 0 !important;
        height: auto !important;
        padding: 0;
    }
    main { padding: 0; min-height: 0 !important; height: auto !important; }

    /* DOH form: display + pagination only. Its visual styling lives in
       base CSS above (shared with the on-screen overlay preview). */
    .doh-form { display: block; }
    .doh-form-page {
        page-break-inside: avoid;
        page-break-after: always;
    }
    .doh-form-page:last-child { page-break-after: auto; }
}

/* ─── small screens ─── */
@media (max-width: 700px) {
    /* Header: keep the title and hamburger on the first row at fixed
       height; flow the subtitle (facility / cert) onto a second row so
       a long certificate string can't push the hamburger down or out. */
    .header {
        padding: .55rem .85rem;
        align-items: flex-start;
        column-gap: .5rem;
        row-gap: .15rem;
        flex-wrap: wrap;
    }
    .header > div:first-child {
        flex: 1 1 calc(100% - 3rem);
        min-width: 0;
    }
    .header h1 {
        font-size: 1rem;
        line-height: 1.15;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
    .header .subtitle {
        font-size: .72rem;
        line-height: 1.2;
        white-space: normal;
        order: 3;
        flex-basis: 100%;
    }
    .header .spacer { display: none; }
    .header .hamburger { margin-left: auto; flex: 0 0 auto; }

    /* On phones the page is often opened with a restored scroll
       position (or with the iOS URL bar collapsing on first scroll),
       which pushes the top bar above the viewport. Pin the wrapper
       around the header + page-tab nav so both stay reachable
       regardless of scroll state. */
    .topbar {
        position: sticky;
        top: 0;
        z-index: 40;
        background: var(--accent);
    }

    main { padding: 1rem; }
    .login-card { padding: 1.5rem; }
    /* Drop the page-footer on small screens — the facility name + cert is
       already in the header / hamburger user card, and the bar steals
       vertical space on phones. */
    footer { display: none; }
}
