/* /Components/Layout/MainLayout.razor.rz.scp.css */
/* The bar spans the window while its contents line up with the sheet below, so the brand sits over
   the page title rather than out at the window's edge. The padding grows to whatever half the
   leftover space is, and never falls below the 1.5rem a narrow window needs — which is the same
   calculation centring the sheet, expressed as padding because the bar itself has to reach the
   edges to read as the application's own edge. */
header[b-r12ijds563] {
    align-items: center;
    /* The chrome tone rather than the sheet's white: this bar frames the application rather than
       holding any of it, which is the same job the filter row and a table's column headings do. */
    background: var(--sunk);
    border-bottom: 1px solid var(--rule);
    display: flex;
    /* Onto a second line rather than off the side of the window. A flex item will not shrink below
       what its own words need, so on a narrow screen the three here — the brand, the bar's links
       and what is the operator's own — simply ran past the right edge, taking the page's whole
       width with them: every page grew a sideways scrollbar, and the settings link sat off-screen
       behind it. Wrapping is what a bar of links can do about that without a script to fold them
       behind a button, and without hiding anything from a reader on a phone that a reader on a
       monitor is given. Nothing moves at the widths where it all fits on one line. */
    flex-wrap: wrap;
    /* The row gap is the one the wrapping asks for and is never seen otherwise; the column gap is
       the bar's own, unchanged. */
    gap: 0.5rem 1.5rem;
    /* The height the brand gives the bar, kept when there is no brand: its mark is 1.6em of the
       brand's size, and without it the bar would shrink to the links and every page would move
       up under it. */
    min-height: calc(var(--text-xl) * 1.6);
    padding-block: 0.75rem;
    /* The 1.75rem is the column's own inner padding, added so the brand lands on the page title
       rather than a hair to the left of it. There is no border to account for any more: the column
       below is no longer a bordered sheet. */
    padding-inline: max(1.5rem, calc((100% - var(--page-width)) / 2 + 1.75rem));
}

/* Given focus so a jump back to the top of the page lands on it, not because anyone tabbed to it —
   the ring would be drawn around the whole bar, which the reader did not choose. See PageTop. */
header:focus[b-r12ijds563] {
    outline: none;
}

/* The fold the whole bar is held in.
   ----------------------------------------------------------------------------------------------
   It takes whatever the brand leaves, and at the widths where the bar fits there is nothing here
   to see: the control is taken away and what is inside lays out as the bar always has. The fold
   only means anything under the width below, where the bar would otherwise be three rows deep
   before a reader has read a word of the page. */
.bar-menu[b-r12ijds563] {
    flex: 1;
    /* Without this the links inside refuse to let the box narrow, and the brand is pushed off. */
    min-width: 0;
}

    .bar-fold[b-r12ijds563] {
        display: none;
    }

/* What was the bar: the two navs, side by side, with the operator's own taking the far end. */
.bar-menu-content[b-r12ijds563] {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1.5rem;
}

    header .brand[b-r12ijds563] {
        align-items: center;
        color: var(--ink);
        display: flex;
        font-size: var(--text-xl);
        font-weight: 600;
        gap: 0.5rem;
        text-decoration: none;
    }

        /* Sized in ems so the mark follows the wordmark beside it rather than a fixed pixel, and
           kept from shrinking if the bar is ever squeezed. Larger than the word it sits against,
           because the drawing keeps a margin inside its square: at the word's own height the lens
           read as a dot. The same 2.25em the website's header draws it at, so the two headers
           match. The width follows the height, so a logo an Administrator uploads keeps its own
           proportions; capped, so a wide one cannot push the menus off the bar. */
        header .brand .mark[b-r12ijds563] {
            flex: none;
            height: 2.25em;
            max-width: 6em;
            object-fit: contain;
            width: auto;
        }

    /* At the size the pages under it are read at, not the browser's prose default. The bar names
       where you are in a tool whose content is dense; set two pixels larger than the tables it
       leads to, it read as the loudest thing on the page. */
    header nav[b-r12ijds563] {
        align-items: center;
        display: flex;
        /* For the same reason the bar itself wraps, and needed as well as that: on a service page
           this one holds Home, the services, and a heading for each model, which together want
           more than a phone's whole width — so the bar wrapping would still leave this running
           off the edge on its own line. Both navs are matched here, the bar's and the operator's:
           each is a row of links that would rather be two rows than be half unreachable. */
        flex-wrap: wrap;
        font-size: var(--text-md);
        gap: 0.5rem 1rem;
    }

        /* Flexed so the mark drawn in front of the words sits on their line rather than on the
           baseline under it, the way a heading's does. */
        header nav[b-r12ijds563]  a {
            align-items: center;
            color: var(--ink-soft);
            display: inline-flex;
            gap: 0.4rem;
            text-decoration: none;
        }

        header nav[b-r12ijds563]  a:hover {
            text-decoration: underline;
        }

        header nav[b-r12ijds563]  a.active {
            color: var(--accent);
            font-weight: 600;
        }

        /* The line between the tool's part of the bar and the service's: one text line tall, in the
           ink the tables rule their rows with, so it marks where a group starts without saying
           anything itself. */
        header nav .separator[b-r12ijds563] {
            align-self: center;
            border-left: 1px solid var(--rule);
            height: 1.25em;
        }

/* The mark in front of every item, in both menus and under every heading. Sized to the text it
   fronts rather than in rem, so it rides the bar's size, and set back in the fainter ink the tiles
   set theirs in: it says which item this is at a glance and then gets out of the way of the word
   beside it. It comes forward to the item's own ink when the item is current or under the pointer,
   so the two read as one thing lit rather than a word lit beside a mark that was not. ::deep
   throughout because the mark is drawn by a component of its own, which this sheet does not
   otherwise reach. */
