/*
 * components.css — every reusable component class, one file, loaded by BOTH
 * layouts (public + app). HIGH BLAST RADIUS: a selector here can restyle any
 * page — after editing, re-check every page that uses the section you touched.
 *
 * Find the section first (banner comments, in file order):
 *   Focus · Cards · Feature cards (landing) · Sleepiness rating buttons ·
 *   Sleepiness dot · Form elements · Stepper · Toggle row · OAuth · Quiz ·
 *   Flash · Disclaimer · Navigation (sidebar + bottom nav + content offset) ·
 *   ESS assessment · Entry overlay · Expandable entry · Trends (range/scale/
 *   view controls, legends, captions, onboarding overlay, tooltip) ·
 *   Responsive breakpoint (769px sidebar swap) · Block selector · Today's
 *   block cards · Fieldsets · First-entry
 *   card · Focused-flow hero (welcome/onboarding) · Onboarding progress ·
 *   Insights · Journal view switch · Journal calendar · Clinician report
 *   (screen + print) · Report actogram (screen + print)
 *
 * House rules:
 *   - Color, radius, shadow values flow from theme.css tokens. Deliberate
 *     exceptions: rgba() blacks for shadows/dim overlays, and the trends
 *     legend swatches, which mirror BLOCK_COLORS hard-coded in trends.js
 *     (chart colors are settled — see docs/design/TRENDS.md).
 *   - Spacing rhythm (padding / margin / gap at ≥0.25rem) flows through the
 *     --space-* tokens in theme.css (ADR 0009), numbered to match Tailwind's
 *     steps — "6" is 1.5rem here and in an `mb-6` template utility alike.
 *     Deliberately literal: micro-optical values <0.25rem and any shorthand
 *     containing one (icon kerning, badge padding — optics, not rhythm),
 *     the calendar day-grid's 3–6px metrics (density-critical optical
 *     tuning), and fixed chrome offsets (80px bottom-nav clearance, 220px
 *     sidebar width, which pair with real element sizes, not the scale).
 *   - A comment on a rule states the WHY when the value isn't self-evident
 *     (contrast floors, z-index layering, uPlot quirks).
 */

/* ─── Focus ─────────────────────────────────────────── */
/* Visible keyboard focus ring for all interactive elements. `:where()` keeps
   specificity at 0 so per-component focus styles (e.g. `.form-input:focus`,
   which uses an inset glow) still win. Only triggers on keyboard focus, so
   mouse clicks don't draw rings. */
:where(button, a, [role="button"], summary, input, select, textarea):focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
    border-radius: 4px;
}

/* ─── Cards ─────────────────────────────────────────── */
.card {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    padding: var(--space-6);
    box-shadow: var(--shadow-sm);
}
.card-sm {
    background: var(--color-surface);
    border-radius: var(--radius-md);
    padding: var(--space-4) var(--space-5);
    box-shadow: var(--shadow-sm);
    display: block;
    text-decoration: none;
    color: inherit;
}

/* ─── Feature Cards (landing) ──────────────────────── */
.feature-card {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    padding: var(--space-8) var(--space-6);
    box-shadow: var(--shadow-sm);
    text-align: center;
    transition: transform 0.2s, box-shadow 0.2s;
}
.feature-card:hover {
    transform: translateY(-2px);
    box-shadow: var(--shadow-md);
}
.feature-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: var(--color-bg);
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto var(--space-4);
}

/* ─── Sleepiness Rating Buttons ────────────────────── */
.sleepiness-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    cursor: pointer;
    padding: var(--space-3) var(--space-2);
    border-radius: var(--radius-md);
    border: 2px solid var(--color-border);
    transition: all 0.2s;
    text-align: center;
}
.sleepiness-btn:has(input:checked) {
    border-color: var(--btn-color, var(--color-primary));
    background: color-mix(in srgb, var(--btn-color, var(--color-primary)) 10%, transparent);
}
.sleepiness-num {
    width: 40px;
    height: 40px;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 700;
    font-size: 1.25rem;
    /* Scale ink, not white: white digits fail AA on the green/amber/orange
       fills (worst was 1.6:1 on amber). --color-scale-ink clears 4.5:1 on
       all four — see theme.css. */
    color: var(--color-scale-ink);
    background: var(--btn-color, var(--color-primary));
}

/* ─── Sleepiness Dot ───────────────────────────────── */
/* Numbered circle so the score (1-4) is readable independent of color —
   colorblind users get the digit; everyone else gets both signals. */
.sleepiness-dot {
    width: 18px;
    height: 18px;
    border-radius: 50%;
    flex-shrink: 0;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 11px;
    font-weight: 700;
    /* Scale ink (see theme.css): --color-text only reaches 3.7:1 on the
       level-4 red fill; the shared ink token clears AA on all four. */
    color: var(--color-scale-ink);
    line-height: 1;
}

