/*
 * Help Room — mobile-first layout layer.
 *
 * NET-NEW, FLAGGED FOR REVIEW. The platform's shared components are
 * desktop-content oriented and there is no existing mobile-first pattern to
 * reuse, so these are NEW LAYOUT classes (a phone-first screen container, a
 * compact status strip, an action bar). They do NOT override shared components
 * — forms (.form-group), buttons (.btn), badges (.status-badge), and cards
 * (.section-card) are reused as-is. All colors and design tokens come only
 * from theme-consolidated.css (no hardcodes, no fallbacks).
 *
 * Mobile-first: base rules target the phone; min-width queries enhance upward.
 */

/* Landing hero page (body.template-helproom-landing, set by landing.html):
   the full-bleed .home-hero sits flush under the site header (zero the content
   wrapper's top padding, like the home/courses landings) and its
   ~scrollbar-width `width: 100vw` overhang is clipped.

   The clip is on the CONTENT WRAPPER, not the body: clipping the body would
   propagate to the viewport and pull the full-width sticky header in. The
   wrapper contains the hero but not the header, so the header stays full-width.
   `overflow-x: clip` (not `hidden`) clips without creating a scroll container. */
body.template-helproom-landing .background-white.padding-medium-top {
    padding-top: 0;
    overflow-x: clip;
}

/* Phone-first screen: comfortable single column, centered + capped on larger
   screens so it reads like an app screen, not a stretched desktop form. */
.hr-screen {
    width: 100%;
    max-width: 40rem;
    margin-inline: auto;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-4);
}

.hr-screen__header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-3);
    flex-wrap: wrap;
}

/* Avatar chip + page title, grouped on the left of the dashboard header. */
.hr-screen__heading {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
}

.hr-screen__title {
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    margin: 0;
}

.hr-screen__subtitle {
    color: var(--text-secondary);
    margin: 0;
}

/* Semester / context tag shown on the header row, beside the screen title. */
.hr-screen__meta {
    color: var(--text-secondary);
    font-size: var(--font-size-lg);
}

/* Groups the screen title with its context tag so they share one row (and wrap
   together) while a header action stays opposite them. */
.hr-screen__heading {
    display: flex;
    align-items: baseline;
    gap: var(--spacing-3);
    flex-wrap: wrap;
}

/* The room location line in the landing hero — stronger than the subtitle so
   "where do I go" reads at a glance. */
.hr-screen__location {
    margin: 0;
    font-weight: var(--font-weight-semibold);
}

/* A quiet one-line hint (login note, empty states) — lighter than an alert. */
.hr-screen__hint {
    margin: 0;
    color: var(--text-secondary);
    font-size: var(--font-size-sm);
}

/* ── Landing top zone ─────────────────────────────────────────────────────
   Mirrors the demos landing: identity + intro text on the left, the live
   status panel (a .section-card) on the right. Mobile-first: a single
   stacked column; the two-zone split arrives with width. Theme-aware —
   everything uses semantic colors on the normal page background. */
.hr-top {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-4);
}

.hr-top__intro {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
    min-width: 0;
}

/* Carries its own surface rather than composing .section-card. It sits beside
   the .hr-item cards further down the page and takes their treatment — a
   hairline border on the same background, no drop shadow — where .section-card
   is a raised panel. Declaring it here avoids inheriting the shadow and then
   having to out-specify the [data-theme="dark"] .section-card rule to remove
   it, which would only hold while this file happens to load last. */
.hr-top__status {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3);
    margin-bottom: 0;
    background: var(--card-bg);
    border: var(--border-1) solid var(--border-color);
    border-radius: var(--radius-lg);
    /* Matches what .section-card actually rendered here: components.css asks
       for --spacing-8, but the touch-target rule in accessibility.css lands
       later and wins with 0.5rem 1rem. */
    padding: var(--spacing-2) var(--spacing-4);
}

.hr-top__badge {
    margin: 0;
}

@media (min-width: 768px) {
    .hr-top {
        flex-direction: row;
        align-items: flex-start;
        gap: var(--spacing-8);
    }
    .hr-top__intro {
        flex: 1 1 55%;
    }
    .hr-top__status {
        flex: 1 1 45%;
        max-width: 28rem;
    }
}

/* Compact horizontal status strip — three at-a-glance numbers in one row on
   phones (vs. tall stacked stat-cards). */
.hr-statbar {
    display: flex;
    gap: var(--spacing-2);
}

.hr-statbar__item {
    flex: 1 1 0;
    background: var(--bg-secondary);
    border-radius: var(--radius-lg);
    padding: var(--spacing-3) var(--spacing-2);
    text-align: center;
}

.hr-statbar__num {
    display: block;
    font-size: var(--font-size-2xl);
    font-weight: var(--font-weight-bold);
    line-height: 1;
    color: var(--ucb-gold-text);
}