header[b-r12ijds563]  .glyph {
    color: var(--ink-faint);
    flex: none;
    height: 1em;
    width: 1em;
}

    header[b-r12ijds563]  a:hover .glyph,
    header[b-r12ijds563]  a.active .glyph,
    header[b-r12ijds563]  summary:hover .glyph,
    header[b-r12ijds563]  summary.active .glyph,
    header[b-r12ijds563]  button:hover .glyph {
        color: inherit;
    }

/* What is the operator's own, at the far end of the bar. Pushed there by the margin rather than
   placed by the grid the bar does not have: the brand and the menu stay where they are, and this
   takes whatever is left. Signed in it is a menu under the name, drawn by .menu like the section
   headings; open it is one link, drawn like the bar's others. */
.operator[b-r12ijds563] {
    font-size: var(--text-md);
    margin-left: auto;
}

    .operator[b-r12ijds563]  a {
        align-items: center;
        color: var(--ink-soft);
        display: inline-flex;
        gap: 0.4rem;
        text-decoration: none;
    }

    .operator[b-r12ijds563]  a:hover {
        text-decoration: underline;
    }

    .operator[b-r12ijds563]  a.active {
        color: var(--accent);
        font-weight: 600;
    }

    /* Hung from the right edge rather than the left: this is the last thing in the bar, and a
       sheet opening leftwards from it stays on the page. Named as the operator's menu rather than
       merely the operator's so that it outweighs the .menu rule below: at equal weight that rule,
       being later, put left: 0 back, and a sheet hung from both edges ran past the window and
       gave the page a scrollbar each way. */
    /* A visitor's two links side by side, spaced as the bar's own are. */
    .operator.visitor[b-r12ijds563] {
        display: flex;
        gap: 1rem;
    }

    .menu.operator .submenu[b-r12ijds563] {
        left: auto;
        right: 0;
    }

    /* The one button among links, drawn as the links are: it is a way out beside a place to go,
       and a bordered button in a column of links would read as the point of the menu. */
    .operator .submenu button[b-r12ijds563] {
        align-items: center;
        background: none;
        border: 0;
        color: var(--ink-soft);
        cursor: pointer;
        display: inline-flex;
        font: inherit;
        gap: 0.4rem;
        padding: 0;
        text-align: left;
    }

        .operator .submenu button:hover[b-r12ijds563] {
            text-decoration: underline;
        }

        .operator .submenu button:focus-visible[b-r12ijds563] {
            outline: 2px solid var(--accent);
            outline-offset: 2px;
        }

/* Admin and the pages under it. */
.menu[b-r12ijds563] {
    position: relative;
}

    .menu summary[b-r12ijds563] {
        align-items: center;
        color: var(--ink-soft);
        cursor: pointer;
        display: flex;
        gap: 0.35rem;
        list-style: none;
    }

    /* Safari draws its own marker through list-style. */
    .menu summary[b-r12ijds563]::-webkit-details-marker {
        display: none;
    }

    .menu summary:hover[b-r12ijds563] {
        text-decoration: underline;
    }

    .menu summary.active[b-r12ijds563] {
        color: var(--accent);
        font-weight: 600;
    }

    /* A disclosure caret, rotated when the menu is open: the affordance that this is a menu
       rather than a link. */
    .menu summary[b-r12ijds563]::after {
        border-left: 0.3rem solid transparent;
        border-right: 0.3rem solid transparent;
        border-top: 0.3rem solid currentColor;
        content: "";
        height: 0;
        width: 0;
    }

    .menu[open] summary[b-r12ijds563]::after {
        transform: rotate(180deg);
    }

    .menu .submenu[b-r12ijds563] {
        background: var(--surface);
        border: 1px solid var(--rule);
        border-radius: 6px;
        display: flex;
        flex-direction: column;
        gap: 0.5rem;
        left: 0;
        min-width: 9rem;
        padding: 0.6rem 0.75rem;
        position: absolute;
        top: calc(100% + 0.5rem);
        z-index: 10;
    }

    /* One concern and the three pages under it, spaced away from the group above so they read as
       belonging to their heading rather than floating between the two. */
    .menu .submenu-group[b-r12ijds563] {
        display: flex;
        flex-direction: column;
        gap: 0.35rem;
    }

    /* Names the group without offering to go anywhere — the group's own overview is the link that
       does. Smaller and set back, and the links under it indented, so a heading is not mistaken
       for one of them. */
    .menu .submenu-label[b-r12ijds563] {
        color: var(--ink-soft);
        font-size: var(--text-xs);
        letter-spacing: 0.04em;
        text-transform: uppercase;
    }

    .menu .submenu-group[b-r12ijds563]  a {
        padding-left: 0.75rem;
    }

/* A bounded column, not a sheet. What is written on the ground and what is written on a surface is
   a distinction the page makes for itself: a breadcrumb, a title and the line under it are the page
   saying where you are, and they belong on the ground the way a heading belongs above a document.
   The stored data belongs on a surface, and takes one of its own further down.

   Runs to --page-width, which is the window itself: a table follows the monitor it was opened on
   rather than scrolling inside a column narrower than the screen. Still written as a max-width
   against that token so a length put back there re-columns the page and the two bars together. */
main[b-r12ijds563] {
    /* So --page-width is the column's whole width, padding included. Otherwise the bar above,
       which centres itself against that same number, would line up against a different edge. */
    box-sizing: border-box;
    flex: 1;
    margin: 0 auto;
    max-width: var(--page-width);
    /* The same space above the footer as under the bar: the page is framed by two bars, and a
       gap twice the height at one end read as the page having stopped short. The last thing on a
       page carries a margin of its own for whatever follows it; app.css drops it here, where
       nothing does. */
    padding: 1.5rem 1.75rem;
    width: 100%;
}