/* ─── Form Elements ────────────────────────────────── */
.form-select {
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    font-size: 1rem;
    color: var(--color-text);
    appearance: auto;
}
.form-textarea {
    width: 100%;
    padding: var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    font-size: 1rem;
    color: var(--color-text);
    resize: vertical;
    font-family: inherit;
}
.form-textarea:focus,
.form-select:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 20%, transparent);
}
.form-input {
    width: 100%;
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    font-size: 1rem;
    color: var(--color-text);
}
.form-input:focus {
    outline: none;
    border-color: var(--color-primary);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-primary) 20%, transparent);
}
/* Validation error state — applied by JS when a duration field is out of range. */
.form-input-error {
    border-color: var(--color-error);
    background: var(--color-error-bg);
}
.form-input-error:focus {
    border-color: var(--color-error);
    box-shadow: 0 0 0 3px color-mix(in srgb, var(--color-error) 25%, transparent);
}

/* ─── Stepper ──────────────────────────────────────── */
.stepper-btn {
    width: 36px;
    height: 36px;
    border-radius: 50%;
    border: 2px solid var(--color-border);
    background: var(--color-surface);
    font-size: 1.25rem;
    font-weight: bold;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.15s;
    color: var(--color-text);
}
.stepper-btn:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
}

/* ─── Toggle Row ───────────────────────────────────── */
.toggle-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    cursor: pointer;
    padding: var(--space-2) 0;
}
.toggle-input {
    width: 44px;
    height: 24px;
    accent-color: var(--color-primary);
}

/* ─── OAuth Buttons ────────────────────────────────── */
.oauth-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-3);
    width: 100%;
    padding: var(--space-3-5);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    background: var(--color-surface);
    font-weight: 500;
    font-size: 1rem;
    color: var(--color-text);
    text-decoration: none;
    transition: all 0.2s;
}
.oauth-btn:hover {
    box-shadow: var(--shadow-md);
    border-color: var(--color-primary);
}

/* ─── Quiz ─────────────────────────────────────────── */
.quiz-question {
    display: none;
}
.quiz-question.active {
    display: block;
}
.quiz-option {
    display: block;
    cursor: pointer;
}
.quiz-option-label {
    display: block;
    padding: var(--space-4) var(--space-5);
    border: 2px solid var(--color-border);
    border-radius: var(--radius-md);
    transition: all 0.2s;
    font-weight: 500;
}
.quiz-option:has(input:checked) .quiz-option-label {
    border-color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 8%, transparent);
    color: var(--color-primary);
}
.quiz-option:hover .quiz-option-label {
    border-color: var(--color-primary);
}

/* ─── Flash Message ────────────────────────────────── */
.flash-msg {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-3) var(--space-4);
    margin: var(--space-3) var(--space-4);
    border-radius: var(--radius-md);
    background: color-mix(in srgb, var(--color-secondary) 15%, var(--color-surface));
    color: var(--color-text);
    font-size: 0.9rem;
}

/* ─── Disclaimer ───────────────────────────────────── */
.disclaimer {
    padding: var(--space-4);
    border-radius: var(--radius-sm);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
}

/* ─── Navigation ───────────────────────────────────── */

/* Sidebar — desktop only */
.sidebar {
    display: none;
    position: fixed;
    left: 0;
    top: 0;
    bottom: 0;
    width: 220px;
    background: var(--color-surface);
    border-right: 1px solid var(--color-border);
    flex-direction: column;
    padding: var(--space-6) 0;
    z-index: 40;
}
.sidebar-logo {
    padding: 0 var(--space-5);
    margin-bottom: var(--space-8);
}
.sidebar-links {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
.sidebar-link {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-2-5) var(--space-5);
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: 0.95rem;
    transition: all 0.15s;
}
.sidebar-link:hover {
    color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 5%, transparent);
}
.sidebar-link.active {
    color: var(--color-primary);
    font-weight: 600;
    background: color-mix(in srgb, var(--color-primary) 8%, transparent);
}
.sidebar-bottom {
    border-top: 1px solid var(--color-border);
    padding-top: var(--space-3);
    display: flex;
    flex-direction: column;
    gap: var(--space-1);
}
/* Sign Out is a POST form (logout must not be a state-changing GET, REM-35);
   strip UA button chrome so the submit button renders like the sibling links. */
.logout-form { margin: 0; }
.logout-form button {
    width: 100%;
    background: none;
    border: none;
    cursor: pointer;
    font: inherit;
    text-align: left;
    padding: 0;
}
.logout-form button.sidebar-link { padding: var(--space-2-5) var(--space-5); }

/* Bottom nav — mobile only */
.bottom-nav {
    display: flex;
    position: fixed;
    bottom: 0;
    left: 0;
    right: 0;
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    padding: var(--space-2) 0 calc(var(--space-2) + env(safe-area-inset-bottom));
    z-index: 40;
}
.bottom-nav-item {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.2rem;
    padding: var(--space-1-5) 0;
    color: var(--color-text-muted);
    text-decoration: none;
    font-size: 0.65rem;
    transition: color 0.15s;
}
.bottom-nav-item.active {
    color: var(--color-primary);
    font-weight: 600;
}

