/* Shared page styling.
 *
 * Ported from the 2025 application's stylesheet so the rebuilt pages look
 * like the ones the ward already knows: same palette, same 8px radii, same
 * soft card shadow, same blue. Only the parts every page needs live here --
 * per-page rules belong beside their page.
 *
 * Presentation values an administrator can change (fonts, sizes, colours)
 * arrive as custom properties set by the page template, which validates them
 * before they reach CSS. The fallbacks below are what renders if a value is
 * missing or was rejected.
 */

:root {
    --spacing-xxs: 4px;
    --spacing-xs: 8px;
    --spacing-sm: 10px;
    --spacing-md: 15px;
    --spacing-lg: 20px;
    --spacing-xl: 24px;
    --spacing-xxl: 30px;
}

/* The spinner overlay is display:flex, which beats the user-agent rule for
 * [hidden]. Without !important the overlay would show the moment it is
 * styled, regardless of the attribute. */
[hidden] {
    display: none !important;
}

/* General Body and Container Styles */
body {
    font-family: var(--font-family, 'Arial', sans-serif);
    font-size: var(--font-size, 16px);
    color: var(--font-color, #333);
    margin: 0;
    padding: 0;
    background-color: #f4f7f6;
    line-height: 1.6;
    display: flex;
    justify-content: center;
    min-height: 100vh;
    transition: background-color 0.3s ease, color 0.3s ease;
}

.container {
    width: 100%;
    max-width: 960px;
    padding: var(--spacing-lg);
    box-sizing: border-box;
}

/* The whole width of the screen, when the reader asks for it.
 *
 * 960px is right for reading a column of forms on a laptop and absurd on a
 * 4K monitor, where the page sat in a quarter of the glass. Which of those a
 * screen is, is not something the markup can know -- so it is a tick box in
 * the display panel, per browser, beside the widths it interacts with.
 *
 * Here rather than in dashboard.css because the member page does not load
 * that file, and on <html> rather than <body> because theme.js sets it in the
 * head before first paint: a class added afterwards is a page that visibly
 * jumps from column to full width on every load, which is the same reason
 * the dark class is set where it is.
 */
html.is-wide .container {
    max-width: none;
}

/* Header Styles */
.app-header {
    background-color: #ffffff;
    padding: var(--spacing-lg);
    border-radius: 8px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
    margin-bottom: var(--spacing-lg);
    display: flex;
    flex-direction: column;
    gap: var(--spacing-md);
    align-items: flex-start;
    transition: background-color 0.3s ease, box-shadow 0.3s ease;
}

.app-header h1 {
    margin: 0;
    color: #2c3e50;
    font-size: 2em;
    transition: color 0.3s ease;
}

.small {
    font-size: 0.9em;
}

.muted {
    color: #7f8c8d;
    transition: color 0.3s ease;
}

.header-actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-sm);
    margin-top: var(--spacing-sm);
}

/* Card Styles */
.card {
    background-color: #ffffff;
    padding: var(--spacing-lg);
    /* Softer than the 8px everything else uses. A dashboard is a wall of
     * cards read from across a room, and at that distance the corner is most
     * of what separates one card from the next -- 8px reads as a rectangle
     * with the edge knocked off, 18px reads as a card. Deliberately not
     * applied to the control radius: an input with a corner this round stops
     * looking like something you can type in. */
    border-radius: 18px;
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
    margin-bottom: var(--spacing-lg);
    transition: background-color 0.3s ease, box-shadow 0.3s ease;
}

/* A resizable card clips its own corners, or the content squares them off
 * again at the bottom where the grip is. */
.card.section-resizable {
    overflow: auto;
}

.card h2 {
    color: #2c3e50;
    margin-top: 0;
    margin-bottom: var(--spacing-md);
    font-size: 1.5em;
    transition: color 0.3s ease;
}

/* Form and Input Styles */
.row {
    display: flex;
    gap: var(--spacing-sm);
    align-items: center;
}

.row.wrap {
    flex-wrap: wrap;
}

.grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
    gap: var(--spacing-md);
}

/* ---- form controls -------------------------------------------------------
 *
 * One set of rules for every input on every page. The settings page is forty
 * fields deep and gets used on a phone, so the things that matter are: a
 * consistent height so a row of controls reads as a row, enough padding that
 * a thumb lands where it means to, and a focus ring somebody can actually
 * see -- the old one was a 2px halo in the browser's default blue, which on
 * a page of blue buttons said nothing.
 *
 * The palette is tokens rather than literals so dark mode is a redefinition
 * rather than a second copy of every rule.
 */
:root {
    --control-radius: 10px;
    --control-border: #d4dae2;
    --control-border-strong: #b9c2cd;
    --control-bg: #ffffff;
    --control-color: #1f2933;
    --control-placeholder: #8a94a1;
    --control-accent: #2a78d6;
    --control-accent-soft: rgba(42, 120, 214, 0.16);
    --control-height: 2.65rem;
}

label {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xxs);
    font-size: 0.88em;
    font-weight: 600;
    letter-spacing: 0.01em;
    color: #4a5561;
    min-width: 0;
    transition: color 0.2s ease;
}

input[type="text"],
input[type="password"],
input[type="number"],
input[type="date"],
input[type="time"],
input[type="url"],
input[type="email"],
input[type="datetime-local"],
input[type="search"],
select,
textarea {
    /* min-height rather than height: a textarea grows, and a select on iOS
     * refuses a fixed height anyway. */
    min-height: var(--control-height);
    padding: 0.5rem 0.7rem;
    border: 1px solid var(--control-border);
    border-radius: var(--control-radius);
    font-size: 1rem;
    font-family: inherit;
    background-color: var(--control-bg);
    color: var(--control-color);
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.04);
    transition: border-color 0.15s ease, box-shadow 0.15s ease,
                background-color 0.15s ease;
}

textarea {
    line-height: 1.5;
    resize: vertical;
}

::placeholder {
    color: var(--control-placeholder);
    opacity: 1;
}

input:hover:not(:disabled),
select:hover:not(:disabled),
textarea:hover:not(:disabled) {
    border-color: var(--control-border-strong);
}

label > input,
label > select,
label > textarea {
    width: 100%;
    box-sizing: border-box;
}

/* One visible focus ring, in the app's own accent, on everything focusable.
 * :focus-visible so a mouse click does not leave a ring behind it. */
input:focus-visible,
select:focus-visible,
textarea:focus-visible,
button:focus-visible,
.button-link:focus-visible,
[role="button"]:focus-visible {
    outline: none;
    border-color: var(--control-accent);
    box-shadow: 0 0 0 3px var(--control-accent-soft);
}

/* Narrow controls for narrow values. A four-digit size box the width of the
 * column is what made these forms feel like a wall. */
input[type="number"],
input[type="time"],
input[type="date"] {
    max-width: 11rem;
}

/* A colour input is a swatch. The browser's default is a chunky bordered
 * button with the colour hiding inside it. */
input[type="color"] {
    -webkit-appearance: none;
    appearance: none;
    width: 100%;
    max-width: 5.5rem;
    height: var(--control-height);
    padding: 3px;
    border: 1px solid var(--control-border);
    border-radius: var(--control-radius);
    background-color: var(--control-bg);
    cursor: pointer;
}

input[type="color"]::-webkit-color-swatch-wrapper { padding: 0; }
input[type="color"]::-webkit-color-swatch {
    border: none;
    border-radius: calc(var(--control-radius) - 3px);
}
input[type="color"]::-moz-color-swatch {
    border: none;
    border-radius: calc(var(--control-radius) - 3px);
}

input[type="checkbox"],
input[type="radio"] {
    /* Big enough to hit, and in the app's accent rather than the browser's. */
    width: 1.15rem;
    height: 1.15rem;
    accent-color: var(--control-accent);
    cursor: pointer;
}

