/* /Components/Layout/MainLayout.razor.rz.scp.css */
.page[b-qji39fi67y] {
    position: relative;
    display: flex;
    flex-direction: column;
}

main[b-qji39fi67y] {
    flex: 1;
    /* Without this, the flex item's default min-width:auto refuses to shrink
       below its content's intrinsic width, so a wide child (the monthly-view
       calendar table) pushes the whole page wider than the viewport instead of
       letting .table-responsive scroll internally. See #198. */
    min-width: 0;
}

.sidebar[b-qji39fi67y] {
    background-image: linear-gradient(180deg, rgb(5, 39, 103) 0%, #3a0647 70%);
}

.top-row[b-qji39fi67y] {
    background-color: #f7f7f7;
    border-bottom: 1px solid #d6d5d5;
    justify-content: flex-end;
    height: 3.5rem;
    display: flex;
    align-items: center;
}

    .top-row[b-qji39fi67y]  a, .top-row[b-qji39fi67y]  .btn-link {
        white-space: nowrap;
        margin-left: 1.5rem;
        text-decoration: none;
    }

    .top-row[b-qji39fi67y]  a:hover, .top-row[b-qji39fi67y]  .btn-link:hover {
        text-decoration: underline;
    }

    .top-row[b-qji39fi67y]  a:first-child {
        overflow: hidden;
        text-overflow: ellipsis;
    }

@media (max-width: 640.98px) {
    .top-row[b-qji39fi67y] {
        justify-content: space-between;
    }

    .top-row[b-qji39fi67y]  a, .top-row[b-qji39fi67y]  .btn-link {
        margin-left: 0;
    }
}

@media (min-width: 641px) {
    .page[b-qji39fi67y] {
        flex-direction: row;
    }

    .sidebar[b-qji39fi67y] {
        width: 250px;
        height: 100vh;
        position: sticky;
        top: 0;
    }

    .top-row[b-qji39fi67y] {
        position: sticky;
        top: 0;
        z-index: 1;
    }

    .top-row.auth[b-qji39fi67y]  a:first-child {
        flex: 1;
        text-align: right;
        width: 0;
    }

    .top-row[b-qji39fi67y], article[b-qji39fi67y] {
        padding-left: 2rem !important;
        padding-right: 1.5rem !important;
    }
}

#blazor-error-ui[b-qji39fi67y] {
    color-scheme: light only;
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    box-sizing: border-box;
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

    #blazor-error-ui .dismiss[b-qji39fi67y] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
/* /Components/Layout/NavMenu.razor.rz.scp.css */
.navbar-toggler[b-wjipvt9b80] {
    appearance: none;
    cursor: pointer;
    width: 3.5rem;
    height: 2.5rem;
    color: white;
    position: absolute;
    top: 0.5rem;
    right: 1rem;
    border: 1px solid rgba(255, 255, 255, 0.1);
    background: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 30 30'%3e%3cpath stroke='rgba%28255, 255, 255, 0.55%29' stroke-linecap='round' stroke-miterlimit='10' stroke-width='2' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e") no-repeat center/1.75rem rgba(255, 255, 255, 0.1);
}

.navbar-toggler:checked[b-wjipvt9b80] {
    background-color: rgba(255, 255, 255, 0.5);
}

.top-row[b-wjipvt9b80] {
    min-height: 3.5rem;
    background-color: rgba(0,0,0,0.4);
}

.navbar-brand[b-wjipvt9b80] {
    font-size: 1.1rem;
}

/* Every nav icon renders via the loaded Bootstrap-Icons font (exact
   bi-* glyph names in NavMenu.razor). This box just reserves a fixed
   width so the labels line up and adds right-margin spacing. */
.bi[b-wjipvt9b80] {
    display: inline-block;
    position: relative;
    width: 1.25rem;
    height: 1.25rem;
    margin-right: 0.75rem;
    top: -1px;
}

.nav-item[b-wjipvt9b80] {
    font-size: 0.9rem;
    padding-bottom: 0.5rem;
}

    .nav-item:first-of-type[b-wjipvt9b80] {
        padding-top: 1rem;
    }

    .nav-item:last-of-type[b-wjipvt9b80] {
        padding-bottom: 1rem;
    }

    .nav-item[b-wjipvt9b80]  .nav-link {
        color: #d7d7d7;
        background: none;
        border: none;
        border-radius: 4px;
        height: 3rem;
        display: flex;
        align-items: center;
        line-height: 3rem;
        width: 100%;
    }

.nav-item[b-wjipvt9b80]  a.active {
    background-color: rgba(255,255,255,0.37);
    color: white;
}

.nav-item[b-wjipvt9b80]  .nav-link:hover {
    background-color: rgba(255,255,255,0.1);
    color: white;
}

.nav-scrollable[b-wjipvt9b80] {
    display: none;
}

.navbar-toggler:checked ~ .nav-scrollable[b-wjipvt9b80] {
    display: block;
}

@media (min-width: 641px) {
    .navbar-toggler[b-wjipvt9b80] {
        display: none;
    }

    .nav-scrollable[b-wjipvt9b80] {
        /* Never collapse the sidebar for wide screens */
        display: block;

        /* Allow sidebar to scroll for tall menus */
        height: calc(100vh - 3.5rem);
        overflow-y: auto;
    }
}
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-eh1kvyqccs],
.components-reconnect-repeated-attempt-visible[b-eh1kvyqccs],
.components-reconnect-failed-visible[b-eh1kvyqccs],
.components-pause-visible[b-eh1kvyqccs],
.components-resume-failed-visible[b-eh1kvyqccs],
.components-rejoining-animation[b-eh1kvyqccs] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-eh1kvyqccs],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-eh1kvyqccs],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-eh1kvyqccs],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-eh1kvyqccs],
#components-reconnect-modal.components-reconnect-retrying[b-eh1kvyqccs],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-eh1kvyqccs],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-eh1kvyqccs],
#components-reconnect-modal.components-reconnect-failed[b-eh1kvyqccs],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-eh1kvyqccs] {
    display: block;
}