/* App content offset */
.app-content {
    position: relative; /* anchors .header-gear */
    padding-bottom: 80px; /* bottom nav */
}

/* Settings gear (REM-49) — Settings' home after leaving the bottom nav.
   Mobile-only: desktop's sidebar has a Settings link. Absolute (not fixed)
   so it sits beside the page title and scrolls away with it. 44px square
   for the touch-target floor. */
.header-gear {
    position: absolute;
    top: var(--space-3);
    right: var(--space-2);
    z-index: 30;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    color: var(--color-text-muted);
}
.header-gear.active {
    color: var(--color-primary);
}
@media (min-width: 769px) {
    .header-gear {
        display: none;
    }
}

/* ─── ESS Assessment in Journal ─────────────────────── */
.ess-question {
    padding: var(--space-3);
    background: var(--color-bg);
    border-radius: var(--radius-md);
}
.ess-option {
    display: block;
    cursor: pointer;
}
.ess-option-label {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: var(--space-2) var(--space-1);
    border: 2px solid var(--color-border);
    border-radius: var(--radius-sm);
    transition: all 0.2s;
    text-align: center;
    min-height: 52px;
    justify-content: center;
}
.ess-option:has(input:checked) .ess-option-label {
    border-color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
}
.ess-option:hover .ess-option-label {
    border-color: var(--color-primary);
}

/* ─── Entry Overlay ────────────────────────────────── */
.entry-overlay {
    position: fixed;
    inset: 0;
    z-index: 100;
    background: rgba(0, 0, 0, 0.4);
    backdrop-filter: blur(4px);
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
}
.entry-overlay.hidden {
    display: none;
}
.entry-overlay-content {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    padding: var(--space-10) var(--space-8);
    max-width: 360px;
    width: 100%;
    text-align: center;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.2);
}

/* ─── Expandable Entry ─────────────────────────────── */
.entry-expandable {
    transition: box-shadow 0.2s;
}
.entry-expandable:hover {
    box-shadow: var(--shadow-md);
}

/* ─── Trends ───────────────────────────────────────── */
.trend-range-selector {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
}
.trend-range-btn {
    padding: var(--space-2) var(--space-3-5);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    background: var(--color-surface);
    color: var(--color-text-muted);
    font-size: 0.9rem;
    font-weight: 500;
    text-decoration: none;
    transition: all 0.15s;
}
.trend-range-btn:hover {
    border-color: var(--color-primary);
    color: var(--color-primary);
}
.trend-range-btn.active {
    background: var(--color-primary);
    border-color: var(--color-primary);
    color: var(--color-surface);
}
.trend-scale-toggle {
    display: inline-flex;
    gap: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-sm);
    overflow: hidden;
    background: var(--color-surface);
}
.trend-scale-btn {
    padding: var(--space-1-5) var(--space-3-5);
    background: transparent;
    border: 0;
    color: var(--color-text-muted);
    font-size: 0.85rem;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.15s;
}
.trend-scale-btn + .trend-scale-btn {
    border-left: 1px solid var(--color-border);
}
.trend-scale-btn.active {
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
    color: var(--color-primary);
}
/* Top-level Trends view switcher (Over time | Patterns). A larger, more
   prominent take on the .trend-scale-toggle segmented idiom — two equal-width
   segments, so it stays clean and unbreakable across viewport sizes. */
/* Full-width sticky bar holding the view switcher. Body is the scroll container
   (sidebar/bottom-nav are fixed; .app-content has no overflow), so top:0 pins to
   the viewport. As a direct child of .app-content it spans the content area
   (stopping at the desktop sidebar). Page-grey background so the white pill reads
   as one unit against it; padding gives the breathing gap above the pill when
   pinned without letting content peek (the bar is opaque to top:0). z-index sits
   above the charts but below the chart tooltip (50) and the nav (40). */
.trend-view-bar {
    position: sticky;
    top: 0;
    z-index: 30;
    background: var(--color-bg);
    padding: var(--space-3) 0;
}
/* Shadow only once pinned (trends-tabs.js toggles is-stuck via a sentinel), so
   there's no stray divider at rest but a clear header edge while scrolling. */
.trend-view-bar.is-stuck {
    box-shadow: var(--shadow-sm);
}
.trend-view-switch {
    display: flex;
    gap: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
    background: var(--color-surface);
    box-shadow: var(--shadow-sm);
}
.trend-view-btn {
    flex: 1 1 0;
    padding: var(--space-2-5) var(--space-4);
    background: transparent;
    border: 0;
    color: var(--color-text-muted);
    font-size: 0.95rem;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.15s;
}
.trend-view-btn + .trend-view-btn {
    border-left: 1px solid var(--color-border);
}
.trend-view-btn.active {
    background: var(--color-primary);
    color: var(--color-surface);
}
.trend-chart {
    width: 100%;
    min-height: 140px;
}
.trend-chart-card h3 {
    color: var(--color-text);
}
/* Caption under the Patterns panel clarifying its charts span all history. */
.trend-section-sub {
    font-size: 0.8rem;
    color: var(--color-text-muted);
    margin: 0 0 var(--space-4);
}
/* Caption for the rolling-average trendline. Sits below the chart canvas;
 * intentionally muted so it reads as a footnote, not a header. */