footer[b-r12ijds563] {
    align-items: center;
    background: var(--sunk);
    border-top: 1px solid var(--rule);
    color: var(--ink-soft);
    display: flex;
    flex-wrap: wrap;
    font-size: var(--text-sm);
    gap: 1rem 1.5rem;
    justify-content: space-between;
    padding-block: 1rem;
    padding-inline: max(1.5rem, calc((100% - var(--page-width)) / 2 + 1.75rem));
}

    footer .footer-left[b-r12ijds563] {
        align-items: center;
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem;
    }

    /* The dot between the copyright and the link after it, faint because it separates rather than
       says anything. */
    footer .footer-separator[b-r12ijds563] {
        color: var(--ink-faint);
    }

    footer .footer-links[b-r12ijds563] {
        align-items: center;
        display: flex;
        flex-wrap: wrap;
        gap: 0.5rem 0.75rem;
    }

    footer .footer-link[b-r12ijds563] {
        align-items: center;
        color: var(--ink-soft);
        display: inline-flex;
        gap: 0.4rem;
        text-decoration: none;
    }

    footer .footer-link:hover[b-r12ijds563] {
        color: var(--accent);
        text-decoration: underline;
    }

    footer .footer-icon[b-r12ijds563] {
        flex: none;
        height: 1.1em;
        width: 1.1em;
    }

@media (max-width: 60rem) {
    main[b-r12ijds563] {
        padding: 1.25rem 1rem 2rem;
    }

    /* Kept level with the column's narrow padding, so the two do not step apart at the one width
       where the misalignment would be most obvious. */
    header[b-r12ijds563],
    footer[b-r12ijds563] {
        padding-inline: 1rem;
    }

    /* Narrow enough that the bar is worth folding, and folded the way the website folds its own:
       the control at the far end of the brand's line, and what it holds a list across the whole
       width under it, a row per place, with what a heading holds opening in the list under that
       heading rather than as a sheet hung from it. The sheets were made for a bar laid out
       across; stacked down the right edge they opened over one another and past the window, where
       nothing in them could be read or reached. Still in the page's flow rather than laid over it:
       the fold is rendered open, so a reader with no script would otherwise arrive to find the
       page behind a menu.

       The fold has to take the bar's whole width to be a list across it, and the control is inside
       it, so the control is lifted out onto the brand's line, level with the brand. */
    header[b-r12ijds563] {
        min-height: calc(var(--text-xl) * 2.25);
        position: relative;
        row-gap: 0;
    }

    .bar-menu[b-r12ijds563] {
        flex-basis: 100%;
    }

    .bar-fold[b-r12ijds563] {
        align-items: center;
        cursor: pointer;
        display: flex;
        height: calc(var(--text-xl) * 2.25);
        /* The browser's own marker is a triangle this application does not draw. The bar's section
           headings take theirs off the same way. */
        list-style: none;
        padding: 0 0.25rem;
        position: absolute;
        right: 1rem;
        top: 0.75rem;
    }

    .bar-fold[b-r12ijds563]::-webkit-details-marker {
        display: none;
    }

    .bar-fold .glyph[b-r12ijds563] {
        height: 1.25rem;
        width: 1.25rem;
    }

    /* Ruled off from the brand's line, as the website's is. With no brand the fold is the bar's
       first line, so the list starts under the control instead of beside it. */
    .bar-menu-content[b-r12ijds563] {
        align-items: stretch;
        border-top: 1px solid var(--rule);
        flex-direction: column;
        gap: 0;
        margin-top: 0.75rem;
        padding-top: 0.5rem;
    }

    .bar-menu:first-child .bar-menu-content[b-r12ijds563] {
        margin-top: calc(var(--text-xl) * 2.25 + 0.5rem);
    }

        .bar-menu-content nav[b-r12ijds563] {
            align-items: stretch;
            flex-direction: column;
            gap: 0;
        }

        /* Every place a row of its own, the width of the list, so each is a target a thumb can find
           rather than a word. */
        .bar-menu-content[b-r12ijds563]  a,
        .bar-menu-content summary[b-r12ijds563],
        .bar-menu-content .operator form[b-r12ijds563],
        .bar-menu-content .operator button[b-r12ijds563] {
            box-sizing: border-box;
            display: flex;
            padding: 0.5rem 0.25rem;
            width: 100%;
        }

        .bar-menu-content .operator form[b-r12ijds563] {
            padding: 0;
        }

        /* The caret rides the far edge of its row, as on a list of rows. */
        .bar-menu-content .menu summary[b-r12ijds563]::after {
            margin-left: auto;
        }

        /* The line between the places to go and the service being read is drawn across the list
           rather than down it: a rule between two rows, which is what it now divides. */
        .bar-menu-content nav .separator[b-r12ijds563] {
            align-self: stretch;
            border-left: 0;
            border-top: 1px solid var(--rule);
            height: 0;
            margin-block: 0.25rem;
        }

        /* The operator's own is the last of the list rather than pushed to the bar's far end. */
        .bar-menu-content .operator[b-r12ijds563] {
            margin-left: 0;
        }

        /* A visitor's two links are two rows of the list, like every other place in it. */
        .bar-menu-content .operator.visitor[b-r12ijds563] {
            flex-direction: column;
            gap: 0;
        }

        /* What a heading holds, opened in the list itself and set in under it. */
        .bar-menu-content .menu .submenu[b-r12ijds563] {
            background: none;
            border: 0;
            gap: 0;
            min-width: 0;
            padding: 0 0 0 1.25rem;
            position: static;
        }

        .bar-menu-content .menu .submenu-group[b-r12ijds563] {
            gap: 0;
        }

        .bar-menu-content .menu .submenu-label[b-r12ijds563] {
            padding: 0.5rem 0.25rem 0.25rem;
        }
}

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

    #blazor-error-ui .dismiss[b-r12ijds563] {
        cursor: pointer;
        position: absolute;
        right: 0.75rem;
        top: 0.5rem;
    }
