:root {
    /* Warm & trustworthy palette — teal accent on warm paper, no gradients.
       Variable names are kept stable so every component picks up the new
       values; semantic aliases (--bg/--surface/--border/--text/--muted) are
       provided for new code. */
    --primary: #2F8F83;          /* teal — primary actions */
    --primary-light: #DCECE9;    /* soft teal tint (backgrounds) */
    --primary-dark: #256F66;     /* teal hover/pressed */
    --secondary: #3D9A6D;        /* warm green — "signed in" / success */
    --secondary-light: #CDE8DA;
    --secondary-dark: #2E7D57;
    --success: #3D9A6D;
    --success-dark: #2E7D57;
    --warning: #E0863A;          /* amber */
    --danger: #C6553B;           /* warm terracotta — sign-out / delete */
    --dark: #2B2A28;             /* warm near-black text */
    --gray: #6F6B64;             /* warm muted text */
    --light-gray: #EFEBE4;       /* warm light surface */
    --light: #FBFAF7;

    /* Semantic aliases */
    --bg: #F7F5F1;               /* warm paper page background */
    --surface: #FFFFFF;          /* cards */
    --border: #E7E2DA;           /* hairline borders */
    --text: #2B2A28;
    --muted: #6F6B64;

    /* --- Text-safe partners for the brand hues (WCAG AA pass) --------------
       --primary / --secondary / --success / --warning / --danger above are
       BRAND hues. They are sized for borders, icon fills and left-rails, where
       WCAG only asks 3:1 (SC 1.4.11). They are NOT dark enough to carry text:
       white on --primary is 3.91:1 and white on --secondary is 3.48:1, both
       short of the 4.5:1 body-text floor.

       RULE: --warning (#E0863A) is a BACKGROUND / BORDER colour only and must
       never carry text, and must never sit under white text. White on it is
       2.75:1 and it is 2.31:1 on --light-gray. Use --warning-strong when amber
       must be a surface under white text, --warning-text when amber must be
       the text. The same discipline applies to the other brand hues below.

       Every ratio here was measured with the WCAG 2.x relative-luminance
       formula and is locked in by tests/test_contrast.py. */
    --primary-strong: #256F66;    /* teal surface/foreground that may carry text: white on it 5.93:1, and 5.93:1 on white. Deliberately the same value as --primary-dark; kept as its own name so "safe for text" is greppable. */
    --primary-stronger: #1C554E;  /* hover/pressed for --primary-strong surfaces: white on it 8.54:1 */
    --success-strong: #2E7D57;    /* green surface under white text: 5.02:1. Same value as --success-dark / --secondary-dark. */
    --success-stronger: #20563B;  /* hover for --success-strong: white on it 8.55:1 */
    --danger-strong: #A8432E;     /* terracotta surface under white text: 5.99:1, and 5.99:1 as text on white */
    --danger-stronger: #8E3826;   /* hover for --danger-strong: white on it 7.65:1 */
    --warning-strong: #96530F;    /* the ONLY amber that may sit under white text: 5.93:1 */
    --warning-text: #92400E;      /* amber as TEXT: 7.09:1 on --surface, 5.97:1 on --light-gray, 6.17:1 on the 15% amber tint */

    /* Foregrounds for the soft tint chips/badges. The tints are the brand hue
       composited over white, so a foreground has to be much darker than the
       hue itself; using the hue directly is what put "Signed In" and
       "Signed Out" below AA. */
    --on-tint-green: #245F42;     /* 6.41:1 on the 15% green tint (#E2F0E9); 5.79:1 on --secondary-light */
    --on-tint-red: #9A3D28;       /* 5.87:1 on the 12% red tint (#F8EBE7) */
    --on-tint-gray: #57534B;      /* 6.54:1 on the 12% gray tint (#EEEDEC); white on it 7.65:1 */

    /* Batch 3 (i): the kiosk home's yellow reminder line. Dark text on it:
       --dark is 14.5:1 on --reminder-yellow. */
    --reminder-yellow: #FFF3BF;
    --reminder-yellow-border: #E5C33F;

    --border-radius: 10px;
    --box-shadow: 0 1px 2px rgba(43, 42, 40, 0.04), 0 2px 8px rgba(43, 42, 40, 0.06);
}

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

/* Plain text links ("Forgot your password?", "Return home", an account name
   in a table) had no colour at all and rendered in the browser's default
   #0000EE — the one saturated blue on a warm teal-on-paper page. Classed links
   (.menu-button, .back-button, the button classes) set their own colour; no
   a:hover here, because its specificity would beat theirs. */
a {
    color: var(--primary-strong);   /* 5.93:1 on white, 5.44:1 on --bg */
}

.container {
    max-width: 1200px;
    margin: 0 auto;
    padding: 20px;
}

h1, h2, h3, h4, h5, h6 {
    margin-top: 0;
    color: var(--dark);
}

/* A page-level section heading needs air above it. With margin-top: 0 above,
   "Invite a guardian", "Change your password" and the like sat flush against
   the table or button of the previous section and read as part of it. Only
   headings that follow something on the page itself, so a heading opening a
   card is unaffected. */
.container > * + h2,
.container > * + h3 {
    margin-top: 32px;
}

/* Authentication styles */
.auth-container {
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 80vh;
}

.auth-box {
    background-color: white;
    border-radius: var(--border-radius);
    padding: 30px;
    width: 100%;
    max-width: 400px;
    box-shadow: var(--box-shadow);
}

.auth-box h2 {
    margin-bottom: 20px;
    text-align: center;
}

/* The sign-in page's one heading is its <h1> (one h1 per page), drawn the
   size the old <h2> was. */
.auth-box h1 {
    margin-bottom: 20px;
    text-align: center;
    font-size: 1.5em;
}

.alert {
    padding: 10px 15px;
    border-radius: var(--border-radius);
    margin-bottom: 20px;
}

.alert-danger {
    background-color: rgba(198, 85, 59, 0.12);
    color: var(--on-tint-red);   /* was --danger on its own tint: 3.78:1 -> 5.87:1 */
    border: 1px solid rgba(198, 85, 59, 0.12);
}

/* Menu Buttons */
.button-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 20px;
}

.menu-button {
    display: flex;
    flex-direction: column;
    background-color: var(--surface);
    padding: 24px;
    min-height: 108px;
    border: 1px solid var(--border);
    border-left: 5px solid var(--border);
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow);
    transition: transform 0.15s, box-shadow 0.15s, border-left-color 0.15s;
    text-decoration: none;
    color: var(--dark);
}

.menu-button:hover {
    transform: translateY(-3px);
    border-left-color: var(--primary);
    box-shadow: 0 10px 18px -6px rgba(43, 42, 40, 0.14);
}

.menu-button i {
    font-size: 26px;
    margin-bottom: 12px;
}

.menu-button-title { font-weight: 600; font-size: 1.05rem; }
.menu-button-sub { font-size: 0.9rem; color: var(--muted); margin-top: 4px; }

/* Main-menu top bar */
.menu-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    margin-bottom: 24px;
}
.menu-title { margin: 0; font-size: 1.6rem; }
.menu-subtitle { margin: 2px 0 0; color: var(--muted); }
.logout-link {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 48px;   /* a tablet target (Batch 2: it was 46px) */
    box-sizing: border-box;
    text-decoration: none;
    color: var(--dark);
    font-weight: 500;
    padding: 10px 16px;
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    background-color: var(--surface);
    transition: border-color 0.15s, color 0.15s;
}
/* Text goes to --danger-strong (5.99:1); the border may stay on the brand
   --danger, which only owes 3:1 as a non-text indicator. */
.logout-link:hover { color: var(--danger-strong); border-color: var(--danger); }

/* Form elements */
/* Browsers do not let form controls inherit the page font, so every date
   heading, nav button and search box rendered in the platform default (Arial
   on the tablet) beside Segoe UI text. */
button, input, select, textarea {
    font-family: inherit;
}

input, select, textarea {
    /* border-box: the width below is meant to INCLUDE the padding and border.
       Under the default content-box every full-width field was 26px wider than
       its column (54px for the padded search boxes), which ran the kiosk search
       bar off the right edge and scrolled the whole page sideways. */
    box-sizing: border-box;
    width: 100%;
    padding: 12px;
    margin-bottom: 15px;
    border: 1px solid #D8D2C8;
    border-radius: var(--border-radius);
    font-size: 16px;
    transition: border-color 0.3s;
}

/* The full-width rule above is for text fields. A tick box that inherits it
   is centred alone on a line of its own, a full row away from the label it
   belongs to (API key scopes, webhook events, "keep forever"). Components that
   style their own box (.switch, .custom-checkbox, .meal-checkbox) come later
   and still win. */
input[type="checkbox"],
input[type="radio"] {
    width: auto;
    padding: 0;
    margin: 0 8px 0 0;
    vertical-align: middle;
}

input:focus, select:focus, textarea:focus {
    outline: none;
    border-color: var(--primary);
    box-shadow: 0 0 0 3px rgba(47, 143, 131, 0.25);
}

.custom-select {
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='%236F6B64'%3E%3Cpath d='M7 10l5 5 5-5H7z'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 12px center;
    background-size: 16px;
}

textarea {
    min-height: 100px;
    resize: vertical;
}

label {
    display: block;
    margin-bottom: 8px;
    font-weight: 500;
    color: var(--dark);
}

.form-group {
    margin-bottom: 20px;
}

/* The button classes are also put on <a> links ("Go to my portal", "Search
   all forms"). A <button> is border-box by default and a link is not, so the
   same class gave a link 26px of extra height (its label sat at the top of a
   74px slab) and, with .btn-primary's width:100%, 40px of extra width that hung
   out of its card. A link also kept its underline. */
.btn-primary, .btn-secondary, .btn-danger {
    box-sizing: border-box;
}
a.btn-primary, a.btn-secondary, a.btn-danger, a.nav-button {
    text-decoration: none;
}

.btn-primary {
    /* --primary-strong, not --primary: white on the brand teal is 3.91:1,
       below the 4.5:1 needed for a 16px label. Now 5.93:1. */
    background-color: var(--primary-strong);
    color: white;
    border: none;
    padding: 13px 20px;
    min-height: 48px;
    border-radius: var(--border-radius);
    cursor: pointer;
    font-size: 16px;
    font-weight: 600;
    transition: background-color 0.15s, transform 0.05s;
    display: inline-block;
    text-align: center;
    width: 100%;
}

.btn-primary:hover {
    background-color: var(--primary-stronger);
}

.btn-primary:active { transform: translateY(1px); }

.btn-secondary {
    background-color: var(--surface);
    color: var(--dark);
    border: 1px solid #D8D2C8;
    padding: 13px 20px;
    min-height: 48px;
    border-radius: var(--border-radius);
    cursor: pointer;
    font-size: 16px;
    font-weight: 600;
    transition: background-color 0.15s, border-color 0.15s;
    display: inline-block;
    text-align: center;
}

.btn-secondary:hover {
    background-color: var(--light-gray);
    border-color: var(--muted);
}

/* The destructive twin of .btn-primary, for confirm-delete dialogs.
   `templates/manage_children.html` has always asked for `.btn-danger`, but only
   `.btn-danger-sm` was ever defined — so the button that permanently destroys a
   child's attendance history rendered as an unstyled browser default beside a
   fully-styled 48px Cancel. Geometry is .btn-secondary's (the Cancel it sits
   next to in .modal-footer, a flex row) rather than .btn-primary's, because
   .btn-primary carries width:100% and would push Cancel off the row. */
.btn-danger {
    background-color: var(--danger-strong);   /* white on it 5.99:1 */
    color: white;
    border: none;
    padding: 13px 20px;
    min-height: 48px;
    border-radius: var(--border-radius);
    cursor: pointer;
    font-size: 16px;
    font-weight: 600;
    transition: background-color 0.15s, transform 0.05s;
    display: inline-block;
    text-align: center;
}

.btn-danger:hover { background-color: var(--danger-stronger); }
.btn-danger:active { transform: translateY(1px); }

/* The keyboard focus ring lives in one place only, near the end of this file
   (search "Visible keyboard focus everywhere"). A duplicate teal rule used to
   sit here and was silently overridden by that later one, so every focus ring
   in the product rendered flat-UI blue. `.menu-button` is an <a>, so the
   `a:focus-visible` half of the surviving rule still covers it. */

.text-button {
    background: none;
    border: none;
    color: var(--primary-strong);   /* was --primary: 3.91:1 on white. Now 5.93:1. */
    cursor: pointer;
    font-weight: 500;
    padding: 5px;
    transition: color 0.2s;
}

.text-button:hover {
    color: var(--primary-stronger);
    text-decoration: underline;
}

.back-button {
    display: inline-flex;
    align-items: center;
    color: var(--dark);
    text-decoration: none;
    /* The way out of every screen, so a full touch target rather than the
       24px line of text it was (v9u: 48px, the kiosk's floor); the margin
       gives back most of the height. */
    min-height: 48px;
    margin-bottom: 8px;
    font-weight: 500;
    transition: color 0.2s;
}

.back-button:hover {
    color: var(--primary-strong);   /* was --primary: 3.59:1 on --bg. Now 5.44:1. */
}

.back-button i {
    margin-right: 8px;
}

/* Custom Checkbox */
.checkbox-container {
    margin-bottom: 15px;
}

.custom-checkbox {
    display: flex;
    align-items: center;
    margin-bottom: 10px;
}

.custom-checkbox input[type="checkbox"] {
    width: auto;
    margin-right: 10px;
    margin-bottom: 0;
}

.custom-checkbox label {
    margin-bottom: 0;
    cursor: pointer;
}

.option-group {
    display: flex;
    gap: 20px;
    margin-bottom: 20px;
}

/* Child Attendance */
.attendance-summary {
    display: flex;
    justify-content: space-between;
    margin-bottom: 20px;
    gap: 15px;
}

.summary-box {
    background-color: white;
    padding: 15px;
    border-radius: var(--border-radius);
    flex: 1;
    text-align: center;
    box-shadow: var(--box-shadow);
}

.summary-label {
    display: block;
    font-size: 14px;
    color: var(--gray);
    margin-bottom: 5px;
}

.summary-value {
    display: block;
    font-size: 24px;
    font-weight: 600;
    color: var(--primary-strong);   /* P08: --primary is 3.9:1 on white */
}

.summary-sub {
    display: block;
    margin-top: 2px;
    font-size: 13px;
    color: var(--gray);
}

.children-grid {
    display: grid;
    /* 340px, not 280px: the photo, status chip, gaps and padding take ~217px
       before the name gets any, so 280px left a child's name about 60px —
       "Emily…", "Mich…" on the screen whose job is telling staff who is in the
       building. 340px leaves ~120px, and the name now WRAPS rather than
       truncating (below), so a long name costs a line, never letters. */
    grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
    gap: 18px;
    margin-top: 20px;
}

/* Child cards share the staff-card layout: horizontal, round photo, status
   chip on the right, status-colored left border. */
.child-card {
    min-width: 0;   /* may shrink to its grid column; see .staff-grid */
    display: flex;
    align-items: center;
    gap: 14px;
    background-color: white;
    border-radius: var(--border-radius);
    padding: 16px;
    box-shadow: var(--box-shadow);
    transition: transform 0.15s, box-shadow 0.15s;
    cursor: pointer;
    border-left: 5px solid #E7E2DA;
}

.child-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05);
}

.child-card.status-none { border-left-color: #E7E2DA; }
.child-card.status-in { border-left-color: var(--secondary); }
.child-card.status-out { border-left-color: var(--danger); }
.child-card.status-absent { border-left-color: var(--gray); }

.child-photo {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    background-color: #E7E2DA;
    display: flex;
    align-items: center;
    justify-content: center;
}

.child-photo img {
    width: 100%;
    height: 100%;
    object-fit: cover;
}

.default-avatar {
    width: 60px;
    height: 60px;
    background-color: var(--primary-light);
    border-radius: 50%;
    display: flex;
    justify-content: center;
    align-items: center;
    /* Was `white` on the pale teal tint: 1.22:1, i.e. the placeholder icon was
       invisible on every child/staff card without a photo. */
    color: var(--primary-strong);   /* 4.86:1 on --primary-light */
}

.default-avatar i {
    font-size: 28px;
}

.child-info {
    flex: 1;
    min-width: 0;
}

.child-info h3 {
    margin: 0 0 2px 0;
    font-size: 1.05rem;
    line-height: 1.25;
    /* Never ellipsize a child's name on the kiosk: wrap at spaces, and break
       inside a word only if one word alone is wider than the column. */
    white-space: normal;
    overflow-wrap: break-word;
}

.child-info small {
    color: var(--gray);
    font-size: 0.85rem;
    /* "DOB: 03/15/2023" is one unit; the label wrapping onto its own line
       above the date read as two unrelated fields. */
    white-space: nowrap;
}

.child-status {
    display: flex;
    align-items: center;
    flex-shrink: 0;
}

.date-navigation {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;
    background-color: white;
    padding: 12px 15px;
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow);
}

.date-display {
    /* It is an <input>, so the form rule gave it width: 100% and a 15px bottom
       margin: it squeezed "Previous Day" / "Next Day" onto two lines each and
       sat the date above the buttons' centre line. It takes the space that
       is left instead. */
    flex: 1 1 auto;
    width: auto;
    min-width: 0;
    margin: 0;
    font-weight: 600;
    font-size: 1.1rem;
    text-align: center;
    padding: 8px;
    border: none;
    cursor: pointer;
    background: transparent;
}

.nav-button {
    white-space: nowrap;
    background-color: var(--light-gray);
    border: 1px solid var(--border);
    padding: 11px 16px;
    min-height: 48px;   /* v9u: the kiosk's 48px floor */
    border-radius: var(--border-radius);
    cursor: pointer;
    display: flex;
    align-items: center;
    font-weight: 500;
    color: var(--dark);
    transition: background-color 0.15s, border-color 0.15s;
}

.nav-button:hover {
    background-color: var(--surface);
    border-color: var(--muted);
}

.search-container {
    position: relative;
    margin-bottom: 20px;
}

.search-container input {
    width: 100%;
    padding-left: 40px;
    /* The container supplies the spacing below. The field's own 15px margin
       made the container taller than the field, so the icon — centred on the
       container — sat 7px below the text it labels. */
    margin-bottom: 0;
}

.search-icon {
    position: absolute;
    left: 12px;
    top: 50%;
    transform: translateY(-50%);
    color: var(--gray);
}

.empty-message {
    text-align: center;
    color: var(--gray);
    grid-column: 1 / -1;
    padding: 30px;
    background-color: white;
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow);
}

/* Modal */
.modal {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    justify-content: center;
    align-items: center;
    z-index: 1000;
}

.modal-content {
    background-color: white;
    border-radius: var(--border-radius);
    width: 90%;
    max-width: 500px;
    max-height: 90vh;
    overflow-y: auto;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}

.modal-header {
    padding: 20px;
    border-bottom: 1px solid #E7E2DA;
    display: flex;
    justify-content: space-between;
    align-items: center;
}

.modal-header h2 {
    margin: 0;
    font-size: 1.5rem;
}

.close-button {
    background: none;
    border: none;
    font-size: 24px;
    cursor: pointer;
    color: var(--gray);
    padding: 0;
}

.modal-body {
    padding: 20px;
}

.modal-footer {
    padding: 15px 20px;
    border-top: 1px solid #E7E2DA;
    display: flex;
    justify-content: flex-end;
    gap: 10px;
}

/* Signature pad */
.signature-container {
    border: 1px solid #D8D2C8;
    border-radius: var(--border-radius);
    overflow: hidden;
    background-color: white;
}

/* M12: every signature canvas has a CSS display size, so only its bitmap
   follows the pixel ratio (static/js/signature-fit.js). A canvas with no
   CSS size grew on every open on a 2x tablet. touch-action: a stroke is
   ink, never a page scroll. */
.signature-container canvas {
    display: block;
    width: 100%;
    height: 200px;
    background-color: white;
    touch-action: none;
}

canvas#signaturePad {
    width: 100%;
    height: 200px;
    background-color: white;
    display: block;
}

/* Custom Alert */
.custom-alert {
    display: none;
    position: fixed;
    top: 0;
    left: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.5);
    justify-content: center;
    align-items: center;
    z-index: 2000;
}

.alert-content {
    background-color: white;
    border-radius: var(--border-radius);
    width: 90%;
    max-width: 400px;
    padding: 20px;
    text-align: center;
    box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
}

.alert-icon {
    font-size: 48px;
    /* --warning was 2.75:1 on the white dialog — below even the 3:1 that
       SC 1.4.11 asks of a meaningful graphic, let alone text. */
    color: var(--warning-text);   /* 7.09:1 */
    margin-bottom: 15px;
}

.alert-message {
    margin-bottom: 20px;
    font-size: 16px;
}

.alert-buttons {
    display: flex;
    justify-content: center;
}

/* Status badges — an in-flow chip, identical in behaviour to .status-chip.
   This was `position: absolute; top: 10px; right: 10px` with no positioned
   ancestor anywhere in the chain (.visitor-card / .visitor-info / .container /
   main are all static), so every badge resolved against the initial containing
   block and they stacked on top of each other in the page's top-right corner:
   a visitor's SIGNED IN / SIGNED OUT and a child's Active / Inactive were
   simply missing from their row. Made an inline-flex chip rather than pinning
   `position: relative` on an ancestor, so nothing downstream can re-break it by
   introducing a new positioned wrapper.
   `align-self: flex-start` matters: in visitor_log.html the badge is a direct
   child of `.visitor-info`, a column flex container, which would otherwise
   stretch the chip to the full card width (this is why the sibling
   `.sign-out-btn` already carries the same declaration). It is inert inside a
   table cell, which is where manage_children.html uses it. */
.status-badge {
    display: inline-flex;
    align-items: center;
    align-self: flex-start;
    gap: 5px;
    padding: 5px 10px;
    border-radius: 999px;
    font-size: 0.8rem;
    font-weight: 600;
    white-space: nowrap;
}

/* Foregrounds match .chip-* below — same tints, same job, same ratios. */
.badge-green {
    background-color: rgba(61, 154, 109, 0.15);
    color: var(--on-tint-green);   /* was --secondary-dark, 4.27:1 -> 6.41:1 */
}

.badge-red {
    background-color: rgba(198, 85, 59, 0.12);
    color: var(--on-tint-red);     /* was --danger, 3.78:1 -> 5.87:1 */
}

.badge-gray {
    background-color: rgba(111, 107, 100, 0.12);
    color: var(--on-tint-gray);    /* was --gray, 4.53:1 -> 6.54:1 */
}

/* Visitor card styles */
.visitor-card {
    background-color: white;
    border-radius: var(--border-radius);
    padding: 20px;
    margin-bottom: 15px;
    box-shadow: var(--box-shadow);
    border-left: 5px solid var(--secondary);
}