.hr-statbar__label {
    display: block;
    margin-top: var(--spacing-1);
    font-size: var(--font-size-xs);
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

/* Action bar: full-width, thumb-friendly primary action on phones. */
.hr-actions {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
}

.hr-actions .btn {
    width: 100%;
    padding-block: var(--spacing-3);
    font-size: var(--font-size-base);
}

/* A single big at-a-glance number (e.g. queue position) for the status screen. */
.hr-bignum {
    text-align: center;
    padding: var(--spacing-4) 0;
}

.hr-bignum__value {
    font-size: var(--font-size-6xl);
    font-weight: var(--font-weight-bold);
    line-height: 1;
    color: var(--ucb-gold-text);
}

.hr-bignum__label {
    margin-top: var(--spacing-2);
    color: var(--text-secondary);
    text-transform: uppercase;
    letter-spacing: 0.05em;
    font-size: var(--font-size-sm);
}

/* Enhance for tablet/desktop: a touch more breathing room, side-by-side
   action buttons when there's room. */
@media (min-width: 768px) {
    .hr-actions {
        flex-direction: row;
        flex-wrap: wrap;
        /* Keep buttons at their natural height — without this, a row that also
           holds a taller item (e.g. the header's semester dropdown) stretches
           every button to match it. */
        align-items: center;
    }
    .hr-actions .btn {
        width: auto;
        flex: 1 1 auto;
    }
}

/* Compact semester dropdown in a screen header: its label is visually hidden
   (the value + the page title already say the semester), and it sizes to its
   content rather than stretching the action row. */
.hr-semester-picker {
    flex: 0 0 auto;
}

.hr-semester-picker select {
    width: auto;
}

/* Inline secondary actions inside a card (e.g. "Update location", the faculty
   "Remove" helper button): compact and right-aligned at every width so they
   don't compete with the screen's primary action. justify-content right-aligns
   the buttons within a full-width container; margin-left:auto pushes the whole
   group to the far edge when it sits beside a sibling in a flex row (the helper
   name in .hr-item__top). Placed after the media query above so it wins at
   desktop widths too. */
.hr-actions--inline {
    flex-direction: row;
    justify-content: flex-end;
    margin-left: auto;
}

.hr-actions--inline .btn {
    width: auto;
    flex: 0 0 auto;
    padding-block: var(--spacing-2);
    font-size: var(--font-size-sm);
}

/* Wider variant for working screens (helper dashboard, schedule builder) that
   benefit from two columns on desktop while still stacking phone-first. */
.hr-screen--wide {
    max-width: 64rem;
}

/* A small section heading inside a screen ("My active sessions", "Waiting").
   Lighter than .section-card h2, which is a heavy 3xl panel heading. */
.hr-section-title {
    font-size: var(--font-size-lg);
    font-weight: var(--font-weight-bold);
    margin: 0 0 var(--spacing-2);
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    flex-wrap: wrap;
}

/* The View-analytics button rides in the course heading row (after the section
   meta); keep it from shrinking when space is tight. Layout only. */
.hr-section-title .btn {
    flex-shrink: 0;
}

/* Faculty analytics: horizontal bar lists (category / weekly distributions)
   and a day×hour demand heatmap table. Layout + token shading only; the count
   numbers carry the precise data, so the heat tint is a visual aid (and stays
   subtle enough to keep the cell text readable in both themes). */
.hr-bars {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
}

.hr-bar {
    display: grid;
    grid-template-columns: minmax(5rem, 9rem) 1fr auto;
    align-items: center;
    gap: var(--spacing-3);
}

.hr-bar__label {
    color: var(--text-secondary);
    font-size: var(--font-size-sm);
}

.hr-bar__track {
    background: var(--bg-elevated);
    /* Outline the full extent: the track shares --bg-elevated with cards and the
       table's even zebra stripe, so without a border it disappears into those
       surfaces (the 100% reference vanished on alternating rows). */
    border: var(--border-1) solid var(--border-color);
    border-radius: var(--radius-sm);
    height: var(--spacing-3);
    overflow: hidden;
}

.hr-bar__fill {
    display: block;
    height: 100%;
    width: var(--bar);
    min-width: var(--spacing-1);
    background: var(--ucb-gold);
    border-radius: var(--radius-sm);
}

.hr-bar__value {
    font-weight: var(--font-weight-bold);
    font-variant-numeric: tabular-nums;
}

.hr-heat-wrap {
    overflow-x: auto;
}

.hr-heat {
    border-collapse: collapse;
    width: 100%;
    font-size: var(--font-size-sm);
}

.hr-heat th,
.hr-heat td {
    border: 1px solid var(--border-color);
    padding: var(--spacing-1);
    text-align: center;
}

.hr-heat th {
    /* The global th pairing (--table-header-bg/-text) is a heavy charcoal that
       fights the gold heat scale, so this grid uses a light, neutral surface
       that lets the gold cells read as the data. Works in both themes:
       --bg-tertiary/--text-primary invert together. */
    background: var(--bg-tertiary);
    color: var(--text-primary);
    font-weight: var(--font-weight-bold);
    white-space: nowrap;
}

.hr-heat__cell {
    color: var(--text-primary);
    font-variant-numeric: tabular-nums;
    /* Cap the gold tint at 22%: above that the dark-mode cell text drops below
       the WCAG AA 4.5:1 ratio (the count, not the shade, carries the value). */
    background: color-mix(in srgb, var(--ucb-gold) calc(var(--heat) * 22%), var(--bg-elevated));
}

/* Faculty analytics: an expandable bar — a <details> whose <summary> IS the
   bar row. Clicking a week reveals the anonymous descriptions students typed
   that week. A custom marker replaces the native one (grid summaries suppress
   it); a leading marker column (--markable) keeps expandable and plain bars in
   alignment. Layout + token surfaces only. */
.hr-bar--markable {
    grid-template-columns: var(--spacing-4) minmax(5rem, 9rem) 1fr auto;
}

.hr-bar--expandable {
    cursor: pointer;
    list-style: none;
}

.hr-bar--expandable::-webkit-details-marker {
    display: none;
}

.hr-bar--expandable:focus-visible {
    outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);
    outline-offset: var(--focus-outline-offset);
}