input[type="range"] {
    accent-color: var(--control-accent);
    height: 1.6rem;
}

input[type="file"] {
    font-size: 0.92rem;
    padding: 0.45rem 0;
}

input:disabled,
select:disabled,
textarea:disabled {
    background-color: #f2f4f7;
    color: #98a2b3;
    cursor: not-allowed;
}

button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--spacing-xs);
    min-height: var(--control-height);
    padding: 0.5rem 1.05rem;
    border: 1px solid transparent;
    border-radius: var(--control-radius);
    /* Colour comes from the role, in buttons.css. */
    font-size: 0.95rem;
    font-weight: 600;
    font-family: inherit;
    line-height: 1.2;
    cursor: pointer;
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.08);
    transition: background-color 0.15s ease, border-color 0.15s ease,
                box-shadow 0.15s ease, transform 0.08s ease;
}

button:hover:not(:disabled) {
    box-shadow: 0 2px 6px rgba(16, 24, 40, 0.14);
}

button:active:not(:disabled) {
    transform: translateY(1px);
    box-shadow: 0 1px 2px rgba(16, 24, 40, 0.1);
}

button:disabled,
button:disabled:hover {
    cursor: default;
    box-shadow: none;
    transform: none;
}

/* Secondary is an outline, not a second filled colour. Two solid buttons
 * side by side both look like the thing to press. */
button.secondary {
    border-color: var(--control-border-strong);
}

button.secondary:hover:not(:disabled) {
    border-color: #97a3b2;
}

button.small {
    min-height: 2rem;
    padding: 0.2rem 0.6rem;
    font-size: 0.82rem;
    border-radius: 8px;
}

/* A link that has to sit in a row of buttons and match them. */
.button-link {
    display: inline-block;
    padding: var(--spacing-sm) var(--spacing-md);
    border-radius: 4px;
    /* Colour comes from the role, in buttons.css. */
    text-decoration: none;
    font-size: 1em;
    transition: background-color 0.2s ease;
}

/* Present to a screen reader, absent to everyone else. */
.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;
}

/* Progress Bar Styles */
.progress {
    background-color: #e0e0e0;
    border-radius: 5px;
    height: var(--spacing-sm);
    overflow: hidden;
}

.progress span {
    display: block;
    height: 100%;
    background-color: #28a745;
    border-radius: 5px;
    transition: width 0.5s ease-in-out;
}

/* Dark Mode Styles */
html.dark {
    --font-color: #e0e0e0;
    --bg-color: #2c3e50;
    --card-bg-color: #34495e;
    --header-bg-color: #34495e;
    --header-h1-color: #ecf0f1;
    --muted-color: #bdc3c7;
    --input-bg-color: #2c3e50;
    --input-border-color: #555;
    --input-color: #ecf0f1;
    --progress-bg-color: #555;
    --progress-span-color: #28a745;
}

html.dark body {
    background-color: var(--bg-color);
    color: var(--font-color);
}