.visitor-info {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.visitor-info h3 {
    margin: 0;
    font-size: 18px;
}

.visitor-info p {
    margin: 0;
    color: var(--gray);
}

.sign-out-btn {
    align-self: flex-start;
    background-color: var(--primary-strong);   /* 3.91:1 -> 5.93:1 */
    color: white;
    border: none;
    border-radius: var(--border-radius);
    padding: 8px 15px;
    cursor: pointer;
    margin-top: 15px;
    transition: background-color 0.2s;
}

.sign-out-btn:hover {
    background-color: var(--primary-stronger);
}

/* Food attendance styles */
.food-attendance-card {
    display: flex;
    justify-content: space-between;
    align-items: center;
    background-color: white;
    border-radius: var(--border-radius);
    padding: 20px;
    margin-bottom: 15px;
    box-shadow: var(--box-shadow);
    transition: transform 0.2s;
}

.food-attendance-card:hover {
    transform: translateY(-3px);
}

.meal-btn {
    background-color: var(--light);
    border: none;
    padding: 8px 15px;
    border-radius: var(--border-radius);
    margin-left: 5px;
    cursor: pointer;
    font-weight: 500;
    transition: background-color 0.2s, color 0.2s;
}

.meal-btn:hover {
    background-color: #E7E2DA;
}

.meal-btn-active {
    background-color: var(--primary-strong);   /* 3.91:1 -> 5.93:1 */
    color: white;
}

.meal-checkbox {
    display: flex;
    align-items: center;
    gap: 8px;
}

.meal-checkbox input[type="checkbox"] {
    margin: 0;
    width: auto;
}

/* Export data page styles */
.section {
    background-color: white;
    border-radius: var(--border-radius);
    padding: 20px;
    box-shadow: var(--box-shadow);
    margin-bottom: 20px;
}

.date-range {
    display: flex;
    flex-wrap: wrap;
    gap: 15px;
}

.date-range label {
    display: block;
    width: 100%;
}

.data-table {
    width: 100%;
    border-collapse: collapse;
}

.data-table th, .data-table td {
    padding: 12px;
    text-align: left;
    border-bottom: 1px solid #E7E2DA;
}

.data-table th {
    background-color: #FBFAF7;
    font-weight: 600;
    color: var(--dark);
}

.data-table tr:hover td {
    background-color: #FBFAF7;
}

.btn-sm {
    display: inline-flex;
    align-items: center;
    background-color: var(--primary-strong);   /* 3.91:1 -> 5.93:1 */
    color: white;
    border: none;
    padding: 6px 12px;
    border-radius: var(--border-radius);
    text-decoration: none;
    font-size: 0.9rem;
    transition: background-color 0.2s;
}

.btn-sm:hover {
    background-color: var(--primary-stronger);
}

.btn-sm i {
    margin-right: 5px;
}

/* Responsive adjustments */
@media (max-width: 768px) {
    /* A roster card is a 60px photo that cannot shrink, a status chip that
       cannot wrap (~92px), 28px of gaps, 32px of padding and a 5px border:
       about 217px before the name has any room at all. At the old 200px floor
       `auto-fill` fitted three columns at 768px, `.child-info` collapsed to
       zero and THE CHILD'S NAME DISAPPEARED — on the one screen whose job is
       telling staff who is in the building. `.staff-grid` got this right
       (single column below 768px); this did not. */
    .children-grid {
        /* One full-width column on a phone/portrait tablet: two 240px columns
           left the name ~20px. */
        grid-template-columns: minmax(0, 1fr);
    }
    
    .attendance-summary {
        flex-direction: column;
    }
    
    .date-navigation {
        flex-direction: column;
        gap: 10px;
        align-items: stretch;
    }
    
    .option-group {
        flex-direction: column;
        gap: 10px;
    }
}
/* === Admin portal (P5-6c) === */
.portal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-bottom: 1rem;
    flex-wrap: wrap;
}
.portal-sub, .auth-sub { color: var(--muted); margin: .25rem 0 1rem; }   /* was #666 */
.auth-alt { margin-top: 1rem; font-size: .9rem; color: var(--muted); }   /* was #666 */
/* Batch 2: the location picker after sign-in (one big button per site). */
.location-pick { display: flex; flex-direction: column; gap: 12px; }
.location-pick-choice { width: 100%; min-height: 56px; }
.portal-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1rem;
    margin-top: 1rem;
}
.invite-form { max-width: 480px; }
/* Small destructive button (Revoke / Remove / Cancel subscription). Same colour
   family as .btn-danger above; was the off-brand flat-UI #c0392b. */
.btn-danger-sm {
    background: var(--danger-strong);   /* was #c0392b, 5.44:1 -> 5.99:1 */
    color: #fff;
    border: none;
    padding: .35rem .7rem;
    border-radius: var(--border-radius);
    cursor: pointer;
    font-size: .85rem;
}
.btn-danger-sm:hover { background: var(--danger-stronger); }   /* was #a93226 */

.error-box { text-align: center; }
.error-box code { background: var(--light-gray); padding:.1rem .3rem; border-radius:3px; }

/* === Staff attendance page (redesign) === */
.page-heading {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    margin-bottom: 8px;
}
.page-heading h1 { margin: 0; }
.page-heading h1 i { color: var(--primary); margin-right: 6px; }

.mode-pill {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8rem;
    font-weight: 600;
    padding: 4px 12px;
    border-radius: 999px;
}
.mode-pill-quick {
    background-color: rgba(224, 134, 58, 0.15);
    color: var(--warning-text);   /* was #B45309: 4.04:1 on the tint over --bg. Now 5.71:1. */
}

.staff-grid {
    display: grid;
    /* 340px for the reason given at .children-grid: photo, status block, gaps
       and padding left a 280px card ~86px for the name, so a teacher's name
       read "Test Teac…". */
    grid-template-columns: repeat(auto-fill, minmax(340px, 1fr));
    gap: 18px;
    margin-top: 20px;
}

.staff-card {
    min-width: 0;   /* may shrink to its grid column; see .staff-grid */
    display: flex;
    align-items: center;
    gap: 14px;
    background-color: white;
    border-radius: var(--border-radius);
    padding: 16px;
    box-shadow: var(--box-shadow);
    transition: transform 0.15s, box-shadow 0.15s;
    border-left: 5px solid #E7E2DA;
}
.staff-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -2px rgba(0,0,0,0.05);
}
.staff-card.status-in { border-left-color: var(--secondary); }
.staff-card.status-out { border-left-color: var(--danger); }
.staff-card.status-none { border-left-color: #E7E2DA; }
/* P08: Absent had its border set INLINE to --warning (2.3:1 on white, under
   the 3:1 a state indicator needs), overriding everything here. */
.staff-card.status-absent { border-left-color: var(--warning-strong); }
/* The summary numbers: text-safe tokens, never the decorative hues (the
   Signed Out count was inline --danger, 4.0:1). */
.summary-value.summary-in { color: var(--on-tint-green); }
.summary-value.summary-out { color: var(--danger-strong); }
.summary-value.summary-none { color: var(--on-tint-gray); }
.summary-value.summary-absent { color: var(--warning-text); }

.staff-photo {
    width: 60px;
    height: 60px;
    border-radius: 50%;
    overflow: hidden;
    flex-shrink: 0;
    background-color: #E7E2DA;
    display: flex;
    align-items: center;
    justify-content: center;
}
.staff-photo img { width: 100%; height: 100%; object-fit: cover; }

.staff-info {
    flex: 1;
    min-width: 0;
}
.staff-info h3 {
    margin: 0 0 2px 0;
    font-size: 1.05rem;
    line-height: 1.25;
    /* Wrap, never ellipsize — as for the child cards. */
    white-space: normal;
    overflow-wrap: break-word;
}
.staff-info p {
    margin: 0;
    color: var(--gray);
    font-size: 0.88rem;
}

.staff-status {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 8px;
    flex-shrink: 0;
}

/* `.status-chip` is defined ONCE, further down with the portal chips. It used
   to be declared here as well, and the later block won for every chip in the
   product — so this rule's `inline-flex`, `align-items` and `gap` were dead and
   the kiosk chips were spacing their icon on the whitespace in the markup. The
   surviving rule carries those properties, which is why they are not repeated
   here. */
/* These three carry safety meaning — "Signed In" / "Signed Out" / "Not
   Arrived" — at 0.75rem, so they need the full 4.5:1, not the large-text 3:1.
   Each used the brand hue itself as the foreground, which is far too light
   against its own tint. Ratios are measured on the tint composited over the
   white card. */
.chip-green { background-color: rgba(61, 154, 109, 0.15); color: var(--on-tint-green); }  /* 4.27:1 -> 6.41:1 */
.chip-red   { background-color: rgba(198, 85, 59, 0.12); color: var(--on-tint-red); }     /* 3.78:1 -> 5.87:1 */
.chip-gray  { background-color: rgba(111, 107, 100, 0.12); color: var(--on-tint-gray); }  /* 4.53:1 -> 6.54:1 */
/* The "Absent" state. Amber as text needs --warning-text; --warning itself is
   2.31:1 on --light-gray, which is roughly invisible. */
.chip-warning { background-color: var(--light-gray); color: var(--warning-text); }         /* 2.31:1 -> 5.97:1 */

.sign-action {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    border: none;
    border-radius: var(--border-radius);
    padding: 9px 16px;
    font-size: 0.9rem;
    font-weight: 600;
    color: white;
    cursor: pointer;
    transition: background-color 0.15s, opacity 0.15s;
    white-space: nowrap;
}
/* All three carry white text, so the surface must clear 4.5:1 against white.
   The brand hues did not: --secondary 3.48:1, --danger 4.41:1, --warning
   2.75:1. */
/* Sign in is the child roster's SIGN IN colour (audit round 1 #15: one look
   for both rosters). */
.sign-action.sign-in { background-color: var(--primary-strong); }      /* white on it 5.93:1 */
.sign-action.sign-in:hover { background-color: var(--primary-stronger); }
/* v9: the "Staff PIN set" note on Manage Staff. */
.staff-pin-set { color: var(--primary-strong); font-weight: 600; white-space: nowrap; }
.sign-action.sign-out { background-color: var(--danger-strong); }      /* 4.41:1 -> 5.99:1 */
.sign-action.sign-out:hover { background-color: var(--danger-stronger); }
/* Was styled only by an inline `background-color: var(--warning)` in
   staff_attendance.html — 2.75:1 white-on-amber, the worst pair in the app. */
.sign-action.mark-absent { background-color: var(--warning-strong); }  /* 2.75:1 -> 5.93:1 */
.sign-action.mark-absent:hover { background-color: var(--warning-text); }
.sign-action.is-busy,
.sign-action:disabled { opacity: 0.6; cursor: default; }

@media (max-width: 768px) {
    /* minmax(0, 1fr), not 1fr: a grid track's floor is its content's
       min-content width, and a card's min-content is the photo + status block
       + the longest unbreakable word of the name — 383px for
       "Anastasia Konstantinopoulou" on a 390px phone, so the page scrolled
       sideways. With a zero floor the card takes the column and the name wraps. */
    .staff-grid { grid-template-columns: minmax(0, 1fr); }
}

.quick-hint {
    display: flex;
    align-items: center;
    gap: 8px;
    background-color: rgba(47, 143, 131, 0.09);
    color: var(--primary-dark);
    border-radius: var(--border-radius);
    padding: 10px 14px;
    margin: 0 0 16px;
    font-size: 0.9rem;
}
.quick-hint i { flex-shrink: 0; }

.child-card.is-busy {
    opacity: 0.55;
    pointer-events: none;
}

/* === Super Admin console (P6) === */
.stat-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 1rem;
    margin: 1rem 0 1.5rem;
}
/* This block (Super Admin / Billing / API keys) was written against a second,
   flat-UI palette — #2c3e50, #27ae60, #2980b9, #e67e22, #c0392b, 8px/4px radii,
   #e3e3e3 borders, #555/#666 greys. Converted onto the ADR-045 tokens. Class
   names are unchanged; templates depend on them. */
.stat-card {
    background: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    padding: 1rem;
    display: flex;
    flex-direction: column;
    align-items: center;
}
.stat-num { font-size: 2rem; font-weight: 700; color: var(--text); }   /* was #2c3e50, 10.98:1 -> 14.34:1 */
.stat-label { color: var(--muted); font-size: .85rem; margin-top: .25rem; }   /* was #666, 5.74:1 -> 5.30:1, still AA */
/* Solid status pills carrying white text, so each surface must clear 4.5:1
   against white — three of the five did not. */
.badge { padding: .15rem .5rem; border-radius: 999px; font-size: .8rem; color: #fff; }
.badge-active { background: var(--success-strong); }    /* was #27ae60, 2.87:1 -> 5.02:1 */
.badge-trialing { background: var(--primary-strong); }  /* was #2980b9, 4.30:1 -> 5.93:1 */
.badge-past_due { background: var(--warning-strong); }  /* was #e67e22, 2.85:1 -> 5.93:1 */
.badge-suspended { background: var(--danger-strong); }  /* was #c0392b, 5.44:1 -> 5.99:1 */
.badge-canceled { background: var(--on-tint-gray); }    /* was #7f8c8d, 3.48:1 -> 7.65:1 */
.inline-search { display: flex; gap: .5rem; margin-bottom: 1rem; }
.status-actions { margin: 1rem 0; }

/* === Billing (P7) === */
.plan-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1rem;
    margin: 1rem 0;
}
.plan-card {
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    padding: 1rem;
    background: var(--surface);
}
.plan-current { border-color: var(--success-strong); box-shadow: 0 0 0 2px rgba(46, 125, 87, .2); }
.plan-price { font-size: 1.4rem; font-weight: 700; color: var(--text); }        /* was #2c3e50 */
.plan-limits { list-style: none; padding: 0; margin: .5rem 0; font-size: .9rem; color: var(--muted); }   /* was #555, 7.46:1 -> 5.30:1, still AA */
.plan-limits li { padding: .1rem 0; }
.plan-badge { color: var(--on-tint-green); font-weight: 600; }                  /* was #27ae60, 2.87:1 -> 7.53:1 */
.cancel-form { margin-top: 1.5rem; }
.billing-current { margin-bottom: 1rem; }

/* === API keys (P9 API) === */
/* Was a Material-amber box (#fff8e1 / #ffd54f) wrapping a neon-lime-on-slate
   code block (#aeea00 on #263238). Same "here is your one-time secret" job, on
   the amber tint the rest of the app uses for it (cf. .past-day-banner), and a
   warm near-black code block. Contrast goes 9.13:1 -> 13.74:1, so the change is
   purely a palette one. */
.new-key-box { background: rgba(224, 134, 58, 0.12); border: 1px solid rgba(224, 134, 58, 0.45); }
.new-key { display: block; margin-top: .5rem; padding: .5rem; background: var(--text);
    color: var(--light); border-radius: var(--border-radius); word-break: break-all; font-size: .9rem; }
.checkbox-row { display: block; font-weight: normal; margin: .2rem 0; }

/* === Access keys (ADR-064) ===
   superadmin/keys.html and portal/billing.html were written against classes no
   stylesheet defined, so the issue form was a raw browser fieldset, help text
   was full-strength body copy, and Set / Suspend were unstyled grey system
   buttons beside a full-width number box. */
.muted { color: var(--muted); font-size: .92rem; }
.mono { font-family: ui-monospace, SFMono-Regular, Consolas, monospace; }
.selectable { user-select: all; overflow-wrap: anywhere; }
.callout {
    padding: 16px 20px;
    margin-bottom: 20px;
    border-radius: var(--border-radius);
    border: 1px solid var(--border);
    background-color: var(--surface);
}
/* The same 15% green tint as .chip-green; body text stays --dark on it. */
.callout-success {
    background-color: rgba(61, 154, 109, 0.15);
    border-color: var(--secondary);
}
.callout h3 { margin-bottom: 8px; }
.stack-form { max-width: 480px; margin-bottom: 24px; }
.stack-form fieldset {
    margin: 0;
    padding: 16px 20px 20px;
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    background-color: var(--surface);
}
.stack-form legend { padding: 0 6px; font-weight: 600; }
.stack-form .muted { margin-top: -6px; }
/* Several small forms side by side in one table cell (allowance, suspend,
   revoke). */
.inline-form {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin: 0 6px 6px 0;
    vertical-align: middle;
}
.input-narrow { width: 6rem; margin-bottom: 0; padding: 8px 10px; }
/* The neutral twin of .btn-danger-sm, styled like .nav-button. */
.btn-secondary-sm {
    background-color: var(--light-gray);
    color: var(--dark);
    border: 1px solid var(--border);
    padding: .35rem .7rem;
    border-radius: var(--border-radius);
    cursor: pointer;
    font-size: .85rem;
    font-weight: 500;
}
.btn-secondary-sm:hover { background-color: var(--surface); border-color: var(--muted); }

/* === Accessibility (a11y pass) === */
.skip-link {
    position: absolute;
    left: -9999px;
    top: 0;
    background: var(--text);   /* was #2c3e50 (off-brand slate): 10.98:1 -> 14.34:1 */
    color: #fff;
    padding: .6rem 1rem;
    z-index: 1000;
    border-radius: 0 0 var(--border-radius) 0;
}
.skip-link:focus {
    left: 0;
}
main:focus {
    outline: none;
}
/* Visible keyboard focus everywhere (was relying on browser default only).
   This is the single source of truth for the focus ring — do not add another
   one earlier in the file, it will lose on source order. Solid --primary:
   3.91:1 against --surface and 3.59:1 against --bg, both clearing the 3:1 that
   WCAG SC 1.4.11 asks of a focus indicator. It was #2980b9 (off-brand blue),
   and the teal rule it overrode was rgba(...,0.45), too faint to see. */
a:focus-visible,
button:focus-visible,
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
[tabindex]:focus-visible {
    outline: 3px solid var(--primary);
    outline-offset: 2px;
}
/* Screen-reader-only helper. */
.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;
}
@media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }
}

/* === Manage-pages controls (children/staff/menus tables) === */
.button-container {
    margin-bottom: 20px;
}

.filter-container {
    display: flex;
    align-items: center;
    gap: 12px;
    flex-wrap: wrap;
    background-color: white;
    padding: 12px 15px;
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow);
    margin-bottom: 20px;
}
.filter-label { font-weight: 600; color: var(--gray); }
.filter-options { display: flex; gap: 8px; }

.filter-btn {
    background-color: var(--light);
    border: 1px solid #E7E2DA;
    color: var(--dark);
    padding: 7px 16px;
    border-radius: var(--border-radius);
    cursor: pointer;
    font-weight: 500;
    transition: background-color 0.15s, color 0.15s, border-color 0.15s;
}
.filter-btn:hover { background-color: #E7E2DA; }
.filter-active {
    background-color: var(--primary-strong);   /* 3.91:1 -> 5.93:1 */
    border-color: var(--primary-strong);
    color: white;
}

.table-container {
    background-color: white;
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow);
    padding: 8px;
    overflow-x: auto;
}

.action-btn {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    background-color: var(--light);
    border: 1px solid #E7E2DA;
    color: var(--dark);
    padding: 6px 12px;
    border-radius: var(--border-radius);
    cursor: pointer;
    font-size: 0.85rem;
    font-weight: 500;
    margin: 2px;
    transition: background-color 0.15s, color 0.15s, border-color 0.15s;
}
.action-btn:hover { background-color: #E7E2DA; }
/* Hover fills carry white text, so they use the text-safe partners. */
.action-btn.edit-btn:hover { background-color: var(--primary-strong); border-color: var(--primary-strong); color: white; }
.action-btn.activate-btn:hover { background-color: var(--success-strong); border-color: var(--success-strong); color: white; }
.action-btn.deactivate-btn:hover,
.action-btn.delete-btn:hover { background-color: var(--danger-strong); border-color: var(--danger-strong); color: white; }

/* Manage Staff list: one row per person, actions pinned right. */
.staff-row-inner {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 12px 0;
    border-bottom: 1px solid var(--border);
}
.staff-row:last-child .staff-row-inner { border-bottom: none; }
.staff-row-who {
    display: flex;
    align-items: center;
    gap: 12px;
    min-width: 0;
}
.staff-row-actions {
    display: flex;
    gap: 8px;
    flex-shrink: 0;
}
/* Icon-only actions. 44px square because they are the only way to edit or
   delete a person and are used on a touchscreen; they were 33x27. White text
   needs the -strong surfaces (the brand hues are below 4.5:1). */
.icon-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    border: none;
    border-radius: var(--border-radius);
    background-color: var(--primary-strong);
    color: white;
    cursor: pointer;
}
.icon-btn:hover { background-color: var(--primary-stronger); }
.icon-btn-danger { background-color: var(--danger-strong); }
.icon-btn-danger:hover { background-color: var(--danger-stronger); }

.menu-card {
    background-color: white;
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow);
    padding: 16px;
    margin-bottom: 15px;
    border-left: 5px solid var(--primary);
}

/* === Food attendance page === */
.meal-selector {
    background-color: white;
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow);
    padding: 16px 20px;
    margin-bottom: 20px;
}
.meal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
}
.meal-header h2 { margin: 0; font-size: 1.2rem; }
.meal-tabs {
    display: flex;
    gap: 8px;
    flex-wrap: wrap;
}
.meal-times {
    margin-top: 12px;
    color: var(--gray);
    font-size: 0.9rem;
}
.meal-times p { margin: 0; }
.meal-attendance {
    display: flex;
    align-items: center;
    gap: 10px;
}

/* === Settings cards + feature toggle switches === */
.settings-card {
    background-color: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow);
    padding: 20px;
    margin-bottom: 20px;
}
.settings-card-title { font-size: 1.3rem; margin: 0 0 6px; }
.settings-card-hint { color: var(--muted); margin: 0 0 8px; font-size: 0.92rem; }

/* The ONE Settings hub (Batch 2, templates/settings_hub.html): one card per
   section, two columns on a tablet, each link a full 48px touch target. */
.hub-sub { margin: -8px 0 16px; }
.hub-portal { margin: 0 0 16px; }
.hub-portal .btn-secondary { width: auto; display: inline-flex; gap: 8px; align-items: center; min-height: 48px; }
.hub-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.hub-grid .settings-card { margin-bottom: 0; }
.hub-card .settings-card-title i { color: var(--primary); margin-right: 6px; }
.hub-links { list-style: none; margin: 0; padding: 0; }
.hub-links li { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.hub-link, .hub-link-off { display: inline-flex; align-items: center; min-height: 48px; }
.hub-link { color: var(--primary-strong); font-weight: 600; }
.hub-link-off { color: var(--muted); }
.hub-state { font-size: 0.85rem; color: var(--muted); border: 1px solid var(--border); border-radius: 999px; padding: 2px 10px; }
.hub-onetap { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; margin: 8px 0; }
.hub-signin { margin: 8px 0 0; }
.hub-signin-note a, .hub-signin a { font-weight: 600; color: var(--primary-strong); }
.hub-lang { margin-top: 12px; }
.hub-lang .settings-subhead { margin: 0 0 6px; font-weight: 600; }
.hub-lang .lang-toggle { justify-content: flex-start; margin: 0; }
@media (max-width: 768px) {
    .hub-grid { grid-template-columns: 1fr; }
}

.feature-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 14px 0;
    border-top: 1px solid var(--border);
    cursor: pointer;
}
.feature-row.is-core { cursor: default; }
.feature-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.feature-name { font-weight: 600; }
.feature-name i { color: var(--primary); margin-right: 8px; width: 18px; text-align: center; }
.feature-desc { color: var(--muted); font-size: 0.88rem; }
.feature-core-badge {
    flex-shrink: 0;
    font-size: 0.78rem;
    font-weight: 600;
    color: var(--on-tint-green);   /* was --secondary-dark: 3.86:1 on --secondary-light -> 5.79:1 */
    background-color: var(--secondary-light);
    padding: 5px 12px;
    border-radius: 999px;
}

/* Toggle switch */
.switch { position: relative; display: inline-flex; flex-shrink: 0; }
.switch input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}
.switch-track {
    width: 48px;
    height: 28px;
    border-radius: 999px;
    background-color: #D8D2C8;
    transition: background-color 0.15s;
    display: inline-block;
    position: relative;
}
.switch-thumb {
    position: absolute;
    top: 3px;
    left: 3px;
    width: 22px;
    height: 22px;
    background-color: #fff;
    border-radius: 50%;
    box-shadow: 0 1px 2px rgba(43, 42, 40, 0.25);
    transition: transform 0.15s;
}
.switch input:checked + .switch-track { background-color: var(--primary); }
.switch input:checked + .switch-track .switch-thumb { transform: translateX(20px); }
/* The real <input> is transparent and stacked over the track, so the ring has
   to be drawn on the track. Matches the global focus ring above. */
.switch input:focus-visible + .switch-track {
    outline: 3px solid var(--primary);
    outline-offset: 2px;
}

/* --- choice chips (Round 2B: the menu's days, the sheet's frequency) ----- */
/* A row of big tap targets, each a real checkbox or radio inside its label.
   The input stays in the page (screen readers, keyboard, a form post) and
   is drawn as the chip: chosen = teal, not chosen = outlined. */
.choice-chips { display: flex; flex-wrap: wrap; gap: 8px; margin: 0 0 .75rem; padding: 0; border: 0; }
.choice-chip { position: relative; display: inline-flex; margin: 0; font-weight: 600; }
.choice-chip input {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    opacity: 0;
    cursor: pointer;
}
.choice-chip span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 56px;
    min-height: 48px;
    padding: 0 16px;
    border: 2px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text);
}
.choice-chip input:checked + span {
    background: var(--primary-strong);
    border-color: var(--primary-strong);
    color: #fff;
}
.choice-chip input:focus-visible + span {
    outline: 3px solid var(--primary);
    outline-offset: 2px;
}
.choice-chip input:disabled { cursor: default; }
.choice-chip input:disabled + span { opacity: .6; }
/* The attendance sheet's weekday row shows only while "Every week" is
   chosen. A browser without :has() shows it always (still correct). */