/* Right-pointing triangle (colored left border, transparent top/bottom); turns
   to point down when its <details> is open. */
.hr-bar__marker {
    width: 0;
    height: 0;
    border-left: var(--spacing-2) solid var(--text-secondary);
    border-top: var(--spacing-1) solid transparent;
    border-bottom: var(--spacing-1) solid transparent;
    transition: transform var(--transition-fast);
}

.hr-bar-group[open] .hr-bar__marker {
    transform: rotate(90deg);
}

.hr-topic-list {
    margin: 0;
    padding: var(--spacing-1) var(--spacing-3) var(--spacing-2) var(--spacing-7);
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
}

.hr-topic-list__item {
    color: var(--text-secondary);
    font-size: var(--font-size-sm);
}

/* Coverage grid (drill-down): week × slot table, reusing .hr-heat layout. The
   cell tint encodes the coverage tier (success/warning/danger tokens, all WCAG
   AA on their paired text) while the % text carries the exact value. */
.hr-cov th[scope="row"] {
    text-align: left;
    white-space: nowrap;
}

.hr-cov-cell--full {
    background: var(--color-success-bg);
    color: var(--color-success-text);
}

.hr-cov-cell--partial {
    background: var(--color-warning-bg);
    color: var(--color-warning-text);
}

.hr-cov-cell--none {
    background: var(--color-danger-bg);
    color: var(--color-danger-text);
}

.hr-cov-cell--empty {
    color: var(--text-secondary);
}

/* Faculty portal: separate the add-helper form from the helper list above it. */
.hr-add-helper {
    margin-top: var(--spacing-5);
}

/* Faculty portal: confirm-helper modal card. Layout only — colors come from
   the shared .modal / .btn components. */
.hr-confirm__lead {
    margin: 0 0 var(--spacing-3);
}

.hr-confirm__details {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--spacing-1) var(--spacing-3);
    margin: 0 0 var(--spacing-3);
}

.hr-confirm__details dt {
    font-weight: var(--font-weight-semibold);
}

.hr-confirm__details dd {
    margin: 0;
}

.hr-confirm__note {
    margin: 0 0 var(--spacing-3);
    font-size: var(--font-size-sm);
}

/* Top bar: breadcrumb on the left, the Available toggle on the right — using the
   otherwise-empty breadcrumb space so it doesn't take its own row beside the
   title on mobile. The check-in/out button stays by the title
   (.hr-screen__header), so the two presence controls split across the two rows
   that each have room. */
.hr-topbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-3);
    flex-wrap: wrap;
    margin-bottom: var(--spacing-3);
}

.hr-topbar__action {
    margin: 0;
    margin-left: auto;  /* stay right-aligned even if the breadcrumb wraps */
}

/* Availability toggle + its live label, sitting at the right of the title row. */
.hr-presence__toggle {
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-2);
}

.hr-presence__status {
    font-weight: var(--font-weight-semibold);
    /* Tighten the line box to ~the toggle height so the switch and label center
       on each other (the relaxed body line-height made the toggle read low). */
    line-height: var(--line-height-tight);
}

.hr-presence__hint {
    margin: 0;
}

/* Claim-button group in the queue header: the course-scoped primaries +
   "any course" overflow, wrapping onto their own row on narrow screens. */
.hr-claim-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-2);
}

/* Shared "Help next:" label that prefixes the compact scope buttons, so the
   bare course-code / General / Any buttons read as "help next in …" without
   each repeating the phrase. */
.hr-claim-actions__label {
    color: var(--text-secondary);
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
}

/* Compact claim buttons — tighter than .btn so the scope row stays on one line.
   Rounded rectangles (not the coverage chips' full pills) so the actions read
   as distinct from the Covering toggles. Course scopes are gold-filled
   (primary); General/Any are the lighter ghost overflow. */