.trend-caption {
    margin-top: var(--space-1-5);
    font-size: 0.75rem;
    color: var(--color-text-muted);
}

/* Inline legend for the by-time-of-day chart. Three small swatches sitting
 * to the right of the chart's heading. Colors are duplicated in trends.js
 * (BLOCK_COLORS) so the chart series and the legend stay in sync. */
.trend-block-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3-5);
    font-size: 0.75rem;
    color: var(--color-text-muted);
}
/* Legend items are interactive toggles (focus a single time-of-day block).
 * Reset the native button chrome, then layer in hover / focus / selected
 * affordances so selection is conveyed by more than color alone (the
 * pill background + aria-pressed both change). */
.trend-block-legend-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1-5);
    font: inherit;
    color: inherit;
    background: transparent;
    border: 1px solid transparent;
    border-radius: 999px;
    padding: 0.2rem 0.55rem;
    cursor: pointer;
    transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.trend-block-legend-item:hover {
    background: var(--color-surface-alt, rgba(0, 0, 0, 0.04));
}
.trend-block-legend-item:focus-visible {
    outline: 2px solid var(--color-primary);
    outline-offset: 2px;
}
.trend-block-legend-item.is-selected {
    background: var(--color-surface-alt, rgba(0, 0, 0, 0.06));
    border-color: var(--color-border, rgba(0, 0, 0, 0.12));
    color: var(--color-text);
    font-weight: 600;
}
.trend-block-swatch {
    width: 0.7rem;
    height: 0.7rem;
    border-radius: 2px;
    display: inline-block;
}
.trend-block-swatch--morning   { background: #6FA3C4; }
.trend-block-swatch--afternoon { background: #D4915C; }
.trend-block-swatch--evening   { background: #5C5A8A; }

/* Day-of-week sleepiness legend. Same pill/swatch chrome as the time-of-day
 * legend (items reuse .trend-block-legend-item / .trend-block-swatch), but the
 * toggles are MULTI-SELECT (show/hide each block additively) rather than
 * single-focus — so an unselected item fades its swatch to signal "hidden",
 * conveying state by more than the pill background alone. */
.trend-dow-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-3-5);
    font-size: 0.75rem;
    color: var(--color-text-muted);
}
.trend-dow-legend .trend-block-legend-item:not(.is-selected) .trend-block-swatch {
    opacity: 0.3;
}

/* Single-line clamp with custom " [...]" suffix. Pair with the JS in
 * static/js/app.js (`.note-clamp`) which measures overflow and rewrites
 * the text. CSS sets up the box: nowrap + hidden so scrollWidth >
 * clientWidth fires when the note is too long. */
.note-clamp {
    display: block;
    overflow: hidden;
    white-space: nowrap;
    min-width: 0;
}

/* Onboarding (no entries anywhere): grey out preview charts, float CTA on top */
.trends-charts-wrap {
    position: relative;
}
.trends-charts-wrap.trends-onboarding > .trend-chart-card {
    filter: grayscale(1);
    opacity: 0.55;
    pointer-events: none;
    user-select: none;
}
.trends-onboarding-overlay {
    position: absolute;
    inset: 0;
    z-index: 5;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding: var(--space-8) var(--space-4);
    pointer-events: none;
}
.trends-onboarding-card {
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-lg);
    padding: var(--space-7) var(--space-6);
    max-width: 380px;
    width: 100%;
    text-align: center;
    box-shadow: var(--shadow-md);
    pointer-events: auto;
    position: sticky;
    top: 1rem;
}
.trends-onboarding-icon {
    width: 56px;
    height: 56px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
    color: var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto var(--space-3-5);
}
.trends-onboarding-cta {
    display: inline-block;
    padding: var(--space-2-5) var(--space-5);
    border-radius: var(--radius-md);
    background: var(--color-primary);
    color: var(--color-surface);
    font-weight: 600;
    font-size: 0.95rem;
    text-decoration: none;
    transition: transform 0.15s, box-shadow 0.15s;
}
.trends-onboarding-cta:hover {
    transform: translateY(-1px);
    box-shadow: var(--shadow-md);
}

