/* /Components/Layout/DesktopLayout.razor.rz.scp.css */
/* /Components/Layout/ReactiveLayout.razor.rz.scp.css */
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-1f42o0xh0h],
.components-reconnect-repeated-attempt-visible[b-1f42o0xh0h],
.components-reconnect-failed-visible[b-1f42o0xh0h],
.components-pause-visible[b-1f42o0xh0h],
.components-resume-failed-visible[b-1f42o0xh0h],
.components-rejoining-animation[b-1f42o0xh0h] {
    display: none;
}

#components-reconnect-modal.components-reconnect-show .components-reconnect-first-attempt-visible[b-1f42o0xh0h],
#components-reconnect-modal.components-reconnect-show .components-rejoining-animation[b-1f42o0xh0h],
#components-reconnect-modal.components-reconnect-paused .components-pause-visible[b-1f42o0xh0h],
#components-reconnect-modal.components-reconnect-resume-failed .components-resume-failed-visible[b-1f42o0xh0h],
#components-reconnect-modal.components-reconnect-retrying[b-1f42o0xh0h],
#components-reconnect-modal.components-reconnect-retrying .components-reconnect-repeated-attempt-visible[b-1f42o0xh0h],
#components-reconnect-modal.components-reconnect-retrying .components-rejoining-animation[b-1f42o0xh0h],
#components-reconnect-modal.components-reconnect-failed[b-1f42o0xh0h],
#components-reconnect-modal.components-reconnect-failed .components-reconnect-failed-visible[b-1f42o0xh0h] {
    display: block;
}


#components-reconnect-modal[b-1f42o0xh0h] {
    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-1f42o0xh0h 0.5s both;
    color: black;
    &[open]

{
    animation: components-reconnect-modal-slideUp-b-1f42o0xh0h 1.5s cubic-bezier(.05, .89, .25, 1.02) 0.3s, components-reconnect-modal-fadeInOpacity-b-1f42o0xh0h 0.5s ease-in-out 0.3s;
    animation-fill-mode: both;
}

}

#components-reconnect-modal[b-1f42o0xh0h]::backdrop {
    background-color: rgba(0, 0, 0, 0.4);
    animation: components-reconnect-modal-fadeInOpacity-b-1f42o0xh0h 0.5s ease-in-out;
    opacity: 1;
}

@keyframes components-reconnect-modal-slideUp-b-1f42o0xh0h {
    0% {
        transform: translateY(30px) scale(0.95);
    }

    100% {
        transform: translateY(0);
    }
}

@keyframes components-reconnect-modal-fadeInOpacity-b-1f42o0xh0h {
    0% {
        opacity: 0;
    }

    100% {
        opacity: 1;
    }
}

@keyframes components-reconnect-modal-fadeOutOpacity-b-1f42o0xh0h {
    0% {
        opacity: 1;
    }

    100% {
        opacity: 0;
    }
}

.components-reconnect-container[b-1f42o0xh0h] {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1rem;
}

#components-reconnect-modal p[b-1f42o0xh0h] {
    margin: 0;
    text-align: center;
}

#components-reconnect-modal button[b-1f42o0xh0h] {
    border: 0;
    background-color: #6b9ed2;
    color: white;
    padding: 4px 24px;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-1f42o0xh0h] {
        background-color: #3b6ea2;
    }

    #components-reconnect-modal button:active[b-1f42o0xh0h] {
        background-color: #6b9ed2;
    }

.components-rejoining-animation[b-1f42o0xh0h] {
    position: relative;
    width: 80px;
    height: 80px;
}

    .components-rejoining-animation div[b-1f42o0xh0h] {
        position: absolute;
        border: 3px solid #0087ff;
        opacity: 1;
        border-radius: 50%;
        animation: components-rejoining-animation-b-1f42o0xh0h 1.5s cubic-bezier(0, 0.2, 0.8, 1) infinite;
    }

        .components-rejoining-animation div:nth-child(2)[b-1f42o0xh0h] {
            animation-delay: -0.5s;
        }

@keyframes components-rejoining-animation-b-1f42o0xh0h {
    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/Home.razor.rz.scp.css */
/*
   The page shell: a full-height flex column holding the window area above
   the drawer.

   Here rather than in app.css, because a global rule with exactly one
   consumer belongs with that consumer. DO NOT put Bootstrap utilities on the
   same element - `d-flex flex-column h-100 w-100` says the same four things
   with `!important`, so every declaration here except the two overflows
   would be overridden by a copy of itself. This rule is the single owner,
   which is the point:
   three mechanisms setting one layout is how they come to disagree.

   The vignette lives on <body> alongside the colour wash it belongs with -
   see the note there for why splitting them across two elements makes the
   backdrop arrive in two visible pieces.
*/
.radial_background[b-96sbtjsgef] {
    display: flex;
    flex-direction: column;
    overflow-x: hidden;
    overflow-y: hidden;
    height: 100%;
    width: 100%;
}

/*
   min-height: 0 is the load-bearing one and is not tidiness: a flex item's
   automatic minimum size is its content, so without it a tall window refuses
   to shrink and pushes the drawer off the bottom of the screen.

   It was also spelled twice more on the element itself, as Bootstrap's
   `flex-grow-1` and a hand-rolled `min-h-0` utility in app.css that Bootstrap
   does not ship. Both were redundant - this rule is an element selector plus
   a scope attribute, so it outranks a bare class either way - and both are
   gone.
*/
main[b-96sbtjsgef] {
    position: relative;
    flex: 1 1 auto;
    min-height: 0;
    overflow: visible;
    margin: 0px;
}
/* /Components/Sections/AccountUpdateReadForm.razor.rz.scp.css */
/*
    View Update: the sentence, when, the room an entry is about and its
    buttons, and the two sides.

    THE SIDES WRAP rather than squeeze. Two cards sit side by side where there
    is room and stack on a phone; a fixed two-column grid would cut a long name
    at 375px, and which is wider is not something this stylesheet knows.

    THE FACE IS THE 64-SQUARE the list draws at 48, shown at the size it was cut
    to, so it is never scaled up.
*/
.update_read_what[b-dtzj3hicwn]
{
    margin-top: 0.5rem;
    margin-bottom: 0.25rem;
    overflow-wrap: break-word;
}

.update_read_what strong[b-dtzj3hicwn]
{
    margin-right: 0.35em;
}

.update_read_when[b-dtzj3hicwn]
{
    margin-bottom: 0.75rem;
}

.update_read_sides[b-dtzj3hicwn]
{
    display: flex;
    flex-wrap: wrap;
    gap: 12px;
}

.update_read_side[b-dtzj3hicwn]
{
    flex: 1 1 14rem;
    min-width: 0;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    padding: 12px;
    border: 1px solid var(--bs-border-color);
    border-radius: 8px;
}

.update_read_side_heading[b-dtzj3hicwn]
{
    margin: 0;
    opacity: 0.75;
}

.update_read_face[b-dtzj3hicwn]
{
    width: 64px;
    height: 64px;
    border-radius: 50%;
    object-fit: cover;
}

.update_read_placeholder[b-dtzj3hicwn]
{
    display: flex;
    align-items: center;
    justify-content: center;
}

.update_read_name[b-dtzj3hicwn]
{
    font-weight: 600;
    overflow-wrap: anywhere;
}

.update_read_side_actions[b-dtzj3hicwn]
{
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

.update_read_room[b-dtzj3hicwn]
{
    margin-bottom: 0.25rem;
    overflow-wrap: break-word;
}

.update_read_room_actions[b-dtzj3hicwn]
{
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-bottom: 0.5rem;
}
/* /Components/Sections/BatchReadList.razor.rz.scp.css */
/*
   One batch line drawn whole, below View Batch's grid.

   It wraps rather than scrolling sideways, because the point of drawing it is
   that all of it is on screen: pre-wrap keeps the indentation JSON is laid out
   with, and overflow-wrap breaks a token longer than the window - a long id or
   an address with no spaces - which would otherwise push the dialog past the
   screen's edge. It is bounded in height and scrolls inside itself, so a line
   of a few thousand characters does not make the dialog taller than the screen.

   contain: inline-size, as string_editor_grid gives the dialog's sentences,
   because the dialog is sized by its grid: without it the longest line here
   would be the width the dialog asks for.
*/
.batch_line_whole[b-zvvc53f0n3] {
    contain: inline-size;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    max-height: 24rem;
    overflow-y: auto;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--bs-border-color);
    border-radius: var(--bs-border-radius);
}
/* /Components/Sections/ChangeLogList.razor.rz.scp.css */
/*
    The releases of the Change Log: a day's heading over its notes, each note
    a rule's width apart, with Change and Remove under the note where they are
    granted. The note's own type is RichTextView's .rich_text, in app.css.
*/

.change_log_release[b-5j0aj7i2xd] {
    margin-bottom: 1.5rem;
}

.change_log_day[b-5j0aj7i2xd] {
    font-size: 1.1rem;
    margin-bottom: 0.5rem;
}

.change_log_note[b-5j0aj7i2xd] {
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--bs-border-color-translucent);
}

.change_log_note_actions[b-5j0aj7i2xd] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-top: 0.25rem;
}
/* /Components/Sections/ChatRoomForm.razor.rz.scp.css */
/*
   One chat room: a transcript, who is in it, and a box to type in.

   THE ROOM FILLS THE WINDOW AND ITS TWO LISTS SCROLL, which is the one thing
   this stylesheet is really for. A conversation and a member list both grow
   without limit, and a window that grew with them would push the composer off
   the bottom - so the height chain is definite the whole way down and each list
   carries its own overflow.

   `min-height: 0` appears on every flex item in that chain deliberately. A flex
   item's automatic minimum is its CONTENT's min-content height, so an item
   holding a long transcript refuses to be smaller than the transcript - the box
   grows, its own `overflow-y` never engages, and the scrollbar appears on the
   window instead. It costs nothing until content would overflow, which is why
   it reads as decoration and is not.

   THE MEMBERS ARE A COLUMN ON WIDE AND A STRIP ON NARROW. A 375px phone has no
   room for a sidebar beside a conversation, and the answer is not a narrower
   sidebar - it is putting the faces above the words, where they are still a
   list and still scroll. One media query, no class toggling.

   ::deep ONLY UNDER .chatroom_said AND .chatroom_message. Every other element
   these rules select is rendered by this section's own markup, so isolation
   stamps the scope attribute on a subject that carries it. A line's words and
   pictures are RichTextView's and the composer is RichTextEditor's - Quill's,
   underneath - so a rule about them reaches through the section's own box
   with ::deep; without it the failure is silent, since it ships and matches
   nothing. A Join button is this section's own markup, handed to the view.
*/
.chatroom[b-kvmfdsnq7a] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    height: 100%;
    min-height: 0;
}

/*
   The sentence above the conversation. Not hidden at any width: "everybody here
   sees everything you say" is the one thing somebody entering a room has to
   know before they type, and a narrow screen is not a reason to stop saying it.
*/
.chatroom_explained[b-kvmfdsnq7a] {
    flex: 0 0 auto;
    margin: 0;
    font-size: 0.75rem;
}

/*
   The transcript and the member list, side by side.

   Column first because that is the phone, and the query below turns it. Both
   children are scrollers, so this is where the definite height has to stop
   growing - flex: 1 1 auto takes what the window has left after the sentence
   and the composer, and min-height: 0 is what lets it be less than its
   contents.
*/
.chatroom_body[b-kvmfdsnq7a] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 8px;
    min-height: 0;
}

/*
   What has been said.

   Ordered SECOND in the markup and FIRST on screen at every width, which is
   what `order` is doing on the member list rather than here. The reading order
   a screen reader takes is the markup's, and "here is the conversation, and
   here is who is in it" is the right one to hear.
*/
.chatroom_transcript[b-kvmfdsnq7a] {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    padding: 4px 8px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.03);
}

/*
   One line: the face's column, and beside it what was said.

   The column is 64px on every line, the face drawn only on the first of a run,
   so a run's words line up under its first line's. The first line of a run
   stands a little apart from the line above it, which is what tells two
   speakers' runs apart before the faces do.
*/
.chatroom_line[b-kvmfdsnq7a] {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 1px 0;
}

.chatroom_line_first[b-kvmfdsnq7a] {
    padding-top: 8px;
}

.chatroom_line_face[b-kvmfdsnq7a] {
    flex: 0 0 64px;
    width: 64px;
}

.chatroom_line_icon[b-kvmfdsnq7a] {
    display: block;
    width: 64px;
    height: 64px;
    border-radius: 8px;
    object-fit: cover;
}

/* The words beside the face. min-width: 0, or a long line pushes the transcript wider than its box. */
.chatroom_line_body[b-kvmfdsnq7a] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/* The first line's name and time. */
.chatroom_line_header[b-kvmfdsnq7a] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px;
}

/*
   What was said, then the time where the header does not carry it, then
   Report. flex-wrap, so a long sentence wraps rather than pushing the time off
   the side - which nothing reports, because the transcript scrolls vertically
   and not horizontally.
*/
.chatroom_line_content[b-kvmfdsnq7a] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px;
}

/*
   The clock. Fixed-width digits so the names line up down the list rather than
   stepping in and out with the width of "1" against "11".
*/
.chatroom_when[b-kvmfdsnq7a] {
    flex: 0 0 auto;
    font-size: 0.7rem;
    font-variant-numeric: tabular-nums;
    opacity: 0.5;
}

.chatroom_who[b-kvmfdsnq7a] {
    flex: 0 0 auto;
    font-weight: 600;
}

/*
   A speaker's name that opens their profile. A button stripped to the text, as
   the face is, so it reads as the same bold name with an underline on hover;
   the focus ring is app.css's.
*/
.chatroom_who_button[b-kvmfdsnq7a] {
    padding: 0;
    border: 0;
    background: none;
    color: inherit;
    font: inherit;
    font-weight: 600;
    text-align: start;
    cursor: pointer;
}

.chatroom_who_button:hover[b-kvmfdsnq7a] {
    text-decoration: underline;
}

/*
   break-word, NOT anywhere.

   `anywhere` counts toward the element's intrinsic min-content width, so a flex
   item carrying it can be squeezed to one character and will be. `break-word`
   breaks a word that has already overflowed and leaves min-content alone.
   Sessions uses `anywhere` on purpose - an IPv6 address is one unbreakable
   token - and a sentence somebody typed is not that.

   min-width: 0 as well, or a pasted URL with no spaces in it pushes the line
   wider than the transcript.
*/
.chatroom_said[b-kvmfdsnq7a] {
    flex: 1 1 12rem;
    min-width: 0;
    overflow-wrap: break-word;
}

/*
   A picture in a line is its 64 square, side by side with the others, and a
   quote sits close to the words around it, since a line is a sentence rather
   than a page.
*/
.chatroom_said[b-kvmfdsnq7a]  img.rich_text_picture {
    width: 64px;
    height: 64px;
    object-fit: cover;
}

.chatroom_said[b-kvmfdsnq7a]  .rich_text_picture_press,
.chatroom_said[b-kvmfdsnq7a]  img.rich_text_picture {
    margin: 2px 4px 2px 0;
}

.chatroom_said[b-kvmfdsnq7a]  .rich_text_picture_press img.rich_text_picture {
    margin: 0;
}

.chatroom_said[b-kvmfdsnq7a]  .rich_text blockquote {
    margin: 2px 0;
    padding-left: 0.6rem;
}

/* A picture taken off its profile since: said quietly, where it stood. */
.chatroom_said[b-kvmfdsnq7a]  .rich_text_picture_gone {
    font-style: italic;
    opacity: 0.6;
}

/*
   An arrival or a departure. Quieter than what people actually said, because it
   is chrome inside the conversation rather than part of it.
*/
.chatroom_event[b-kvmfdsnq7a] {
    flex: 1 1 12rem;
    min-width: 0;
    font-style: italic;
    opacity: 0.6;
    overflow-wrap: break-word;
}

/*
   A message this reader has chosen not to see, and the way to see it anyway.

   Drawn at all rather than dropped: the service sends every word and marks the
   ones above this reader's own ignore threshold, so withholding it is a
   decision made here - and one that can be undone without asking the server
   again.
*/
.chatroom_ignored[b-kvmfdsnq7a] {
    flex: 0 1 auto;
    font-style: italic;
    opacity: 0.5;
}

.chatroom_reveal[b-kvmfdsnq7a] {
    flex: 0 0 auto;
    padding: 0;
    font-size: 0.75rem;
}

/* Report on somebody else's line: small and last, so it never pushes the words aside. */
.chatroom_report[b-kvmfdsnq7a] {
    flex: 0 0 auto;
    margin-left: auto;
    padding: 0;
    font-size: 0.75rem;
    opacity: 0.7;
}

/*
   Who is in the room.

   A STRIP AT PHONE WIDTH: a bounded height with its own scroller, above the
   conversation. `max-height` in rem rather than a line count, because a name
   that wraps to two lines would otherwise make the strip taller than the
   conversation below it.
*/
.chatroom_members[b-kvmfdsnq7a] {
    display: flex;
    flex: 0 0 auto;
    flex-direction: column;
    gap: 4px;
    max-height: 9rem;
    padding: 4px 8px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.03);
}

.chatroom_members_heading[b-kvmfdsnq7a] {
    flex: 0 0 auto;
    margin: 0;
    font-size: 0.75rem;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.6;
}

.chatroom_members_empty[b-kvmfdsnq7a] {
    margin: 0;
    font-size: 0.75rem;
}

/*
   The faces themselves, and the only thing in the window that scrolls
   independently of the transcript.

   A ROW THAT WRAPS ON NARROW and a column on wide, which is the same list
   answering two shapes: a strip of faces across the top of a phone, and a
   named list down the side of a desktop.
*/
.chatroom_members_list[b-kvmfdsnq7a] {
    display: flex;
    flex: 1 1 auto;
    flex-wrap: wrap;
    align-content: flex-start;
    gap: 8px;
    min-height: 0;
    overflow-y: auto;
}

.chatroom_member[b-kvmfdsnq7a] {
    display: flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/*
   The reader's own row.

   The NAME already says "(you)", so this is emphasis and not the information -
   a colour on its own would say nothing to anybody who cannot see it, and would
   say nothing at all in the member strip of a phone where the row is one face.
*/
.chatroom_member_self .chatroom_member_name[b-kvmfdsnq7a] {
    font-weight: 600;
}

/*
   THE FACE IS A BUTTON, and it carries none of the chrome one usually has.

   A button element rather than a click handler on the image, because the
   keyboard and a screen reader both need it to be one - an <img> with an
   onclick is reachable by a mouse and by nothing else. The padding and border
   are stripped rather than the element being changed, and the focus ring is
   left to app.css so it matches every other focusable thing here.
*/
.chatroom_face_button[b-kvmfdsnq7a] {
    display: block;
    flex: 0 0 auto;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: none;
    cursor: pointer;
    line-height: 0;
}

.chatroom_face[b-kvmfdsnq7a] {
    width: 32px;
    height: 32px;
    border-radius: 6px;
    object-fit: cover;
}

/*
   A member's name. It gives before the face does - a squeezed picture is a
   picture nobody recognises, and a clipped name is still most of a name.
*/
.chatroom_member_name[b-kvmfdsnq7a] {
    flex: 1 1 auto;
    min-width: 0;
    font-size: 0.8rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/*
   The box to type in. Pinned below both lists at every width, because a
   composer that scrolls with the conversation is a composer somebody has to go
   and find.
*/
.chatroom_composer[b-kvmfdsnq7a] {
    display: flex;
    flex: 0 0 auto;
    align-items: flex-end;
    gap: 8px;
}

/*
   The composer's text starts one line tall and grows to a few before it
   scrolls, where a body's editor starts at 8rem: a line is a sentence, and a
   tall box would take the conversation's room. A picture placed in it is its
   64, as the line will draw it.
*/
.chatroom_message[b-kvmfdsnq7a]  .rich_text_editor .ql-editor {
    min-height: 2.5rem;
    max-height: 8rem;
    overflow-y: auto;
}

.chatroom_message[b-kvmfdsnq7a]  .rich_text_editor img.rich_text_picture {
    width: 64px;
    height: 64px;
    object-fit: cover;
}

/*
   `flex: 1 1 6rem` rather than `flex: 1`. The shorthand on its own is
   flex-basis: 0, so the field claims no width of its own and is shrunk away by
   the button beside it instead of pushing it onto a second line. A real basis
   is a WRAPPING THRESHOLD rather than a width - it still grows into whatever is
   left - and 6rem is where a message box stops being usable.
*/
.chatroom_message[b-kvmfdsnq7a] {
    flex: 1 1 6rem;
    min-width: 0;
}

/*
   flex-shrink: 0, so the button is never squeezed narrower than its label. The
   field above is the one that is supposed to give.
*/
.chatroom_send[b-kvmfdsnq7a] {
    flex: 0 0 auto;
}

/*
   WIDE ENOUGH FOR A SIDEBAR.

   48rem rather than a device name: what decides this is whether a 14rem column
   can sit beside a conversation and leave it readable, which is a question
   about the window and not about the hardware. Note a room is MAXIMIZED, so the
   window is the viewport - a query on the viewport is the right question here
   and would not be inside a dialog.
*/
@media (min-width: 48rem) {

    .chatroom_body[b-kvmfdsnq7a] {
        flex-direction: row;
    }

    .chatroom_transcript[b-kvmfdsnq7a] {
        order: 1;
    }

    /*
       The sidebar. A declared basis this time, because at this width there IS
       room to pay one - and the column stops growing so the conversation keeps
       everything else.
    */
    .chatroom_members[b-kvmfdsnq7a] {
        flex: 0 0 14rem;
        order: 2;
        max-height: none;
        min-height: 0;
    }

    /*
       One face per line down the side, where the strip above wrapped them.
       nowrap as well as column, or a name that is wider than the column starts
       a second column of its own.
    */
    .chatroom_members_list[b-kvmfdsnq7a] {
        flex-direction: column;
        flex-wrap: nowrap;
    }

    .chatroom_member[b-kvmfdsnq7a] {
        width: 100%;
    }
}

/*
   The owner's and moderators' buttons and the invite link sit above the
   conversation and never grow, so the transcript keeps whatever height is left.
   The link's field shrinks before its Copy button does, which keeps both on one
   line at 375px.
*/
.chatroom_toolbar[b-kvmfdsnq7a] {
    display: flex;
    flex: 0 0 auto;
    flex-wrap: wrap;
    gap: 6px;
}

.chatroom_invite[b-kvmfdsnq7a] {
    display: flex;
    flex: 0 0 auto;
    flex-direction: column;
    gap: 4px;
}

.chatroom_invite_row[b-kvmfdsnq7a] {
    display: flex;
    gap: 6px;
    min-width: 0;
}

.chatroom_invite_row input[b-kvmfdsnq7a] {
    flex: 1 1 auto;
    min-width: 0;
}

/* Remove and Block beside a name: an icon each, since the sidebar is 14rem wide. */
.chatroom_member_action[b-kvmfdsnq7a] {
    flex: 0 0 auto;
    padding: 0 2px;
    line-height: 1;
}

/* An invite link inside a line, drawn as a small button sitting on the text's baseline. */
.chatroom_link[b-kvmfdsnq7a] {
    margin: 0 2px;
    padding: 0 6px;
    vertical-align: baseline;
}
/* /Components/Sections/ChatRoomSettingsForm.razor.rz.scp.css */
/*
   Chat Room Settings' own rules: what an ask was asked and answered, and the
   search for somebody to invite. The headings, the people and their buttons
   are app.css's, since Update Chat Room draws them too.

   NO ::deep ANYWHERE. Every element these rules select is this section's own
   markup.
*/
.settings_subheading[b-jwexx27wtn] {
    margin: 8px 0 4px;
    font-size: 0.9rem;
}

/* A question and its answer wrap rather than cut: what somebody answered is the point of the row. */
.settings_question[b-jwexx27wtn] {
    margin-top: 4px;
    font-weight: 600;
    overflow-wrap: break-word;
}

.settings_answer[b-jwexx27wtn] {
    overflow-wrap: break-word;
}

.settings_find[b-jwexx27wtn] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 8px;
}

.settings_find .form-group[b-jwexx27wtn] {
    flex: 1 1 10rem;
    min-width: 0;
}
/* /Components/Sections/ChatRoomsForm.razor.rz.scp.css */
/*
   The chat room lobby.

   THE PICTURE LIST'S SHAPE, DELIBERATELY. Both are "a handful of things, each
   with one action", and a second answer would be a second thing to keep in
   step while reading as a mistake rather than a decision. See
   ProfilePictureForm.razor.css for why flex-wrap, min-width: 0 and the written-out
   flex shorthand are load-bearing rather than decoration.

   BUT THIS WINDOW IS MAXIMIZED, WHICH IS THE ONE DIFFERENCE THAT MATTERS. It
   is opened from the launcher, so it gets the whole workspace rather than
   sizing itself to its own content the way a window opened as a dialog does -
   and a declared flex-basis CAN be paid here. `auto` is kept anyway, because it
   is the answer that is right at both widths and a room name is exactly the
   unbounded-length value that made a declared one wrong next door.

   NO ::deep ANYWHERE. Every element these rules select is rendered by this
   section's own markup, so isolation stamps the scope attribute on a subject
   that carries it. A rule whose subject belonged to Section or WindowFrame
   would need ::deep, and the failure is silent - it ships and matches nothing.
*/
.rooms_list[b-3ukiqbiqc3] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

/*
   One room: its name and sentence, then the button.

   flex-wrap is the FLOOR rather than the usual case. A room with a long name
   and a customer's own wording for "Enter" can run out of room on a 375px
   phone, and wrapping the button to a second line is what the picture list
   does at that width - so the two read alike. Without it the button is pushed
   off the side, which nothing reports: .window_content does not scroll for it.
*/
.rooms_row[b-3ukiqbiqc3] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
}

/*
   The name and its sentence, stacked.

   `flex: 1 1 auto` rather than `flex: 1`. The shorthand on its own is
   flex-basis: 0, so the item claims no width of its own and shrinks away
   instead of pushing its neighbour onto a second line - which at 375px renders
   a name one letter per line. That shipped on the profile list once, which is
   why this is written out rather than abbreviated.

   min-width: 0 stays: a flex item's automatic minimum is its content's
   min-content width, so without it a long room name pushes the row wider than
   the window - the opposite failure, and equally invisible on a desktop.
*/
.rooms_detail[b-3ukiqbiqc3] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/*
   break-word, NOT anywhere.

   `anywhere` counts toward the element's intrinsic min-content width, so a
   flex item carrying it can be squeezed to one character and will be.
   `break-word` breaks a word that has already overflowed and leaves
   min-content alone. Sessions uses `anywhere` on purpose - an IPv6 address is
   one unbreakable token - and a room name is not that.
*/
.rooms_name[b-3ukiqbiqc3] {
    font-weight: 600;
    overflow-wrap: break-word;
}

/*
   The room's own sentence, when it has one. Most do not.

   Quieter than the name and NOT hidden at any width: it is the only thing on
   the row that says what a room is for, and somebody choosing which to enter
   is exactly who needs it. Same size and opacity as the picture list's access
   line, so the two lists' second lines match.
*/
.rooms_description[b-3ukiqbiqc3] {
    font-size: 0.75rem;
    opacity: 0.6;
    overflow-wrap: break-word;
}

/*
   The button, PINNED RIGHT.

   margin-left: auto is what puts it against the edge rather than immediately
   after a short room name, so the buttons line up down the list however long
   each name is.

   flex-shrink: 0 so it is never squeezed narrower than its label - a button
   that yields is a button whose text clips, and the name column above is the
   one that is supposed to give.
*/
.rooms_actions[b-3ukiqbiqc3] {
    display: flex;
    flex-shrink: 0;
    gap: 6px;
    margin-left: auto;
}

/*
   The search box, its button and Start a Room, on one line where they fit.

   The box takes what is left (flex: 1 1 12rem, written out for the reason
   .rooms_detail gives) and wraps the buttons under it on a phone rather than
   squeezing itself to nothing.
*/
.rooms_toolbar[b-3ukiqbiqc3] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 12px;
}

.rooms_search[b-3ukiqbiqc3] {
    flex: 1 1 12rem;
    min-width: 0;
}

/* Start a Room sits at the far end, like a row's buttons. */
.rooms_start[b-3ukiqbiqc3] {
    margin-left: auto;
}

/*
   A list's heading - Your rooms, In the lobby, or what a search was for.

   An h3 at body size: these divide one window's content rather than titling a
   page, and the browser's own h3 would shout over the rooms beneath it.
*/
.rooms_heading[b-3ukiqbiqc3] {
    margin: 16px 0 0;
    font-size: 1rem;
    font-weight: 600;
}

/* A search's heading with its way back beside it. */
.rooms_heading_row[b-3ukiqbiqc3] {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 8px;
}

/* How many people are in the room right now - the same quiet line as the room's own sentence. */
.rooms_present[b-3ukiqbiqc3] {
    font-size: 0.75rem;
    opacity: 0.6;
}
/* /Components/Sections/EmployeeFieldsForm.razor.rz.scp.css */
/*
    Employee Fields' tables borrow version_history from app.css, whose first
    column stays on one line for the dates it was made for. A field's name is
    words, so it wraps here.

    EVERY SECTION'S TABLE HAS THE SAME COLUMNS, so Filed Under and Product
    Default line up down the whole window. Each section is a table of its own,
    and an automatic layout sizes each by its own longest field name, which
    started the selects at a different place in each. A fixed layout takes the
    widths from the col elements instead, and every table is the window's
    width, so the same percentages put the same edges in the same place.

    On a phone the table keeps a width its select can be read at and scrolls
    sideways inside its own box rather than squeezing the control.
*/
.employee_fields[b-u0roz45qzs] {
    table-layout: fixed;
    min-width: 34rem;
}

.employee_fields td:first-child[b-u0roz45qzs] {
    white-space: normal;
}

.employee_fields_field[b-u0roz45qzs] {
    width: 40%;
}

.employee_fields_filed_under[b-u0roz45qzs] {
    width: 35%;
}

.employee_fields_product_default[b-u0roz45qzs] {
    width: 25%;
}
/* /Components/Sections/EmployeePtoCalendarForm.razor.rz.scp.css */
/*
    PTO Calendar's month. Seven columns that share the width, so a month fits a
    375px phone without scrolling sideways; a day is a button, so it keeps the
    aura every button wears, and its count wraps under the number rather than
    widening the cell.
*/
.pto_calendar_bar[b-zqavy23lpo] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.75rem;
}

.pto_calendar_month[b-zqavy23lpo] {
    min-width: 9rem;
    text-align: center;
}

.pto_calendar_grid[b-zqavy23lpo] {
    display: grid;
    grid-template-columns: repeat(7, minmax(0, 1fr));
    gap: 5px;
}

.pto_calendar_weekday[b-zqavy23lpo] {
    text-align: center;
    font-size: 0.8rem;
}

.pto_calendar_day[b-zqavy23lpo] {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    min-height: 3.25rem;
    padding: 0.25rem 0.125rem;
}

.pto_calendar_count[b-zqavy23lpo] {
    font-size: 0.7rem;
    line-height: 1.1;
    overflow-wrap: break-word;
}

.pto_calendar_list[b-zqavy23lpo] {
    padding-left: 1.25rem;
}
/* /Components/Sections/MbtiForm.razor.rz.scp.css */
/*
   The personality test's question and result screens.

   NO ::deep ANYWHERE IN THIS FILE. Every element selected here is one Mbti's own
   markup renders, so isolation stamps the scope attribute onto a subject that
   carries it. A rule reaching into anything Section or WindowFrame draws would
   need ::deep, and would otherwise ship and match nothing.

   NOTHING HERE GIVES A BUTTON A LOOK OF ITS OWN. The answers wear
   .btn.btn-secondary and take their fill, their rim and all three aura states
   from app.css; what this file adds is the one thing the button system has no
   opinion about, which is how a button that is CHOSEN and stays chosen should
   read.
*/

/*
   ROOM FOR THE FOCUS RING - see --aura-reach in app.css.

   Every block here that holds buttons leaves that much clear inside its own box
   rather than relying on a clip margin, because overflow-clip-margin is
   unimplemented in WebKit and is therefore a bonus rather than a guarantee.
*/
.mbti_actions[b-it32967pbw] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 24px;
    padding: var(--aura-reach);
}

/* -- Progress ---------------------------------------------------------- */

.mbti_progress[b-it32967pbw] {
    margin-top: 8px;
}

.mbti_progress_track[b-it32967pbw] {
    height: 6px;
    border: 1px solid var(--aura-border);
    border-radius: 3px;
    background-color: rgba(255, 255, 255, 0.04);
    overflow: hidden;
}

/*
   The fill is the aura's own hue rather than a colour of its own, so the one
   moving thing on the question screen belongs to the same palette as everything
   pressable on it.
*/
.mbti_progress_fill[b-it32967pbw] {
    display: block;
    height: 100%;
    background-color: rgba(var(--aura-hue), 0.7);
    transition: width 0.2s ease-out;
}

.mbti_progress_text[b-it32967pbw] {
    margin: 8px 0 0 0;
    font-size: 0.875rem;
}

/* -- The question ------------------------------------------------------ */

.mbti_stem[b-it32967pbw] {
    margin: 20px 0 0 0;
    font-size: 1.125rem;
    line-height: 1.5;
}

.mbti_hint[b-it32967pbw] {
    margin: 4px 0 0 0;
    font-size: 0.875rem;
}

/*
   The pressure block's framing.

   Bordered on the leading edge only rather than boxed: a full box reads as an
   alert, and this is not a warning about anything - it is a change of subject.
   border-inline-start so it stays on the reading edge under a right-to-left
   language.
*/
.mbti_pressure_note[b-it32967pbw] {
    margin: 16px 0 0 0;
    padding: 8px 0 8px 12px;
    border-inline-start: 2px solid rgba(var(--aura-hue), 0.6);
    font-size: 0.9375rem;
    line-height: 1.5;
}

.mbti_pressure_label[b-it32967pbw] {
    margin: 16px 0 0 0;
    font-size: 0.75rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    color: rgba(var(--aura-hue), 0.9);
}

/*
   ONE COLUMN, ALWAYS.

   The agreement ladder is an ORDER - strongly disagree through to strongly
   agree - and an order only reads as one when it runs in a single direction. A
   grid that reflowed to two columns on a wide window would put "neither" at the
   top of the second column and break the sequence, which is why this is a
   column at every width rather than the auto-fill grid the Settings menu uses.
*/
.mbti_choices[b-it32967pbw] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 16px;
    padding: var(--aura-reach);
}

/*
   An answer.

   text-align: left because Bootstrap centres button text, and a centred block of
   two or three lines of prose has a ragged left edge that is hard to read down.
   white-space: normal for the same reason - .btn sets nowrap, which a written-out
   scenario answer would overflow.
*/
.mbti_choice[b-it32967pbw] {
    text-align: left;
    white-space: normal;
    line-height: 1.4;
}

/*
   CHOSEN.

   Keyed on aria-checked rather than on a class, exactly as CheckBox does, so the
   picture and what a screen reader is told cannot disagree - there is no second
   piece of state that could be set without the other.

   The rim goes gold and the glow goes to its hover strength, which is the
   design system's own ACTIVE state made to persist. That is deliberate reuse
   rather than a new look: gold-means-this already reads as "the one" from every
   other button in the application, and it leaves the fill exactly where it was,
   which is the rule the whole button system rests on.
*/
.mbti_choice[aria-checked="true"][b-it32967pbw] {
    border-color: var(--aura-border-active);
    box-shadow: var(--aura-hover);
}

/* -- The result -------------------------------------------------------- */

.mbti_result[b-it32967pbw] {
    text-align: center;
}

.mbti_code[b-it32967pbw] {
    margin: 0;
    font-size: 3rem;
    font-weight: 600;
    letter-spacing: 0.15em;
    /*
       The gold the aura is built from. The four letters are the one thing on
       this screen somebody came for, and it is the only place in the window
       where that colour is used on text rather than on a rim or a glow.
    */
    color: rgba(var(--aura-hue), 1);
}

.mbti_name[b-it32967pbw] {
    margin: 0;
    font-size: 1.25rem;
}

/*
   The two-sentence description of the type. Capped and centred rather than
   filling the window, because a maximized window on a wide screen would
   otherwise run this to one very long line, and a measure of about 60 characters
   is where prose stops being hard to track back from.
*/
.mbti_summary[b-it32967pbw] {
    margin: 12px auto 0 auto;
    max-width: 40rem;
    line-height: 1.55;
}