.hr-claim__btn {
    padding: var(--spacing-1) var(--spacing-3);
    border: var(--border-2) solid var(--border-color);
    border-radius: var(--radius-md);
    background: transparent;
    color: var(--text-primary);
    font-family: inherit;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    cursor: pointer;
    transition: background-color var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.hr-claim__btn:hover {
    background: var(--bg-secondary);
}

.hr-claim__btn--primary {
    background: var(--ucb-gold);
    border-color: var(--ucb-gold);
    color: var(--ucb-black);
}

.hr-claim__btn--primary:hover {
    background: var(--ucb-gold-dark);
    border-color: var(--ucb-gold-dark);
    color: var(--ucb-black);
}

.hr-claim__btn:focus-visible {
    outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);
    outline-offset: var(--focus-outline-offset);
}

.hr-claim__btn:disabled {
    opacity: 0.6;
    cursor: not-allowed;
}

/* Coverage toggles (helper dashboard): real <button aria-pressed> pills for the
   courses + General the helper is covering right now. Off reads as an outlined
   pill, on as a filled gold pill — a fill/outline difference (not color alone),
   with aria-pressed carrying the state for assistive tech. Mirrors the
   lightweight On-break affordance. */
.hr-coverage {
    margin-block: var(--spacing-2);
}

.hr-coverage__toggles {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-2);
}

.hr-coverage__form {
    margin: 0;
}

.hr-coverage__toggle {
    padding: var(--spacing-1) var(--spacing-3);
    border: var(--border-2) solid var(--ucb-gold);
    border-radius: var(--radius-full);
    background: transparent;
    color: var(--text-primary);
    font-family: inherit;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-medium);
    cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}

.hr-coverage__toggle:hover {
    background: var(--bg-secondary);
}

/* On: a filled gold pill (distinct from the outlined off state, not hue-only). */
.hr-coverage__toggle[aria-pressed="true"] {
    background: var(--ucb-gold);
    color: var(--ucb-black);
}

.hr-coverage__toggle[aria-pressed="true"]:hover {
    background: var(--ucb-gold-dark);
    border-color: var(--ucb-gold-dark);
}

.hr-coverage__toggle:focus-visible {
    outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);
    outline-offset: var(--focus-outline-offset);
}

.hr-coverage__toggle:disabled {
    opacity: 0.6;
    cursor: progress;
}

/* Phone-first columns: stacked on phones, side by side on desktop. The first
   child stays narrower (controls / forms), the second grows (the live list). */
.hr-cols {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-3);
}

/* Each column is its own vertical stack, so a gap separates the section
   heading (and the "Claim next" buttons) from the card list beneath it. */
.hr-cols__aside,
.hr-cols__main {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
    min-width: 0;
}

@media (min-width: 768px) {
    .hr-cols {
        flex-direction: row;
        align-items: flex-start;
    }
    /* The aside (coverage + active sessions) stays compact so the live queue
       gets the room — it's mostly empty when no one's being helped. */
    .hr-cols__aside {
        flex: 1 1 30%;
    }
    .hr-cols__main {
        flex: 1 1 70%;
    }
}

/* Landing manager tooling: a labeled cluster of admin links below the shared
   page list. The "Manager tools" heading + extra top space (no divider rule)
   separate manager-only tools from the public navigation; each task group
   stacks its own compact card list so a manager scans by group instead of
   reading one flat list. Layout/token only. */
.hr-manager-tools {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-4);
    padding-top: var(--spacing-4);
}

.hr-tool-group {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
}

/* Group label heading each cluster of links. Base size (matches the card
   titles, so it never reads smaller than the cards) and the secondary color +
   lighter weight keep it clearly subordinate to the bold "Manager tools" h2. */
.hr-tool-group__title {
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-semibold);
    color: var(--text-secondary);
    margin: 0;
}

/* Compact card list (queue entries, active sessions, schedule slots). Tighter
   than .section-card, which is a heavy full-width panel — this mirrors the
   scheduling app's per-item card pattern. Token-only; no component overrides. */
.hr-list {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
}

.hr-item {
    background: var(--card-bg);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-lg);
    padding: var(--spacing-2) var(--spacing-3);
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
}

/* Accent a card that needs attention (e.g. a student who requested this helper). */
.hr-item--accent {
    border-color: var(--color-success);
    border-width: 2px;
}

/* Location card with a ready-to-post join QR: details on the left, the
   scannable code on the right. Stacks on narrow screens. */
.hr-item--location {
    flex-direction: row;
    align-items: flex-start;
    flex-wrap: wrap;
    gap: var(--spacing-3);
}

.hr-item__body {
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: var(--spacing-2);
}

/* Only the row-layout location card needs the body to claim the remaining
   width beside the QR code. On the default column-layout cards a flex-basis
   here would instead force a tall vertical height regardless of content. */
.hr-item--location .hr-item__body {
    flex: 1 1 16rem;
}

.hr-location-qr {
    flex: none;
    background: var(--ucb-white);
    border-radius: var(--radius-md);
    padding: var(--spacing-2);
    line-height: 0;
}

.hr-location-qr img {
    display: block;
    width: 7rem;
    height: auto;
    image-rendering: pixelated;
}