.sheet-schedule:has(input[name="daily_sheet_frequency"][value="weekly"]:not(:checked)) .sheet-weekday { display: none; }

/* --- roster photo cell (manage children / staff) ------------------------- */
/* A face is the fastest way for staff to confirm the right child at pickup,
   so the cell is a real control: click to replace, with a text fallback for
   keyboard and screen-reader users. */
.photo-cell { width: 64px; }
.photo-thumb {
    width: 44px; height: 44px; border-radius: 50%;
    object-fit: cover; display: block; background: var(--light-gray);
}
.photo-placeholder {
    width: 44px; height: 44px; border-radius: 50%;
    background: var(--primary-light);
    /* Was --surface (white) on the pale teal tint: 1.22:1 — the child's initial
       was invisible, which defeats the whole point of the cell. */
    color: var(--primary-strong);   /* 4.86:1 */
    display: flex; align-items: center; justify-content: center;
    font-weight: 600; font-size: 0.95rem;
}
.photo-button {
    background: none; border: none; padding: 0; cursor: pointer;
    border-radius: 50%;
}
.photo-button:focus-visible { outline: 3px solid var(--primary); outline-offset: 2px; }

/* --- application-wide flash region -------------------------------------- */
/* One place, one style. Previously copied into 25 templates in three different
   looks and absent from thirteen more, so a refused action on any kiosk page
   was indistinguishable from a successful one. */
.flash-region:empty { display: none; }
.flash-region {
    max-width: 1100px;
    margin: 16px auto 0;
    padding: 0 20px;
}
.flash-message {
    /* Dark teal on the soft teal tint: 4.86:1, past the WCAG AA 4.5:1 floor for
       body text — the previous ad-hoc variants included white-on-tint, which is
       not readable. (The comment here used to claim ~7:1; measured, it is
       4.86:1. Still a pass, so the colours are unchanged.) */
    background-color: var(--primary-light);
    color: var(--primary-strong);
    border-left: 4px solid var(--primary);
    border-radius: var(--border-radius);
    padding: 12px 16px;
    margin-bottom: 12px;
    font-weight: 500;
}

/* --- v9 M5: "License number not verified yet" (templates/_license_banner.html).
   Amber tint + --warning-text, the .past-day-banner pairing (5.71:1). */
.license-banner {
    background-color: rgba(224, 134, 58, 0.12);
    color: var(--warning-text);
    border: 1px solid rgba(224, 134, 58, 0.45);
    border-left: 4px solid var(--warning-strong);
    border-radius: var(--border-radius);
    padding: 12px 16px;
    margin: 12px 0;
}
.license-banner p { margin: 4px 0; }
.license-banner a { color: var(--warning-text); font-weight: 600; text-decoration: underline; }

/* --- Viewing a day other than today -----------------------------------------
   Quick mode stamps the time *now*, so it cannot apply to another day. The
   banner says which day is on screen and the read-only state takes the tap
   affordance away, rather than letting a card look tappable and then refusing.
   Both matter: the screen saying one date while a tap wrote to another is how a
   child who is in the building gets recorded as collected. */
.past-day-banner {
    display: flex;
    align-items: center;
    gap: 8px;
    background-color: rgba(224, 134, 58, 0.12);
    color: var(--warning-text);   /* now a real :root token; 5.71:1 on this tint */
    border: 1px solid rgba(224, 134, 58, 0.45);
    border-radius: var(--border-radius);
    padding: 10px 14px;
    margin: 0 0 16px;
    font-weight: 600;
}

.past-day-banner[hidden] { display: none; }
.past-day-banner i { flex-shrink: 0; }

.child-card.is-readonly {
    cursor: default;
    opacity: 0.85;
}

.child-card.is-readonly:hover {
    /* Cancel the lift that says "this does something". */
    transform: none;
    box-shadow: var(--box-shadow);
}


/* =============================================================================
   Admin portal & Super Admin console
   -----------------------------------------------------------------------------
   Lifted out of templates/portal/_ui_head.html so these rules live with the
   rest of the design system: as a template partial they sat outside
   tests/test_contrast.py, which is the guard that stops a colour pair silently
   regressing, and they gave the product a second place where a card or a chip
   was defined. Every colour pair below reuses a token that test already checks.
   ============================================================================= */
    /* --- Dashboard information architecture (audit 6.1) ------------------
       The portal home used to be one flat grid of fifteen equal-weight tiles.
       These rules give the grouped version its rhythm: a section is a heading,
       an optional one-line explanation, then its grid. */
    .portal-section { margin: 2rem 0 0; }
    .portal-section:first-of-type { margin-top: 1.25rem; }
    .portal-section-title {
        font-size: 1.15rem; margin: 0 0 .25rem;
        padding-bottom: .35rem; border-bottom: 1px solid var(--border);
    }
    .portal-section-sub { color: var(--muted); font-size: .9rem; margin: .4rem 0 0; }
    .portal-section .portal-grid { margin-top: .75rem; }

    /* Developer tools sit behind a disclosure: a director never needs them,
       and they were competing for attention with "Late sign-outs". */
    .portal-disclosure { margin-top: 2rem; }
    .portal-disclosure > summary {
        cursor: pointer; font-weight: 600; padding: .5rem 0;
        border-top: 1px solid var(--border); color: var(--muted);
        list-style: revert;
    }
    .portal-disclosure > summary:hover { color: var(--dark); }
    .portal-disclosure > summary:focus-visible {
        outline: 3px solid var(--primary); outline-offset: 2px;
    }
    .portal-disclosure .portal-grid { margin-top: .75rem; }

    /* --- Empty states (audit 7.3) ----------------------------------------
       Every empty state names the next action, in the shape backups.html and
       late_signouts.html already used. */
    .empty-state { text-align: center; padding: 28px 16px; color: var(--muted); }
    .empty-state > i {
        display: block; font-size: 2.2rem; color: var(--primary);
        margin-bottom: 10px;
    }
    .empty-state-title { margin: 0 0 6px; font-weight: 600; color: var(--dark); }
    .empty-state-hint { margin: 0 auto; max-width: 52ch; font-size: .92rem; }
    /* .empty-message is a kiosk grid tile (white card). Inside a table cell the
       card treatment reads as a phantom row, so strip it back. */
    td.empty-message, th.empty-message {
        background: transparent; box-shadow: none; padding: 0;
    }

    /* --- Status chips (audit 8.3) ----------------------------------------
       Raw enum values ("past_due", "trialing") were printed straight from the
       database. status_text() in portal/_ui.html humanises the word; these
       carry the tone. Deliberately NOT reusing .badge: .badge sets color:#fff
       and only five .badge-<status> backgrounds exist, so any status outside
       that set rendered white-on-white. */
    /* The single definition, serving both the kiosk chips (icon + label, which
       is why this is inline-FLEX with a gap rather than inline-block) and the
       portal's. */
    .status-chip {
        display: inline-flex; align-items: center; gap: 5px;
        padding: 3px 10px; border-radius: 999px;
        font-size: .8rem; font-weight: 600; white-space: nowrap;
    }
    /* P08: the foregrounds are the text-safe on-tint tokens. They used to be
       the brand hues (--secondary-dark 4.27:1, #B45309 4.04:1, --danger
       3.78:1 on their own tints) -- below 4.5:1 for 0.8rem text. */
    .status-chip-ok { background: rgba(61, 154, 109, 0.15); color: var(--on-tint-green); }
    /* Each tint/foreground pair below is one that style.css already ships and
       tests/test_contrast.py already validates at WCAG AA (.badge-green,
       .badge-red, .mode-pill-quick, .backup-pill-none) — reused verbatim so
       these chips inherit that guarantee. */
    .status-chip-warn { background: rgba(224, 134, 58, 0.15); color: var(--warning-text); }
    .status-chip-bad { background: rgba(198, 85, 59, 0.12); color: var(--on-tint-red); }
    .status-chip-muted { background: var(--light-gray); color: var(--on-tint-gray); }

    /* --- Scrollable table regions (audit 4.1) -----------------------------
       .table-container is tabbable so a keyboard user can reach the scrollbar;
       it therefore needs a visible focus ring. */
    .table-container:focus-visible {
        outline: 3px solid var(--primary); outline-offset: 2px;
    }

    /* --- Card-stack fallback for wide tables (audit 4.1) ------------------
       A 7-column table that scrolls sideways on a phone technically works and
       is practically useless. Below 768px the marked tables become one card
       per row, each cell labelled from its data-label attribute.

       768px, not 760: the grid breakpoints above use 768, and the eight pixels
       between the two left a band where the grids were in phone layout while
       the tables were still in desktop scroll. */
    @media (max-width: 768px) {
        .stack-table thead {
            position: absolute; width: 1px; height: 1px;
            overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap;
        }
        /* The cells too, not just their row group: clipped, the header row
           was still laid out at full table width, so each <th> reported a box
           up to 280px past the right edge of a phone — invisible, but exactly
           what a layout check (or a browser deciding scroll extent) measures.
           Still in the accessibility tree; the cards carry the same labels. */
        .stack-table thead th {
            position: absolute; width: 1px; height: 1px; padding: 0;
            overflow: hidden; clip: rect(0 0 0 0);
        }
        .stack-table,
        .stack-table tbody,
        .stack-table tr,
        .stack-table td {
            display: block; width: 100%;
            /* The card's padding and border inside its 100%, not added to it:
               a stacked row was 26px wider than its table and the empty-state
               card was clipped at the right edge on a phone. */
            box-sizing: border-box;
        }
        .stack-table tr {
            border: 1px solid var(--border);
            border-radius: var(--border-radius);
            padding: 8px 12px; margin-bottom: 12px;
            background-color: var(--surface);
        }
        .stack-table tr:hover td { background-color: transparent; }
        /* Label floated left, value flowing beside it. This was a flex row,
           which made every node in the cell its own column: "owner@… <br>
           <span>user</span>" squeezed the second line to one letter per
           line, and "4 / 50 children (account total)" split into two
           columns. Inline flow keeps a mixed value together, and a value too
           long to fit beside the label drops below it at full width. */
        .stack-table td {
            border: none; padding: 6px 0;
            display: flow-root;
            text-align: right;
        }
        .stack-table td::before {
            content: attr(data-label);
            float: left; width: 42%;
            box-sizing: border-box; padding-right: 14px;
            font-weight: 600; color: var(--muted);
            text-align: left;
        }
        /* Action cells carry no label; and the empty state is not a record. */
        .stack-table td:not([data-label])::before,
        .stack-table td[data-label=""]::before { content: none; }
        .stack-table td.empty-message { display: block; }
        .stack-table td.empty-message::before { content: none; }
    }

/* --- Admin elevation notice --------------------------------------------------
   The kiosk tablet sits in an entrance and stays signed in all day by design.
   The PIN elevation layered on top of it is the dangerous part, so when it is
   active the main menu says so and offers a one-tap way to drop it. */
.admin-unlocked {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 12px;
    margin: 20px 0 0;
    padding: 12px 16px;
    background-color: rgba(224, 134, 58, 0.12);
    border: 1px solid rgba(224, 134, 58, 0.45);
    border-radius: var(--border-radius);
    color: var(--warning-text);
    font-weight: 600;
}

.admin-unlocked .btn-secondary { width: auto; }
.admin-lock-form { display: inline-block; margin-left: 16px; }
/* v9: the same control on every other unlocked admin screen (base.html). */
.admin-lock-bar { display: flex; justify-content: flex-end; margin: 8px 16px 0; }

/* --- Allergy marker ----------------------------------------------------------
   Sits in the name cell because that is the cell staff scan, and an allergy is
   the one detail that must never be a click away. Amber is the surface here;
   the text uses the readable counterpart (--warning is 2.75:1 and never
   carries text — see tests/test_contrast.py). */
.allergy-flag {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    margin-left: 8px;
    padding: 2px 8px;
    border-radius: 999px;
    background-color: rgba(224, 134, 58, 0.15);
    color: var(--warning-text);
    font-size: 0.8rem;
    font-weight: 600;
}

.field-hint {
    display: block;
    margin-top: 4px;
    color: var(--muted);
    font-size: 0.85rem;
}

/* Plan features read as description, not as a checklist of entitlements —
   nothing enforces them yet (see app/billing.py). The limits above them are
   what the product actually checks. */
.plan-features {
    margin: 8px 0 0;
    color: var(--muted);
    font-size: 0.9rem;
}

/* =============================================================================
   Narrow viewports
   -----------------------------------------------------------------------------
   The kiosk is a wall-mounted tablet and is not used on a phone. The parent
   portal and the admin portal are — a parent checks their child's attendance on
   the way to work, a director reads the late sign-out list standing in a
   corridor. Everything below either undoes a kiosk rule that leaked into the
   portal, or lets an existing row wrap. None of it changes the desktop layout.
   ========================================================================== */

/* portal/my_children.html wraps each child in `.child-card`, which is the
   KIOSK roster card: a horizontal flex row, vertically centred, with a hover
   lift and a pointer cursor. So the child's name, the date-of-birth line, the
   health information and the whole five-column attendance table were laid out
   side by side and squeezed to min-content — roughly 700px of irreducible
   width inside a 320px screen. The page scrolled sideways at every width and
   the table was unreadable on a phone. Scoped to <section> so the kiosk card,
   which is a <div>, is untouched. */
section.child-card {
    display: block;
    cursor: default;
}
section.child-card:hover {
    transform: none;
    box-shadow: var(--box-shadow);
}

/* `.inline-search` is a non-wrapping flex row, and the attendance-summary
   filter puts two date inputs, a location select and a submit button in it —
   about 600px that cannot shrink, because a flex item's min-width defaults to
   its content. On a phone the Apply button was simply off the right edge, so
   a director could not change the reporting period at all. */
.inline-search {
    flex-wrap: wrap;
    align-items: end;
}
.inline-search .form-group {
    margin-bottom: 0;
    flex: 1 1 11rem;
    min-width: 0;
}
.inline-search .form-group input,
.inline-search .form-group select,
.inline-search > input,
.inline-search > select {
    margin-bottom: 0;
}
.inline-search > input,
.inline-search > select {
    flex: 1 1 11rem;
    min-width: 0;
}
.inline-search > label {
    margin-bottom: 0;
    align-self: center;
}
/* .btn-primary is width:100% by design; inside a flex row that made the submit
   button claim the whole bar and stretch to its full height. */
.inline-search .btn-primary,
.inline-search .btn-secondary {
    width: auto;
    flex: 0 0 auto;
}

/* Six .nav-button anchors in the Super Admin console header. .nav-button is
   display:flex, i.e. block-level, so they stacked into a six-high column at
   every width instead of sitting in a row. */
.portal-header nav {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* The dialog footer is a flex row and .btn-primary is width:100%, so the
   confirm button claimed the bar and squeezed Cancel — the safe control — to
   its minimum. */
.modal-footer .btn-primary {
    width: auto;
}

@media (max-width: 768px) {
    /* A long activation code or email address inside a stacked table card had
       nothing to wrap on and pushed the whole page sideways. */
    .stack-table td > * {
        min-width: 0;
        /* break-word, not anywhere: anywhere also let a short button label
           break ("Susp|end", "Rev|oke") because it lowers the min-content
           width. Not on the cell's own text: there break-word splits an email
           that is merely too long to sit BESIDE the label ("sample.tes|t"),
           where without it the whole address drops below the label instead. */
        overflow-wrap: break-word;
    }

    /* .btn-primary, .btn-secondary and .nav-button all carry a 44px minimum
       already. The small family never got it — and it is the family that
       revokes access, deletes a child and closes a dialog. The modal close
       button was a 16px-wide target, which on a touchscreen is the only way
       out of a dialog. */
    .btn-sm,
    .action-btn,
    .btn-danger-sm,
    .btn-secondary-sm,
    .filter-btn {
        min-height: 44px;
        padding-top: 10px;
        padding-bottom: 10px;
    }
    .close-button {
        min-width: 44px;
        min-height: 44px;
    }
    .text-button {
        min-height: 44px;
        padding: 10px 8px;
    }
}

/* Forms page: Children and Staff side by side. A fixed two-column grid kept
   both columns on a phone, each too narrow for "Food Enrollment Form" plus its
   count, and the page scrolled 110px sideways. One column below 640px. */
.forms-columns {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 20px;
    margin-bottom: 30px;
}
@media (max-width: 640px) {
    .forms-columns {
        grid-template-columns: 1fr;
    }
}

/* Tables that cannot stack (their markup carries no data-label) at least stop
   spending 96px of a 320px screen on cell padding. */
@media (max-width: 560px) {
    .table-container {
        padding: 4px;
    }
    .data-table th,
    .data-table td {
        padding: 8px 6px;
    }
}

/* Emergency contact rows inside the child dialog (never on the roster — see
   the comment in child_attendance.html for why). */
.contact-row {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 8px;
    padding: 6px 0;
    border-bottom: 1px solid var(--border);
}
.contact-row:last-child { border-bottom: none; }
.contact-rel { color: var(--muted); font-size: 0.9rem; }
.contact-phone {
    margin-left: auto;
    font-weight: 600;
    /* A phone number is the thing being reached for, so it gets the same
       text-safe teal the rest of the product uses for actions. */
    color: var(--primary-strong);
}
.contact-missing { color: var(--muted); font-weight: 400; }

/* "Your plan" card on the owner's Access key page: label / value pairs that
   wrap to one per line on a phone instead of overflowing. */
.plan-card h2 { margin-top: 0; }
.plan-facts {
    display: grid;
    grid-template-columns: max-content minmax(0, 1fr);
    gap: 4px 16px;
    margin: 0 0 8px;
}
.plan-facts dt { color: var(--gray); }
.plan-facts dd { margin: 0; font-weight: 600; overflow-wrap: anywhere; }
/* The dashboard's "your plan ends in N days" line: the flash style, set apart
   from the menu below it. */
.plan-banner { margin-bottom: 16px; }

/* Product lockup (templates/_brand.html): icon + "ChildCare Kiosk". */
.brand-lockup {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    color: var(--text);
    font-weight: 700;
    font-size: 1.15rem;
    letter-spacing: -0.01em;
    line-height: 1.2;
}
.brand-mark { width: 32px; height: 32px; flex: none; border-radius: 7px; }
.brand-name { white-space: nowrap; }
/* On the sign-in boxes the lockup sits centred above the form heading. */
.auth-brand { display: flex; justify-content: center; margin-bottom: 16px; }
.portal-brand { display: block; margin-bottom: 6px; }

/* ===========================================================================
   v2 item 1 / 8 — the one-tap roster (templates/child_attendance.html)
   Tablet-first (820-1024px): every touch target is at least 56px tall.
   =========================================================================== */
.child-card { flex-wrap: wrap; }
.child-info-button {
    display: flex;
    align-items: center;
    gap: 14px;
    flex: 1 1 200px;
    min-width: 0;
    min-height: 56px;
    padding: 0;
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    text-align: left;
    cursor: pointer;
}
.child-info-button .child-info { display: block; }
.info-badge {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    flex-shrink: 0;
    width: 26px;
    height: 26px;
    border-radius: 50%;
    border: 2px solid var(--primary-strong);
    color: var(--primary-strong);
    font-size: 0.8rem;
    font-weight: 700;
    font-style: italic;
    vertical-align: middle;
}
.child-actions {
    display: flex;
    gap: 10px;
    flex-basis: 100%;
    align-items: stretch;
}
.child-card .child-card-button {
    flex: 1 1 auto;
    min-height: 56px;
    border: 0;
    border-radius: var(--border-radius);
    font: inherit;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: 0.04em;
    cursor: pointer;
    background-color: var(--light-gray);
    color: var(--dark);
}
.child-card .child-card-button[data-action="in"] {
    background-color: var(--primary-strong);   /* white on it 5.93:1 */
    color: white;
}
.child-card .child-card-button[data-action="in"]:hover:not(:disabled) {
    background-color: var(--primary-stronger);
}
.child-card .child-card-button[data-action="out"] {
    background-color: var(--danger-strong);    /* white on it 5.99:1 */
    color: white;
}
.child-card .child-card-button[data-action="out"]:hover:not(:disabled) {
    background-color: var(--danger-stronger);
}
.child-card .child-card-button:disabled { cursor: default; opacity: 0.75; }
/* v9: another day's button reads as disabled but still answers a tap
   with the reason (aria-disabled, not disabled). */
.child-card .child-card-button.is-readonly-day,
.sign-action.is-readonly-day,
.card-edit-link.is-readonly-day { cursor: not-allowed; opacity: 0.6; }
/* v9: an earlier day's shift nobody clocked out. */
.overdue-mark { display: block; color: var(--danger-strong); font-weight: 600; }
.card-edit-link {
    flex: 0 0 auto;
    min-height: 56px;
    min-width: 72px;
    padding: 0 12px;
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    background: white;
    color: var(--primary-strong);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.card-edit-link:hover { background-color: var(--primary-light); }

/* Audit round 1 #15: the staff roster uses the child roster's card layout —
   name and status on top, then the full-width .child-actions row: one big
   SIGN IN / SIGN OUT (.child-card-button, same size and type as the child
   page) and Absent beside it at the size of the child page's Edit. */
.staff-card { flex-wrap: wrap; }
.staff-card .child-card-button {
    flex: 1 1 auto;
    justify-content: center;
    min-height: 56px;
    padding: 0 16px;
    font-size: 1.15rem;
    font-weight: 700;
    letter-spacing: 0.04em;
}
.staff-card .sign-action.mark-absent {
    flex: 0 0 auto;
    justify-content: center;
    min-height: 56px;
    min-width: 72px;
    padding: 0 12px;
    font-size: 1rem;
}

/* The requirement sheet: health tap, PIN keypad, signature. */
.tap-step { margin-bottom: 16px; }
.tap-step-label { margin: 0 0 8px; font-weight: 600; }
.health-toggle {
    width: 100%;
    min-height: 56px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    border: 2px dashed var(--primary-strong);
    border-radius: var(--border-radius);
    background: white;
    color: var(--primary-strong);
    font: inherit;
    font-size: 1.05rem;
    font-weight: 600;
    cursor: pointer;
}
.health-toggle.is-done {
    border-style: solid;
    background-color: var(--success-strong);   /* white on it 5.02:1 */
    color: white;
}
/* "Who is signing?" — big chips, one tap each. */
.signer-chips { display: flex; flex-wrap: wrap; gap: 8px; }
.signer-chip {
    min-height: 56px;
    padding: 0 18px;
    border: 2px solid var(--primary-strong);
    border-radius: var(--border-radius);
    background: white;
    color: var(--primary-strong);
    font: inherit;
    font-size: 1.05rem;
    font-weight: 600;
    cursor: pointer;
}
.signer-chip .signer-rel { font-weight: 400; }
.signer-chip[aria-pressed="true"] {
    background-color: var(--primary-strong);
    color: white;
}
.signer-other { margin-top: 8px; width: 100%; min-height: 48px; font-size: 1.05rem; }
/* The roster's PIN keypads (.tap-keypad / .tap-key) are the shared
   .pin-keypad component: see "the PIN keypad" (v9u) at the end. */
canvas#tapSignaturePad {
    width: 100%;
    height: 180px;
    background-color: white;
    display: block;
}
/* Addendum 4 item 4: PIN and signature on ONE screen. When a location asks
   for both, the sheet widens and puts the keypad beside the signature, so
   neither one -- nor Save -- scrolls out of view on a landscape tablet. A
   narrow screen keeps them stacked. */
#tapSheet.tap-sheet-both .modal-content { max-width: 880px; }
@media (min-width: 720px) {
    #tapSheet.tap-sheet-both .modal-body {
        display: grid;
        grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
        column-gap: 20px;
        align-items: start;
    }
    #tapSheet.tap-sheet-both .modal-body > * { grid-column: 1 / -1; }
    #tapSheet.tap-sheet-both #tapPin { grid-column: 1; }
    #tapSheet.tap-sheet-both #tapSignature { grid-column: 2; }
    #tapSheet.tap-sheet-both canvas#tapSignaturePad { height: 240px; }
}

/* The child's sheet (parents by phone, v2 item 8). */
.info-section { margin-bottom: 16px; }
.info-heading {
    margin: 0 0 6px;
    font-size: 1rem;
    color: var(--muted);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}
.info-section .contact-phone {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-height: 44px;
    font-size: 1.1rem;
}
.contact-notes { flex-basis: 100%; margin: 2px 0 0; color: var(--muted); }
.info-pickups { margin: 0; font-weight: 600; }