/* Hover tooltip for trend charts */
.trend-tooltip {
    position: absolute;
    z-index: 50;
    min-width: 220px;
    max-width: 300px;
    padding: var(--space-3) var(--space-3-5);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    box-shadow: var(--shadow-md);
    font-size: 0.85rem;
    line-height: 1.35;
    color: var(--color-text);
    pointer-events: none;
    opacity: 0;
    transform: translateY(4px);
    transition: opacity 0.12s, transform 0.12s;
}
.trend-tooltip.visible {
    opacity: 1;
    transform: translateY(0);
}
.trend-tooltip-date {
    font-weight: 600;
    margin-bottom: var(--space-2);
    padding-bottom: var(--space-1-5);
    border-bottom: 1px solid var(--color-border);
    color: var(--color-primary);
}
.trend-tooltip-rows {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: 0.15rem 0.75rem;
}
.trend-tooltip-row {
    display: contents;
}
.trend-tooltip-label {
    color: var(--color-text-muted);
}
.trend-tooltip-val {
    font-weight: 500;
    text-align: right;
}
/* Focused metric — the row corresponding to the chart being hovered.
   `.trend-tooltip-row` itself uses display: contents, so the highlight has to
   live on its label/val children directly. */
.trend-tooltip-label--focused,
.trend-tooltip-val--focused {
    color: var(--color-primary);
    font-weight: 700;
    font-size: 0.95rem;
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
    padding: 0.05rem 0.35rem;
    border-radius: var(--radius-sm);
}
.trend-tooltip-notes {
    margin-top: var(--space-2);
    padding-top: var(--space-2);
    border-top: 1px solid var(--color-border);
    color: var(--color-text-muted);
    font-size: 0.8rem;
    font-style: italic;
    max-height: 6.5em;
    overflow: hidden;
}

/* ─── Responsive ───────────────────────────────────── */
@media (min-width: 769px) {
    .sidebar {
        display: flex;
    }
    .bottom-nav {
        display: none;
    }
    .app-content {
        margin-left: 220px;
        padding-bottom: 0;
    }
}

/* ─── Time-of-day block selector ───────────────────── */
/* Three chips above the entry form: morning / afternoon / evening. The
   default selection is set by journal.js based on the device clock and can
   be overridden by the user (e.g. logging at 9pm about how they felt that
   morning). The active chip uses the same color-mix pattern as
   .sleepiness-btn so the selection feels consistent. */
.block-btn {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    cursor: pointer;
    padding: var(--space-2-5) var(--space-2);
    border-radius: var(--radius-md);
    border: 2px solid var(--color-border);
    transition: all 0.2s;
    text-align: center;
    line-height: 1.15;
}
.block-btn-active,
.block-btn:has(input:checked) {
    border-color: var(--color-primary);
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
}
.block-btn-icon {
    display: block;
    font-size: 1.35rem;
    line-height: 1;
    color: var(--color-text-muted);
    margin-bottom: 0.2rem;
}
.block-btn:has(input:checked) .block-btn-icon { color: var(--color-primary); }
.block-btn-label {
    display: block;
    font-weight: 600;
    font-size: 0.95rem;
}
/* Time-of-day glyph beside a today-card label. */
.block-card-icon {
    display: inline-flex;
    vertical-align: -0.15em;
    font-size: 1.05rem;
    color: var(--color-text-muted);
}
.block-btn-hint {
    display: block;
    font-size: 0.7rem;
    color: var(--color-text-muted);
    margin-top: 0.15rem;
}

/* ─── Today's block cards ──────────────────────────── */
/* Three cards on the Journal page (one per block) showing fill status. An
   empty card becomes a "Tap to log" prompt that scrolls to the form and
   pre-fills the block selector. A filled card shows the latest entry's
   sleepiness summary; tapping expands all entries in that block. */
.block-card {
    transition: box-shadow 0.2s;
}
.block-card-header {
    /* Rendered as a <button> for keyboard access. Strip the browser's button
       chrome so it visually matches the surrounding card content. */
    user-select: none;
    display: block;
    width: 100%;
    text-align: left;
    background: transparent;
    border: 0;
    padding: 0;
    color: inherit;
    font: inherit;
    cursor: pointer;
}
.block-card-empty {
    background: transparent;
    border: 0;
    padding: 0;
    cursor: pointer;
    width: 100%;
}
/* Expand/collapse cue on filled block cards. toggleBlockCard() flips
   aria-expanded on the header button; sighted users previously got NO
   affordance at all — the chevron is that affordance, and it rotates so
   open/closed state isn't conveyed by position alone. */
.block-card-chevron {
    flex-shrink: 0;
    display: inline-flex;
    color: var(--color-text-muted);
    transition: transform 0.2s ease;
}
.block-card-header[aria-expanded="true"] .block-card-chevron {
    transform: rotate(180deg);
}
.sleepiness-dot-empty {
    background: var(--color-border);
    opacity: 0.6;
    color: transparent; /* hide digit slot when there's no entry */
}

/* Block-conditional form sections — JS toggles `.hidden` on these as the
   block selector changes. The `.hidden` utility from Tailwind sets
   `display: none`, which is what we want. No styles needed here beyond
   making the selector visible for documentation. */

/* (The segmented mode/scale toggle CSS that lived here was removed with
   REM-46 — entry detail and sleepiness scale are Settings preferences now,
   rendered as plain radios on the settings page.) */