#components-reconnect-modal[b-eh1kvyqccs] {
    background-color: white;
    width: 20rem;
    margin: 20vh auto;
    padding: 2rem;
    border: 0;
    border-radius: 0.5rem;
    box-shadow: 0 3px 6px 2px rgba(0, 0, 0, 0.3);
    opacity: 0;
    transition: display 0.5s allow-discrete, overlay 0.5s allow-discrete;
    animation: components-reconnect-modal-fadeOutOpacity-b-eh1kvyqccs 0.5s both;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-eh1kvyqccs 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-eh1kvyqccs 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-eh1kvyqccs]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-eh1kvyqccs 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-eh1kvyqccs {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-eh1kvyqccs {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-eh1kvyqccs {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-eh1kvyqccs] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-eh1kvyqccs] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-eh1kvyqccs] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-eh1kvyqccs] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-eh1kvyqccs] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-eh1kvyqccs] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-eh1kvyqccs] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-eh1kvyqccs 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-eh1kvyqccs] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-eh1kvyqccs {
    0% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    4.9% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 0;
    }

    5% {
        top: 40px;
        left: 40px;
        width: 0;
        height: 0;
        opacity: 1;
    }

    100% {
        top: 0px;
        left: 0px;
        width: 80px;
        height: 80px;
        opacity: 0;
    }
}
/* /Components/Pages/MonthlyView.razor.rz.scp.css */
/* #309: the calendar stays mounted during month/patient reloads; the loading
   state is an overlay on top of it (rather than swapping the table for a bare
   spinner, which detached the table from the DOM and raced the E2E assertion). */
.monthly-view-content[b-e9h6tquu7o] {
    position: relative;
}

/* Dim the stale calendar while the next range loads, so the overlay reads as
   "refreshing" rather than "frozen". */
/* Transition on the base rule so opacity animates both into AND out of the
   loading state — if it lived only in the .is-loading rule it would vanish the
   moment the class is removed and some browsers wouldn't animate back to 1. */
.monthly-view-content > .card[b-e9h6tquu7o] {
    transition: opacity 0.1s ease-in-out;
}

.monthly-view-content.is-loading > .card[b-e9h6tquu7o] {
    opacity: 0.5;
}

.monthly-view-loading-overlay[b-e9h6tquu7o] {
    position: absolute;
    inset: 0;
    z-index: 10;
    display: flex;
    align-items: flex-start;
    justify-content: center;
    padding-top: 4rem;
    /* Let clicks fall through to nothing meaningful; the pickers sit above this
       region, so the overlay only covers the calendar content. */
    pointer-events: none;
}
/* /Components/Pages/MoodLog.razor.rz.scp.css */
/* The habit chain (#877, reopened).

   WHY THIS REPLACED A BUTTON. #877 first shipped a labelled toggle drawn as
   `btn-warning` pressed and `btn-outline-warning` unpressed. That had a
   mechanical defect — Bootstrap defines `.btn-outline-warning`'s hover
   background as `#ffc107`, which is `.btn-warning`'s RESTING background, and
   `.btn:focus-visible` takes the hover background too, so an unpressed toggle
   under the pointer or under keyboard focus was pixel-identical to a pressed
   one — and a design one underneath it: a counter and a button give the user
   nothing to extend, so pressing felt like filing a form rather than keeping a
   streak.

   The chain fixes both at once. It is the representation habit tracking has
   used since Seinfeld's wall calendar: draw the days, and let today's press
   visibly lengthen the row.

   THE STATE CHANNEL, since that is what the mechanical defect was about. Kept
   and not-kept differ in FILL — solid amber against near-white — which is a
   difference in ink rather than in hue, so it survives greyscale and colour
   blindness. Nothing interactive ever adds that fill: hover and focus move the
   BORDER and add a ring, both outside the cell. So "about to press" can never
   be mistaken for "already pressed", which is the property the previous pair
   could not provide.

   THE ASYMMETRY IS DELIBERATE. Unkept, today is a dashed outline — a visibly
   empty slot, which reads as something to fill. Kept, it is a solid cell that
   has joined the chain and stops advertising itself. Completing is meant to be
   the inviting gesture and withdrawing is not meant to be its mirror image. The
   ARIA APG rule that a toggle's label must not change with state governs the
   accessible NAME, which is constant here; the visual affordance is free to
   differ. */

/* Two rows: the habit and its run length across the top, the chain beneath.

   ONE row was the first build and it truncated every name — the streak rows sit
   inside the two-column symptom grid, and half a column does not hold a habit
   name and fourteen cells side by side. "Brushed teeth" rendered as "Brush…".
   A chain one line lower costs a glance; a habit you cannot read costs the row
   its meaning. */