/* /Components/Layout/ReconnectModal.razor.rz.scp.css */
.components-reconnect-first-attempt-visible[b-9rskkytcyj],
.components-reconnect-repeated-attempt-visible[b-9rskkytcyj],
.components-reconnect-failed-visible[b-9rskkytcyj],
.components-pause-visible[b-9rskkytcyj],
.components-resume-failed-visible[b-9rskkytcyj],
.components-rejoining-animation[b-9rskkytcyj] {
    display: none;
}

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


#components-reconnect-modal[b-9rskkytcyj] {
    background-color: var(--surface);
    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-9rskkytcyj 0.5s both;
    &[open]

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

}

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

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

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

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

    100% {
        opacity: 1;
    }
}

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

    100% {
        opacity: 0;
    }
}

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

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

/* font: inherit because a button does not take the page's face or size on its own — without it
   this was the one control in the application still set in the browser's 13.333px default. */
#components-reconnect-modal button[b-9rskkytcyj] {
    border: 0;
    background-color: var(--accent);
    color: var(--on-fill);
    font: inherit;
    font-size: var(--text-md);
    font-weight: 600;
    padding: 0.35rem 1.5rem;
    border-radius: 4px;
}

    #components-reconnect-modal button:hover[b-9rskkytcyj] {
        background-color: var(--accent-strong);
    }

    #components-reconnect-modal button:active[b-9rskkytcyj] {
        background-color: var(--accent);
    }

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

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

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