/* Scale sections wrap their inputs as <fieldset>; reset default UA styling
   so the existing form widgets inside don't gain a border. */
.scale-section {
    border: 0;
    padding: 0;
    margin: 0;
}

/* Generic borderless fieldset for form-control groups (e.g. hours+minutes
   pairs, radiogroups). Pairs with `.form-legend` which inherits the same
   typography as the prior `<label class="block font-semibold mb-2">` so
   visual rhythm is unchanged after the markup swap. */
.form-fieldset {
    border: 0;
    padding: 0;
    margin: 0;
    min-width: 0; /* let flex/grid children shrink inside fieldset */
}
.form-legend {
    display: block;
    font-weight: 600;
    margin-bottom: var(--space-2);
    padding: 0;
}

/* First-entry empty-state card on the journal page. Subtle background tint
   to differentiate from the form card below it. */
.first-entry-card {
    background: linear-gradient(135deg, var(--color-bg) 0%, var(--color-surface) 100%);
    border: 1px solid var(--color-border);
}

/* ─── Focused-flow hero (welcome, onboarding) ───────── */
/* Soft tinted circle holding a single glyph. The quiet, non-clinical way we
   open a full-screen moment — same recipe as .trends-onboarding-icon
   (primary at 10% over transparent) so empty/first-run states feel related
   across the app. */
.hero-glyph {
    width: 64px;
    height: 64px;
    border-radius: 50%;
    background: color-mix(in srgb, var(--color-primary) 10%, transparent);
    color: var(--color-primary);
    display: flex;
    align-items: center;
    justify-content: center;
    margin: 0 auto var(--space-5);
}

/* Onboarding explainer cards: a small leading glyph beside each option's
   text keeps the three cards scannable without reading every line. */
.onboard-option {
    display: flex;
    align-items: flex-start;
    gap: var(--space-3-5);
}
.onboard-option-icon {
    flex-shrink: 0;
    display: inline-flex;
    color: var(--color-primary);
    opacity: 0.85;
    margin-top: 0.15rem;
}

/* Onboarding step indicator. Two pills that fill in as the user progresses
   from step 1 → step 2. */
.onboarding-progress {
    display: flex;
    gap: var(--space-2);
    margin-bottom: var(--space-6);
}
.onboarding-progress-step {
    flex: 1;
    height: 4px;
    border-radius: 999px;
    background: var(--color-border);
    transition: background 0.25s;
}
.onboarding-progress-step.active {
    background: var(--color-primary);
}
.onboarding-progress-label {
    font-size: 0.75rem;
    color: var(--color-text-muted);
    margin-bottom: var(--space-2);
    font-weight: 600;
    letter-spacing: 0.05em;
    text-transform: uppercase;
}

/* ─── Insights (correlation cards) ─────────────────── */
.insight-list {
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
}
.insight-card {
    padding: var(--space-5) var(--space-6);
}
.insight-card-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-3);
    margin-bottom: var(--space-1-5);
}
.insight-factor {
    font-size: 1.05rem;
    font-weight: 600;
}
.insight-strength {
    font-size: 0.7rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    color: var(--color-text-muted);
    background: var(--color-bg);
}
.insight-strength--strong { color: var(--color-primary); background: color-mix(in srgb, var(--color-primary) 12%, transparent); }
.insight-strength--moderate { color: var(--color-text-muted); }
.insight-sentence {
    font-size: 0.95rem;
    line-height: 1.45;
    margin-bottom: var(--space-3-5);
}
/* Strength meter. The fill hue carries the direction (favorable vs not) but is
   never the only cue — the sentence states it and the badge labels strength. */
.insight-meter {
    height: 7px;
    border-radius: 999px;
    background: var(--color-border);
    overflow: hidden;
}
.insight-meter-fill {
    height: 100%;
    border-radius: 999px;
    background: var(--color-accent);
    transition: width 0.3s ease;
}
.insight-card[data-direction="lower"] .insight-meter-fill { background: var(--color-secondary); }
.insight-card-foot {
    display: flex;
    align-items: center;
    gap: var(--space-3);
    margin-top: var(--space-3);
    font-size: 0.75rem;
    color: var(--color-text-muted);
}
.insight-tag {
    font-weight: 600;
    text-transform: capitalize;
}
.insight-spark {
    display: inline-flex;
    margin-left: auto;
    color: var(--color-text-muted);
    opacity: 0.7;
}
.insight-card[data-direction="lower"] .insight-spark { color: var(--color-secondary); opacity: 0.85; }
.insight-card[data-direction="higher"] .insight-spark { color: var(--color-accent); opacity: 0.85; }
.insight-n { white-space: nowrap; }