html.dark .app-header {
    background-color: var(--header-bg-color);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

html.dark .app-header h1 {
    color: var(--header-h1-color);
}

html.dark .muted {
    color: var(--muted-color);
}

html.dark .card {
    background-color: var(--card-bg-color);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
}

html.dark .card h2 {
    color: var(--header-h1-color);
}

html.dark label {
    color: var(--muted-color);
}

/* Dark mode is a redefinition of the tokens, not a second copy of every
 * rule above. */
html.dark {
    --control-border: #4a5b6d;
    --control-border-strong: #61748a;
    --control-bg: #2b3a4a;
    --control-color: #ecf0f1;
    --control-placeholder: #93a2b3;
    --control-accent: #4f9df0;
    --control-accent-soft: rgba(79, 157, 240, 0.28);
}

html.dark input[type="text"],
html.dark input[type="password"],
html.dark input[type="number"],
html.dark input[type="date"],
html.dark input[type="time"],
html.dark input[type="url"],
html.dark input[type="datetime-local"],
html.dark select,
html.dark textarea {
    background-color: var(--control-bg);
    border-color: var(--control-border);
    color: var(--control-color);
    box-shadow: none;
}

html.dark label {
    color: #c7d0da;
}

html.dark input:disabled,
html.dark select:disabled,
html.dark textarea:disabled {
    background-color: #263442;
    color: #7d8b9a;
}

html.dark .progress {
    background-color: var(--progress-bg-color);
}

html.dark .progress span {
    background-color: var(--progress-span-color);
}

/* Password show/hide. The wrapper is created by password-eye.js. */
.pw-wrap {
    position: relative;
    display: block;
    width: 100%;
}

.pw-wrap input {
    width: 100%;
    box-sizing: border-box;
    /* Room for the button so text never runs under it. */
    padding-right: 48px;
}

.pw-eye {
    position: absolute;
    right: 2px;
    top: 50%;
    transform: translateY(-50%);
    background: transparent;
    border: none;
    font-size: 18px;
    line-height: 1;
    /* A real tap target, not a decoration. */
    min-width: 44px;
    min-height: 44px;
    cursor: pointer;
    padding: 0;
}

.pw-eye:hover {
    background: transparent;
    transform: translateY(-50%);
}

/* Branding photos. Inline images or files this app serves; never a
 * third-party URL, which would make every member's browser call out to
 * somebody else on every page load. */
.photo-strip {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-sm);
    margin-bottom: var(--spacing-lg);
    align-items: center;
}

.photo-strip img {
    border-radius: 8px;
    object-fit: cover;
    max-width: 100%;
}

/* The running build, at the foot of the member and admin pages. Quiet on
 * purpose: it is for the one conversation a month that starts "something
 * looks wrong", not something to read past every day. */
.version-line {
    margin-top: var(--spacing-xl);
    text-align: center;
    opacity: 0.75;
}

/* A button that reads as a link. Used where the action is secondary to the
 * sentence it sits in -- "Not you?", "Reset the order" -- and a full button
 * would out-shout the thing it qualifies. */
.link-button {
    background: none;
    border: none;
    padding: 0;
    margin: 0;
    color: #2a78d6;
    font: inherit;
    text-decoration: underline;
    cursor: pointer;
    min-height: 0;
}

.link-button:hover {
    background: none;
    color: #1b5ea8;
}

html.dark .link-button {
    color: #7db3f0;
}

/* Who last signed in on this browser. */
.last-user {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--spacing-xs);
    margin: 0 0 var(--spacing-sm);
    font-size: 0.95em;
}

/* Card reordering. The buttons sit in the corner of the card they move,
 * because a control that is not attached to its target is a control people
 * press on the wrong card. */
/* The arrange controls sit in the card's corner, out of the flow.
 *
 * They used to float right, and a float is the one thing that could not
 * work here: a flex container beside a float does not flow around it, it
 * shrinks to avoid it -- for its whole height. The quote card's text is a
 * flex column, so a quote in a half-width card was squeezed into a ribbon
 * half the card wide with empty space beside it, and a chart title wrapped
 * under the buttons rather than beside them.
 *
 * Absolute, so the content underneath uses the full width; the heading
 * beside them gets padding instead, which is the only thing they can
 * actually collide with.
 */
.section-move {
    display: flex;
    gap: var(--spacing-xxs);
    justify-content: flex-end;
    position: absolute;
    top: var(--spacing-xs);
    right: var(--spacing-xs);
    z-index: 2;
}

[data-section] {
    position: relative;
}

/* Room for four small buttons. Only the first heading needs it: everything
 * below the controls is clear of them. */
[data-section] > h2:first-of-type,
[data-section] > h3:first-of-type,
[data-section] > .card-head {
    padding-right: 10.5em;
    min-height: 2.2em;
}

@media (max-width: 480px) {
    /* On a narrow phone the buttons take the line to themselves rather than
     * squeezing a heading into two words per line. */
    .section-move {
        position: static;
        justify-content: flex-start;
        margin-bottom: var(--spacing-xs);
    }

    [data-section] > h2:first-of-type,
    [data-section] > h3:first-of-type,
    [data-section] > .card-head {
        padding-right: 0;
    }
}