@keyframes components-rejoining-animation-b-9rskkytcyj {
    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/Layout/SignInLayout.razor.rz.scp.css */
/* The window's middle, for the brand, the form under it and the copyright line under that: the
   body is already a column the height of the window, and this takes all of it. */
.sign-in[b-pq9e3btuvd] {
    align-items: center;
    box-sizing: border-box;
    display: flex;
    flex: 1;
    flex-direction: column;
    gap: 1.5rem;
    justify-content: center;
    padding: 2rem 1rem;
    width: 100%;
}

/* The brand as the header draws it, a size up: the mark in ems so it follows the word beside it,
   larger than the word because the drawing keeps a margin inside its square, and capped so a wide
   logo of their own keeps its proportions without running across the window. */
.sign-in-brand[b-pq9e3btuvd] {
    align-items: center;
    color: var(--ink);
    display: flex;
    font-size: 1.75rem;
    font-weight: 600;
    gap: 0.6rem;
}

    .sign-in-brand .mark[b-pq9e3btuvd] {
        flex: none;
        height: 2.25em;
        max-width: 6em;
        object-fit: contain;
        width: auto;
    }

/* Setting up says what it is making, over the form and as wide as it, centred like the rest; signing
   in keeps its heading for a screen reader alone. */
.sign-in[b-pq9e3btuvd]  h1,
.sign-in[b-pq9e3btuvd]  .lede {
    max-width: 24rem;
    text-align: center;
    width: 100%;
}

.sign-in[b-pq9e3btuvd]  h1 {
    margin: 0;
}

.sign-in[b-pq9e3btuvd]  .lede {
    margin: 0;
}

/* The form and its answer narrower than on the pages behind it: two fields, read in the middle. */
.sign-in[b-pq9e3btuvd]  .card-form,
.sign-in[b-pq9e3btuvd]  .notice,
.sign-in[b-pq9e3btuvd]  .alert {
    max-width: 24rem;
    width: 100%;
}

.sign-in[b-pq9e3btuvd]  :is(.notice, .alert) {
    margin-top: 0;
}

/* The footer's line, said the way the footer says it, under the form and centred with it; the icons
   on a line of their own under it, a little apart, and pulled up to it rather than set a whole gap
   down, so the two read as one foot. */
.sign-in-copyright[b-pq9e3btuvd],
.sign-in-links[b-pq9e3btuvd] {
    color: var(--ink-soft);
    font-size: var(--text-sm);
    margin: 0;
    text-align: center;
}

.sign-in-links[b-pq9e3btuvd] {
    display: flex;
    gap: 0.5rem;
    justify-content: center;
    margin-top: -0.75rem;
}

    /* As the footer's icons are: quiet until pointed at. */
    .sign-in-links a[b-pq9e3btuvd] {
        color: inherit;
        display: inline-flex;
    }

        .sign-in-links a:hover[b-pq9e3btuvd] {
            color: var(--accent);
        }

    .sign-in-links .icon[b-pq9e3btuvd] {
        height: 1.1em;
        width: 1.1em;
    }
/* /Components/Pages/About.razor.rz.scp.css */
/* The headings, at the size the home page names each model at: a heading over a card or a row of
   tiles rather than a page's own title. Each stands off from the section above it by the space
   that section leaves under itself, so the headings need no room of their own. */
h2[b-ekljjqpthx] {
    font-size: var(--text-xl);
    font-weight: 600;
    margin: 0 0 0.75rem;
}

/* A row of tiles with a section after it leaves the space the card leaves under itself, so every
   heading on the page stands the same distance from what is above it. The shared stylesheet gives
   tiles no margin, because elsewhere they end the page. */
.tiles:not(:last-child)[b-ekljjqpthx] {
    margin-bottom: 1.5rem;
}

/* The card runs to the width of the tiles under it, so the two sections read as one column rather
   than a wide card over a narrower row. The tiles cap their own width in the shared stylesheet;
   this is the same number, said here because the Info tabs the card is borrowed from have nothing
   under them to line up with. */
.tab-panel .facts[b-ekljjqpthx] {
    max-width: 40rem;
}

/* The page's title: the tool's mark beside its name, drawn the way the header draws the pair, and
   larger than the title because the drawing keeps a margin inside its square: at the title's own
   height the lens read as a dot beside it. */
.product[b-ekljjqpthx] {
    align-items: center;
    display: flex;
    gap: 0.6rem;
}

.product-mark[b-ekljjqpthx] {
    flex: none;
    height: 2.2em;
    width: auto;
}
/* /Components/Pages/Admin/Settings.razor.rz.scp.css */
/* The installed archives, read in the same table the stored data is read in: .grid and the card it
   draws itself into are in wwwroot/app.css, and all that is left here is what this table holds that
   the others do not. Declared fixed like the log's and the snapshots', so the columns keep their
   proportions however long a file name is; the file takes the room, because it is the only column
   whose width is not known in advance. */
.grid.archives[b-9bc1038gnp] {
    table-layout: fixed;
}

    /* On a phone the proportions above are what break it. A fifth of 300px is a column that sets
       Sample Service down it two letters at a time, and a tenth holds "50 KB" one character to a
       line. Down here the table is inside its scroller, so it no longer has to fit: the columns are
       as wide as their words, nothing breaks in the middle of one, and a reader moves the table to
       reach the rest of the row. The size is short and meaningless split, so it stays on its line;
       the date may break at its space, which is where a date and a time part anyway. */
    @media (max-width: 40rem) {
        .grid.archives[b-9bc1038gnp] {
            table-layout: auto;
        }

            .grid.archives td[b-9bc1038gnp] {
                overflow-wrap: normal;
            }

            .grid.archives td:nth-child(2)[b-9bc1038gnp] {
                white-space: nowrap;
            }
    }

    .grid.archives .col-file[b-9bc1038gnp] {
        width: 34%;
    }

    .grid.archives .col-size[b-9bc1038gnp] {
        width: 10%;
    }

    .grid.archives .col-uploaded[b-9bc1038gnp] {
        width: 26%;
    }

    /* The services the manifest declares, by name: what the row is about, said in the row. */
    .grid.archives .col-services[b-9bc1038gnp] {
        width: 20%;
    }

    /* Two marks now — the manifest and the bin — so the column takes what the file gives up. */
    .grid.archives .col-actions[b-9bc1038gnp] {
        width: 10%;
    }

    /* A name somebody chose and uploaded, not something the store generated, so it keeps the page's
       voice — the same exception the instance lists make for the names in them. */
    .grid.archives .name[b-9bc1038gnp] {
        font-family: var(--font);
    }

    /* The services are names too, chosen by whoever wrote the manifest. */
    .grid.archives .services[b-9bc1038gnp] {
        font-family: var(--font);
    }

    /* One service to a line, each the way into its own sheet and nothing else in the row a link:
       no markers, since the mark in front of each name is what says it is a place to go. */
    .grid.archives .service-links[b-9bc1038gnp] {
        list-style: none;
        margin: 0;
        padding: 0;
    }

        .grid.archives .service-links li + li[b-9bc1038gnp] {
            margin-top: 0.25rem;
        }

        .grid.archives .service-link[b-9bc1038gnp] {
            align-items: center;
            color: var(--ink);
            display: inline-flex;
            gap: 0.4rem;
            text-decoration: none;
        }

            .grid.archives .service-link:hover[b-9bc1038gnp] {
                color: var(--accent);
            }

            /* The mark, at the weight the tiles hold theirs at, and in the soft ink until the
               name beside it is gone near. Reached with ::deep because SectionMark draws it. */
            .grid.archives .service-link[b-9bc1038gnp]  .glyph {
                color: var(--ink-faint);
                flex: none;
                height: 1.05rem;
                width: 1.05rem;
            }

            .grid.archives .service-link:hover[b-9bc1038gnp]  .glyph {
                color: var(--accent);
            }

    /* Why an archive declares nothing, where its services would be: the page's own words, in the
       soft ink, since something is missing rather than wrong. */
    .grid.archives .services .none[b-9bc1038gnp] {
        color: var(--ink-soft);
        font-size: var(--text-sm);
    }

    /* The mark on an archive that declares nothing, beside its name so it is not mistaken for one
       that is installed: the sheet says why. Set the way the site marks a retired type — a small
       word in a soft box — rather than as an alert, since nothing failed; something is missing. */
    .grid.archives .flag[b-9bc1038gnp] {
        background: var(--sunk);
        border: 1px solid var(--rule);
        border-radius: 0.25rem;
        color: var(--ink-soft);
        font-size: var(--text-sm);
        margin-left: 0.5rem;
        padding: 0.05rem 0.4rem;
        vertical-align: middle;
        white-space: nowrap;
    }

    /* The row's controls, held at the end of the row they act on — the manifest to read, then the
       bin — each at its own size inside the padding an ordinary cell has, and a little apart so
       going near one is not going near the other. */
    .grid.archives td.actions[b-9bc1038gnp] {
        text-align: right;
        white-space: nowrap;
    }

        .grid.archives td.actions .icon-link[b-9bc1038gnp] {
            color: var(--ink-soft);
            display: inline-flex;
            padding: 0.25rem;
            /* Centred on the line rather than stood on the baseline: the two marks are not the
               same height — the page is drawn at 1.2em in a 20-unit box, the bin at 1em in a
               16-unit one, and the bin carries a border besides — and boxes of two heights set on
               their bottoms put one mark higher than the other. */
            vertical-align: middle;
        }

            .grid.archives td.actions .icon-link:hover[b-9bc1038gnp] {
                color: var(--accent);
            }

            .grid.archives td.actions .icon-link + .icon-link[b-9bc1038gnp] {
                margin-left: 0.25rem;
            }

/* The space under the pair, which the tables used to carry themselves. Moved up here because a
   table's own bottom margin is measured below each of them — which is right when they are stacked
   down a page and doubles the row gap when the grid drops to one column under 40rem. */
.models[b-9bc1038gnp] {
    margin-bottom: 1.5rem;
}

    .model .grid[b-9bc1038gnp] {
        margin-bottom: 0;
    }

/* What each model registered, a table to a column. The widths are declared on the columns rather
   than taken from the first row, because the first row is the model's name spanning both of them
   and there is nothing there for a fixed layout to measure — and declared at all so the two tables
   split their width identically and the rows can be read across from one to the other. Each table
   takes the whole of its column: what stops a count drifting away from the name it counts is the
   width of the pair, set once on .models, and not a second measure here. */
.grid.registered[b-9bc1038gnp] {
    table-layout: fixed;
}

    .grid.registered .col-kind[b-9bc1038gnp] {
        width: 68%;
    }

    .grid.registered .col-count[b-9bc1038gnp] {
        width: 32%;
    }

    /* What is counted, named as the site names it elsewhere rather than as a stored value: these
       are the page's own words for the six kinds of thing, not something read out of a store. */
    .grid.registered .name[b-9bc1038gnp] {
        font-family: var(--font);
    }

        /* The mark for what the row counts, in front of the name and out of the way of it: the same
           drawing as the tile that leads there, at the weight the tiles hold theirs at. Set on the
           baseline by hand — a glyph this size sits low against a line of text left to itself.
           Inline, because a cell that is laid out as a flex container stops being a table cell and
           the row loses the padding and the rules that the rest of the table is drawn with.

           Reached with ::deep because the mark is drawn by SectionMark and not by this page: a
           scoped rule puts the page's attribute on the last element it names, and that element
           belongs to the other component and never carries it. Without this the rule matches
           nothing at all, and does so silently. */
        .grid.registered[b-9bc1038gnp]  .glyph {
            color: var(--ink-faint);
            height: 1.15rem;
            margin-right: 0.5rem;
            vertical-align: -0.28em;
            width: 1.15rem;
        }

    /* The counts down the right-hand edge, so the two columns can be compared without reading the
       labels again. */
    .grid.registered .count[b-9bc1038gnp] {
        text-align: right;
    }

/* Each tab ends with its button and, under it, what the last press did. The gap is the same on both
   so the answer reads as belonging to the button above it rather than floating at the foot of the
   panel — and it is written here rather than in app.css because it is this pairing, not the button
   row itself, that wants the tighter space. */
.actions-row[b-9bc1038gnp],
.refresh[b-9bc1038gnp] {
    margin-bottom: 1rem;
}

.actions-row[b-9bc1038gnp] {
    margin-top: 0;
}

/* Nothing installed yet is said in the space the table would have filled, and is given the space
   under it the table would have had. Without it the button row, which sets no space above so as
   to sit close under the table's own margin, lands flush on the dashed box as if it were part of
   it — on both tabs, since the refresh form sets none above either. */
.empty[b-9bc1038gnp] {
    margin-bottom: 1.5rem;
}

/* The line at the foot of both type-changing panels, saying who else a change there reaches. Set
   smaller and in italic to read as a footnote to the panel rather than another thing in it — the
   panel is done by the time this is reached, and it is a condition on what was just done rather
   than a step in doing it. Given the room above that the notice it follows does not need. */
.shared[b-9bc1038gnp] {
    color: var(--ink-soft);
    font-size: var(--text-sm);
    font-style: italic;
    margin: 1.5rem 0 0;
    max-width: 44rem;
}

/* The upload form, brought up over the page rather than sitting on it. */
.dialog[b-9bc1038gnp] {
    border: 1px solid var(--rule);
    /* The width below is the whole box, padding and border included. Measured the default way it
       was the content alone, so the box came out fifty pixels wider than the window minus its
       gutters: on a phone it could not be centred, sat hard against the left edge and ran the
       Cancel side off the right — opened by a tap exactly as much as by the address. The 32rem
       measure counts the same way, so the dialog is that wide on a monitor, padding and all. */
    box-sizing: border-box;
    border-radius: 8px;
    box-shadow: 0 10px 30px rgb(var(--shadow-rgb) / 0.18);
    color: var(--ink);
    max-width: 32rem;
    padding: 1.25rem 1.5rem 1.5rem;
    width: calc(100% - 2rem);
}

    /* Pinned to the middle of the window however the dialog was opened.

       Opened by a script, it is modal, and a modal dialog is fixed to the window by the browser's
       own rule. But app.css gives every .dialog a relative position, for the overlay's sheet, and an
       author's rule outweighs the browser's: a modal positioned any other way is laid out against
       the top of the document, which is out of sight on a page scrolled down.

       Open because the address says so, with no script to have made it modal — the no-script path,
       and where a reload, a bookmark or the back button lands after one of these links — it is
       laid out where it stands, and neither stands anywhere useful: the upload form pushes the
       panel around from inside the section, and the remove question is laid out inside the cell of
       the row it asks about, which is a column a few characters wide — so it hung off the right of
       the window and the page grew a sideways scrollbar to reach it.

       The same three declarations the user agent applies to dialog:modal, for both, so the dialog
       lands in the same place whichever way it was opened, and the only difference left between
       the two is the veil behind. */
    dialog.dialog[b-9bc1038gnp] {
        inset: 0;
        margin: auto;
        position: fixed;
    }

    .dialog[b-9bc1038gnp]::backdrop {
        background: rgb(var(--shadow-rgb) / 0.35);
    }

    .dialog h2[b-9bc1038gnp] {
        margin: 0 0 0.75rem;
    }

    /* Inside the dialog the border would be a second frame around the first. */
    .dialog .upload[b-9bc1038gnp] {
        border: none;
        margin: 0;
        max-width: none;
        padding: 0;
    }

.dialog-actions[b-9bc1038gnp] {
    display: flex;
    gap: 0.75rem;
    margin-top: 0.5rem;
}

.dialog p[b-9bc1038gnp] {
    color: var(--ink-soft);
    margin: 0 0 1rem;
}

/* The row's own dialog sits in a cell; it must not read as one. Both of these undo something the
   cell sets on its contents — the column of bins is set to the right and kept on one line — and
   both are inherited down the page rather than taken from where the dialog is drawn, so they still
   reach it once it is pinned to the window above. Its width is not among them any more: a fixed
   box measures a percentage against the window, which is what that rule was reaching for. */
.grid.archives td.actions .dialog[b-9bc1038gnp] {
    text-align: left;
    white-space: normal;
}

/* The branding fields, in one card drawn the way the Types tab draws its two tables: the surface,
   the rule and the shadow of the stored-data card, and each field under a band in the tint and the
   small capitals a table's header row is set in. The button sits the Types pair's gap below it, and
   the whole is held to a measure so a name field does not run the width of a wide screen. */
.branding[b-9bc1038gnp],
.caching-settings[b-9bc1038gnp] {
    display: flex;
    flex-direction: column;
    gap: 1.5rem;
    max-width: 40rem;
}

.branding input[type="text"][b-9bc1038gnp],
.caching-settings input[type="number"][b-9bc1038gnp] {
    background: var(--surface);
    border: 1px solid var(--field-rule);
    border-radius: 4px;
    color: var(--ink);
    font: inherit;
    font-size: var(--text-md);
    padding: 0.5rem 0.625rem;
}

    .branding input[type="text"]:focus-visible[b-9bc1038gnp],
    .caching-settings input[type="number"]:focus-visible[b-9bc1038gnp] {
        border-color: var(--accent);
        box-shadow: 0 0 0 3px rgb(var(--accent-rgb) / 0.18);
        outline: none;
    }

/* The three logo choices, one to a line, each drawn as the header would draw it so the choice is
   made by looking. Their own keeps its file input on the same line, wrapping under on a narrow
   screen. */
.logo-option[b-9bc1038gnp] {
    align-items: center;
    display: flex;
    flex-wrap: wrap;
    gap: 0.6rem;
    min-height: 2rem;
}

    label.logo-option[b-9bc1038gnp] {
        cursor: pointer;
    }

    .logo-option input[type="radio"][b-9bc1038gnp] {
        accent-color: var(--accent);
        margin: 0;
    }

    /* Their own name, typed on the line of the choice it belongs to and taking what is left of it. */
    .logo-option input[type="text"][b-9bc1038gnp] {
        flex: 1;
        min-width: 12rem;
    }

.brand-preview[b-9bc1038gnp] {
    height: 2rem;
    max-width: 8rem;
    object-fit: contain;
}

/* Under the card rather than in it, and with no space of its own above: the column's gap already
   sets it apart. */
.branding .actions-row[b-9bc1038gnp],
.caching-settings .actions-row[b-9bc1038gnp] {
    margin: 0;
}

/* What the last save did, as far below the button or the restore row above it as the button is
   below the card, so the tab keeps one rhythm down its length — and as wide as the card, edge
   for edge, so it reads as that form's answer. Counted with its padding and edge inside the
   width, since the card's outer edge is what it lines up with. */
.branding-panel[b-9bc1038gnp]  .notice,
.branding-panel[b-9bc1038gnp]  .alert,
.caching-panel[b-9bc1038gnp]  .notice,
.caching-panel[b-9bc1038gnp]  .alert {
    box-sizing: border-box;
    margin-top: 1.5rem;
    max-width: 40rem;
}

/* How long Home keeps a count: a number a few digits wide with its unit after it on the same line,
   the way it is said aloud. */
.caching-settings .minutes[b-9bc1038gnp] {
    align-items: center;
    display: flex;
    gap: 0.6rem;
}

    .caching-settings .minutes input[type="number"][b-9bc1038gnp] {
        width: 6rem;
    }
/* /Components/Pages/Preferences.razor.rz.scp.css */
/* This browser's own settings, in the card the data pages read their rows in. Painted here
   rather than borrowed from app.css: the run of pieces that draws a card there is a run of tables
   and the controls around them, joined by being adjacent, and this is one block that is none of
   those. It is the same three tokens the tiles on the home page use to paint theirs.

   Uncapped, like the tables it is standing in for: a card that stopped short of the ones in the
   data pages would read as a different kind of thing rather than the same card holding a
   different kind of row. The sentence under each setting keeps its own measure below. */
.preferences[b-pjfj71m0jp] {
    background: var(--surface);
    border: 1px solid var(--rule);
    border-radius: 8px;
    box-shadow: var(--shadow-card);
    margin-bottom: 1.5rem;
}

    /* A row, at the padding and under the rule .grid gives a table cell, so a setting and a stored
       value sit the same distance off the same edge. Taller than a cell top and bottom because a
       row here is two lines rather than one, and the sentence would otherwise crowd the row under
       it as closely as it sits under its own control. */
    .preference[b-pjfj71m0jp] {
        border-bottom: 1px solid var(--rule);
        color: var(--ink-soft);
        font-size: var(--text-md);
        padding: 0.75rem 1rem;
    }

        /* The last row's rule and the card's bottom edge are the same line drawn twice. */
        .preference:last-child[b-pjfj71m0jp] {
            border-bottom: 0;
        }

        /* The control beside the name that says what it sets, not held off at the far end of the
           row: the gap is the one the picker under a table already puts between its own label and
           select, so the pair reads as one control wherever it is met. */
        .preference .control[b-pjfj71m0jp] {
            align-items: center;
            display: flex;
            gap: 0.5rem;
        }

        /* What is being set, in the page's ink: the sentence under it is the soft one, and a label
           the same weight as its own explanation reads as two lines of explanation. */
        .preference label[b-pjfj71m0jp] {
            color: var(--ink);
        }

        /* Every select on the card, drawn the way the picker under a table is drawn: one of them is
           that picker, and the theme beside it is the same kind of choice made the same way. The
           rows-per-page row carries .page-size and would be drawn by that rule alone; this says the
           same thing for the rest, so a select added here does not arrive as a native control. */
        .preference select[b-pjfj71m0jp] {
            background: var(--surface);
            border: 1px solid var(--field-rule);
            border-radius: 4px;
            color: var(--ink);
            font: inherit;
            padding: 0.3rem 0.4rem;
        }

        .preference select:focus-visible[b-pjfj71m0jp] {
            border-color: var(--accent);
            box-shadow: 0 0 0 3px rgb(var(--accent-rgb) / 0.18);
            outline: none;
        }

        /* Sized and coloured, because a checkbox left alone is drawn by the operating system and
           arrives in whatever blue that machine happens to use — the one control on the page that
           would not be in the site's own colour. */
        .preference input[type="checkbox"][b-pjfj71m0jp] {
            accent-color: var(--accent);
            flex: none;
            height: 1rem;
            margin: 0;
            width: 1rem;
        }

        /* What the setting does, under it rather than beside it: it is a sentence, and a sentence
           in the second column would be a column of prose against a column of controls. */
        .preference .hint[b-pjfj71m0jp] {
            margin: 0.3rem 0 0;
            max-width: 42rem;
        }

/* On a narrow window the box goes in front of its name.
   ----------------------------------------------------------------------------------------------
   Across, the name fits on one line and the box sits straight after it, where the pickers above
   sit after theirs. Down here the name wraps, and a wrapped label fills the row, so the box was
   pushed to the far right, apart from every other control on the card. In front of the name it
   starts at the left edge the rest of the page's controls start at on a phone.

   Moved by order, not in the markup: the label still comes first to be read out, and it is the
   label's own control either way. Held against the name's first line rather than centred on the
   two, so it reads as the start of the sentence it answers. */
@media (max-width: 40rem) {
    .preference input[type="checkbox"][b-pjfj71m0jp] {
        align-self: flex-start;
        /* The box is shorter than a line of the label. This drops it to that line's middle — set by
           measuring the two against each other, not worked out from the font. */
        margin-top: 0.07rem;
        order: -1;
    }
}

/* /Components/Pages/ServiceHome.razor.rz.scp.css */
/* Only what is particular to this page: here each model's heading is the way into it. The
   two-column layout, the palette tokens and the section-list furniture live in wwwroot/app.css,
   because the settings page sets the two models beside each other too. */

.model h2 a[b-3k1r73k4mr] {
    color: var(--ink);
    text-decoration: none;
}

    .model h2 a:hover[b-3k1r73k4mr] {
        text-decoration: underline;
    }
/* /Components/Shared/ServiceDialog.razor.rz.scp.css */
/* The row of views, set a little under the header rather than flush against it: the other sheets
   carry a line naming the row between the two, and this one has nothing to put there but space. */
.dialog-body .tabs[b-5aypakdd2h] {
    margin-top: 1rem;
}

/* A sentence the manifest wrote rather than a value the store did, so it is read in the page's
   face like the rest of the prose here — and the sheet's own sentences about the store, which
   StoreFacts draws: reached with ::deep, since scoped styles stop at a child component's markup. */
.facts dd.prose[b-5aypakdd2h],
.facts[b-5aypakdd2h]  dd.prose {
    font-family: var(--font);
}

/* What the configuration says about a name, beside the name: the sheet's own words, in the page's
   face, and softer than the name they are about. Spaced here rather than by the space in the
   markup, the way the facts card sets a note beside a value. */
.facts dd .state[b-5aypakdd2h] {
    color: var(--ink-soft);
    font-family: var(--font);
    margin-left: 0.5rem;
}

/* Three lists, each stepped in under the thing it belongs to and none of them bulleted: the indent
   already says what is under what, and a bullet in a sheet of names reads as a mark rather than as
   a list. The assembly and the types are stored data, set in the face every stored value here is
   read in; the kind between them is the sheet's own word, like the labels the Types tab counts
   under, and is set in the page's face and in the soft ink so the types stay the ones being listed. */
.assemblies[b-5aypakdd2h],
.kinds[b-5aypakdd2h],
.types[b-5aypakdd2h] {
    list-style: none;
    margin: 0;
    padding: 0;
}

.assemblies[b-5aypakdd2h] {
    font-family: var(--mono);
    font-size: var(--text-md);
    overflow-wrap: anywhere;
}

    .assemblies > li + li[b-5aypakdd2h] {
        margin-top: 0.75rem;
    }

.kinds[b-5aypakdd2h],
.types[b-5aypakdd2h] {
    padding-left: 1.25rem;
}

.kind[b-5aypakdd2h] {
    color: var(--ink-soft);
    font-family: var(--font);
}

/* The sentence for a file that registered nothing, under that file's name and stepped in where
   its list of kinds would start; and for what the archive also holds — so whichever answer is
   given, it is read in the same weight. */
.none[b-5aypakdd2h] {
    color: var(--ink-soft);
    font-family: var(--font);
    font-size: var(--text-md);
    margin: 0;
    padding-top: 1rem;
}

    .assemblies .none[b-5aypakdd2h] {
        padding-left: 1.25rem;
        padding-top: 0;
    }