.insight-baseline { text-align: center; padding: 2.5rem 1.5rem; }
.insight-baseline-icon { color: var(--color-primary); display: flex; justify-content: center; margin-bottom: 0.75rem; }
.insight-baseline-cta {
    display: inline-block;
    background: var(--color-primary);
    color: var(--color-surface);
    padding: var(--space-2-5) var(--space-5);
    border-radius: var(--radius-md);
    font-weight: 600;
    text-decoration: none;
}

/* ─── Journal list/calendar view switch ──────────────── */
/* Two anchor links (NOT the trends tablist — different semantics/JS). */
.view-switch {
    display: inline-flex;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
    overflow: hidden;
}
.view-switch-btn {
    padding: var(--space-1-5) var(--space-5);
    font-size: 0.9rem;
    font-weight: 500;
    color: var(--color-text-muted);
    text-decoration: none;
    transition: background 0.15s, color 0.15s;
}
.view-switch-btn + .view-switch-btn { border-left: 1px solid var(--color-border); }
.view-switch-btn:hover { color: var(--color-text); }
.view-switch-btn.is-active {
    background: color-mix(in srgb, var(--color-primary) 12%, transparent);
    color: var(--color-primary);
    font-weight: 600;
}

/* ─── Journal calendar (month grid) ──────────────────── */
/* Month stepper — a self-contained bordered control so it reads as a distinct
   selector against the page background, matching the card idiom used elsewhere. */
.cal-header {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--space-1);
    width: fit-content;
    margin: 0 auto var(--space-4);
    padding: var(--space-1) var(--space-1-5);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-md);
}
.cal-title { font-size: 1.05rem; font-weight: 600; min-width: 8.5rem; text-align: center; }
.cal-nav {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    font-size: 1.4rem;
    line-height: 1;
    border-radius: var(--radius-sm);
    color: var(--color-primary);
    text-decoration: none;
}
.cal-nav:hover { background: color-mix(in srgb, var(--color-primary) 10%, transparent); }
.cal-nav-disabled { color: var(--color-border); }
.cal-nav-disabled:hover { background: none; }

.cal-legend {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-1-5) var(--space-4);
    margin-bottom: var(--space-3-5);
    font-size: 0.8rem;
    color: var(--color-text-muted);
}
.cal-legend-item { display: inline-flex; align-items: center; gap: 0.35rem; }
.cal-legend-sw { width: 0.85rem; height: 0.85rem; border-radius: 4px; display: inline-block; }
.cal-legend-sw-empty { border: 1px dashed var(--color-border); background: transparent; }
.cal-legend-order { gap: 0.2rem; }
.cal-legend-order .block-icon { font-size: 0.95rem; }

.cal-dow, .cal-grid {
    display: grid;
    grid-template-columns: repeat(7, 1fr);
    gap: 6px;
}
.cal-dow { margin-bottom: 6px; }
.cal-dow span { text-align: center; font-size: 0.72rem; font-weight: 600; color: var(--color-text-muted); }

.cal-cell {
    display: flex;
    flex-direction: column;
    gap: 3px;
    min-height: 84px;
    padding: 4px;
    border: 1px solid var(--color-border);
    border-radius: 10px;
    background: var(--color-surface);
    text-decoration: none;
    color: inherit;
    transition: box-shadow 0.15s, border-color 0.15s;
}
a.cal-cell:hover { box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08); border-color: var(--color-primary); }
.cal-cell-pad { border: none; background: transparent; min-height: 0; }
.cal-cell-future { opacity: 0.55; }
.cal-cell-today { border-color: var(--color-primary); box-shadow: 0 0 0 1px var(--color-primary); }

.cal-day { font-size: 0.72rem; font-weight: 600; color: var(--color-text-muted); padding: 0 2px 1px; }
.cal-cell-today .cal-day { color: var(--color-primary); }

.cal-band {
    display: flex;
    align-items: center;
    justify-content: space-between;
    height: 18px;
    padding: 0 5px;
    border-radius: 4px;
    color: var(--color-text);
    font-size: 0.72rem;
}
.cal-band-icon { display: inline-flex; font-size: 0.8rem; opacity: 0.85; }
.cal-band-num { font-weight: 600; }
.cal-band-empty { background: transparent; border: 1px dashed var(--color-border); }

@media (max-width: 400px) {
    .cal-band-icon { display: none; }
    .cal-cell { min-height: 72px; }
}

/* ─── Clinician report (REM-38) ─────────────────────── */
/* One template serves screen and print. On screen the table lives in a card
   and scrolls horizontally at narrow widths; in print the app chrome is
   stripped and everything goes black-on-white — a clinician's photocopy must
   not depend on color. */
/* The mobile header gear (44px, absolute top-right) overlaps this page's
   top-right Print button — shift the actions row clear of it. */