/* "Signed in 9:14 AM — Undo" */
.tap-toast {
    position: fixed;
    left: 50%;
    bottom: 24px;
    transform: translateX(-50%);
    z-index: 1100;
    display: flex;
    align-items: center;
    gap: 12px;
    max-width: calc(100% - 32px);
    padding: 10px 12px 10px 18px;
    border-radius: var(--border-radius);
    background-color: var(--dark);
    color: white;
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.25);
    font-size: 1.05rem;
}
.tap-toast[hidden] { display: none; }
.tap-undo {
    min-height: 48px;
    padding: 0 16px;
    border: 2px solid white;
    border-radius: var(--border-radius);
    background: transparent;
    color: white;
    font: inherit;
    font-weight: 700;
    cursor: pointer;
}
.tap-undo[hidden] { display: none; }

/* Dialogs keep their buttons on screen (bug B3). The whole dialog used to
   scroll inside itself, so on an 820px tablet "Add New Child" put Save below
   the fold of a box that did not look scrollable. Now only the body scrolls;
   the title and the Cancel/Save row stay put. */
.modal-content {
    display: flex;
    flex-direction: column;
}
.modal-header,
.modal-footer { flex-shrink: 0; }
.modal-body {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
}

/* A wide table on a phone scrolls inside its card (bug B2). Touch browsers
   hide the scrollbar, so say it. */
.scroll-hint { display: none; margin: 0 0 8px; color: var(--muted); font-size: 0.9rem; }
@media (max-width: 768px) {
    .scroll-hint { display: block; }
    .table-container { -webkit-overflow-scrolling: touch; overscroll-behavior-x: contain; }
}

/* Kiosk home (Batch 2, Hershey items a + b): a slim status bar, six big
   buttons in three columns (two rows) and one wide Settings button under
   them -- all on one screen at 1024x768 and 1280x800 with no scrolling
   (tests/e2e/test_b2_home_layout.py). The old Admin strip is gone: its links
   moved into the Settings hub. */
.home-status {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    margin: -8px 0 16px;
    padding: 8px 16px;
    min-height: 44px;
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    background-color: var(--surface);
    color: var(--dark);
    font-size: 1.05rem;
}
.home-status[hidden] { display: none; }
.home-status-item { display: inline-flex; align-items: center; gap: 8px; }
.home-status-item i { color: var(--muted); }
.home-status-sep { color: var(--muted); }
.home-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
.home-grid .menu-button { min-height: 132px; }
.home-settings {
    flex-direction: row;
    align-items: center;
    gap: 16px;
    margin-top: 16px;
    min-height: 72px;
    padding: 14px 24px;
    border-left-color: var(--gray);
}
.home-settings i { margin-bottom: 0; color: var(--gray); }
.home-settings-text { display: flex; flex-direction: column; }
@media (max-width: 900px) {
    .home-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 520px) {
    .home-grid { grid-template-columns: 1fr; }
}
.alert-info {
    background-color: var(--primary-light);
    color: var(--dark);
    border: 1px solid var(--primary-light);
}

/* === v3: the kiosk screen — live clock, keep-screen-on hint, footer dot === */
/* The date header's centre column: the date, and the live clock under it.
   It takes the space .date-display used to take on its own, so Previous /
   Next Day keep their one-line labels. */
.date-center {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
}
.date-center .date-display { width: 100%; flex: none; }
.live-clock {
    font-size: 1.05rem;
    font-weight: 600;
    color: var(--muted);
    font-variant-numeric: tabular-nums;
    letter-spacing: 0.01em;
    line-height: 1.2;
}
.live-clock:empty { display: none; }

/* Never an error: the teal tint of .quick-hint, not an alert colour. */
.wake-hint {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 10px 14px;
    box-sizing: border-box;
    max-width: 1160px;
    margin: 12px auto 0;
    padding: 10px 14px;
    border-radius: var(--border-radius);
    background-color: rgba(47, 143, 131, 0.09);
    color: var(--primary-dark);
    font-size: 0.95rem;
}
/* Real-user round (Oct 23 2026, #25): a fixed bar at the bottom, so showing
   it never moves the page under a finger that is about to tap. */
.wake-hint {
    position: fixed;
    left: 12px;
    right: 12px;
    bottom: 12px;
    z-index: 900;
    margin: 0 auto;
    background-color: #e9f4f2;
    box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
}
.wake-hint[hidden] { display: none; }
.wake-hint span { flex: 1 1 260px; min-width: 0; }
.wake-hint .btn-secondary { width: auto; min-height: 44px; padding: 8px 18px; }
@media (max-width: 1200px) {
    .wake-hint { margin-left: auto; margin-right: auto; }
}

.kiosk-footer {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    max-width: 1200px;
    box-sizing: border-box;
    margin: 0 auto;
    padding: 4px 20px 16px;
    font-size: 0.8rem;
    color: var(--muted);
}
.wake-dot {
    width: 10px;
    height: 10px;
    border-radius: 50%;
    flex-shrink: 0;
    background-color: #B9B3A9;     /* off: a quiet warm grey */
}
.wake-dot[data-state="on"] { background-color: var(--success-strong); }

/* Addendum 4 item 10: "1 pending" -- taps saved on the tablet while Wi-Fi is
   down. Fixed bottom-left so it is seen from anywhere on a long roster; a
   button, because tapping it retries now. Never colour alone: it says what
   it is. */
.tap-queue-badge {
    position: fixed;
    left: 16px;
    bottom: 16px;
    z-index: 1050;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 16px;
    border: 2px solid var(--warning-text);
    border-radius: 999px;
    background-color: white;
    color: var(--warning-text);
    font: inherit;
    font-weight: 700;
    box-shadow: 0 6px 16px rgba(0, 0, 0, 0.15);
    cursor: pointer;
}
.tap-queue-badge[hidden] { display: none; }
/* v9 M6: the roster was served from the tablet's offline copy. */
.offline-roster-banner {
    position: sticky;
    top: 0;
    z-index: 1060;
    padding: 12px 16px;
    border-bottom: 2px solid var(--warning-text);
    background-color: white;
    color: var(--warning-text);
    font-weight: 700;
    text-align: center;
}
.tap-queue-badge.has-failed { border-color: var(--danger-strong); color: var(--danger-strong); }
/* The list behind the badge: what is waiting, what was not saved (with
   Dismiss), and "Try now". */
.tap-queue-panel {
    position: fixed;
    left: 16px;
    bottom: 72px;
    z-index: 1050;
    box-sizing: border-box;
    width: min(420px, calc(100% - 32px));
    max-height: 50vh;
    overflow-y: auto;
    padding: 12px 14px;
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    background-color: white;
    box-shadow: 0 10px 25px rgba(0, 0, 0, 0.2);
}
.tap-queue-panel[hidden] { display: none; }
.tap-queue-panel ul { list-style: none; margin: 0 0 10px; padding: 0; }
.tap-queue-panel li {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    padding: 8px 0;
    border-bottom: 1px solid var(--light-gray);
}
.tap-queue-panel li.is-failed span { color: var(--danger-strong); }
.tap-queue-panel .btn-primary,
.tap-queue-panel .btn-secondary { width: auto; min-height: 44px; }
/* Audit round 1 #11: on the child and staff rosters the badge sits in the
   page heading, in the normal flow, right of the title, so it can never
   cover a card's SIGN IN / SIGN OUT button. The heading keeps the badge's
   height reserved, so the roster does not jump down when a tap goes
   pending under someone's finger. Its list drops down from it. */
.page-heading { min-height: 44px; }
.tap-queue-slot.in-header {
    position: relative;
    margin-left: auto;
    max-width: 100%;
}
.tap-queue-slot.in-header .tap-queue-badge {
    position: static;
    box-shadow: none;
    max-width: 100%;
    text-align: left;
    line-height: 1.3;
    padding: 6px 16px;
}
.tap-queue-slot.in-header .tap-queue-panel {
    position: absolute;
    left: auto;
    right: 0;
    top: calc(100% + 6px);
    bottom: auto;
    width: min(420px, calc(100vw - 32px));
}

/* v3 section 11: a sign-out the closing-time job recorded. A small, quiet
   pill beside the time on the kiosk roster and in the attendance history;
   dark text on a light surface (AA), never colour alone (it says "Auto"). */
.auto-checkout-mark {
    display: inline-block;
    margin-left: 4px;
    padding: 0 6px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    color: var(--text);
    font-size: 0.75em;
    font-weight: 600;
    line-height: 1.5;
    vertical-align: middle;
}

/* v6 audit #10: a time written from the kiosk's offline queue ("Sign-in
   recorded offline at 8:05 AM, sent at 8:41 AM"). Words, not colour alone;
   amber text at AA on the surfaces it sits on. */
.offline-mark {
    display: block;
    margin-top: 2px;
    color: var(--warning-text);
    font-size: 0.8em;
    font-weight: 600;
    line-height: 1.35;
    overflow-wrap: anywhere;
}
.offline-mark[hidden] { display: none; }
.child-card > .offline-mark { flex-basis: 100%; min-width: 0; margin-top: -6px; }

/* v3 section 10: the weekly hours form (templates/portal/_hours_form.html). */
.hours-form { margin: 0; }

/* v3 section 11: "After closing" on the dashboard -- people still signed in
   after closing time. A warning rail, the same weight as other alerts. */
.closing-flags { border-left: 4px solid var(--warning); }

/* v3 3C: the smaller heading on the sign-up verification page. */
.verify-subhead { font-size: 1.15rem; margin: 1.25rem 0 .5rem; }

/* v3 PR 4 item 6: the one printout header (templates/_print_header.html):
   daycare name, NY license #, address. */
.print-header { margin: 0 0 .75rem; }
.print-header .print-header-name { margin: 0 0 .2rem; font-weight: 700; }
.print-header p.print-header-name { font-size: 1.2rem; }
.print-header .print-header-line { margin: 0 0 .15rem; }

/* ===========================================================================
   v4 PHONE LAYOUT PASS
   Phones are 375-390px wide; 768px is tablet portrait and must look as it did
   or better. Only :root tokens. Behaviour lives in static/js/phone-layout.js;
   the checks in tests/e2e/test_phone_layout.py. Every rule below is inside a
   width @media block except the few that give the new elements a default.
   =========================================================================== */

/* --- defaults for the new elements (all widths) --------------------------- */
/* The nav links sit in their own box so a phone can fold them away. */
.portal-nav-menu {
    display: flex;
    align-items: center;
    gap: 4px;
    flex: 1 0 auto;
}
/* Drawn only by the phone rules below (and only once the script has run). */
.portal-nav-toggle,
.phone-toggle { display: none; }

/* Three bars, drawn in CSS: no icon font, nothing to subset. */
.portal-nav-bars,
.portal-nav-bars::before,
.portal-nav-bars::after {
    display: block;
    width: 18px;
    height: 2px;
    border-radius: 1px;
    background: currentColor;
}
.portal-nav-bars { position: relative; }
.portal-nav-bars::before,
.portal-nav-bars::after {
    content: "";
    position: absolute;
    left: 0;
}
.portal-nav-bars::before { top: -6px; }
.portal-nav-bars::after { top: 6px; }

/* .quick-hint is display:flex, which beat the `hidden` attribute: the staff
   screen's filter note (hidden until a search is typed) drew an empty teal
   bar above the roster at every width. */
.quick-hint[hidden] { display: none; }

/* The small secondary button is also put on links ("Edit" beside
   "Deactivate" on Children / Staff). Inline, a link ignored the 44px
   minimum height the phone rules give the family and drew an underlined
   word in a tall grey slab beside a normal button. */
a.btn-secondary-sm {
    display: inline-flex;
    align-items: center;
    box-sizing: border-box;
    text-decoration: none;
}

/* "Back to today" whenever the kiosk shows another day (every width). */
.back-to-today {
    width: auto;
    flex: none;
    margin-left: auto;
    min-height: 44px;
    padding: 8px 16px;
    white-space: nowrap;
}

/* --- portal menu: 1100px and below -----------------------------------------
   Eleven links do not fit a phone or a portrait tablet; they used to scroll
   sideways inside the bar, with most of them off screen and nothing saying
   so. Behind one Menu button they are a plain list, 48px per row. The
   selectors carry .has-toggle (set by the script) so that without JavaScript
   the old scrolling bar still works.
   v8 (Tab U4 / board M9): 1100px, not 768px. At 1024px (a landscape tablet)
   the eleven links still ran past the bar's right edge on child pages, with
   Settings and Sign out scrolled out of sight. */
@media (max-width: 1100px) {
    .portal-nav.has-toggle .portal-nav-inner {
        flex-wrap: wrap;
        overflow-x: visible;
        min-height: 56px;
        padding: 0 16px;
    }
    .portal-nav.has-toggle .portal-nav-toggle {
        display: inline-flex;
        align-items: center;
        gap: 10px;
        margin-left: auto;
        min-height: 44px;
        min-width: 44px;
        padding: 0 14px;
        border: 1px solid var(--border);
        border-radius: var(--border-radius);
        background: var(--surface);
        color: var(--text);
        font: inherit;
        font-weight: 600;
        cursor: pointer;
    }
    .portal-nav.has-toggle .portal-nav-toggle[aria-expanded="true"] {
        background: var(--primary-light);
        border-color: var(--primary-strong);
        color: var(--primary-stronger);
    }
    .portal-nav.has-toggle .portal-nav-toggle:focus-visible {
        outline: 2px solid var(--primary-strong);
        outline-offset: 2px;
    }
    .portal-nav.has-toggle .portal-nav-toggle .nav-badge { margin-left: 0; }
    .portal-nav.has-toggle:not(.is-open) .portal-nav-menu { display: none; }
    .portal-nav.has-toggle .portal-nav-menu {
        flex: 1 0 100%;
        flex-direction: column;
        align-items: stretch;
        gap: 0;
        padding: 4px 0 12px;
        border-top: 1px solid var(--border);
    }
    .portal-nav.has-toggle .portal-nav-link {
        min-height: 48px;
        padding: 0 12px;
        border-bottom: 0;
        border-left: 3px solid transparent;
        color: var(--text);
        font-size: 1.05rem;
    }
    .portal-nav.has-toggle .portal-nav-link.is-current {
        border-left-color: var(--primary-strong);
        background: var(--primary-light);
        color: var(--primary-stronger);
    }
    .portal-nav.has-toggle .portal-nav-end {
        margin: 8px 0 0;
        border-top: 1px solid var(--border);
    }
}

/* --- phones: 640px and below ------------------------------------------------ */
@media (max-width: 640px) {
    /* Less frame, more page: 20px of container padding and a 32px heading
       spent a fifth of a 667px screen before any content. */
    .container { padding: 12px 16px 20px; }
    h1 { font-size: 1.6rem; line-height: 1.25; }
    .page-heading h1 { font-size: 1.45rem; }
    .back-button { margin-bottom: 4px; }
    .container > * + h2,
    .container > * + h3 { margin-top: 24px; }
    .dash-card { padding: 14px; }

    /* The menu's first link is Dashboard; "Back to portal" was a second way
       to the same place, 54px above every page's own content. */
    .portal-nav ~ main .back-button[href="/portal"] { display: none; }
    /* The nav already names the product; the dashboard's second lockup
       under it was 40px of repetition. */
    .portal-nav ~ main .portal-brand { display: none; }

    /* "Summary that expands": counters and filters fold to one line. */
    .phone-toggle:not([hidden]) {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 12px;
        box-sizing: border-box;
        width: 100%;
        min-height: 48px;
        margin: 0 0 12px;
        padding: 10px 14px;
        border: 1px solid var(--border);
        border-radius: var(--border-radius);
        background: var(--light);
        color: var(--text);
        font: inherit;
        text-align: left;
        cursor: pointer;
    }
    .phone-toggle:focus-visible {
        outline: 2px solid var(--primary-strong);
        outline-offset: 2px;
    }
    .phone-toggle-text { min-width: 0; font-weight: 600; }
    .phone-toggle-more {
        flex: none;
        display: inline-flex;
        align-items: center;
        gap: 6px;
        color: var(--primary-strong);
        font-weight: 600;
    }
    .phone-toggle-more i { transition: transform 0.15s; }
    .phone-toggle[aria-expanded="true"] .phone-toggle-more i { transform: rotate(180deg); }
    .phone-collapse:not(.is-open) { display: none; }

    /* Forms: one column, and the submit button is a full-width target. */
    .inline-search .form-group,
    .inline-search > input,
    .inline-search > select { flex-basis: 100%; }
    .inline-search[role="search"] > input { flex-basis: 0; flex-grow: 1; }
    .inline-search .btn-primary,
    .inline-search .btn-secondary { flex: 1 1 auto; }
    .inline-search[role="search"] .btn-primary { flex: none; }

    /* --- the kiosk roster: the cards on the first screen ------------------- */
    .quick-hint { padding: 8px 12px; margin-bottom: 12px; font-size: 0.85rem; }
    /* The counters stay visible but as one row of small tiles, not three
       (five on the staff screen) full-width cards stacked 330px high. */
    .attendance-summary { flex-direction: row; gap: 6px; margin-bottom: 12px; }
    .summary-box { min-width: 0; padding: 8px 4px; }
    .summary-label { margin-bottom: 2px; font-size: 0.72rem; line-height: 1.25; }
    .summary-value { font-size: 1.3rem; line-height: 1.2; }
    .summary-sub { font-size: 0.72rem; line-height: 1.25; }
    /* Date navigation: one row. The arrow buttons keep their words as their
       accessible name ("Previous Day") but show only the chevron. */
    .date-navigation {
        flex-direction: row;
        align-items: center;
        gap: 6px;
        padding: 6px;
        margin-bottom: 12px;
    }
    .date-navigation .nav-button {
        flex: none;
        justify-content: center;
        width: 48px;
        padding: 0;
        font-size: 0;
    }
    .date-navigation .nav-button i { margin: 0 !important; font-size: 1rem; }
    .date-display { padding: 4px; font-size: 0.95rem; }
    .live-clock { font-size: 0.9rem; }
    .search-container { margin-bottom: 12px; }
    .children-grid,
    .staff-grid { gap: 12px; margin-top: 12px; }
    .past-day-banner { flex-wrap: wrap; margin-bottom: 12px; }
    /* Food attendance: "Present" is the tap target, not the 13px box. */
    .meal-checkbox label {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        margin: 0;
        padding: 0 4px;
    }
    .meal-checkbox input[type="checkbox"] { width: 22px; height: 22px; }
}

/* === PR 3: CAPS auto-fill (portal/caps_export.html, caps_fill_*.html) === */
.caps-fill-box { margin-top: 24px; }
/* Round 2B (O): the auto-fill preview table. */
.caps-fill-preview h1 { margin-bottom: 4px; }
.caps-preview-scroll { overflow-x: auto; }
.caps-preview-totals { margin: 12px 0; }
.caps-preview-closed td, .caps-preview-review td { color: var(--muted); }
.caps-preview-review td:last-child { font-style: italic; }
.caps-fill .btn-primary, .caps-fill .btn-secondary {
    width: auto;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    text-decoration: none;
}
.caps-fill-modes {
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    padding: 8px 12px;
    margin: 0 0 12px;
}
.caps-fill-modes legend { font-weight: 600; padding: 0 4px; }
.caps-fill-mode { display: flex; align-items: center; gap: 8px; min-height: 44px; }
.caps-fill-mode input { width: 20px; height: 20px; flex-shrink: 0; }
.caps-fill-meta { color: var(--muted); margin: 0 0 12px; }
.caps-fill-panel {
    background-color: var(--surface);
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    padding: 24px;
    max-width: 720px;
}
.caps-fill-panel h2 { margin: 0 0 12px; font-size: 1.4rem; }
.caps-fill-panel h2 i { color: var(--primary); margin-right: 8px; }
.caps-fill-progress { font-weight: 600; font-size: 1.1rem; }
.caps-fill-summary, .caps-fill-errors { margin: 0 0 12px; padding-left: 20px; }
.caps-fill-summary li, .caps-fill-errors li { margin: 4px 0; }
.caps-fill-errors { color: var(--on-tint-red); }
.caps-fill-review {
    border-left: 4px solid var(--warning);
    padding: 4px 0 4px 12px;
    margin: 0 0 12px;
}
.caps-fill-review h3 { margin: 0 0 6px; font-size: 1.1rem; color: var(--warning-text); }
.caps-fill-review ul { margin: 0 0 8px; padding-left: 20px; }
.caps-fill-review li { margin: 4px 0; overflow-wrap: anywhere; }
.caps-fill-steps { margin: 0 0 8px; padding-left: 22px; }
.caps-fill-steps li { margin: 6px 0; line-height: 1.5; }

/* v7 B05: "Present now" is qualified while taps wait to be sent. */
.summary-pending { color: var(--warning-text); font-weight: 600; }

/* v7 M11: the staff-assisted signature path in the tap sheet. */
.tap-assist-open { margin-top: 8px; }
.tap-assist { display: grid; gap: 6px; margin-top: 8px; padding: 12px;
    border: 1px solid #D8D2C8; border-radius: var(--border-radius); background: var(--surface, #fff); }
.tap-assist[hidden] { display: none; }
.tap-assist-help { margin: 0; color: var(--on-tint-gray); font-size: 0.9rem; }
.tap-assist input, .tap-assist select { width: 100%; min-height: 44px; }

/* v7 P07: the staff result line's close button. */
.result-close { margin-left: auto; font-size: 1.2rem; line-height: 1; padding: 4px 10px; }

/* v9u: the kiosk roster's first screen (child_attendance.html). The three
   count tiles are one compact line, and the "Tap SIGN IN" hint carries its
   own "Got it". Only the child roster: the staff screen keeps its tiles. */
.attendance-summary.summary-line {
    flex-wrap: wrap;
    justify-content: flex-start;
    align-items: baseline;
    gap: 4px 0;
    padding: 8px 6px;
    margin-bottom: 12px;
    background-color: var(--surface);
    border-radius: var(--border-radius);
    box-shadow: var(--box-shadow);
}
.summary-line .summary-box {
    flex: none;
    display: inline-flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0 6px;
    padding: 0 14px;
    min-width: 0;
    background: none;
    box-shadow: none;
    border-radius: 0;
    text-align: left;
    border-left: 1px solid var(--border);
}
/* "Present now" is the number staff look for: shown first on the line. */
.summary-line .summary-box:last-child { order: -1; border-left: none; }
.summary-line .summary-label,
.summary-line .summary-sub { display: inline; margin: 0; font-size: 0.9rem; }
.summary-line .summary-value { display: inline; font-size: 1.25rem; line-height: 1.2; }
.summary-line .summary-sub[hidden] { display: none; }
/* A phone has no room for one sentence of counts: three narrow columns in
   the same bar, still one row (tests/e2e/test_phone_layout.py). */
@media (max-width: 640px) {
    .attendance-summary.summary-line { flex-wrap: nowrap; align-items: stretch; padding: 6px 0; }
    .summary-line .summary-box { flex: 1 1 0; display: block; padding: 0 6px; text-align: center; }
    .summary-line .summary-label,
    .summary-line .summary-sub { display: block; font-size: 0.72rem; line-height: 1.25; }
}

.roster-hint { padding-top: 0; padding-bottom: 0; min-height: 48px; margin-bottom: 12px; }
.roster-hint > span { flex: 1 1 auto; min-width: 0; }
.roster-hint-dismiss {
    flex: none;
    min-height: 48px;
    min-width: 48px;
    padding: 0 12px;
    font-weight: 600;
}

/* v9u: roster and staff cards (child_attendance.html, staff_attendance.html).
   A card is a column: the head row (photo, name, status), then any full-width
   lines (overdue, offline), then the actions pinned to the foot -- so SIGN IN
   sits at the same height in every card of a grid row, and the grid's
   stretch plus one shared minimum keeps the rows even. Scoped to the two
   grids: the portal's section.child-card is a different component. */
:root { --roster-card-min-height: 168px; }
.children-grid > .child-card,
.staff-grid > .staff-card {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 12px;
    min-height: var(--roster-card-min-height);
}
/* In a column, flex-basis is a HEIGHT: .child-actions' 100% basis (a row
   rule) would make the buttons as tall as the card, and shrinking would clip
   the overdue line. Every part keeps its own height. */
.children-grid > .child-card > *,
.staff-grid > .staff-card > * { flex: none; }
.card-head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 14px;
    min-width: 0;
}
.children-grid > .child-card > .child-actions,
.staff-grid > .staff-card > .child-actions { margin-top: auto; }
.children-grid > .child-card > .offline-mark,
.staff-grid > .staff-card > .offline-mark { margin-top: -4px; }
/* The overdue warning: its own full-width line, never more than two lines
   (the whole sentence is in its title and in the button's label). */