/* The arrange controls, put away from the heading.
 *
 * `display: none` rather than `visibility: hidden`: the point is the space as
 * much as the clutter, and a heading that still reserves ten ems for four
 * invisible buttons has given back nothing. The reserved room comes back
 * below for the same reason. */
body.controls-hidden .section-move {
    display: none;
}

body.controls-hidden [data-section] > h2:first-of-type,
body.controls-hidden [data-section] > h3:first-of-type,
body.controls-hidden [data-section] > .card-head {
    padding-right: 0;
}

/* The collapsed-card label reserves the same room, for the same buttons. */
body.controls-hidden .section-collapsed-label {
    padding-right: 0;
}

.section-move .section-width.is-on,
.header-actions button.is-on {
    /* On means "sharing a row" for the width button and "the controls are
     * out" for the heading's; in both cases the button is lit rather than
     * relabelled, so there is nothing to read before pressing it. */
    background-color: #2a78d6;
    color: #ffffff;
}

/* Collapsed: the heading and the controls stay, everything else goes. A
 * collapsed card is a card you can still find, which is the point of
 * collapsing rather than hiding.
 *
 * `.section-toggle` is in that list because on the settings page the section
 * name *is* the toggle -- a button, not a heading -- so hiding it collapsed
 * a card down to four anonymous arrows and no way to tell which one it was.
 */
.is-collapsed > *:not(.section-move):not(h1):not(h2):not(h3):not(.card-head):not(.section-toggle) {
    display: none;
}

/* A collapsed toggle should not still claim to be expandable-looking: the
 * arrow points the way it will go. */
.is-collapsed > .section-toggle {
    opacity: 0.85;
}

.is-collapsed {
    /* A collapsed card must not keep a height somebody dragged it to. */
    height: auto !important;
    resize: none;
}

.is-collapsed .card-head > *:not(h1):not(h2):not(h3) {
    display: none;
}

/* Cards beside each other, at four widths, packed.
 *
 * Six tracks rather than two, because six is the first number that divides by
 * both: full is six, a half three, a third two, two thirds four. The grid only
 * exists while something is narrower than full, so a page of full-width cards
 * lays out exactly as it did before any of this -- and on a phone that is
 * every page, because section-order.js gives every card the full six tracks
 * below the reader's first threshold and the class comes off.
 *
 * There are no media queries here on purpose. The widths at which this changes
 * are set by the reader per browser, and a media query cannot read a stored
 * number; `--section-span` is written per card from JS instead.
 */
.sections-grid {
    display: grid;
    grid-template-columns: repeat(6, minmax(0, 1fr));
    gap: var(--spacing-lg);
    align-items: start;
}

.sections-grid > * {
    grid-column: span var(--section-span, 6);
    min-width: 0;
}

/* Packing -- every card measured and given a row span in four-pixel rows --
 * has no rule here on purpose.
 *
 * `align-items: start` above stops a short card stretching to its neighbour's
 * height, and on its own that is not enough: the row is still as tall as the
 * tallest card in it, so the gap moves from inside the short card to
 * underneath it, which is the same gap in a worse place. Small rows and an
 * explicit span each are what actually close it, and both are written inline
 * by section-order.js -- the dashboard's wide-screen grid is selected far too
 * specifically for a class here to reach it. `.is-packed` on the container
 * says it has happened; it carries nothing.
 *
 * So a page whose script never ran still gets the plain grid above -- cards
 * side by side with gaps under the short ones, which is where this started --
 * rather than a pile of overlapping ones.
 */

.section-move button {
    min-width: 40px;
    min-height: 36px;
    padding: 2px 8px;
    line-height: 1;
}

.section-move button:disabled {
    opacity: 0.35;
    cursor: default;
}

.section-order-note {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-xs);
    align-items: baseline;
    margin: 0 0 var(--spacing-md);
}