@media (max-width: 768px) {
    .report-actions { margin-right: 52px; }
}
.report-table-wrap {
    background: var(--color-surface);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-sm);
    overflow-x: auto;
}
.report-table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.8rem;
}
.report-table th {
    text-align: left;
    font-weight: 600;
    color: var(--color-text-muted);
    text-transform: uppercase;
    letter-spacing: 0.02em;
    font-size: 0.68rem;
    padding: var(--space-3) var(--space-2);
    border-bottom: 2px solid var(--color-border);
    white-space: nowrap;
}
.report-table td {
    padding: var(--space-2);
    border-bottom: 1px solid var(--color-border);
    vertical-align: top;
}
.report-table tr:last-child td { border-bottom: none; }
.report-table th:first-child,
.report-table td:first-child { padding-left: var(--space-4); }
.report-table th:last-child,
.report-table td:last-child { padding-right: var(--space-4); }
.report-date { white-space: nowrap; font-weight: 500; }
.report-dash { color: var(--color-text-muted); }
/* "Not rated" marker in the sleepiness cells — a quiet dot, distinct from the
   text columns' em-dash so an unrated triplet can't read as data. */
.report-nodata { color: var(--color-text-muted); font-weight: 700; }
.report-row-empty td { color: var(--color-text-muted); }
.report-empty-cell { font-style: italic; }
.report-rating { text-align: center; }
/* Digit + muted calendar fill, same pairing as the calendar bands: the number
   is always present, so the color never carries meaning alone. */
.report-chip {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 22px;
    height: 22px;
    padding: 0 4px;
    border-radius: 6px;
    font-weight: 600;
    color: var(--color-text);
}
.report-text-cell { min-width: 10rem; }
.report-text-cell > div + div { margin-top: var(--space-1); }
.report-time { color: var(--color-text-muted); font-size: 0.7rem; }

@media print {
    /* Strip the app chrome; the report header carries the context. */
    .sidebar, .bottom-nav, .header-gear, .flash-msg, .report-actions {
        display: none !important;
    }
    .app-content { margin-left: 0 !important; padding-bottom: 0 !important; }
    body { background: #fff !important; color: #000 !important; }
    .report-page { max-width: none; padding: 0; }
    .report-table-wrap { box-shadow: none; border-radius: 0; overflow: visible; }
    .report-table { font-size: 9pt; }
    .report-table th { color: #000; border-bottom-color: #000; }
    .report-table td { border-bottom-color: #999; }
    .report-table tr { break-inside: avoid; page-break-inside: avoid; /* Safari still needs the legacy alias */ }
    /* Fills don't survive photocopies; the digit does. */
    .report-chip { background: none !important; border: 1px solid #000; color: #000; }
    .report-header h1, .report-header p, .report-legend, .disclaimer p { color: #000 !important; }
}

/* ─── Report actogram (REM-58) ──────────────────────── */
/* Sleep-schedule strip below the report grid: server-rendered inline SVG (no
   JS), geometry from service/actogram.go. Colors are class-driven so the print
   block below can swap the whole thing to black-on-white; nothing depends on
   color to carry meaning (bars read by position, weekends by shading AND bold
   dates). */
.report-actogram { margin-top: var(--space-6); break-inside: avoid; page-break-inside: avoid; }
.report-actogram-title {
    font-size: 0.95rem;
    font-weight: 600;
    color: var(--color-text);
    margin-bottom: var(--space-2);
}
.actogram-svg { width: 100%; height: auto; display: block; }
.actogram-svg text { font-family: inherit; }
.actogram-weekend { fill: color-mix(in srgb, var(--color-primary) 7%, transparent); }
.actogram-grid { stroke: var(--color-border); stroke-width: 1; }
.actogram-grid-mid { stroke: var(--color-text-muted); stroke-width: 1.5; }
.actogram-axis { font-size: 10px; fill: var(--color-text-muted); }
.actogram-daylabel { font-size: 10.5px; fill: var(--color-text); }
.actogram-daylabel-wknd { font-weight: 600; }
.actogram-bar { fill: var(--color-primary); }
.actogram-tick { stroke: var(--color-primary); stroke-width: 3; stroke-linecap: round; }
.actogram-mean { stroke: var(--color-accent); stroke-width: 1; stroke-dasharray: 4 3; }
.actogram-mean-label { font-size: 8.5px; fill: var(--color-accent); }
.actogram-nap, .actogram-gutter { font-size: 9.5px; fill: var(--color-text-muted); }
.actogram-noentry { font-size: 10px; font-style: italic; fill: var(--color-text-muted); }
.actogram-legend { margin-top: var(--space-2); }

@media print {
    /* Everything to black-on-white; weekend tint → hatch (strokes survive a
       photocopy, a flat fill may not), reinforced by the already-bold dates. */
    .actogram-weekend { fill: url(#actogram-wknd-hatch); }
    .actogram-grid { stroke: #ccc; }
    .actogram-grid-mid { stroke: #000; }
    .actogram-axis, .actogram-daylabel, .actogram-nap, .actogram-gutter, .actogram-noentry { fill: #000; }
    .actogram-bar { fill: #000; }
    .actogram-tick { stroke: #000; }
    .actogram-mean, .actogram-mean-label { stroke: #000; fill: #000; }
    .report-actogram-title { color: #000 !important; }
}