.streak-row[b-8dym0m1q52] {
    display: grid;
    grid-template-columns: 1fr auto;
    align-items: center;
    column-gap: 0.5rem;
    row-gap: 0.125rem;
    padding: 0.375rem 0;
    border-bottom: 1px solid var(--bs-border-color-translucent, #f1f3f5);
}

.streak-row > .streak-name[b-8dym0m1q52] {
    grid-column: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 0.875rem;
}

/* Full width on its own row, so the strip never competes with the name for
   space and the cells stay a consistent size at every column width. */
.streak-row > .streak-chain[b-8dym0m1q52] {
    grid-column: 1 / -1;
    display: flex;
    align-items: center;
    gap: 2px;
    flex-wrap: nowrap;
}

/* A past day.

   GREEN, not amber: the daily log already says "done" in Bootstrap's success
   green — the Taken segment on every medication, the tick beside every entry in
   the Recent Entries list — so a kept habit drawing in the same green makes the
   page speak one colour language instead of two.

   A missed day is a grey cell carrying a MULTIPLICATION SIGN, and both halves of
   that are deliberate.

   The MARK, because a shape survives what a colour does not. Green-and-red is
   precisely the pair that deuteranopia and protanopia collapse — roughly 8% of
   men — and a chain whose whole meaning is carried by hue would turn to two
   shades of mud for them. With the × present, the chain reads correctly in
   greyscale, at a glance, and to anyone.

   NOT RED, and this is a decision rather than a palette preference. Streak
   design writing is consistent that marking missed days as FAILURES is what
   manufactures quit moments — Chou names Snapchat's permanent broken-streak
   display as the canonical example. On a tracker whose users miss days BECAUSE
   they are unwell, a row of red during an episode is the app blaming someone
   for a symptom, on the week they opened it feeling worst. A grey × says
   "nothing here", which is true; a red × says "you failed", which is not the
   app's to say. */
.streak-row .chain-cell[b-8dym0m1q52] {
    width: 0.85rem;
    height: 0.85rem;
    border-radius: 2px;
    background-color: var(--bs-secondary-bg, #f1f3f5);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    font-size: 0.7rem;
    font-weight: 700;
    line-height: 1;
    color: var(--bs-secondary-color, #adb5bd);
}

/* The non-colour channel. In the pseudo-element rather than the markup because
   the cells are aria-hidden — the chain carries ONE summary for assistive tech
   (see .streak-chain), so a per-cell glyph would be noise to read out and is
   purely visual. */
.streak-row .chain-cell[b-8dym0m1q52]::before {
    content: "\00d7";
}

/* Kept: solid green, and the × goes. A filled cell needs no mark — the ink IS
   the signal, and a glyph on top would only muddy it at this size. */
.streak-row .chain-cell.kept[b-8dym0m1q52] {
    background-color: #198754;
}

.streak-row .chain-cell.kept[b-8dym0m1q52]::before {
    content: none;
}

/* Today: the one cell that is a control. Larger than the history it joins, so
   the press target clears the ~24px minimum a finger needs even though the
   cells beside it are 12px. */
.streak-row .chain-today[b-8dym0m1q52] {
    width: 1.625rem;
    height: 1.625rem;
    margin-left: 0.3125rem;
    padding: 0;
    flex: 0 0 auto;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border-radius: 5px;
    font-size: 0.875rem;
    line-height: 1;

    /* Unkept: an empty slot. Dashed, so it reads as waiting to be filled rather
       than as a small button that happens to be there. */
    background-color: transparent;
    border: 2px dashed #198754;
    color: transparent;
}

/* Hover and focus move the border and nothing else — see the state-channel note
   at the top. The cell's interior is what says "kept", so the cell's interior is
   the one thing interaction may not touch. */
.streak-row .chain-today:hover:not(:disabled)[b-8dym0m1q52] {
    border-color: #146c43;
}

.streak-row .chain-today:focus-visible[b-8dym0m1q52] {
    outline: 2px solid #198754;
    outline-offset: 2px;
}

/* Kept: solid, and the tick appears. The tick is a second channel on top of the
   fill, so the two states differ in shape as well as in ink. */
.streak-row .chain-today.kept[b-8dym0m1q52] {
    background-color: #198754;
    border: 2px solid #198754;
    color: #fff;
}

.streak-row .chain-today.kept:hover:not(:disabled)[b-8dym0m1q52] {
    background-color: #146c43;
    border-color: #146c43;
}

.streak-row .chain-today:disabled[b-8dym0m1q52] {
    opacity: 0.5;
}

/* The run length, or the fortnight when there is no run. Tabular figures so the
   column does not jitter between 9 and 10 as the numbers change. */
.streak-row > .streak-run[b-8dym0m1q52] {
    grid-column: 2;
    min-width: 3rem;
    text-align: right;
    font-size: 0.75rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    color: #146c43;
}

/* A darkened green rather than the cells' #198754. The fill only has to be
   distinguishable; a small bold LABEL has to be readable, and #146c43 clears
   4.5:1 on white with room to spare. The cells carry the hue, the text carries
   the contrast. */
.streak-row .streak-run-quiet[b-8dym0m1q52] {
    font-weight: 400;
    color: var(--bs-secondary-color, #6c757d);
}

/* ---------------------------------------------------------------------------
   #930 — the daily log on a phone.

   Measured at a 430x900 viewport on an account with 8 scheduled medications and
   13 custom symptoms: the page was 5,104px tall, and the editor's first input
   sat at y=1,219 — nearly a screen and a half of NAVIGATION before anything you
   came to record. The sidebar is `col-lg-4`, so below Bootstrap's lg breakpoint
   it stops being a column beside the form and becomes a 1,128px preamble above
   it, of which 860px is the Recent Entries list: 21 full-width rows, each one a
   date.

   That list is not the problem on a wide screen, where it costs nothing — it
   sits in a column the form does not use, and the whole point of it is being
   able to see at a glance which of the last three weeks are logged. So this
   does not hide it, collapse it, or move it. It reflows it: below lg the same
   21 links lay out as a compact grid of date chips instead of a stack of rows,
   which is the same information in about a third of the height.

   Nothing is hidden and nothing is reordered, which is the reason to prefer
   this over the two obvious alternatives. A <details> disclosure would have to
   be closed on a phone and open on a wide screen, and there is no reliable
   CSS-only way to force a closed <details> open — ::details-content is at ~86%
   support (Firefox only from 143), and the 14% that miss it would get a desktop
   sidebar collapsed behind a summary this rule had hidden. Visually reordering
   the two columns with `order-*` leaves DOM order — and so tab order — pointing
   the other way, which is the disconnect Bootstrap's own grid docs warn about.
   A media query on the list's own layout has neither failure mode: DOM order is
   untouched, every day is still a visible, tappable link, and a browser that
   ignored the query would simply draw today's page.
   --------------------------------------------------------------------------- */

/* Shared by both viewports, so the historical rows do not depend on Bootstrap's
   `justify-content-between` utility — which lands as `!important` and could
   then only be overridden by another `!important`. Stated here once, the narrow
   rule below just changes it. */
.recent-entry-line[b-8dym0m1q52] {
    display: flex;
    justify-content: space-between;
    align-items: center;
}

@media (max-width: 991.98px) {
    /* Grid rather than flex-wrap: the chips have to be one width regardless of
       how long their date reads, or the last row of a wrapped list stretches to
       fill and stops looking like the rows above it. */
    .recent-entries[b-8dym0m1q52] {
        display: grid;
        grid-template-columns: repeat(3, minmax(0, 1fr));
        gap: 0.375rem;
    }

    /* `.list-group-flush > .list-group-item` draws only a bottom border, which
       is right for a stack and wrong for a grid — the chips need a box each.
       Restated rather than removed from the markup, because the flush treatment
       is still what the wide-screen list wants.

       Width and style only, never colour: `.list-group-item` supplies the
       border colour and `.list-group-item.active` replaces it with the selected
       day's blue. Restating the colour here would win on specificity and leave
       the selected chip with a grey box around a blue fill. */
    .recent-entries > .list-group-item[b-8dym0m1q52] {
        border-width: 1px;
        border-style: solid;
        border-radius: var(--bs-border-radius, 0.375rem);
        padding: 0.375rem 0.25rem;
        font-size: 0.75rem;
        white-space: nowrap;
    }

    /* Today is the row people come here to press, and it carries a "Log" badge
       that no chip has room for, so it keeps its full width and its own size at
       the top of the grid. */
    .recent-entries > .recent-entry-today[b-8dym0m1q52] {
        grid-column: 1 / -1;
        padding: 0.5rem 0.75rem;
        font-size: 1rem;
        white-space: normal;
    }

    /* Centred, because a chip has no far edge to push a tick to. */
    .recent-entries > .recent-entry .recent-entry-line[b-8dym0m1q52] {
        justify-content: center;
        gap: 0.25rem;
        min-width: 0;
    }

    /* The 40-character note preview needs a row's width to say anything. In a
       120px chip it would be two words and an ellipsis, and it would set the
       height of every chip in its grid row. The note is still on the day's own
       page, one tap away. */
    .recent-entry-note[b-8dym0m1q52] {
        display: none;
    }
}

/* Three columns stop fitting before the smallest phones do.

   Measured, not guessed: a chip's content — "Aug 28, 2026" plus the entry tick
   — needs about 88px, and three columns give it 120px at 430, 97px at 360 and
   83px at 320. So 320 is the width at which a logged day's date runs into its
   own border, and it is a width real phones still have (an SE-sized viewport).
   Two columns there give 136px; every width above it keeps the three. */
@media (max-width: 359.98px) {
    .recent-entries[b-8dym0m1q52] {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

/* #930: the units half of a medication's dose. Bootstrap gives every
   input-group child `flex: 1 1 auto`, which would split the group evenly
   between a number and "mg"; a fixed basis leaves the dose the room, since the
   dose is the field that varies. */
.med-units[b-8dym0m1q52] {
    flex: 0 0 4.5rem;
}

/* #928 — the group captions inside Custom Symptoms.

   An EYEBROW rather than a heading-sized heading, and that is the #929 lesson
   applied one level down. #929's complaint was that every section heading was an
   h6 — 1rem, byte-identical in size to the .form-label captions beneath it — so
   the page had no visible skeleton. A group caption at 1rem grey would land in
   exactly that trap against the symptom names it sits above, which are
   .form-label at 1rem.

   So this goes the other way: smaller, uppercase, letter-spaced and muted. Size,
   case and weight all move at once, which is what keeps it legible as a caption
   at 0.75rem instead of reading as small body text. The <h4> tag carries the
   outline level; none of this touches it. */
.symptom-group-heading[b-8dym0m1q52] {
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--bs-secondary-color, #6c757d);
    margin-bottom: 0.5rem;
}

/* The double bottom margin under the two groups whose control is a
   SegmentedChoice.

   Every custom-symptom cell carries `mb-3`, and `.segmented-choice` carries its
   own `mb-3` inside it — so a severity or yes/no group ended 2rem clear of the
   next group's caption while a streak or counts group ended 1rem clear. With the
   groups now captioned (#928) that inconsistency is visible as uneven bands
   rather than as the noise it used to hide in.

   Scoped to `:last-child` on purpose. A severity cell with timed readings under
   it (#676) still has the control's margin doing real work — separating the rail
   from the list beneath — so only the case where the margin is the cell's own
   trailing space is dropped.

   `!important` because the margin being cancelled is Bootstrap's `mb-3` utility,
   which lands as `!important` itself and can therefore only be overridden by
   another one — the same constraint the `.recent-entry-line` note above records.
   Specificity does not enter into it; a plain rule here loses however it is
   written, silently, which is how the first attempt at this changed nothing.

   `::deep` because `.segmented-choice` is SEGMENTEDCHOICE'S root element, not
   this page's. CSS isolation appends the scope id to the LAST compound selector,
   so the same rule written without `::deep` compiles to

       [data-symptom-cell] .segmented-choice:last-child[b-8dym0m1q52]

   while the markup is `<div data-symptom-cell b-8dym0m1q52>` wrapping
   `<div class="segmented-choice" b-xdmyx6xwk4>` — MoodLog's scope asserted on an
   element that carries the child component's. It matches nothing, in silence.
   `::deep` moves the scope onto `[data-symptom-cell]`, which this page does own:

       [data-symptom-cell][b-8dym0m1q52] .segmented-choice:last-child

   Copilot caught this on PR #995; a screenshot harness that stripped scope
   attributes in order to link the raw .razor.css files could not, and showed the
   rule working. */
[data-symptom-cell][b-8dym0m1q52]  .segmented-choice:last-child {
    margin-bottom: 0 !important;
}

/* The five form sections' disclosures (#994).

   WHY THE PAGE STILL SHIPS OPEN. Every one of these sections is a question the
   log is asking, and NN/g's rule for accordions is that they suit a page where
   the reader needs only a few of the pieces on it — GDS is blunter still about a
   form's own questions going behind one. A daily log is a form whose questions
   are the point, so nothing here is collapsed by the product. It is collapsed by
   the USER, once, and remembered per browser: the two tall sections are the two
   that scale with the account, and which of your own medications and habits you
   want out of the way on a phone is not a call the app is in a position to make
   for you.

   <details> rather than a Bootstrap collapse for the same reason
   CalendarLegendPanel uses it: the open/closed state, the button semantics, the
   keyboard behaviour and the aria-expanded reporting are all native, so there is
   no JS in the disclosure itself and it survives prerender.

   NOTHING HERE SETS display, and that is deliberate rather than an omission. A
   <summary> is display: list-item in every UA stylesheet, which is what draws the
   disclosure triangle; setting flex (the obvious way to push the count to the
   right) takes the element out of list-item and the marker silently goes with it
   — the affordance disappearing while the layout looks fine. The heading and the
   count are inline instead, and the marker stays the browser's. */
.log-section > .log-section-summary[b-8dym0m1q52] {
    /* The rule the h3 used to carry itself (border-bottom pb-2). It moves here so
       it spans the whole clickable row rather than stopping under the heading
       text, which is what makes the row read as one control. */
    padding-bottom: 0.5rem;
    margin-bottom: 0.5rem;
    border-bottom: 1px solid var(--bs-border-color-translucent, #dee2e6);
    cursor: pointer;
}

/* Inline so the heading shares the marker's line. The h5 SIZE is untouched —
   #929 chose it against the .form-label captions below, and that comparison is
   unaffected by the display mode. */
.log-section > .log-section-summary h3[b-8dym0m1q52] {
    display: inline;
}

/* Hover and focus move the ROW, never the heading's colour: a control needs a
   resting/hover/focus set a reader can tell apart, and recolouring the text
   would say something about the heading rather than about the control. */
.log-section > .log-section-summary:hover[b-8dym0m1q52] {
    background-color: var(--bs-tertiary-bg, #f8f9fa);
}

.log-section > .log-section-summary:focus-visible[b-8dym0m1q52] {
    outline: 2px solid var(--bs-primary, #0d6efd);
    outline-offset: 2px;
}

/* The count beside the heading — subordinate to it, and never large enough to
   compete with the .form-label captions inside the section (#929). */
.log-section .log-section-status[b-8dym0m1q52] {
    margin-left: 0.5rem;
    font-size: 0.875rem;
    color: var(--bs-secondary-color, #6c757d);
}

/* A link-styled button, so the one control above the form does not read as a
   sixth thing to fill in. */
.log-sections-toggle-all[b-8dym0m1q52] {
    padding: 0;
    text-decoration: none;
}
/* /Components/Shared/CrisisResources.razor.rz.scp.css */
.crisis-resources[b-zwu4rjllh2] {
    border: 1px solid #f0d0d0;
    background-color: #fff6f6;
    border-radius: 6px;
    padding: 1rem 1.25rem;
}

.crisis-resources-compact[b-zwu4rjllh2] {
    padding: 0.75rem 1rem;
    font-size: 0.9rem;
}

.crisis-resources-heading[b-zwu4rjllh2] {
    font-weight: 600;
    color: #a02020;
    margin-bottom: 0.5rem;
}

.crisis-resources-list[b-zwu4rjllh2] {
    margin: 0;
    padding-left: 1.1rem;
}

.crisis-resources-list li[b-zwu4rjllh2] {
    margin-bottom: 0.35rem;
}

.crisis-resources-list li:last-child[b-zwu4rjllh2] {
    margin-bottom: 0;
}
/* /Components/Shared/ImportStepper.razor.rz.scp.css */
/* Horizontal step indicator for the import wizard (#361). Styled with Bootstrap
   CSS custom properties so it tracks the app's theme (light/dark) automatically.
   The connecting line between two steps is drawn as two halves — each step's
   ::after (right half) and the next step's ::before (left half) — and a segment
   fills primary only once the step it leaves is complete. */

.import-stepper[b-vncyakzrgo] {
    margin-bottom: 1.5rem;
}

.import-stepper ol[b-vncyakzrgo] {
    list-style: none;
    display: flex;
    padding: 0;
    margin: 0;
}

.import-stepper .step[b-vncyakzrgo] {
    flex: 1 1 0;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    position: relative;
}

/* Connector halves — centered vertically on the 2rem marker. */
.import-stepper .step[b-vncyakzrgo]::before,
.import-stepper .step[b-vncyakzrgo]::after {
    content: "";
    position: absolute;
    top: 1rem;
    height: 2px;
    width: 50%;
    background: var(--bs-border-color);
}

.import-stepper .step[b-vncyakzrgo]::before { left: 0; }
.import-stepper .step[b-vncyakzrgo]::after { right: 0; }
.import-stepper .step:first-child[b-vncyakzrgo]::before { display: none; }
.import-stepper .step:last-child[b-vncyakzrgo]::after { display: none; }

/* Fill the path up to (and into) the current step. */
.import-stepper .step.complete[b-vncyakzrgo]::after,
.import-stepper .step.complete[b-vncyakzrgo]::before,
.import-stepper .step.active[b-vncyakzrgo]::before {
    background: var(--bs-primary);
}

.import-stepper .marker[b-vncyakzrgo] {
    position: relative;
    z-index: 1;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    background: var(--bs-body-bg);
    border: 2px solid var(--bs-border-color);
    color: var(--bs-secondary-color);
    font-size: .9rem;
}

.import-stepper .step.active .marker[b-vncyakzrgo] {
    border-color: var(--bs-primary);
    color: var(--bs-primary);
}

.import-stepper .step.complete .marker[b-vncyakzrgo] {
    background: var(--bs-primary);
    border-color: var(--bs-primary);
    color: #fff;
}

.import-stepper .label[b-vncyakzrgo] {
    margin-top: .375rem;
    font-size: .8125rem;
    line-height: 1.2;
    color: var(--bs-secondary-color);
}

.import-stepper .step.active .label[b-vncyakzrgo] {
    color: var(--bs-primary);
    font-weight: 600;
}

.import-stepper .step.complete .label[b-vncyakzrgo] {
    color: var(--bs-body-color);
}
/* /Components/Shared/SegmentedChoice.razor.rz.scp.css */
/* Severity scale: a slider to look at and to touch, a toolbar of toggle buttons
   to the keyboard and to assistive tech (#622).

   #450 made this one contiguous control and #381 made it one keyboard control,
   but its own body set the target as "look and behave like a contiguous slider
   does" — and the acceptance criteria only asked for contiguous segments, so
   four buttons touching is what got built. This finishes the presentation half.
   NO behaviour changes.

   WHY NOT A REAL SLIDER. Per the WAI-ARIA APG slider pattern the arrow keys
   CHANGE THE VALUE, and the pattern carries no representation for "no value
   set". Both are disqualifying here: every scale autosaves through
   @bind-Value:after, so value-changing arrows would write Mild and Moderate into
   the record while arrowing past them (the hazard SegmentedChoice.razor's
   keyboard handler is written to avoid), and "not recorded" — which #350 keeps
   distinct from None/0 — would become inexpressible. Microsoft's own
   FluentSlider<TValue> where TValue : INumber<TValue> cannot take an int? for
   exactly that second reason. So the slider is DRAWN, and the buttons underneath
   are untouched (#611 records the full investigation).

   Layout still a grid, for the reason #450/#198 gave: minmax(0, 1fr) lets a
   column shrink below its content's intrinsic width rather than forcing the row
   — and therefore the page — wider than the viewport. Four columns at every
   width; the container queries at the bottom step type down rather than
   rewrapping. */
.segmented-choice[b-xdmyx6xwk4] {
    container-type: inline-size;
}

/* The rail zone sits above the labels rather than behind them: a rail crossing
   the text would fight it for contrast at exactly the sizes the container
   queries below are already squeezing. */
.seg-track[b-xdmyx6xwk4] {
    --seg-rail-height: 0.375rem;
    --seg-rail-zone: 1.25rem;
    --seg-thumb-size: 0.875rem;

    position: relative;
    display: grid;
    grid-template-columns: repeat(var(--seg-count, 4), minmax(0, 1fr));
    gap: 0;
    /* A drag on a phone must move the thumb, not scroll the page under it. */
    touch-action: none;
}

/* The rail. Inset by half a column at each end so it spans FIRST STOP CENTRE to
   LAST STOP CENTRE — the thumb sits on a stop, so a rail running the full width
   would leave it floating short of both ends. */
.seg-track[b-xdmyx6xwk4]::before {
    content: "";
    position: absolute;
    top: calc((var(--seg-rail-zone) - var(--seg-rail-height)) / 2);
    left: calc(50% / var(--seg-count, 4));
    right: calc(50% / var(--seg-count, 4));
    height: var(--seg-rail-height);
    border-radius: calc(var(--seg-rail-height) / 2);
    background-color: var(--bs-secondary-bg, #e9ecef);
    z-index: 0;
}

/* The fill — the slider's trail (#669).

   REVERSES, FOR THIS CONTROL ONLY, #622's "a position mark, never a fill up to
   it (#427)". That rule was written for the READ-ONLY forecast renderings
   (SeverityTrack / PredictedSeverityBand), where a filled bar sits beside an
   uncertainty band and can genuinely be misread as an interval: Moderate does
   not contain Mild, so a bar drawn up to Moderate must not imply it. Those two
   keep that reasoning and are untouched.

   On an INPUT the trail says something else, and something every slider a user
   has ever touched already says: how far along this scale you have dragged the
   thumb. Nobody reads a volume slider at 60% as also asserting 30% and 10%. Its
   absence was the single biggest reason this still didn't read as a slider —
   Severe and Mild drew nearly the same picture, a uniform grey bar with a small
   coloured dot somewhere along it.

   Spans the rail's left end (the first stop's centre) to the thumb, so its
   width is the thumb's own `left` MINUS the rail's half-column inset:
   (i + 0.5)/n - 0.5/n = i/n. At the last stop that is (n-1)/n, which is exactly
   the rail's width (100% - 100%/n), so Severe fills it end to end. At stop 0 it
   is zero-length by construction — None is a recorded answer with no trail, and
   the THUMB is what distinguishes it from not-recorded, exactly as before.

   Sits between the rail and the thumb: same z-index as the rail (::before) but
   later in tree order, so it paints over it; under the thumb (z-index 1) and
   under the segments (z-index 2), whose ::before tick stops therefore stay
   legible as notches across it. Not rendered at all when nothing is recorded —
   see the .razor. */
.seg-track > .seg-fill[b-xdmyx6xwk4] {
    position: absolute;
    top: calc((var(--seg-rail-zone) - var(--seg-rail-height)) / 2);
    left: calc(50% / var(--seg-count, 4));
    width: calc(var(--seg-thumb-pos, var(--seg-selected, 0)) / var(--seg-count, 4) * 100%);
    height: var(--seg-rail-height);
    border-radius: calc(var(--seg-rail-height) / 2);
    background-color: var(--seg-live-color, var(--seg-thumb-color, var(--bs-secondary, #6c757d)));
    z-index: 0;
}

/* The thumb: a position mark on its stop, now at the head of the #669 fill
   above rather than alone on a grey rail.

   Positioned from --seg-thumb-pos, which falls back to the selected stop and is
   overridden by wwwroot/segmented-drag.js while a pointer is down. That
   indirection is the whole reason the index is published as a custom property:
   during a drag the thumb must move without Value changing, and re-rendering per
   pointer move would be a server round trip per frame over the circuit.

   --seg-live-color is the colour half of that same trick, and exists for the
   same reason: --seg-thumb-color is written server-side from the COMMITTED
   value, so it cannot move during a drag. With only a dot to recolour that went
   unnoticed; with a full-width fill, dragging None->Severe would sweep a green
   bar across the whole rail and only turn red on release. The drag script sets
   --seg-live-color per stop crossed and removes it on release, so the committed
   colour takes over again for free — the same "hand it back by removing the
   override" the position already relies on for a rejected or superseded save.

   Deliberately a SECOND property rather than the script overwriting
   --seg-thumb-color: .seg-current below reads that one to emphasise the label of
   the committed answer, and that label must go on identifying the recorded value
   while the thumb is somewhere else. */
.seg-track[b-xdmyx6xwk4]::after {
    content: "";
    position: absolute;
    top: calc((var(--seg-rail-zone) - var(--seg-thumb-size)) / 2);
    left: calc((var(--seg-thumb-pos, var(--seg-selected, 0)) + 0.5) / var(--seg-count, 4) * 100%);
    width: var(--seg-thumb-size);
    height: var(--seg-thumb-size);
    margin-left: calc(var(--seg-thumb-size) / -2);
    border-radius: 50%;
    background-color: var(--seg-live-color, var(--seg-thumb-color, var(--bs-secondary, #6c757d)));
    border: 2px solid var(--bs-body-bg, #fff);
    box-shadow: 0 0 0 1px rgb(0 0 0 / 0.15);
    z-index: 1;
}

/* Cleared is NOT RECORDED, and must read as obviously empty (#350) — distinct
   from None/0, which is a logged answer. With no solid segment left to
   disappear, the absence of the thumb IS the signal, so it is removed outright
   rather than greyed: a grey thumb parked on a stop still asserts a position.

   The #669 fill needs no companion rule here, and deliberately has none: it is
   an element, and the .razor renders it only when SelectedIndex >= 0 — the same
   source this class is set from. One fact expressed once, so the two cannot
   drift into a cleared group that draws a coloured bar and no thumb. */
.seg-cleared[b-xdmyx6xwk4]::after {
    content: none;
}

/* The segments: unchanged as controls, invisible as buttons. Every Bootstrap
   fill — solid or outlined — would paint over the rail, so background, border
   and the button's own colour all go, leaving a full-height transparent hit area
   over its stop. The label is pushed below the rail zone. */
.seg-track > .seg-hit[b-xdmyx6xwk4] {
    position: relative;
    z-index: 2;
    padding-top: var(--seg-rail-zone);
    background-color: transparent;
    border-color: transparent;
    color: var(--bs-secondary-color, #6c757d);
    border-radius: 0;
}

/* The tick stop, drawn per segment so each mark inherits its own column's centre
   rather than being computed from an index — one rule for any --seg-count. */
.seg-track > .seg-hit[b-xdmyx6xwk4]::before {
    content: "";
    position: absolute;
    top: calc((var(--seg-rail-zone) - var(--seg-rail-height)) / 2);
    left: 50%;
    width: 2px;
    height: var(--seg-rail-height);
    margin-left: -1px;
    background-color: var(--bs-body-bg, #fff);
    z-index: 1;
}

/* Reading your own answer must not mean eyeballing a dot against four labels,
   which is what a position-only mark would otherwise ask. The selected label
   takes the level's colour and weight. */
.seg-track > .seg-current[b-xdmyx6xwk4] {
    color: var(--seg-thumb-color, var(--bs-body-color));
    font-weight: 600;
}

/* Hover/active must not reintroduce a fill. Bootstrap's default is for a button
   to take a background on hover, and because the pointer sits on the segment at
   the moment you click-to-clear, that fill made a just-cleared group look
   selected — the #350 defect. The rail makes the affordance visible without it,
   so the segment stays transparent throughout and only the label lifts. */
.seg-track > .seg-hit:hover[b-xdmyx6xwk4],
.seg-track > .seg-hit:focus[b-xdmyx6xwk4],
.seg-track > .seg-hit:active[b-xdmyx6xwk4] {
    background-color: transparent;
    border-color: transparent;
    color: var(--bs-body-color);
}

/* ...but the SELECTED label keeps its level colour through those states
   (Copilot, PR #643). The rule above is (0,3,0) — two classes and a
   pseudo-class — while .seg-current is (0,2,0), so it wins on specificity no
   matter which is written first. The effect was that hovering or focusing your
   own answer stripped the colour identifying it, in exactly the moment you are
   looking at it for confirmation. This restates the emphasis at equal
   specificity, after, so it wins on order. */
.seg-track > .seg-current:hover[b-xdmyx6xwk4],
.seg-track > .seg-current:focus[b-xdmyx6xwk4],
.seg-track > .seg-current:active[b-xdmyx6xwk4] {
    color: var(--seg-thumb-color, var(--bs-body-color));
}

/* The focus ring has to clear both the rail and its neighbours — this is the
   arrow-key path #381 added, so it must be followable. Outline rather than a
   background, since a background is precisely what this control has given up. */
.seg-track > .seg-hit:focus-visible[b-xdmyx6xwk4] {
    z-index: 3;
    outline: 2px solid var(--bs-focus-ring-color, #0d6efd);
    outline-offset: -2px;
}

/* Long labels must not blow their column open — the #198 page-widening bug.
   Each segment's text shrinks to its share and ellipsises only as a last resort;
   the container queries below exist so real labels don't reach it.
   SegmentedScaleNarrowWidthE2ETests pins that "Moderate" and "Not tracked" still
   render in full at 320px. */
.seg-track > .seg-hit[b-xdmyx6xwk4] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* ---------------------------------------------------------------------------
   NON-ORDINAL scales: the segmented buttons #450 shipped, unchanged.

   Psychotic Symptoms (None/Present), Therapy (No/Yes) and Menstrual Cycle
   (Not tracked/Period/Spotting) are categorical, not ordered — Spotting is not
   "more" than Period and "Not tracked" is not a low end. A rail would assert an
   ordering that does not exist, which is the same claim #626 removed from the
   reporting side. So these keep filled segments, and everything below is the
   pre-#622 rule set scoped to them.
   --------------------------------------------------------------------------- */
.seg-buttons[b-xdmyx6xwk4] {
    display: grid;
    grid-template-columns: repeat(var(--seg-count, 4), minmax(0, 1fr));
    /* No gap: shared edges are what make this read as one control. */
    gap: 0;
}

/* Square the inner edges and collapse the shared borders, so N segments render
   as one bar with N-1 dividing lines rather than N outlined boxes. Logical
   properties so the bar stays correct if the app is ever rendered RTL. */
.seg-buttons > .btn[b-xdmyx6xwk4] {
    margin-left: 0;
    border-radius: 0;
    margin-inline-start: calc(var(--bs-border-width, 1px) * -1);
}

.seg-buttons > .btn:first-child[b-xdmyx6xwk4] {
    margin-inline-start: 0;
    border-start-start-radius: var(--bs-btn-border-radius, 0.375rem);
    border-end-start-radius: var(--bs-btn-border-radius, 0.375rem);
}

.seg-buttons > .btn:last-child[b-xdmyx6xwk4] {
    border-start-end-radius: var(--bs-btn-border-radius, 0.375rem);
    border-end-end-radius: var(--bs-btn-border-radius, 0.375rem);
}

/* The selected segment renders solid while its neighbours are outlines, so it
   has to sit above them or its own border is overdrawn by the next segment's
   negative margin. */
.seg-buttons > .btn:not([class*="btn-outline-"])[b-xdmyx6xwk4] {
    position: relative;
    z-index: 1;
}

/* Strictly above the selected segment, not merely above the outlines (#608
   review). At equal z-index the later sibling wins, and every segment overlaps
   its predecessor by the collapsed border — so focusing the segment immediately
   BEFORE the selected one put its focus ring under that overlap. That is the
   arrow-key path #381 adds, so the ring has to outrank everything in the group. */
.seg-buttons > .btn:focus-visible[b-xdmyx6xwk4] {
    position: relative;
    z-index: 2;
}

/* #350: an unselected option must always read as EMPTY — an unfilled, coloured
   outline — so re-clicking the active option to clear it produces an obviously
   blank group. Bootstrap's default is the opposite: on hover/focus/active an
   outline button fills solid. Because the pointer sits on the button at the
   moment you click-to-clear, that hover-fill makes the just-cleared "untracked"
   state look identical to a selected one — worst for the grey "None"/secondary
   option, where cleared and selected-hovered are near-indistinguishable greys.

   #937 made this repo-wide: app.css now suppresses the fill on any
   [aria-pressed="false"] .btn, which these segments are. This rule is kept
   rather than deleted because it is the one that actually applies — scoped
   component CSS carries a [b-xxxxx] attribute and so outranks app.css — and
   because it says something app.css cannot, namely which colour the unselected
   segment falls back to inside a collapsed-border group. The shared rule is the
   backstop for the next control, not a replacement for this one. */
.seg-buttons > .btn[class*="btn-outline-"]:hover[b-xdmyx6xwk4],
.seg-buttons > .btn[class*="btn-outline-"]:focus[b-xdmyx6xwk4],
.seg-buttons > .btn[class*="btn-outline-"]:active[b-xdmyx6xwk4] {
    background-color: transparent;
    color: var(--bs-btn-color);
    border-color: var(--bs-btn-border-color);
}

.seg-buttons > .btn[b-xdmyx6xwk4] {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* Narrow: keep every column, shrink the type and padding instead of reflowing
   (#249's breakpoint, #450's response). Applies to both presentations. */
@container (max-width: 22rem) {
    .seg-track > .seg-hit[b-xdmyx6xwk4],
    .seg-buttons > .btn[b-xdmyx6xwk4] {
        --bs-btn-padding-x: 0.25rem;
        --bs-btn-font-size: 0.8125rem;
    }
}

/* The 4-up severity scale at a 320px viewport is the tightest real case in the
   app, and 0.8125rem measured too large for it. Sized by measurement, not by
   eye. Abbreviating to "Mod" was the alternative and is deliberately not taken:
   a shortened word on a clinical severity scale costs the user more than a
   smaller one. */
@container (max-width: 18rem) {
    .seg-track > .seg-hit[b-xdmyx6xwk4],
    .seg-buttons > .btn[b-xdmyx6xwk4] {
        --bs-btn-padding-x: 0.125rem;
        --bs-btn-font-size: 0.75rem;
    }
}

/* Very narrow (small phones, and the mood log's own columns at their tightest).
   Still one row — a single-column stack would read as four separate controls,
   which is precisely the bug #450 fixed. */
@container (max-width: 11rem) {
    .seg-track > .seg-hit[b-xdmyx6xwk4],
    .seg-buttons > .btn[b-xdmyx6xwk4] {
        --bs-btn-padding-x: 0.125rem;
        --bs-btn-font-size: 0.6875rem;
    }
}
/* /Components/Shared/SeverityTrack.razor.rz.scp.css */
/* #427: the predicted band, drawn on the 0–3 severity track.

   The track is the full scale (None at 0%, Severe at 100%) so two dimensions'
   bands can be compared against each other — the defect Dr. V read as "the
   scales are all over the place" was partly that each row's mark meant
   something different. */

.band-track[b-03yrt7ysyb] {
    position: relative;
    height: 25px;
    border-radius: 0.25rem;
    background-color: var(--bs-secondary-bg, #e9ecef);
    overflow: hidden;
}

/* Level gridlines at 1 and 2 — the ends are labelled beneath the track, and
   these are what let a reader tell Mild from Moderate without counting. */
.band-track[b-03yrt7ysyb]::after {
    content: "";
    position: absolute;
    inset: 0;
    background-image: linear-gradient(to right,
        transparent calc(33.333% - 1px), var(--bs-border-color, #dee2e6) calc(33.333% - 1px),
        var(--bs-border-color, #dee2e6) 33.333%, transparent 33.333%,
        transparent calc(66.667% - 1px), var(--bs-border-color, #dee2e6) calc(66.667% - 1px),
        var(--bs-border-color, #dee2e6) 66.667%, transparent 66.667%);
    pointer-events: none;
}

/* The plausible range. Lightened so the expected marker reads on top of it,
   and floored at a visible width so a low == high prediction still shows the
   level it landed on rather than disappearing.

   The floor is wider than the 4px marker on purpose. The span is centred on its
   level (#504), so a floor of exactly the marker's width would sit under it and
   show nothing at all — the disappearance this rule exists to prevent. At 12px
   it reads as an even 4px either side of the marker: present, and pointing
   nowhere. At the two ends of the scale the span is held inside the clipped
   track instead, so that one is one-sided — as is the marker beneath it, and
   for the same reason: there is no scale left to draw on. */
.band-span[b-03yrt7ysyb] {
    position: absolute;
    top: 0;
    bottom: 0;
    min-width: 12px;
    opacity: 0.4;
}

/* The most likely level. Solid and full-height: this is the one value the
   reader takes away, and the band around it is the caveat. The horizontal
   shift is set inline — at 0% and 100% the marker sits flush inside the track
   instead of being centred and half-clipped by the container. */
.band-expected[b-03yrt7ysyb] {
    position: absolute;
    top: 0;
    bottom: 0;
    width: 4px;
    background-color: var(--bs-body-color, #212529);
}