/* Where the reader sets the two widths at which this page changes shape.
 * Wraps rather than scrolls: it sits inside the member page's note and inside
 * the dashboard's display panel, and neither has a width to promise. */
.section-layout {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-xs) var(--spacing-md);
    align-items: baseline;
    margin: 0 0 var(--spacing-md);
}

.layout-threshold {
    display: flex;
    gap: var(--spacing-xxs);
    align-items: baseline;
    margin: 0;
}

.layout-threshold input[type="number"] {
    width: 6em;
    min-height: 36px;
    margin: 0;
}

.layout-unit {
    /* The unit belongs to the box, not to the gap after it. */
    margin-left: -2px;
}

.layout-wide,
.layout-now {
    /* Their own lines: the tick box is a sentence rather than a labelled
     * number, and the readout is the answer to "what did that do" -- reading
     * it beside the control that just changed is the whole point of it. */
    flex-basis: 100%;
    margin: 0;
}

/* Not the real database. Loud on purpose, and on every page.
 *
 * The failure this exists to prevent is quiet and expensive: an evening's
 * real entries recorded into a test copy, which nothing backs up and which
 * the next switch throws away. Somebody has to be able to tell at a glance,
 * from whatever page they happen to be on.
 *
 * Amber rather than red. Red is the maintenance banner and the danger zone,
 * and a working application is not an error -- it is the wrong filing
 * cabinet.
 */
.test-db-badge {
    display: inline-flex;
    align-items: center;
    padding: 3px 9px;
    border-radius: 999px;
    border: 1px solid #d08700;
    background-color: #ffc046;
    color: #3a2200;
    /* The name has to be read exactly; the rest of the badge is a label. */
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: 0.75rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    line-height: 1.4;
    white-space: nowrap;
    /* Long names truncate rather than pushing the heading's buttons onto
     * another line; the full name is in the title and the aria-label. */
    max-width: 16em;
    overflow: hidden;
    text-overflow: ellipsis;
}

/* The sign-in page and the wall display have no heading to sit in, so it
 * pins itself to the corner instead. Fixed rather than absolute: the lobby
 * screen never scrolls, and on the sign-in page the badge should not scroll
 * away from somebody reading down a long gatekeeper message. */
body > .test-db-badge {
    position: fixed;
    top: 8px;
    right: 8px;
    z-index: 60;
}

@media print {
    /* A printed report outlives the session it came from, so which database
     * it came out of belongs on it -- as text, not as a filled pill. */
    .test-db-badge {
        background: none;
        color: #000000;
        border-color: #000000;
    }
}

/* The one in use, in the Test Databases table.
 *
 * `is-active-database` was already being put on the row by admin-settings.js
 * and no rule anywhere used it, so the only thing distinguishing the live
 * database from the others was the text "(in use)" at the end of its name --
 * in a column of names, on a row identical to every other. */
tr.is-active-database {
    background-color: #fff3d6;
    box-shadow: inset 4px 0 0 #d08700;
}

tr.is-active-database th,
tr.is-active-database td {
    font-weight: 600;
}

html.dark tr.is-active-database {
    background-color: #4a3a12;
    box-shadow: inset 4px 0 0 #ffc046;
}

/* Down for maintenance. Loud on purpose: it is the answer to "why can I not
 * sign in", and someone who misses it will ask a person instead. */
.maintenance-banner {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-xxs);
    background-color: #fdecea;
    border: 2px solid #b02a37;
    color: #7a1620;
    border-radius: 8px;
    padding: var(--spacing-md);
    margin-bottom: var(--spacing-lg);
}

html.dark .maintenance-banner {
    background-color: #3a1418;
    border-color: #ff9aa4;
    color: #ffd9dd;
}

.maintenance-card {
    max-width: 40em;
    margin: var(--spacing-xxl) auto;
    text-align: center;
}

.maintenance-message {
    font-size: 1.1em;
}