/* A card that is itself a link (landing navigation): the whole card is the
   tap target, so suppress the global anchor underline/color and signal
   clickability with a chevron + hover/focus affordance instead. */
a.hr-item--link {
    color: var(--text-primary);
    text-decoration: none;
    position: relative;
    padding-right: var(--spacing-8);
    transition: var(--transition-fast);
    transform: translateZ(0);
    backface-visibility: hidden;
}

a.hr-item--link::after {
    content: "›";
    position: absolute;
    right: var(--spacing-3);
    top: 50%;
    transform: translateY(-50%);
    font-size: var(--font-size-xl);
    color: var(--text-secondary);
}

a.hr-item--link:hover,
a.hr-item--link:focus-visible {
    color: var(--text-primary);
    text-decoration: none;
    border-color: var(--ucb-gold);
    box-shadow: var(--shadow-sm);
}

a.hr-item--link:focus-visible {
    outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);
    outline-offset: var(--focus-outline-offset);
}

.hr-item__top {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--spacing-2);
}

.hr-item__name {
    font-weight: var(--font-weight-semibold);
}

/* Wait time / time range sits at the far right of the row. */
.hr-item__meta {
    margin-left: auto;
    color: var(--text-secondary);
    font-size: var(--font-size-sm);
    white-space: nowrap;
}

.hr-item__badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-1);
}

/* Per-display font-size tuner (manager displays page). */
.hr-scale-form {
    margin-block: var(--spacing-3);
}

.hr-scale-form__row {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
    margin-block: var(--spacing-1);
}

.hr-scale-form__row .form-control {
    width: auto;
    max-width: 6rem;
    flex: 0 0 auto;
}

.hr-scale-form__row .btn {
    flex: 0 0 auto;
}

.hr-item__topic {
    color: var(--text-secondary);
    font-size: var(--font-size-sm);
    margin: 0;
}

/* Student table/location — wayfinding for the helper, so it reads as primary
 * text (not muted like topic/meta). */
.hr-item__loc {
    display: flex;
    align-items: center;
    gap: var(--spacing-1);
    font-weight: var(--font-weight-semibold);
    color: var(--text-primary);
    margin: 0;
}

/* Waiting-queue card body: student info on the left; the claim button stacked
   top-right with the wait time directly beneath it (right-aligned). Keeps each
   queue card compact — the button no longer spans its own full-width row. */
.hr-queue {
    display: flex;
    align-items: flex-start;
    gap: var(--spacing-3);
}

.hr-queue__main {
    flex: 1 1 auto;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
}

.hr-queue__aside {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: var(--spacing-1);
}

/* Weekly schedule grid: one day per row on phones, widening to a multi-day
   grid on larger screens. */
.hr-week {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--spacing-3);
}

@media (min-width: 600px) {
    .hr-week {
        grid-template-columns: repeat(2, 1fr);
    }
}

@media (min-width: 1100px) {
    .hr-week {
        grid-template-columns: repeat(5, 1fr);
    }
}

/* A single day's coverage list inside the week grid. */
.hr-day__title {
    font-size: var(--font-size-base);
    font-weight: var(--font-weight-bold);
    margin: 0 0 var(--spacing-2);
    padding-bottom: var(--spacing-1);
    border-bottom: 1px solid var(--border-color);
}

.hr-slot {
    margin-bottom: var(--spacing-2);
}

.hr-slot:last-child {
    margin-bottom: 0;
}

.hr-slot__time {
    font-weight: var(--font-weight-semibold);
}

.hr-slot__notes {
    color: var(--text-secondary);
    font-size: var(--font-size-sm);
}

/* ── Calendar schedule (Tier D) ───────────────────────────────────────────
   A help-room calendar: weekday columns (Mon–Fri) × time rows on desktop, a
   stacked per-day agenda on phones. Adapts the scheduling app's cal-grid
   technique (CSS-grid time×day, grid-row positioning) but Mon–Fri, non-HTMX,
   and mobile-first — the agenda replaces the desktop grid below md instead of
   horizontally scrolling it. Layout + the established calendar color tokens
   only (mirrors .cal-event in scheduling.css). */

/* Mobile-first: the agenda is the default view; the grid is hidden until md. */
.hr-cal {
    display: none;
}

.hr-agenda {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-4);
}

/* Mobile day switcher (built by schedule_day_switcher.js): a segmented Mon–Fri
   control above the agenda. One day's coverage shows at a time, so a densely
   covered day stays scannable without a long scroll. It lives inside .hr-agenda,
   which is hidden at md+, so it's inherently mobile-only. */
.hr-day-switcher {
    display: flex;
    gap: var(--spacing-1);
}

.hr-day-tab {
    flex: 1 1 0;
    min-width: 0;
    padding: var(--spacing-2) var(--spacing-1);
    border: 1px solid var(--border-color);
    border-radius: var(--radius-md);
    background: var(--bg-secondary);
    color: var(--text-secondary);
    font-family: inherit;
    font-size: var(--font-size-sm);
    font-weight: var(--font-weight-semibold);
    cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}