.children-grid > .child-card > .overdue-mark,
.staff-grid > .staff-card > .overdue-mark {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    min-width: 0;
    margin-top: -4px;
    font-size: 0.9rem;
    line-height: 1.35;
    overflow-wrap: anywhere;
}
/* Staff: SIGN IN, Absent and Edit times share the foot row and wrap rather
   than pushing Edit times out of the card -- upward (wrap-reverse), so SIGN
   IN stays on the card's bottom line, level with its neighbours'. */
.staff-grid > .staff-card .child-actions { flex-wrap: wrap-reverse; }
.staff-card .child-card-button { flex: 1 1 140px; }
.staff-card .edit-times {
    flex: 0 0 auto;
    min-height: 48px;
    min-width: 48px;
    padding: 0 12px;
    white-space: nowrap;
}
/* The visitor log's Sign Out pill: a 48px target like every other button
   on the kiosk (it was 8px of padding around one line, ~35px tall). */
.sign-out-btn { min-height: 48px; min-width: 48px; padding: 0 20px; }

/* v9u: the PIN keypad (templates/_pin_keypad.html) -- ONE component for the
   admin gate and the roster's staff-unlock and pickup sheets: the same dots,
   keys and type sizes on both. */
.pin-dots {
    display: flex;
    justify-content: center;
    align-items: center;
    gap: 12px;
    min-height: 32px;
    margin: 0 0 16px;
}
.pin-dot {
    flex: none;
    width: 16px;
    height: 16px;
    border-radius: 50%;
    border: 2px solid var(--gray);
    background: transparent;
}
.pin-dot.is-filled { background-color: var(--dark); border-color: var(--dark); }
/* A slot the PIN may leave empty (a 4-8 digit legacy PIN): fainter. */
.pin-dot[data-optional="1"]:not(.is-filled) { border-style: dashed; border-color: var(--border); }
.pin-keypad {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 10px;
    max-width: 320px;
    margin: 0 auto;
}
.pin-key {
    min-height: 60px;
    min-width: 48px;
    padding: 0;
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    background: var(--surface);
    color: var(--dark);
    font: inherit;
    font-size: 1.5rem;
    font-weight: 600;
    line-height: 1;
    cursor: pointer;
}
.pin-key:hover { background-color: var(--primary-light); }
.pin-key-word { font-size: 1rem; color: var(--primary-strong); }
.pin-key-back { font-size: 1.35rem; color: var(--primary-strong); }
/* The step after the keys (admin: Enter; roster: the sheet's Unlock / Save). */
.pin-submit { display: block; width: 100%; max-width: 320px; margin: 14px auto 0; min-height: 56px; }

/* v9u: the roster's staff unlock, counting down the server's window. */
.unlock-countdown {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    color: var(--primary-strong);
}

/* v9u 2b: ONE strong colour per state on the child and staff rosters --
   the chip, the card's left rail and the count all say the same thing:
     in             green       (--success-strong)
     out            neutral     (--on-tint-gray)
     not here yet   teal outline (--primary-strong)
     absent         amber       (--warning-strong)
     overdue        terracotta  (--danger-strong)
   Solid chips carry white text; every pair is one the :root tokens annotate
   at AA (tests/test_contrast.py). Names, chips and counts one size up. */
.chip-in      { background-color: var(--success-strong); color: white; }   /* 5.02:1 */
.chip-out     { background-color: rgba(111, 107, 100, 0.12); color: var(--on-tint-gray); }  /* 6.54:1 */
.chip-none    { background-color: var(--surface); color: var(--primary-strong);
                box-shadow: inset 0 0 0 2px var(--primary-strong); }      /* 5.93:1 */
.chip-absent  { background-color: var(--warning-strong); color: white; }   /* 5.93:1 */
.chip-overdue { background-color: var(--danger-strong); color: white; }    /* 5.99:1 */

.children-grid > .child-card .status-chip,
.staff-grid > .staff-card .status-chip { font-size: 0.95rem; padding: 4px 12px; }
.children-grid > .child-card .child-info h3,
.staff-grid > .staff-card .staff-info h3 { font-size: 1.2rem; }

.children-grid > .child-card.status-in,
.staff-grid > .staff-card.status-in { border-left-color: var(--success-strong); }
.children-grid > .child-card.status-out,
.staff-grid > .staff-card.status-out { border-left-color: var(--on-tint-gray); }
.children-grid > .child-card.status-none,
.staff-grid > .staff-card.status-none { border-left-color: var(--primary-strong); }
.children-grid > .child-card.status-absent,
.staff-grid > .staff-card.status-absent { border-left-color: var(--warning-strong); }
.children-grid > .child-card.is-overdue,
.staff-grid > .staff-card.is-overdue { border-left-color: var(--danger-strong); }

/* The counts: the same colours, one size up. */
.summary-value.summary-in { color: var(--success-strong); }       /* 5.02:1 on white */
.summary-value.summary-out { color: var(--on-tint-gray); }        /* 7.65:1 on white */
.summary-value.summary-none { color: var(--primary-strong); }     /* 5.93:1 on white */
.summary-value.summary-absent { color: var(--warning-text); }     /* 7.09:1 on white */
.attendance-summary .summary-value { font-size: 28px; }
.summary-line .summary-value { font-size: 1.5rem; color: var(--success-strong); }
.summary-line .summary-label,
.summary-line .summary-sub { font-size: 1rem; }
@media (max-width: 640px) {
    .attendance-summary .summary-value { font-size: 1.4rem; }
    .summary-line .summary-label,
    .summary-line .summary-sub { font-size: 0.8rem; }
}
/* .summary-sub is display:block, which beat the [hidden] attribute: the staff
   page read "+ 0 waiting to be sent" with nothing waiting. */
.summary-sub[hidden] { display: none; }

/* v9u item 4: the sign-in/out sheet as numbered steps. The requirements are
   a checklist up front -- a hollow ring while needed, a green tick once done
   -- and each step still missing says so on its own label line, so the
   sheet is no taller than before (the PIN + signature sheet stays on one
   1024x768 screen, tests/e2e/test_fast_signin.py). */
.sheet-checklist {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    margin: 0 0 12px;
    padding: 0;
    list-style: none;
    font-weight: 600;
    color: var(--muted);
}
.sheet-checklist[hidden],
.sheet-checklist li[hidden] { display: none; }
.sheet-checklist li { display: inline-flex; align-items: center; gap: 6px; }
.sheet-checklist li i { color: transparent; font-size: 1.1rem;
                        border-radius: 50%; box-shadow: inset 0 0 0 2px var(--gray); }
.sheet-checklist li.is-done { color: var(--success-strong); }        /* 5.02:1 on white */
.sheet-checklist li.is-done i { color: var(--success-strong); box-shadow: none; }
/* number | what the step is | what it still needs -- one row; the middle
   wraps rather than pushing the need onto lines of its own. */
#tapSheet .tap-step-label { display: flex; align-items: baseline; gap: 8px; }
#tapSheet .tap-step-label > span:not(.step-num):not(.step-need) { flex: 1 1 auto; min-width: 0; }
#tapSheet .modal-header { padding: 14px 20px; }
#tapSheet .modal-footer { padding: 10px 20px; }
#tapSheet .sheet-checklist { margin-bottom: 8px; }
#tapSheet #tapWho { margin-bottom: 12px; }
/* PIN beside signature: the sheet may use the screen's height. */
#tapSheet.tap-sheet-both .modal-content { max-height: 96vh; }
.step-num {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 1.6em;
    height: 1.6em;
    border-radius: 50%;
    background-color: var(--primary-strong);   /* white on it 5.93:1 */
    color: white;
    font-size: 0.9rem;
}
.step-num:empty { display: none; }
.step-need { flex: 0 1 auto; margin-left: auto; text-align: right;
             font-size: 0.95rem; font-weight: 600; color: var(--warning-text); }
.step-need[hidden] { display: none; }
.step-need::before { content: "\2190\00a0"; }   /* the arrow points at the step */
.step-need.is-problem { color: var(--danger-strong); }
#tapSheet .modal-footer .sheet-confirm { min-height: 56px; padding: 0 28px; font-size: 1.1rem; }
#tapSheet .sheet-confirm:disabled {
    background-color: var(--light-gray);
    color: var(--on-tint-gray);
    cursor: not-allowed;
}

/* v9u item 4: "Absent" on a card of a child not here yet, at the size of
   Times / absence; amber, as the Absent state is. */
.card-absent-button {
    flex: 0 0 auto;
    min-height: 56px;
    min-width: 72px;
    padding: 0 12px;
    border: 0;
    border-radius: var(--border-radius);
    background-color: var(--warning-strong);   /* white on it 5.93:1 */
    color: white;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.card-absent-button[hidden] { display: none; }
/* Fix round Oct 23 2026 (item 16): "Undo absent" on a card marked Absent or
   No-show -- the same size, outlined in amber so it reads as an undo. */
.card-undo-absent-button {
    flex: 0 0 auto;
    min-height: 56px;
    min-width: 72px;
    max-width: 9em;
    padding: 0 12px;
    border: 2px solid var(--warning-strong);
    border-radius: var(--border-radius);
    background-color: white;
    color: var(--warning-strong);
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}
.card-undo-absent-button[hidden] { display: none; }
/* Batch 2 (g): "Health check ✓?" after a one-tap sign-in -- the size of
   Times / absence, outlined so it never reads as the big SIGN OUT. */
.card-health-button {
    flex: 0 0 auto;
    min-height: 56px;
    min-width: 72px;
    max-width: 8em;
    padding: 0 12px;
    border: 2px solid var(--primary-strong);
    border-radius: var(--border-radius);
    background: var(--primary-light);
    color: var(--primary-strong);
    font: inherit;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
}
.card-health-button[hidden] { display: none; }
.card-health-button:disabled { opacity: 0.6; cursor: wait; }
/* 29-item round: the optional health check beside one-tap SIGN IN. */
.card-health-pre {
    flex: 0 0 auto;
    min-height: 56px;
    min-width: 72px;
    max-width: 9em;
    padding: 0 10px;
    border: 2px dashed var(--border);
    border-radius: var(--border-radius);
    background: var(--surface);
    color: var(--text);
    font: inherit;
    font-weight: 600;
    line-height: 1.2;
    cursor: pointer;
}
.card-health-pre.is-done { border-style: solid; border-color: var(--primary-strong); color: var(--primary-strong); background: var(--primary-light); }
.card-health-pre[hidden] { display: none; }
.card-edit-link { max-width: 7.5em; line-height: 1.2; }
#absentConfirm .absent-go { background-color: var(--warning-strong); min-height: 56px; }

/* Times / absence opens on two big choices. */
.edit-choice { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; }
.edit-choice[hidden] { display: none; }
.edit-choice-button {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 8px;
    min-height: 120px;
    border: 2px solid var(--primary-strong);
    border-radius: var(--border-radius);
    background: white;
    color: var(--primary-strong);
    font: inherit;
    font-size: 1.2rem;
    font-weight: 700;
    cursor: pointer;
}
.edit-choice-button i { font-size: 1.8rem; }
.edit-choice-button.is-absent { border-color: var(--warning-strong); color: var(--warning-text); }
#editForm[hidden] { display: none; }

#childModal .modal-footer [hidden] { display: none; }

/* v9u item 5: an earlier day's open record -- its dated line (above), and
   the way to fix it, kept apart from today's status chip. */
.overdue-fix {
    align-self: flex-start;
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 48px;
    margin-top: -4px;
    padding: 0 14px;
    border: 2px solid var(--danger-strong);
    border-radius: var(--border-radius);
    background: white;
    color: var(--danger-strong);                 /* 5.99:1 on white */
    font: inherit;
    font-weight: 600;
    text-decoration: none;
    cursor: pointer;
}
.overdue-fix:hover { background-color: rgba(198, 85, 59, 0.08); }

/* v9u item 4b: Times / absence -- big toggles instead of checkboxes. */
.sheet-toggles { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 16px; }
.sheet-toggle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    min-height: 56px;
    padding: 0 18px;
    border: 2px solid var(--primary-strong);
    border-radius: var(--border-radius);
    background: white;
    color: var(--primary-strong);
    font: inherit;
    font-size: 1.05rem;
    font-weight: 600;
    cursor: pointer;
}
.sheet-toggle[aria-pressed="true"] { background-color: var(--primary-strong); color: white; }
.sheet-toggle#absent[aria-pressed="true"],
.sheet-toggle#noShow[aria-pressed="true"] { background-color: var(--warning-strong);   /* white on it 5.93:1 */
                                            border-color: var(--warning-strong); }
.sheet-toggle:disabled { opacity: 0.5; cursor: default; }

/* ── v9u item 6: kiosk language toggle + right-to-left ─────────────────── */
.lang-toggle { display: flex; flex-wrap: wrap; gap: .5rem; justify-content: center; margin: 0 0 1rem; }
.lang-choice {
    min-height: 48px; min-width: 48px; padding: .5rem 1rem;
    border: 1px solid var(--border); border-radius: 999px;
    background: var(--surface); color: var(--text); font-size: 1rem; cursor: pointer;
}
.lang-choice[aria-pressed="true"] {
    background: var(--primary-strong); border-color: var(--primary-strong); color: #fff; font-weight: 600;
}
.lang-choice:focus-visible { outline: 3px solid var(--primary); outline-offset: 2px; }
[dir="rtl"] body { text-align: right; }
[dir="rtl"] .auth-box, [dir="rtl"] .form-group label { text-align: right; }
[dir="rtl"] .lang-toggle { direction: rtl; }

/* -----------------------------------------------------------------------------
   Batch 1 item 8: new-password checklist (templates/_password_rules.html,
   static/js/password-rules.js). A met line shows a check icon and says "done"
   to screen readers; an unmet line shows an empty ring. Colour is never the
   only signal.
   -------------------------------------------------------------------------- */
.pw-rules {
    list-style: none;
    margin: 8px 0 0;
    padding: 0;
    font-size: 14px;
    color: var(--muted);
}
.pw-rule {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 2px 0;
}
.pw-rule-dot {
    display: inline-block;
    box-sizing: border-box;
    width: 14px;
    height: 14px;
    flex: 0 0 14px;
    border: 2px solid var(--on-tint-gray);
    border-radius: 50%;
}
.pw-rule-check {
    display: none;
    width: 14px;
    flex: 0 0 14px;
    color: var(--success-strong);
}
.pw-rule.is-met {
    color: var(--on-tint-green);
}
.pw-rule.is-met .pw-rule-check {
    display: inline-block;
}
.pw-rule.is-met .pw-rule-dot {
    display: none;
}

/* Batch 1: Remove record sits at the far left of the Times / absence footer,
   apart from Cancel and Save, so it is never the button under a thumb. */
.edit-remove { margin-right: auto; }
.pw-rule-state { white-space: nowrap; }   /* the screen-reader "done / not yet" */
/* [hidden] must win over the display these rows and buttons set, or a
   "hidden" Absent toggle or PIN button is still on screen. */
.attendance-options[hidden],
.modal-footer [hidden] { display: none; }

/* === Batch 3 (i): safety reminders (app/safetychecks) ======================
   The kiosk home's slim yellow line, the Drills page's reminder rows, the
   bag/kit checks page, "who did it", and Settings -> Safety reminders.
   Touch targets 48px+ on the kiosk; fits 1024x768. */
.home-reminders {
    display: flex;
    align-items: center;
    gap: 10px;
    margin: -8px 0 16px;
    padding: 8px 16px;
    min-height: 48px;
    border: 1px solid var(--reminder-yellow-border);
    border-left: 5px solid var(--reminder-yellow-border);
    border-radius: var(--border-radius);
    background-color: var(--reminder-yellow);
    color: var(--dark);
    font-size: 1.05rem;
    font-weight: 600;
    text-decoration: none;
}
.home-reminders:hover { border-color: var(--warning-strong); color: var(--dark); }
.home-reminders.is-urgent { border-left-color: var(--danger-strong); }
.home-reminders i { color: var(--warning-text); }
.home-reminders-text { flex: 1 1 auto; min-width: 0; }
.home-reminders-go { margin-left: auto; }
.rem-drills-link { margin: 0 0 16px; }

.rem-panel { margin: 0 0 16px; }
.rem-panel-title { font-size: 1.2rem; margin: 0 0 8px; }
.rem-list { list-style: none; margin: 0; padding: 0; display: grid; gap: 8px; }
.rem-row {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 10px 14px;
    min-height: 64px;
    background-color: var(--surface);
    border: 1px solid var(--border);
    border-left: 5px solid var(--success);
    border-radius: var(--border-radius);
}
.rem-card .rem-row { border: none; border-left: 5px solid var(--success); padding: 0 0 0 12px; min-height: 56px; }
.rem-row.rem-soon, .rem-card .rem-row.rem-soon,
.rem-row.rem-due, .rem-card .rem-row.rem-due { border-left-color: var(--reminder-yellow-border); }
.rem-row.rem-overdue, .rem-card .rem-row.rem-overdue { border-left-color: var(--danger-strong); }
/* .rem-ok: nothing due -- the default green edge above. */
.rem-ok .rem-when { color: var(--muted); }
.rem-soon .rem-when, .rem-due .rem-when { color: var(--warning-text); font-weight: 600; }
.rem-overdue .rem-when { color: var(--danger-strong); font-weight: 600; }
.rem-icon { font-size: 1.4rem; width: 28px; text-align: center; color: var(--muted); }
.rem-main { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; }
.rem-label { font-weight: 600; }
.rem-when { color: var(--muted); font-size: 0.95rem; }
.rem-done {
    width: auto;
    min-height: 52px;
    min-width: 120px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    text-decoration: none;
}
.rem-card { padding: 16px; }
.rem-items { list-style: none; margin: 12px 0 0; padding: 0; }
.rem-item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    padding: 8px 0;
    border-top: 1px solid var(--border);
}
.rem-item-name { flex: 1 1 180px; font-weight: 600; }
.rem-item-date { color: var(--muted); font-size: 0.95rem; }
.rem-badge-amber {
    background-color: rgba(224, 134, 58, 0.15);
    color: var(--warning-text);   /* 6.17:1 on the 15% amber tint */
}
.rem-date { width: auto; min-height: 48px; margin: 0; }

/* "Who did it?" */
.rem-step { font-size: 1.2rem; margin: 20px 0 8px; }
.rem-who-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 10px;
}
.rem-who { width: 100%; min-height: 64px; font-size: 1.1rem; }
.rem-typed { margin-top: 16px; }
.rem-typed label { display: block; font-weight: 600; margin-bottom: 6px; }
.rem-typed-row { display: flex; flex-wrap: wrap; gap: 10px; align-items: center; }
.rem-typed-row input { flex: 1 1 240px; min-height: 52px; margin: 0; }
.rem-typed-done { width: auto; min-height: 52px; min-width: 140px; }

/* Settings -> Safety reminders (portal) */
.rem-btn { width: auto; display: inline-flex; align-items: center; gap: 6px; }
.rem-inline-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 10px; margin-top: 12px; }
.rem-inline-form input[type="text"] { flex: 1 1 200px; max-width: 320px; margin: 0; }
.rem-inline-label { font-weight: 600; }
.rem-freq-row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.rem-freq-label { flex: 0 0 220px; font-weight: 600; margin: 0; }
.rem-freq-select { width: auto; min-width: 200px; margin: 0; }
.rem-days { display: inline-flex; align-items: center; gap: 6px; }
.rem-days[hidden] { display: none; }
.rem-days-input { width: 100px; margin: 0; }
.rem-check { display: flex; align-items: flex-start; gap: 8px; font-weight: normal; margin: 16px 0 12px; min-height: 44px; }
.rem-check input { margin-top: 4px; }
.rem-check-hint { display: block; margin: 0; }
.rem-item-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; flex: 1 1 auto; }
.rem-item-form input[type="text"] { flex: 1 1 200px; margin: 0; }
.rem-item-remove { margin: 0; }
.rem-add { margin-top: 12px; }
.rem-summary { list-style: none; margin: 0 0 8px; padding: 0; }
.rem-summary li { padding: 4px 0; }
.rem-summary .rem-overdue, .rem-summary li.rem-overdue { color: var(--danger-strong); }
.rem-summary li.rem-soon, .rem-summary li.rem-due { color: var(--warning-text); }
.rem-inline-hint { color: var(--muted); font-size: 0.9rem; }
.rem-summary-email { margin: 0 0 12px; }
@media (max-width: 600px) {
    .rem-row { flex-wrap: wrap; }
    .rem-done { width: 100%; }
    .rem-freq-label { flex-basis: 100%; }
}

/* Round 1: a plain on/off switch on the Settings hub (pickup PIN at sign-out). */
.hub-switch { display: flex; align-items: center; gap: 12px; margin: 8px 0; flex-wrap: wrap; }
.hub-switch-label { font-weight: 600; }
.hub-switch-btn { min-width: 72px; min-height: 48px; padding: 0 18px; border-radius: 999px;
                  border: 2px solid var(--border); background: var(--surface); color: var(--muted);
                  font: inherit; font-weight: 700; cursor: pointer; }