.mbti_confidence[b-it32967pbw] {
    margin: 8px 0 0 0;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.mbti_heading[b-it32967pbw] {
    margin-top: 32px;
}

/* -- The stack --------------------------------------------------------- */

/*
   list-style: none on an <ol> and not a <ul>, because the ORDER is the content
   here - a stack is four functions in the order somebody reaches for them, and
   a screen reader announcing "list of 4" rather than "4 items in order" would
   lose the only thing being said. The markers are dropped because each row
   already carries its position as a word.
*/
.mbti_stack[b-it32967pbw] {
    list-style: none;
    margin: 8px 0 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 12px;
}

    .mbti_stack > li[b-it32967pbw] {
        display: grid;
        grid-template-columns: 6.5rem 1fr;
        gap: 2px 12px;
        align-items: baseline;
    }

.mbti_stack_position[b-it32967pbw] {
    grid-row: span 2;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

.mbti_stack_name[b-it32967pbw] {
    font-weight: 600;
}

.mbti_stack_description[b-it32967pbw] {
    grid-column: 2;
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
}

/* -- The eight bars ---------------------------------------------------- */

.mbti_bars[b-it32967pbw] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

/*
   The name column collapses below 480px rather than the bar doing so: a bar too
   short to compare against its neighbours says nothing, while the two-letter
   code alone is still enough to read the order off. min-content on the code
   keeps "Se" and "Ni" on the same left edge.
*/
.mbti_bar[b-it32967pbw] {
    display: grid;
    grid-template-columns: 2rem minmax(0, 18rem) 1fr 3rem;
    gap: 12px;
    align-items: center;
}

.mbti_bar_code[b-it32967pbw] {
    font-weight: 600;
}

.mbti_bar_head[b-it32967pbw] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.mbti_bar_name[b-it32967pbw] {
    font-size: 0.875rem;
    font-weight: 600;
}

.mbti_bar_gloss[b-it32967pbw] {
    font-size: 0.8125rem;
    line-height: 1.35;
    color: var(--bs-secondary-color);
}

.mbti_bar_track[b-it32967pbw] {
    display: block;
    height: 10px;
    border: 1px solid var(--aura-border);
    border-radius: 5px;
    background-color: rgba(255, 255, 255, 0.04);
    overflow: hidden;
}

.mbti_bar_fill[b-it32967pbw] {
    display: block;
    height: 100%;
    background-color: rgba(var(--aura-hue), 0.7);
}

.mbti_bar_value[b-it32967pbw] {
    font-size: 0.875rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

/* -- All sixteen ------------------------------------------------------- */

/*
   An <ol> because the ORDER is the whole content - this is a ranking, and the
   number beside each row is what it ranked at. Markers dropped because each row
   already carries its own score.
*/
.mbti_ranking[b-it32967pbw] {
    list-style: none;
    margin: 12px 0 0 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 6px;
}

    .mbti_ranking > li[b-it32967pbw] {
        display: grid;
        grid-template-columns: 3.25rem minmax(0, 10rem) 1fr 2rem;
        gap: 12px;
        align-items: center;
    }

.mbti_rank_code[b-it32967pbw] {
    font-weight: 600;
    letter-spacing: 0.04em;
}

.mbti_rank_name[b-it32967pbw] {
    font-size: 0.875rem;
    color: var(--bs-secondary-color);
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.mbti_rank_track[b-it32967pbw] {
    display: block;
    height: 8px;
    border: 1px solid var(--aura-border);
    border-radius: 4px;
    background-color: rgba(255, 255, 255, 0.04);
    overflow: hidden;
}

.mbti_rank_fill[b-it32967pbw] {
    display: block;
    height: 100%;
    background-color: rgba(var(--aura-hue), 0.45);
}

.mbti_rank_value[b-it32967pbw] {
    font-size: 0.875rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
    color: var(--bs-secondary-color);
}

/*
   The winning row. Full-strength fill and no dimming on the text, so the row
   the four letters at the top came from is findable in a list of sixteen
   without having to count down from the first.
*/
.mbti_rank_best .mbti_rank_fill[b-it32967pbw] {
    background-color: rgba(var(--aura-hue), 0.85);
}

.mbti_rank_best .mbti_rank_name[b-it32967pbw],
.mbti_rank_best .mbti_rank_value[b-it32967pbw] {
    color: inherit;
}

@media (max-width: 480px) {
    .mbti_bar[b-it32967pbw] {
        grid-template-columns: 2rem 1fr 3rem;
    }

    /*
       The gloss and the function's full name go, not the bar. A bar too short
       to compare against its neighbours says nothing, while the two-letter code
       alone is still enough to read the order off.
    */
    .mbti_bar_head[b-it32967pbw] {
        display: none;
    }

    .mbti_ranking > li[b-it32967pbw] {
        grid-template-columns: 3.25rem 1fr 2rem;
    }

    .mbti_rank_name[b-it32967pbw] {
        display: none;
    }

    .mbti_code[b-it32967pbw] {
        font-size: 2.25rem;
    }
}

/*
   The progress fill is the only transitioned property in this window, and it
   moves because a bar that jumps between two widths reads as the layout
   changing rather than as progress being made. Honoured for anyone who has
   asked for less motion.
*/
@media (prefers-reduced-motion: reduce) {
    .mbti_progress_fill[b-it32967pbw] {
        transition: none;
    }
}
/* /Components/Sections/PictureChooserList.razor.rz.scp.css */
/*
   Choose a Picture's gallery: three squares across under each heading, as a
   phone's gallery draws them, and the whole list scrolling inside the window
   so a long one never pushes the window off the screen.
*/
.picture_chooser[b-xb8o7iys6i] {
    max-height: 60vh;
    overflow-y: auto;
    padding: var(--aura-reach);
}

.picture_chooser_heading[b-xb8o7iys6i] {
    margin: 0.75rem 0 0.25rem;
    font-size: 0.9rem;
    font-weight: 600;
}

.picture_chooser_heading:first-child[b-xb8o7iys6i] {
    margin-top: 0;
}

/* Three across whatever the window's width, each column the square's size. */
.picture_chooser_grid[b-xb8o7iys6i] {
    display: grid;
    grid-template-columns: repeat(3, 64px);
    gap: 8px;
}

.picture_chooser_choice[b-xb8o7iys6i] {
    width: 64px;
    height: 64px;
    padding: 0;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 6px;
    overflow: hidden;
    background: none;
}

.picture_chooser_choice:hover[b-xb8o7iys6i],
.picture_chooser_choice:focus-visible[b-xb8o7iys6i] {
    box-shadow: var(--aura-hover);
}

.picture_chooser_choice img[b-xb8o7iys6i] {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}
/* /Components/Sections/ProfileBlocksForm.razor.rz.scp.css */
/*
   The profiles one profile has blocked.

   CONNECTIONS' SHAPE, AND FOR ITS REASON: every row is a person, so the
   avatar is round and 48px, and somebody moving between the two lists sees
   one idiom. The window is content-sized as that one is, so the detail
   column takes `flex: 1 1 auto` rather than a declared basis -
   ProfileConnectionForm.razor.css has why.

   NO ::deep ANYWHERE. Every element these rules select is rendered by this
   section's own markup.
*/
.blocks_list[b-rallrr10w8] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

/*
   One row: avatar, then the name and when, then Unblock. flex-wrap is the
   floor at 375px, so the button drops to a second line rather than off the
   side.
*/
.blocks_row[b-rallrr10w8] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
}

.blocks_picture[b-rallrr10w8] {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    object-fit: cover;
    background-color: rgba(255, 255, 255, 0.06);
}

/*
   The placeholder for a profile with no cover picture, so every row is the
   same height and the names stay in one column.
*/
.blocks_picture_none[b-rallrr10w8] {
    display: inline-block;
    border: 1px dashed rgba(255, 255, 255, 0.2);
}

/*
   The basis comes from the content, and min-width: 0 keeps a long name from
   pushing the row wider than the window.
*/
.blocks_detail[b-rallrr10w8] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/*
   break-word, not anywhere, which would let the column be squeezed to one
   character.
*/
.blocks_name[b-rallrr10w8] {
    font-weight: 600;
    overflow-wrap: break-word;
}

.blocks_when[b-rallrr10w8] {
    font-size: 0.75rem;
    opacity: 0.6;
}

/*
   Pinned right, and never squeezed narrower than its label.
*/
.blocks_actions[b-rallrr10w8] {
    display: flex;
    flex-shrink: 0;
    margin-left: auto;
}

/*
   The question Unblock asks, above the list, set apart so it reads as a
   question rather than as another row.
*/
.blocks_confirm[b-rallrr10w8] {
    margin-top: 12px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 8px;
}

.blocks_confirm_actions[b-rallrr10w8] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}
/* /Components/Sections/ProfileBlogComments.razor.rz.scp.css */
/*
   The comments under a blog entry: one block per comment, a reply indented
   under the comment at the top of its thread, and each comment's buttons under
   its words, wrapping on a phone rather than going off the side.
*/
.blog_comments[b-r917f60xqq] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.blog_comment[b-r917f60xqq] {
    padding: 8px 10px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
}

/* One level deep, so one step in: a reply answering another reply sits beside it, saying whom it answers. */
.blog_comment_reply[b-r917f60xqq] {
    margin-left: 1.5rem;
}

.blog_comment_answering[b-r917f60xqq] {
    margin-top: 0.25rem;
    font-size: 0.8rem;
    opacity: 0.75;
}

/* The words quoted, as they were when quoted, set off by a rule down the left as a quotation is. */
.blog_comment_quote[b-r917f60xqq] {
    margin: 0.25rem 0;
    padding: 2px 0 2px 8px;
    border-left: 3px solid rgba(255, 255, 255, 0.3);
    opacity: 0.85;
    white-space: pre-wrap;
    overflow-wrap: break-word;
}

.blog_comment_head[b-r917f60xqq] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px;
}

.blog_comment_face[b-r917f60xqq] {
    flex-shrink: 0;
    width: 32px;
    height: 32px;
    border-radius: 50%;
    object-fit: cover;
}

.blog_comment_face_none[b-r917f60xqq] {
    display: inline-block;
    border: 1px dashed rgba(255, 255, 255, 0.2);
}

.blog_comment_name[b-r917f60xqq] {
    font-weight: 600;
    overflow-wrap: break-word;
    min-width: 0;
}

.blog_comment_when[b-r917f60xqq] {
    font-size: 0.75rem;
    opacity: 0.7;
}

/* A comment is plain text, so its own line breaks are kept. */
.blog_comment_text[b-r917f60xqq] {
    margin: 0.25rem 0;
    white-space: pre-wrap;
    overflow-wrap: break-word;
}

/* Withheld rather than dropped, as Chat Room withholds a line: dim and slanted, with a small Show It Anyway beside it. */
.blog_comment_ignored[b-r917f60xqq] {
    font-style: italic;
    opacity: 0.5;
}

.blog_comment_reveal[b-r917f60xqq] {
    padding: 0;
    font-size: 0.75rem;
}

.blog_comment_actions[b-r917f60xqq] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 0.25rem;
}

.blog_comment_box[b-r917f60xqq] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}
/* /Components/Sections/ProfileBlogForm.razor.rz.scp.css */
/*
   The entries on a profile, in Pictures' shape and for its reasons: a handful
   of rows, each with its own actions, in a dialog the content sizes. Read
   ProfilePictureForm.razor.css before changing a flex rule here - it measured
   why the detail column takes its basis from its content and why its words
   break with break-word rather than anywhere.
*/
.blog_list[b-raeiaiznac] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

.blog_row[b-raeiaiznac] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
}

.blog_detail[b-raeiaiznac] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.blog_topic[b-raeiaiznac] {
    font-weight: 600;
    overflow-wrap: break-word;
}

.blog_when[b-raeiaiznac],
.blog_comments[b-raeiaiznac],
.blog_access[b-raeiaiznac] {
    font-size: 0.75rem;
    opacity: 0.7;
}

/* An empty count draws nothing rather than a gap. */
.blog_comments:empty[b-raeiaiznac] {
    display: none;
}

.blog_actions[b-raeiaiznac] {
    display: flex;
    flex-wrap: wrap;
    flex-shrink: 0;
    gap: 6px;
    margin-left: auto;
}
/* /Components/Sections/ProfileBlogReadForm.razor.rz.scp.css */
/*
   One blog entry: when it was written and who may read it, small, above the
   body, and the author's two buttons under it. The body's own typography is
   .rich_text's, in app.css, which RichTextView wears.
*/
.blog_entry_when[b-2u9b17a3dn],
.blog_entry_access[b-2u9b17a3dn] {
    font-size: 0.8rem;
    margin-bottom: 0.25rem;
}

.blog_entry_actions[b-2u9b17a3dn] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 0.75rem;
}
/* /Components/Sections/ProfileConnectionForm.razor.rz.scp.css */
/*
   The connections on a profile.

   PROFILE'S SHAPE AGAIN, AND FOR PROFILE'S REASON. Every row here is a PERSON,
   which is what the profile list holds too - so the avatar is round and 48px,
   and a reader moving between the two windows sees one idiom rather than two.
   Pictures is deliberately square because a photograph is not a person.

   THE WINDOW IS CONTENT-SIZED, so the same trap Pictures documents applies
   here: OpenProgramDialog puts this inside .window_component_host_overlay,
   which is `width: auto`, and a DECLARED flex-basis wider than the content can
   never be paid - the window sizes itself against the content's max-content
   and then breaks lines against the basis. `flex: 1 1 auto` is the answer, not
   a smaller number.

   NO ::deep ANYWHERE. Every element these rules select is rendered by this
   section's own markup, so isolation stamps the scope attribute on a subject
   that carries it. A rule whose subject belonged to Section or WindowFrame
   would need ::deep, and the failure is silent - it ships and matches nothing.
*/
.connections_list[b-l6ac0t3ywu] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

/*
   The heading over each of the three groups.

   A REAL HEADING RATHER THAN A BOLD LINE, because the groups are what this
   window is organized by and a screen reader has to be able to skip between
   them. It is h3 because Section has already opened the window's own heading
   levels above it.

   The top margin is larger than the gap between rows so a group reads as a
   break rather than as another row; the first one keeps it too, since the
   sentence above it is body text.
*/
.connections_heading[b-l6ac0t3ywu] {
    margin-top: 20px;
    margin-bottom: 0;
    font-size: 0.9rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.7;
}

/*
   One row: avatar, then the name and how it is filed, then the actions.

   flex-wrap is the FLOOR, and it is reached rather than theoretical - at 375px
   three buttons beside an avatar and a name need more room than there is, so
   the actions drop to a second line, which is what the profile and picture
   lists do at that width. Without it a button is pushed off the side, and that
   is a failure nothing reports: .window_content does not scroll for it.
*/
.connections_row[b-l6ac0t3ywu] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
}

/*
   48px and round, matching the profile list - see the file header.
*/
.connections_picture[b-l6ac0t3ywu] {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    object-fit: cover;
    background-color: rgba(255, 255, 255, 0.06);
}

/*
   The placeholder for a connection whose profile has no cover picture.

   It exists so every row is the same height and the names stay in one column;
   a row that omitted the image would sit narrower than its neighbours and read
   as a different kind of thing.
*/
.connections_picture_none[b-l6ac0t3ywu] {
    display: inline-block;
    border: 1px dashed rgba(255, 255, 255, 0.2);
}

/*
   THE BASIS COMES FROM THE CONTENT, AND IN A CONTENT-SIZED WINDOW IT HAS TO -
   the whole argument is in ProfilePictureForm.razor.css under .pictures_detail,
   and it is the same window shape here.

   NOT `flex: 1`, which is `flex-basis: 0`: an item with no basis of its own
   shrinks to nothing rather than pushing its neighbours onto a second line,
   and at 375px that renders a name one letter per line. That bug shipped on
   the profile list, which is why the shorthand is written out.

   min-width: 0 stays: a flex item's automatic minimum is its content's
   min-content width, so without it a long name pushes the row wider than the
   window.
*/
.connections_detail[b-l6ac0t3ywu] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/*
   break-word, NOT anywhere.

   `anywhere` counts toward the element's intrinsic min-content width, so a
   flex item carrying it can be squeezed to one character and will be.
   `break-word` breaks a word that has already overflowed and leaves min-content
   alone. Sessions uses `anywhere` on purpose - an IPv6 address is one
   unbreakable token - and copying that rule without its reason is what produced
   a vertical name on the profile list once already.
*/
.connections_name[b-l6ac0t3ywu] {
    font-weight: 600;
    overflow-wrap: break-word;
}

/*
   The presence dot before a name.

   FILLED AND GLOWING FOR ONLINE, A HOLLOW RING FOR OFFLINE, so the two differ
   in shape as well as colour and neither depends on telling green from grey.
   A connection who does not share their presence gets no dot at all - see the
   markup - so the ring never stands for "unknown".

   inline-block and vertical-align: middle keep it on the name's first line
   however the name wraps, and the margin is the gap to the first letter.
*/
.connections_presence[b-l6ac0t3ywu] {
    display: inline-block;
    width: 10px;
    height: 10px;
    margin-right: 6px;
    border-radius: 50%;
    vertical-align: middle;
}

.connections_presence_online[b-l6ac0t3ywu] {
    background-color: #3fb950;
    box-shadow: 0 0 4px rgba(63, 185, 80, 0.7);
}

.connections_presence_offline[b-l6ac0t3ywu] {
    border: 2px solid rgba(255, 255, 255, 0.45);
}

/*
   How this side files them, who may see it, and whether they see you online.

   All three are quiet, because the NAME is what somebody is looking for in a
   list of people. The visibility and the presence line are owner-only - see
   the markup.
*/
.connections_category[b-l6ac0t3ywu],
.connections_access[b-l6ac0t3ywu],
.connections_shared[b-l6ac0t3ywu] {
    font-size: 0.75rem;
    opacity: 0.6;
}

/*
   The row's own actions, PINNED RIGHT.

   margin-left: auto is what puts them against the edge rather than immediately
   after a short name, so the buttons line up down the list however long each
   name is. It also keeps them right on their own line in the case the row has
   wrapped anyway.

   flex-shrink: 0 so the buttons are never squeezed narrower than their labels -
   a button that yields is a button whose text clips, and the name column above
   is the one that is supposed to give.
*/
.connections_actions[b-l6ac0t3ywu] {
    display: flex;
    flex-wrap: wrap;
    flex-shrink: 0;
    gap: 6px;
    margin-left: auto;
}

/*
   The Find people button, under the list with room above it, because it does
   not act on a row - the same separation the profile list gives Set Up A
   Profile.
*/
.connections_add[b-l6ac0t3ywu] {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
}
/* /Components/Sections/ProfileConnectionReadForm.razor.rz.scp.css */
/*
    One side of a connection.

    THE PICTURE IS THE 256-SQUARE, at the one size a profile shows it. Fixed
    rather than responsive: picture_additional sub 3 IS a 256-square, so letting
    it grow would scale a bitmap up. max-width keeps it inside a narrow
    viewport, where 256 is most of the width a phone has.
*/
.connection_picture[b-ux41r45wcy]
{
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}

/*
    ProfileRead's definition list, and deliberately the same one: label above
    value on a phone, two columns where there is room.

    NOT a grid with a fixed first column - a label here can be a tenant's own
    wording, so its length is not something this stylesheet knows. min-content
    lets the column take what the longest label actually needs and no more.

    ELEMENT SELECTORS RATHER THAN CLASSES because isolation already scopes them
    to this section: a bare `dl` here cannot reach any other component's list.
*/
dl[b-ux41r45wcy]
{
    display: grid;
    grid-template-columns: 1fr;
    gap: 2px 12px;
    margin-top: 12px;
    margin-bottom: 0;
}

dt[b-ux41r45wcy]
{
    font-weight: 600;
    opacity: 0.75;
}

dd[b-ux41r45wcy]
{
    margin-bottom: 0.5rem;
    overflow-wrap: break-word;
    min-width: 0;
}

@media (min-width: 30rem)
{
    dl[b-ux41r45wcy]
    {
        grid-template-columns: minmax(min-content, 12rem) 1fr;
    }

    dt[b-ux41r45wcy]
    {
        grid-column: 1;
    }

    dd[b-ux41r45wcy]
    {
        grid-column: 2;
    }
}
/* /Components/Sections/ProfileConnectionSearchForm.razor.rz.scp.css */
/*
   Finding a person to connect to.

   THE RESULT ROWS ARE Connections' ROWS, and the rules below are that file's
   with one column removed - there is no category or visibility to show on
   somebody who is not a connection yet. The reasoning for every value is in
   ProfileConnectionForm.razor.css and is not repeated: round 48px avatar because a
   row is a PERSON, flex-wrap because three items beside an avatar do not fit
   at 375px, `flex: 1 1 auto` because this window is content-sized by
   OpenProgramDialog and a declared basis can never be paid in one.

   A SEPARATE FILE RATHER THAN A SHARED CLASS, because CSS isolation scopes a
   stylesheet to the component that owns it: a rule here naming
   .connections_row would be stamped with THIS window's scope attribute and
   match nothing, silently. Sharing would mean lifting the rules to a global
   stylesheet, which is a bigger decision than two windows.

   NO ::deep ANYWHERE. Every element these rules select is rendered by this
   section's own markup.
*/
.connection_search_list[b-onotpvyvxe] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 16px;
}

.connection_search_row[b-onotpvyvxe] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
}

.connection_search_picture[b-onotpvyvxe] {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    object-fit: cover;
    background-color: rgba(255, 255, 255, 0.06);
}

.connection_search_picture_none[b-onotpvyvxe] {
    display: inline-block;
    border: 1px dashed rgba(255, 255, 255, 0.2);
}

.connection_search_detail[b-onotpvyvxe] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/*
   break-word, NOT anywhere - see ProfileConnectionForm.razor.css.
*/
.connection_search_name[b-onotpvyvxe] {
    font-weight: 600;
    overflow-wrap: break-word;
}

.connection_search_actions[b-onotpvyvxe] {
    display: flex;
    flex-wrap: wrap;
    flex-shrink: 0;
    gap: 6px;
    margin-left: auto;
}
/* /Components/Sections/ProfileForm.razor.rz.scp.css */
/*
   The list of profiles on an account.

   SESSIONS' SHAPE, ON PURPOSE. Both are "a handful of things, each with its own
   actions", and both live where the window is around 360px wide - so the same
   answer applies and a second one would only be a second thing to keep in step.

   NO ::deep ANYWHERE. Every element these rules select is rendered by ProfileForm's
   own markup, so isolation stamps the scope attribute on a subject that carries
   it. A rule whose subject belonged to Section or WindowFrame would need
   ::deep, and the failure is silent - it ships and matches nothing.

   NOTHING HERE STYLES THE BUTTONS. They are Bootstrap .btn and the gold aura
   comes from the .btn rules in wwwroot/app.css, which is where it has to live:
   .btn is somebody else's class worn by a dozen components, so a rule in this
   stylesheet would be scoped to ProfileForm's markup and every other button in the
   application would go without.
*/
.profiles_list[b-jr1ptoi6do] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

/*
   One row: picture, then details, then the actions.

   flex-wrap, and it is not decoration. A name plus three buttons does not fit
   across a phone, so without this the last button is pushed off the side -
   where .window_content does not scroll for it and nothing reports a problem.
   Wrapping puts the actions on a second line under the name instead.
*/
.profiles_row[b-jr1ptoi6do] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
}

/*
   The cover picture at 48px, square and clipped to a circle.

   flex-shrink: 0 so it keeps its size when a long name is competing for the
   row, and object-fit: cover so a rendition that is not exactly square is
   filled rather than squashed - the 64-square this draws is produced by the
   cropper at a 1:1 aspect ratio, but nothing in the schema enforces that and a
   distorted face is worse than a cropped one.
*/
.profiles_picture[b-jr1ptoi6do] {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: 50%;
    object-fit: cover;
    background-color: rgba(255, 255, 255, 0.06);
}

/*
   The placeholder for a profile with no picture yet.

   It exists so every row is the same height and the names stay in one column;
   a row that simply omitted the image would sit narrower than its neighbours
   and read as a different kind of thing.
*/
.profiles_picture_none[b-jr1ptoi6do] {
    display: inline-block;
    border: 1px dashed rgba(255, 255, 255, 0.2);
}

/*
   THE BASIS IS WHAT MAKES THE ROW WRAP, and 0 here was a bug that only a phone
   showed: with `flex: 1` the details had a basis of 0, so on a 375px screen
   they shrank to nothing rather than pushing the buttons onto a second line,
   and "Ada Lovelace" rendered one letter per line.

   7rem, DOWN FROM 10, and the number matters because it decides when the row
   wraps rather than how wide the column ends up. The item still grows into
   whatever is left, so on a 375px phone it measures about 158px and a name sits
   on one line exactly as before - what changed is that at 10rem the row wanted
   332px against 330 available and the buttons dropped to a second line, two
   pixels short.

   THAT COST THE WHOLE POINT OF THE ICON-ONLY BUTTONS. Collapsing three verbs to
   their glyphs saves about 81px, and a basis that then wraps anyway gives every
   one of them straight back. A basis is a wrapping THRESHOLD; it is not a width,
   and setting it to what the content would like is what makes a row wrap while
   there is still room.

   min-width: 0 stays: a flex item's automatic minimum size is its content's
   min-content width, so without it a long name would push the row wider than
   the window - the opposite failure, and equally invisible on a desktop.
*/
.profiles_detail[b-jr1ptoi6do] {
    display: flex;
    flex: 1 1 7rem;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/*
   break-word, NOT anywhere - and the difference is the whole reason the name
   collapsed.

   `anywhere` counts toward the element's intrinsic MIN-CONTENT width, so a
   flex item carrying it can be squeezed down to one character and will be.
   `break-word` breaks a long word that has overflowed but leaves min-content
   alone, so the column keeps a real minimum and the row wraps instead.

   Sessions uses `anywhere` on purpose: an IPv6 address is one unbreakable
   token and collapsing it is better than pushing the row off the side. A
   person's name is not that, and copying the rule without the reason is what
   produced a vertical name.
*/
.profiles_name[b-jr1ptoi6do] {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
    overflow-wrap: break-word;
}

/*
   "In use" - a badge rather than a colour on the row, because the row is not in
   a different STATE, it is the one everything else is acting as. flex-shrink: 0
   so it never collapses to a sliver beside a long name.
*/
.profiles_current[b-jr1ptoi6do] {
    flex-shrink: 0;
    padding: 1px 8px;
    border-radius: 999px;
    background-color: rgba(255, 204, 102, 0.2);
    color: rgba(255, 204, 102, 0.95);
    font-size: 0.7rem;
    font-weight: 600;
    font-style: normal;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.profiles_type[b-jr1ptoi6do] {
    font-size: 0.75rem;
    opacity: 0.6;
}

/*
   The row's own actions.

   flex-wrap again, for the case the row itself has already wrapped: three
   buttons still may not fit on one line at the narrowest widths, and the third
   going off the side is the failure this whole file is arranged to avoid.

   margin-left: auto pins them to the right edge rather than leaving them
   immediately after a short name, so they line up down the list however long
   each name is - and on a row that has wrapped anyway they stay right rather
   than sitting under the picture. Same rule as the picture list, and the two
   are meant to read alike.
*/
.profiles_actions[b-jr1ptoi6do] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-left: auto;
}

/*
   Create, under the list.

   A row of its own with a rule above it, because it does not act on a profile -
   the separation is what stops it reading as one more row. Drawn even when the
   list is empty, since an account with no profile has nothing else to do here.
*/
.profiles_add[b-jr1ptoi6do] {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
}

/*
   A removed profile, drawn under the live ones.

   A dashed border rather than faded text, so the row is plainly out of use
   while its name and its Put Back stay as readable as any other row's. No
   picture column: nobody sees a removed profile, so its face is not the thing
   being chosen.
*/
.profiles_row_removed[b-jr1ptoi6do] {
    border-style: dashed;
    background-color: transparent;
}
/* /Components/Sections/ProfilePictureDeleteConfirm.razor.rz.scp.css */
/*
    The 256-square, so somebody can see which picture they are changing.

    max-width because 256 is wider than the content area of a dialog on a
    narrow phone; height: auto keeps it square as it shrinks.
*/
.picture_preview[b-isoc3i3s8z]
{
    display: block;
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* /Components/Sections/ProfilePictureForm.razor.rz.scp.css */
/*
   The pictures on a profile.

   PROFILE'S SHAPE, DELIBERATELY THE SAME ONE. Both are "a handful of things,
   each with its own actions" in a window around 360px wide, and they are opened
   one from the other - so a second answer would only be a second thing to keep
   in step, and the difference would read as a mistake rather than a decision.

   BUT THE WINDOW IS NOT PROFILE'S, AND THAT IS WHAT DECIDES THIS FILE.
   Profiles is opened from the launcher, so it is MAXIMIZED and has the whole
   workspace - 1251px of row, measured. This one is opened with
   OpenProgramDialog, and .window_component_host_overlay is `width: auto`: the
   window is sized BY this content and capped at the viewport. So a rule that
   is merely generous on a maximized window is a rule that cannot be paid here,
   which is exactly what happened - see .pictures_detail.

   NO ::deep ANYWHERE. Every element these rules select is rendered by this
   section's own markup, so isolation stamps the scope attribute on a subject
   that carries it. A rule whose subject belonged to Section or WindowFrame
   would need ::deep, and the failure is silent - it ships and matches nothing.
*/
.pictures_list[b-3azlpihhxp] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

/*
   One row: thumbnail, then caption, then the actions.

   flex-wrap is the FLOOR, and it is reached rather than theoretical. On a
   375px phone the window is capped at the viewport and three buttons beside a
   thumbnail and a caption need about 28px more than there is, so the actions
   drop to a second line - which is what the profile list does at that width
   too, measured, so the two read alike. A tenant's own wording for "Update"
   can reach it on a wider screen. Without it a button is pushed off the side,
   and that is a failure nothing reports: .window_content does not scroll for
   it.
*/
.pictures_row[b-3azlpihhxp] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
}

/*
   48px, matching the profile list.

   SQUARE BUT NOT ROUND: a profile picture is a person and reads as an avatar,
   where these are pictures - a circle would crop a photograph somebody chose
   the framing of. The cropper produces a 1:1 rendition, but nothing in the
   schema enforces that, so object-fit: cover fills rather than squashes.
*/
.pictures_thumbnail[b-3azlpihhxp] {
    flex-shrink: 0;
    width: 48px;
    height: 48px;
    border-radius: 6px;
    object-fit: cover;
    background-color: rgba(255, 255, 255, 0.06);
}

/*
   The placeholder for a picture whose cropped rendition was never written.

   It exists so every row is the same height and the captions stay in one
   column; a row that omitted the image would sit narrower than its neighbours
   and read as a different kind of thing.
*/
.pictures_thumbnail_none[b-3azlpihhxp] {
    display: inline-block;
    border: 1px dashed rgba(255, 255, 255, 0.2);
}

/*
   THE BASIS COMES FROM THE CONTENT, AND IN A CONTENT-SIZED WINDOW IT HAS TO.

   A DECLARED basis wider than the caption can never be satisfied here, because
   the window is sized by the same content the basis overrides. A flex item that
   can GROW contributes its CONTENT's max-content width to the container's
   max-content - not its flex-basis - so `flex: 1 1 8rem` had the window measure
   the caption at 105px and size itself to that, and then had the row break
   lines against 128px. Measured: 381px wanted against 369 available, so the
   actions block went to a second line and the row stood 108px tall where it
   should have been 70. No window width fixed it, because widening the window
   widened the caption's contribution by the same amount.

   `auto` rather than a smaller number: a basis taken from the content is one
   the content can always pay, at any caption length and any width. A longer
   caption widens the window instead - up to the viewport, where the row wraps,
   which is the floor .pictures_row describes.

   NOT `flex: 1`, which is `flex-basis: 0` - an item with no basis shrinks to
   nothing rather than pushing its neighbours onto a second line, and at 375px
   that renders a caption one letter per line. That bug shipped on the profile
   list, which is why the shorthand is written out rather than abbreviated.

   min-width: 0 stays: a flex item's automatic minimum is its content's
   min-content width, so without it a long caption pushes the row wider than the
   window - the opposite failure, and equally invisible on a desktop.
*/
.pictures_detail[b-3azlpihhxp] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/*
   break-word, NOT anywhere.

   `anywhere` counts toward the element's intrinsic min-content width, so a flex
   item carrying it can be squeezed to one character and will be. `break-word`
   breaks a word that has already overflowed and leaves min-content alone, so
   the column keeps a real minimum and the row wraps instead. Sessions uses
   `anywhere` on purpose - an IPv6 address is one unbreakable token - and
   copying that rule without its reason is what produced a vertical name here
   once already.
*/
.pictures_caption[b-3azlpihhxp] {
    font-weight: 600;
    overflow-wrap: break-word;
}

/*
   Who may see it. Owner-only - see the markup.
*/
.pictures_access[b-3azlpihhxp] {
    font-size: 0.75rem;
    opacity: 0.6;
}

/*
   The cover badge, a pill under the caption. align-self keeps it the width of
   its word, since a column flex item otherwise stretches to the row.
*/
.pictures_cover[b-3azlpihhxp] {
    align-self: flex-start;
    padding: 1px 8px;
    border: 1px solid var(--bs-border-color);
    border-radius: 999px;
    font-size: 0.75rem;
}

/*
   The row's own actions, PINNED RIGHT.

   margin-left: auto is what puts them against the edge rather than immediately
   after a short caption, so the buttons line up down the list however long each
   caption is. It also keeps them right on their own line in the case the row
   has wrapped anyway.

   flex-shrink: 0 so the buttons are never squeezed narrower than their labels -
   a button that yields is a button whose text clips, and the caption column
   above is the one that is supposed to give.

   flex-wrap for the narrowest widths, where three still may not fit on one
   line: wrapping them among themselves is better than the third going off the
   side.
*/
.pictures_actions[b-3azlpihhxp] {
    display: flex;
    flex-wrap: wrap;
    flex-shrink: 0;
    gap: 6px;
    margin-left: auto;
}
/* /Components/Sections/ProfilePictureReadForm.razor.rz.scp.css */
/*
    The original, at whatever size it was uploaded.

    max-width rather than a fixed width, because this is the ONE place the full
    upload is shown and it can be any shape - the 256-square is what the list
    draws. height: auto keeps the aspect ratio; without it a portrait photo is
    squashed to the box.
*/
.picture_full[b-yarn7l2jw0]
{
    display: block;
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* /Components/Sections/ProfilePictureUpdateForm.razor.rz.scp.css */
/*
    The 256-square, so somebody can see which picture they are changing.

    max-width because 256 is wider than the content area of a dialog on a
    narrow phone; height: auto keeps it square as it shrinks.
*/
.picture_preview[b-8twrz5o03v]
{
    display: block;
    max-width: 100%;
    height: auto;
    border-radius: 8px;
}
/* /Components/Sections/ProfileReadForm.razor.rz.scp.css */
/*
    The question Block and Unblock ask before they act, under the buttons that
    raise it, set apart so it reads as a question rather than as a field.
*/
.profile_block_confirm[b-ajk4zxgls8]
{
    margin-bottom: 1rem;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.2);
    border-radius: 8px;
}

.profile_block_confirm_actions[b-ajk4zxgls8]
{
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
}

/*
    The lines saying the reader has blocked or follows this profile. Quiet,
    like the access badges: the profile is still what is being read.
*/
.profile_blocked[b-ajk4zxgls8],
.profile_following[b-ajk4zxgls8]
{
    margin-bottom: 1rem;
}
/* /Components/Sections/ProfileReportCreateForm.razor.rz.scp.css */
/*
   The Report form.

   THE LINE BEING REPORTED is quoted above the form, as the room drew it, so
   the person sees what they are sending before they send it. pre-wrap keeps
   the line's own breaks, and overflow-wrap a long word inside the window at
   375px.

   ::deep ONLY FOR THE LINE'S PICTURES, which RichTextView draws: each is its
   64, as the room drew it. Every other element these rules select is rendered
   by this section's own markup.
*/
.reportcreate_line[b-przuurj4tb] {
    margin: 0 0 12px;
    padding: 8px 12px;
    border-left: 3px solid rgba(255, 255, 255, 0.3);
    background-color: rgba(255, 255, 255, 0.04);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.reportcreate_line[b-przuurj4tb]  img.rich_text_picture {
    width: 64px;
    height: 64px;
    object-fit: cover;
}
/* /Components/Sections/ProfileReportReadForm.razor.rz.scp.css */
/*
   One report, for an administrator.

   THE FACTS are a definition list, a term above its value, so a long name or
   a long piece of writing wraps inside the window at 375px rather than
   pushing a second column off the side.

   THE REST OF A CASE is a row per report beside its View, and THE PICTURES a
   grid two across on a phone, each captioned with who it is shown to.

   THE LINES AROUND A REPORTED ONE are drawn as the room draws them - when,
   who, what - with the reported line marked by a gold rule, the colour the
   aura uses for the thing pressed, so it is the one the eye finds.

   ::deep ONLY FOR A LINE'S PICTURES. A line is drawn by RichTextView, so a
   rule about its pictures reaches through this section's own box with ::deep;
   every other element these rules select is rendered by this section's own
   markup. A picture a reported line places is the upload, so it is held to
   16rem rather than drawn at its own size.
*/
.report_facts[b-bset22wf3h] {
    margin: 0 0 12px;
}

.report_facts dt[b-bset22wf3h] {
    margin-top: 8px;
    font-weight: 600;
}

.report_facts dd[b-bset22wf3h] {
    margin: 0;
    overflow-wrap: anywhere;
}

/* What the person wrote keeps its own line breaks. */
.report_details[b-bset22wf3h] {
    white-space: pre-wrap;
}

.report_heading[b-bset22wf3h] {
    margin: 16px 0 6px;
    font-size: 1rem;
    font-weight: 600;
}

/* A reported entry's topic, above its body. */
.report_topic[b-bset22wf3h] {
    margin: 0.25rem 0;
    font-weight: 600;
    overflow-wrap: break-word;
}

.report_line[b-bset22wf3h] {
    margin: 0 0 8px;
    padding: 8px 12px;
    border-left: 3px solid rgba(255, 255, 255, 0.3);
    background-color: rgba(255, 255, 255, 0.04);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.report_lines[b-bset22wf3h] {
    display: flex;
    flex-direction: column;
    gap: 4px;
}

/* flex-wrap is the floor at 375px: the words drop under the name rather than off the side. */
.report_said[b-bset22wf3h] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    padding: 4px 8px;
    border-left: 3px solid transparent;
}

.report_said_reported[b-bset22wf3h] {
    border-left-color: #d4af37;
    background-color: rgba(212, 175, 55, 0.08);
}

.report_when[b-bset22wf3h] {
    flex-shrink: 0;
    opacity: 0.7;
}

.report_who[b-bset22wf3h] {
    flex-shrink: 0;
    font-weight: 600;
}

.report_message[b-bset22wf3h] {
    flex: 1 1 12rem;
    min-width: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

.report_picture[b-bset22wf3h] {
    display: block;
    max-width: 100%;
    height: auto;
    margin-top: 12px;
}

.report_actions[b-bset22wf3h] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}

/* The rest of a case: each report beside its View, wrapping under it at 375px. */
.report_joined[b-bset22wf3h] {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.report_joined_row[b-bset22wf3h] {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 8px;
    padding: 6px 0;
    border-top: 1px solid rgba(255, 255, 255, 0.1);
}

.report_joined_facts[b-bset22wf3h] {
    flex: 1 1 auto;
    min-width: 0;
}

/* A grid of the profile's pictures, two across on a phone. */
.report_gallery[b-bset22wf3h] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
    gap: 12px;
}

.report_figure[b-bset22wf3h] {
    margin: 0;
    min-width: 0;
}

.report_figure .report_picture[b-bset22wf3h] {
    margin-top: 0;
}

.report_figure figcaption[b-bset22wf3h] {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    margin-top: 4px;
}

.report_line[b-bset22wf3h]  img.rich_text_picture,
.report_message[b-bset22wf3h]  img.rich_text_picture {
    max-width: min(100%, 16rem);
}
/* /Components/Sections/ProfileTagForm.razor.rz.scp.css */
/*
   The tags on a profile.

   NO AVATAR ANYWHERE, which is what separates this list from Connections and
   Profiles. A row here is a WORD rather than a person: a self tag is the
   profile's own statement about itself, and a community entry is pooled across
   everybody who placed it, so there is no one face it could carry. The
   reference drew a card per rater with the rater's picture on it; averaging is
   what removed the picture along with the name.

   THE WINDOW IS CONTENT-SIZED, so the trap Pictures documents applies here:
   OpenProgramDialog puts this inside .window_component_host_overlay, which is
   `width: auto`, and a DECLARED flex-basis wider than the content can never be
   paid - the window sizes itself against the content's max-content and then
   breaks lines against the basis. `flex: 1 1 auto` is the answer, not a smaller
   number.

   NO ::deep ANYWHERE. Every element these rules select is rendered by this
   section's own markup, so isolation stamps the scope attribute on a subject
   that carries it. A rule whose subject belonged to Section or WindowFrame
   would need ::deep, and the failure is silent - it ships and matches nothing.
*/
.tags_list[b-fltqwnjeq8] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

/*
   The heading over each of the three groups.

   A REAL HEADING RATHER THAN A BOLD LINE, because the groups are what this
   window is organized by and a screen reader has to be able to skip between
   them. It is h3 because Section has already opened the window's own heading
   levels above it.

   The top margin is larger than the gap between rows so a group reads as a
   break rather than as another row; the first one keeps it too, since the
   sentence above it is body text.
*/
.tags_heading[b-fltqwnjeq8] {
    margin-top: 20px;
    margin-bottom: 0;
    font-size: 0.9rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.04em;
    opacity: 0.7;
}

/*
   One row: the tag and its number on the left, the actions on the right.

   flex-wrap is the FLOOR, and it is reached rather than theoretical - at 375px
   three buttons beside a tag as long as "Black Lives Matter" need more room
   than there is, so the actions drop to a second line, which is what every
   other list in this family does at that width. Without it a button is pushed
   off the side, and that is a failure nothing reports: .window_content does not
   scroll for it.
*/
.tags_row[b-fltqwnjeq8] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
}

/*
   THE BASIS COMES FROM THE CONTENT, AND IN A CONTENT-SIZED WINDOW IT HAS TO -
   the whole argument is in ProfilePictureForm.razor.css under .pictures_detail,
   and it is the same window shape here.

   NOT `flex: 1`, which is `flex-basis: 0`: an item with no basis of its own
   shrinks to nothing rather than pushing its neighbours onto a second line,
   and at 375px that renders a name one letter per line. That bug shipped on
   the profile list, which is why the shorthand is written out.

   min-width: 0 stays: a flex item's automatic minimum is its content's
   min-content width, so without it a long tag pushes the row wider than the
   window.
*/
.tags_detail[b-fltqwnjeq8] {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

/*
   break-word, NOT anywhere.

   `anywhere` counts toward the element's intrinsic min-content width, so a
   flex item carrying it can be squeezed to one character and will be.
   `break-word` breaks a word that has already overflowed and leaves min-content
   alone. Sessions uses `anywhere` on purpose - an IPv6 address is one
   unbreakable token - and copying that rule without its reason is what produced
   a vertical name on the profile list once already.
*/
.tags_name[b-fltqwnjeq8] {
    font-weight: 600;
    overflow-wrap: break-word;
}

/*
   The number, which is the one thing on this row somebody is comparing between
   rows.

   LOUDER THAN THE LINES UNDER IT AND QUIETER THAN THE TAG, because the tag is
   what the eye finds first and the score is what it reads second. Tabular
   figures so a column of them lines up on the decimal - an average is one
   decimal place and a self score is none, so without it "7" and "6.3" sit at
   different widths down the list.
*/
.tags_score[b-fltqwnjeq8] {
    font-size: 0.9rem;
    font-variant-numeric: tabular-nums;
}

/*
   An Ignore row's number, drawn as the sentence that says what it does.

   It is a THRESHOLD rather than a rating, and the same integer means opposite
   things in the two groups - 3 on a self tag is "barely", 3 on an ignore tag
   filters nearly everybody carrying it. A bare number could not say which.
*/
.tags_threshold[b-fltqwnjeq8] {
    font-size: 0.75rem;
    opacity: 0.6;
    overflow-wrap: break-word;
}

/*
   How many placed a community tag, and the mark on the reader's own entry.

   Both are quiet, for the reason .connections_category is: the TAG is what
   somebody is looking for in a list of tags.
*/
.tags_raters[b-fltqwnjeq8],
.tags_mine[b-fltqwnjeq8] {
    font-size: 0.75rem;
    opacity: 0.6;
}

/*
   The row's own actions, PINNED RIGHT.

   margin-left: auto is what puts them against the edge rather than immediately
   after a short tag, so the buttons line up down the list however long each tag
   is. It also keeps them right on their own line in the case the row has
   wrapped anyway.

   flex-shrink: 0 so the buttons are never squeezed narrower than their labels -
   a button that yields is a button whose text clips, and the tag column above
   is the one that is supposed to give.
*/
.tags_actions[b-fltqwnjeq8] {
    display: flex;
    flex-wrap: wrap;
    flex-shrink: 0;
    gap: 6px;
    margin-left: auto;
}

/*
   The Add a Tag button, under the list with room above it, because it does not
   act on a row - the same separation Connections gives its search.
*/
.tags_add[b-fltqwnjeq8] {
    margin-top: 16px;
    padding-top: 16px;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
}
/* /Components/Sections/ProfileUpdateForm.razor.rz.scp.css */
/*
    A field and its own visibility, as one row.

    MOBILE FIRST, which for this form means the two stack. A phone has room for
    one control across, and a date input beside a three-option select at 375px
    leaves neither readable - so the default is a column and the row is what a
    wider viewport opts into.
*/
.profile_field[b-pw28rihaj2]
{
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin-top: 0.5rem;
}

/*
    A REAL BASIS, not `flex: 1`.

    `flex: 1` is `flex-basis: 0`, so an item claims no width of its own and the
    row never has a reason to wrap - the two controls just shrink together until
    both are unusable. Giving each a basis is what makes the wrap happen at a
    width somebody chose rather than at zero.

    min-width: 0 because a form control's default min-content width would
    otherwise stop it shrinking to its share at all.
*/
.profile_field_value[b-pw28rihaj2]
{
    display: flex;
    flex: 1 1 12rem;
    flex-direction: column;
    min-width: 0;
}

/*
    Narrower than the value, because "Connections Only" is the longest thing it
    will ever hold and the value beside it is a name or a date.
*/
.profile_field_access[b-pw28rihaj2]
{
    display: flex;
    flex: 1 1 9rem;
    flex-direction: column;
    min-width: 0;
}
/* /Components/Sections/SessionsForm.razor.rz.scp.css */
/*
   The list of live sessions.

   NO ::deep ANYWHERE, and that is worth stating rather than noticing: every
   element these rules select is rendered by SessionsForm's own markup, so isolation
   stamps the scope attribute on a subject that carries it. A rule whose subject
   belongs to Section or WindowFrame would need ::deep, and the failure is
   silent - it ships and matches nothing.
*/

/*
   NOTHING HERE STYLES THE SIGN-OUT BUTTONS, and that is on purpose rather
   than an omission - which is worth saying, because this is the file
   somebody will open looking for them.

   All four (the three per-row "Sign out" buttons and the bulk "Sign out
   everywhere else") are Bootstrap .btn, and the gold aura they wear comes
   from the .btn rules in wwwroot/app.css. It has to live there: .btn is
   somebody else's class worn by a dozen components, so a rule in this
   stylesheet would be scoped by CSS isolation to SessionsForm's own markup and
   every other button in the application would go without.

   Nothing here draws a busy state either. A revoke runs through the section's
   RunSavingAsync, so the list is covered by the same indicator every window
   draws and a second press is refused there.
*/
.sessions_list[b-bi0tomfo4q] {
    display: flex;
    flex-direction: column;
    gap: 8px;
    margin-top: 12px;
}

/*
   One row: details on the left, the action on the right.

   flex-wrap, and it is not decoration. A window is around 360px wide on a
   phone, and an address plus two timestamps plus a button does not fit - so
   without this the button is pushed off the side, where .window_content does
   not scroll for it and nothing reports a problem. It is the same reason
   Section's own action row wraps.
*/
.sessions_row[b-bi0tomfo4q] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 8px;
    padding: 10px 12px;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
}

/*
   min-width: 0 is load-bearing. A flex item's automatic minimum size is its
   content's min-content width, so without it a long address would push the row
   wider than the window instead of letting the button wrap beneath it.

   flex: 1 so the details take the slack and the button keeps its own width.
*/
.sessions_detail[b-bi0tomfo4q] {
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.sessions_where[b-bi0tomfo4q] {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 600;
    /* An IPv6 address has no spaces to break at, so it would otherwise set the
       row's minimum width all by itself. */
    overflow-wrap: anywhere;
}

/*
   "This device" - a badge rather than a colour on the row, because the row is
   not in a different STATE, it is the one you are reading from. flex-shrink: 0
   so it never collapses to a sliver beside a long address.
*/
.sessions_current[b-bi0tomfo4q] {
    flex-shrink: 0;
    padding: 1px 8px;
    border-radius: 999px;
    background-color: rgba(255, 204, 102, 0.2);
    color: rgba(255, 204, 102, 0.95);
    font-size: 0.7rem;
    font-weight: 600;
    font-style: normal;
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.sessions_when[b-bi0tomfo4q] {
    font-size: 0.75rem;
    opacity: 0.6;
}

/*
   The bulk action, under the list.

   A row of its own with a rule above it, because it acts on everything in the
   list rather than on a row - the separation is what stops it reading as a
   fourth session.
*/
.sessions_all[b-bi0tomfo4q] {
    margin-top: 14px;
    padding-top: 12px;
    border-top: 1px solid rgba(255, 255, 255, 0.12);
}

.sessions_confirm_question[b-bi0tomfo4q] {
    margin-bottom: 8px;
    font-weight: 600;
}

/*
   flex-wrap for the same reason .sessions_row has it: a window is around 360px
   wide on a phone, and two buttons plus their gap do not always fit. Without it
   the second is pushed off the side, where .window_content does not scroll and
   nothing reports a problem.
*/
.sessions_confirm_actions[b-bi0tomfo4q] {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
}
/* /Components/Sections/SettingsMenuForm.razor.rz.scp.css */
/*
   Settings' list of what it opens.

   NO ::deep ANYWHERE IN THIS FILE, and that is worth stating rather than
   noticing: every element these rules select is rendered by SettingsMenuForm's own
   markup, so isolation stamps the scope attribute on a subject that carries it.
   The moment a rule here reaches into something Section or WindowFrame renders
   it needs ::deep, and the failure is silent - the rule ships and matches
   nothing. See DataGrid.razor.css, where nine of fifteen rules did exactly that.
*/

/*
   AUTO-FILL RATHER THAN A BREAKPOINT.

   The window this lives in can be any width at all - maximized on a desktop,
   360px on a phone, or a few hundred pixels wide docked to an edge - and none of
   those is a viewport width, so a media query would be asking the wrong
   question. `auto-fill` with a minimum lets the entries reflow against the
   space the WINDOW actually has.

   min() rather than a bare 280px: below that width the track would be wider
   than the container and the grid would overflow sideways, which .window_content
   does not scroll for. At 100% the entries simply stack one per row.
*/
.settings_menu[b-3z3ng0hgnk] {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 280px), 1fr));
    gap: 8px;
    margin-top: 4px;
}