/* Selected day reuses the primary (gold/black) pairing — the same active cue as
   the site nav, and contrast-checked in both themes via the button tokens. */
.hr-day-tab[aria-selected="true"] {
    background: var(--btn-primary-bg);
    color: var(--btn-primary-text);
    border-color: var(--btn-primary-border);
}

.hr-day-tab:focus-visible {
    outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);
    outline-offset: var(--focus-outline-offset);
}

@media (min-width: 768px) {
    .hr-agenda {
        display: none;
    }

    .hr-cal {
        --hr-cal-slot-height: var(--spacing-3);
        display: grid;
        grid-template-columns: auto repeat(5, 1fr);
        border: 1px solid var(--border-color);
        border-radius: var(--radius-lg);
        overflow: hidden;
    }
}

/* Header row: the time-gutter corner + sticky day names. */
.hr-cal__corner,
.hr-cal__day-header {
    grid-row: 1;
    background: var(--bg-secondary);
    padding: var(--spacing-2);
    text-align: center;
    font-weight: var(--font-weight-bold);
    border-bottom: 1px solid var(--border-color);
}

.hr-cal__corner {
    grid-column: 1;
}

/* Hour labels down the gutter. Top-aligned just below their hour line (no
   upward nudge — that pushed the first label into the day-header row); with
   no drawn gridlines this reads the same and matches slot tops exactly. */
.hr-cal__time-label {
    grid-column: 1;
    padding: var(--spacing-1) var(--spacing-2) 0;
    font-size: var(--font-size-xs);
    color: var(--text-secondary);
    text-align: right;
}

/* A day column: its own lane grid spanning the time rows, so overlapping
   coverage lays out side-by-side (lane positions come from the service).
   Inline styles supply the row/lane templates; rows reuse the same
   slot-height var as the outer grid so times stay aligned with the gutter. */
.hr-cal__day {
    display: grid;
    grid-row: 2 / -1;
}

/* A positioned coverage block. grid-row/grid-column come from
   row_start/row_span and lane_start/lane_span. */
.hr-cal__slot {
    margin: var(--border-1) var(--spacing-1);
    padding: var(--spacing-1) var(--spacing-2);
    border-left: var(--border-3) solid var(--color-info-border);
    border-radius: var(--radius-sm);
    background-color: color-mix(in srgb, var(--color-info-border) 10%, var(--color-bg-secondary));
    font-size: var(--font-size-xs);
    line-height: 1.25;
    overflow: hidden;
}

/* Closure / blackout block: danger accent so it reads as "room unavailable". */
.hr-cal__slot--closure {
    border-left-color: var(--color-danger-border);
    background-color: color-mix(in srgb, var(--color-danger-border) 12%, var(--color-bg-secondary));
}

.hr-cal__slot-name {
    font-weight: var(--font-weight-semibold);
}

.hr-cal__slot-time {
    color: var(--text-secondary);
}

.hr-cal__slot-link {
    display: inline-block;
    margin-top: var(--spacing-1);
}

/* ── Block schedule grid (sheet-style) ─────────────────────────────────────
   A period × weekday table with helpers stacked in each cell — the readable
   replacement for the lane grid when many helpers cover one block (mirrors the
   legacy Google Sheet). Desktop table; the .hr-agenda stack takes over below
   md. Course colors cycle a small palette of existing hue tokens, mixed into
   the card background so each chip reads in both themes. */

.hr-block-wrap {
    display: none;
}

@media (min-width: 768px) {
    .hr-block-wrap {
        display: block;
        overflow-x: auto;
    }
}

.hr-block {
    width: 100%;
    border-collapse: collapse;
    table-layout: fixed;
}

.hr-block th,
.hr-block td {
    border: 1px solid var(--border-color);
    vertical-align: top;
    padding: var(--spacing-1);
}

/* Header cells set their own color: the global `th { color: table-header-text }`
   in accessibility.css pairs with table-header-bg, but this grid uses a
   bg-secondary header, so the text must be re-paired or it vanishes in light
   mode. */
.hr-block thead th {
    background: var(--bg-secondary);
    color: var(--text-primary);
    text-align: center;
    padding: var(--spacing-2);
}

.hr-block__time-head {
    width: 9%;
}

.hr-block__period {
    background: var(--bg-secondary);
    white-space: nowrap;
    text-align: center;
    font-size: var(--font-size-xs);
    font-weight: var(--font-weight-semibold);
    color: var(--text-secondary);
}

/* This grid is laid out as a table but isn't a scannable data table, so the
   global zebra striping + full-row hover (set on `tr` in accessibility.css and
   re-applied for dark mode in dark-mode-components.css) fight the course
   colors. Rather than out-specify those theme-specific `tr` rules, give the
   data cells an opaque page-background so any row-level background never shows
   through — then cue the hovered cell instead, identically in both themes. */
.hr-block tbody td {
    background: var(--bg-primary);
}

/* A stacked helper chip inside a cell. The hover cues the individual helper
   session (the chip), not the whole cell/row. */