.hub-switch-btn.is-on { background: var(--primary-strong); border-color: var(--primary-strong); color: #fff; }

/* Round 2: on the tablet, a provider page opened through the Settings PIN. */
.bridge-bar { display: flex; gap: 16px; align-items: center; justify-content: space-between;
              padding: 8px 16px; background: var(--surface); border-bottom: 1px solid var(--border); }
.bridge-bar form { margin: 0; }
.bridge-bar-link { display: inline-flex; gap: 8px; align-items: center; min-height: 48px;
                   color: var(--primary-strong); font-weight: 600; text-decoration: none; }
.bridge-bar-button { background: none; border: 0; font: inherit; cursor: pointer; padding: 0 8px; }
/* Round 2 (Hershey H): the ratio rule in plain words, Settings -> Ratio rules. */
.ratio-summary { margin: 0 0 12px; }

/* Round 2 (Hershey H): the ratio state in the kiosk home's bar -- green when
   met, red when more staff are needed or a limit is passed. Words, not only
   colour. */
.home-status-ratio { margin-left: auto; padding: 4px 12px; border-radius: 999px; font-weight: 700; }
.home-status-ratio.is-ok { background: var(--success-strong); color: #fff; }
.home-status-ratio.is-short,
.home-status-ratio.is-over { background: var(--danger-strong); color: #fff; }
/* Fix round Oct 23 2026 (item 13): a plain line under the bar says why the
   ratio is not met, with a link to the ratio page. */
.home-status-why { display: flex; flex-wrap: wrap; gap: 6px; align-items: baseline; margin: 4px 0 10px;
    padding: 8px 12px; border-radius: 10px; background: #fdecec; color: #7a1414; font-size: 0.95rem; }
.home-status-why[hidden] { display: none; }
.home-status-why-link { font-weight: 700; color: inherit; }
/* Round 2 (Hershey H): the ratio warning after a sign-in (saved, not blocked). */
.quick-hint.ratio-warn { background: var(--danger-strong); color: #fff; font-weight: 700; }

/* === Round 2B (Hershey I): Settings as big tiles, one short page per tile ===
   templates/portal/settings_home.html, settings_group.html and the
   portal/_settings_*.html parts. The SAME pages on the tablet (through the
   admin PIN) and in the portal. Phones first: one column of tiles, two from
   600px, three from 900px. */
.set-topbar { display: flex; align-items: center; justify-content: space-between;
              gap: 8px 16px; flex-wrap: wrap; }
.set-topbar .back-button { margin-bottom: 0; }
.set-lock { margin: 0; }
.set-btn { width: auto; display: inline-flex; align-items: center; justify-content: center;
           gap: 8px; min-height: 48px; }
.set-title { margin: 8px 0 4px; }
.set-for { margin: 0 0 12px; }
.settings-tiles { display: grid; grid-template-columns: minmax(0, 1fr); gap: 16px; margin: 16px 0; }
@media (min-width: 600px) { .settings-tiles { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (min-width: 900px) { .settings-tiles { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
.settings-tile { min-height: 108px; justify-content: center; border-left-color: var(--primary); }
.settings-tile i { color: var(--primary-strong); }

/* The form pages. */
.settings-page .settings-card { padding: 16px; margin: .75rem 0 0; box-shadow: none; }
.settings-page .settings-card .btn-primary,
.settings-page .settings-card .btn-secondary,
.settings-page .settings-card .btn-danger { width: auto; }
.settings-page .settings-card form + form { margin-top: 1.25rem; padding-top: 1.25rem; border-top: 1px solid var(--border); }
.settings-page fieldset { border: 0; margin: 0; padding: 0; min-width: 0; }
.settings-hint { display: block; color: var(--muted); font-size: .9rem; }
.settings-subhead { font-weight: 600; margin: 1rem 0 .5rem; padding: 0; }
.settings-links { margin: .5rem 0 0; padding-left: 1.25rem; }
.settings-links li { margin: .35rem 0; }
.settings-field { max-width: 360px; }
.settings-switcher { display: flex; flex-wrap: wrap; align-items: flex-end; gap: 8px; margin: 0 0 12px; }
.settings-switcher .form-group { margin-bottom: 0; min-width: 220px; }
.settings-switcher select { margin-bottom: 0; }
.settings-error { color: var(--danger-strong); font-size: .9rem; font-weight: 600; margin: .35rem 0 0; }
.settings-card [aria-invalid="true"] { border-color: var(--danger-strong); }
.settings-error-summary ul { margin: .5rem 0 0; padding-left: 1.25rem; }
.settings-error-summary a { color: inherit; }
.settings-action-form { display: none; }
.set-links { display: flex; flex-wrap: wrap; gap: 8px; margin: 12px 0 0; }
.set-state { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 1rem 0 0; }
.set-state a { display: inline-flex; align-items: center; min-height: 48px; font-weight: 600; }
.set-wide { width: 100%; max-width: 360px; }

/* One option per row: label (and switch) on the left, the small (i) on the
   right, its text on its own line below when opened. */
.set-row { display: grid; grid-template-columns: minmax(0, 1fr) auto; align-items: center;
           column-gap: 8px; }
.set-row > :not(.set-hint-btn):not(label):not(h2):not(h3):not(.ratio-summary):not(.settings-links) { grid-column: 1 / -1; }
.set-row > h2, .set-row > h3 { margin: 0; }
.set-row + .set-row { border-top: 1px solid var(--border); }
.set-switch { display: flex; align-items: center; gap: 14px; min-height: 56px; margin: 0;
              cursor: pointer; font-weight: 600; position: relative; }
.set-switch-input { position: absolute; opacity: 0; width: 52px; height: 32px; margin: 0; left: 0;
                    cursor: pointer; }
.set-switch-track { flex: 0 0 auto; position: relative; width: 52px; height: 32px; border-radius: 999px;
                    background: var(--border); border: 2px solid #D8D2C8; box-sizing: border-box;
                    transition: background-color .15s, border-color .15s; }
.set-switch-track::after { content: ""; position: absolute; top: 2px; left: 2px; width: 24px; height: 24px;
                           border-radius: 50%; background: var(--surface); box-shadow: 0 1px 2px rgba(43, 42, 40, .25);
                           transition: transform .15s; }
.set-switch-input:checked + .set-switch-track { background: var(--primary-strong); border-color: var(--primary-strong); }
.set-switch-input:checked + .set-switch-track::after { transform: translateX(20px); }
.set-switch-input:focus-visible + .set-switch-track { outline: 3px solid var(--primary-strong); outline-offset: 2px; }
.set-switch-input:disabled + .set-switch-track { opacity: .5; }
.set-switch-label { line-height: 1.3; }
.set-hint-btn { width: 48px; height: 48px; padding: 0; border: 0; background: none; cursor: pointer;
                display: inline-flex; align-items: center; justify-content: center; }
.set-hint-btn[hidden] { display: none; }
.set-hint-btn > span[aria-hidden="true"] { width: 26px; height: 26px; border-radius: 50%;
                border: 2px solid var(--muted); color: var(--muted); font: italic 700 15px/22px Georgia, serif;
                text-align: center; box-sizing: border-box; }
.set-hint-btn[aria-expanded="true"] > span[aria-hidden="true"] { border-color: var(--primary-strong);
                color: #fff; background: var(--primary-strong); }
.set-hint-btn:focus-visible { outline: 3px solid var(--primary-strong); outline-offset: -3px; border-radius: 50%; }
.set-hint-text { margin: 0 0 10px; color: var(--muted); font-size: .92rem; }
.set-hint-text[hidden] { display: none; }

/* The page's one Save: at the end of the page, never sticky. */
.set-save { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; margin: 1.5rem 0 0; }
.set-save .btn-primary { width: auto; min-width: 160px; margin: 0; }
.set-save-status { margin: 0; color: var(--text); font-weight: 600; }
@media (max-width: 599px) {
    .set-save .btn-primary { width: 100%; }
}
/* Round 2: a person's name entered as "First name" + "Last name" (staff and
   visitor forms). Side by side where there is room, stacked on a phone; each
   field at least the kiosk's 48px touch floor. */
.person-name-pair { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0 16px; }
.person-name-pair input { min-height: 48px; }
@media (max-width: 600px) { .person-name-pair { grid-template-columns: 1fr; } }
.person-name-optional { font-weight: 400; color: var(--muted); }
/* === Round 2: one row per uploaded file (templates/_file_row.html) ===
   "<name>  <date>  View · Rename · Remove" on every list of files. */
.file-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; padding: 4px 0; }
.file-row-name { font-weight: 600; overflow-wrap: anywhere; min-width: 0; }
.file-row-name .fa-solid { color: var(--muted); margin-right: 4px; }
.file-row-meta { color: var(--muted); font-size: .9rem; }
.file-list > .file-row { border-bottom: 1px solid var(--border); padding: 6px 0; }
.file-list > .file-row:last-child { border-bottom: 0; }
.file-act { display: inline-flex; align-items: center; min-height: 44px; margin: 0; }
.file-act + .file-act::before { content: "\00B7"; color: var(--muted); margin-right: 12px; }
a.file-act, .file-rename > summary, .link-btn {
    color: var(--primary-strong);
    text-decoration: underline;
    cursor: pointer;
}
.link-btn { background: none; border: 0; padding: 0; min-height: 44px; font: inherit; }
a.file-act:hover, .file-rename > summary:hover, .link-btn:hover { color: var(--text); }
.file-rename > summary { min-height: 44px; display: inline-flex; align-items: center; list-style: none; }
.file-rename > summary::-webkit-details-marker { display: none; }
.file-rename[open] { display: block; flex-basis: 100%; order: 10; }
.file-rename[open]::before { content: none; }
.file-rename-form { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; margin: 0 0 6px; }
.file-rename-form input[type="text"] { flex: 1 1 240px; max-width: 520px; margin: 0; }
.file-rename-form .btn-primary, .file-rename-form .btn-secondary { width: auto; margin: 0; }

/* Round 2B (Hershey Q): Settings -> Advanced -> Activity log. */
.settings-advanced { margin: 24px 0 0; }
.activity-filter { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 8px 16px; align-items: end; margin: 0 0 16px; }
.activity-filter .btn-primary { width: auto; min-height: 48px; }
.activity-list { list-style: none; margin: 0; padding: 0; }
.activity-row { display: grid; grid-template-columns: 11rem 1fr; gap: 2px 16px; padding: 10px 0; border-bottom: 1px solid var(--border); }
.activity-when { color: var(--muted); font-size: .9rem; }
.activity-who { font-weight: 600; }
.activity-what { grid-column: 2; }
.activity-detail { grid-column: 2; color: var(--muted); font-size: .9rem; overflow-wrap: anywhere; }
@media (max-width: 600px) {
    .activity-row { grid-template-columns: 1fr; }
    .activity-what, .activity-detail { grid-column: 1; }
}
/* Round 2B (Hershey R): Log out is a POST form; the button keeps the link's look. */
.logout-form { margin: 0; }
button.logout-link { background: none; border: 0; font: inherit; cursor: pointer; }
.signed-out { text-align: center; padding-top: 48px; }
/* A checkbox with its label (the staff form); was styled by the old one-page
   Settings' own <style> block, which the redesign removed. */
.settings-check { display: flex; align-items: flex-start; gap: 10px; min-height: 44px; margin: 8px 0; cursor: pointer; }
.settings-check input[type="checkbox"] { width: 22px; height: 22px; margin: 2px 0 0; flex: 0 0 auto; }

/* --- Round 3: card billing + promo codes (portal Billing, sign-up, Super Admin) --- */
.bill-price { margin: 16px 0; }
.bill-status { margin: 0 0 12px; }
.bill-lines { width: 100%; border-collapse: collapse; margin: 0 0 16px; }
.bill-lines th, .bill-lines td { padding: 10px 4px; border-bottom: 1px solid var(--border); text-align: left; font-weight: 400; }
.bill-lines td { text-align: right; white-space: nowrap; }
.bill-promo th, .bill-promo td { color: var(--on-tint-green); }
.bill-total th, .bill-total td { font-size: 1.15rem; border-bottom: 0; }
.bill-total s { color: var(--muted); }
.bill-promo-form { margin: 0 0 16px; }
.caps-ck { scroll-margin-top: 16px; }
.caps-ck-form { margin: 0; }
.caps-ck-note { margin: 0 0 8px; }
.caps-ck-list { border: 0; margin: 0 0 12px; padding: 0; }
.caps-ck-row { display: flex; flex-wrap: wrap; align-items: center; gap: 4px 12px; min-height: 52px; padding: 8px 4px; border-bottom: 1px solid var(--border); cursor: pointer; }
.caps-ck-row input[type=checkbox] { width: 24px; height: 24px; flex: 0 0 auto; margin: 0; }
.caps-ck-name { flex: 1 1 12rem; font-weight: 600; }
.caps-ck-num { flex: 0 0 auto; font-size: .95rem; }
.caps-ck-actions { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 12px; }
.bill-promo-row { display: flex; gap: 10px; align-items: stretch; }
.bill-promo-row input { flex: 1 1 auto; min-height: 48px; margin: 0; text-transform: uppercase; }
.bill-promo-row .btn-secondary { width: auto; min-height: 48px; padding: 0 22px; }
.bill-btn { min-height: 56px; font-size: 1.1rem; display: inline-flex; gap: 10px; align-items: center; justify-content: center; }
.promo-msg { margin: 6px 0 0; }
.promo-msg-ok { color: var(--on-tint-green); }
.promo-msg-bad { color: var(--on-tint-red); }
.stripe-card { display: flex; flex-wrap: wrap; gap: 8px 24px; align-items: center; margin: 0 0 24px; }
.stripe-card h2 { margin: 0; font-size: 1.1rem; }
.promo-form { display: flex; flex-wrap: wrap; gap: 10px 16px; align-items: flex-end; margin: 0; }
.promo-form label { display: block; font-size: .85rem; color: var(--muted); margin: 0 0 2px; }
.promo-form input, .promo-form select { margin: 0; min-height: 44px; }
.promo-form .promo-code { width: 10rem; text-transform: uppercase; }
.promo-form .promo-value { width: 6rem; }
.promo-form .promo-max { width: 6rem; }
.promo-form .btn-primary, .promo-form .btn-secondary { width: auto; min-height: 44px; }
.promo-check { display: flex; gap: 8px; align-items: center; min-height: 44px; }
.promo-check input[type="checkbox"] { width: 22px; height: 22px; }
.promo-off { opacity: .6; }
/* Round 3 item 5: the Visitor Log's big "Add New Visitor" button. Its label
   read as near-invisible on the tablet; the darkest teal (white 8.54:1), a
   bigger bold label, and the fill pinned so no hover/auto-dark tint can
   lighten it under the white text. */
.visitor-add-btn,
.visitor-add-btn:hover,
.visitor-add-btn:focus,
.visitor-add-btn:active {
    background-color: var(--primary-stronger);
    color: #FFFFFF;
    -webkit-text-fill-color: #FFFFFF;
}
.visitor-add-btn { min-height: 60px; font-size: 1.2rem; font-weight: 700; letter-spacing: 0.01em; }
/* --- Round 3 item 11: logo + photos ---------------------------------------
   One face component (templates/_avatar.html): the photo, or the initials on
   the soft teal tint. sm = lists, md = the roster cards, lg = the record. */
.avatar {
    display: inline-flex; align-items: center; justify-content: center;
    flex-shrink: 0; border-radius: 50%; object-fit: cover;
    background: var(--primary-light); vertical-align: middle;
}
.avatar-sm { width: 40px; height: 40px; font-size: .9rem; }
.avatar-md { width: 60px; height: 60px; font-size: 1.25rem; }
.avatar-lg { width: 96px; height: 96px; font-size: 2rem; }
.avatar-initials {
    color: var(--primary-strong);   /* 4.86:1 on --primary-light */
    font-weight: 700; letter-spacing: .02em; line-height: 1;
    user-select: none;
}
/* The roster cards' round frame already clips: the face fills it. */
.child-photo > .avatar, .staff-photo > .avatar { width: 100%; height: 100%; }
td > .avatar-sm { margin-right: 8px; }

/* The daycare's logo above every tablet / portal page (base.html). */
.daycare-header {
    display: flex; justify-content: center; align-items: center;
    padding: 6px 16px; background: var(--surface);
    border-bottom: 1px solid var(--border);
}
.daycare-logo { display: block; max-width: min(400px, 80vw); max-height: 48px; width: auto; height: auto; object-fit: contain; }
.daycare-logo-menu { max-height: 56px; max-width: 200px; }
.daycare-logo-preview { max-height: 120px; }
.daycare-header-name { font-weight: 700; font-size: 1.2rem; color: var(--text); }
.menu-title-row { display: flex; align-items: center; gap: 12px; min-width: 0; }
.print-header-logo { display: block; max-height: 60px; max-width: 240px; margin: 0 0 .3rem; }
@media print { .daycare-header { display: none; } }

/* Add/Edit child and staff: the photo field (templates/_photo_field.html). */
.photo-field { margin-bottom: 16px; }
.photo-field-label { display: block; font-weight: 600; margin-bottom: 6px; }
.photo-field-row { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; }
.photo-field-preview { display: inline-flex; }
.photo-pick {
    position: relative; display: inline-flex; align-items: center;
    min-height: 48px; padding: 0 18px; cursor: pointer;
}
.photo-pick:focus-within { outline: 3px solid var(--primary); outline-offset: 2px; }
.photo-input, .logo-input {
    position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden;
}
.photo-remove { min-height: 48px; color: var(--danger-strong); }
.record-title { display: flex; align-items: center; gap: 16px; }
.record-title > h1 { margin: 0; }

/* Settings -> Daycare info -> Logo. */
.logo-card { display: flex; flex-direction: column; gap: 12px; }
.logo-preview {
    display: flex; align-items: center; justify-content: center;
    min-height: 96px; padding: 12px; border: 1px dashed var(--border);
    border-radius: 8px; background: var(--bg);
}
.logo-form { display: flex; flex-wrap: wrap; gap: 12px; align-items: center; margin: 0; }
/* Round 3 (item 9): the Forms drill-down (templates/forms.html, formtree/). */
.forms-head { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 12px; margin-bottom: 16px; }
.forms-head h1 { margin: 0; }
.forms-search-btn { width: auto; display: inline-flex; align-items: center; gap: 8px; min-height: 52px; text-decoration: none; }
.forms-big-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; }
.forms-big-btn { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
                 min-height: 170px; padding: 20px; text-align: center; text-decoration: none; color: var(--dark);
                 background: var(--surface); border: 1px solid var(--border); border-bottom: 5px solid var(--primary);
                 border-radius: var(--border-radius); box-shadow: var(--box-shadow); font-size: 1.3rem; font-weight: 600; }
.forms-big-btn i { font-size: 40px; color: var(--primary-strong); }
.forms-big-btn:hover, .forms-big-btn:focus-visible { border-bottom-color: var(--primary-strong); background: var(--light); }
@media (min-width: 1000px) { .forms-big-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
.forms-name-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 12px; }
.forms-name-btn { display: flex; align-items: center; gap: 14px; min-height: 76px; padding: 12px 16px; text-decoration: none;
                  color: var(--dark); background: var(--surface); border: 1px solid var(--border);
                  border-radius: var(--border-radius); box-shadow: var(--box-shadow); font-weight: 600; font-size: 1.1rem; }
.forms-name-btn:hover, .forms-name-btn:focus-visible { border-color: var(--primary); }
.forms-name-text { overflow-wrap: anywhere; min-width: 0; }
.forms-person-head { display: flex; align-items: center; gap: 14px; margin: 4px 0 16px; }
.forms-person-head h1 { margin: 0; overflow-wrap: anywhere; }
.forms-leaf-sep { color: var(--muted); font-weight: 400; }
.forms-type-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 12px; }
.forms-type-btn { display: flex; align-items: center; justify-content: space-between; gap: 10px; min-height: 84px;
                  padding: 14px 18px; text-decoration: none; color: var(--dark); background: var(--surface);
                  border: 1px solid var(--border); border-left: 5px solid var(--primary);
                  border-radius: var(--border-radius); box-shadow: var(--box-shadow); font-weight: 600; font-size: 1.1rem; }
.forms-type-btn:hover, .forms-type-btn:focus-visible { background: var(--light); }
.forms-type-misc { border-left-color: var(--muted); }
.forms-type-name { overflow-wrap: anywhere; min-width: 0; }
.forms-count { flex: 0 0 auto; min-width: 32px; padding: 2px 10px; border-radius: 999px; text-align: center;
               background: var(--primary-light); color: var(--primary-stronger); font-size: .95rem; }
.forms-empty { color: var(--muted); text-align: center; padding: 24px 0; }
.forms-add { display: flex; flex-wrap: wrap; gap: 12px; margin: 0 0 16px; }
.forms-add-form { margin: 0; }
.forms-add-btn { position: relative; width: auto; display: inline-flex; align-items: center; justify-content: center;
                 gap: 8px; min-height: 56px; padding: 0 22px; cursor: pointer; font-size: 1.05rem; }
.forms-file-input { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.forms-add-btn:focus-within { outline: 3px solid var(--primary-strong); outline-offset: 2px; }
.forms-files { background: var(--surface); border: 1px solid var(--border); border-radius: var(--border-radius); padding: 8px 16px; }
.formtypes-rename > summary { list-style: none; cursor: pointer; }
.formtypes-rename > summary::-webkit-details-marker { display: none; }
.formtypes-rename[open] { flex-basis: 100%; }

/* CAPS item 2: a preview row whose CAPS child number is missing or invalid. */
.caps-number-missing { color: var(--danger-strong); font-weight: 600; }

/* Fill CAPS (helper 1.4.0): the one big button and the result line. */
.caps-fill-big {
    font-size: 1.25rem;
    min-height: 56px;
}

/* Parent applications, provider side (templates/applications/). */
.app-narrow { max-width: 560px; }
.app-review { max-width: 960px; }
.app-card { background: var(--surface); border: 1px solid var(--border);
    border-radius: var(--border-radius); box-shadow: var(--box-shadow);
    padding: 16px; margin: 0 0 16px; }
.app-step { font-size: 1.15rem; margin: 0 0 12px; color: var(--dark); }
.app-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
    gap: 0 16px; }
.app-link-input { width: 100%; font-size: 1rem; margin-bottom: 12px; }
.app-copy { min-height: 56px; font-size: 1.1rem; }
.app-tabs { display: flex; flex-wrap: wrap; gap: 8px; margin: 8px 0 16px; }
.app-tab { display: inline-flex; align-items: center; gap: 8px; min-height: 48px;
    padding: 0 16px; border: 1px solid var(--border); border-radius: 999px;
    background: var(--surface); color: var(--dark); text-decoration: none; }
.app-tab-on { background: var(--primary-strong); border-color: var(--primary-strong);
    color: #fff; }
.app-count { font-weight: 600; }
.app-list { list-style: none; margin: 0; padding: 0; }
.app-row { display: flex; flex-wrap: wrap; gap: 4px 16px; align-items: baseline;
    min-height: 56px; padding: 12px 16px; margin-bottom: 8px; background: var(--surface);
    border: 1px solid var(--border); border-radius: var(--border-radius);
    color: var(--dark); text-decoration: none; }
.app-row:hover { border-color: var(--primary); }
.app-row-name { font-weight: 600; flex: 1 1 200px; }
.app-row-meta { color: var(--muted); font-size: .92rem; }
.app-empty { color: var(--muted); }
.app-value { padding: 8px 0; min-height: 24px; white-space: pre-wrap; }
.app-checks { display: flex; flex-wrap: wrap; gap: 4px 16px; }
.app-error { color: var(--danger-strong); font-size: .92rem; margin-top: 4px; }
.app-field-error input, .app-field-error select, .app-field-error textarea {
    border-color: var(--danger-strong); }
.app-repeat { border-top: 1px solid var(--border); padding-top: 12px; margin-top: 12px; }
.app-repeat:first-of-type { border-top: 0; margin-top: 0; padding-top: 0; }
.app-repeat-head { display: flex; justify-content: space-between; align-items: center;
    font-weight: 600; margin-bottom: 8px; }
.app-files { list-style: none; margin: 0; padding: 0; }
.app-files li { display: flex; justify-content: space-between; align-items: center;
    gap: 12px; padding: 8px 0; border-bottom: 1px solid var(--border); }
.app-approve { border-color: var(--primary); }
.app-danger-row { margin-top: 8px; }
.app-status { display: inline-block; padding: 2px 10px; border-radius: 999px;
    font-size: .85rem; font-weight: 600; background: var(--light-gray); color: var(--on-tint-gray); }
.app-status-submitted { background: var(--primary-light); color: var(--primary-stronger); }
.app-status-sent { background: var(--light-gray); color: var(--on-tint-gray); }
.app-status-approved { background: var(--secondary-light); color: var(--on-tint-green); }
.app-status-declined { background: #F8EBE7; color: var(--on-tint-red); }
.app-badge { display: inline-block; min-width: 1.5em; padding: 0 6px; margin-left: 4px;
    border-radius: 999px; background: var(--danger-strong); color: #fff;
    font-size: .85rem; text-align: center; }
/* Parent application form (/apply/<token>, templates/applications/):
   mobile-first, one column on a phone, two on a tablet. */
.apf-page { background: var(--bg); margin: 0; }
.apf-main { max-width: 760px; margin: 0 auto; padding: 16px 16px 120px; }
.apf-head { text-align: center; padding: 8px 0 16px; }
.apf-logo { display: block; max-width: 240px; max-height: 80px; margin: 0 auto 8px; object-fit: contain; }
.apf-daycare { font-size: 1.4rem; margin: 0; color: var(--text); }
.apf-flash { background: var(--surface); border: 1px solid var(--danger); border-left: 5px solid var(--danger);
             border-radius: var(--border-radius); padding: 10px 14px; margin-bottom: 12px; color: var(--danger-strong); }
.apf-flash p { margin: 4px 0; }
.apf-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--border-radius);
            padding: 16px; margin-bottom: 14px; }
.apf-card h2 { font-size: 1.15rem; margin: 0 0 12px; color: var(--primary-strong); }
.apf-card h3 { font-size: 1rem; margin: 0 0 8px; }
.apf-message { text-align: center; padding: 32px 16px; }
.apf-message h2 { font-size: 1.4rem; color: var(--text); }
.apf-form { margin: 0; }
.apf-saved { background: var(--secondary-light); color: var(--on-tint-green); border-radius: var(--border-radius);
             padding: 10px 14px; font-weight: 600; margin: 0 0 12px; }
.apf-error-top { background: var(--surface); border-left: 5px solid var(--danger); padding: 10px 14px;
                 color: var(--danger-strong); font-weight: 600; margin: 0 0 12px; border-radius: var(--border-radius); }
.apf-grid { display: grid; grid-template-columns: 1fr; gap: 0 14px; }
.apf-field { margin-bottom: 12px; min-width: 0; }
.apf-field label { margin-bottom: 4px; }
.apf-field input, .apf-field textarea, .apf-field select { width: 100%; box-sizing: border-box; min-height: 48px; font-size: 16px; }
.apf-field-check input { width: auto; min-height: 0; }
.apf-field-bad input, .apf-field-bad textarea, .apf-field-bad select { border-color: var(--danger); }
.apf-error { display: block; color: var(--danger-strong); font-size: .95rem; margin-top: 4px; }
.apf-rows { display: block; }
.apf-row { border: 1px solid var(--border); border-radius: var(--border-radius); padding: 10px 12px 2px; margin: 0 0 12px; }
.apf-row-title { font-weight: 600; padding: 0 6px; color: var(--muted); }
.apf-add { width: 100%; }
.apf-upload { margin-bottom: 16px; }
.apf-file { display: flex; align-items: center; justify-content: space-between; gap: 10px; padding: 8px 0;
            border-bottom: 1px solid var(--border); }
.apf-file-name { overflow-wrap: anywhere; min-width: 0; }
.apf-remove { flex: 0 0 auto; }
.apf-file-label { margin: 10px 0 4px; }
.apf-upload-btn { width: 100%; margin-top: 8px; }
.apf-actions { position: sticky; bottom: 0; display: grid; grid-template-columns: 1fr 1fr; gap: 12px;
               background: var(--bg); padding: 12px 0; border-top: 1px solid var(--border); }
.apf-big { min-height: 60px; font-size: 1.15rem; width: 100%; }
@media (min-width: 640px) {
    .apf-grid { grid-template-columns: 1fr 1fr; }
    .apf-field-wide { grid-column: 1 / -1; }
}
.apf-daycare-info { margin: 4px 0 0; color: var(--muted); font-size: .95rem; }
.apf-dots { display: flex; flex-wrap: wrap; justify-content: center; gap: 8px; margin: 0 0 14px; }
.apf-dot { width: 36px; height: 36px; border-radius: 50%; border: 2px solid var(--border); background: var(--surface);
           color: var(--muted); font-weight: 600; font-size: .9rem; cursor: pointer; padding: 0; }
.apf-dot-done { background: var(--primary-light); border-color: var(--primary); color: var(--primary-stronger); }
.apf-dot-current { background: var(--primary-strong); border-color: var(--primary-strong); color: white; }
.apf-dot-todo { background: var(--surface); }
.apf-count { margin: 0; color: var(--muted); font-size: .9rem; }
.apf-note { background: var(--primary-light); color: var(--primary-stronger); border-radius: var(--border-radius);
            padding: 10px 14px; font-weight: 600; }
.apf-statement { margin: 16px 0 0; font-size: .85rem; color: var(--muted); line-height: 1.45; }
.apf-req { color: var(--danger-strong); }
.apf-check { display: flex; align-items: flex-start; gap: 10px; font-weight: 500; cursor: pointer; }
.apf-check input, .apf-choice input { width: 24px; height: 24px; min-height: 0; flex: 0 0 auto; margin: 0; }
.apf-choices { border: 0; padding: 0; margin: 0; min-width: 0; }
.apf-choices legend { font-weight: 500; margin-bottom: 6px; padding: 0; }
.apf-choice { display: flex; align-items: flex-start; gap: 10px; padding: 10px 12px; margin: 0 0 6px; font-weight: 400;
              border: 1px solid var(--border); border-radius: var(--border-radius); background: var(--light); cursor: pointer; }
.apf-signature canvas { height: 180px; }
.apf-signed { color: var(--on-tint-green); font-weight: 600; margin: 6px 0; }
.apf-clear { margin-top: 8px; }
.apf-field[hidden] { display: none; }
.app-dl { display: grid; grid-template-columns: minmax(140px, 1fr) 2fr; gap: 6px 16px; margin: 0; }
.app-dl dt { color: var(--muted); }
.app-dl dd { margin: 0; white-space: pre-wrap; }
.app-tag { font-size: .8rem; font-weight: 600; padding: 2px 8px; border-radius: 999px;
    background: #F8EBE7; color: var(--on-tint-red); }
.app-food { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px;
    margin: 8px 0 16px; }
.app-food-ok { color: var(--on-tint-green); font-weight: 600; }
.app-food-wait { color: var(--warning-text); font-weight: 600; }
.app-food-upload { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.app-file-input { max-width: 220px; }
/* Parent application: save-for-later, the thank-you upload (apps2). */
.apf-later { grid-column: 1 / -1; }
.apf-done-actions { display: grid; grid-template-columns: 1fr; gap: 12px; margin-top: 16px; }
@media (min-width: 640px) { .apf-done-actions { grid-template-columns: 1fr 1fr; } }
.apf-file-hidden { position: absolute; width: 1px; height: 1px; opacity: 0; overflow: hidden; }
.apf-received { color: var(--on-tint-green); font-weight: 600; }
.apf-link-input { width: 100%; box-sizing: border-box; min-height: 48px; font-size: 16px; margin: 12px 0; }

/* Fill CAPS bookmark (templates/portal/caps_fill_bookmark.html, the
   bookmark panel of caps_fill_working.html). */
.caps-bm-copied { margin-left: 12px; color: var(--on-tint-green); font-weight: 600; }
.caps-bm-drag { cursor: grab; }

/* --- Kiosk alerts (app/kioskalerts): the one big pop-up, the card's Add
   note and its badge, Settings -> Alerts. Colours from the :root tokens. --- */
.ck-popup-overlay {
    position: fixed; inset: 0; z-index: 3000;
    display: flex; align-items: center; justify-content: center;
    padding: 16px; background: rgba(43, 42, 40, .55);
}
.ck-popup {
    width: 100%; max-width: 560px; max-height: calc(100vh - 32px); overflow-y: auto;
    padding: 28px 24px 20px; border-radius: 16px;
    background: var(--surface); color: var(--text);
    border-top: 8px solid var(--primary);
    box-shadow: 0 12px 40px rgba(0, 0, 0, .25);
}
.ck-popup-overdue { border-top-color: var(--danger-strong); }
.ck-popup-staff { border-top-color: var(--warning); }
.ck-popup-note { border-top-color: var(--primary-strong); }
.ck-popup-title { margin: 0 0 14px; font-size: 1.6rem; line-height: 1.25; }
.ck-popup-lines { margin: 0 0 20px; padding: 0; list-style: none; }
.ck-popup-lines li {
    padding: 12px 0; border-bottom: 1px solid var(--border);
    font-size: 1.3rem; line-height: 1.35;
}
.ck-popup-lines li:last-child { border-bottom: 0; }
.ck-popup-actions { display: flex; gap: 12px; justify-content: flex-end; flex-wrap: wrap; }
.ck-popup-btn {
    min-height: 64px; min-width: 140px; padding: 0 24px;
    border: 1px solid var(--border); border-radius: 12px;
    background: var(--surface); color: var(--primary-strong);
    font: inherit; font-size: 1.25rem; font-weight: 700; cursor: pointer;
}
.ck-popup-btn.is-primary { background: var(--primary-strong); border-color: var(--primary-strong); color: #fff; }
.ck-popup-btn.is-primary:hover { background: var(--primary-stronger); }
.ck-popup-btn:focus-visible { outline: 3px solid var(--warning-strong); outline-offset: 2px; }
.ck-note-quick { display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 12px; }
.ck-note-chip {
    min-height: 52px; padding: 0 16px; border-radius: 26px;
    border: 1px solid var(--border); background: var(--light-gray); color: var(--text);
    font: inherit; font-weight: 600; cursor: pointer;
}
.ck-note-chip:hover { background: var(--primary-light); }
.ck-note-text {
    width: 100%; min-height: 96px; padding: 12px; box-sizing: border-box;
    border: 1px solid var(--border); border-radius: 10px; font: inherit; font-size: 1.15rem;
}
.ck-note-error { margin: 8px 0 0; color: var(--danger-strong); font-weight: 600; }
.ck-note-history { margin: 16px 0 12px; padding: 0; list-style: none; color: var(--muted); }
.ck-note-history li { padding: 6px 0; border-bottom: 1px solid var(--border); }
.ck-note-state { color: var(--muted); }
.card-note-link {
    flex: 0 0 auto; min-height: 56px; min-width: 72px; max-width: 7.5em; padding: 0 12px;
    border: 1px solid var(--border); border-radius: var(--border-radius);
    background: white; color: var(--primary-strong);
    font: inherit; font-weight: 600; line-height: 1.2; cursor: pointer;
}
.card-note-link:hover { background-color: var(--primary-light); }
.note-badge {
    display: inline-flex; align-items: center; gap: 4px; margin-top: 4px;
    padding: 2px 10px; border-radius: 12px;
    background: var(--primary-light); color: var(--primary-strong);
    font-size: .85rem; font-weight: 700;
}
.note-badge[hidden] { display: none; }
.alert-setting { padding: 8px 0 16px; border-bottom: 1px solid var(--border); margin-bottom: 12px; }
.alert-setting:last-child { border-bottom: 0; margin-bottom: 0; }
/* APPS3: the parent application's own questions (help line, Submit summary)
   and Settings -> Applications -> Questions. */
.apf-help { display: block; color: var(--muted); font-size: 0.9rem; margin-top: 4px; }
.apf-missing { background: var(--surface); border-left: 5px solid var(--danger); padding: 10px 14px;
               margin: 0 0 12px; border-radius: var(--border-radius); }
.apf-missing p { margin: 6px 0; }
.apf-missing-title { font-weight: 700; color: var(--danger-strong); }
.apf-missing-step { min-height: 44px; padding: 6px 14px; margin-right: 8px; font-weight: 600;
                    background: var(--secondary-light); color: var(--text); border: 1px solid var(--border);
                    border-radius: var(--border-radius); cursor: pointer; }
.aq-gaps { display: flex; flex-wrap: wrap; align-items: center; gap: 12px; padding: 14px;
           background: var(--surface); border: 1px solid var(--border); border-radius: var(--border-radius);
           margin: 0 0 18px; }
.aq-gaps-label { flex: 1 1 240px; font-weight: 600; }
.aq-step { margin: 0 0 22px; }
.aq-step-title { font-size: 1.2rem; margin: 0 0 8px; }
.aq-row { background: var(--surface); border: 1px solid var(--border); border-radius: var(--border-radius);
          padding: 12px 14px; margin: 0 0 8px; }
.aq-row-hidden { opacity: 0.65; }
.aq-text { display: flex; flex-direction: column; gap: 4px; margin: 0 0 8px; }
.aq-label { font-weight: 600; overflow-wrap: anywhere; }
.aq-help { color: var(--muted); font-size: 0.9rem; }
.aq-tags { display: flex; flex-wrap: wrap; gap: 6px; }
.aq-tag { font-size: 0.8rem; padding: 2px 8px; border-radius: 999px; background: var(--secondary-light);
          color: var(--on-tint-green); }
.aq-tag-off { background: var(--border); color: var(--text); }
.aq-actions { display: flex; flex-wrap: wrap; gap: 8px; margin: 0; }
.aq-btn { width: auto; min-height: 48px; padding: 8px 16px; margin: 0; }
.aq-move { min-width: 56px; }
.aq-edit { margin: 12px 0 0; display: flex; flex-direction: column; gap: 8px; }
.aq-edit .aq-btn { align-self: flex-start; }
.aq-check { display: flex; align-items: center; gap: 8px; min-height: 48px; font-weight: 600; }
.aq-add { display: inline-flex; align-items: center; }
/* APPS3: the thank-you page's success message and received meal form. */
.apf-flash-ok { background: var(--secondary-light); color: var(--on-tint-green); border-left: 5px solid var(--on-tint-green);
                border-radius: var(--border-radius); padding: 10px 14px; margin-bottom: 12px; font-weight: 600; }
.apf-flash-ok p { margin: 4px 0; }
.apf-food-received { background: var(--secondary-light); border-radius: var(--border-radius); padding: 14px;
                     margin: 12px 0 0; display: flex; flex-direction: column; align-items: center; gap: 10px; }
.aq-box { background: var(--surface); border: 1px solid var(--border); border-radius: var(--border-radius);
          padding: 14px; margin: 0 0 18px; }
.apf-card .apf-note { white-space: pre-line; }
/* Application fixes: print button, the "Changes saved" toast, the
   Settings letterhead preview. */
.app-print { width: 100%; min-height: 56px; font-size: 1.1rem; justify-content: center; }
.flash-message.flash-success {
    background-color: var(--success-light, #e6f4ea); color: var(--success-strong); border-left-color: var(--success);
}
.letterhead-preview { width: 100%; }
.letterhead-image { max-width: 100%; max-height: 120px; object-fit: contain; }

/* Fill CAPS 1.4.1: big Done line; the per-day summary behind "Details". */
.caps-fill-panel h2.caps-fill-done { font-size: 2rem; }
.caps-fill-details { margin: 8px 0 16px; }
.caps-fill-details > summary { cursor: pointer; color: var(--primary-strong); font-weight: 600;
    min-height: 44px; display: inline-flex; align-items: center; }
.caps-fill-details[open] > summary { margin-bottom: 8px; }

/* Application review: "Save changes" is a normal-size button (8b). */
.page-actions .app-save-btn { width: auto; min-width: 160px; flex: 0 0 auto; align-self: flex-start; }

/* Application Tuition step: live "Total contract $"; a daycare preset reads as fixed text. */
.apf-total-field { display: flex; flex-direction: column; }
.apf-total-label { font-weight: 600; margin-bottom: 4px; }
.apf-total { display: flex; align-items: center; min-height: 48px; padding: 0 12px; box-sizing: border-box;
    font-size: 1.15rem; font-weight: 700; color: var(--text); background: var(--surface-alt, var(--surface));
    border: 1px solid var(--border); border-radius: 8px; }
.apf-field input[readonly] { background: var(--surface-alt, var(--surface)); color: var(--text);
    border-style: dashed; cursor: default; }
/* Android app (templates/portal/caps_fill_android.html) and the Fill CAPS
   panels that point to it (caps_fill_working.html "app" / "nohelper"). */
.caps-apk-download { min-width: 220px; justify-content: center; }
.caps-apk-version { color: var(--muted); margin: 8px 0 0; }
.caps-fill-choices { display: flex; flex-wrap: wrap; gap: 12px; margin: 8px 0; }
.caps-fill-choices .caps-fill-big { flex: 1 1 220px; justify-content: center; }

/* --- Item 15: Terms of Service + Privacy Policy (app/legal.py) ----------- */
.legal-agree { display: flex; align-items: flex-start; gap: 12px; margin: 16px 0;
    font-size: 1rem; line-height: 1.45; color: var(--text); cursor: pointer; }
.legal-agree input[type="checkbox"] { flex: 0 0 auto; width: 28px; height: 28px;
    margin: 0; accent-color: var(--primary); cursor: pointer; }
.legal-agree a { color: var(--primary-dark); font-weight: 600; }
.legal-agree-error { outline: 2px solid var(--danger); outline-offset: 6px; border-radius: 6px; }
.legal-accept-links { display: flex; flex-wrap: wrap; gap: 12px; margin: 16px 0 20px; }
.legal-accept-links a { flex: 1 1 160px; display: flex; align-items: center; justify-content: center;
    min-height: 52px; padding: 0 16px; border: 1px solid var(--border); border-radius: 10px;
    background: var(--surface); color: var(--primary-dark); font-weight: 600; text-decoration: none; }
.legal-accept-actions { display: flex; flex-direction: column; gap: 12px; }
.legal-accept-actions .btn-primary { min-height: 56px; font-size: 1.1rem; width: 100%; }
.portal-footer { display: flex; justify-content: center; gap: 18px; padding: 20px 16px 28px;
    font-size: .9rem; color: var(--muted); }
.portal-footer a { color: var(--muted); }

/* APPS5: tuition terms -- Settings -> Applications (aq-term*) and the
   parent's Tuition step (apf-term*). */
.aq-terms { display: flex; flex-direction: column; gap: 12px; }
.aq-term { border: 1px solid var(--border); border-radius: var(--border-radius); padding: 12px; margin: 0; }
.aq-term-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); gap: 0 12px; }
.aq-term-grid .form-group { margin-bottom: 8px; }
.aq-term-name { grid-column: 1 / -1; }
.aq-term-add select { width: auto; min-height: 48px; margin: 0; }
.apf-terms { border: 0; padding: 0; margin: 0; display: flex; flex-direction: column; gap: 10px; }
.apf-term { background: var(--surface); border: 1px solid var(--border); border-radius: var(--border-radius); padding: 12px; }
.apf-term-pick { align-items: center; min-height: 48px; }
.apf-term-name { font-weight: 600; }
.apf-term-dates { color: var(--muted); font-size: 0.9rem; }
.apf-term-line { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 14px; margin-top: 6px; }
.apf-term-cell { display: inline-flex; align-items: center; gap: 6px; margin: 0; font-weight: 500; }
.apf-term-cell input { width: 6.5rem; margin: 0; }
.apf-term-cell select { width: auto; margin: 0; }
.apf-term-unit, .apf-term-fixed { font-weight: 600; }
.apf-term-sub { margin-left: auto; font-weight: 700; }
/* ===========================================================================
   Item 17c/17d: ONE navigation pattern. The phone Menu and the Settings list
   are the same kind of row -- icon, label, chevron. Settings follows the
   phone-Settings look: rows in white rounded groups on a light grey page,
   a small coloured round icon per row, thin dividers, a floating search box.
   =========================================================================== */
:root {
    --set-page-bg: #F1EFEB;     /* light grey behind the groups */
    --ico-blue: #3B6FB6;
    --ico-green: #3D8B5E;
    --ico-orange: #C9702E;
    --ico-red: #C0503A;
    --ico-purple: #7457A8;
    --ico-teal: #2F8F83;
    --ico-pink: #B5527F;
    --ico-grey: #6F6B64;
}

/* --- the portal Menu: icon + label + chevron per row ---------------------- */
.nav-row-icon { display: none; }
.portal-nav .nav-row-chevron { display: none; }
@media (max-width: 1100px) {
    .portal-nav.has-toggle .portal-nav-link { gap: 14px; }
    .portal-nav.has-toggle .nav-row-icon {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 24px;
        color: var(--primary-strong);
    }
    .portal-nav.has-toggle .nav-row-label { flex: 1 1 auto; }
    .portal-nav.has-toggle .nav-row-chevron {
        display: inline-block;
        color: var(--muted);
        font-size: .85rem;
    }
}

/* --- the Settings list ------------------------------------------------------ */
.set-page { max-width: 720px; }
.set-search {
    position: sticky;
    top: 8px;
    z-index: 5;
    display: flex;
    align-items: center;
    gap: 10px;
    margin: 4px 0 14px;
    padding: 0 16px;
    min-height: 48px;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: var(--surface);
    box-shadow: 0 2px 8px rgba(43, 42, 40, .08);
    color: var(--muted);
}
.set-search input {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 44px;
    border: 0;
    background: transparent;
    font: inherit;
    color: var(--text);
}
.set-search input:focus { outline: none; }
.set-search:focus-within { border-color: var(--primary-strong); }
/* Round 3 (One UI): small white blocks of 1-4 one-line rows, a gap between
   blocks, thin dividers inside one; a profile card on top. */
.set-list {
    margin: 0 -8px;
    padding: 10px 8px 4px;
    border-radius: 18px;
    background: var(--set-page-bg);
}
.set-block {
    overflow: hidden;
    margin: 0 0 12px;
    border-radius: 18px;
    background: var(--surface);
}
.set-block[hidden] { display: none; }
.set-profile {
    display: flex;
    align-items: center;
    gap: 14px;
    margin: 0 0 12px;
    padding: 14px 16px;
    border-radius: 18px;
    background: var(--surface);
    color: var(--text);
    text-decoration: none;
}
.set-profile[hidden] { display: none; }
.set-profile:hover { background: var(--light); }
.set-profile:focus-visible { outline: 2px solid var(--primary-strong); outline-offset: -2px; }
.set-profile-avatar {
    flex: none;
    width: 56px;
    height: 56px;
    border-radius: 50%;
    object-fit: cover;
    background: var(--surface);
    border: 1px solid var(--border);
}
.set-profile-initial {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 0;
    background: var(--primary-strong);
    color: #fff;
    font-size: 1.5rem;
    font-weight: 700;
}
.set-profile-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.set-profile-name {
    font-weight: 700;
    font-size: 1.15rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.set-profile-sub { color: var(--muted); font-size: .9rem; }
.set-row {
    display: flex;
    align-items: center;
    gap: 14px;
    min-height: 52px;
    padding: 6px 16px;
    color: var(--text);
    text-decoration: none;
}
.set-row[hidden] { display: none; }
.set-row + .set-row { border-top: 1px solid var(--border); }
.set-block .set-row { box-sizing: border-box; }
.set-row:hover { background: var(--light); }
.set-row:focus-visible { outline: 2px solid var(--primary-strong); outline-offset: -2px; }
.set-row-icon {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    color: #fff;
    font-size: .85rem;
}
.set-ico-blue { background: var(--ico-blue); }
.set-ico-green { background: var(--ico-green); }
.set-ico-orange { background: var(--ico-orange); }
.set-ico-red { background: var(--ico-red); }
.set-ico-purple { background: var(--ico-purple); }
.set-ico-teal { background: var(--ico-teal); }
.set-ico-pink { background: var(--ico-pink); }
.set-ico-grey { background: var(--ico-grey); }
.set-row-title {
    flex: 1 1 auto;
    min-width: 0;
    font-weight: 500;
    font-size: 1.02rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
/* The grouped rows inside an opened Settings page (settings_group.html) keep
   their heading-less group, grey line and chevron. */
.set-group { margin: 0 0 18px; }
.set-group[hidden] { display: none; }
.set-group-rows {
    overflow: hidden;
    border-radius: 16px;
    background: var(--surface);
}
.set-row-text { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; }
.set-row-desc {
    color: var(--muted);
    font-size: .88rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.set-row-chevron { flex: none; color: var(--muted); font-size: .85rem; }
/* Phone: the page is the grey; blocks fill the width with small margins and
   the search sits at the top of the list. */
@media (max-width: 640px) {
    /* the home list, or a page that is itself a list -- not the split
       view's list pane, which a phone does not show */
    body:has(.set-page .set-list), body:has(.settings-page .set-list) { background: var(--set-page-bg); }
    .container.set-page { padding-left: 10px; padding-right: 10px; }
    .set-list { margin: 0 -10px; padding: 8px 10px calc(16px + env(safe-area-inset-bottom, 0px)); border-radius: 0; }
    /* Settings cleanup (Oct 2026): the search sits at the TOP of the list
       (sticky while scrolling), no longer a floating pill over the last
       rows. */
    .set-search {
        position: sticky;
        top: 8px;
        margin: 4px 0 12px;
        z-index: 20;
    }
}
.set-empty { margin: 0 14px 12px; color: var(--muted); }
.set-empty[hidden] { display: none; }
/* Settings cleanup (Oct 2026): the folded "Advanced" block -- its summary
   looks like a row; the rows open under it -- and the small Help / Terms /
   Privacy links at the foot of the list. */
.set-advanced { margin: 0 0 12px; }
.set-advanced[hidden] { display: none; }
.set-advanced-summary {
    display: flex;
    align-items: center;
    gap: 14px;
    min-height: 52px;
    padding: 6px 16px;
    border-radius: 18px;
    background: var(--surface);
    cursor: pointer;
    list-style: none;
}
.set-advanced-summary::-webkit-details-marker { display: none; }
.set-advanced-summary::after {
    content: "\25B8";
    color: var(--muted);
    margin-left: auto;
}
.set-advanced[open] > .set-advanced-summary::after { content: "\25BE"; }
.set-advanced[open] > .set-advanced-summary { border-radius: 18px 18px 0 0; border-bottom: 1px solid var(--border); }
.set-advanced[open] > .set-block { border-radius: 0 0 18px 18px; margin-bottom: 0; }
.set-advanced-summary:focus-visible { outline: 2px solid var(--primary-strong); outline-offset: -2px; }
.set-foot-links { margin: 4px 16px 16px; color: var(--muted); font-size: .88rem; }
.set-foot-links a { color: var(--muted); }
.dash-notice { margin: 0 0 16px; }
.dash-notice a { display: inline-flex; align-items: center; gap: 6px; font-weight: 600; }

/* --- Split-view Settings (wide screens) -------------------------------------
   768px and up: the Settings list on the left (its own scroll, sticky under
   the top bar, the open row marked), the open page on the right. A phone
   never shows the list pane: list -> tap -> full page, as before. */
:root {
    --set-split-nav-w: 340px;
    --set-split-gap: 24px;
}
.set-split-nav { display: none; }
/* the letterhead preview box is width 100% plus padding: keep it inside its
   card (it showed past the card's edge in the narrower right pane) */
.letterhead-preview { box-sizing: border-box; }
@media (min-width: 768px) {
    .set-split {
        display: grid;
        grid-template-columns: var(--set-split-nav-w) minmax(0, 1fr);
        gap: var(--set-split-gap);
        align-items: start;
        max-width: 1240px;
        margin: 0 auto;
        padding: 16px 16px 0;
    }
    .set-split-nav {
        display: block;
        position: sticky;
        top: 12px;
        max-height: calc(100vh - 24px);
        overflow-y: auto;
        overscroll-behavior: contain;
        padding: 0 10px;
        border-radius: 18px;
        background: var(--set-page-bg);
    }
    .set-split-nav .set-list { margin: 0; padding: 0 0 10px; border-radius: 0; }
    /* the search sits at the top of the pane (a phone keeps the floating
       pill); its shadow covers the rows scrolling up behind it */
    .set-split-nav .set-search {
        top: 10px;
        margin: 10px 0 12px;
        box-shadow: 0 -10px 0 10px var(--set-page-bg);
    }
    .set-split-nav .set-row[aria-current="page"],
    .set-split-nav .set-profile[aria-current="page"] {
        background: var(--primary-light);
        box-shadow: inset 4px 0 0 var(--primary-strong);
    }
    .set-split-nav .set-row[aria-current="page"] .set-row-title,
    .set-split-nav .set-profile[aria-current="page"] .set-profile-name { color: var(--primary-stronger); font-weight: 700; }
    .set-split > .settings-page { max-width: none; margin: 0; padding: 0 0 20px; min-width: 0; }
}
@media (min-width: 768px) and (max-width: 1100px) {
    :root { --set-split-nav-w: 320px; --set-split-gap: 18px; }
}

/* 2026-10-20: the desktop top bar has 12 items (Open kiosk ... Sign out).
   Above 1100px (where the Menu button takes over below) it scrolled sideways
   and clipped "Sign out". Tighter spacing and a slightly smaller font make it
   fit at 1280; if it still does not fit, the links wrap to a second line --
   never clipped, never scrolled. (Selectors outrank _nav.html's local styles.) */
@media (min-width: 1101px) {
    .portal-nav .portal-nav-inner {
        flex-wrap: wrap;
        overflow-x: visible;
        row-gap: 0;
        column-gap: 2px;
    }
    .portal-nav .portal-nav-brand { margin-right: 8px; }
    .portal-nav .portal-nav-menu {
        flex: 1 1 auto;
        flex-wrap: wrap;
        min-width: 0;
        gap: 0 2px;
    }
    .portal-nav .portal-nav-link {
        padding: 0 9px;
        font-size: .94rem;
    }
}

/* Settings cleanup: English / Espanol at the foot of Settings. */
.set-lang { margin: 12px 0 24px; display: flex; justify-content: center; }

/* Missing-child alert (Oct 21 2026, static/js/missing-alert.js) */
.mca-overlay { position: fixed; inset: 0; z-index: 10000; background: rgba(16, 24, 40, .55); display: flex; align-items: flex-start; justify-content: center; padding: 16px; overflow-y: auto; }
.mca-card { background: #fff; border-radius: 18px; width: 100%; max-width: 560px; padding: 18px; box-shadow: 0 20px 50px rgba(0,0,0,.3); border-top: 6px solid #d92d20; margin-top: 4vh; }
.mca-head { display: flex; align-items: center; gap: 10px; }
.mca-head h2 { margin: 0; font-size: 1.3rem; color: #101828; }
.mca-bell { font-size: 1.8rem; animation: mca-shake 1s ease-in-out infinite; }
@keyframes mca-shake { 0%, 100% { transform: rotate(0); } 20% { transform: rotate(-18deg); } 40% { transform: rotate(16deg); } 60% { transform: rotate(-10deg); } 80% { transform: rotate(6deg); } }
@media (prefers-reduced-motion: reduce) { .mca-bell { animation: none; } }
.mca-sub { color: #475467; margin: 6px 0 10px; }
.mca-list { list-style: none; margin: 0; padding: 0; }
.mca-row { border: 1px solid #eaecf0; border-radius: 12px; padding: 12px; margin-bottom: 10px; }
.mca-name { font-weight: 700; font-size: 1.1rem; color: #101828; }
.mca-parent { color: #475467; margin: 2px 0 8px; }
.mca-actions, .mca-foot { display: flex; flex-wrap: wrap; gap: 8px; }
.mca-btn { min-height: 44px; padding: 0 14px; border-radius: 10px; border: 1px solid #d0d5dd; background: #fff; color: #101828; font-weight: 600; font-size: 1rem; display: inline-flex; align-items: center; justify-content: center; text-decoration: none; cursor: pointer; width: auto; }
.mca-call { background: #067647; border-color: #067647; color: #fff; flex: 1 1 100%; }
.mca-foot { margin-top: 6px; justify-content: flex-end; }
.mca-dismiss { background: #101828; border-color: #101828; color: #fff; }
.mca-ghost { background: transparent; }


/* Board round (Oct 22 2026, board item 8): on a 1280-wide tablet the one big
   SIGN IN / SIGN OUT button was squeezed by Absent / Times beside it and
   wrapped to "SIGN / IN"; on a 390px phone the same row would not wrap and
   pushed the page to ~462px wide. The button never wraps its words and keeps
   a real minimum; the small buttons go on the line above it when there is
   no room (wrap-reverse keeps SIGN IN on the card's bottom line). */
.children-grid > .child-card .child-actions { flex-wrap: wrap-reverse; min-width: 0; }
.child-card .child-card-button {
    white-space: nowrap;
    flex: 1 0 9.5em;
    min-width: 9.5em;
}
.children-grid > .child-card .child-actions > :not(.child-card-button) { flex: 0 1 auto; min-width: 0; }
@media (max-width: 480px) {
    .children-grid { grid-template-columns: minmax(0, 1fr); }
    .children-grid > .child-card { max-width: 100%; }
    .child-card .child-card-button { flex-basis: 100%; min-width: 0; }
}

/* Board round: shared bits for the new screens. */
.alert-warning {
    background-color: #FFF4E5;
    color: var(--warning-text, #7A4B00);
    border: 1px solid #F5C77E;
}
.sheet-save-why { margin: 0 auto 0 0; align-self: center; font-size: 0.95rem; color: var(--warning-text, #7A4B00); }
.pin-reset-card .form-group { margin-bottom: 14px; }
.pin-reset-card input[type="password"] { width: 100%; font-size: 1.2rem; }
.inline-check { display: inline-flex; align-items: center; gap: 6px; margin: 0 10px; }
/* Oct 2026 (full Spanish): the compact language switch (templates/_lang_switch.html). */
.lang-mini { display: inline-flex; gap: 2px; padding: 2px; border: 1px solid var(--border, #d9d9d9);
    border-radius: 999px; background: var(--surface, #fff); flex: 0 0 auto; white-space: nowrap; }
.lang-mini-choice { border: 0; background: transparent; color: var(--text-muted, #555); font: inherit;
    font-size: .85rem; line-height: 1; padding: .45rem .7rem; border-radius: 999px; cursor: pointer; min-height: 32px; }
.lang-mini-choice[aria-pressed="true"] { background: var(--primary, #2F8F83); color: #fff; font-weight: 600; }
.lang-mini-choice:focus-visible { outline: 3px solid var(--primary, #2F8F83); outline-offset: 2px; }
.lang-mini.lang-corner { position: absolute; top: 10px; right: 12px; z-index: 20; }
.lang-mini.lang-corner-static { display: flex; width: max-content; margin: 0 0 12px auto; }
.lang-mini.lang-nav { margin-left: 8px; }
.lang-mini.lang-footer { margin-left: auto; }
.lang-mini.lang-mk { margin-left: 4px; }
.lang-mini[hidden] { display: none; }
[dir="rtl"] .lang-mini.lang-corner { right: auto; left: 12px; }
@media (max-width: 480px) {
    .lang-mini-choice { padding: .4rem .55rem; font-size: .8rem; }
    .lang-mini.lang-corner { top: 6px; right: 6px; }
}
/* Oct 22 2026 (Hershey's filming): on a phone or tablet the corner language
   switch sat on top of the green "saved" message. When a page has the corner
   switch and a message is showing, the message starts below the switch. */
@media (max-width: 1180px) {
    body:has(.lang-mini.lang-corner) .flash-region:not(:empty) { margin-top: 52px; }
}
/* Longer Spanish words must wrap, never push a phone page sideways. */
html[lang="es"] .btn, html[lang="es"] .btn-primary, html[lang="es"] .btn-secondary,
html[lang="es"] button, html[lang="es"] .flash-message { overflow-wrap: break-word; }


/* ===========================================================================
   29-item round (Hershey Oct 22 2026): ONE three-line Menu at every width.
   Below 1101px the rules above already fold the links behind "Menu"; here
   the same Menu is used on a wide screen too, as a panel under the button,
   instead of the crowded row of links. phone-layout.js does the behaviour.
   =========================================================================== */
@media (min-width: 1101px) {
    .portal-nav.has-toggle .portal-nav-inner {
        position: relative;
        flex-wrap: nowrap;
        overflow: visible;
        min-height: 56px;
        padding: 0 16px;
    }
    .portal-nav.has-toggle .portal-nav-toggle {
        display: inline-flex;
        align-items: center;
        gap: 10px;
        margin-left: auto;
        min-height: 44px;
        min-width: 44px;
        padding: 0 14px;
        border: 1px solid var(--border);
        border-radius: var(--border-radius);
        background: var(--surface);
        color: var(--text);
        font: inherit;
        font-weight: 600;
        cursor: pointer;
    }
    .portal-nav.has-toggle .portal-nav-toggle[aria-expanded="true"] {
        background: var(--primary-light);
        border-color: var(--primary-strong);
        color: var(--primary-stronger);
    }
    .portal-nav.has-toggle .portal-nav-toggle .nav-badge { margin-left: 0; }
    .portal-nav.has-toggle:not(.is-open) .portal-nav-menu { display: none; }
    .portal-nav.has-toggle .portal-nav-menu {
        position: absolute;
        top: 100%;
        right: 16px;
        z-index: 1000;
        width: 340px;
        max-height: calc(100vh - 72px);
        overflow-y: auto;
        flex: none;
        flex-direction: column;
        flex-wrap: nowrap;
        align-items: stretch;
        gap: 0;
        padding: 6px 0 10px;
        background: var(--surface);
        border: 1px solid var(--border);
        border-radius: 12px;
        box-shadow: 0 12px 32px rgba(16, 24, 40, .18);
    }
    .portal-nav.has-toggle .portal-nav-link {
        gap: 14px;
        min-height: 46px;
        padding: 0 16px;
        border-bottom: 0;
        border-left: 3px solid transparent;
        color: var(--text);
        font-size: 1rem;
    }
    .portal-nav.has-toggle .portal-nav-link.is-current {
        border-left-color: var(--primary-strong);
        background: var(--primary-light);
        color: var(--primary-stronger);
    }
    .portal-nav.has-toggle .portal-nav-end {
        margin: 6px 0 0;
        border-top: 1px solid var(--border);
    }
    .portal-nav.has-toggle .nav-row-icon {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 24px;
        color: var(--primary-strong);
    }
    .portal-nav.has-toggle .nav-row-label { flex: 1 1 auto; }
    .portal-nav.has-toggle .nav-row-chevron {
        display: inline-block;
        color: var(--muted);
        font-size: .85rem;
    }
}
/* The Home button beside the Menu (every width). */
.portal-nav-home {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    padding: 0 12px;
    margin-left: 8px;
    border: 1px solid var(--border);
    border-radius: var(--border-radius);
    color: var(--text);
    text-decoration: none;
    font-weight: 600;
    white-space: nowrap;
}
.portal-nav-home:hover { background: var(--primary-light); }
.portal-nav.has-toggle .portal-nav-toggle { margin-left: auto; }
.portal-nav-lang-row .lang-mini { margin-left: auto; }
@media (max-width: 640px) {
    .portal-nav-home .portal-nav-home-label { display: none; }
}
/* Kiosk screens: the Home button (templates/_kiosk_home.html). */
.kiosk-home-btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    min-height: 48px;
    padding: 0 16px;
    margin: 0 0 8px;
    border: 2px solid var(--primary-strong);
    border-radius: var(--border-radius);
    background: var(--surface);
    color: var(--primary-strong);
    font-weight: 700;
    text-decoration: none;
}
.kiosk-home-btn:hover { background: var(--primary-light); }
@media print { .kiosk-home-btn, .portal-nav-home { display: none !important; } }

.kiosk-home-row { padding-top: 8px; padding-bottom: 0; }
.kiosk-home-row[hidden] { display: none; }

/* 29-item round: PIN boxes that are not password fields (no autofill). */
.pin-mask { -webkit-text-security: disc; text-security: disc; font-family: inherit; letter-spacing: .2em; }

/* 29-item round: the Documents tab's Save bar. */
.docs-save-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; }
.docs-save-note { color: var(--muted); }
.portal-nav-lang-row a.nav-row-label { color: inherit; text-decoration: none; }
.portal-nav-lang-row a.nav-row-label:hover { text-decoration: underline; }

/* 29-item round: the menu page's Repeat and Print rows. */
.food-inline-form { display: flex; flex-wrap: wrap; gap: 8px 10px; align-items: center; }
.food-inline-form select, .food-inline-form input[type=date] { width: auto; min-width: 9rem; }
.food-print-dates { display: inline-flex; flex-wrap: wrap; gap: 8px; align-items: center; }
.food-print-dates[hidden] { display: none; }
.food-inline-form .btn-primary, .food-inline-form .btn-secondary { width: auto; flex: 0 0 auto; }

/* 29-item round: the two "start with an application" choices on Add a child. */
.add-child-options h2 { font-size: 1.1rem; margin: 0 0 10px; }
.add-child-option-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 14px; }
.add-child-option { border: 1px solid #e3ded5; border-radius: 10px; padding: 14px; display: flex; flex-direction: column; gap: 8px; }
.add-child-option h3 { font-size: 1rem; margin: 0; }
.add-child-option .btn-primary, .add-child-option .btn-secondary { align-self: flex-start; width: auto; }
.add-child-or { margin: 10px 0 0; }


/* --- Menu drawer (real-user round, Hershey Oct 23 2026) --------------------
   The 3-bar button at the left of the bar opens a side drawer, Gmail-style:
   it slides in from the left over a dimmed page; one column of icon + label
   rows in groups; the current page is a rounded pill. Same at every width.
   templates/portal/_nav.html draws it, static/js/phone-layout.js opens and
   closes it. Without JavaScript (.has-toggle not set) the rows just show. */
.nav-drawer-head,
.nav-drawer-scrim,
.nav-drawer-divider { display: none; }
.portal-nav:not(.has-toggle) .nav-drawer {
    display: flex;
    flex-wrap: wrap;
    max-width: 1200px;
    margin: 0 auto;
    padding: 0 16px;
}
.portal-nav:not(.has-toggle) .nav-drawer-group { display: flex; flex-wrap: wrap; }
.portal-nav.has-toggle #navMenuButton {
    order: -1;
    margin-left: -6px;
    margin-right: 6px;
    padding: 0 12px;
    min-width: 48px;
    min-height: 48px;
    gap: 8px;
    border: 0;
    border-radius: 999px;
    background: transparent;
}
.portal-nav.has-toggle #navMenuButton:hover,
.portal-nav.has-toggle #navMenuButton[aria-expanded="true"] {
    background: var(--primary-light);
    color: var(--text);
}
#navMenuButton .portal-nav-bars,
#navMenuButton .portal-nav-bars::before,
#navMenuButton .portal-nav-bars::after { width: 20px; }
.portal-nav.has-toggle .portal-nav-home { margin-left: auto; }
.portal-nav.has-toggle .nav-drawer-scrim {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 1000;
    background: rgba(15, 23, 42, .45);
    opacity: 0;
    pointer-events: none;
    transition: opacity .25s ease;
}
.portal-nav.has-toggle.is-open .nav-drawer-scrim {
    opacity: 1;
    pointer-events: auto;
}
.portal-nav.has-toggle .nav-drawer {
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 1001;
    display: flex;
    flex-direction: column;
    width: min(320px, 86vw);
    padding: 4px 0 24px;
    overflow-y: auto;
    overscroll-behavior: contain;
    background: var(--surface);
    border-radius: 0 18px 18px 0;
    box-shadow: 0 8px 32px rgba(15, 23, 42, .28);
    transform: translateX(-105%);
    visibility: hidden;
    transition: transform .25s ease, visibility 0s linear .25s;
}
.portal-nav.has-toggle.is-open .nav-drawer {
    transform: none;
    visibility: visible;
    transition: transform .25s ease;
}
.portal-nav.has-toggle .nav-drawer-head {
    display: flex;
    align-items: center;
    gap: 12px;
    min-height: 64px;
    padding: 8px 8px 8px 24px;
    color: var(--text);
    font-size: 1.15rem;
    font-weight: 700;
}
.nav-drawer-logo {
    width: 36px;
    height: 36px;
    border-radius: 8px;
    object-fit: cover;
}
.nav-drawer-name {
    flex: 1 1 auto;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}
.nav-drawer-close {
    min-width: 48px;
    min-height: 48px;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--muted);
    font-size: 1.75rem;
    line-height: 1;
    cursor: pointer;
}
.nav-drawer-close:hover { background: var(--primary-light); color: var(--text); }
.nav-drawer-close:focus-visible { outline: 2px solid var(--primary-strong); outline-offset: 2px; }
.portal-nav.has-toggle .nav-drawer-group {
    display: flex;
    flex-direction: column;
    padding: 4px 12px;
}
.portal-nav.has-toggle .nav-drawer-divider {
    display: block;
    margin: 6px 24px;
    border: 0;
    border-top: 1px solid var(--border);
}
.nav-drawer-form { margin: 0; }
.portal-nav.has-toggle .nav-drawer .portal-nav-link {
    display: flex;
    align-items: center;
    gap: 18px;
    width: 100%;
    min-height: 52px;
    margin: 1px 0;
    padding: 0 18px;
    box-sizing: border-box;
    border: 0;
    border-radius: 999px;
    background: transparent;
    color: var(--text);
    font: inherit;
    font-weight: 500;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}
.portal-nav.has-toggle .nav-drawer .portal-nav-link:hover { background: rgba(15, 23, 42, .06); }
.portal-nav.has-toggle .nav-drawer .portal-nav-link:focus-visible {
    outline: 2px solid var(--primary-strong);
    outline-offset: -2px;
}
.portal-nav.has-toggle .nav-drawer .portal-nav-link.is-current {
    background: var(--primary-light);
    color: var(--primary-stronger);
    font-weight: 700;
}
.portal-nav.has-toggle .nav-drawer .nav-row-icon {
    display: inline-flex;
    justify-content: center;
    width: 24px;
    color: inherit;
    font-size: 1.1rem;
}
.portal-nav.has-toggle .nav-drawer .nav-row-label { flex: 1 1 auto; }
.portal-nav.has-toggle .nav-drawer .nav-row-chevron { display: none; }
.portal-nav.has-toggle .nav-drawer .nav-badge { margin-left: auto; }
html.nav-drawer-open,
html.nav-drawer-open body { overflow: hidden; }
@media (prefers-reduced-motion: reduce) {
    .portal-nav.has-toggle .nav-drawer,
    .portal-nav.has-toggle .nav-drawer-scrim { transition: none; }
}
@media print { .nav-drawer, .nav-drawer-scrim { display: none !important; } }

/* Real-user round (#19): the day sheet's "here now" count, today only. */
.day-chip.is-here { font-weight: 700; }

/* Menu drawer: on a phone the bar keeps one line (Menu, name, Home); the
   language choice is in the drawer. */
@media (max-width: 640px) {
    .portal-nav.has-toggle .portal-nav-inner > .lang-nav { display: none; }
}
/* Staff sign-in / sign-out reminders (Oct 23 2026, static/js/staff-reminders.js). */
.srm-card { border-top-color: #b54708; max-width: 620px; }
.srm-row { padding: 16px; }
.srm-row .mca-head h2 { font-size: 1.25rem; }
.srm-name { font-size: 1.6rem; margin: 6px 0 2px; }
.srm-count { font-weight: 700; color: #b42318; font-size: 1.1rem; margin: 4px 0 10px; }
.srm-actions .srm-btn { min-height: 56px; font-size: 1.1rem; flex: 1 1 200px; }
.srm-actions .mca-call { flex: 1 1 100%; }
.srm-later { background: #fff7e6; border-color: #f79009; color: #7a2e0e; }
.srm-pin { display: flex; gap: 8px; margin-top: 10px; }
.srm-pin-input { flex: 1; min-height: 52px; font-size: 1.4rem; letter-spacing: .3em; text-align: center; border: 1px solid #d0d5dd; border-radius: 10px; }
.srm-pin .srm-ok { flex: 0 0 auto; min-width: 96px; }
.srm-msg { color: #b42318; margin: 6px 0 0; min-height: 1em; }
.srm-done { background: #ecfdf3; border-color: #abefc6; }
.srm-result { color: #067647; font-weight: 700; font-size: 1.1rem; margin-top: 4px; }

/* Date of birth under the child's name on the roster (Hershey Oct 24 2026). */
.child-info .child-dob { display: block; font-size: .78rem; line-height: 1.2; color: var(--muted); font-variant-numeric: tabular-nums; }

/* Hershey's audit Oct 26 2026 item 03: the recording status, in plain words. */
.tap-queue-badge[data-state="saving"] { border-color: var(--border); color: var(--muted); }
.tap-queue-badge.is-saved { border-color: var(--success, #2e7d4f); color: var(--on-tint-green, #1f6b41); }

/* Oct 29 2026: while the icon font is still on its way (html.ck-icons-wait,
   set and cleared by the small script at the top of base.html) icons are
   blank space, never the empty squares a browser draws in their place. */
.ck-icons-wait .fa::before,
.ck-icons-wait .fas::before,
.ck-icons-wait .fa-solid::before { visibility: hidden; }

/* Nov 1 2026: the AI assistant's floating button (templates/base.html). */
.ai-fab { position: fixed; right: 16px; bottom: 16px; z-index: 900; display: inline-flex; align-items: center; gap: 8px;
  min-height: 52px; padding: 0 18px; border-radius: 999px; background: var(--primary-strong); color: var(--light);
  text-decoration: none; font-weight: 600; box-shadow: var(--box-shadow); }
.ai-fab:hover, .ai-fab:focus-visible { background: var(--primary-stronger); color: var(--light); }
.ai-fab:focus-visible { outline: 3px solid var(--primary-light); outline-offset: 2px; }
@media (max-width: 600px) { .ai-fab { right: 12px; bottom: 12px; padding: 0 16px; } .ai-fab-label { display: none; } }
@media print { .ai-fab { display: none; } }
/* Nov 5 2026 sale-ready pass: the screen-timeout hint sat on top of the AI
   assistant button. While the hint shows, lift the button above it. */
body:has(.wake-hint:not([hidden])) .ai-fab { bottom: 96px; }
@media (max-width: 600px) { body:has(.wake-hint:not([hidden])) .ai-fab { bottom: 120px; } }


/* Nov 1 2026: AI in the parent app (static/js/ai-parent.js). */
.ai-sum { margin-top: 12px; padding: 12px 14px; }
.ai-sum-text { margin: 6px 0 4px; line-height: 1.5; }
.ai-sum-note { display: block; color: var(--muted); }
.ai-sum .ai-typing { color: var(--muted); font-style: italic; }

/* Google Play app (app/play_app.py, static/js/play-app.js): inside the Android
   app the site is sign-in only. The server already leaves these out; this is
   the safety net for any link it missed. */
html.ck-play a[href^="/pricing"], html.ck-play a[href*="childcarekiosk.com/pricing"],
html.ck-play a[href^="/signup"]:not([href^="/signup/pending"]), html.ck-play a[href*="childcarekiosk.com/signup"],
html.ck-play a[href^="/portal/billing"], html.ck-play a[href*="childcarekiosk.com/portal/billing"],
html.ck-play form[action^="/portal/billing"],
html.ck-play a[href^="/faq"], html.ck-play a[href^="/how-to"], html.ck-play a[href^="/getting-started"],
html.ck-play a[href*="checkout.stripe.com"], html.ck-play a[href*="billing.stripe.com"], html.ck-play a[href*="buy.stripe.com"],
html.ck-play [data-play-hide] { display: none !important; }

/* Nov 5 2026: the phone scroll wrappers must not clip a printed meal sheet */
@media print {
    .food-table-wrap, .meal-sheet-scroll { overflow: visible !important; max-width: none !important; }
}