/*
   One entry.

   A <button> rather than an anchor: this opens a window, it does not navigate,
   and there is no href that would mean anything - the window framework has no
   routes. A button also gets keyboard activation and the disabled/focus
   semantics for free.

   align-items: start so the icon sits level with the title rather than
   floating to the middle of a two- or three-line block.
*/
.settings_entry[b-3z3ng0hgnk] {
    display: flex;
    align-items: start;
    gap: 12px;
    width: 100%;
    padding: 12px;
    /*
       THE RIM - see --aura-border in app.css. Black because a
       box-shadow paints immediately outside the border box, so without a
       dark edge between the card's own fill and the glow the two blend and
       it reads as a fuzzy card rather than a lit one.

       Before the aura: border: 1px solid rgba(255, 255, 255, 0.12);
  */
    border: 1px solid var(--aura-border);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.04);
    color: inherit;
    text-align: start;
    cursor: pointer;
    /*
       THE GOLD AURA. See the section of the same name in
       wwwroot/app.css for what the tokens hold and why they are tokens; the
       short version is that this is the treatment the titlebar buttons, the
       launcher and the drawer entries have always worn, and a card that
       opens a program is the same kind of thing - something whose whole job
       is to be pressed.

       NOT PIXEL-FOR-PIXEL THE CHROME'S GLOW, and the difference is on
       purpose: the tokens carry a 1px spread where the chrome uses 2px,
       because what suits a handful of 26px pills along a titlebar is haze
       when it is on every button and card in a window. The rim, the hue,
       the alphas and the states are identical, and app.css carries the
       reasoning.

       THE BACKGROUND IS THIS CARD'S OWN - these are full-width cards inside
       a window rather than 26px pills on the backdrop, so they keep a 4%
       white fill rather than --button-bg. The RIM is not its own: it is
       black, because the glow needs something opaque to sit outside of and
       a 12%-white edge is not it. See the note on the border property
       below.
  */
    box-shadow: var(--aura-rest);
    /*
       NAMED PROPERTIES, NEVER `all` - the rule the launcher's tiles record the
       hard way. `all` sweeps in every property that might one day differ
       between two states, and anything encoding a MODE rather than feedback
       then animates when it should switch.

       box-shadow had to be ADDED to this list when the aura arrived, or the
       glow would snap between states while the border eased, which reads as
       a rendering fault rather than as feedback. That is the running cost of
       naming properties, and it is still the right trade.

       background-color came OFF it when the hover fill was dropped later
       the same day - nothing changes that property on this element any
       more, so easing it was a name for an animation that never runs. Put
       it back if a background ever moves here again.

       Before the aura:  transition: border-color .15s, background-color .15s;
       With the aura:    ... plus box-shadow .15s
  */
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}

    /*
       THE RIM STAYS BLACK THROUGH HOVER, which it did not before: this used
       to tint the border gold, and that is not what the chrome does. All
       three chrome controls hold black from rest through hover and swap the
       rim only on :active, so the glow brightening is the whole hover
       signal and the gold rim is left to mean one thing - held down. Two
       cues firing at once leaves nothing to say for the press.

       Before the aura: border-color: rgba(255, 204, 102, 0.5);
  */
    /*
       THE GLOW IS THE WHOLE HOVER SIGNAL. The rim holds black and the fill
       does not move, which is what the chrome does - .window_button,
       .launch_button and .window_drawer_entry each keep one background for
       their whole life and say everything through the aura.

       DO NOT ADD A SECOND HOVER SIGNAL HERE. Tinting the border gold takes
       the press's own signal away, and lightening the fill reads as the
       card itself changing rather than as the card being pointed at - which
       is loudest of all on a full-width card. The glow says it.
  */
    .settings_entry:hover[b-3z3ng0hgnk] {
        border-color: var(--aura-border);
        box-shadow: var(--aura-hover);
    }

    /*
       Held down, the border itself goes gold - what .window_button and
       .window_drawer_entry both do on :hover:active.

       Written as a plain :active rather than :hover:active so that a
       keyboard Space or Enter gets the same acknowledgement a mouse does.
       There is no hover in that case, so the chrome's own selector would
       simply never match and the press would go unremarked.
  */
    .settings_entry:active[b-3z3ng0hgnk] {
        border-color: var(--aura-border-active);
        box-shadow: var(--aura-hover);
    }

    /*
       Focus keeps its solid ring AND takes the bright glow: the ring is
       what makes focus tellable from hover, and the glow is what makes the
       card look like the rest of the chrome while it is focused.

       The two outline values are the app.css tokens now and resolve to
       exactly what was written here before - 2px solid rgba(255,204,102,0.9)
       at a 2px offset.
  */
    .settings_entry:focus-visible[b-3z3ng0hgnk] {
        box-shadow: var(--aura-hover);
        outline: var(--aura-focus-ring);
        outline-offset: var(--aura-focus-offset);
    }

/*
   line-height only. The SIZE belongs to bx-lg, which is Boxicons' own from
   transformations.min.css and carries !important - so a font-size here would
   be a rule that looks like it sets the size and does nothing.

   flex-shrink: 0 because the text beside it wraps and the icon must not be
   squeezed to make room.
*/
.settings_entry_icon[b-3z3ng0hgnk] {
    flex-shrink: 0;
    line-height: 1;
    color: rgba(255, 204, 102, 0.9);
}

/*
   min-width: 0 is load-bearing. A flex item's automatic minimum size is its
   content's min-content width, so without this a long unbroken description
   would push the entry wider than its grid track instead of wrapping - and the
   overflow lands on the window, which does not scroll sideways.

   align-self: stretch is what lets the timestamp sit on the floor of the card
   rather than under the description. The entry itself is align-items: start,
   so the icon stays level with the title instead of floating to the middle of a
   two-line block - and that same rule would shrink-wrap THIS box to its
   content, leaving margin-top: auto below with no free space to absorb.
   Stretching only the text column keeps both.
*/
.settings_entry_text[b-3z3ng0hgnk] {
    display: flex;
    flex-direction: column;
    align-self: stretch;
    gap: 2px;
    min-width: 0;
}

.settings_entry_title[b-3z3ng0hgnk] {
    font-weight: 600;
}

.settings_entry_description[b-3z3ng0hgnk] {
    font-size: 0.875rem;
    opacity: 0.8;
}

/*
   THE TIMESTAMP IS PINNED TO THE BOTTOM OF THE CARD, and that is about the ROW
   rather than about this one entry.

   Grid items stretch to the tallest in their row, so every card in a row is the
   same height - but the CONTENT was top-aligned, so a card whose description
   wrapped to two lines pushed its timestamp a line lower than its neighbours'.
   Three cards side by side then had their timestamps at two different heights,
   which reads as one of them being misaligned rather than as a longer
   description. Change Email is the one that wraps first, its description being
   the longest of the five.

   margin-top: auto absorbs whatever vertical slack the card has, so the
   timestamps line up across the row however many lines each description takes.
   On the tallest card there is no slack and it simply sits after the
   description - which is why padding-top carries the breathing room rather than
   the margin: an auto margin collapses to zero exactly when the gap is most
   needed.
*/
.settings_entry_when[b-3z3ng0hgnk] {
    margin-top: auto;
    padding-top: 10px;
    font-size: 0.75rem;
    font-style: italic;
    opacity: 0.6;
}
/* /Components/Sections/SystemHealthAccounts.razor.rz.scp.css */
/*
   SYSTEM HEALTH'S ACCOUNTS. The four counts as large figures in a row, each
   with its measure's name above it, wrapping on a phone, in the frame the
   graph under it wears.
*/
.system_health_counts[b-qizx8p7apn] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 2rem;
    margin: 0;
    padding: 0.5rem 0.75rem;
    border: 1px solid rgba(255, 255, 255, 0.12);
    border-radius: 8px;
    background-color: rgba(255, 255, 255, 0.03);
}

.system_health_counts dt[b-qizx8p7apn] {
    font-weight: normal;
    color: var(--bs-secondary-color);
    font-size: 0.85rem;
}

.system_health_counts dd[b-qizx8p7apn] {
    font-size: 1.4rem;
    margin: 0;
}
/* /Components/Sections/SystemHealthProblems.razor.rz.scp.css */
/*
   SYSTEM HEALTH'S PROBLEMS. One row per problem with a bar down its left edge:
   red once it is raised, amber while it is still being checked, and the
   border colour for one dismissed or cleared, which is drawn quieter.
*/
.system_health_good[b-ewravjpyxf] {
    color: var(--bs-success);
}

.system_health_problems[b-ewravjpyxf] {
    list-style: none;
    padding: 0;
    margin: 0 0 0.5rem;
}

.system_health_problems li[b-ewravjpyxf] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    justify-content: space-between;
    padding: 0.4rem 0.6rem;
    margin-bottom: 0.35rem;
    border-left: 0.25rem solid var(--bs-border-color);
}

.system_health_problems li.system_health_raised[b-ewravjpyxf] {
    border-left-color: var(--bs-danger);
}

.system_health_problems li.system_health_pending[b-ewravjpyxf] {
    border-left-color: var(--bs-warning);
}

.system_health_problem_text[b-ewravjpyxf] {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-width: 0;
    overflow-wrap: break-word;
}

.system_health_detail[b-ewravjpyxf] {
    font-size: 0.85rem;
    color: var(--bs-secondary-color);
}

.system_health_quiet li[b-ewravjpyxf] {
    border-left-color: var(--bs-border-color);
    opacity: 0.85;
}

/* Dismissed and Cleared stand apart from the list above them. */
.system_health_heading[b-ewravjpyxf] {
    margin-top: 0.75rem;
}
/* /Components/Sections/SystemHealthRange.razor.rz.scp.css */
/*
   SYSTEM HEALTH'S RANGE. When the newest sample was taken on one side and the
   range and Refresh on the other, wrapping under each other when the window
   is narrow, above the row of tabs.
*/
.system_health_bar[b-sm3rhvi8c6] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 0.75rem;
}

.system_health_bar p[b-sm3rhvi8c6] {
    margin: 0;
}

.system_health_ranges[b-sm3rhvi8c6] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
}
/* /Components/Sections/TermsAgreementForm.razor.rz.scp.css */
/*
   The dialog's own layout. Everything here is about ONE thing: the buttons
   staying put while the terms scroll.

   A consent dialog whose Agree button is below several hundred lines of legal
   text is a consent control the user has to hunt for, and on a phone it is one
   they may never find at all - Section's action row sits after the content, so
   without a cap on the content the row is simply off the bottom of the window.
*/

.terms_agreement_intro[b-7v55obi2a4] {
    margin-bottom: 10px;
    font-weight: bold;
}

/*
   max-height rather than height, so a short document does not leave a box of
   empty space under it. The terms are long enough today that this is always
   the cap; that is not a reason to hardcode the height, because the component
   inside is shared with the Terms window and may legitimately be edited.

   The unit is `vh` rather than a percentage: this is an overlay window, sized
   by its content rather than by a definite parent height, so a percentage
   would resolve against nothing and the cap would silently do nothing. Same
   trap Section's `Fill` documents from the other side.
*/
.terms_agreement_scroller[b-7v55obi2a4] {
    max-height: 45vh;
    overflow-y: auto;
    overflow-x: hidden;
    /* Room for the scrollbar, so the text does not sit under it. */
    padding-right: 12px;
    border: 1px solid rgba(0, 0, 0, 0.25);
    border-radius: 6px;
    background-color: rgba(0, 0, 0, 0.15);
    /* Matches the drawer's minimized rows - thin, and visible enough to say
       there is more to read, which on a consent dialog is the point. */
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 204, 102, 0.5) transparent;
}

    /*
       tabindex="0" in the markup makes this focusable, which is what lets a
       keyboard user scroll it with the arrow keys - a scroll container is not
       reachable by keyboard otherwise, so the terms would be readable only
       with a mouse. The outline is the visible half of that and must not be
       removed.
    */
    .terms_agreement_scroller:focus-visible[b-7v55obi2a4] {
        outline: 2px solid rgba(255, 204, 102, 0.9);
        outline-offset: 2px;
    }

    .terms_agreement_scroller[b-7v55obi2a4]::-webkit-scrollbar {
        width: 8px;
    }

    .terms_agreement_scroller[b-7v55obi2a4]::-webkit-scrollbar-thumb {
        border-radius: 999px;
        background: rgba(255, 204, 102, 0.5);
    }
/* /Components/UI/AuthenticatorApp/AuthenticatorSetUp.razor.rz.scp.css */
/* The QR code and the setup key under it.

   The code is a fixed size rather than the window's width: a scanner needs
   modules a few pixels across, and a code stretched across a maximized window
   is harder to frame with a phone, not easier. 240px holds a version 8 code,
   the size an address usually needs, at four pixels a module with its quiet
   zone.

   The key wraps anywhere, since it is one long word that would otherwise push
   a narrow dialog wider than a phone. */
.authenticator_qr[b-uoh4hpie36] {
    display: block;
    width: 240px;
    height: 240px;
    margin: 0.5rem 0 0.75rem;
}

.authenticator_key[b-uoh4hpie36] {
    overflow-wrap: anywhere;
    font-size: 1rem;
    user-select: all;
}
/* /Components/UI/AuthenticatorApp/RecoveryCodeList.razor.rz.scp.css */
/* Two columns where there is room and one where there is not, so ten codes
   fit a dialog without scrolling and still read on a phone. user-select: all on
   the list copies the set in one gesture. */
.recovery_code_list[b-c07wfhivco] {
    list-style: none;
    padding: 0;
    margin: 0 0 0.75rem;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(9rem, 1fr));
    gap: 0.25rem 1rem;
    user-select: all;
}