.hr-chip {
    margin-bottom: var(--spacing-1);
    padding: var(--spacing-1) var(--spacing-2);
    border-left: var(--border-3) solid var(--border-color);
    border-radius: var(--radius-sm);
    background-color: var(--bg-secondary);
    font-size: var(--font-size-xs);
    line-height: 1.3;
    text-align: center;
    overflow-wrap: anywhere;
    transition: transform var(--transition-fast), box-shadow var(--transition-fast);
}

.hr-chip:last-child {
    margin-bottom: 0;
}

/* Lift the hovered session above its dense neighbors so the cue is obvious. */
.hr-chip:hover {
    transform: translateY(-2px) scale(1.02);
    box-shadow: var(--shadow-lg);
    position: relative;
    z-index: 1;
}

.hr-chip__name {
    display: block;
    font-weight: var(--font-weight-semibold);
}

.hr-chip__course {
    color: var(--text-secondary);
}

.hr-chip__time {
    display: block;
    color: var(--text-secondary);
}

.hr-chip__link {
    display: inline-block;
    margin-top: var(--spacing-1);
}

/* Course color — one stable hue per course (ScheduleService.course_hue),
   supplied inline as --course-hue; saturation/lightness come from theme tokens
   so it adapts to light/dark. Both the schedule chip accent and the course
   badge key off the same hue, so a course reads the same color at every
   help-room touchpoint. */
.hr-course-accent {
    border-left-color: hsl(var(--course-hue) var(--course-sat) var(--course-border-l));
    background-color: hsl(var(--course-hue) var(--course-sat) var(--course-tint-l));
}

/* A course pill (helper dashboard, status page, mobile agenda) — sized like
   .status-badge but colored by --course-hue. */
.hr-course-badge {
    display: inline-block;
    padding: var(--spacing-1) var(--spacing-2_5);
    border-radius: var(--radius-md);
    font-size: var(--font-size-sm);
    font-weight: 600;
    color: var(--text-primary);
    background-color: hsl(var(--course-hue) var(--course-sat) var(--course-tint-l));
    border: 1px solid hsl(var(--course-hue) var(--course-sat) var(--course-border-l));
}

/* Closure / blackout: danger accent, "room unavailable". */
.hr-chip--closure {
    border-left-color: var(--color-danger-border);
    background-color: color-mix(in srgb, var(--color-danger-border) 12%, var(--bg-secondary));
}

/* "Upcoming closures" below the grid: the shared .section-card panel (heading +
   compact rows) gives the section a clear boundary and a 3xl heading that leads
   the rows. The rows inside are flat one-liners — NOT item-cards — so there's no
   double-boxing (a card-in-a-card was the earlier mistake). Just needs top
   separation from the grid (.section-card supplies its own bottom margin). */
.hr-upcoming-closures {
    margin-top: var(--spacing-6);
}

/* In light mode .section-card's bg (--card-bg = --bg-elevated = white) matches
   the white page, so only the shadow separates it — no top edge. The subtle
   gray surface token gives a real boundary. In dark mode --bg-secondary is the
   same gray-950 the card already uses, so dark is unchanged. */
.hr-upcoming-closures.section-card {
    background: var(--bg-secondary);
}

/* section-card's default h2 is 3xl — larger than this page's 2xl H1. Bring the
   panel heading down to the help-room section scale so it sits below the page
   title. Two classes out-specify .section-card h2 (no load-order reliance); the
   panel's gold underline stays as the section delimiter. */
.hr-upcoming-closures.section-card h2 {
    font-size: var(--font-size-xl);
    margin-bottom: var(--spacing-4);
}

/* One compact row per closure (date · time — reason), separated by spacing only
   (no dividers). Mobile-first: stacked on two lines; collapses to a single
   inline line at desktop width. The em-dash separator only appears inline (it
   would dangle if the reason wrapped). */
.hr-closures {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: var(--spacing-2);
}

.hr-closure-row {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
}

.hr-closure-row__when {
    color: var(--text-primary);
    white-space: nowrap;
}

.hr-closure-row__reason {
    color: var(--text-secondary);
}

@media (min-width: 768px) {
    .hr-closure-row {
        flex-direction: row;
        align-items: baseline;
        gap: var(--spacing-2);
    }

    .hr-closure-row__reason::before {
        content: "—";
        margin-right: var(--spacing-2);
    }
}

/* Editable chip (manager builder): the read-only chip rendered as a <button>
   that opens the slot editor modal. Reset the native button chrome (borders,
   font) so it still reads as a chip; the lift on hover comes from the base
   .hr-chip:hover rule, and we add the keyboard-focus mirror + outline here. */
.hr-chip--editable {
    display: block;
    width: 100%;
    border-top: 0;
    border-right: 0;
    border-bottom: 0;
    font-family: inherit;
    color: var(--text-primary);
    cursor: pointer;
}

.hr-chip--editable:focus-visible {
    transform: translateY(-2px) scale(1.02);
    box-shadow: var(--shadow-lg);
    position: relative;
    z-index: 1;
    outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);
    outline-offset: var(--focus-outline-offset);
}