/* A card the reader can resize. `resize` is the browser's own grip -- no
 * pointer maths, no drag library, and it works with a trackpad, a touch
 * screen and a keyboard-driven zoom alike. The size is remembered per
 * browser next to the order. */
.section-resizable {
    resize: vertical;
    overflow: auto;
    /* Low enough that a card can be dragged down to a strip. The old floor
     * of 6em meant the header and the controls could not be made small,
     * which is most of what anybody wants to do with them. */
    min-height: 2.5em;
}

.section-resizable.is-sized {
    /* Once a reader has set a height, the card stops growing with its
     * content -- which is the point of having set one. */
    overflow: auto;
}

/* ---- compact chrome ------------------------------------------------------
 *
 * The header and the controls card shrink to a line. Neither carries data,
 * and on a screen showing charts to a room both are mostly in the way once
 * they have been set.
 */
.app-header.is-compact {
    padding: var(--spacing-xs) var(--spacing-md);
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-sm);
}

.app-header.is-compact h1 {
    font-size: 1.1em;
    margin: 0;
}

.app-header.is-compact .small,
.app-header.is-compact .muted,
.app-header.is-compact p {
    display: none;
}

/* The clock survives: on a wall display it is the only thing saying the
 * screen is still live. */
.app-header.is-compact #clock {
    display: inline;
    font-size: 0.8em;
    margin-left: var(--spacing-sm);
}

.compact-toggle {
    min-width: 40px;
    min-height: 32px;
    padding: 2px 8px;
    line-height: 1;
}

/* The replay card had a fold control of its own -- a card that could be
 * collapsed to its first row, inside a panel that could be hidden, behind a
 * button that revealed the panel. Three levels of hiding for one set of
 * controls. It is one now: the button in the heading, and the card is either
 * there or it is not, so `.replay-card.is-compact` and everything under it
 * has gone with the button that set it.
 */

/* The photo strip is a card now, so it collapses and moves with the rest.
 * The height comes from the administrator's setting and is overridden per
 * browser by the slider on the card. */
.photo-card .photo-strip {
    margin-bottom: 0;
}

.photo-card img {
    height: var(--photo-height, 80px);
}

.photo-controls {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-md);
    margin-bottom: var(--spacing-sm);
}

.photo-controls label {
    display: flex;
    align-items: center;
    gap: var(--spacing-xs);
}

/* The name of a collapsed card that has no heading of its own -- the hero
 * figure and the photo strip are all content and nothing else, and
 * collapsing them left a strip with four arrows and no way to tell which
 * card it was. Hidden while the card is open, where the content says what it
 * is. */
.section-collapsed-label {
    display: none;
    margin: 0;
    font-weight: 600;
    padding-right: 10.5em;
}

.is-collapsed > .section-collapsed-label {
    display: block;
}

/* Where a card has both, the heading is enough. */
.is-collapsed:has(> h2) > .section-collapsed-label,
.is-collapsed:has(> h1) > .section-collapsed-label,
.is-collapsed:has(> .card-head) > .section-collapsed-label,
.is-collapsed:has(> .section-toggle) > .section-collapsed-label {
    display: none;
}

/* The way back to a member's own page.
 *
 * Green, and the only green control in any heading. Every other button in
 * that row does something to the page you are on; this one leaves it, and on
 * a dashboard being read by somebody who arrived from a link it is the most
 * useful control in the row and looked exactly like the rest.
 *
 * A dark enough green to carry white text: #1b7f3b against #ffffff is 4.8:1,
 * which clears AA for the size these are set at. "Bright" at the expense of
 * being unreadable is not brighter.
 */
.button-link.is-home {
    /* Colour comes from the role, in buttons.css. */
}

.button-link.is-home:hover {
    background-color: #15672f;
    border-color: #15672f;
}

html.dark .button-link.is-home {
    /* Lighter on a dark card, for the same reason it is darker on a light
     * one: the text on it has to stay readable. */
    background-color: #2ea75a;
    border-color: #2ea75a;
    color: #08240f;
}