.recovery_code_list code[b-c07wfhivco] {
    font-size: 1rem;
}
/* /Components/UI/CheckBox/CheckBox.razor.rz.scp.css */
/*
   A button drawn as a checkbox.

   It is a button because a real <input type="checkbox"> cannot be driven from
   the model once it has been clicked - see the note in the markup for the
   dirty-checkedness flag that causes it. Everything here is therefore about
   making a button read as the checkbox it stands in for, without inheriting
   any of Bootstrap's button styling.
*/
.checkbox[b-31zotzeqp0] {
    display: flex;
    align-items: center;
    gap: 8px;
    /* Strip the <button> back to text; this is a control the user reads, not
       a call to action competing with Submit. */
    padding: 0;
    border: none;
    background: none;
    color: inherit;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

    /*
       The box itself. Sized well above the surrounding text so it is a
       hittable target on a phone - 20px is the same compromise the titlebar
       buttons make, which are as large as a 36px titlebar allows.
  */
    .checkbox > i[b-31zotzeqp0] {
        flex: 0 0 auto;
        font-size: 22px;
        line-height: 1;
        opacity: 0.9;
        transition: opacity 0.15s ease, transform 0.15s ease;
    }

    /*
       min-width: 0 so the sentence can wrap on a narrow window instead of
       pushing the box out of the row - the same automatic-minimum-size rule
       .window_title_icon records in the titlebar.
  */
    .checkbox > span[b-31zotzeqp0] {
        min-width: 0;
    }

    .checkbox:hover > i[b-31zotzeqp0] {
        opacity: 1;
        transform: scale(1.05);
    }

    /*
       A visible focus ring, and it must stay. This is the only control in the
       form that cannot be reached by typing, so a keyboard user arrives here
       by tabbing and has nothing else to tell them where they are.

       THE TOKENS RATHER THAN THE LITERALS, AND THAT FIXED A CLIPPED RING
      . This rule spelled the ring out as
       `2px solid rgba(255,204,102,0.9)` at `outline-offset: 3px` - the same
       colour and width every other control uses, at an offset one pixel
       larger than any of them. That put its reach at 5px against
       --aura-reach's 4px, which is what `.window_content` leaves, so the
       outermost pixel of this ring was being clipped on whichever side the
       control sat against. Exactly the drift the tokens exist to stop, and
       exactly the defect the titlebar and the window body had.
  */
    .checkbox:focus-visible[b-31zotzeqp0] {
        outline: var(--aura-focus-ring);
        outline-offset: var(--aura-focus-offset);
        border-radius: 4px;
    }

/*
   ---------------------------------------------------------------------
   THE SWITCH APPEARANCE - see the note in the markup for why this is drawn
   here rather than worn from Bootstrap. The shape and the timing are
   Bootstrap's; the palette is the aura's.
   ---------------------------------------------------------------------
*/
.checkbox_track[b-31zotzeqp0] {
    flex: 0 0 auto;
    position: relative;
    /* 36x20 keeps the same 22px vertical footprint the tick box has, so a
       column of switches and a column of boxes line their labels up
       identically and swapping one for the other moves nothing. */
    width: 36px;
    height: 20px;
    border-radius: 20px;
    /* The chrome's own rim and fill - .window_button, every .btn and the
       drawer entries all wear these two. A switch is a control, so it reads
       as one of them rather than as a shape of its own. */
    border: 1px solid var(--aura-border);
    background-color: var(--button-bg);
    /* Named properties, never `all`: the knob's offset below encodes the
       STATE, and the launcher tiles record what happens when `all` sweeps a
       state-bearing property into a transition. */
    transition: background-color 0.15s ease-in-out;
}

    /* The knob. Positioned from the left in both states so one property
       animates; `right` in the on state would be a different property and
       would not transition from `left`. */
    .checkbox_track[b-31zotzeqp0]::after {
        content: "";
        position: absolute;
        top: 50%;
        left: 2px;
        width: 14px;
        height: 14px;
        border-radius: 50%;
        transform: translateY(-50%);
        background-color: rgba(255, 255, 255, 0.65);
        transition: left 0.15s ease-in-out, background-color 0.15s ease-in-out;
    }

/*
   ON. Keyed on aria-checked rather than on a class, because that attribute
   is already what tells assistive technology the state - so the picture and
   the announcement cannot disagree, and there is no second source of truth
   to keep in step.
*/
.checkbox[aria-checked="true"] .checkbox_track[b-31zotzeqp0] {
    background-color: rgba(var(--aura-hue), 0.55);
}

    .checkbox[aria-checked="true"] .checkbox_track[b-31zotzeqp0]::after {
        /* 36 - 14 - 2 = 20px, the mirror of the 2px inset on the off side. */
        left: 20px;
        background-color: white;
    }

.checkbox:hover .checkbox_track[b-31zotzeqp0] {
    border-color: var(--aura-border-active);
}

.checkbox:disabled .checkbox_track[b-31zotzeqp0] {
    opacity: 0.5;
}

@media (prefers-reduced-motion: reduce) {
    .checkbox > i[b-31zotzeqp0] {
        transition: none;
    }

    .checkbox:hover > i[b-31zotzeqp0] {
        transform: none;
    }

    /* The knob still MOVES - it has to, that is the state - it just stops
       sliding. Removing the transition leaves it where the model says it is
       on the very next frame. */
    .checkbox_track[b-31zotzeqp0],
    .checkbox_track[b-31zotzeqp0]::after {
        transition: none;
    }
}
/* /Components/UI/DataGrid/DataGrid.razor.rz.scp.css */
/*
   .small_scroll IS GONE, and it is worth saying why rather than just deleting
   it.

   It carried `max-height: 50%; overflow: auto` and was worn by the filter
   dropdown - which DataGridFilter renders, not this component. Isolation stamps
   the scope attribute on the last element of a selector, so it compiled to
   `.small_scroll[b-...]` and matched nothing at all. The filter panel therefore
   ran off the bottom of the window with no scrollbar, which is exactly how it
   was reported.

   The percentage would not have worked either: it resolves against the
   containing block, and a Popper-positioned dropdown's is auto-height, so 50%
   computes to no limit. Both halves now live inline on the element, in
   DataGridFilter.MenuStyle, alongside the width - see the remarks there.
*/

.paginator[b-s8v0ydlg1m] {
    width: 100%;
}

/*
   The row area: the middle of the grid, between the toolbar and the paginator.

   It replaced Bootstrap's `flex-grow-1 h-100`, which was two rules fighting.
   h-100 asks for the full height of the parent, and flex-grow-1 then grows from
   that - so the toolbar and paginator were both ADDITIONAL to a child
   already claiming everything, and the paginator was pushed below the bottom of
   the window. Measured: 2px past .window_content at one size, more at others,
   which is why it reads as "the buttons land below the window".

   min-height: 0 is the half that is easy to leave out. A flex item will not
   shrink below its content by default, so without it the row area could never
   give height back to its siblings however little room there was.
*/
.datagrid_body[b-s8v0ydlg1m] {
    /*
       NO GROW. The height is set inline from the measurement, and flex-grow
       overrides it - the element takes its basis from the inline height and then
       grows past it to fill the row, which un-bounds the very thing the inline
       height exists to bound. Measured: a body told to be 331px sitting at 623px
       with a third of it empty, because the page size was still the one computed
       for 331.

       Shrink is left on so a container smaller than the measurement still fits
       rather than overflowing while the next measurement is in flight.
  */
    flex: 0 1 auto;
    min-height: 0;
    /*
       The horizontal twin of min-height above, and it became load-bearing when
       columns became resizable.

       A flex item defaults to `min-width: auto`, which is its CONTENT's minimum -
       and a `table-layout: fixed` table with stated column widths has a large
       one. So dragging the columns wider than the window made this element grow
       to match rather than scroll, and the grid pushed out past the window edge
       taking the toolbar and paginator's alignment with it. Measured: 2054px of
       columns in a 1254px window, with the element itself reporting 2054.
  */
    min-width: 0;
    /*
       CLIPS, and this is the guarantee rather than the tidiness. Everything
       else here is arithmetic - how many rows fit - and arithmetic can be a row
       out while a measurement settles. Without a clip, being one row out does
       not show as a slightly full grid, it shoves the paginator
       down and out of the window. Measured: the row content ran 96px past the
       height this element had been given, and all 96 came out of the bottom.
  */
    overflow-y: hidden;
    /*
       ACROSS it does not clip, because a column can now be dragged wider than
       the grid and clipping one would put it out of reach with no way back. The
       two axes genuinely want different answers: vertically the row count is
       arithmetic that must never be allowed to shove the paginator out of the
       window, horizontally it is the user's own choice and they have to be able
       to follow it.

       In practice the scrolling is done by Bootstrap's `.table-responsive`
       INSIDE this element, which was already in the markup and is already
       `overflow-x: auto` - measured at 2053px of columns scrolling inside
       1239px. So this never engages today. It is here as the honest statement
       of intent for the axis, and as what would catch the overflow if that
       wrapper were ever removed.

       A horizontal scrollbar does eat into the measured height, so the last row
       can be clipped by the rule above. That is the right way round: a row cut
       off at the bottom of a scroll area is visibly a row, where a paginator
       pushed off the window is simply gone.
  */
    overflow-x: auto;
}

/*
   What the row area says when the list holds nothing - see
   DataGrid.EmptyMessage.

   It sits under the header rather than inside the table, so it is not a cell
   and owes nothing to `table-layout: fixed`. The padding is what keeps it from
   sitting hard against the header's bottom border, and the sentence is left
   aligned with the first column rather than centred: it reads as an explanation
   of the list, which is what it is, rather than as a placeholder graphic.
*/
.datagrid_empty[b-s8v0ydlg1m] {
    padding: 1rem 0.5rem;
    margin: 0;
}

/*
   ::deep IS LOAD-BEARING IN EVERY RULE BELOW THAT HAS IT, and its absence is
   why this grid had no striping, no hover, no header styling and no selection
   highlight (found when the first window to actually render one was
   written).

   CSS isolation stamps the scope attribute on the LAST element of a selector,
   and that element has to be one THIS component rendered. DataGrid renders the
   table, thead, tbody and the header tr - and nothing else. Every other tr, th
   and td comes from DataGridRow, DataGridColumn, DataGridCell or
   DataGridFilter, none of which has a stylesheet and therefore none of which
   has a scope attribute at all. So `.datagrid tbody tr` compiled to
   `.datagrid tbody tr[b-xxxxx]` and matched nothing, silently.

   ::deep moves the attribute onto the compound before it, so
   `.datagrid tbody ::deep tr` becomes `.datagrid tbody[b-xxxxx] tr` - anchored
   on the tbody we do render, reaching the rows we do not. The rule of thumb:
   put ::deep immediately after the last element in the selector that this
   component's own markup creates.
*/
.datagrid[b-s8v0ydlg1m] {
    /*
       One row's height, declared once. The rows use it, and the JS measures a
       real row rather than reading this - so the two cannot disagree, and a
       consumer that overrides it is measured correctly without telling anyone.
  */
    --datagrid-row-height: 32px;
    width: 100%;
    table-layout: fixed;
}

    .datagrid thead[b-s8v0ydlg1m] {
/*        border-bottom: 1px solid black;*/
    }

        /* th comes from DataGridFilter and DataGridColumn. */
        .datagrid thead[b-s8v0ydlg1m]  th {
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        /*
           ROOM FOR THE FILTER BUTTON'S AURA.

           DataGridFilter renders its button `w-100 p-0 m-0`, so it fills this
           cell, and the cell clips - which it has to, because
           `text-overflow: ellipsis` does nothing without `overflow: hidden`
           and a long filter value would otherwise spill across the columns
           beside it. The cell carried the BROWSER'S default `padding: 1px`,
           since this table is `class="datagrid"` rather than Bootstrap's
           `.table` and so never picked up its 0.5rem cell padding. Measured at
           1px of room on three sides and 2.6px on the top, against the aura's
           4px reach: the rest and hover glow were clipped, and so was the
           focus ring.

           --aura-reach is the room the widest of those needs, and putting it
           here rather than working around it is what lets this button be an
           ordinary .btn: with real room there is no need for an inset focus
           ring, so the filter toggles wear exactly what every other button in
           the application wears.

           IT COSTS THE BUTTONS WIDTH, NOT THE COLUMNS. `table-layout: fixed`
           takes the column width from the declared width, and `box-sizing:
           border-box` puts the padding inside it - so the column the user
           sized is untouched and the button inside it gives up 8px. The
           HEADER also grows by about 6px, which is free: the page-size
           arithmetic measures the head rather than assuming it, so a taller
           header simply means one fewer row.

           THE 4px GUTTERS ARE WANTED, NOT A SIDE EFFECT. The filter row used
           to be one continuous bar and is now separate buttons; that change
           was put to the user as the cost of this padding, and on seeing it
           they kept it. So it is not a regression to be won back - closing
           the gutters up again means taking the aura's room away, which is
           the defect this rule exists to fix.
  */
        .datagrid thead[b-s8v0ydlg1m]  th.datagrid_filter {
            padding: var(--aura-reach);
        }

        /*
           Every body row is a DataGridRow.

           A FIXED height, not max-height, and that is what makes the page size
           computable at all. max-height does not constrain a table row, so rows
           stretched to fill whatever space the table had - which meant the row
           height depended on the ROW COUNT, and the row count is derived from
           the row height. Measured going round that loop: 18.5px with one page
           of rows, 20.5px at another size, then 26px once seventeen were asked
           for in a box sized for a shorter row. It never settled.

           With a fixed height the measurement is the same answer every time and
           the arithmetic converges on the first pass.
  */
        .datagrid tbody[b-s8v0ydlg1m]  tr {
            height: var(--datagrid-row-height);
        }

            .datagrid tbody[b-s8v0ydlg1m]  tr:hover {
                background-image: linear-gradient(to right, rgba(248,249,251,0.30), rgba(248,249,251, 0.10), rgba(248,249,251, 0.30));
            }

            .datagrid tbody[b-s8v0ydlg1m]  tr:nth-child(even) {
                background-color: rgba(0,0,0,0.10);
            }

            .datagrid tbody[b-s8v0ydlg1m]  tr td {
                overflow: hidden;
                text-overflow: ellipsis;
                white-space: nowrap;
            }

                .datagrid tbody[b-s8v0ydlg1m]  tr td input {
                    width: 100%;
                    height: 100%;
                    overflow: hidden;
                    text-overflow: ellipsis;
                    white-space: nowrap;
                    margin: 0px;
                    padding: 0px;
                }

                /*
                   AN ELLIPSIS BELONGS ON THE ELEMENT WHOSE OWN TEXT
                   OVERFLOWS, WHICH IS THE LABEL AND NOT THE CELL.

                   DataGridCell draws its value inside a `<label class="w-100">`,
                   so the text is the LABEL's inline content. `text-overflow`
                   on the `td` above only ever applies to the td's own inline
                   content, and a child box that is too wide is simply clipped
                   by its `overflow: hidden` - hard, mid-glyph, with no
                   ellipsis and no gap before the column beside it. A row
                   reading "418 Northgate Road, Cedar Rapids, IA, 524Mailing
                   Address" is two cells and looks like one run-on value.

                   The `input` rule above already says this for the editable
                   cell; the display cell had been left out, and it is the one
                   every grid in the product draws.
  */
                .datagrid tbody[b-s8v0ydlg1m]  tr td label {
                    overflow: hidden;
                    text-overflow: ellipsis;
                    white-space: nowrap;
                }

/*
   The header row IS ours - DataGrid renders <tr class="datagrid_header"> - so
   this one needs no ::deep. Left empty deliberately: thead already carries the
   rule underneath it, and a second border here drew two.
*/
.datagrid_header[b-s8v0ydlg1m] {
}

/*
   Applied by DataGridRow and DataGridCell to their own markup, so there is no
   element of ours at the end of it - the anchor has to be the table.
*/
.datagrid[b-s8v0ydlg1m]  .datagrid_selected {
    background-image: linear-gradient(to bottom, rgba(248,249,251,0.15), rgba(248,249,251, 0.10), rgba(248,249,251, 0.15));
}

/*
   COLUMN RESIZING.

   ::deep on every rule here, and for the usual reason: the th, and the handle
   inside it, are rendered by DataGridColumn - which has no stylesheet and
   therefore no scope attribute. The anchor is the thead, which this component
   does render.
*/
.datagrid thead[b-s8v0ydlg1m]  th.datagrid_column {
    /*
       The containing block for the handle below.

       Safe on THIS cell and deliberately not applied to the filter's, which
       holds an absolutely-positioned dropdown: positioning that cell would make
       it the dropdown's containing block, and the grid's row area clips - so the
       filter panel would be cut off at the edge of the grid instead of floating
       over the window. That is the same trap the dock menu documents from the
       other end.
  */
    position: relative;
}

/*
   The grab area, on the column's right edge.

   THE SAME SHAPE AS A WINDOW SPLITTER, deliberately: a finger-sized transparent
   handle with a hairline drawn by ::after, thin enough to read as a boundary
   rather than a gutter. Same idiom, same colours, so a column edge and a dock
   edge look like the same affordance - which they are.

   Inside the cell rather than straddling the join, which is where the splitters
   sit. An absolutely-positioned child contributes to its scroll container's
   overflow, so a handle hanging 6px past the LAST column would add 6px of
   horizontal scroll to a table that otherwise fits exactly. Ten pixels of the
   column's own trailing edge is a large enough target without that.
*/
.datagrid thead[b-s8v0ydlg1m]  th.datagrid_column .datagrid_column_resize {
    position: absolute;
    top: 0;
    right: 0;
    z-index: 1;
    display: flex;
    width: 10px;
    height: 100%;
    cursor: col-resize;
    /*
       The pointer has to be able to grab this, and the cell above carries a
       Bootstrap tooltip attribute - so the handle sits above the cell's own
       content rather than beside it.
  */
    touch-action: none;
    user-select: none;
}

    /*
       The line, ALWAYS VISIBLE. It was `border-right: 1px solid transparent`
       lit only on hover, which is no affordance at all: nothing on screen said
       the column could be resized, so there was nothing to aim at and no reason
       to try. The splitters have never done that - .window_splitter::after is
       painted at rest and merely brightens - and this now matches them value
       for value.
  */
    .datagrid thead[b-s8v0ydlg1m]  th.datagrid_column .datagrid_column_resize::after {
        content: "";
        width: 1px;
        height: 100%;
        margin-left: auto;
        background: var(--window-splitter-color, rgba(255,255,255,0.14));
        transition: background 120ms ease;
    }

    /*
       Lit while hovered, and while THIS handle is being dragged.

       The second half is not decoration and the splitters record why: a drag
       holds pointer capture, so the moment the pointer outruns the handle
       nothing is hovered any more and the line being dragged would go dark
       mid-drag. DataGrid.razor.js puts the active class on the handle for
       exactly the span of the drag.
  */
    .datagrid thead[b-s8v0ydlg1m]  th.datagrid_column .datagrid_column_resize:hover::after,
    .datagrid thead[b-s8v0ydlg1m]  th.datagrid_column .datagrid_column_resize_active::after {
        background: var(--window-splitter-color-active, rgba(255,255,255,0.4));
    }

/*
   While a drag is in flight.

   The cursor is put on the whole grid because the pointer is captured by the
   handle and will very often be outside it - without this it reverts to the
   default arrow the moment it leaves the 6px strip, which reads as the drag
   having ended. Selection is killed for the same reason: a drag across a table
   otherwise highlights every cell it crosses.
*/
.datagrid_resizing[b-s8v0ydlg1m] {
    cursor: col-resize;
    user-select: none;
}

    .datagrid_resizing[b-s8v0ydlg1m]  * {
        cursor: col-resize;
    }

/*
   A grid that asks for its columns' width - see DataGrid.SizesToColumns. The
   table is 100% wide under table-layout: fixed, which gives every container
   above it no usable preferred width, so a window sized by its content could
   never find the columns' width by measuring. The grid states it instead,
   capped by the room there is, and a maximized window still fills.
*/
.datagrid_sized[b-s8v0ydlg1m] {
    width: var(--datagrid-columns-width);
    max-width: 100%;
}

.window_maximized .datagrid_sized[b-s8v0ydlg1m] {
    width: auto;
}
/* /Components/UI/Duo/DuoSetUp.razor.rz.scp.css */
/* Duo's QR code, at the size the authenticator app's is drawn and for the
   same reason: a scanner needs modules a few pixels across, and a code
   stretched across a maximized window is harder to frame with a phone. */
.duo_qr[b-lekj0ucq8x] {
    display: block;
    width: 240px;
    height: 240px;
    margin: 0.5rem 0 0.75rem;
}
/* /Components/UI/HealthChart/HealthChart.razor.rz.scp.css */
/*
   SYSTEM HEALTH'S GRAPHS. The drawing stretches to its panel's width and keeps
   its height, so a phone gets the same graph narrower rather than a scrollbar.

   COLOURS ARE BOOTSTRAP'S OWN VARIABLES, which follow the theme, so a line is
   as readable in dark mode as in light with nothing written here for it. Eight
   series, then they repeat; a panel with more parts than that is a list first
   and a graph second.

   THE STROKE IS NON-SCALING, set on the element, so a line stays two pixels
   however far the viewBox stretches.
*/
.health_chart[b-3wwf1xf9xj] {
    margin: 0.5rem 0 1rem;
    min-width: 0;
}

.health_chart_frame[b-3wwf1xf9xj] {
    display: flex;
    gap: 0.5rem;
    align-items: stretch;
}

.health_chart_scale[b-3wwf1xf9xj] {
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
    text-align: right;
    white-space: nowrap;
    min-width: 3.5rem;
}

.health_chart_drawing[b-3wwf1xf9xj] {
    flex: 1 1 auto;
    min-width: 0;
    width: 100%;
    height: 9rem;
    overflow: visible;
}

.health_chart_rule[b-3wwf1xf9xj] {
    stroke: var(--bs-border-color);
    stroke-width: 1;
}

.health_chart_rule_faint[b-3wwf1xf9xj] {
    stroke-dasharray: 2 4;
}

.health_chart_line[b-3wwf1xf9xj] {
    fill: none;
    stroke-width: 2;
    stroke-linejoin: round;
    stroke-linecap: round;
}

.health_chart_axis[b-3wwf1xf9xj] {
    display: flex;
    justify-content: space-between;
    margin-left: 4rem;
    font-size: 0.75rem;
    color: var(--bs-secondary-color);
}

.health_chart_legend[b-3wwf1xf9xj] {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
    margin-top: 0.25rem;
    font-size: 0.85rem;
}

.health_chart_key[b-3wwf1xf9xj] {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    overflow-wrap: break-word;
}

.health_chart_swatch[b-3wwf1xf9xj] {
    display: inline-block;
    width: 1rem;
    height: 0.2rem;
    border-radius: 0.1rem;
    background: currentColor;
}

.health_chart_empty[b-3wwf1xf9xj] {
    margin: 0.25rem 0 1rem;
}

.health_chart_series_0[b-3wwf1xf9xj] { stroke: var(--bs-primary); color: var(--bs-primary); }
.health_chart_series_1[b-3wwf1xf9xj] { stroke: var(--bs-success); color: var(--bs-success); }
.health_chart_series_2[b-3wwf1xf9xj] { stroke: var(--bs-warning); color: var(--bs-warning); }
.health_chart_series_3[b-3wwf1xf9xj] { stroke: var(--bs-info); color: var(--bs-info); }
.health_chart_series_4[b-3wwf1xf9xj] { stroke: var(--bs-danger); color: var(--bs-danger); }
.health_chart_series_5[b-3wwf1xf9xj] { stroke: var(--bs-indigo, #6610f2); color: var(--bs-indigo, #6610f2); }
.health_chart_series_6[b-3wwf1xf9xj] { stroke: var(--bs-pink, #d63384); color: var(--bs-pink, #d63384); }
.health_chart_series_7[b-3wwf1xf9xj] { stroke: var(--bs-teal, #20c997); color: var(--bs-teal, #20c997); }

.health_chart_limit[b-3wwf1xf9xj] {
    stroke: var(--bs-secondary-color);
    color: var(--bs-secondary-color);
    stroke-dasharray: 6 4;
}

.health_chart_key .health_chart_swatch.health_chart_limit[b-3wwf1xf9xj] {
    background: repeating-linear-gradient(90deg, currentColor 0 0.35rem, transparent 0.35rem 0.55rem);
}
/* /Components/UI/IconPicker/IconPicker.razor.rz.scp.css */
/*
   The picker's own box draws nothing, so its button is one more item in the
   .icon_field row beside the text box and the preview, and the panel, at
   flex-basis 100%, wraps onto a line of its own beneath them.

   A row is a grid of eight equal columns rather than fixed squares, so a
   phone-width window shrinks the buttons instead of pushing the eighth off the
   side. The scroll box has a stated height because Virtualize draws only what
   that box shows; with none it would grow to every row.
*/

.icon_picker[b-3zqhhxkvn6] {
    display: contents;
}

.icon_picker_toggle[b-3zqhhxkvn6] {
    flex-shrink: 0;
    width: 2.25rem;
    height: 2.25rem;
    padding: 0;
    font-size: 1.25rem;
    line-height: 1;
}

.icon_picker_panel[b-3zqhhxkvn6] {
    flex: 1 1 100%;
    min-width: 0;
    padding: 8px;
    border: 1px solid rgba(255, 255, 255, 0.18);
    border-radius: 6px;
    background-color: rgba(255, 255, 255, 0.04);
}

.icon_picker_grid[b-3zqhhxkvn6] {
    max-height: 15rem;
    overflow-y: auto;
}

.icon_picker_row[b-3zqhhxkvn6] {
    display: grid;
    grid-template-columns: repeat(8, minmax(0, 1fr));
    gap: 4px;
    height: 40px;
    padding-bottom: 4px;
}

.icon_picker_choice[b-3zqhhxkvn6] {
    display: flex;
    align-items: center;
    justify-content: center;
    min-width: 0;
    padding: 0;
    border: 1px solid transparent;
    border-radius: 6px;
    background: none;
    color: inherit;
    font-size: 1.25rem;
    line-height: 1;
}

.icon_picker_choice:hover[b-3zqhhxkvn6] {
    background-color: rgba(255, 255, 255, 0.08);
}

.icon_picker_choice[aria-pressed="true"][b-3zqhhxkvn6] {
    border-color: rgba(255, 204, 102, 0.55);
    background-color: rgba(255, 204, 102, 0.12);
}
/* /Components/UI/LiveServiceGate.razor.rz.scp.css */
/*
   The blocking layer.

   ABOVE EVERYTHING. The drawer menus sit at 1600 and the drawer scrim at 1500,
   which are the highest things this application draws - so this has to clear
   them or an open launcher menu would float over a modal that is supposed to be
   blocking the whole app. Blazor's own reconnect dialog uses the top layer and
   is above this by construction, which is the right way round: if the circuit
   itself has dropped, that is the more fundamental problem and its message
   should win.

   backdrop-filter is safe here where it was not on the overlay windows: this
   element never animates its opacity, and an element with opacity < 1 is its
   own backdrop root, which is what made the filter sample nothing there.
*/
.live_service_gate[b-yxoxce95u2] {
    position: fixed;
    inset: 0;
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 16px;
    background-color: rgba(5, 8, 22, 0.55);
    backdrop-filter: blur(6px);
}

/*
   The panel. Deliberately close to Blazor's reconnect dialog in weight and
   shape - same situation, same promise - while wearing this application's own
   amber accent rather than the framework default.
*/
.live_service_gate_panel[b-yxoxce95u2] {
    max-width: 420px;
    padding: 24px 28px;
    border: 1px solid rgba(255, 204, 102, 0.55);
    border-radius: 10px;
    background-color: rgba(32, 32, 40, 0.96);
    box-shadow: 0 40px 120px rgba(0,0,0,0.55), 0 0 8px 4px rgba(0,0,0,0.5);
    color: white;
    text-align: center;
}

    .live_service_gate_panel p[b-yxoxce95u2] {
        margin: 8px 0px 0px 0px;
    }

.live_service_gate_heading[b-yxoxce95u2] {
    margin: 12px 0px 0px 0px;
    font-size: 1.15rem;
    font-weight: 600;
}

/*
   The one moving thing. bx-spin comes from Boxicons' animations.min.css, which
   App.razor loads beside the glyph font - the same stylesheet that carries the
   size scale. Checking only fonts/basic/boxicons.min.css says these do not
   exist, because that file is glyph names and nothing else.
*/
.live_service_gate_spinner i[b-yxoxce95u2] {
    font-size: 2.25rem;
    color: rgba(255, 204, 102, 0.9);
    animation: live_service_gate_spin-b-yxoxce95u2 1.4s linear infinite;
}

@keyframes live_service_gate_spin-b-yxoxce95u2 {
    from {
        transform: rotate(0deg);
    }

    to {
        transform: rotate(360deg);
    }
}

/*
   The consequence, said plainly and quietly. It is the part that tells somebody
   whether to wait or to go and start the service, so it is here rather than in
   a log nobody reads - but it is secondary to "this is being retried".
*/
.live_service_gate_detail[b-yxoxce95u2] {
    color: rgba(255, 255, 255, 0.65);
    font-size: 0.85rem;
}
/* /Components/UI/LookalikeOffer/LookalikeOffer.razor.rz.scp.css */
/*
   One match per row, its name and its button, wrapping to a second line when
   the dialog is narrow. min-width: 0 on the name, because a flex item will not
   shrink below its content's width without it, and a long name would otherwise
   push the button off the side of a phone-width window.
*/

.lookalike_offer[b-3vwjfunwgp] {
    list-style: none;
    margin: 0;
    padding: 0;
}

.lookalike_offer li[b-3vwjfunwgp] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.25rem;
}

.lookalike_offer_name[b-3vwjfunwgp] {
    flex: 1 1 10rem;
    min-width: 0;
    overflow-wrap: anywhere;
}
/* /Components/UI/MaintenanceBanner.razor.rz.scp.css */
/*
   The maintenance strip, first in the page's flex column, so the window
   area shrinks to make room for it rather than having it laid over a
   titlebar. It never grows: flex 0 0 auto keeps it to its own text, which
   wraps on a phone.

   The amber edge is the live-service gate's, the one other thing that
   speaks for the whole application rather than for a window.
*/
.maintenance_banner[b-d5m619leab] {
    flex: 0 0 auto;
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 12px;
    padding: 8px 16px;
    border-bottom: 1px solid rgba(255, 204, 102, 0.55);
    background-color: rgba(32, 32, 40, 0.92);
    color: white;
}

.maintenance_banner_closed[b-d5m619leab] {
    border-bottom-color: rgba(255, 120, 120, 0.65);
}

.maintenance_banner_heading[b-d5m619leab] {
    font-weight: 600;
}

/*
   min-width: 0, or a long unbroken word in the message refuses to shrink and
   widens the page past a phone's screen. break-word rather than anywhere:
   anywhere counts toward the min-content width, so a flex item wearing it can
   be squeezed to one letter per line beside the heading.
*/
.maintenance_banner_message[b-d5m619leab] {
    min-width: 0;
    overflow-wrap: break-word;
}
/* /Components/UI/ProfileFields/ProfileFieldTable.razor.rz.scp.css */
/*
    Who a field is shared with, beside its value.

    Quieter than the value on purpose: it is the answer to a question the reader
    only sometimes has, and reading the profile back should be reading the
    values, not a column of settings.
*/
.profile_field_access[b-clyqi25xwr]
{
    padding: 1px 6px;
    border: 1px solid currentColor;
    border-radius: 999px;
    font-size: 0.75em;
    opacity: 0.7;
    white-space: nowrap;
}

/*
    The fields, as a real table with the visibility in a column of its own.

    A TABLE RATHER THAN A DEFINITION LIST BECAUSE OF THE THIRD COLUMN. Beside
    the value, each badge starts wherever its own value happened to end, so a
    screen of them comes out ragged and reads as something broken rather than
    as a column. A column can be scanned; that is the whole job of that
    information.

    THE OUTER ELEMENT SCROLLS, THE TABLE DOES NOT WRAP THE WINDOW. Standing
    rule for any wide content: a value long enough to push the table past the
    window scrolls inside its own box rather than putting a horizontal
    scrollbar on the whole page.
*/
.profile_fields_scroll[b-clyqi25xwr]
{
    overflow-x: auto;
}

.profile_fields[b-clyqi25xwr]
{
    width: 100%;
    border-collapse: collapse;
}

/*
    THE LABEL COLUMN TAKES WHAT IT NEEDS AND NO MORE. `width: 1%` with
    `white-space: nowrap` is the old and reliable way of saying shrink-to-fit
    in a table: the declared width is smaller than the content, so the browser
    gives the column its minimum and hands the rest to the flexible column.

    NOT a fixed rem measure - a label here can be a tenant's own wording for
    "Marital status", so its length is not something this stylesheet knows.
*/
.profile_fields th[b-clyqi25xwr]
{
    width: 1%;
    white-space: nowrap;
    text-align: left;
    font-weight: 600;
    opacity: 0.75;
    padding: 3px 12px 3px 0;
    vertical-align: top;
}

.profile_fields td[b-clyqi25xwr]
{
    padding: 3px 0;
    overflow-wrap: break-word;
    vertical-align: top;
}

/*
    The badge column: shrink-to-fit like the label, and pushed to the trailing
    edge so every badge on the screen shares one edge to read down.
*/
.profile_fields_access_cell[b-clyqi25xwr]
{
    width: 1%;
    white-space: nowrap;
    text-align: right;
    padding-left: 12px;
}
/* /Components/UI/RecordedFields/RecordedSearch.razor.rz.scp.css */
/*
   The search box and its button on one row, the box taking what is left.

   min-width: 0 on the box, because a flex item will not shrink below its
   content's width without it, and an input's intrinsic width is a desktop
   size: at 375px the button would be pushed off the right edge of the dialog.
*/
.recorded_search_row[b-f5p00tis37] {
    display: flex;
    gap: 8px;
}

.recorded_search_row input[b-f5p00tis37] {
    flex: 1 1 auto;
    min-width: 0;
}

.recorded_search_row button[b-f5p00tis37] {
    flex: 0 0 auto;
}
/* /Components/UI/ScheduleFields/ScheduleFields.razor.rz.scp.css */
/*
    The schedule form's two shapes: a row of tick boxes that wraps, and the
    preview panel under it.
*/

/*
    THE WEEKDAY BOXES. A wrapping row rather than a column, because seven of
    them down the page pushes the preview - the one control that answers the
    question - off the bottom of a content-sized dialog.

    THE BASIS IS A WRAPPING THRESHOLD RATHER THAN A WIDTH. Each item still grows
    into whatever is left; 7rem is where the row should BREAK, which on a phone
    puts two per line and on a desktop puts all seven on one. A basis set to
    what the content would like makes a row wrap while there is still room.
*/
.schedule_flags[b-u94ez2z4ox]
{
	display: flex;
	flex-wrap: wrap;
	gap: 0.25rem 0.75rem;
	margin-top: 0.25rem;
}

.schedule_flags > *[b-u94ez2z4ox]
{
	flex: 1 1 7rem;
}

/*
    THE PREVIEW. Set apart with a rule rather than a box, because a box inside a
    dialog that is itself a box reads as a second window.
*/
.schedule_preview[b-u94ez2z4ox]
{
	border-top: 1px solid var(--as-border, rgba(255, 255, 255, 0.15));
	padding-top: 0.75rem;
}

.schedule_preview h3[b-u94ez2z4ox]
{
	font-size: 1rem;
	margin-bottom: 0.5rem;
}

/*
    The dates themselves. Tabular figures so five of them line up as a column of
    numbers rather than as five sentences - which is what makes the interval
    between them readable at a glance, and reading the interval is the whole
    point of showing five.
*/
.schedule_preview ul[b-u94ez2z4ox]
{
	font-variant-numeric: tabular-nums;
	margin-bottom: 0.5rem;
	padding-left: 1.25rem;
}
/* /Components/UI/Screen/Screen.razor.rz.scp.css */
/*
   The window's footer: one row under the scroll area holding the window's
   Close at its right. Screen draws it, and WindowFrame's outlet places it in
   .window_container, a flex column, after .window_content_padding.

   flex: 0 0 auto, so a window capped in height or maximized gives the room to
   the scroll area above it rather than squeezing the footer, and a grid that
   fills the window measures the scroll area alone and so leaves the footer
   where it is.

   The sides and bottom are .window_content_padding's 3px plus the aura's
   reach inside .window_content, so Close lines up with the sections' right
   edge and its focus ring is not cut by .window_container, which clips. The
   top is nothing: the scroll area's own bottom padding is the gap.
*/
.window_footer[b-0ze290nl0j] {
    flex: 0 0 auto;
    display: flex;
    justify-content: flex-end;
    padding: 0 calc(3px + var(--aura-reach)) calc(3px + var(--aura-reach));
}
/* /Components/UI/Section/Section.razor.rz.scp.css */
/*
   The one element the content always sits in, whatever state the section is
   in. Two jobs, and the second is why it is a real box.

   1. Section.razor.js roots its "which field gets the caret" query here.
      Section renders the form but not the fields inside it, so this wrapper
      is the only handle it has on them.
   2. It carries the blocked state below.

   It was display: contents, chosen so a wrapper added for job 1 could not
   move anything. Job 2 rules that out: display: contents generates no box,
   and opacity has nothing to apply to, so the dimming simply would not
   paint. Measured against the real Login window before changing it - the
   form's geometry is identical either way, x/y/width/height to the pixel -
   so the box costs nothing here. Worth re-measuring if a section is ever
   dropped straight into a flex or grid parent, where a block child is not
   the same thing as no child.
*/
.section_form[b-yekh2crnk9] {
    display: block;

    /*
       Two durations, because the two states they serve last for very different
       lengths of time.

       OPACITY IS FAST (160ms) because it is the save, and a save against a
       local API is over in a few hundred milliseconds. Anything slower than
       this spends the whole round trip mid-transition and the section never
       settles anywhere - which is exactly what went wrong with the blur this
       replaced: 220ms out and 220ms back meant the form was blurring or
       unblurring for essentially the entire operation, and reading a thing
       that never holds still is noise rather than feedback.

       FILTER IS SLOWER (220ms) because it serves the locked state, which lasts
       as long as a modal is open. That is .window_lock's own figure, and this
       is the same gesture at a smaller scale.

       Idle is `filter: none` rather than `blur(0px)`, which is the reason
       .window_lock gives and it holds here too: blur(0) is not free, it
       promotes the element to its own composited layer permanently for no
       visual gain. Interpolating from `none` is well defined - the browser
       substitutes the identity value - so the transition still animates.
    */
    transition: opacity 160ms ease, filter 220ms ease;
}

/*
   Stacks the form and the saving indicator in one grid cell, so the indicator
   is drawn OVER the content rather than in place of it.

   Grid rather than position:absolute, and that is the load-bearing part. An
   absolutely-positioned overlay needs a positioned wrapper, and a positioned
   wrapper becomes the containing block for every absolutely-positioned thing
   a window renders inside its form - a dropdown, a popover, a picker - which
   silently clips or re-anchors them. Two children assigned the same grid area
   overlap and nothing's containing block changes.

   Both subjects below are elements THIS component renders, which is why
   neither needs ::deep. SectionBusy's own root is left alone: it is given a
   wrapper here rather than being positioned from a distance, so it stays
   usable on its own in the Loading branch.
*/
.section_busy_host[b-yekh2crnk9] {
    display: grid;
}

/*
   Stretches the section to the height the window gives it.

   min-height rather than height, so content taller than the window still
   grows the box and .window_content scrolls it, instead of being clipped at
   exactly one screenful.

   IT IS SELF-LIMITING TO MAXIMIZED WINDOWS, which is the neat part and is
   worth not "fixing" later. .window_content is a flex item that grows; in a
   maximized window the chain above it has a definite height so this resolves
   and the section fills. In a NORMAL window the whole frame is sized BY its
   content, so that height is indefinite, a percentage min-height resolves
   against nothing, and the section shrink-wraps exactly as before. One rule,
   both behaviours, no breakpoint and no class toggling on maximize.

   What it fixes is the indicator jumping. The overlay is sized to this box, so
   while the box shrink-wraps the form, anything that changes the form's height
   during a save - a validation message arriving is the obvious one - drags the
   hourglass up or down with it. A constant box means a constant centre.
*/
.section_fill[b-yekh2crnk9] {
    min-height: 100%;
}

/*
   The frame every section wears unless the window says Framed="false", in the
   app.css tokens System Health's grids and graphs wear, so where one section
   ends and the next begins is drawn.

   ON THIS BOX, the one that is already the section's whole extent in every
   state, so the frame does not change as the section loads or saves. The
   padding inside it is also the room a focus ring needs, which a clipping
   container would otherwise take.

   SPACED FROM THE SECTION ABOVE, never from the one below. A bottom margin on
   the last section would be a scrollbar in a maximized window, since nothing
   follows it to absorb it; a top margin on a section that has one above it
   costs nothing anywhere else.

   A filling section stays exactly the window's height with the frame on: the
   border box is what min-height measures, so the padding comes out of it. The
   grid's own measurement subtracts the frame below it in DataGrid.razor.js.
*/
.section_framed[b-yekh2crnk9] {
    padding: var(--frame-padding);
    border: var(--frame-border);
    border-radius: var(--frame-radius);
    background-color: var(--frame-fill);
}

    .section_framed + .section_framed[b-yekh2crnk9] {
        margin-top: var(--frame-gap);
    }

    .section_busy_host > .section_form[b-yekh2crnk9],
    .section_busy_host > .section_busy_overlay[b-yekh2crnk9] {
        grid-area: 1 / 1;
        /*
           STAY INSIDE THE TRACK.

           A grid item defaults to `min-width: auto`, which is its CONTENT's
           min-content width - so an item whose content is genuinely wide grows
           past its own grid area instead of letting that content overflow.
           Nothing in a section is normally wide enough to notice, which is why
           this went unnoticed until a DataGrid's columns became draggable:
           widening them pushed this element to 2053px inside a 1254px track,
           and the grid's own `overflow-x: auto` never engaged because it was
           being stretched to the full width rather than constrained.

           min-width: 0 hands the decision back to whatever is inside. It has no
           effect at all until content would overflow, so a form that fits is
           laid out exactly as before.
        */
        min-width: 0;
    }

/*
   The overlay's own box. A soft scrim so the indicator stays legible over
   whatever text it happens to land on, and pointer-events off so it is never
   the thing a click hits - the form beneath is already inert, and one
   statement about interaction is better than two that can disagree.

   --section-busy-min-height is SectionBusy's floor, overridden to nothing
   here. Left at its default the indicator would force the grid row to 180px,
   so a short form would grow while it saved and shrink back afterwards. Custom
   properties inherit across component boundaries, so setting it on this
   element reaches SectionBusy without a selector that has to reach into it.
*/
.section_busy_overlay[b-yekh2crnk9] {
    --section-busy-min-height: 0;

    display: flex;
    align-items: center;
    justify-content: center;
    pointer-events: none;

    /*
       NO BACKGROUND. This element positions the hourglass and nothing else.

       It had a scrim - rgba(0,0,0,0.45), copied from .window_locked - and it
       was wrong here for a reason worth keeping: a scrim is a sheet of dark
       laid OVER something, and over a whole window that is invisible as a
       shape, because it covers everything the eye can see. Over a section it
       is a dark RECTANGLE sitting on part of a window, with four visible
       edges, and it reads as a box that has appeared rather than as content
       going away.

       What replaced it is .section_saving fading the content itself right out,
       which needs nothing laid over anything.

       THE DELAY IS THE IMPORTANT PART OF THIS RULE. The content takes 160ms to
       fade out, so the hourglass waits until that is nearly done before it
       starts - it is not a cross-fade, it is a handover. `both` holds it at
       opacity 0 through the delay rather than letting it show early.

       IT COMES FROM C#, as --section-busy-appear-delay, and the fallback here
       is only for an overlay rendered without it. Submit adds the same figure
       to MinimumIndicatorMilliseconds so that parameter can mean the
       indicator's own time on screen rather than the saving state's, which
       means the number is needed in both places - and a duration living
       independently in a stylesheet and a code file is one that disagrees with
       itself the first time either is tuned.

       With the minimum hold at its default the delay is invisible, because
       every save now lasts longer than it. It still matters at
       MinimumIndicatorMilliseconds = 0, where it goes back to its original
       job: a save quicker than the delay shows no hourglass at all, only the
       content dipping and recovering, which is the right amount of feedback at
       that speed and far better than a spinner appearing and vanishing inside
       a fifth of a second.

       An animation rather than a transition because this element is added to
       the DOM rather than being always present, so it has no previous state to
       transition FROM - the trick .window_shadow::after uses to avoid popping
       is not available here.

       There is deliberately no exit. The element is removed the instant the
       state changes, and the content fading back over 160ms covers that end.
    */
    animation: section_busy_overlay_in-b-yekh2crnk9 160ms ease var(--section-busy-appear-delay, 140ms) both;
}

@keyframes section_busy_overlay_in-b-yekh2crnk9 {
    from {
        opacity: 0;
    }

    to {
        opacity: 1;
    }
}

/*
   The button row: Submit, plus whatever the window put in ActionContent.

   flex-wrap is the load-bearing part rather than a nicety. This app is
   mobile-first and a window is about 360px wide on a phone, while Login's
   row alone is "Login" + "Forgot Username" + "Forgot Password" - measured
   at roughly 340px of buttons before gaps. Without wrapping, the last one
   is simply off the side of the window: .window_content does not scroll
   sideways for it, and nothing reports a problem.

   gap rather than margins on the buttons, because the buttons belong to the
   window rather than to this component - a margin rule here would need
   ::deep to reach them, and gap needs to reach nothing. Same reason the
   margin-top lives here instead of the `mt-2` the Submit button used to
   carry: one owner for the row's spacing.
*/
.section_actions[b-yekh2crnk9] {
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
}

/*
   Content that is on screen but must not be touched - saving, or locked
   behind a modal. One class for both, because it is one statement: "this is
   still here, and it is not yours right now".

   APPEARANCE ONLY. Blocking interaction is the `inert` attribute the markup
   puts on the same element, not CSS, and the difference matters:
   `pointer-events: none` stops a mouse and nothing else. The caret is very
   often already in a field when a save starts, and
   from there the keyboard reaches everything - including submitting the form
   again with Enter. `inert` takes the subtree out of hit-testing, out of the
   tab order and out of the accessibility tree.

   Those rules were also broken in their own right: their subjects were
   controls the WINDOW rendered, so isolation stamped the scope attribute
   where it matches nothing and pointer-events resolved to `auto`. The content
   dimmed to 45% and stayed fully editable, which is worse than not dimming
   it. Both faults were latent - nothing had ever put a form section into
   Locked, and Saving rendered an empty fragment rather than this.

   BLUR AT THE SOURCE, NOT A backdrop-filter ON THE INDICATOR, and the numbers
   are .window_locked's rather than new ones - this is the modal lock's
   gesture applied to one section, so it should not look like a second idea.

   The temptation is to put backdrop-filter on .section_busy_overlay, and
   WindowFrame.razor.css records why that was tried on the overlay windows and
   removed: an element with opacity < 1 is its own backdrop root, so during
   any fade the filter samples nothing at all and then snaps into focus the
   instant opacity reaches exactly 1. It also costs a permanent composited
   layer on the element being read. Blurring the source has neither problem
   and is what actually reads as "something is on top of this".

   SAVING AND LOCKED ARE TWO DIFFERENT PICTURES, and they were one class for a
   while because both happened to be a dim. They are not the same statement:

     locked  "still here, just not yours right now" - so the content stays
             visible and goes soft. Lasts as long as a modal is open.
     saving  "gone for a moment" - so it fades out entirely and the hourglass
             takes its place. Lasts one round trip.

   Collapsing them again makes one of the two wrong: a shared opacity: 0 leaves
   a locked form invisible with nothing explaining why, and a shared dim leaves
   a saving form half-showing behind the indicator.

   NOTHING IS LAID ON TOP in either case. A scrim was tried and is wrong at
   this scale - a sheet of dark over a whole window has no perceptible shape
   because it covers everything the eye can see, while the same sheet over one
   section is a rectangle with four visible edges and reads as a box appearing
   rather than as content going away.
*/

/*
   Saving. Straight to nothing, no blur.

   NO BLUR HERE, and the reason is how SHORT a save is: the round trip is a few
   hundred milliseconds, so a 220ms blur in and back leaves the form mid-
   transition for essentially all of it, never holding a settled state. A thing
   that is always mid-change reads as noise. Fading right out is a single
   legible event - content goes, hourglass arrives, content returns - and it
   has the side benefit that there is nothing left behind the indicator to
   compete with it.

   opacity: 0 and not `display: none` or `visibility: hidden`: the box has to
   keep its size or the section would collapse mid-save and the hourglass would
   move. `inert` in the markup is what actually stops it being touched -
   invisible content is still perfectly focusable and clickable.
*/
.section_saving[b-yekh2crnk9] {
    opacity: 0;
}

/*
   Locked, and ONLY when the window is not already locked - see IsSelfLocked.
   These are .window_locked's own numbers, because this is that gesture applied
   to one section and two sets of figures for one idea is how they drift.
*/
.section_locked[b-yekh2crnk9] {
    filter: blur(6px);
    opacity: 0.8;
}
/* /Components/UI/Section/SectionBusy.razor.rz.scp.css */
/*
   The busy indicator: a still hourglass, centred, with a shadow.

   NOTHING HERE ANIMATES, and nothing here is coloured. What says "something is
   happening" is the handover - see .section_saving in Section.razor.css, which
   fades the content out so this can arrive in the space it left, then fades it
   back. That is already one legible movement; an indicator that moves as well
   competes with it, and a coloured one pulls the eye towards the part of the
   window that has just been made unavailable.
*/
.section_busy[b-w9n36tzoi8] {
    display: flex;
    align-items: center;
    justify-content: center;

    /*
       Centred in the space available, which is what the floor buys: the
       section sits in .window_content, a flex column only as tall as its
       content, so height:100% would resolve against an auto height and
       collapse to the size of the hourglass itself. A floor plus centring
       gives the same result in a short window and a tall one.

       --section-busy-min-height is part of this component's contract, read as
       a var() FALLBACK rather than declared here. A declaration on this
       element would beat the inherited value and the override would silently
       do nothing. Section sets it to 0 when the indicator is laid over a form,
       where the floor would otherwise stretch the form's own row and a short
       form would visibly grow while saving and shrink back afterwards.
    */
    min-height: var(--section-busy-min-height, 180px);
    width: 100%;

    /*
       --section-busy-padding and --section-busy-glyph-height below are the same
       kind of contract, for a host far smaller than a window, where a 64px
       hourglass with 16px either side would grow the host while it saves.
    */
    padding: var(--section-busy-padding, 16px);
    box-sizing: border-box;

    /*
       Decorative, and laid over live content while a section is saving. It
       must never be the thing a click lands on - the content underneath is
       already inert, and making this transparent to the pointer keeps that
       one statement about interaction rather than two.
    */
    pointer-events: none;
    user-select: none;

    /*
       The only colour in the component, and the SVG's shapes all draw with
       currentColor at varying opacity - so the whole hourglass is retinted by
       changing this one line. Plain white, deliberately: the backdrop is a
       dark navy with blue and violet washes, and anything tinted reads as
       belonging to one of them.
    */
    color: rgba(255, 255, 255, 0.92);
}

.section_busy_hourglass[b-w9n36tzoi8] {
    display: block;
    height: var(--section-busy-glyph-height, 64px);
    aspect-ratio: 24 / 32;

    /*
       drop-shadow, not box-shadow. A filter runs on what is actually painted,
       so this traces the hourglass; box-shadow is cast by the element's border
       box and would put a soft grey rectangle behind it.

       Two layers: a tight dark one that separates the glyph from whatever it
       happens to be sitting on, and a wide soft one that lifts it off the
       blur. Both are black rather than tinted, for the reason `color` above is
       white.
    */
    filter: drop-shadow(0 2px 3px rgba(0, 0, 0, 0.9)) drop-shadow(0 8px 18px rgba(0, 0, 0, 0.65));
}
/* /Components/UI/StringLabel/StringLabel.razor.rz.scp.css */
/*
   An icon and its word, side by side, inside whatever opened them - a button,
   a menu entry, a heading.

   display: inline-flex rather than a block, because this sits INSIDE a control
   that has already decided its own box. A block here would fight the button's
   own padding and centring.
*/
.string_label[b-gcn41xg9wh] {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    min-width: 0;
}

/*
   The glyph.

   line-height: 1 so a font icon does not add the leading of a text line to a
   button that has already been sized for one - boxicons renders as text, and
   inherits every text metric unless told otherwise.

   flex-shrink: 0 because the icon is the part that must survive: it is what is
   left when the word goes.
*/
.string_label_icon[b-gcn41xg9wh] {
    flex-shrink: 0;
    line-height: 1;
    font-size: 1.05em;
}

.string_label_text[b-gcn41xg9wh] {
    min-width: 0;
}

/*
   THE NARROW STATE - the word goes and the glyph stays.

   VISUALLY HIDDEN, NOT display: none, AND THE DIFFERENCE IS THE WHOLE REASON
   THIS COMPONENT CAN BE USED ON A BUTTON. Text removed with display: none
   leaves the accessibility tree too, so a button whose only remaining content
   is an aria-hidden glyph has NO ACCESSIBLE NAME - it announces as "button".
   Clipped text is still read, still names the button, and occupies no space.

   The rule is the standard clip: absolute so it is out of flow, 1px so it has
   a box to clip, and inset(50%) so nothing of it paints. white-space: nowrap
   stops a clipped multi-word label from being re-laid out as one word per line
   before it is clipped, which some engines do and which costs layout for
   something nobody sees.

   IT IS A VIEWPORT QUERY, AND A CONTAINER QUERY IS WHAT THIS WANTS AND CANNOT
   HAVE. A container query needs an ancestor whose inline size does not depend
   on its contents, and `container-type: inline-size` is what declares that -
   but a window opened with OpenProgramDialog is `width: auto`, sized BY its
   content, so declaring a container anywhere inside it would break the window's
   own sizing rather than answer the question. Nothing between here and the
   viewport has a content-independent width.

   SO THIS SEES THE CASE THAT ACTUALLY FAILS AND NOT THE GENERAL ONE. On a
   phone the window IS the viewport - an overlay is capped at 100% - which is
   exactly where three verbs beside a thumbnail run out of room, measured at
   about 28px short. What it cannot see is a NARROW WINDOW ON A WIDE SCREEN: a
   400px dialog on a desktop keeps its words. That is the right way round of
   the two errors, since a wide screen has room to wrap.
*/
@media (max-width: 575.98px) {
    .string_label:not(.string_label_keep) .string_label_text[b-gcn41xg9wh] {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        padding: 0;
        overflow: hidden;
        clip-path: inset(50%);
        white-space: nowrap;
    }

    /*
       With the word gone the gap has nothing to separate, and 6px of it would
       sit as dead space inside every button on the row.

       AND THE GLYPH IS THEN SITTING ON A BASELINE THAT NOTHING ELSE IS USING,
       WHICH IS WHY IT LOOKS HIGH. This is an inline-flex box, so it is
       INLINE-LEVEL: it sits on the enclosing button's text baseline rather than
       in the middle of it, with the font's descender left empty underneath.
       With the word present that is exactly right - the word is text and
       belongs on the baseline - but once the glyph is alone in the box there is
       no text for it to line up with, and the empty descender reads as the icon
       riding high. Measured at 375px: 2px above the button's centre, against
       1px in the wide state where the word is still there.

       HALF THE DESCENDER IS THE CORRECTION, and `em` is what keeps it true when
       the font size changes - the gap is a property of the font's metrics, so a
       pixel here would drift the moment a button set its own size. Measured to
       land exactly on centre in both axes.

       NOT `vertical-align: middle`, WHICH OVERSHOOTS: it aligns to the baseline
       plus half the X-HEIGHT, not half the line box, and measured 2.4px BELOW
       centre - a worse error than the one being fixed, in the other direction.

       AND NOT `display: flex`, WHICH CENTRES PERFECTLY AND COSTS THE BUTTON ITS
       HEIGHT. A block-level child leaves no line box, so the button stops being
       sized by its own line-height: measured 30.4px against 37.6px for the text
       buttons beside it, which is both a visibly shorter control in the row and
       a smaller touch target.
    */
    .string_label:not(.string_label_keep)[b-gcn41xg9wh] {
        gap: 0;
        vertical-align: -0.125em;
    }
}
/* /Components/UI/TabPanel/TabPanel.razor.rz.scp.css */
/*
   THE ROW OF TABS. One line on a rule, the chosen tab underlined in the aura's
   gold and the rest quieter: a tab says where you are, which is the job the
   gold rim does for a held button, so the row wears that colour and not the
   glow every pressable thing at rest wears - eight glowing tabs are haze.

   THE ROW SCROLLS SIDEWAYS rather than wrapping, so a phone gets one line it
   can swipe instead of three it has to read. A scrolling box clips on both
   axes, so the focus ring is drawn inset, where the clip cannot reach it.
*/
.tab_panel[b-ms6q9m4zen] {
    min-width: 0;
}

.tab_panel_tabs[b-ms6q9m4zen] {
    display: flex;
    gap: 0.25rem;
    overflow-x: auto;
    overflow-y: hidden;
    scrollbar-width: thin;
    border-bottom: 1px solid var(--bs-border-color);
    margin-bottom: 0.75rem;
}

.tab_panel_tab[b-ms6q9m4zen] {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    flex: 0 0 auto;
    padding: 0.45rem 0.75rem;
    border: 0;
    border-bottom: 2px solid transparent;
    background: transparent;
    color: var(--bs-secondary-color);
    white-space: nowrap;
    transition: color 0.15s ease-in-out, border-color 0.15s ease-in-out;
}

/* Where StringLabel leaves only the glyph, so a row of eight fits a phone without scrolling. */
@media (max-width: 575.98px) {
    .tab_panel_tab[b-ms6q9m4zen] {
        gap: 0.25rem;
        padding: 0.45rem 0.5rem;
    }
}

.tab_panel_tab:hover[b-ms6q9m4zen] {
    color: var(--bs-body-color);
    border-bottom-color: rgba(var(--aura-hue), 0.4);
}

.tab_panel_tab:focus-visible[b-ms6q9m4zen] {
    outline: var(--aura-focus-ring);
    outline-offset: var(--aura-focus-inset);
}

.tab_panel_tab_chosen[b-ms6q9m4zen],
.tab_panel_tab_chosen:hover[b-ms6q9m4zen] {
    color: var(--bs-body-color);
    border-bottom-color: rgba(var(--aura-hue), 1);
}

.tab_panel_count[b-ms6q9m4zen] {
    min-width: 1.4em;
    padding: 0 0.4em;
    border-radius: 0.7em;
    font-size: 0.75rem;
    line-height: 1.4;
    text-align: center;
    background: var(--bs-secondary-bg);
    color: var(--bs-body-color);
}

.tab_panel_dot[b-ms6q9m4zen] {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
}

.tab_panel_attention[b-ms6q9m4zen] {
    background: var(--bs-danger);
    color: #fff;
}
/* /Components/UI/WindowPurpose/WindowPurpose.razor.rz.scp.css */
/* The sentence under the window's own name.

   Quieter than the content below it, because it is context rather than
   something to act on - the same weight .text-body-secondary gives every other
   explanatory line in these screens, stated here rather than borrowed so this
   component owns its own appearance.

   margin-top: 0 because it is always the first thing in a window's content and
   the frame already pads above it; the bottom margin is what separates it from
   the toolbar underneath.

   contain: inline-size because a child window is a dialog sized by its
   content, and a sentence asks for its whole length - up to .string_editor's
   40rem cap - where the fields under it might ask for half that. Contained, it
   adds nothing to the width and wraps to whatever the form sets. In a window
   that has been given a width, the list windows and anything maximized, it
   changes nothing. */
.window_purpose[b-kuqv22lrmb] {
    margin-top: 0;
    margin-bottom: 0.75rem;
    color: var(--bs-secondary-color);
    contain: inline-size;
}
/* /Components/UI/Window/HelpPanel.razor.rz.scp.css */
/*
   A section's help in the Help panel: its name a step above the headings a
   body may hold, which RichTextView draws as h2 and h3 at 1.4rem and
   1.15rem, and a rule above it so each section reads as its own part of
   the window - except the first part, where the window has no help of its
   own and nothing stands above it.
*/
.help_section[b-vpm482nr6f] {
    margin-top: 1rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--bs-border-color-translucent);
}

.help_section:first-child[b-vpm482nr6f] {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

.help_section_name[b-vpm482nr6f] {
    font-size: 1.5rem;
    margin: 0 0 0.5rem;
}
/* /Components/UI/Window/ProfileSwitcher.razor.rz.scp.css */
/*
   The acting profile's face, pinned at the start of the drawer's left cell.

   44px TO MATCH A MINIMIZED ENTRY, not 64 to match the rendition it is drawn
   from. Two reasons, and the second is the one that bites: a 64px circle
   towers over the 44px squares beside it and stops reading as part of that
   row, and the drawer's left cell is only about 139px wide on a phone - so
   every pixel here is taken from the workspaces, where an entry costs 50.
   The source is the 64-square either way and downscales cleanly.
*/

/*
   The section a switch runs through. flex: 0 0 auto because this is the flex
   item in the drawer's leading row, and the face is pinned; the two
   variables size the section's hourglass to the face, since the defaults are
   for a window and would grow the drawer while a switch runs.
*/
.profile_switcher[b-x50rq21dlx] {
    flex: 0 0 auto;
    --section-busy-glyph-height: 28px;
    --section-busy-padding: 0;
}

.profile_switcher_button[b-x50rq21dlx] {
    /*
       THE RIM AND THE GLOW ARE app.css's --aura-* TOKENS, which every
       pressable thing in the application reads - see "THE GOLD AURA" there.
       Never restate a value: the launch button once carried its own numbers
       and had silently drifted from the rest of the chrome by the time anyone
       compared them.
    */
    border: 1px solid var(--aura-border);
    box-shadow: var(--aura-rest);
    border-radius: 50%;
    /*
       Transparent for the same reason .launch_button is: this is a ring drawn
       AROUND a picture rather than a pill with a label on it, and a
       translucent dark fill would sit over the face it exists to frame.
    */
    background-color: transparent;
    width: 44px;
    height: 44px;
    padding: 0;
    /* Breathing room against the workspace row, which packs hard rightwards. */
    margin: 2px 6px 2px 2px;
    /* Block-level: inside the section's block wrapper an inline box would sit on a line box and gain a strut. */
    display: flex;
    align-items: center;
    justify-content: center;
    /* Never let the face be squeezed: it is pinned, and the row beside it is
       what gives way when the drawer runs out of width. */
    flex: 0 0 auto;
    overflow: hidden;
    color: rgba(255, 255, 255, 0.75);
    cursor: pointer;
    transition: all 0.2s ease;
}

    .profile_switcher_button:hover[b-x50rq21dlx] {
        border: 1px solid var(--aura-border);
        box-shadow: var(--aura-hover);
        color: white;
    }

    /*
       A plain :active, never :hover:active - :hover cannot match a keyboard
       press, so opening this with Space or Enter would say nothing at all.
    */
    .profile_switcher_button:active[b-x50rq21dlx] {
        border: 1px solid var(--aura-border-active);
        box-shadow: var(--aura-hover);
    }

    .profile_switcher_button:focus-visible[b-x50rq21dlx] {
        outline: var(--aura-focus-ring);
        outline-offset: var(--aura-focus-offset);
    }

/*
   object-fit rather than a plain width/height, which would squash a face that
   is not square. The renditions are cropped square in the browser before they
   are sent, so this is a guard rather than the normal case.
*/
.profile_switcher_face[b-x50rq21dlx] {
    width: 100%;
    height: 100%;
    object-fit: cover;
    border-radius: 50%;
    display: block;
}

/*
   The menu, opening up the left side of the screen.

   A floor rather than a width, like .launcher_menu: with short names it is
   still sized by its content. max-height keeps a long list inside the
   viewport, and the scroll is the menu's own rather than the page's.
*/
.profile_switcher_menu[b-x50rq21dlx] {
    min-width: 220px;
    max-width: min(92vw, 360px);
    max-height: min(70dvh, 560px);
    overflow-y: auto;
    overflow-x: hidden;
}

.profile_switcher_choice[b-x50rq21dlx] {
    display: flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    padding: 6px 10px;
    border: 1px solid transparent;
    border-radius: 8px;
    background-color: transparent;
    color: rgba(255, 255, 255, 0.85);
    text-align: start;
    cursor: pointer;
    transition: all 0.15s ease;
}

    .profile_switcher_choice:hover[b-x50rq21dlx] {
        border-color: var(--aura-border);
        background-color: rgba(255, 255, 255, 0.08);
        color: white;
    }

    .profile_switcher_choice:focus-visible[b-x50rq21dlx] {
        outline: var(--aura-focus-ring);
        /*
           INSET, like .launcher_view_button's. These stack with no gap between
           them, so an outset ring would be drawn over the entry above.
        */
        outline-offset: var(--aura-focus-inset);
    }

    /*
       The one already being acted as. The BORDER carries it rather than a fill,
       matching how .launcher_view_active marks the chosen view - and
       aria-current says the same thing to a reader who cannot see the gold.
    */
    .profile_switcher_choice.profile_switcher_current[b-x50rq21dlx] {
        border-color: var(--aura-border-active);
    }

    .profile_switcher_choice:disabled[b-x50rq21dlx] {
        opacity: 0.6;
        cursor: default;
    }

/*
   64px HERE, where the user's instinct about the size belongs: this menu has
   room, and a face is what somebody is picking by. The group menu already
   draws pictures at this size.
*/
.profile_switcher_choice_face[b-x50rq21dlx] {
    width: 64px;
    height: 64px;
    object-fit: cover;
    border-radius: 50%;
    flex: 0 0 auto;
    display: block;
}

/*
   The placeholder wears the same box so the rows stay a uniform height - a
   list mixing profiles with and without pictures was 78px against 50px. The
   ring says the empty circle is a face's place rather than a missing image.
*/
.profile_switcher_placeholder[b-x50rq21dlx] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--aura-border);
    color: rgba(255, 255, 255, 0.55);
}

/*
   break-word, NEVER anywhere. `anywhere` counts toward the element's
   min-content width, so a flex child carrying it can be squeezed to a single
   character per line rather than making its neighbours give way - which is
   exactly what the profile list rendered at 375px. `break-word` breaks a word
   that has already overflowed and leaves min-content alone.
*/
.profile_switcher_choice_name[b-x50rq21dlx] {
    min-width: 0;
    overflow-wrap: break-word;
}
/* /Components/UI/Window/UpdateIndicator.razor.rz.scp.css */
/*
   The update indicator, pinned at the drawer's trailing edge.

   44px, matching a minimized entry and the profile switcher opposite it. The
   two corners are a pair and should read as one.
*/
.update_indicator_button[b-uvvyozlgu5] {
    /*
       THE RIM AND THE GLOW ARE app.css's --aura-* TOKENS. Never restate a
       value here - see "THE GOLD AURA" there, and the note on .launch_button
       about what three copies of one number do over time.
    */
    border: 1px solid var(--aura-border);
    box-shadow: var(--aura-rest);
    border-radius: 50%;
    background-color: transparent;
    width: 44px;
    height: 44px;
    padding: 0;
    margin: 2px 2px 2px 6px;
    /*
       RELATIVE IS SAFE HERE and is not the trap the drawer's other notes are
       about: the badge is positioned against this button, and the MENU is a
       sibling of it rather than a descendant - so this element never becomes
       the menu's containing block and cannot hand it to .window_drawer's
       overflow to clip.
    */
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    /* Pinned: the window row beside it is what gives way. */
    flex: 0 0 auto;
    color: rgba(255, 255, 255, 0.75);
    cursor: pointer;
    transition: all 0.2s ease;
}

    .update_indicator_button:hover[b-uvvyozlgu5] {
        border: 1px solid var(--aura-border);
        box-shadow: var(--aura-hover);
        color: white;
    }

    /* A plain :active - :hover cannot match a keyboard press. */
    .update_indicator_button:active[b-uvvyozlgu5] {
        border: 1px solid var(--aura-border-active);
        box-shadow: var(--aura-hover);
    }

    .update_indicator_button:focus-visible[b-uvvyozlgu5] {
        outline: var(--aura-focus-ring);
        outline-offset: var(--aura-focus-offset);
    }

/*
   The count, sitting on the button's upper trailing corner.

   min-width with a pill radius rather than a fixed circle, so "99+" widens
   instead of overflowing. It is allowed outside the button's box - the drawer
   clips, but 4px of overhang is well inside the padding the row already has.
*/
.update_indicator_count[b-uvvyozlgu5] {
    position: absolute;
    top: -2px;
    inset-inline-end: -2px;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    border-radius: 999px;
    background-color: var(--aura-border-active, rgba(255, 204, 102, 0.9));
    color: #201800;
    font-size: 11px;
    font-weight: 600;
    line-height: 18px;
    text-align: center;
}

/*
   A floor rather than a width, so short lists stay compact - and a max-height
   with its own scroll, so a long one does not run off the top of the screen.

   300 rather than 260 because a row carries TWO faces. At 260 the text column
   was left about 140px, which puts "On your profile Ada Lovelace" on three
   lines and makes every row taller than the pictures beside it.
*/
.update_indicator_menu[b-uvvyozlgu5] {
    min-width: 300px;
    max-width: min(92vw, 380px);
    max-height: min(70dvh, 560px);
    overflow-y: auto;
    overflow-x: hidden;
}

.update_indicator_row[b-uvvyozlgu5] {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 10px;
    color: rgba(255, 255, 255, 0.85);
}

/*
   A row that leads somewhere is a BUTTON, and this is what makes one look like
   the div beside it.

   THE ELEMENT IS THE AFFORDANCE, not a click handler on a div. A row about the
   account alone has nowhere to go and stays a div, so the two shapes sit in one
   list - which is why every property a button brings of its own has to be
   turned off here rather than left to look "close enough".

   width: 100% and text-align: left because a button shrink-wraps its content
   and centres it; the row has to fill the menu or the faces stop lining up
   down the list.

   font: inherit because a button does not inherit the menu's type. Without it
   the names render in the browser's default UI font at its default size, which
   is a difference nobody would think to look for.
*/
.update_indicator_row_pressable[b-uvvyozlgu5] {
    width: 100%;
    border: 0;
    background: none;
    font: inherit;
    text-align: left;
    cursor: pointer;
}

.update_indicator_row_pressable:hover[b-uvvyozlgu5],
.update_indicator_row_pressable:focus-visible[b-uvvyozlgu5] {
    background-color: rgba(255, 255, 255, 0.08);
}

.update_indicator_empty[b-uvvyozlgu5] {
    padding: 8px 10px;
    color: rgba(255, 255, 255, 0.65);
}

/*
   The pair: the reader's own profile, then the counterpart. Pinned, so the
   text column is what gives way as the menu narrows.
*/
.update_indicator_faces[b-uvvyozlgu5] {
    display: flex;
    align-items: center;
    gap: 4px;
    flex: 0 0 auto;
}

/*
   48, not the 64 a single face wore. The rendition IS a 64-square and
   downscales cleanly; what will not fit is two of them, which take 128px of a
   menu that may only be 300 wide.

   THE TWO ARE THE SAME SIZE, deliberately. Making the reader's own smaller
   would be inventing a convention only somebody already told about it could
   read, and the sentence beside them is what actually says which is which.
*/
.update_indicator_face[b-uvvyozlgu5] {
    width: 48px;
    height: 48px;
    object-fit: cover;
    border-radius: 50%;
    flex: 0 0 auto;
    display: block;
}

/*
   The placeholder wears the same box so a list mixing profiles with and
   without pictures does not come out ragged.
*/
.update_indicator_placeholder[b-uvvyozlgu5] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    border: 1px solid var(--aura-border);
    color: rgba(255, 255, 255, 0.55);
}

.update_indicator_text[b-uvvyozlgu5] {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

/*
   break-word, NEVER anywhere. `anywhere` counts toward min-content width, so a
   flex child carrying it collapses to one character per line rather than
   making its neighbours give way - which is exactly what the profile list did
   at 375px.
*/
.update_indicator_who[b-uvvyozlgu5] {
    font-weight: 600;
    overflow-wrap: break-word;
}

.update_indicator_what[b-uvvyozlgu5] {
    font-size: 12px;
    color: rgba(255, 255, 255, 0.65);
    overflow-wrap: break-word;
}

/*
   Which of the reader's own profiles the update landed on - context rather
   than news, so it is quieter than the line above it.
*/
.update_indicator_mine[b-uvvyozlgu5] {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.5);
    overflow-wrap: break-word;
}

/* The room an entry is about, as quiet as the line naming the reader's own profile. */
.update_indicator_room[b-uvvyozlgu5] {
    font-size: 11px;
    color: rgba(255, 255, 255, 0.5);
    overflow-wrap: break-word;
}
/* /Components/UI/Window/WindowFrame.razor.rz.scp.css */
.window_shadow[b-k73fy81xfz] {
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 0;
    width: 100%;
    border-radius: 8px;
    align-self: flex-start;
    padding: 5px;
    overflow: visible;
    /* Fills .window_lock - see the note on .window_lock's flex rule. */
    flex: 1 1 auto;
    min-height: 0;
}


.window[b-k73fy81xfz] {
    /* Single source of truth for the titlebar's height - used by
       .window_titlebar to size itself and by .window_dock_menu to sit just
       below it from outside the clipping container. */
    --window-titlebar-height: 36px;
    /*
       The titlebar's own metrics, declared once here and consumed in three
       places: by .window_button itself, by .window_title_icon, and by the
       reserve arithmetic that keeps the title clear of both of them.

       They are variables rather than literals BECAUSE of that third
       consumer. The reserve has to be at least as wide as the button strip
       really is, so a button that grew a pixel while the reserve did not
       would either slide a start-aligned title under the strip or push a
       centred one quietly off centre - with nothing on screen to say why.
       Written once, the two cannot disagree.
  */
    --window-titlebar-button-glyph: 20px;
    --window-titlebar-button-padding: 2px;
    --window-titlebar-button-border: 1px;
    --window-titlebar-button-gap: 12px;
    /* The inset between the last button and the window's rounded corner. */
    --window-titlebar-button-edge: 4px;
    /*
       THE AURA'S REACH, and the inset in front of the FIRST button that
       holds it - which is not the same job as the trailing edge above,
       though the two happen to want the same number.

       Every other side of every button already has room inside the strip's
       clip box: 4px of vertical margin above and below, and the trailing
       edge to the right of Close. The leading edge had none - the Dock
       button's left border sat exactly ON the strip's box - so that one
       edge was the only place in the titlebar where the glow got out only
       because `overflow-clip-margin` let it.

       IT IS NOT SAFE TO REST ANYTHING ON THAT PROPERTY. WebKit does not
       support it, so Safari and EVERY browser on iOS and iPadOS - Chrome
       included, since they are all WebKit underneath - clip at the border
       box exactly and slice the Dock button's glow off flat down its left
       side. Reported from an Apple device and reproduced by setting
       `overflow-clip-margin: 0` in Chromium, which cuts that one button's
       left edge and nothing else, exactly as described.

       --aura-reach is what the widest of the three states needs, which is
       the focus ring; the two glows fit inside it. It is an app.css token
       because this is not the only container that has to leave that room -
       `.window_content` needs the identical figure for the controls inside
       every form window, and it had 3px. The clip margins stay where they
       are as a second line of defence for the browsers that honour them;
       nothing depends on them any more.
  */
    --window-titlebar-button-lead: var(--aura-reach);
    /* A Boxicon is a 1em square, so a button is its glyph plus its own box. */
    --window-titlebar-button-size: calc(var(--window-titlebar-button-glyph) + 2 * (var(--window-titlebar-button-padding) + var(--window-titlebar-button-border)));
    --window-titlebar-icon-margin: 10px;
    --window-titlebar-icon-size: 20px;
    /* The breathing room the title keeps between itself and whichever of
       the two side groups it is closest to. */
    --window-titlebar-title-gap: 10px;
    position: relative;
    display: flex;
    flex-direction: column;
    width: 100%;
    min-width: 0;
    min-height: 0;
    max-height: 100%;
    border-radius: 8px;
    border: 1px solid rgba(0,0,0,.25);
    background-color: rgba(64,64,64,0.5);
    /* Fills .window_shadow - see the note on .window_lock's flex rule. */
    flex: 1 1 auto;
    min-height: 0;
    /*
       The drop shadow lives on .window itself rather than on a separate
       element painted behind it.

       An outer box-shadow is never drawn inside the element's own border
       box, so it physically cannot show through the window. That matters
       here because .window is only 50% opaque - the previous
       .window_shadow::before sat behind the glass at inset: 10px, so its
       outer shadow radiated from a box 10px inside the window's edges and
       read straight through the translucent background as a dark ring just
       inside the border.

       The white hairline is an INSET shadow, which paints above the
       background and below content - which is where it was always meant to
       read, and it now follows the window's actual top edge rather than a
       line 10px in.
  */
    box-shadow: 0 40px 120px rgba(0,0,0,0.55), 0 0 8px 4px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.12);
}


    /*
   A DOCKED window gets a much tighter shadow than a floating one, and this
   is the actual fix for "the splitter is right up against the window".

   The default `0 40px 120px` is a floating-window shadow: its core sits 40px
   below the frame and it reaches 160px. That reads beautifully for a window
   hovering over a backdrop, and badly for a panel that is flush against
   other panels - every dock boundary is only ~11px from the frame to the
   splitter line, so the shadow was still at nearly full strength when the
   line crossed it, and it washed across whatever panel sat beyond. It was
   the reason the top dock looked cramped, and the reason a left dock sitting
   above a bottom dock looked cramped in exactly the same way.

   Reserving enough room for the big shadow was tried first and rejected: it
   cost ~20% of a 200px panel's height to buy nothing but appearance. Fitting
   the shadow to the space instead costs nothing at all.

   `0 6px 16px` puts the core at about the 5px the frame is already inset by,
   so it resolves inside its own gap. The ambient ring and the inset
   highlight are unchanged, so a docked panel still reads as a distinct
   surface with a lit top edge - it just stops throwing a floating window's
   shadow across its neighbours.
*/
    .window.window_docked[b-k73fy81xfz] {
        box-shadow: 0 6px 16px rgba(0,0,0,0.5), 0 0 8px 4px rgba(0,0,0,0.5), inset 0 1px 0 rgba(255,255,255,0.12);
    }

    .window:not(.window_maximized)[b-k73fy81xfz] {
        max-height: 100%;
    }

        .window:not(.window_maximized) .window_content_padding[b-k73fy81xfz] {
            min-height: 0;
            overflow: hidden;
        }

        .window:not(.window_maximized) .window_content[b-k73fy81xfz] {
            overflow-y: auto;
        }


.window_lock[b-k73fy81xfz] {
    position: relative;
    display: flex;
    flex-direction: column;
    min-height: 0;
    width: 100%;
    align-self: flex-start;
    overflow: visible;
    /*
       Unlocked is `filter: none`, not `blur(0px)`. blur(0px) is not free -
       it still promotes this element to its own composited layer for every
       unlocked window, permanently, for no visual gain. Interpolating from
       `none` is well defined: the browser substitutes the identity value
       (blur(0)), so the transition still animates.
  */
    /*
       The whole frame fills .window_component_host UNCONDITIONALLY, in both
       normal and maximized states, using flex rather than height: 100%.
       Two reasons, both found by measuring mid-animation:

       1. While the host's height is mid-interpolation FROM `auto` (which is
          how maximize/restore animates), the host stays "indefinite" for
          percentage resolution - so `height: 100%` on a child falls back to
          content height for the whole animation and only snaps to the right
          size on the final frame. Flex reads the container's used height
          each layout pass instead, so it tracks frame by frame.

       2. Making the fill conditional on .window_maximized broke RESTORE:
          that class is removed instantly, so the frame collapsed to content
          height on frame 0 while the host was still shrinking around it.
          Filling unconditionally keeps both directions symmetrical.

       At rest in normal mode this is a no-op - an auto-height flex
       container has no free space to distribute, so the frame still sizes
       to its content.
  */
    flex: 1 1 auto;
    min-height: 0;
    /*
       Deliberately NO height transition here, and none on .window_shadow or
       .window either. Maximize/restore is animated on exactly ONE element,
       .window_component_host.

       Transitioning height on these nested elements too looks reasonable
       and is badly broken: each interpolates from its resolved `auto`
       toward `100%` of a parent that is ITSELF mid-transition, so the
       percentage collapses while the parent is in flight. Measured
       mid-animation, .window_lock went 85px -> 2px -> 0px -> 0px -> 734px
       while the host grew smoothly - on screen, the window implodes to its
       titlebar and then snaps open.

       Only ever animate height at a single level of a nested layout chain.
  */
    transition: filter 220ms ease, opacity 220ms ease;
}

/*
   ---------------------------------------------------------------------
   Locked windows: blurred and dimmed, as a cue that something is above.
   ---------------------------------------------------------------------

   `filter`, not `backdrop-filter` - this blurs the window's OWN content,
   which is what reads as depth ("something sits on top of me"). Blurring
   the backdrop instead would blur whatever is BEHIND this window, which
   says nothing about what is above it.

   Keyed off lock state rather than stacking position, deliberately. A
   minimized modal still locks its owner (see
   WindowManager.RefreshOwnershipStates), so when the user minimizes a
   Confirm dialog its owner stays locked - and therefore stays blurred,
   with nothing on screen above it to explain why it is unusable. The blur
   IS that explanation: "there is still a popup up here, go bring it back."

   The happy side effect is that nothing flickers. Minimizing the modal on
   top does not change the owner's lock state, so the owner does not change
   appearance at that moment. Blur appears when the modal opens and clears
   when it actually closes - both moments where a visible change is the
   correct signal rather than a distraction.

   This is ALSO how legibility is handled for the window on top. An overlay
   is translucent, so without help the text beneath it shows through and
   makes it hard to read. Blurring and fading the source is what fixes that
   - and it is strictly better than a backdrop-filter on the active overlay,
   which costs a permanent composited layer on the one window the user is
   actually reading and scrolling.

   All three numbers below are pure taste: blur radius and opacity here,
   scrim alpha in the rule beneath. Raise the blur first if text still
   reads through an overlay - blur destroys legibility far faster than
   dimming does.
*/
.window_locked[b-k73fy81xfz] {
    filter: blur(6px);
    opacity: 0.8;
}

/*
   The scrim darkens on top of the blur; between them they stop text
   beneath an overlay reading through it.

   It is always present and merely transparent when unlocked, rather than
   being created by the .window_locked rule. A pseudo-element that blinks
   into existence via `content` has no previous state to animate from, so it
   would pop; one that already exists can transition its colour.

   Note it lives INSIDE the .window_locked opacity group, so its effective
   alpha is this value multiplied by that opacity.
*/
.window_shadow[b-k73fy81xfz]::after {
    content: "";
    position: absolute;
    /* Matches .window_shadow's 5px padding, so the scrim covers .window exactly. */
    inset: 5px;
    border-radius: 8px;
    background-color: transparent;
    pointer-events: none;
    z-index: 1;
    transition: background-color 220ms ease;
}

.window_locked > .window_shadow[b-k73fy81xfz]::after {
    background-color: rgba(0,0,0,0.45);
}

/*
   The lock blur, fade and scrim deliberately still cross-fade under
   reduced motion - those are changes in appearance, not movement. The
   maximize/restore resize is suppressed in WindowComponentHost.razor.css,
   which is the only place size is animated.
*/

/*
   OFF, deliberately - kept as a documented decision rather than deleted,
   because the selector is the non-obvious part if it is ever reconsidered.

   NO FROSTED BACKDROP on the active overlay, for two reasons:

   1. It popped. The entry animation fades opacity 0 -> 1, and opacity < 1
      makes an element a backdrop root - so for the whole fade the overlay's
      backdrop-filter could only sample inside itself (i.e. nothing), then
      snapped into focus the instant opacity hit exactly 1.

   2. It became redundant. Locked windows are now blurred and scrimmed at
      the SOURCE (see .window_locked above), which solves the same
      text-bleed problem before the overlay ever composites over it -
      without a permanent composited layer on the one window being read
      and scrolled.

   The gap it leaves: an INDEPENDENT (non-modal) overlay does not lock its
   owner, so nothing beneath it is blurred. No such overlay exists today -
   every overlay in the app is Modal. When chat windows arrive, prefer
   extending the source-blur to "anything that is not the topmost
   interactive window" over switching this back on.
*/
.window_popup_item_active .window_lock:not(.window_locked) .window[b-k73fy81xfz] {
    /* backdrop-filter: blur(10px); */
}

.window_container[b-k73fy81xfz] {
    /*
       This is where the window's own content stops.

       The titlebar never shrinks (flex: 0 0 auto - see its note), which is
       right, but it means a window squeezed shorter than its own titlebar
       has a titlebar sticking out of the bottom of it, with the content
       chain trailing below that. Measured on a left dock dragged down to
       40px: the container sized correctly at 29px while the titlebar ran 7px
       past the frame and the content 16px past.

       Clipping here rather than on .window keeps .window's overflow visible,
       which the dock menu needs - it is positioned against .window precisely
       so it can leave this box.

       An element's own box-shadow is not affected by its own overflow, so
       clipping here would have been safe on .window too; the menu is the
       reason it is one level in.
  */
    overflow: hidden;
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    border-radius: 8px;
    border: 1px solid rgba(255,255,255,0.05);
}

/*
   .window_maximized no longer needs to change how the frame is sized -
   the frame fills its host unconditionally (see the flex rules on
   .window_lock / .window_shadow / .window). Only .window_component_host
   changes size, and everything inside follows it.
*/

.window_maximized.window[b-k73fy81xfz] {
    display: flex;
    flex-direction: column;
}

.window_maximized .window_container[b-k73fy81xfz] {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

/*
   A narrow window - a shrunk dock, mostly - has to give up something, and
   the order it gives things up in is the whole point of these three rules.

   1. The title truncates first, ALL THE WAY TO ZERO, before the buttons
      give up anything. That is now structural rather than a shrink weight:
      .window_title is absolutely positioned, so it is not a flex item at
      all and contributes nothing to the row's sizing. It can only ever be
      squeezed by its own reserve, which is derived from the very things it
      must not overlap.

   2. Then the buttons start to clip. The button strip is allowed to shrink
      (flex: 0 1 auto) and clips its own overflow.

   3. Nothing ever escapes the window. .window itself keeps overflow:
      visible on purpose - it has to, or it would clip its own drop shadow -
      so the clipping has to happen here, on the titlebar row.

   Before this, every one of those was min-width: auto all the way down, so
   a titlebar simply painted at its content width and the close button ended
   up outside the window's rounded box entirely.
*/
.window_titlebar[b-k73fy81xfz] {
    min-width: 0;
    /*
       The containing block for .window_title, which is stretched across this
       row rather than laid out in it.

       Safe to position, unlike .window_drawer: the only absolutely-positioned
       descendant this row has is the title, and this row is already clipping
       it either way. The dock menu is deliberately rendered OUTSIDE
       .window_container precisely so that neither this element nor that one
       can ever become its containing block - see the note beside it in the
       markup.
  */
    position: relative;
    /*
       `clip` with a margin rather than `hidden`, so the buttons' hover glow
       is not cut off at the titlebar's edge.

       The clipping itself has to stay - it is what rule 3 above is about.
       What was wrong is that it clipped at exactly the border box, and
       .window_button's hover shadow (blur 5px, spread 2px) reaches about 7px
       past the button. A button sits 4px inside this row, so the top and
       bottom of its glow were being sliced off.

       overflow-clip-margin moves the clip edge outwards by that much without
       letting anything else out: a button that genuinely overflows is still
       clipped, just 8px later, which is invisible against a glow that fades
       to nothing over the same distance.

       IT IS A SECOND LINE OF DEFENCE, NOT THE FIRST ONE, and it must not
       become load-bearing again. WebKit does not implement the property at
       all, so Safari and every browser on iOS and iPadOS clip at the border
       box regardless of what is written here. Every aura in this row has
       room INSIDE its clip box - 4px of button margin above and below, and
       the two paddings on the strip - which is what actually keeps the glow
       whole. See --window-titlebar-button-lead for the edge that did not,
       and what it looked like.

       `clip` rather than `hidden` because this element never wants to be a
       scroll container - `hidden` quietly is one, and can be scrolled
       programmatically, which would slide the titlebar's contents out of
       alignment with nothing on screen to say why. Both values are
       non-visible, so the flex automatic-minimum-size note below still
       applies exactly as it did.
  */
    overflow: clip;
    overflow-clip-margin: 8px;
    /*
       Fixed height rather than whatever the button metrics happen to add up
       to. Two things depend on knowing it: the dock menu positions itself
       just below the titlebar from outside the clipping container, and a
       fixed height is what lets flex-shrink stay at 0 below without the
       titlebar's size being a moving target.
  */
    height: var(--window-titlebar-height);
    /*
       flex-shrink: 0 is required BECAUSE of the overflow: hidden above, and
       the connection is easy to miss.

       A flex item's automatic minimum size is only `auto` while its overflow
       is visible; setting overflow to hidden silently changes it to zero. So
       the moment this row started clipping, it also became free to be
       squashed to nothing by the column flex around it - and a window whose
       content wants more room than it has, like Terms, promptly did exactly
       that, crushing a 40px titlebar to about 16px and cutting the buttons
       in half.

       The titlebar is fixed-height chrome. It gives up width (see the title
       and button rules) and never height.
  */
    flex: 0 0 auto;
}

/*
   justify-content: flex-end is load-bearing, not cosmetic. An overflowing
   flex container spills away from its justification, so aligning to the end
   makes the strip overflow to the LEFT - which means the leftmost button
   (Dock) is clipped first and Close, the one you always need, is clipped
   last. Aligning to the start would clip Close first and leave a window
   that cannot be closed.
*/
.window_titlebar_buttons[b-k73fy81xfz] {
    flex: 0 1 auto;
    min-width: 0;
    /*
       What pushes the strip to the right-hand end of the row.

       The title is out of flow, so it cannot push this strip right by eating
       the free space between them - and on a window with no icon this strip is
       the row's only item and would otherwise sit at the start. An auto margin
       absorbs the free space instead, and
       collapses to zero the moment there is none - which is exactly when the
       strip has to start shrinking and clipping.
  */
    margin-left: auto;
    /*
       Same clip-with-a-margin as .window_titlebar, and it has to be done in
       BOTH places: this strip clips before the titlebar does, so leaving
       this one at `hidden` would cut the glow off regardless of what its
       parent allows. See the note there for why 8px.

       It is a SECOND line of defence rather than the first one now. The
       glow used to escape this box only because of the clip margin, which
       WebKit ignores - see --window-titlebar-button-lead. The padding
       below is what gives it room INSIDE the box, on every engine.
  */
    overflow: clip;
    overflow-clip-margin: 8px;
    justify-content: flex-end;
    /*
       The space BETWEEN buttons, and the only thing that sets it.

       NOT from .window_button's own horizontal margin, which would make the
       spacing half of a value also doing two other jobs - the vertical inset
       inside a 36px titlebar, and the gap between the last button and the
       window's edge - so nudging any one of the three moves all three. The
       button carries vertical margin only; this sets the
       spacing, and the padding below sets the edge inset.

       Sized for a thumb rather than a cursor. The buttons are ~26px square,
       which is as large as a 36px titlebar allows, so they are already well
       under the 44px a touch target wants - spacing is the only room left to
       give, and 8px was leaving Maximize and Close close enough to hit the
       wrong one on a phone.
  */
    gap: var(--window-titlebar-button-gap);
    /*
       The room the Dock button's aura lives in, and the reason it is here
       rather than resting on the clip margin above is the whole of
       --window-titlebar-button-lead - read that first.

       Physical rather than logical, matching the margin-left and the
       padding-right it sits between. This whole rule is written in
       physical properties; mixing one logical property into it would leave
       the strip half-flipped in a right-to-left document, which is worse
       than being consistently unflipped. Making the strip logical is a
       change of its own and has nothing to do with the glow.
  */
    padding-left: var(--window-titlebar-button-lead);
    /* The inset .window_button's horizontal margin used to provide, so the
       Close button does not sit against the window's rounded corner. It
       doubles as the trailing side's aura room, which is why it is the
       same 4px the leading side needs. */
    padding-right: var(--window-titlebar-button-edge);
}

/*
   Only present when the window declared an icon, so this rule can never
   change the metrics of a window that did not.

   flex: 0 0 auto is the same lesson .window_titlebar_buttons learned: the
   titlebar clips, and a flex item inside an overflow:hidden container has an
   automatic minimum size of 0, so without this the icon would be squeezed to
   nothing by a long title rather than the title being ellipsised.
*/
.window_title_icon[b-k73fy81xfz] {
    flex: 0 0 auto;
    margin-left: var(--window-titlebar-icon-margin);
    font-size: var(--window-titlebar-icon-size);
    text-shadow: 1px 1px 2px black;
    opacity: 0.85;
}

/*
   THE RESERVE: the room the title is not allowed into, so that it ellipsises
   instead of running under the icon or the buttons.

   Each side is measured independently here and the two alignments then use
   them differently - see .window_title and .window_title_centered.

   The button sum counts the strip's leading inset, every button, a gap for
   every button rather than for the spaces between them, and the trailing
   inset - so it states the strip's real width and then one spare gap, which
   is the clearance the title keeps from the Dock button.

   THE LEADING INSET HAS TO BE IN HERE. It is real width the strip gained
   when the Dock button's aura was given room inside the clip box (see
   --window-titlebar-button-lead), and a reserve narrower than the strip is
   a title that slides under the leftmost button - which is precisely what
   this arithmetic exists to prevent. Leaning on the spare gap to absorb it
   instead would work today and quietly stop working the day the gap is
   tuned down, with nothing on screen to say why.

   Both sides are declared on .window_titlebar rather than on the title, so
   the :has() below - which is about what this ROW contains - has something
   of its own to set.
*/
.window_titlebar[b-k73fy81xfz] {
    --window-titlebar-icon-reserve: 0px;
    /*
       Where a START-aligned title begins, which is NOT the same as the icon
       reserve: with no icon that reserve is 0 and the title would sit hard
       against the window's rounded corner. Falling back to the icon's own
       margin puts the text exactly where an icon would have been, so a
       window's title starts in the same place whether or not it declared
       one - which matters because most windows in one workspace differ only
       by that.
  */
    --window-titlebar-title-start: var(--window-titlebar-icon-margin);
    --window-titlebar-buttons-reserve: calc(var(--window-titlebar-button-lead) + var(--window-titlebar-button-count, 0) * (var(--window-titlebar-button-size) + var(--window-titlebar-button-gap)) + var(--window-titlebar-button-edge));
}

/*
   An icon widens the leading side, so it widens both the reserve and the
   start. :has() rather than a flag on the state object, because the icon's
   presence is already expressed by whether the element is rendered and a
   second statement of it could only drift from the first.
*/
.window_titlebar:has(.window_title_icon)[b-k73fy81xfz] {
    --window-titlebar-icon-reserve: calc(var(--window-titlebar-icon-margin) + var(--window-titlebar-icon-size) + var(--window-titlebar-title-gap));
    --window-titlebar-title-start: var(--window-titlebar-icon-reserve);
}

/*
   OUT OF FLOW, ON PURPOSE, and it is the consequence of that rather than the
   positioning itself that matters:

   "The title truncates first" stops being a shrink weight and becomes a
   structural fact. Contributing nothing to the row's sizing is stronger than
   contributing zero shrink: the buttons cannot be squeezed by a long title
   at all, at any width, and the strip only ever starts clipping when the
   window itself is narrower than the strip. This was a flex item with
   .flex-grow-1, and had been wrong - measured on a 375px phone with
   "Terms & Conditions" open, the title held 196px while the Dock button was
   cut to 9px of its 26.

   THE DEFAULT IS START, and the asymmetric padding is the whole of it: the
   leading side clears the icon, the trailing side clears the buttons, and
   nothing is reserved that is not actually occupied. That is the alignment
   that survives a phone - see .window_title_centered for what centring costs
   and why it is opt-in.

   Logical properties throughout (padding-inline-*, flex-start), so a
   right-to-left document flips the whole row without either this rule or the
   framework's WindowTitleAlignment.Start knowing about it.

   pointer-events: none is REQUIRED, not defensive. This box is painted over
   the icon and the whole button strip, so without it the title would swallow
   every click aimed at Dock, Minimize, Maximize and Close - the buttons would
   simply stop working, with nothing to see. It has no handlers of its own and
   nothing here is selectable, so there is nothing to give up.
*/
.window_title[b-k73fy81xfz] {
    position: absolute;
    inset: 0;
    padding-inline-start: var(--window-titlebar-title-start);
    padding-inline-end: var(--window-titlebar-buttons-reserve);
    display: flex;
    align-items: center;
    justify-content: flex-start;
    min-width: 0;
    overflow: hidden;
    pointer-events: none;
    text-shadow: 1px 1px 2px black;
    font-size: 24px;
    font-weight: bold;
}

/*
   CENTRED ON THE WINDOW, not on the space left over between the icon and the
   buttons - which is what makes this more than a justify-content change.

   A title between two groups of unequal width is centred on the GAP, so it
   sits off to one side by half the difference, and the difference moves as
   an icon appears, as the dock control comes and goes, and from window to
   window. Measured on a 1280px window with an icon and four buttons, the
   text sat 57px left of the window's true centre. No amount of flex tuning
   fixes that: a flex item cannot know about a sibling on the other side of
   it.

   The fix is symmetry rather than measurement. This box is already stretched
   across the whole titlebar, so giving it the SAME padding on both sides
   puts its content box on the row's centre line whatever that padding is;
   the only job left for the padding is to be wide enough that the text
   cannot reach the icon or the buttons. So it is the WIDER of the two
   reserves, and an over-estimate is harmless - it costs the title a little
   width and cannot move it off centre.

   THAT IS ALSO WHAT IT COSTS, and why it is not the default. The wider side
   is very nearly always the buttons - four of them plus their gaps is about
   120px - so a centred title spends ~240px of a titlebar to be centred in.
   On a 360px phone that is two thirds of the row, and titles ellipsise with
   the space to render them sitting empty on the other side of the text. Set
   it on a window that is wide by nature and has a short title.
*/
.window_title_centered[b-k73fy81xfz] {
    padding-inline: max(var(--window-titlebar-icon-reserve), var(--window-titlebar-buttons-reserve));
    justify-content: center;
}

    .window_title > span[b-k73fy81xfz] {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

/*
   The dock menu is anchored to .window_container (see the position: relative
   there) rather than to the dock button, and sits outside the titlebar's
   clipping.

   It stays a descendant of the window rather than being portalled to a
   top-level layer on purpose: it therefore moves with the window through its
   open/minimize/close transforms, because it is part of what is being
   transformed. A fixed-position menu would detach and slide on its own -
   and, with a transformed ancestor, `fixed` stops meaning "relative to the
   viewport" anyway.
*/
.window_dock_menu[b-k73fy81xfz] {
    position: absolute;
    /* Both offsets are +1px for .window_container's border, which sits
       between .window's padding box (this element's containing block) and
       the titlebar the menu is aligning to. */
    top: calc(var(--window-titlebar-height) + 1px);
    right: 1px;
    z-index: 20;
    min-width: 10rem;
    padding: 4px;
    border-radius: 6px;
    background: var(--window-menu-background, #1d2028);
    border: 1px solid var(--window-menu-border, rgba(255, 255, 255, 0.12));
    box-shadow: 0 8px 24px rgba(0, 0, 0, 0.45);
}

.window_dock_option[b-k73fy81xfz] {
    display: flex;
    align-items: center;
    gap: 8px;
    width: 100%;
    padding: 6px 10px;
    border: 0;
    border-radius: 4px;
    background: transparent;
    color: inherit;
    text-align: left;
    white-space: nowrap;
}

    .window_dock_option:hover[b-k73fy81xfz] {
        background: var(--window-menu-hover, rgba(255, 255, 255, 0.08));
    }

.window_dock_option_current[b-k73fy81xfz] {
    background: var(--window-menu-current, rgba(255, 255, 255, 0.14));
}

.window_content_padding[b-k73fy81xfz] {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
    padding: 3px;
}

.window_content[b-k73fy81xfz] {
    flex: 1 1 auto;
    min-height: 0;
    border-radius: 5px;
    overflow-x: hidden;
    overflow-y: auto;
    margin: 0;
    /*
       AT LEAST THE AURA'S REACH, NOT A ROUND NUMBER. Was 3px, raised to 4px
       - overflow clips at the padding box, so this padding is
       the only room a control inside has for its focus ring, and 3px cut
       1px off it.

       It bites on the LEFT and stays invisible on the right, which is what
       makes it easy to miss: `overflow-y: auto` reserves a scrollbar gutter
       on the trailing side, so the right-hand edge had room by accident
       while the leading edge had none. Measured on Login and Register - the
       Submit button and both text fields came out with a flat vertical cut
       down their left side and a properly rounded corner on their right.

       The vertical axis is not affected the same way: it SCROLLS, so a
       control whose ring is clipped at the top or bottom edge can simply be
       scrolled into the middle. Only a clipped axis is a real defect, which
       here is `overflow-x`.
  */
    padding: var(--aura-reach);
}

/* Firefox ignores the -webkit- rules below; this gives it the same thin bar. Only there: in Chrome
   either standard property switches the -webkit- rules off. */
@supports not selector(::-webkit-scrollbar) {
    .window_content[b-k73fy81xfz] {
        scrollbar-width: thin;
        scrollbar-color: rgba(255,255,255,0.3) transparent;
    }
}

/*
   A SCROLL CONTAINER IS FOCUSABLE WHETHER OR NOT ANYBODY ASKED, and that is
   why this rule exists . Chrome makes a scrollable region
   keyboard-focusable on its own so the arrow keys can scroll it - which is
   a genuine accessibility feature and the only way to read a long window
   without a mouse - and it then drew the BROWSER'S default ring here,
   measured as `rgb(229,151,0) auto 0.8px`. Near-gold by coincidence, not by
   design, and different on every browser and platform.

   Same ring as everything else, and NO aura: the glow means "this responds
   to a press", and this is a region you scroll rather than a control you
   press. TermsAgreement's scroller already made exactly this call.

   THE OFFSET IS INSET, WHICH IS THE ONE PLACE IT IS. .window_content fills
   the window body and .window_container is overflow: hidden, so a ring
   drawn 4px outside this element would be clipped away entirely and the
   focus indicator would silently not exist. --aura-focus-inset is the
   negative twin of the usual offset, declared beside it in app.css.

   :focus-visible rather than :focus - unlike a text field there is no caret
   to find, so a mouse click that happens to land on the body should not
   ring the whole window.
*/
.window_content:focus-visible[b-k73fy81xfz] {
    outline: var(--aura-focus-ring);
    outline-offset: var(--aura-focus-inset);
}

.window_maximized .window_content_padding[b-k73fy81xfz] {
    flex: 1 1 auto;
    min-height: 0;
    overflow: hidden;
}

.window_maximized .window_content[b-k73fy81xfz] {
    flex: 1 1 auto;
    min-height: 0;
    overflow-y: auto;
    overflow-x: hidden;
}

.window_content[b-k73fy81xfz]::-webkit-scrollbar {
    width: 8px;
}

.window_content[b-k73fy81xfz]::-webkit-scrollbar-track {
    background: transparent;
}

.window_content[b-k73fy81xfz]::-webkit-scrollbar-thumb {
    background-color: rgba(255,255,255,0.3);
    border-radius: 10px;
    border: 1px solid rgba(255,255,255,0.5);
}

    .window_content[b-k73fy81xfz]::-webkit-scrollbar-thumb:hover {
        background-color: rgba(255,255,255,0.5);
    }

.top_gradient[b-k73fy81xfz] {
    content: "";
    position: absolute;
    top: 0px;
    left: 5%;
    right: 5%;
    width: 90%;
    height: 1px;
    background-image: linear-gradient(to right, rgba(255,255,255,0.0) 0%, rgba(255,255,255, 0.10) 20%, rgba(255,255,255, 0.30) 50%, rgba(255,255,255, 0.10) 80%, rgba(255,255,255, 0.0) 100%);
}

.bottom_gradient[b-k73fy81xfz] {
    content: "";
    position: absolute;
    bottom: -1px;
    left: 0%;
    right: 0%;
    width: 100%;
    height: 1px;
    background-image: linear-gradient(to right, rgba(255,255,255,0.0) 0%, rgba(255,255,255, 0.10) 20%, rgba(255,255,255, 0.30) 50%, rgba(255,255,255, 0.10) 80%, rgba(255,255,255, 0.0) 100%);
}

/*.bottom_star {
    position: absolute;
    left: 50%;
    transform: translateX(-50%);
    bottom: -32px;
    width: 64px;
    height: 64px;
    overflow: visible;
    background-image: url("star4.png");
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
}*/

.window_button[b-k73fy81xfz] {
    position: relative;
    display: flex;
    /* Never squash. A button that shrinks to fit becomes an unreadable
       sliver of an icon; one that keeps its size and gets clipped by the
       strip above is at least honestly gone. */
    flex: 0 0 auto;
    align-items: center;
    justify-content: center;
    /* --button-radius, shared with .window_drawer_entry and every .btn. */
    border-radius: var(--button-radius);
    /*
       These three come from .window's variables because the title's reserve
       is computed from the same three. A literal here would be a second,
       silent statement of the button's width, and the title would slide
       under the strip - or off centre - the first time the two disagreed.
  */
    /*
       THE RIM COLOUR AND THE GLOW COME FROM app.css's --aura-* TOKENS, so
       this button, the launcher, the drawer entries, every Bootstrap .btn
       and the Settings cards all wear one aura at one set of numbers. Never
       restate a value here: five copies of one number drift, and nothing
       reports it when they do.

       The WIDTH stays local, because the title's reserve is computed from
       it - see the note above.
  */
    border: var(--window-titlebar-button-border) solid var(--aura-border);
    box-shadow: var(--aura-rest);
    /* --button-bg in app.css, which every .btn reads too. */
    background-color: var(--button-bg);
    /*    backdrop-filter: blur(5px);*/
    transition: all 0.2s ease;
    /*
       Vertical only. The horizontal half moved to .window_titlebar_buttons
       as `gap` (spacing) and `padding-right` (edge inset) - see the note
       there for why one value doing three jobs was the problem.

       4px top and bottom is what centres a ~26px button in the 36px
       titlebar; it is not free space and should not be traded away.
  */
    margin: 4px 0;
    padding: var(--window-titlebar-button-padding);
    font-size: var(--window-titlebar-button-glyph);
}

/*
   The destructive tint, shared with .btn-danger. Same alpha as --button-bg,
   so Close reads as a titlebar button that happens to be red rather than as
   a different kind of control.
*/
.close_button[b-k73fy81xfz] {
    background-color: var(--button-bg-danger);
}


.window_button:hover[b-k73fy81xfz] {
    border: var(--window-titlebar-button-border) solid var(--aura-border);
    box-shadow: var(--aura-hover);
}

/*
   A PLAIN :active, NEVER :hover:active.

   :hover:active can only ever match a mouse - a keyboard Space or Enter
   activates the button with no hover - so a button pressed from the
   keyboard would get no acknowledgement at all. Every aura consumer uses
   the plain form.

   The specificity drops from (0,3,0) to (0,2,0), which ties with the
   :hover rule above; this one is later, so it still wins when both apply.
*/
.window_button:active[b-k73fy81xfz] {
    border: var(--window-titlebar-button-border) solid var(--aura-border-active);
    box-shadow: var(--aura-hover);
}

/*
   KEYBOARD FOCUS - before this there was no rule at all
   here and the button took the BROWSER'S default ring, which on this
   machine drew `rgb(229,151,0) auto 0.8px`. A near-gold hairline was close
   enough to look intentional and is not: it is whatever the user agent
   feels like, it differs between browsers and platforms, and it was the
   only focus indicator in the application that .btn, .settings_entry,
   CheckBox and TermsAgreement did not share.

   The bright glow AND a solid ring, exactly as .btn does. The glow alone
   cannot be a focus indicator, because it is indistinguishable from hover;
   the ring is the half that says "the keyboard is here".

   The rim stays BLACK - focus is not a press, and the gold rim is reserved
   for :active. This rule declares no border for that reason: sitting after
   :active and declaring one would take the press's own signal away.

   ROOM FOR IT IS EXACTLY THERE, AND IT IS THIS RING THAT SETS THE FIGURE.
   It extends 4px beyond the border box (2px offset + 2px width), which is
   the widest reach of the three aura states, and every side of the strip's
   clip box now allows exactly that: 4px of vertical margin in a 36px
   titlebar, and 4px of padding at each end. The clip margins on
   .window_titlebar_buttons and .window_titlebar are spare on top of it, and
   are not to be relied on - WebKit ignores them. See
   --window-titlebar-button-lead.
*/
.window_button:focus-visible[b-k73fy81xfz] {
    outline: var(--aura-focus-ring);
    outline-offset: var(--aura-focus-offset);
    box-shadow: var(--aura-hover);
}

.window_button[b-k73fy81xfz],
.window_button *[b-k73fy81xfz] {
    cursor: pointer;
}
/* /Components/UI/Window/WindowLauncher.razor.rz.scp.css */
.launch_button[b-7syw44fqbi] {
    position: relative;
    border-radius: 45px;
    /*
       THE RIM COLOUR AND THE GLOW ARE app.css's --aura-* TOKENS, which every
       button in the application reads - see "THE GOLD AURA" there.

       Never restate a value here. This button once carried its own numbers
       and had silently drifted from the other two chrome controls by the
       time anyone compared them, which is what three copies of one value do
       over time. One aura, one set of numbers, one edit.
  */
    border: 1px solid var(--aura-border);
    box-shadow: var(--aura-rest);
    /*
       TRANSPARENT, AND DELIBERATELY NOT --button-bg. This is the one aura
       consumer that does not take the shared button surface: it is a ring
       drawn AROUND the product logo rather than a pill with a label on it,
       so a translucent dark fill would sit over the artwork it exists to
       frame. The rim, the radius and the aura are shared; the fill is not.
  */
    background-color: transparent;
    /*backdrop-filter: blur(5px) saturate(50%);*/
    transition: all 0.2s ease;
    /*
       Vertical 2px, horizontal 12px - the horizontal half is the launcher's
       breathing room, not a nudge.

       This button is the "auto" middle column of .window_drawer's grid, with
       a minimized list packed hard against it on either side (see the auto
       margin in WindowDrawer.razor.css, which is what makes the left-hand row
       hug the launcher). At 2px the nearest entry sat almost against the
       button's glow, so a row of minimized windows read as continuing
       straight through the launcher rather than stopping at it.

       Margin rather than padding: the button's own padding would grow the
       lit border with it, and it is the ring that marks where the launcher
       ends. Because the column is sized to its content, this is simply
       column width and cannot push anything off the row - the two lists
       divide what is left equally, so they each give up half of it.
  */
    margin: 2px 12px;
    padding: 0px;
}

    .launch_button:hover[b-7syw44fqbi] {
        border: 1px solid var(--aura-border);
        box-shadow: var(--aura-hover);
    }

    /*
       A plain :active, never :hover:active - see the note on
       .window_button:active. :hover:active cannot match a keyboard press, so
       opening the launcher with Space or Enter would say nothing at all.
  */
    .launch_button:active[b-7syw44fqbi] {
        border: 1px solid var(--aura-border-active);
        box-shadow: var(--aura-hover);
    }

    /*
       Keyboard focus - see the note on
       .window_button:focus-visible. There was no rule here and this took
       the browser's default ring, which was the last thing in the chrome
       not matching the application's own controls.
  */
    .launch_button:focus-visible[b-7syw44fqbi] {
        outline: var(--aura-focus-ring);
        outline-offset: var(--aura-focus-offset);
        box-shadow: var(--aura-hover);
    }

    .launch_button[b-7syw44fqbi],
    .launch_button *[b-7syw44fqbi] {
        cursor: pointer;
    }

.launch_inner[b-7syw44fqbi] {
    display: inline-block;
    width: 64px;
    height: 64px;
    background-image: url('/logo64.png');
    background-size: contain;
    background-repeat: no-repeat;
    background-position: center;
    vertical-align: middle;
}

/*
   The menu gets a ceiling and a floor once it can hold a grid or a table.

   Content is one row per program and stays short; Small icons and Details are
   both far wider and taller for the same set, and the menu is anchored to a
   button at the bottom of the viewport - so without a max-height it grows off
   the top of the screen, exactly as an overlay window did before it was clamped
   on both axes. min-width stops the four picker buttons being wider than the
   menu they sit in when only one or two programs are launchable.

   overflow-y here rather than on a child: .menu is already overflow: hidden so
   the rounded corners clip, and a scroll container has to be the element that
   is actually too tall.
*/
.launcher_menu[b-7syw44fqbi] {
    max-height: min(70dvh, 560px);
    min-width: 232px;
    max-width: min(92vw, 560px);
    overflow-y: auto;
    overflow-x: hidden;
}

/*
   A wider floor for the two tile views.

   Nothing inside a wrapped flex row makes its container wider - the tiles just
   wrap harder - so at the 232px floor above, 84px tiles came out two to a row
   and the grid read as a narrow column. This is a floor, not a width: with few
   enough programs to fit, the menu is still sized by its content.

   SELECTED WITH :has(), NOT WITH A CONDITIONAL CLASS, and that is load-bearing.
   Bootstrap toggles `.show` on this element at run time; Blazor rewrites the
   whole class attribute whenever its own expression for it changes, taking
   `.show` with it. A conditional class here therefore made the menu disappear
   on the first view change that altered the string, with no hide.bs.dropdown
   firing - it read as a menu that had never opened. :has() moves the decision
   into CSS, where the markup never changes. app.css already leans on it for the
   drawer scrim.
*/
.launcher_menu:has(.launcher_tiles)[b-7syw44fqbi] {
    min-width: 320px;
}

/*
   The view picker, across the top of the menu.

   Sticky rather than scrolling away with the list: the whole point of it is to
   change a list that may be taller than the menu, and having to scroll back up
   to reach it would be worse than not having it. Its own background is opaque
   enough to hide the rows passing underneath - the menu's own is translucent,
   so a transparent bar here would show the list through it.
*/
.launcher_views[b-7syw44fqbi] {
    position: sticky;
    top: 0;

    /* Above the details table's own sticky heading, which stops beneath it. */
    z-index: 2;
    display: flex;
    justify-content: flex-end;
    gap: 2px;
    padding: 4px 6px;
    background-color: rgba(48,48,48,0.92);
    border-bottom: 1px solid rgba(255,255,255,0.10);
}

.launcher_view_button[b-7syw44fqbi] {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 28px;
    height: 28px;
    padding: 0px;
    border: 1px solid transparent;
    border-radius: 6px;
    background-color: transparent;
    color: rgba(255,255,255,0.65);
    font-size: 16px;
    cursor: pointer;
    transition: all 0.15s ease;
}

    .launcher_view_button:hover[b-7syw44fqbi] {
        border-color: rgba(255,204,102,0.5);
        background-color: rgba(255,255,255,0.08);
        color: white;
    }

    /*
       KEYBOARD FOCUS, alongside .launcher_tile's - see the
       longer note there for why a ring is not the aura and why these two
       had none at all.

       THE OFFSET IS INSET HERE, WHICH THE TILES DO NOT NEED. These sit 2px
       apart, and an outset ring reaches 4px, so it would be drawn 2px over
       the top of the button beside it - and this row is four buttons in
       about 130px, so that neighbour is always there. Inset draws the ring
       just inside the button's own border box, where the 2px gap cannot be
       crossed. --aura-focus-inset is the token for exactly this case and
       .window_content already uses it.

       It reads correctly against .launcher_view_active below, which paints
       the BORDER gold: focused-and-active shows the gold border with the
       ring just inside it, which is two facts about one button rather than
       one fact said twice. Clipping is not the reason for the inset - there
       is 4px above and 6px at the row's end, which an outset ring would
       just fit.
  */
    .launcher_view_button:focus-visible[b-7syw44fqbi] {
        outline: var(--aura-focus-ring);
        outline-offset: var(--aura-focus-inset);
    }

    /*
       The selected view. Amber, the same accent the launcher ring and the focus
       rings already use, so "this is the one you are looking at" reads as part
       of the same interface.
  */
    .launcher_view_active[b-7syw44fqbi] {
        border-color: rgba(255,204,102,0.85);
        background-color: rgba(255,204,102,0.16);
        color: white;
    }

/*
   Small and Large icons: one wrapped flex row per category.

   THE ICON SIZE IS NOT SET HERE. bx-sm and bx-md come from Boxicons' own
   transformations.min.css, which App.razor loads beside the glyph font, and
   they are declared !important - so a font-size on the same element would lose
   anyway. Only the tile WIDTH is ours, because that is what decides how many
   fit on a row.

   The trap this walked into first: the glyph file
   (fonts/basic/boxicons.min.css) is names only and contains not a single
   font-size rule, so checking it alone reads as "the size classes do not
   exist". Check transformations.min.css too - it also carries the rotate and
   flip helpers, bx-fw, bx-border and the rest of the bx-xs..bx-5xl scale.
*/
.launcher_tiles[b-7syw44fqbi] {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
    padding: 6px;
}

/*
   The tile width, which is the only thing separating Small icons from Large.

   On the TILE rather than inherited from the row through a custom property.
   Equivalent either way; this is one less indirection, and it puts the
   declaration on the element whose box it describes.

   Safe to make this class conditional because nothing else writes to a tile's
   class list - unlike the menu <ul>, which Bootstrap toggles `.show` on and
   where a conditional class made the menu vanish.

   THE CENTRING BUG WAS NOT HERE - see the transition note on .launcher_tile
   below. Moving the class was tried first as a fix and changed nothing, because
   the width was being ANIMATED and the menu simply had not finished growing
   when Popper measured it.
*/

/* bx-sm is 1.55rem, so 25px at this app's 16px root. */
.launcher_tile_small[b-7syw44fqbi] {
    width: 44px;
}

/* bx-md is 2.25rem, so 36px. */
.launcher_tile_large[b-7syw44fqbi] {
    width: 84px;
}

.launcher_tile[b-7syw44fqbi] {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    padding: 6px 2px;
    border: 1px solid transparent;
    border-radius: 8px;
    background-color: transparent;
    color: inherit;
    cursor: pointer;
    /*
       NAMED PROPERTIES, NEVER `all`, AND THAT IS THE WHOLE OF THE CENTRING BUG
      .

       `transition: all` included WIDTH, and width is what separates Small icons
       from Large icons - so switching view ANIMATED every tile from 44px to 84px
       over 150ms, and the menu only reached its final size at the end of that.
       Popper is told to re-measure from OnAfterRenderAsync, which is the moment
       the DOM is patched and therefore the moment the animation STARTS: it read
       the old width, positioned for it, and was never asked again. The menu
       ended up off-centre by roughly the width the tiles had yet to gain, worst
       between the two tile views because that is the only pair whose widths
       differ. Content -> Large looked fine because those tiles are built fresh
       and start at their final size.

       Only the hover feedback should animate. A property that encodes a MODE -
       which view you are in - has no business easing, and `all` is what quietly
       swept it in.
  */
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

    .launcher_tile:hover[b-7syw44fqbi] {
        border-color: rgba(255,204,102,0.5);
        background-color: rgba(255,255,255,0.10);
    }

    /*
       KEYBOARD FOCUS. Without a rule here this and .launcher_view_button
       take the BROWSER'S default ring, which is whatever the user agent
       feels like, differs by browser and platform, and is the one focus
       indicator in the application that nothing else shares.

       NO AURA, AND THAT IS DELIBERATE - see
       _doc/README_Client_Windows.md for why these two families are excluded from
       the glow: a grid of glowing tiles is exactly the haze the aura's
       numbers were tuned away from. "Not wearing the aura" has never meant
       "no focus ring".
       A RING IS NOT THE GLOW. `Components/UI/CheckBox` is the precedent and
       settles it - it is excluded from the aura for its own reasons and
       draws this same ring, because the ring is what says "the keyboard is
       here" and nothing else in the interface says it.

       There is room: a tile has 6px to .launcher_menu's clip box, against
       the ring's 4px reach. The 4px gap BETWEEN tiles is tighter than the
       ring, so it lands on the neighbouring tile's border box - which is
       harmless, because only one element is ever focused, so no two rings
       can meet.
  */
    .launcher_tile:focus-visible[b-7syw44fqbi] {
        outline: var(--aura-focus-ring);
        outline-offset: var(--aura-focus-offset);
    }

    /*
       line-height only. The font-size belongs to bx-sm / bx-md, which carry
       !important and would win regardless; stating one here would be a rule
       that looks like it sets the size and does nothing.
  */
    .launcher_tile i[b-7syw44fqbi] {
        line-height: 1;
    }

/*
   The title under a large tile. Two lines at most, then clipped - a tile grid
   whose rows are different heights because one program has a long name stops
   reading as a grid.
*/
.launcher_tile_title[b-7syw44fqbi] {
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
    /*
       Always two lines tall, even for a one-word name. Clamping alone is not
       enough: it caps the tall ones but leaves the short ones short, and the
       grid then has rows of two different heights depending on which programs
       happened to land in them. Measured before this: 63px for a row of Login
       and Register against 76px for a row of Cookie Policy and Privacy Policy.

       1.2 line-height x 2 lines, stated as a min so a title that somehow
       renders taller is not clipped by this as well as by the clamp.
  */
    min-height: 2.4em;
    font-size: 11px;
    line-height: 1.2;
    text-align: center;
    overflow-wrap: anywhere;
}

/*
   Details.

   A plain table rather than the DataGrid component, which is a full-window
   control: it renders a toolbar and paging arrows in FontAwesome - a font this
   application does not load at all, so those six buttons draw nothing - and it
   sizes itself h-100 inside a dropdown that has no height to give it.
*/
.launcher_details[b-7syw44fqbi] {
    width: 100%;
    border-collapse: collapse;
    font-size: 13px;
}

    /*
       A STICKY HEADER NEEDS AN OPAQUE BACKGROUND AND A STACKING CONTEXT, and
       this one had neither: rows scrolled visibly THROUGH the heading, because
       `.menu` is translucent and a 10% white tint over it hides nothing.

       The tint is kept as an IMAGE over an opaque colour rather than being
       replaced, so the band looks as it did and the rows behind it are gone.
       `.launcher_views` says the same thing about itself a few rules up - it
       sits above this one and carries the higher z-index for that reason.
    */
    .launcher_details thead th[b-7syw44fqbi] {
        position: sticky;
        top: 36px;
        z-index: 1;
        padding: 4px 8px;
        background-color: rgba(48,48,48,0.98);
        background-image: linear-gradient(rgba(255,255,255,0.10), rgba(255,255,255,0.10));
        font-weight: 600;
        text-align: left;
        white-space: nowrap;
    }

    .launcher_details td[b-7syw44fqbi] {
        padding: 4px 8px;
        border-top: 1px solid rgba(255,255,255,0.06);
        vertical-align: middle;
    }

    .launcher_details tbody tr[b-7syw44fqbi] {
        cursor: pointer;
        transition: background-color 0.15s ease;
    }

        .launcher_details tbody tr:hover[b-7syw44fqbi] {
            background-color: rgba(255,255,255,0.10);
        }

/*
   A category heading inside the Details table: a row spanning every column,
   so the columns keep one width down the whole list, drawn as the other views
   draw `.seperator_header`. The sticky header above is `thead th` alone - a
   plain `th` would make every heading stick at the top as well.
*/
    .launcher_details tbody tr.launcher_details_heading[b-7syw44fqbi] {
        cursor: default;
    }

        .launcher_details tbody tr.launcher_details_heading:hover[b-7syw44fqbi] {
            background-color: transparent;
        }

    .launcher_details_heading th[b-7syw44fqbi] {
        padding: 3px 8px;
        background-color: rgba(255,255,255,0.10);
        font-weight: 600;
        text-align: left;
        white-space: nowrap;
    }

/*
   The Description column, given real room rather than being left to collapse.

   It measured 83px, which was the width of the word "Description" in the
   header and nothing else - because NO PROGRAM HAS A DESCRIPTION SEEDED.
   `program` carries an optional second `string` pointer beside its
   NOT NULL header, and it is null for all sixty-eight, so every cell in this
   column is empty and the column shrink-wrapped the heading. Reserving the
   width is what makes the column look like somewhere text will go, and stops
   the table reflowing the day the first description is written.

   A FLOOR, NOT A WIDTH. The table is `width: 100%` of the menu and the menu is
   sized by its content between its own min-width and max-width, so this pushes
   the menu wider until it hits `max-width: min(92vw, 560px)` and no further.

   RELAXED ON A NARROW SCREEN, and that is the half that is easy to leave out.
   The menu caps at 92vw, and `.launcher_menu` is `overflow-x: hidden` so a
   table wider than the menu is CLIPPED rather than scrollable - the last
   column would simply be cut off with nothing to reach it with. Below the same
   767px breakpoint the workspace grid uses, the floor goes away and the column
   collapses back to its heading, which is the right trade when there is no
   width to give it and no text in it yet.
*/
.launcher_details_description[b-7syw44fqbi] {
    min-width: 190px;
}

/*
   The Name column.

   Given a floor because "Data Grid Sample" was wrapping onto a second line at
   128px, which makes that row 48px tall against 28px for its neighbours - a
   ragged list, and the program name is the one thing in this table somebody is
   actually scanning for.

   NOT `white-space: nowrap`, deliberately. A floor lets a long name still wrap
   rather than forcing the table wider than the menu can show, and the menu is
   `overflow-x: hidden` so anything past its edge is cut off with no way to
   reach it.
*/
.launcher_details_name[b-7syw44fqbi] {
    min-width: 170px;
}

/*
   The Last Accessed column.

   `white-space: nowrap` so a timestamp is never broken across lines - it was
   wrapping its AM/PM onto a second line - plus a floor wide enough for the
   longest date this renders (a two-digit month, day and hour, e.g.
   "12/31/2026 12:00 PM") so the column does not resize as the clock passes
   noon or the month rolls over.

   THIS RULE IS EASY TO KILL SILENTLY, and the failure is worth knowing.
   A scripted edit inserting the block above it once used a Perl replacement of
   `$add . $old` WITHOUT /e, so the replacement string interpolated a literal
   " . " and the selector became `. .launcher_details_when` - a parse error, so
   the browser dropped the whole rule. Nothing errored, the stylesheet still
   loaded, and the only symptom was this column quietly starting to wrap. Check
   the SEAM after a scripted insert, not just the inserted text.
*/
.launcher_details_when[b-7syw44fqbi] {
    min-width: 140px;
    white-space: nowrap;
    color: rgba(255,255,255,0.70);
}

/*
   EVERY column floor goes away on a narrow screen, and leaving one behind
   would undo the others.

   The menu caps at 92vw and `.launcher_menu` is `overflow-x: hidden`, so a
   table wider than the menu is CLIPPED rather than scrollable - the last
   column would simply be cut off with nothing to reach it with. The three
   floors add up to 500px, which does not fit a 375px phone, so below the same
   767px breakpoint the workspace grid uses they are all released and the
   columns go back to being sized by their content.

   `.launcher_details_when` keeps its `nowrap` here on purpose: a timestamp
   broken across two lines is unreadable at any width, and at ~110px it still
   leaves room for the other two.

   THIS BLOCK MUST STAY BELOW ALL THREE FLOORS. A media query adds NO
   specificity - it only gates when its rules apply - so `min-width: 0` here
   and `min-width: 170px` up there are the same weight and SOURCE ORDER
   decides. It sat above two of them for a while and lost to both: the query
   matched, the description relaxed because its floor was declared earlier, and
   the other two stayed at their desktop widths and clipped the table off the
   side of a phone. Add a fourth column and its floor goes ABOVE this block.
*/
@media (max-width: 767px) {
    .launcher_details_name[b-7syw44fqbi],
    .launcher_details_description[b-7syw44fqbi],
    .launcher_details_when[b-7syw44fqbi] {
        min-width: 0;
    }
}

/*
   One row of the launcher menu: the program's icon beside its name.

   Moved here from app.css when the drawer's minimized entries became
   icon-only and stopped using it, which left this component as the only
   consumer. Note that the menu's own frame - `.menu` and
   `.window_drawer_menu` - deliberately stays global, because the minimized
   groups wear those two as well.
*/
.menu_item[b-7syw44fqbi] {
    display: flex;
    align-items: center;
    gap: 6px;
}

/*
   `.seperator_header` is in app.css, because three components draw one now.
   A scoped rule would make this component the owner of the other two's
   appearance - which is exactly what went wrong while it lived here.
*/

/*
   A sub menu: one package at one context, opened in place beneath its own
   row. The chevron is pushed to the row's far end so it reads as the row's
   state rather than as part of the name, and an entry inside is indented by
   the width of an icon and its gap so its icon sits under the name above it.
   The Details view draws the same row as a table row spanning every column.
*/
.launcher_sub_menu_chevron[b-7syw44fqbi] {
    margin-left: auto;
    padding-left: 12px;
}

button.launcher_sub_menu_entry[b-7syw44fqbi] {
    padding-left: 38px;
}

    .launcher_details .launcher_sub_menu_entry td.launcher_details_name[b-7syw44fqbi] {
        padding-left: 30px;
    }
/* /Components/WindowFramework/Drawer/MinimizedWindowGroupList.razor.rz.scp.css */
/*
   ---------------------------------------------------------------------
   A drawer entry: one minimized window, or one collapsed group of them.

   ICON ONLY, with the window's name on `title`/`aria-label` and nowhere on
   screen. A labelled entry was as wide as its window's name - "Terms &
   Conditions" measured 113px, and two lines tall once it wrapped - against
   a column that is about 150px on a phone. Four windows wanted 444px of a
   149px row, so the drawer was full at two and unusable at four.

   A square entry makes the cost per window fixed and known, which is what
   lets the row scroll sensibly (see WindowDrawer.razor.css) instead of
   simply being overfull.

   The size is a touch target first: 44px is the smallest square a thumb
   hits reliably, and it fits the drawer without changing its height, which
   the 64px launcher sets.

   `title` is the browser's native tooltip, which appears on hover and so
   reaches a mouse but not a finger. A finger holds the entry instead, and
   WindowDrawer.razor.js shows the same name above it; the two rules below
   keep the browser's own long-press menu and text selection out of the way.
   ---------------------------------------------------------------------
*/
.window_drawer_entry[b-ialpz2dghn] {
    position: relative;
    /* Never shrink. A row that squashes its entries to fit is a row that
       silently stops being scrollable, which is the failure this replaced:
       the buttons compressed and then overflowed past the START edge, where
       overflow-x cannot reach them. */
    flex: 0 0 auto;
    display: flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    /* Matches .window_button and .launch_button - the same dark translucent
       pill with a gold glow, so the drawer reads as part of the same chrome
       rather than as browser default buttons, which is what these were.

       "Matches" is enforced rather than hoped for: the rim colour and the
       glow are app.css's --aura-* tokens, which every button in the
       application reads. Never restate one here - three copies of a value
       drift, and nothing reports it when they do. */
    border: 1px solid var(--aura-border);
    /* Both are app.css tokens, shared with .window_button and with every
       .btn in the application. */
    border-radius: var(--button-radius);
    background-color: var(--button-bg);
    box-shadow: var(--aura-rest);
    color: inherit;
    font-size: 24px;
    line-height: 1;
    transition: all 0.2s ease;
    cursor: pointer;
    -webkit-touch-callout: none;
    user-select: none;
}

.window_drawer_entry:hover[b-ialpz2dghn] {
    box-shadow: var(--aura-hover);
}

/*
   A plain :active, never :hover:active - see the note on
   .window_button:active for why. :hover:active cannot match a keyboard
   press, so an entry activated by Space or Enter would say nothing.
*/
.window_drawer_entry:active[b-ialpz2dghn] {
    border: 1px solid var(--aura-border-active);
    box-shadow: var(--aura-hover);
}

/*
   Keyboard focus - see the note on
   .window_button:focus-visible. There was no rule here and this took the
   browser's default ring.

   It matters more here than anywhere else in the chrome: these entries are
   ICON ONLY, so a keyboard user has no label to read and the ring is the
   only thing telling them which window they are about to restore.
*/
.window_drawer_entry:focus-visible[b-ialpz2dghn] {
    outline: var(--aura-focus-ring);
    outline-offset: var(--aura-focus-offset);
    box-shadow: var(--aura-hover);
}

/*
   The member count, so a collapsed group still says how much is behind it.
   Without it a group of eight conversations looks exactly like a group of
   two, and the drawer's whole job is telling the user what is open.

   A corner badge rather than a chip beside the name, because there is no
   name any more. Positioned against the entry (position: relative there)
   and allowed to sit slightly outside it, so it never crowds the icon.
*/
.window_group_count[b-ialpz2dghn] {
    position: absolute;
    top: -4px;
    right: -4px;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 18px;
    height: 18px;
    padding: 0 4px;
    border-radius: 999px;
    /* Opaque, not the translucent chip it was: it now overlaps the entry's
       own edge and the icon behind it, and a see-through badge over a glyph
       is unreadable. */
    background: rgba(255, 204, 102, 0.95);
    color: #201a0c;
    font-size: 11px;
    font-weight: bold;
    line-height: 1;
}

/*
   ---------------------------------------------------------------------
   The group menu.

   Positioning is left entirely to Bootstrap/Popper, exactly as
   WindowLauncher's menu is - which is why nothing here knows or cares how
   tall the drawer is. Popper measures the toggle and flips the menu above
   it when there is no room below, and there never is: the drawer is the
   last row of the page.

   The one rule that matters is a NEGATIVE one, and it lives in the markup
   rather than here: there must be no positioned wrapper around the toggle
   and menu. Bootstrap's own .dropdown class sets position: relative, and
   that is enough to hand the menu to .window_workspacelist (overflow-x:
   auto) and .window_drawer (overflow: hidden) to clip, because an
   absolutely-positioned element is only clipped by overflow ancestors in
   its containing-block chain. Unwrapped, the menu's containing block is
   the fixed <body>, which is outside both.
   ---------------------------------------------------------------------
*/
.window_group_menu[b-ialpz2dghn] {
    /* Never taller than the space above the drawer; past that the list
       scrolls rather than the menu running off the top of the screen.
       Popper writes the max-height itself when it has to, but only after a
       flip - this keeps a long list sane from the first frame. */
    max-height: min(60vh, 520px);
    overflow-y: auto;
    min-width: 260px;
    max-width: min(420px, calc(100vw - 24px));
    padding: 6px;
    /*
       Deeper than the ambient .menu shadow: this one is asking for a
       decision, so it should read as sitting well above the drawer.

       ON TOP of that shadow rather than instead of it, which is what
       --menu-shadow is for. box-shadow is one property, so naming it here
       used to discard all three of .menu's layers - and while .menu's were
       broken that went unnoticed. Now that they paint, replacing them would
       leave the menu that most wants lift with less of it than the launcher
       beside it. Earlier layers paint over later ones, so this close dark
       shadow sits in front of the ambient one and the two darken together.
  */
    box-shadow: rgba(0, 0, 0, 0.7) 0 8px 24px 4px, var(--menu-shadow);
}

/*
   Sized for a finger rather than a cursor. The picture alone is a 64px
   target and the row is taller still, so the whole row - not just the
   text - is what gets pressed.
*/
.window_group_item[b-ialpz2dghn] {
    display: flex;
    align-items: center;
    gap: 12px;
    width: 100%;
    padding: 6px 10px;
    border-radius: 6px;
}

.window_group_title[b-ialpz2dghn] {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    font-size: 1.1rem;
}

/*
   Full 64x64. Pictures are supplied at whatever size the application likes,
   so the size is pinned here rather than trusted - but pinned to the size
   the source images actually are, so nothing is being scaled up.

   object-fit keeps a non-square image from stretching into a distorted
   face; a plain width/height would squash it.
*/
.window_group_picture[b-ialpz2dghn] {
    flex: 0 0 auto;
    width: 64px;
    height: 64px;
    border-radius: 8px;
    object-fit: cover;
    /* A transparent or slow-loading image would otherwise collapse the row
       as it swaps in. */
    background: rgba(255, 255, 255, 0.08);
}
/* /Components/WindowFramework/Drawer/WindowDrawer.razor.rz.scp.css */
/* Grid (not flex) is what keeps the launcher fixed dead-center: the two
   side columns are both "1fr", so they always get equal, content-
   independent widths and the "auto" middle column never shifts no matter
   how many buttons pile up on either side. A flex row with
   justify-content:center would center the row's total width instead,
   which is exactly what let the launcher drift as the workspace list grew. */
/*
   Dims and blurs everything behind an open group menu, so picking a
   conversation reads as a decision rather than as a tooltip.

   Entirely CSS-driven: Bootstrap puts .show on the menu it opened, and
   :has() picks that up from here. Nothing has to be told when a menu opens
   or closes, and no state is duplicated between Bootstrap and Blazor.

   pointer-events stays none throughout, which is the important part. The
   scrim must not intercept the click that dismisses the menu - Bootstrap's
   own click-outside handling is what closes it, and it should also reach
   whatever was clicked, rather than being eaten by a backdrop the way a
   modal's would be.

   Nothing renders it inert when no menu is open beyond opacity, so it costs
   a composited layer and no hit-testing.
*/
/*
   1500 sits above .window_popup_layer (1000), so an open group menu blurs
   overlay windows too rather than leaving a modal sitting sharply on top of
   the scrim. The menu itself is lifted past this in
   MinimizedWindowGroupList.razor.css, since Bootstrap's own .dropdown-menu
   z-index is 1000 and would otherwise end up underneath.
*/
.window_drawer_scrim[b-dyv98koi4h] {
    position: fixed;
    inset: 0;
    z-index: 1500;
    pointer-events: none;
    opacity: 0;
    background: rgba(0, 0, 0, 0.35);
    transition: opacity 160ms ease;
}

/*
   Any drawer menu raises it - the launcher's as well as a group's. They are
   the same gesture from the user's side (a menu is up, everything else is
   waiting), so they should look the same.
*/
body:has(.window_drawer_menu.show) .window_drawer_scrim[b-dyv98koi4h] {
    opacity: 1;
    backdrop-filter: blur(6px) saturate(80%);
}

@media (prefers-reduced-motion: reduce) {
    .window_drawer_scrim[b-dyv98koi4h] {
        transition: none;
    }
}

/*
   NOTE: this element must stay position: static. It has overflow: hidden,
   and positioning it would make it the containing block for WindowLauncher's
   dropdown - which is a direct child - handing that menu to this overflow to
   clip. Unpositioned, the menu's containing block is the fixed <body>,
   outside this element entirely, and the menu is free to open upwards over
   the page. The same rule is what makes the group menus work; see
   MinimizedWindowGroupList.razor's header note.

   That does mean the drawer blurs along with everything else behind an open
   menu, which is the intent - "blur everything while they select".
*/
.window_drawer[b-dyv98koi4h] {
    display: grid;
    grid-template-columns: 1fr auto 1fr;
    align-items: center;
    width: 100%;
    /* flex-shrink:0 here - the drawer sits as an item in the *outer* page's
       flex column alongside the window content area; without this, a tall
       window (e.g. Terms) growing that sibling squeezes the drawer down to
       almost nothing, pushing the launcher off the bottom of the screen. */
    flex: 0 0 auto;
    overflow: hidden;
    padding: 4px;
}

/*
   The leading cell: pinned chrome, then the workspace row beside it.

   MUST STAY position: static, for the reason .window_drawer above must - it
   would otherwise become the containing block for a dropdown opened by the
   pinned fragment and hand that menu to the drawer's overflow: hidden.

   The cell is the grid's first 1fr, so whatever is pinned here is paid for by
   the workspace row alone and the launcher does NOT move. That asymmetry is
   deliberate: making both rows pay, by mirroring the width on the right, buys
   dead-centring that the grid already delivers and costs the right-hand row an
   entry it has no reason to give up.
*/
.window_drawer_leading[b-dyv98koi4h],
.window_drawer_trailing[b-dyv98koi4h] {
    display: flex;
    flex-direction: row;
    align-items: center;
    min-width: 0;
}

/*
   Both minimized lists. They are one column each side of the launcher, and
   the grid above gives each of them exactly half of what is left - about
   139px on a phone, less whatever the leading cell has pinned - so
   overflowing is the normal case rather than the edge case, and scrolling has
   to actually work. An entry is 44px with a 6px gap, so that is two of them.
*/
.window_workspacelist[b-dyv98koi4h],
.window_windowlist[b-dyv98koi4h] {
    display: flex;
    flex-direction: row;
    /* Centred against the 64px launcher. These were flex-end on one list
       and flex-start on the other, which reads as a pair of opposites but
       is the CROSS axis in a row - it bottom-aligned one row of buttons and
       top-aligned the other. The horizontal packing those comments were
       about is justify-content, below. */
    align-items: center;
    gap: 6px;
    overflow-x: auto;
    overflow-y: hidden;
    /* Don't let a swipe that runs off the end of the row start scrolling
       the page behind it. */
    overscroll-behavior-x: contain;
    min-width: 0;
    padding: 4px;
    /* Thin rather than hidden: a row that scrolls with nothing to say so is
       a row whose extra entries do not exist as far as the user knows. On
       touch these are overlay scrollbars and cost no height; on a mouse the
       ~11px they reserve still fits under the launcher. */
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 204, 102, 0.5) transparent;
}

    .window_workspacelist[b-dyv98koi4h]::-webkit-scrollbar,
    .window_windowlist[b-dyv98koi4h]::-webkit-scrollbar {
        height: 6px;
    }

    .window_workspacelist[b-dyv98koi4h]::-webkit-scrollbar-thumb,
    .window_windowlist[b-dyv98koi4h]::-webkit-scrollbar-thumb {
        border-radius: 999px;
        background: rgba(255, 204, 102, 0.5);
    }

/*
   Packing the left-hand row against the launcher WITHOUT breaking its
   scrolling, which is the whole reason this is an auto margin on the first
   entry rather than justify-content: flex-end.

   An overflowing flex container spills away from its justification, so
   flex-end made this row overflow past its START edge - and a start-edge
   overflow is unreachable, because scrollLeft cannot go below zero. That
   was not a theoretical limit: with four windows open the row's content was
   444px inside a 149px box, the first entry sat at x = -295, and
   scrollWidth equalled clientWidth, so the browser reported nothing to
   scroll while three of the four entries were off the side of the screen.

   An auto margin on the first item does the same job and collapses to zero
   the moment the content no longer fits, at which point the row starts at
   its start edge and overflows to the END - which scrolls.

   ::deep because the entries are rendered by MinimizedWindowGroupList; this
   component owns the row's layout but not the elements in it.
*/
.window_workspacelist[b-dyv98koi4h]  > :first-child {
    margin-inline-start: auto;
}

/*
   The right-hand row needs no such trick: flex-start already overflows to
   the end edge, which is the scrollable direction.
*/
.window_windowlist[b-dyv98koi4h] {
    justify-content: flex-start;
}

/*
   The workspace row is a FLEX ITEM now rather than a grid cell, so it has to
   be told to take the rest of the leading cell. Without flex-grow it sizes to
   its content and sits against the pinned chrome, which leaves its entries
   packed at the START edge - the one direction that cannot be scrolled back
   to, and the exact failure the auto-margin above exists to avoid.
*/
.window_drawer_leading .window_workspacelist[b-dyv98koi4h],
.window_drawer_trailing .window_windowlist[b-dyv98koi4h] {
    flex: 1 1 auto;
}
/* /Components/WindowFramework/Host/WindowHost.razor.rz.scp.css */
/*
   The main window layer is a 3x3 grid:

       ┌───────────────────────────────┐
       │           TopDock             │   row 1, spanning all columns
       ├──────┬─────────────────┬──────┤
       │ Left │      Main       │ Right│   row 2
       ├──────┴─────────────────┴──────┤
       │          BottomDock           │   row 3, spanning all columns
       └───────────────────────────────┘

   Track sizes come from the four --dock-* custom properties, written
   inline by WindowHost.razor from each docked window's DockSize. All four
   are always emitted, including zeroes, because a track can only be
   transitioned if it is present in both the old and new declarations -
   dropping one would make a dock appear and disappear instantly while the
   others animate.

   The grid areas themselves are claimed by WindowComponentHost, from its
   own Placement - see the region rules in WindowComponentHost.razor.css.
   That split is forced by CSS isolation (this file's selectors only match
   elements WindowHost itself renders) but it also lands in the right
   place: "how big are the regions" is this component's business, "which
   region am I in" is the window's.
*/
.window_workspace[b-i4u0m7ueeg] {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: visible;
    display: grid;
    grid-template-columns: minmax(0, var(--dock-left, 0px)) minmax(12px, 1fr) minmax(0, var(--dock-right, 0px));
    grid-template-rows: minmax(0, var(--dock-top, 0px)) minmax(12px, 1fr) minmax(0, var(--dock-bottom, 0px));
    transition: grid-template-columns 260ms cubic-bezier(0.22, 1, 0.36, 1), grid-template-rows 260ms cubic-bezier(0.22, 1, 0.36, 1);
}

/*
   Every track is a minmax(), and both halves are doing a job.

   The MAIN track is minmax(12px, 1fr) rather than a bare 1fr, because 1fr
   is really minmax(auto, 1fr) and that auto minimum refuses to shrink below
   the content's intrinsic size - a long unbroken line in the main window
   would push the grid wider than the viewport and take the docks off screen
   with it. Any definite minimum fixes that; 12px is chosen to match
   MIN_MAIN_SIZE in WindowSplitter.razor.js, which sizes it to two splitter
   grab areas rather than to content. When someone deliberately squeezes the
   docks together, all the main area still owes them is a way to take hold
   of the splitters again.

   The DOCK tracks are minmax(0, <size>) rather than a fixed <size>, which
   makes the whole layout self-limiting. A fixed track is never reduced to
   fit its container, so two docks that between them asked for more than the
   workspace simply overflowed it - the main track hit zero and everything
   past it slid off screen. With a zero base and the requested size only as a
   growth limit, the grid distributes what space actually exists: below
   capacity nothing changes and each dock gets exactly what it asked for;
   over capacity they share equally and the main area keeps its 120px.

   The drag clamps in WindowSplitter.razor.js keep it from getting there
   interactively. This is the guarantee underneath that, for the cases JS
   never sees - a viewport that shrinks after the fact, a restored dock size
   from a wider screen, a font-size change.
*/

/*
   While a splitter is being dragged the track sizes are written straight
   to the element by JS at pointer speed. Transitioning them then would
   make the panel lag a finger it is supposed to be following, so the
   transition is suspended for the duration of the drag and restored on
   release, where it smooths the single authoritative update coming back
   from the server.
*/
.window_workspace_resizing[b-i4u0m7ueeg] {
    transition: none;
    user-select: none;
    cursor: inherit;
}

@media (prefers-reduced-motion: reduce) {
    .window_workspace[b-i4u0m7ueeg] {
        transition: none;
    }
}

/*
   Mobile-first fallback: below the tablet breakpoint there is no room to
   put two panels side by side, so the side docks stop being side docks and
   stack as full-width rows instead - member list above, conversation
   below. The columns collapse to a single track and the left/right dock
   sizes are reinterpreted as row heights.

   Their splitters turn horizontal at the same breakpoint (see
   WindowSplitter.razor.css) rather than being withdrawn: with all four docks
   now competing on one axis, giving height back to the main area is the only
   way to keep it on screen, and that needs a handle on every one of them.

   This block and WindowSplitter.razor.js are the two things that have to
   agree about the shape of the stacked grid, and they agree by DERIVATION
   rather than by both being told: the drag maths reads the used track lists
   off this grid and recognises the layout from one column and five rows, so
   the breakpoint itself is written down only here.
*/
@media (max-width: 767px) {
    .window_workspace[b-i4u0m7ueeg] {
        grid-template-columns: minmax(0, 1fr);
        /* Same minmax() reasoning as the desktop template above - more so
           here, since four dock tracks share one axis instead of two. */
        grid-template-rows:
            minmax(0, var(--dock-top, 0px))
            minmax(0, var(--dock-left, 0px))
            minmax(12px, 1fr)
            minmax(0, var(--dock-right, 0px))
            minmax(0, var(--dock-bottom, 0px));
        transition: grid-template-rows 260ms cubic-bezier(0.22, 1, 0.36, 1);
    }
}

/*
   One wrapper per region, and the wrapper - not the window - is what claims
   a grid cell.

   THE WINDOWS MUST NOT BE GRID ITEMS THEMSELVES, each placing itself into its
   own cell. That works right up to the moment two of them want the same cell:
   grid items in one cell OVERLAP, so two normal windows in the main area render
   on top of each other. A wrapper turns the cell into a formatting context the
   windows can FLOW in, which is what lets them tile.

   position: relative makes each region the containing block for the windows
   inside it. That is what the exit animation pins to (see the leaving rules
   in WindowComponentHost.razor.css) - previously it relied on an
   absolutely-positioned grid item being contained by its grid AREA, which
   only worked while the window was a grid item.

   min-width/min-height: 0 for the usual reason - the automatic minimum size
   of a flex item refuses to shrink below its content, and without this a
   long line inside a window would push its region wider than its track.
*/
.window_region[b-i4u0m7ueeg] {
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 0;
    min-height: 0;
}

.window_region_top[b-i4u0m7ueeg] {
    grid-column: 1 / -1;
    grid-row: 1;
}

.window_region_bottom[b-i4u0m7ueeg] {
    grid-column: 1 / -1;
    grid-row: 3;
}

.window_region_left[b-i4u0m7ueeg] {
    grid-column: 1;
    grid-row: 2;
}

.window_region_right[b-i4u0m7ueeg] {
    grid-column: 3;
    grid-row: 2;
}

.window_region_main[b-i4u0m7ueeg] {
    grid-column: 2;
    grid-row: 2;
}

/*
   Stacked layout below the tablet breakpoint - one column, five rows, in
   visual order. Mirrors the template swap above; both have to change
   together.
*/
@media (max-width: 767px) {
    .window_region_top[b-i4u0m7ueeg] {
        grid-column: 1;
        grid-row: 1;
    }

    .window_region_left[b-i4u0m7ueeg] {
        grid-column: 1;
        grid-row: 2;
    }

    .window_region_main[b-i4u0m7ueeg] {
        grid-column: 1;
        grid-row: 3;
    }

    .window_region_right[b-i4u0m7ueeg] {
        grid-column: 1;
        grid-row: 4;
    }

    .window_region_bottom[b-i4u0m7ueeg] {
        grid-column: 1;
        grid-row: 5;
    }
}

.window_popup_layer[b-i4u0m7ueeg] {
    position: absolute;
    inset: 0;
    z-index: 1000;
    pointer-events: none;
}

/* z-index is set inline per item from WindowInstance.ZIndex - see WindowHost.razor. */
.window_popup_item[b-i4u0m7ueeg] {
    position: absolute;
    inset: 0;
    display: flex;
    justify-content: center;
    align-items: center;
    pointer-events: auto;
}

    .window_popup_item:has(.window_component_host_hidden)[b-i4u0m7ueeg],
    .window_popup_item:has(.window_component_host_minimized)[b-i4u0m7ueeg] {
        pointer-events: none;
    }
/* /Components/WindowFramework/Host/WindowSplitter.razor.rz.scp.css */
/*
   A splitter is a grid item placed in the track NEXT TO the dock it guards,
   then pushed against the shared edge. Living in the grid rather than being
   absolutely positioned means it follows the track automatically - no second
   copy of the layout maths to keep in sync with WindowHost.razor.css.

   The vertical pair (left/right) straddle their boundary with a -6px
   margin, so the line sits on it with 6px of grab area either side.

   The horizontal pair are tuned differently, and deliberately: both sit
   ENTIRELY BELOW their boundary, putting the line about 6px down. Top takes
   margin-top: 0 (flush with the row start), bottom takes margin-bottom:
   -12px (its whole band past the row end). Two things fall out of that, and
   both are why it is done this way:

     The frame's drop shadow throws downward (`0 6px 16px` when docked), so
     the window that needs clearance at a horizontal boundary is always the
     one ABOVE it. Pushing the line down gives that window room and costs
     the window below almost nothing, since its top edge only ever meets the
     ambient ring.

     Nothing overlaps. A vertical splitter runs the full height of the main
     row and stops exactly at its end edge; because the bottom splitter now
     starts there rather than 6px earlier, the two abut instead of fighting
     over a 12x12 square at the corner. That is what makes the vertical pair
     need no vertical inset at all.
*/
.window_splitter[b-1syyv8sftp] {
    z-index: 5;
    background: transparent;
    touch-action: none;
    /* Matches .window_lock's lock transition exactly, so a splitter blurs in
       step with the windows either side of it rather than a beat apart. */
    transition: filter 220ms ease, opacity 220ms ease;
}

/*
   Splitters blur with the layer they belong to.

   A locked window blurs itself at the source (.window_locked), but splitters
   are siblings of the windows rather than children, so nothing was reaching
   them - a modal came up, the whole main layer went soft, and the splitter
   lines stayed razor sharp on top of it, which read as though they were part
   of the modal.

   pointer-events is dropped at the same time, and that part is correctness
   rather than polish: a modal blocks the layer beneath it, so resizing a
   dock behind one must be impossible, not merely discouraged. Without it the
   splitter still sat above the blurred windows and stayed perfectly
   draggable.

   Unlocked is `filter: none` rather than `blur(0)`, for the same reason
   .window_lock is - blur(0) is not free, it promotes every splitter to its
   own composited layer permanently. Interpolating from `none` still
   animates, because the browser substitutes the identity value.
*/
.window_workspace_locked .window_splitter[b-1syyv8sftp] {
    filter: blur(6px);
    opacity: 0.8;
    pointer-events: none;
}

/*
   The visible line is drawn by ::after and is thinner than the element
   itself. The element stays finger-sized (Fitts's law applies harder on a
   phone than a mouse); the line stays hairline-thin so it reads as a
   boundary rather than as a gutter.
*/
.window_splitter[b-1syyv8sftp]::after {
    content: "";
    display: block;
    background: var(--window-splitter-color, rgba(255, 255, 255, 0.14));
    transition: background 120ms ease;
}

/*
   Lit while hovered, and while THIS splitter is being dragged.

   The drag half must NOT read `.window_workspace_resizing .window_splitter`:
   that class lives on the WORKSPACE, so grabbing one splitter would light every
   splitter on screen - four lines announcing a drag only one of them is doing.

   The hover half alone is not enough to replace it, which is why the drag
   needs a state of its own at all: a drag holds pointer capture, so once the
   pointer outruns the handle nothing is hovered any more and the line the
   user is actually dragging would go dark mid-drag. WindowSplitter.razor.js
   puts .window_splitter_active on the handle itself for exactly the span of
   the drag.
*/
.window_splitter:hover[b-1syyv8sftp]::after,
.window_splitter_active[b-1syyv8sftp]::after,
.window_splitter:focus-visible[b-1syyv8sftp]::after {
    background: var(--window-splitter-color-active, rgba(255, 255, 255, 0.4));
}

/*
   The keyboard's ring, inset: a splitter straddles a boundary between two
   windows, so an outset ring would paint over both and be clipped by the
   workspace at the edges. Lit as well, since the ring alone around a 12px
   band reads as a box rather than as a line that will move.
*/
.window_splitter:focus-visible[b-1syyv8sftp] {
    outline: var(--aura-focus-ring);
    outline-offset: var(--aura-focus-inset);
}

/*
   No vertical inset is needed - margin-block stays 0, and that is load
   bearing rather than merely default.

   align-self: stretch runs these the full height of the main row, ending
   exactly on its end edge. The horizontal splitters are positioned to start
   there rather than straddle it (see the header note), so the two abut and
   never contest the same pixels. An earlier revision inset these by 6px to
   dodge a horizontal splitter that DID straddle; moving the horizontal one
   instead solved it at the source and this inset became unnecessary.

   Where the two still cross, the horizontal splitter takes the higher
   z-index below, so the junction reads as a clean T and the pointer lands on
   one of them rather than on whichever came last in the DOM.
*/
.window_splitter_left[b-1syyv8sftp],
.window_splitter_right[b-1syyv8sftp] {
    grid-column: 2;
    grid-row: 2;
    width: 12px;
    cursor: col-resize;
    align-self: stretch;
    margin-block: 0px;
}

    .window_splitter_left[b-1syyv8sftp]::after,
    .window_splitter_right[b-1syyv8sftp]::after {
        width: 1px;
        height: 100%;
        margin-inline: auto;
    }

.window_splitter_left[b-1syyv8sftp] {
    justify-self: start;
    margin-left: -6px;
}

.window_splitter_right[b-1syyv8sftp] {
    justify-self: end;
    margin-right: -6px;
}

.window_splitter_top[b-1syyv8sftp],
.window_splitter_bottom[b-1syyv8sftp] {
    grid-column: 1 / -1;
    grid-row: 2;
    height: 12px;
    cursor: row-resize;
    justify-self: stretch;
    /* One above .window_splitter's 5, so a horizontal splitter wins any
       crossing with a vertical one - both the paint order and the hit test.
       They span the full width, so they are the ones that read as
       continuous. */
    z-index: 6;
}

    .window_splitter_top[b-1syyv8sftp]::after,
    .window_splitter_bottom[b-1syyv8sftp]::after {
        height: 1px;
        width: 100%;
        margin-block: auto;
    }

.window_splitter_top[b-1syyv8sftp] {
    align-self: start;
    margin-top: 0px;
}

.window_splitter_bottom[b-1syyv8sftp] {
    align-self: end;
    margin-bottom: -12px;
}

/*
   Below the stacking breakpoint the side docks become full-width rows (see
   WindowHost.razor.css), so their splitters stop being vertical lines and
   become horizontal ones - the same shape, and the same maths, as the
   top/bottom pair, just guarding a different pair of rows.

   DO NOT WITHDRAW THEM HERE on the grounds that a phone has no width to trade
   between two panels - that is the wrong axis. Stacked, these rows compete for
   HEIGHT with everything else, and with no handle four docks at their default
   thickness squeeze the main area down to its 12px minimum with no way to give
   any of it back. All four docks need
   a splitter precisely because they now share one axis.

   The row a splitter sits in has to be remapped, because the row COUNT
   changes. Desktop is three rows:

       1 top dock | 2 main | 3 bottom dock

   and stacked is five:

       1 top dock | 2 left dock | 3 main | 4 right dock | 5 bottom dock

   Each splitter belongs in the row ADJACENT to the dock it guards, on the
   side the boundary actually falls: start-aligned in the row after a leading
   dock, end-aligned in the row before a trailing one. So what is fixed is the
   relationship, not the number. The top splitter is start-aligned in the row
   BELOW the top dock - row 2 in both layouts, which is why it needs no
   override here and kept working by luck. The bottom splitter is end-aligned
   in the row ABOVE the bottom dock, which moves from row 2 to row 4; left at
   row 2 it guarded the boundary above the MAIN area instead, appearing in the
   middle of the screen with nothing to resize. Left and right both land in
   row 3, the main area, start- and end-aligned respectively.

   The drag axis follows on its own: WindowSplitter.razor.js reads the grid's
   USED track lists, and a one-column five-row workspace tells it everything
   it needs. The breakpoint stays written down exactly once - here.
*/
@media (max-width: 767px) {
    .window_splitter_left[b-1syyv8sftp],
    .window_splitter_right[b-1syyv8sftp] {
        grid-column: 1 / -1;
        grid-row: 3;
        width: auto;
        height: 12px;
        cursor: row-resize;
        justify-self: stretch;
        /* Undoes the -6px straddle of the vertical layout; stacked, these
           sit entirely below their boundary like the horizontal pair. */
        margin-inline: 0;
    }

        .window_splitter_left[b-1syyv8sftp]::after,
        .window_splitter_right[b-1syyv8sftp]::after {
            width: 100%;
            height: 1px;
            margin-inline: 0;
            margin-block: auto;
        }

    .window_splitter_left[b-1syyv8sftp] {
        align-self: start;
        margin-top: 0px;
    }

    .window_splitter_right[b-1syyv8sftp] {
        align-self: end;
        margin-bottom: -12px;
    }

    .window_splitter_bottom[b-1syyv8sftp] {
        grid-row: 4;
    }
}
/* /Components/WindowFramework/Rendering/WindowComponentHost.razor.rz.scp.css */
/*
   Open / minimize / restore animation.

   Windows stay in the DOM for their whole lifetime and only toggle
   `display`, which historically could not be transitioned at all. Two
   modern additions make it work:

     `display ... allow-discrete` defers the flip to `display: none` until
     the end of the transition, so a window animates OUT before it stops
     being laid out.

     `@starting-style` supplies the "from" state on the way back IN. Going
     display:none -> display:flex, `display` flips at the START and the
     element has no previous style to interpolate from, so without this it
     would simply appear.

   Both degrade cleanly: a browser that supports neither just shows and
   hides instantly, which is exactly the old behaviour.

   Deliberately NO `will-change` here. will-change of transform, opacity or
   filter promotes the element to its own composited layer permanently,
   which is exactly the cost this file works to avoid - see the note on
   .window_component_host_visible about why the resting transform is `none`.
*/
.window_component_host[b-mtxjgbouud] {
    display: flex;
    flex-direction: column;
    width: 100%;
    min-height: 0;
    min-width: 0;
    overflow: visible;
    /* Shrink toward the drawer at the bottom of the screen. */
    transform-origin: bottom center;
    /*
       How far a leaving window travels downward. A variable rather than a
       literal because it has to differ for windows whose HEIGHT is animating
       at the same time - see the override below the away state.

       14% is a percentage of the element's OWN height, which is what makes
       the distinction necessary.

       The floor is what stops a SHORT window fading in place. Percentage
       travel is proportional to height, and so is the scale about
       bottom-center, so the whole gesture shrinks with the window: measured
       on the top edge, a 952px side dock falls 364px and reads as a drop,
       while a 200px bottom dock falls 58px and reads as hovering while it
       fades. Same declaration, two different animations, purely because one
       panel is short.

       max() raises the short cases to a distance that reads as deliberate
       while leaving every window already taller than ~457px exactly as it
       was - so the side docks and maximized windows keep the fall that
       already looked right, and nothing regresses to fix the bottom dock.

       This pair is the DEFAULT - "fall toward the drawer at the bottom of
       the screen" - and it is right for a main-area window and an overlay.
       A DOCKED panel overrides it to retract into its own edge instead; see
       the four region rules below the away state.
    */
    --host-exit-x: 0px;
    --host-exit-travel: max(14%, 64px);
    /*
       Maximize/restore animates height between `auto` (content-sized) and
       100%. Interpolating to or from an intrinsic keyword like `auto` is
       normally impossible - `interpolate-size: allow-keywords` is what
       makes it legal. It inherits, so setting it here also covers
       .window_lock / .window_shadow / .window inside WindowFrame, which
       resize in lockstep with this element.

       Unlike opacity and transform, animating height is NOT a
       compositor-only effect: it forces layout on every frame. This is by
       far the most expensive animation in the window system, and the first
       one to drop if maximize feels sluggish on a real device.

       Where interpolate-size is unsupported this degrades to the instant
       snap you had before, so it is safe to ship as-is.
    */
    interpolate-size: allow-keywords;
    /*
       `width` is in here for maximizing OVERLAYS, which are content-width
       rather than 100% and so grow on both axes. Root windows are always
       width: 100%, so the width leg never fires for them.
    */
    /*
       flex-grow is in the list for windows SHARING a dock: they split it by
       grow rather than by content, so giving that share back smoothly is the
       only way a neighbour can take it over without snapping. It is
       deliberately never used for main-area sizing - see the maximized rule
       further down for why grow must stay out of that.
    */
    transition: opacity 200ms ease, transform 260ms cubic-bezier(0.22, 1, 0.36, 1), width 260ms cubic-bezier(0.22, 1, 0.36, 1), height 260ms cubic-bezier(0.22, 1, 0.36, 1), flex-grow 260ms cubic-bezier(0.22, 1, 0.36, 1), display 260ms allow-discrete;
}

.window_component_host_maximized[b-mtxjgbouud] {
    /*
       This flex is for the OVERLAY layer, where the host is a flex item of
       .window_popup_item. Main-layer hosts are flex items of their region
       wrapper and override it further down - grow there would fill the
       region in one frame and swallow the maximize animation.
    */
    flex: 1 1 auto;
    height: 100%;
}

/*
   The viewport clamp is deliberately NOT keyed on _visible.

   It must not be, or the exit animation breaks badly. `allow-discrete` keeps a
   minimizing window laid out for the whole transition, but the class has
   already flipped to _minimized by then - so a _visible-only clamp is dropped
   on the first frame of the animation and the window balloons to its full
   intrinsic content height while it is fading and
   folding. Measured on the Cookie window: 734px -> 2581px, an 1847px jump
   mid-flight, which reads on screen as the titlebar scrambling before the
   window vanishes.

   Clamping in every visibility state keeps the geometry stable for the
   entire animation.
*/
.window_component_host:not(.window_component_host_overlay)[b-mtxjgbouud] {
    max-height: 100%;
}

/*
   Overlay popup windows size to their content, but never past the
   viewport ON EITHER AXIS: they grow until they are effectively as large as
   a maximized window and then their content scrolls or wraps instead.
   Without the clamp a long overlay (a chat thread, a terms body) runs off
   the edges of the screen with no way to reach the rest.

   BOTH clamps are load-bearing, and the width one is the easier of the two
   to leave out, because nothing looks wrong until a window has genuinely
   wide content in it. `width: auto` on a flex item resolves to its
   MAX-CONTENT width - which for a paragraph is that whole paragraph set on
   one line. The Terms & Conditions dialog is what found this: its body is
   several hundred lines of prose, so the window sized itself to the longest
   sentence and, being centred by .window_popup_item, overflowed off BOTH
   sides at once, taking the titlebar buttons and the Agree/Disagree row
   with it. There was no way to reach them and no scrollbar to get there,
   because the overflow was on the layer rather than inside the window.

   max-width: 100% caps the flex item at the popup layer - which is exactly
   the box a maximized overlay fills - and the paragraphs then wrap inside
   it like any other block. So a dialog is never wider than a maximized
   window, whatever it contains.

   min-height / min-width: 0 are what actually let the inner .window_content
   scroll and wrap - a flex item's automatic minimum size is its content, so
   without them the element refuses to shrink below it and pushes the
   overflow straight back out past the clamps.
*/
.window_component_host_overlay[b-mtxjgbouud] {
    width: auto;
    height: auto;
    flex: 0 0 auto;
    max-height: 100%;
    min-height: 0;
    max-width: 100%;
    min-width: 0;
}

/*
   A maximized OVERLAY fills the popup layer, the same way a maximized root
   fills the workspace.

   This has to be a COMPOUND selector, not just .window_component_host_maximized.
   That rule and .window_component_host_overlay carry identical specificity
   (one class plus the scope attribute each) and _overlay is declared later,
   so _overlay silently won and reset flex/height straight back to content
   sizing. The framework was doing its part the whole time - SizeMode flipped
   to Maximized and the titlebar swapped Maximize for Normal - but the window
   never changed size, so the button looked dead.

   Note it keeps `flex: 0 0 auto` from the rule above rather than switching
   to `flex: 1 1 auto`. With flex-grow the widening is done by flex
   distribution, which is not interpolable - width snapped to full on the
   first frame while height eased over 260ms, so the overlay lurched wide
   and then unfolded. Leaving grow off makes the explicit width/height the
   things that change, and both axes then animate together (measured
   237->343->370->375 wide against 109->587->710->734 tall).
*/
.window_component_host_overlay.window_component_host_maximized[b-mtxjgbouud] {
    width: 100%;
    height: 100%;
    min-height: 0;
}

/*
   The "away" state: the window drops toward the drawer and folds away from
   the viewer. perspective() must come first in the list for the rotate to
   have any depth.

   The sign of rotateX matters and is easy to get backwards. CSS's +Y axis
   points DOWN, so rotateX(positive) swings the TOP edge away from the
   viewer and rotateX(negative) brings it toward them. Folding down into a
   drawer at the bottom of the screen is the former - like a lid closing
   away from you.

   translateY does the heavy lifting rather than the rotation. A small tilt
   on a tall window is a genuinely ambiguous depth cue: the eye can read it
   either as the top coming forward or the bottom receding, and it can flip
   between viewings of the very same animation. Leading with clear downward
   travel removes the ambiguity and leaves the fold as seasoning.

   All three states below list the SAME transform functions in the SAME
   order - that is what lets the browser interpolate componentwise instead
   of falling back to a matrix blend, which is what makes a fold look like
   a fold rather than a smear.
*/
.window_component_host_hidden[b-mtxjgbouud],
.window_component_host_minimized[b-mtxjgbouud] {
    display: none;
    opacity: 0;
    transform: perspective(1000px) translate(var(--host-exit-x), var(--host-exit-travel)) scale(0.9) rotateX(12deg);
}

/*
   A DOCKED panel retracts into its OWN edge, rather than falling toward the
   drawer like everything else.

   The default gesture is "fall toward the drawer at the bottom of the
   screen", which is right for a main-area window: the drawer is where it is
   going, and there is nothing between it and the bottom of the screen. For a
   docked panel it is wrong twice over, and the bottom dock shows both.

   It goes the WRONG WAY for three of the four edges. Minimizing a top dock
   sends it down into the content rather than up out of the way, and a side
   dock travels perpendicular to the direction its own space is closing.

   And on the bottom it does not travel FAR ENOUGH to leave. A bottom panel
   sits directly above the drawer, so 64px of fall lands it on top of the
   launcher button and it fades out there, over the chrome, instead of
   leaving the screen. With the main region simultaneously growing 242 -> 442
   into the space behind it, the panel reads as being shoved down by the row
   above rather than retracting under its own steam.

   100% is the panel's own size along the axis it docks on, which is exactly
   far enough to clear the edge: a 200px bottom dock at y 442-642 lands at
   642-842, past the bottom of a 642px workspace. Percentages are safe here
   because these are the panels that KEEP their box - the ones whose height
   collapses take a fixed pixel travel instead, from the rule below, which
   wins on specificity (two classes to one).

   `translate()` takes both axes in one function, so all three states still
   list the same functions in the same order - which is what keeps the
   browser interpolating componentwise instead of blending matrices.
*/
.window_component_host_region_top[b-mtxjgbouud] {
    --host-exit-travel: -100%;
}

.window_component_host_region_bottom[b-mtxjgbouud] {
    --host-exit-travel: 100%;
}

.window_component_host_region_left[b-mtxjgbouud] {
    --host-exit-x: -100%;
    --host-exit-travel: 0px;
}

.window_component_host_region_right[b-mtxjgbouud] {
    --host-exit-x: 100%;
    --host-exit-travel: 0px;
}

/*
   A window whose HEIGHT is animating cannot express its travel as a
   percentage, because translateY(%) resolves against the element's own
   height - so the distance it moves is the PRODUCT of two curves running in
   opposite directions, and a product of that shape peaks in the middle and
   returns to where it started.

   That is a window falling down and then rising back up before it vanishes,
   which is what it looked like. Measured on a 734px window, in pixels of
   travel across the exit:

     progress  0     0.15   0.3    0.5    0.7    0.85   1
     travel    0     13.1   21.6   25.7   21.6   13.1   0

   Both halves are individually correct and neither is the bug on its own.
   The collapse to `height: 0` is what lets the neighbours below slide up
   smoothly (see the tiled rule further down), and the percentage is what
   makes travel proportional for windows that keep their height. They simply
   cannot both apply to the same window.

   So the windows that collapse - tiled main windows, and windows sharing a
   dock - travel a fixed distance instead. Every other window keeps the
   percentage, because its height is stable for the whole animation and the
   proportional feel is the intended one.

   Set on the plain selectors rather than on the exit states, because the
   ENTRY animation has the same shape in reverse: @starting-style takes
   these windows in from `height: 0`, so a percentage dips them downward
   mid-entry and lifts them back. One override covers both directions.

   48px rather than something derived: it is comfortably more than the 25.7px
   the broken curve peaked at, so the fall reads as deliberate, and well
   under the ~90px a full-height window travels, so a short tiled window does
   not sail down over whatever is beneath it.

   The main-region test has to be the SAME one that decides whether the height
   collapses at all - a window with nobody below it keeps its box, so its
   height is stable and the percentage is correct for it, exactly as it is for
   a maximized window. If these two selectors ever drift apart, one of them is
   wrong: the fixed travel exists only to compensate for a collapsing height.
*/
.window_component_host_region_main:not(.window_component_host_maximized):has(~ .window_component_host_visible)[b-mtxjgbouud],
.window_component_host_dock_x:has(~ .window_component_host_visible)[b-mtxjgbouud],
.window_component_host_visible ~ .window_component_host_dock_x[b-mtxjgbouud],
.window_component_host_dock_y:has(~ .window_component_host_visible)[b-mtxjgbouud],
.window_component_host_visible ~ .window_component_host_dock_y[b-mtxjgbouud] {
    --host-exit-travel: 48px;
}

/*
   Which cell of the workspace grid this window occupies, taken straight
   from its framework Placement. The track sizes are WindowHost's business
   (see WindowHost.razor.css); this is only the claim on a cell.

   Two windows in the same region are stacked in the same cell, which is
   correct: the framework guarantees only one of them is visible at a time
   (activating one minimizes the other - see WindowManager.ActivateCore's
   sharesRegion check), and the loser is display:none.
*/
/*
   How a window sizes itself WITHIN its region. Which region that is, and
   where the region sits, belongs to the wrapper - see .window_region in
   WindowHost.razor.css.

   A DOCKED window fills its region: the dock's track is what defines its
   size along the docking axis, and a sidebar that only came down as far as
   its content would leave a gap under itself. Two windows docked to the
   same edge share it.
*/
.window_component_host_region_top[b-mtxjgbouud],
.window_component_host_region_bottom[b-mtxjgbouud],
.window_component_host_region_left[b-mtxjgbouud],
.window_component_host_region_right[b-mtxjgbouud] {
    flex: 1 1 auto;
}

/*
   A window in the MAIN area sizes to its own content and does not grow, so
   several normal windows tile down the region instead of one of them
   swallowing the space. `1` for flex-shrink lets them give way
   proportionally when their combined content exceeds the region rather than
   overflowing it.

   Note this is flex-GROW zero even when maximized - see the rule below.
*/
.window_component_host_region_main[b-mtxjgbouud] {
    flex: 0 1 auto;
}

/*
   A maximized main window fills its region through `height`, never through
   flex-grow, and the distinction is the whole maximize animation.

   flex-grow interpolates perfectly well - measured 100/100 -> 66.7/133.3 ->
   0/200 across a two-item column - but it only does so if it is in the
   transition list, and for a main window it deliberately is not. Letting
   grow do the filling would resize the window in a single frame, leaving
   the height transition underneath nothing to animate. Keeping grow at zero
   makes `height: auto -> 100%` the only thing changing.

   (An earlier version of this note claimed flex-grow was not interpolable
   at all. It is; the property that genuinely cannot be interpolated, and
   which broke this animation before, is align-self.)

   This overrides the generic .window_component_host_maximized rule further
   up, whose `flex: 1 1 auto` is for the OVERLAY layer, where the host is a
   flex item of .window_popup_item and there is no height animation to
   protect.
*/
.window_component_host_region_main.window_component_host_maximized[b-mtxjgbouud] {
    flex: 0 1 auto;
    height: 100%;
}

/*
   A main-layer window that is LEAVING - minimized, hidden by a workspace
   switch, or closing - is taken out of flow for the duration of its exit.

   Two things that are individually correct combine badly without this.
   `display ... allow-discrete` deliberately keeps a leaving window laid out
   for the whole animation so it has something to animate, and a laid-out
   flex item still claims space. Together they meant the outgoing window
   held its slot while the incoming one was pushed below it, then snapped up
   when the exit finished: opening Profile 2 over Profile showed the new
   window 108px down for ~260ms before it jumped into place.

   Which is why this applies only to windows that FILL their region - see the
   rule that exempts tiled windows below.

   The offsets are pinned explicitly rather than left to the static
   position. That distinction matters and is easy to get wrong: an
   absolutely positioned box with no offsets sits where it WOULD have been
   in flow, and that location still moves when the elements around it
   change. It only looked correct while the leaving window happened to be
   first in DOM order; closing one that was later, with an incoming window
   re-entering flow above it, dropped the leaving window by exactly the
   incoming one's height - it visibly fell before fading out.

   What it pins TO is its region wrapper, which carries position: relative
   for exactly this (see .window_region in WindowHost.razor.css). So inset 0
   here means "the top-left of my own region", and a docked panel animates
   out of its own dock rather than leaping to the corner of the workspace.

   Do NOT lean on the subtler rule here - an absolutely positioned child of a
   grid container takes its grid AREA as containing block, provided it carries
   grid placement properties - which holds only while each window is itself a
   grid item. Regions have wrappers so their windows can tile, so the windows
   are not grid items and that rule does not
   applying; an ordinary positioned ancestor is both sturdier and easier to
   reason about.

   Scoped away from overlays deliberately: an overlay host is centred by
   .window_popup_item's flexbox, and taking it out of that flow would snap
   it to the corner mid-animation. Overlays are already positioned by their
   wrapper, so they never had this problem.
*/
.window_component_host_hidden:not(.window_component_host_overlay)[b-mtxjgbouud],
.window_component_host_minimized:not(.window_component_host_overlay)[b-mtxjgbouud],
.window_component_host_closing:not(.window_component_host_overlay)[b-mtxjgbouud] {
    position: absolute;
    top: 0;
    left: 0;
    width: 100%;
}

/*
   A TILED window leaves from where it is standing, so it stays in flow.

   Taking a window out of flow and pinning it to the top of its region is
   right for one that FILLS that region - a docked panel, or a maximized main
   window - because the top of the region is where it already was, so the pin
   is invisible, and releasing the space immediately is what stops the window
   replacing it from being shoved down for the length of an animation.

   For a tiled window it is neither of those things. The lower of two tiled
   windows would jump to the top of the region and only then fade, which
   reads as the wrong window minimizing. Left in flow it folds away exactly
   where it sits.

   Staying in flow is also what makes the space it leaves behind closeable
   smoothly, which is what `height: 0` below is for. Because the window is
   still in flow, its box is what the windows after it are standing on, so
   collapsing that box slides them up - no measuring, no JS, and it rides
   the same 260ms curve as everything else. Out of flow there would be
   nothing left to animate: the space would already be gone on frame one and
   the survivors would jump.

   Order matters in the pairing. Opacity finishes at 200ms and height at
   260ms, so the window has faded out before the last of the collapse, and
   the squeeze is never seen against a still-visible frame. The content does
   not squash as it goes, because .window_container clips (see
   WindowFrame.razor.css) - the frame closes over its content like a blind
   rather than crushing it.

   Interpolating `auto -> 0` needs `interpolate-size: allow-keywords`, which
   is set at the top of this file.

   Only main-region NORMAL windows qualify, which is exactly the tiling case:
   docked windows fill their dock, and a maximized main window fills the main
   area, so for those the top of the region IS where they already are.

   ...and only when something is actually STANDING BELOW to take the space.
   That qualifier is what `:has(~ .window_component_host_visible)` is doing,
   and without it the collapse runs the animation backwards.

   Collapsing height keeps the top edge pinned by flow and pulls the BOTTOM
   edge up to meet it. When a window below is waiting for that room, the rise
   is the point - it is the survivor sliding up. When nothing is below, the
   window simply folds upward into its own top edge, and for a tall window
   that swamps everything else: measured on the Cookie window, the bottom
   edge travels 642px up against 48px of downward translate, so the window
   visibly leaves UPWARDS. Maximizing it first made it correct again, which
   is the tell - a maximized window takes the pinned branch above and keeps
   its box, so only the transform moves it.

   A window that fills its region is in exactly the position a maximized one
   is in, whether or not the framework calls it maximized. The Cookie window
   gets there through `max-height: 100%` clamping content that wants more
   room: 642.4px of content in a 642.4px region, tiled by class and
   region-filling in fact.

   `:only-child` is the obvious test and it is the WRONG one. Windows stay in
   the DOM for their whole lifetime and only toggle `display` (see the note at
   the top of this file), so a minimized window is still a sibling: the last
   visible window in a region reports :only-child = false and would go on
   collapsing. Measured with two windows open - the visible one had
   :only-child false and no later visible sibling, which is the distinction
   that matters. The subsequent-sibling test asks the question the collapse
   actually depends on: is there anyone after me who would move up.
*/
.window_component_host_region_main:not(.window_component_host_maximized):has(~ .window_component_host_visible).window_component_host_hidden[b-mtxjgbouud],
.window_component_host_region_main:not(.window_component_host_maximized):has(~ .window_component_host_visible).window_component_host_minimized[b-mtxjgbouud],
.window_component_host_region_main:not(.window_component_host_maximized):has(~ .window_component_host_visible).window_component_host_closing[b-mtxjgbouud] {
    position: static;
    height: 0;
    min-height: 0;
}

/*
   A tiled window with nothing below it stays in flow as well, where it
   stands, while the windows above it are at rest.

   Out of flow it is pinned to the top of the region by the leaving rule
   further up, which is right for the only window in a region and wrong for
   the lower of two: it leapt to the top, over the window above, before
   fading - measured 224px - which reads as the wrong window leaving.
   `top: auto` cannot keep it where it was, because an absolutely positioned
   child of a flex container takes its static position at the container's
   start.

   Its height is left alone, so it folds from where it stands. Only a window
   with somebody below to take the room collapses, by the rule above.

   "At rest" is the arriving class, which WindowComponentHost puts on a
   window from the moment it is shown until its entry settles. A window shown
   above the leaver in the same render - the main area emptied, and an older
   window brought back - would push a leaver left in flow down by its whole
   height. Then the leaver stays pinned at the top, which is where it was,
   being the only window there.
*/
.window_component_host_visible:not(.window_component_host_arriving) ~ .window_component_host_region_main:not(.window_component_host_maximized):not(.window_component_host_arriving ~ *).window_component_host_hidden[b-mtxjgbouud],
.window_component_host_visible:not(.window_component_host_arriving) ~ .window_component_host_region_main:not(.window_component_host_maximized):not(.window_component_host_arriving ~ *).window_component_host_minimized[b-mtxjgbouud],
.window_component_host_visible:not(.window_component_host_arriving) ~ .window_component_host_region_main:not(.window_component_host_maximized):not(.window_component_host_arriving ~ *).window_component_host_closing[b-mtxjgbouud] {
    position: static;
}

/*
   ...and the same collapse as the ENTRY state, so a tiled window coming back
   pushes its neighbours down as smoothly as leaving let them slide up.

   This does not come for free, which is easy to assume and wrong. Going from
   display: none to displayed, a property transitions only if
   @starting-style gives it a before-change value; anything omitted starts at
   its after-change value and therefore has no delta to animate. The block
   further up lists opacity and transform, so height was snapping from 0 to
   auto in a single frame and shoving the window below it down - the leaving
   half looked animated and the returning half did not.

   Restoring from the drawer is the obvious way to see it, but it is the same
   for any route back: un-maximizing a window returns the neighbours it
   evicted, and those were arriving the same way.

   Deliberately narrower than the block above, which applies to every
   visible host. A docked window or a maximized one growing from zero height
   on entry would be a different animation from the fold they have now, and
   the tiling case is the only one where anything is standing underneath
   waiting for the room.

   Carries the same "is anyone below me" test as the exit, and for the same
   reason: growing from zero height only means something when there is a
   neighbour to push down. A window arriving on its own would instead unfold
   from its own top edge - the entry equivalent of leaving upwards - so it
   arrives at full height with just the fold, exactly as a maximized window
   does. Both directions have to agree, or a window would leave one way and
   come back another.
*/
@starting-style {
    .window_component_host_region_main:not(.window_component_host_maximized):has(~ .window_component_host_visible).window_component_host_visible[b-mtxjgbouud] {
        height: 0;
    }

    /* Windows sharing a dock arrive the same way they leave - claiming their
       grow share gradually, so the neighbour already in the dock gives ground
       smoothly instead of halving in one frame.

       Same both-directions test as the exit, and for the same reason: a dock
       whose other window is merely MINIMIZED is not being shared, and a window
       arriving into it alone would otherwise unfold from zero height with
       nothing to give ground. Entry and exit have to agree, or a panel leaves
       one way and comes back another. */
    .window_component_host_dock_x:has(~ .window_component_host_visible).window_component_host_visible[b-mtxjgbouud],
    .window_component_host_visible ~ .window_component_host_dock_x.window_component_host_visible[b-mtxjgbouud],
    .window_component_host_dock_y:has(~ .window_component_host_visible).window_component_host_visible[b-mtxjgbouud],
    .window_component_host_visible ~ .window_component_host_dock_y.window_component_host_visible[b-mtxjgbouud] {
        flex-grow: 0;
        height: 0;
    }
}

/*
   ...except that a leaving DOCKED window cannot use "100% of my region",
   because its region is disappearing at the same moment. WindowHost drops a
   dock from the track sizes as soon as its window stops being visible, so
   the track is already animating to 0px on the first frame of the exit.

   A percentage of a collapsing track would be bad enough; what actually
   happened was worse. The frame keeps overflow: visible for its drop
   shadow, so a zero-width containing block does not clip it - it paints at
   its intrinsic content width. The panel appeared to snap out to full size
   and fold away from there, reading as "it undocked itself, then closed".

   --host-dock-size is written inline by WindowComponentHost from the same
   value WindowHost used for the track, so the panel keeps its real size on
   the way out while the space closes up underneath it. The two happen
   together rather than one after the other.

   Same specificity as the rule above (two classes either way), so these
   must stay AFTER it to win.
*/
/*
   max-height is released here, and that is not incidental.

   The viewport clamp further up is what stops a leaving window ballooning
   to its intrinsic content height mid-exit. But it is `max-height: 100%`,
   and 100% now resolves against a grid area that is collapsing to zero at
   exactly the same moment - so a leaving bottom dock was clamped to
   max-height: 0 and vanished on the first frame instead of folding away
   (measured: height 170px -> 0px the instant it started closing).

   Setting an explicit height from --host-dock-size does the clamp's job
   already, and does it better: the size is known rather than inherited from
   a track that is disappearing.
*/
/*
   "Does this dock go away with me?" - and holding its own box is the DEFAULT
   answer, with sharing as the exception below.

   A dock whose last visible window is leaving IS that window: the track
   collapses underneath it, so it has to carry its own size out. A dock that
   still holds a visible window survives, and a leaver hands its share over
   instead.

   NEVER ASK `:only-child` HERE, for the same reason it is wrong in the main
   region: windows stay in the DOM for their whole lifetime and only toggle
   `display`, so a MINIMIZED window is still a child. A dock holding one visible
   window plus one minimized one therefore fails :only-child and takes the
   sharing branch - collapsing height to 0 with
   nothing to hand the space to, which folds the panel upward into its own top
   edge. Measured on a synthetic bottom dock: sole leaver kept height 170px,
   the same leaver with one minimized sibling collapsed to 0px.

   It also lost the two declarations below, which is why the failure was worse
   here than in the main region. Releasing `max-height` and pinning the size
   from --host-dock-size are what stop a leaving panel being clamped by a
   track that is collapsing to zero at the same moment - see the note above.

   The test is inverted rather than negated because "is there another VISIBLE
   window in this dock" has to look BOTH WAYS, and CSS can only look forward:
   `:has(~ .visible)` finds one after, and `.visible ~ ...` finds one before.
   Writing the negation would need both of those inside :not(). Making the
   safe answer the default and letting the two positive cases override it says
   the same thing without the gymnastics - and it fails safe, since a window
   that matches neither keeps its box rather than collapsing into nothing.

   Note the main region asks a NARROWER question - only later siblings, since
   those are the ones that slide up into the space. Here any surviving window
   keeps the track alive, wherever it sits in DOM order.
*/
/*
   The cap is REPLACED here, never released, and that distinction is the
   whole of a bug that made a docked panel leave from off the top of the
   screen.

   A docked window rests at `height: auto` held down by `max-height: 100%` -
   the content is taller than the dock and the clamp is what hides that. The
   exit sets an explicit height, so the height transition runs
   `auto -> <length>`, and `interpolate-size: allow-keywords` (set at the top
   of this file) resolves that `auto` to the INTRINSIC CONTENT height rather
   than to the clamped height it was displaying. Release the clamp in the
   same frame and there is nothing left to hide it.

   Measured on the Cookie window docked to the bottom, one frame after
   pressing minimize: height 200px -> 1309.2px, top 752 -> -357. Anchored
   `bottom: 0`, the panel grows UPWARDS off the top of the viewport and then
   shrinks back down over 260ms - which reads exactly as "it minimized from
   the top of the screen".

   `max-height: none` was right about what it was fixing and wrong about how.
   The clamp could not stay `100%`, because 100% resolves against a grid
   track that is collapsing to zero at the same moment, which clamped a
   leaving bottom dock to zero on the first frame (measured 170px -> 0px).
   But the answer to "this percentage resolves against the wrong thing" is a
   value that resolves against the right thing, not no value at all. Capping
   at the same size the height is heading for makes the bogus start value
   unobservable: the used height is that size on every frame.

   For dock_x the cap stays `100%` deliberately - a left or right dock
   collapses along WIDTH, so its region's height is not going anywhere and
   100% still means what it says.

   And its width is held by `min-width`, never by animating `width`. Width
   is in the transition list, and running it from `100%` of a track that is
   collapsing to a fixed size interpolates against both at once: the panel
   narrowed to three quarters of itself and widened again on the way out
   (measured 260 -> 196 -> 260). A minimum is not transitioned, starts equal
   to the width it is holding, and keeps the box whole while `100%` falls
   away under it.
*/
.window_component_host_dock_x.window_component_host_hidden[b-mtxjgbouud],
.window_component_host_dock_x.window_component_host_minimized[b-mtxjgbouud],
.window_component_host_dock_x.window_component_host_closing[b-mtxjgbouud] {
    min-width: var(--host-dock-size);
    height: 100%;
    max-height: 100%;
}

.window_component_host_dock_y.window_component_host_hidden[b-mtxjgbouud],
.window_component_host_dock_y.window_component_host_minimized[b-mtxjgbouud],
.window_component_host_dock_y.window_component_host_closing[b-mtxjgbouud] {
    width: 100%;
    height: var(--host-dock-size);
    max-height: var(--host-dock-size);
}

/*
   Windows SHARING a dock leave the way tiled main windows do: in flow,
   giving their space back as they go, so whatever is left grows into it
   rather than snapping.

   The mechanism differs from the main region though, and it has to. Tiled
   main windows are content-sized, so collapsing `height` is enough. Docked
   windows split their dock with flex-grow, and a grow share is not something
   `height` can give back - set height to 0 alone and grow: 1 simply claims
   the space again. So the share itself is animated, grow 1 -> 0, with height
   collapsing alongside it to take the basis down too.

   That works because flex-grow interpolates (measured), and it is why
   flex-grow is in the transition list at the top of this file.

   "Sharing" means another window in this dock is still VISIBLE - not merely
   still in the DOM, which a minimized one always is. Each axis therefore
   appears twice: once finding a visible sibling after it, once finding one
   before it. Both carry three classes against the base rule's two, so they
   win on specificity as well as on source order.
*/
.window_component_host_dock_x:has(~ .window_component_host_visible).window_component_host_hidden[b-mtxjgbouud],
.window_component_host_dock_x:has(~ .window_component_host_visible).window_component_host_minimized[b-mtxjgbouud],
.window_component_host_dock_x:has(~ .window_component_host_visible).window_component_host_closing[b-mtxjgbouud],
.window_component_host_visible ~ .window_component_host_dock_x.window_component_host_hidden[b-mtxjgbouud],
.window_component_host_visible ~ .window_component_host_dock_x.window_component_host_minimized[b-mtxjgbouud],
.window_component_host_visible ~ .window_component_host_dock_x.window_component_host_closing[b-mtxjgbouud],
.window_component_host_dock_y:has(~ .window_component_host_visible).window_component_host_hidden[b-mtxjgbouud],
.window_component_host_dock_y:has(~ .window_component_host_visible).window_component_host_minimized[b-mtxjgbouud],
.window_component_host_dock_y:has(~ .window_component_host_visible).window_component_host_closing[b-mtxjgbouud],
.window_component_host_visible ~ .window_component_host_dock_y.window_component_host_hidden[b-mtxjgbouud],
.window_component_host_visible ~ .window_component_host_dock_y.window_component_host_minimized[b-mtxjgbouud],
.window_component_host_visible ~ .window_component_host_dock_y.window_component_host_closing[b-mtxjgbouud] {
    position: static;
    flex-grow: 0;
    height: 0;
    min-height: 0;
    max-height: none;
}

/*
   Which EDGE a leaving panel is pinned to has to match the edge it docks
   on, because its grid area does not merely shrink - it moves.

   Pinning everything to top/left is right for the left and top docks: their
   tracks collapse toward the origin, so the area stays put at x=0 (or y=0)
   and only loses size. The right and bottom docks collapse the other way.
   Their zero-width area ends up flush against the far edge of the
   workspace, so a panel pinned to its left would start where the track
   ended and slide out past the viewport - measured at x=1293 on a 1280px
   screen, the panel visibly shooting off to the right as it folded.

   Anchoring to the far edge instead keeps the panel exactly where it was
   while the space closes up behind it.
*/
.window_component_host_region_right.window_component_host_hidden[b-mtxjgbouud],
.window_component_host_region_right.window_component_host_minimized[b-mtxjgbouud],
.window_component_host_region_right.window_component_host_closing[b-mtxjgbouud] {
    left: auto;
    right: 0;
}

.window_component_host_region_bottom.window_component_host_hidden[b-mtxjgbouud],
.window_component_host_region_bottom.window_component_host_minimized[b-mtxjgbouud],
.window_component_host_region_bottom.window_component_host_closing[b-mtxjgbouud] {
    top: auto;
    bottom: 0;
}

/*
   Stacked mobile layout: a left/right dock is a full-width row there, so its
   size is a height rather than a width and the axis rules swap over. Mirrors
   the template swap in WindowHost.razor.css.

   All of them, the cap included. The desktop rule keeps `max-height: 100%`
   because its region's height is not going anywhere; stacked, the region is
   the row that collapses, and that cap crushed a leaving 260px panel to
   nothing along with it. It is capped at the size it holds, as the top and
   bottom docks are.
*/
@media (max-width: 767px) {
    .window_component_host_dock_x.window_component_host_hidden[b-mtxjgbouud],
    .window_component_host_dock_x.window_component_host_minimized[b-mtxjgbouud],
    .window_component_host_dock_x.window_component_host_closing[b-mtxjgbouud] {
        width: 100%;
        min-width: 0;
        height: var(--host-dock-size);
        max-height: var(--host-dock-size);
    }
}

/*
   `transform: none` at rest, NOT an identity 3D transform.

   Writing the resting state as perspective(1000px) translateY(0) scale(1)
   rotateX(0deg) looks harmless - it is visually identity - but it computes
   to matrix3d(...) rather than none, which means every idle window
   permanently owns a 3D-transformed composited layer. Descendant scrollers
   inside a 3D-transformed subtree lose fast composited scrolling, and text
   in such a layer loses subpixel antialiasing and has to be re-rasterized.
   On the Terms window (5990px of text in a 679px viewport) that is the
   difference between smooth and gritty scrolling.

   Interpolating none -> the away transform still animates: the browser
   substitutes identity values. Measured at 50%, scale/rotate/translate are
   bit-identical to the old explicit-identity version; only the perspective
   component differs, because the identity for perspective() is
   perspective(infinity), so depth ramps in rather than being constant. The
   fold reads a touch flatter early and lands in exactly the same place.
*/
.window_component_host_visible[b-mtxjgbouud] {
    display: flex;
    opacity: 1;
    transform: none;
}

/* Entry state, used when a window opens or is restored. */
@starting-style {
    .window_component_host_visible[b-mtxjgbouud] {
        opacity: 0;
        transform: perspective(1000px) translate(var(--host-exit-x), var(--host-exit-travel)) scale(0.9) rotateX(12deg);
    }
}

/*
   Closing reuses the same away state as minimizing, so a window leaves the
   same way whether it is being put down or thrown out.

   Unlike minimize, this cannot be done with `display` alone: closing
   destroys the element, and a destroyed element has nothing to transition.
   The window is kept alive for exactly this animation by the two-phase
   close in WindowManager - it sits in WindowLifecycleState.Closing until
   WindowComponentHost reports WindowUiPhase.ExitComplete, which is fired
   from JS when these animations settle.

   Needs to beat .window_component_host_visible, which is still present on a
   closing window (it is still on screen), hence the compound selector.
*/
.window_component_host_visible.window_component_host_closing[b-mtxjgbouud] {
    opacity: 0;
    transform: perspective(1000px) translate(var(--host-exit-x), var(--host-exit-travel)) scale(0.9) rotateX(12deg);
    pointer-events: none;
}

@media (prefers-reduced-motion: reduce) {
    .window_component_host_visible.window_component_host_closing[b-mtxjgbouud] {
        transform: none;
    }
}

/*
   Respect the OS "reduce motion" setting. The window still appears and
   disappears, it just stops moving - which matters more than usual here,
   since scale+rotate animations are a common migraine and vestibular
   trigger.
*/
@media (prefers-reduced-motion: reduce) {
    .window_component_host[b-mtxjgbouud] {
        transition: opacity 120ms ease, display 120ms allow-discrete;
    }

    .window_component_host_hidden[b-mtxjgbouud],
    .window_component_host_minimized[b-mtxjgbouud],
    .window_component_host_visible[b-mtxjgbouud] {
        transform: none;
    }

    @starting-style {
        .window_component_host_visible[b-mtxjgbouud] {
            transform: none;
        }
    }
}
/* /Components/Windows/TaskHistory.razor.rz.scp.css */
/*
   THE DATE-RANGE ROW IS NO LONGER HERE, and that is deliberate.

   `.history_range` and its two companions moved to app.css when Exceptions
   (11400) and Activity (11600) started drawing the same control. CSS isolation
   scopes a rule to the component whose file it is in, so leaving them here
   would have given those two windows the class NAMES and none of the rules -
   and the markup renders perfectly either way, which is what makes the trap
   worth a note rather than a silent move.

   Nothing else in this window has styling of its own. The file stays so this
   comment has somewhere to live.
*/