/* Editable agenda item (mobile builder): the coverage card rendered as a
   full-width <button> that opens the slot editor. */
.hr-item--editable {
    width: 100%;
    font-family: inherit;
    font-size: inherit;
    text-align: left;
    color: var(--text-primary);
    cursor: pointer;
}

.hr-item--editable:hover,
.hr-item--editable:focus-visible {
    border-color: var(--ucb-gold);
}

.hr-item--editable:focus-visible {
    outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);
    outline-offset: var(--focus-outline-offset);
}

/* Per-cell "+ Add" affordance in the editable grid — subtle until hovered or
   focused so the filled chips stay the visual focus. */
.hr-cell-add {
    display: block;
    width: 100%;
    margin-top: var(--spacing-1);
    padding: var(--spacing-1);
    border: var(--border-1) dashed var(--border-color);
    border-radius: var(--radius-sm);
    background: transparent;
    color: var(--text-secondary);
    font-size: var(--font-size-xs);
    cursor: pointer;
    transition: background-color var(--transition-fast), color var(--transition-fast);
}

.hr-cell-add:hover {
    background-color: var(--bg-secondary);
    color: var(--text-primary);
}

.hr-cell-add:focus-visible {
    outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);
    outline-offset: var(--focus-outline-offset);
}

/* Course legend above the grid — a row of course badges. */
.hr-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-2);
    margin: 0 0 var(--spacing-3);
    padding: 0;
    list-style: none;
}

/* Course-color picker (manager portal): a hue slider + live preview swatch and
   named preset swatches. The hue is unconstrained (0–359), so there's no cap on
   how many courses can have a distinct color. */
.hr-hue-row {
    display: flex;
    align-items: center;
    gap: var(--spacing-3);
}

.hr-hue-slider {
    flex: 1 1 auto;
    min-width: 0;
}

.hr-hue-presets {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-2);
    margin-top: var(--spacing-2);
}

/* A preset swatch is a mini course badge — the same tint fill + accent border
   the real badge uses, so the preview matches in both light and dark mode. */
.hr-hue-swatch {
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    border: 1px solid hsl(var(--course-hue) var(--course-sat) var(--course-border-l));
    border-radius: var(--radius-sm);
    cursor: pointer;
    background-color: hsl(var(--course-hue) var(--course-sat) var(--course-tint-l));
}

/* Public schedule filter bar — one compact wrapping row of dropdowns + actions.
   The field labels are visually hidden (the default option text — "All courses"
   etc. — already names each field), so the controls sit on a single tight line
   instead of a taller label-above-select grid. Selects shrink to their content
   so the row reads as a toolbar, leaving more room for the grid below. */
.hr-filters {
    display: flex;
    flex-wrap: wrap;
    gap: var(--spacing-2);
    align-items: center;
    margin-bottom: var(--spacing-3);
}

.hr-filters .form-group {
    margin-bottom: 0;
}

.hr-filters select {
    width: auto;
}

.hr-filters__actions {
    display: flex;
    gap: var(--spacing-2);
    align-items: center;
}

/* "Add a profile photo" helper nudge (dashboard). Layout only — the alert
 * component supplies the colors. */
.hr-photo-nudge {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: var(--spacing-3);
}

.hr-photo-nudge__text {
    margin: 0;
}

.hr-photo-nudge__actions {
    display: flex;
    align-items: center;
    gap: var(--spacing-2);
}

/* Consolidated attendance cell (helper-activity table): the met/scheduled count
   and reliability %, a slim reliability bar, and any ad-hoc coverage, stacked.
   The bar reuses the hr-bar track/fill so the gold sits in its own track and
   never behind text — contrast holds in both themes (the % lives in the text). */
.hr-attend {
    display: flex;
    flex-direction: column;
    gap: var(--spacing-1);
    align-items: flex-start;
}

.hr-attend__counts {
    font-variant-numeric: tabular-nums;
}

.hr-attend__bar {
    display: block;
    width: 100%;
    max-width: 9rem;
}

/* Sortable column header: a plain text button so the sort is keyboard- and
   screen-reader-operable. The ↕/▲/▼ glyph changes shape (not just color) with
   aria-sort, so sort state isn't conveyed by color alone. */
.hr-sort {
    background: none;
    border: 0;
    padding: 0;
    margin: 0;
    font: inherit;
    font-weight: var(--font-weight-bold);
    color: inherit;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: var(--spacing-1);
}

.hr-sort::after {
    content: "↕";
    color: var(--text-secondary);
    font-size: var(--font-size-sm);
}

th[aria-sort="ascending"] .hr-sort::after {
    content: "▲";
    color: var(--text-primary);
}

th[aria-sort="descending"] .hr-sort::after {
    content: "▼";
    color: var(--text-primary);
}

.hr-sort:focus-visible {
    outline: var(--focus-outline-width) var(--focus-outline-style) var(--focus-outline-color);
    outline-offset: var(--focus-outline-offset);
}
