/*
 * File Share - main stylesheet
 * The palette is the one of the TechCraft portal: burnt orange accent on a
 * very dark, warm grey background, one radius for everything.
 *
 * Organisation
 *   1. Design tokens         12. Dropdowns and modals
 *   2. Reset and base        13. Administration
 *   3. Utilities             14. Sign in and error pages
 *   4. Header                15. Page progress bar
 *   5. Layout and panels     16. Permissions and storages
 *   6. Buttons               17. Responsive and accessibility
 *   7. Forms                 18. Storages and files pages
 *   8. Pagination            19. Size of a storage
 *   9. Notices and flashes   20. Account
 *  10. Badges and chips      21. Storages administration
 *  11. Tables
 *
 * The sections from 18 on were added screen by screen, below the responsive
 * rules, so each of them carries the narrow layouts of its own.
 *
 * The listing of a storage itself - the breadcrumbs, the rows of the files,
 * the uploads, the menu of a file and the viewer of pictures and films -
 * lives in files.css.
 */

/* --------------------------------------------------------- Design tokens */

:root {
    --accent: #e34f0e;
    --accent-dark: #ce480e;
    --accent-soft: rgba(227, 79, 14, 0.14);
    --accent-faint: rgba(227, 79, 14, 0.07);
    --danger: #e2212f;
    --danger-dark: #b71824;
    --ok: #3ba55d;
    --warn: #d99e2b;

    --bg: #131211;
    --bg-alt: #111111;
    --panel: #1a1917;
    --panel-alt: #201f1c;
    --panel-hover: #262421;

    --text: #b9b8b8;
    --text-strong: #e6e5e3;
    --text-dim: #9a9791;

    --border: rgba(255, 255, 255, 0.11);
    --border-strong: rgba(255, 255, 255, 0.2);

    --radius: 6px;
    --shadow: 0 6px 22px rgba(0, 0, 0, 0.45);
    --shadow-soft: 0 2px 10px rgba(0, 0, 0, 0.3);

    --header-height: 58px;
    --content-width: 1560px;

    --font: "Raleway", "Segoe UI", system-ui, -apple-system, Arial, sans-serif;
    --mono: "JetBrains Mono", "Cascadia Mono", "Courier New", monospace;

    color-scheme: dark;
    accent-color: var(--accent);
}

/* ---------------------------------------------------------- Reset and base */

*,
*::before,
*::after {
    box-sizing: border-box;
}

html {
    -webkit-text-size-adjust: 100%;
    overflow-x: clip;
}

body {
    margin: 0;
    min-height: 100vh;
    min-height: 100dvh;
    display: flex;
    flex-direction: column;
    background: var(--bg);
    color: var(--text);
    font-family: var(--font);
    font-size: 15px;
    font-weight: 400;
    line-height: 1.6;
    letter-spacing: 0.01em;
    overflow-x: clip;
}

img {
    max-width: 100%;
    height: auto;
}

/*
 * Scrollbars in the colours of the share: a thin dark thumb on no track at
 * all, which lightens under the pointer. The standard properties serve
 * Firefox and a current Chrome; the prefixed rules serve Safari.
 */
* {
    scrollbar-width: thin;
    scrollbar-color: #37332f transparent;
}

*:hover {
    scrollbar-color: #4a4540 transparent;
}

::-webkit-scrollbar {
    width: 10px;
    height: 10px;
}

::-webkit-scrollbar-track,
::-webkit-scrollbar-corner {
    background: transparent;
}

::-webkit-scrollbar-thumb {
    background: #37332f;
    background-clip: padding-box;
    border: 2px solid transparent;
    border-radius: var(--radius);
}

::-webkit-scrollbar-thumb:hover {
    background-color: #4f4944;
}

[hidden] {
    display: none !important;
}

a {
    color: var(--accent);
    text-decoration: none;
    transition: color 0.2s ease-in-out;
}

a:hover {
    color: var(--accent-dark);
}

h1,
h2,
h3,
h4 {
    margin: 0 0 0.6rem 0;
    color: var(--text-strong);
    font-weight: 600;
    line-height: 1.25;
    letter-spacing: 0.02em;
    overflow-wrap: break-word;
}

h1 {
    font-size: 1.75rem;
}

h2 {
    font-size: 1.3rem;
}

h3 {
    font-size: 1.05rem;
}

p {
    margin: 0 0 1rem 0;
}

code,
pre {
    font-family: var(--mono);
    font-size: 0.88em;
}

code {
    padding: 0.05rem 0.3rem;
    background: rgba(255, 255, 255, 0.05);
    border-radius: 4px;
    color: var(--text-strong);
    overflow-wrap: anywhere;
}

/* ------------------------------------------------------------- Utilities */

.icon {
    width: 1em;
    height: 1em;
    vertical-align: -0.125em;
    flex: none;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.skip-link {
    position: absolute;
    top: -40px;
    left: 1rem;
    z-index: 200;
    padding: 0.5rem 1rem;
    background: var(--accent);
    border-radius: var(--radius);
    color: #fff;
}

.skip-link:focus {
    top: 0.5rem;
}

.nowrap {
    white-space: nowrap;
}

.center {
    text-align: center !important;
}

.is-muted {
    opacity: 0.6;
}

.stack {
    display: flex;
    flex-direction: column;
    gap: 1.25rem;
    min-width: 0;
}

/* ---------------------------------------------------------------- Header */

.site-header {
    position: sticky;
    top: 0;
    z-index: 60;
    display: flex;
    align-items: center;
    gap: 1.1rem;
    height: var(--header-height);
    padding: 0 1.1rem;
    background: rgba(17, 17, 17, 0.97);
    border-bottom: 1px solid var(--border);
    flex: none;
}

.site-header__brand {
    display: flex;
    align-items: center;
    /* No gap of its own: the mark sits in the middle of its picture with
       room around it, and that room is all the distance to the name it
       needs. */
    gap: 0;
    flex: none;
    color: var(--text-strong);
    font-size: 1.08rem;
    font-weight: 700;
    letter-spacing: 0.02em;
    white-space: nowrap;
}

.site-header__brand:hover {
    color: var(--text-strong);
}

.site-header__brand img {
    width: 32px;
    height: 32px;
}

.site-header__name em {
    color: var(--accent);
    font-style: normal;
}

.site-header__actions {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex: none;
    margin-left: auto;
}

.site-header__actions form {
    margin: 0;
}

.header-icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 38px;
    height: 38px;
    flex: none;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text);
    transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.header-icon:hover {
    background: var(--panel-hover);
    border-color: var(--accent);
    color: var(--accent);
}

.header-icon.is-active {
    background: var(--accent-soft);
    border-color: var(--accent);
    color: var(--accent);
}

/*
 * The language chip is the one of the TechCraft portal: the globe, the short
 * code in capitals and a small caret, turning orange while its panel is open.
 */
.language-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    height: 38px;
    padding: 0 0.6rem;
    flex: none;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text);
    font-family: inherit;
    font-size: 0.76rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    cursor: pointer;
    transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.language-chip:hover {
    background: var(--panel-hover);
    border-color: var(--accent);
    color: var(--accent);
}

.language-chip[aria-expanded="true"] {
    border-color: var(--accent);
    color: var(--accent);
}

.language-chip__caret {
    transition: transform 0.18s ease;
}

.language-chip[aria-expanded="true"] .language-chip__caret {
    transform: rotate(180deg);
}

.user-chip {
    display: inline-flex;
    align-items: center;
    gap: 0.45rem;
    height: 38px;
    padding: 0 0.6rem 0 0.35rem;
    background: transparent;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text);
    font-family: inherit;
    font-size: 0.8rem;
    font-weight: 600;
    cursor: pointer;
    transition: background-color 0.18s ease, border-color 0.18s ease, color 0.18s ease;
}

.user-chip:hover,
.user-chip[aria-expanded="true"] {
    background: var(--panel-hover);
    border-color: var(--accent);
    color: var(--text-strong);
}

.user-chip__name {
    max-width: 12rem;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.user-chip__avatar {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 24px;
    height: 24px;
    flex: none;
    background: var(--accent);
    border-radius: 50%;
    color: #fff;
    font-size: 0.72rem;
    font-weight: 700;
}

.user-chip__avatar--large {
    width: 40px;
    height: 40px;
    font-size: 1rem;
}

/*
 * The bottom line of every page, centred like the one of TechCraft: the years
 * the share has run, its name and the rights, with the version as small
 * print. On a narrow screen it breaks into lines of a similar length.
 */
.site-footer {
    display: flex;
    justify-content: center;
    padding: 1.2rem 1.25rem;
    border-top: 1px solid var(--border);
    color: var(--text-dim);
    font-size: 0.8rem;
    text-align: center;
}

.site-footer__copy {
    margin: 0;
    text-wrap: balance;
}

/* Only the weight. The colour is the one every link of the share already has
   - the accent - and the footer used to be the one place which overrode it to
   near white; saying it again here is how the two would drift apart. */
.site-footer__copy a {
    font-weight: 600;
}

/* ---------------------------------------------------------- Layout, panels */

.page {
    flex: 1 0 auto;
    min-width: 0;
}

.wrapper {
    width: 100%;
    max-width: var(--content-width);
    margin: 0 auto;
    padding: 2rem 1.25rem 3rem;
}

.wrapper--narrow {
    max-width: 920px;
}

.page-heading {
    margin-bottom: 1.5rem;
}

.page-heading p {
    margin: 0;
    color: var(--text-dim);
}

.page-heading--actions {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}

.back-link {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    /*
     * The line box of the text is as tall as the text itself, so centring the
     * two really does put the arrow on the middle of the word - with the
     * leading of a paragraph around it, the arrow rides above it.
     */
    line-height: 1;
    margin-bottom: 0.5rem;
    color: var(--text-dim);
    font-size: 0.8rem;
    font-weight: 600;
}

.back-link:hover {
    color: var(--accent);
}

.panel {
    min-width: 0;
    padding: 1.4rem;
    margin-bottom: 1.25rem;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.stack > .panel,
.admin-columns .panel {
    margin-bottom: 0;
}

.panel--flush {
    padding: 0;
    overflow: hidden;
}

.panel--danger {
    border-color: rgba(226, 33, 47, 0.45);
}

.panel__title {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-bottom: 0.9rem;
    font-size: 1.02rem;
}

.panel__title .icon {
    color: inherit;
}

.panel__subtitle {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    margin: 1.2rem 0 0.6rem;
    color: var(--text-dim);
    font-size: 0.78rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.panel__lead {
    margin: -0.4rem 0 1rem;
    color: var(--text-dim);
    font-size: 0.86rem;
}

.panel__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    padding: 1.2rem 1.4rem;
    border-bottom: 1px solid var(--border);
}

.panel__head .panel__title {
    margin-bottom: 0.5rem;
}

/* A heading which only names what is under it needs no line under it. */
.panel__head--plain {
    border-bottom: 0;
    padding-bottom: 0;
}

/* A badge or a button which follows the title of a panel ends its line. */
.panel__title > .badge,
.panel__title > form {
    margin-left: auto;
}

/*
 * The foot of a panel which saves on its own: its own button on the right,
 * and - when that panel was the one refused - what was wrong with it beside
 * the button rather than at the top of a screen full of other panels.
 */
.panel__save {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    flex-wrap: wrap;
    gap: 0.8rem;
    margin-top: 1.2rem;
}

.panel__save .notice {
    margin: 0 auto 0 0;
}

.panel__head .panel__lead {
    margin: 0;
}

/* --------------------------------------------------------------- Buttons */

.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    height: 2.55rem;
    padding: 0 1.1rem;
    border: 0;
    border-radius: var(--radius);
    background: transparent;
    box-shadow: inset 0 0 0 1px var(--text);
    color: var(--text);
    font-family: inherit;
    font-size: 0.78rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    white-space: nowrap;
    cursor: pointer;
    text-decoration: none;
    transition: background-color 0.2s ease, box-shadow 0.2s ease, color 0.2s ease;
}

.button:hover {
    box-shadow: inset 0 0 0 1px var(--accent);
    color: var(--accent);
}

.button:active {
    background: var(--accent-soft);
}

.button--primary {
    background: var(--accent);
    box-shadow: none;
    color: #fff;
}

.button--primary:hover {
    background: var(--accent-dark);
    box-shadow: none;
    color: #fff;
}

.button--danger {
    box-shadow: inset 0 0 0 1px var(--danger);
    color: var(--danger);
}

.button--danger:hover {
    background: var(--danger);
    box-shadow: none;
    color: #fff;
}

.button--ghost {
    box-shadow: none;
    color: var(--text-dim);
}

.button--ghost:hover {
    background: rgba(255, 255, 255, 0.06);
    box-shadow: none;
    color: var(--text-strong);
}

.button--small {
    height: 2.05rem;
    padding: 0 0.75rem;
    font-size: 0.7rem;
}

.button--wide {
    width: 100%;
}

.button--icon {
    min-width: 2.2rem;
    padding: 0 0.55rem;
    flex: none;
}

.button--small.button--icon {
    min-width: 2.05rem;
}

.button.is-active {
    background: var(--accent-soft);
    box-shadow: inset 0 0 0 1px var(--accent);
    color: var(--accent);
}

.button[disabled],
.button.is-disabled {
    opacity: 0.5;
    pointer-events: none;
}

.button.is-busy {
    position: relative;
    color: transparent !important;
    pointer-events: none;
}

.button.is-busy::after {
    content: "";
    position: absolute;
    width: 1rem;
    height: 1rem;
    border: 2px solid currentcolor;
    border-color: #fff transparent #fff transparent;
    border-radius: 50%;
    animation: spin 0.8s linear infinite;
}

@keyframes spin {
    to {
        transform: rotate(360deg);
    }
}

.button-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    min-width: 0;
}

.button-row > form,
.inline-form {
    display: inline-flex;
    margin: 0;
}

.button-row--center {
    justify-content: center;
}

/* ----------------------------------------------------------------- Forms */

form {
    min-width: 0;
}

.form-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.1rem 1.25rem;
}

.form-grid--single {
    grid-template-columns: minmax(0, 1fr);
}

.form-grid > * {
    min-width: 0;
}

.field--full {
    grid-column: 1 / -1;
}

.field {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    min-width: 0;
}

.field + .field {
    margin-top: 0;
}

.panel > .field + .field,
form > .field + .field {
    margin-top: 1rem;
}

.field > label {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    min-height: 1.4rem;
    color: var(--text-strong);
    font-size: 0.74rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.field__hint {
    color: var(--text-dim);
    font-size: 0.78rem;
    font-weight: 400;
    letter-spacing: 0;
    text-transform: none;
}

input[type="text"],
input[type="password"],
input[type="email"],
input[type="search"],
input[type="number"],
input[type="url"],
select,
textarea {
    width: 100%;
    max-width: 100%;
    padding: 0.6rem 0.8rem;
    background: rgba(255, 255, 255, 0.045);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text-strong);
    font-family: inherit;
    font-size: 0.9rem;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

textarea {
    min-height: 6rem;
    resize: vertical;
    line-height: 1.55;
}

input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):focus,
select:focus,
textarea:focus {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 1px var(--accent);
}

/*
 * A field which only shows a value - the username on the account page - keeps
 * the shape of the fields around it and is greyed out, so it reads as part of
 * the form and plainly as nothing to type into.
 */
input:not([type="checkbox"]):not([type="radio"]):disabled,
select:disabled,
textarea:disabled {
    background: rgba(255, 255, 255, 0.02);
    border-style: dashed;
    color: var(--text-dim);
    cursor: not-allowed;
}

input::placeholder,
textarea::placeholder {
    color: var(--text-dim);
}

/*
 * No smaller than the browser's own size under a finger: a phone which
 * finds a smaller field zooms the whole page in to read it, and keeps it
 * zoomed - so a dialog opened afterwards, centred in the page, shows up
 * half off the screen the visitor is looking at.
 */
@media (pointer: coarse) {
    input:not([type="checkbox"]):not([type="radio"]):not([type="file"]),
    select,
    textarea {
        font-size: 1rem;
    }
}

input[type="checkbox"],
input[type="radio"] {
    width: 17px;
    height: 17px;
    margin: 0;
    flex: none;
    cursor: pointer;
}

input:user-invalid {
    border-color: var(--danger);
}

select {
    appearance: none;
    background-image: url("data:image/svg+xml;charset=utf8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' fill='none' stroke='%23b9b8b8' stroke-width='2'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
    background-repeat: no-repeat;
    background-position: right 0.6rem center;
    background-size: 16px;
    padding-right: 2.2rem;
}

select option {
    background-color: var(--panel-alt);
    color: var(--text-strong);
}

.input-group {
    display: flex;
    gap: 0.4rem;
    min-width: 0;
}

.input-group input {
    flex: 1 1 auto;
    min-width: 0;
}

.input-group .button {
    height: auto;
    min-height: 2.45rem;
}

.checkbox {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    padding: 0.35rem 0;
    color: var(--text);
    font-size: 0.9rem;
    cursor: pointer;
}

.checkbox input {
    margin-top: 0.2rem;
}

.checkbox strong {
    color: var(--text-strong);
    font-weight: 600;
}

/* A switch with a second line saying what it does. */
.checkbox__text {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}

.checkbox__text .field__hint {
    line-height: 1.45;
}

.checkbox-list {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    margin-top: 1.1rem;
}

/* Switches side by side, each half of the row - one under the other again where the row is narrow. */
.checkbox-list--row {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 0.35rem 1.25rem;
    align-items: start;
}

@media (max-width: 640px) {
    .checkbox-list--row {
        grid-template-columns: minmax(0, 1fr);
    }
}

.form-grid + .checkbox,
.form-grid + .checkbox-list {
    margin-top: 1rem;
}

.form-actions {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    flex-wrap: wrap;
    margin-top: 1.4rem;
}

.form-actions--end {
    justify-content: flex-end;
}

.password-meter {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    margin-top: 0.45rem;
    font-size: 0.76rem;
    color: var(--text-dim);
}

.password-meter__bar {
    flex: 1 1 auto;
    height: 4px;
    background: rgba(255, 255, 255, 0.08);
    border-radius: 999px;
    overflow: hidden;
}

.password-meter__fill {
    display: block;
    height: 100%;
    width: 0;
    background: var(--danger);
    transition: width 0.2s ease, background-color 0.2s ease;
}

/*
 * The select of the share, the same one the TechCraft portal draws.
 *
 * The native list of a select belongs to the operating system, and a grey
 * system menu in the middle of a dark page is the one part of a form no
 * stylesheet reaches. The real <select> stays in the page, invisible but
 * focused, validated and submitted; a button and a panel of our own are what
 * is drawn over it (see components/select.ts).
 */

.select {
    position: relative;
    display: block;
    min-width: 0;
}

/*
 * Kept in the layout rather than hidden: a control which is `display: none`
 * cannot be focused, and the browser refuses to submit a form whose invalid
 * field it cannot show. It sits exactly under the button, so the message the
 * browser pops up points at the right box.
 *
 * The disabled state is spelled out because the rule which dims every
 * disabled control is written further down the sheet and is exactly as
 * specific as this one - so it won, and a switched-off control showed its
 * own text at half opacity through the button drawn over it.
 */
.select > select,
.select > select:disabled {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    padding: 0;
    border: 0;
    opacity: 0;
    pointer-events: none;
    appearance: none;
}

.select__button {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    width: 100%;
    padding: 0.6rem 0.8rem;
    background: rgba(255, 255, 255, 0.045);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text-strong);
    font-family: inherit;
    font-size: 0.9rem;
    line-height: 1.6;
    text-align: left;
    cursor: pointer;
    transition: border-color 0.2s ease, box-shadow 0.2s ease;
}

.select__button:hover {
    border-color: var(--border-strong);
}

/* The ring belongs to the select, which is the thing actually focused. */
.select > select:focus + .select__button,
.select.is-open .select__button {
    outline: none;
    border-color: var(--accent);
    box-shadow: 0 0 0 1px var(--accent);
}

.select__value {
    flex: 1;
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The option which is not an answer yet reads like a placeholder. */
.select__value.is-placeholder {
    color: var(--text-dim);
}

.select__chevron {
    flex: none;
    color: var(--text-dim);
    transition: transform 0.18s ease;
}

.select.is-open .select__chevron {
    transform: rotate(180deg);
}

.select.is-disabled .select__button {
    opacity: 0.55;
    cursor: not-allowed;
}

/*
 * The list a control drops open.
 *
 * Fixed rather than absolute, and placed by the script against the window.
 * Drawn inside the control it was clipped by anything above it which scrolls
 * - a dialog, a panel with a ceiling of its own - and came out with a slice
 * missing off the bottom. Its position, width and ceiling are written by the
 * script, which is the only thing which knows where the control is.
 */
.select__menu {
    position: fixed;
    z-index: 80;
    display: flex;
    flex-direction: column;
    max-height: 17rem;
    padding: 0.3rem;
    background: var(--panel);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    animation: menu-drop 0.14s ease;
}

/*
 * Opened upwards where the room below has run out. Which way that is comes
 * from the script; this only says the panel should rise into place rather
 * than drop into it.
 */
.select__menu--above {
    animation-name: menu-rise;
}

@keyframes menu-rise {
    from {
        opacity: 0;
        transform: translateY(0.35rem);
    }
}

.select__menu[hidden] {
    display: none;
}

.select__search {
    flex: none;
    margin-bottom: 0.3rem;
}

.select__search input {
    padding: 0.45rem 0.6rem;
    font-size: 0.86rem;
}

.select__list {
    overflow-y: auto;
    overscroll-behavior: contain;
}

.select__option {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.5rem 0.6rem;
    border-radius: calc(var(--radius) - 2px);
    color: var(--text);
    font-size: 0.9rem;
    line-height: 1.35;
    cursor: pointer;
}

/*
 * The face of whoever a row stands for. Square, pixelated and of a fixed
 * size, so a list of a hundred nicknames is a hundred rows of one height
 * whatever the pictures turn out to be.
 */
.select__option .icon {
    flex: none;
    opacity: 0;
    color: var(--accent);
}

.select__label {
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The row the keyboard is on, which the mouse also paints as it passes. */
.select__option.is-active {
    background: var(--panel-alt);
    color: var(--text-strong);
}

.select__option.is-chosen {
    color: var(--text-strong);
    font-weight: 600;
}

.select__option.is-chosen .icon {
    opacity: 1;
}

.select__option.is-locked {
    color: var(--text-dim);
    cursor: not-allowed;
}

.select__option[hidden] {
    display: none;
}

/* What the search says when it has narrowed the list down to nothing. */
.select__nothing {
    padding: 0.75rem 0.6rem;
    color: var(--text-dim);
    font-size: 0.85rem;
    text-align: center;
}

.toolbar .select {
    width: auto;
    min-width: 220px;
}

/* ------------------------------------------------------------ Pagination */

.pagination {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    flex-wrap: wrap;
    margin-top: 1.5rem;
}

.pagination a,
.pagination span {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.3rem;
    min-width: 2.3rem;
    height: 2.3rem;
    padding: 0 0.65rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text);
    font-size: 0.82rem;
    font-weight: 600;
}

.pagination a:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.pagination .is-current {
    background: var(--accent);
    border-color: var(--accent);
    color: #fff;
}

.pagination .is-disabled {
    opacity: 0.4;
}

/* --------------------------------------------------------------- Notices */

.notice {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    padding: 0.8rem 1rem;
    margin-bottom: 1.25rem;
    border: 1px solid var(--accent);
    border-radius: var(--radius);
    background: var(--panel-alt);
    font-size: 0.88rem;
}

.notice .icon {
    flex: none;
}

.notice--error {
    border-color: var(--danger);
    color: #f0c5c8;
}

.notice--error .icon {
    color: var(--danger);
}

.notice--warn {
    border-color: var(--warn);
}

.notice--warn .icon {
    color: var(--warn);
}

.notice--muted {
    border-color: var(--border);
    color: var(--text-dim);
}

.flash-stack {
    position: fixed;
    /*
     * The corner is said on all four sides, and the box is said to be bare:
     * while a dialog is open the stack lies above it as a popover (see
     * `core/toast`), and a popover comes with a place in the middle of the
     * window, a frame and a background of its own.
     */
    top: auto;
    right: 1rem;
    bottom: 1rem;
    left: auto;
    z-index: 300;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    width: min(420px, calc(100vw - 2rem));
    height: auto;
    margin: 0;
    padding: 0;
    background: none;
    border: 0;
    color: inherit;
    overflow: visible;
    pointer-events: none;
}

.flash {
    display: flex;
    align-items: flex-start;
    gap: 0.65rem;
    padding: 0.8rem 0.9rem;
    background: var(--panel-alt);
    border: 1px solid var(--ok);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    color: var(--text-strong);
    font-size: 0.88rem;
    pointer-events: auto;
    animation: flash-in 0.25s ease;
}

.flash .icon {
    margin-top: 0.2rem;
    color: var(--ok);
}

.flash span {
    flex: 1 1 auto;
    overflow-wrap: anywhere;
}

.flash--error {
    border-color: var(--danger);
}

.flash--error .icon {
    color: var(--danger);
}

.flash--info {
    border-color: var(--accent);
}

.flash--info .icon {
    color: var(--accent);
}

.flash button {
    padding: 0 0.2rem;
    background: transparent;
    border: 0;
    color: var(--text-dim);
    font-size: 1.2rem;
    line-height: 1;
    cursor: pointer;
}

.flash button:hover {
    color: var(--text-strong);
}

.flash.is-leaving {
    opacity: 0;
    transform: translateY(6px);
    transition: opacity 0.2s ease, transform 0.2s ease;
}

@keyframes flash-in {
    from {
        opacity: 0;
        transform: translateY(8px);
    }
}

/* ------------------------------------------------------- Badges and chips */

.badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.1rem 0.5rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    font-size: 0.68rem;
    font-weight: 700;
    letter-spacing: 0.05em;
    text-transform: uppercase;
    color: var(--text-dim);
    white-space: nowrap;
    vertical-align: middle;
}

.badge--accent,
.role-badge[data-role="user"] {
    color: var(--text);
}

.role-badge[data-role="admin"] {
    border-color: var(--accent);
    color: var(--accent);
}

.badge--ok {
    border-color: var(--ok);
    color: var(--ok);
}

.badge--danger {
    border-color: var(--danger);
    color: var(--danger);
}

.badge--muted {
    border-color: var(--border);
    color: var(--text-dim);
}

.chip-row {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    min-width: 0;
    margin: 0;
}

.chip {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    min-height: 34px;
    padding: 0.25rem 0.75rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text-dim);
    font-size: 0.76rem;
    font-weight: 600;
    white-space: nowrap;
    cursor: pointer;
}

.chip:hover {
    border-color: var(--accent);
    color: var(--accent);
}

.chip.is-active {
    background: var(--accent-soft);
    border-color: var(--accent);
    color: var(--accent);
}

.chip--static {
    min-height: 0;
    padding: 0.15rem 0.5rem;
    background: rgba(255, 255, 255, 0.03);
    color: var(--text);
    font-weight: 500;
    white-space: normal;
    cursor: default;
}

.chip--static:hover {
    border-color: var(--border);
    color: var(--text);
}

.chip--static em {
    color: var(--text-dim);
    font-style: normal;
}

.column-head {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
}

.column-head .icon {
    color: var(--text-dim);
}

/* How many there are of what a chip names, in a bubble at its end. */
.chip__count {
    margin-left: 0.15rem;
    padding: 0 0.4rem;
    border-radius: 999px;
    background: rgba(255, 255, 255, 0.08);
    color: var(--text-strong);
    font-size: 0.72rem;
    font-variant-numeric: tabular-nums;
}

/*
 * A number in a cell of a table, in a frame of its own - how often
 * something was downloaded through a link. An outline and nothing filled
 * in: among the lines of a table a filled one reads as a button. Its
 * corners are the corners of the badges and the buttons, as everything of
 * the share has them, and it is never narrower than it is tall, so a single
 * digit sits in a square. Dim while there is nothing to count.
 */
.count-bubble {
    display: inline-block;
    min-width: 1.5rem;
    padding: 0 0.4rem;
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    color: var(--text-strong);
    font-size: 0.72rem;
    font-weight: 600;
    font-variant-numeric: tabular-nums;
    line-height: calc(1.5rem - 2px);
    text-align: center;
}

.count-bubble.is-empty {
    border-color: var(--border);
    color: var(--text-dim);
}

/* ---------------------------------------------------------------- Tables */

.table-wrap {
    width: 100%;
    max-width: 100%;
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
}

table.data {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.88rem;
}

table.data th {
    padding: 0.65rem 0.9rem;
    background: var(--panel-alt);
    border-bottom: 1px solid var(--border);
    color: var(--text-dim);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-align: left;
    white-space: nowrap;
}

table.data td {
    padding: 0.7rem 0.9rem;
    border-bottom: 1px solid var(--border);
    vertical-align: middle;
}

table.data tbody tr:hover {
    background: rgba(255, 255, 255, 0.025);
}

table.data tbody tr:last-child td {
    border-bottom: 0;
}

table.data td.actions {
    text-align: right;
    white-space: nowrap;
}

table.data td.actions .button-row {
    justify-content: flex-end;
    flex-wrap: nowrap;
}

.cell-title {
    color: var(--text-strong);
    font-weight: 600;
    overflow-wrap: anywhere;
}

a.cell-title:hover {
    color: var(--accent);
}

.cell-sub {
    display: block;
    color: var(--text-dim);
    font-size: 0.76rem;
}

/*
 * An address in a row of a table, with the button which copies it: what the
 * pages of everything handed out show of a public entry and of a link. Wide
 * enough to see where the address leads, and written in the face in which
 * every character is as wide as the next - it is copied whole and checked
 * one character at a time.
 *
 * That is the least it is given. With room to spare the column takes it; in
 * a window of a thousand pixels the wider field pushed the button which
 * takes a link down past the edge of its table.
 */
.share-address {
    min-width: 11rem;
}

/*
 * The column of the button which takes a line down is as wide as the button
 * and no wider. A table hands the room it has to spare to every column, and
 * what this one got lay between the button which copies an address and the
 * edge of the table: the address ended short of it, its button in the middle
 * of nowhere. Now the address reaches the last column, and the two buttons
 * stand together at the right hand edge.
 */
table.share-table th:last-child,
table.share-table td.actions {
    width: 1%;
}

.share-address input {
    font-family: var(--mono);
    font-size: 0.8rem;
}

.user-cell {
    display: inline-flex;
    align-items: center;
    gap: 0.65rem;
    min-width: 0;
}

/*
 * Never narrower than a name of ordinary length: a table short of room takes
 * it from the column which gives way most easily, and a name which may break
 * anywhere gave way until it was read a few letters to a line.
 */
.user-cell__text {
    display: flex;
    flex-direction: column;
    min-width: 5.5rem;
}

/*
 * The badges of a cell keep room for two beside each other, for the same
 * reason: six of them, one to a line, made a row of a list as tall as six.
 */
table.data td .chip-row {
    min-width: 5.6rem;
}

/*
 * A heading of two words over a column of short values may take two lines,
 * so the column is as narrow as what stands in it.
 */
table.data th.wraps {
    white-space: normal;
}

.grant-table input[type="checkbox"] {
    width: 19px;
    height: 19px;
}

/*
 * A box its reader may not tick: a right it does not hold itself, the row of
 * a storage whose members it does not manage, the reading of a storage
 * anybody reads. A dark page draws an empty box which is locked nearly the
 * way it draws one which is not, so a locked one is dimmed and says so to
 * the pointer - ticked or not, it is plainly nothing to click.
 */
.grant-table input[type="checkbox"]:disabled {
    opacity: 0.45;
    cursor: not-allowed;
}

.empty-state {
    padding: 3rem 1.5rem;
    text-align: center;
    color: var(--text-dim);
}

.empty-state .icon {
    width: 42px;
    height: 42px;
    margin-bottom: 0.75rem;
    opacity: 0.5;
}

.empty-state p {
    margin: 0;
}

/* A column of numbers: against the right hand edge, digit under digit. */
table.data th.num,
table.data td.num {
    text-align: right;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

/* A row which says something went wrong, marked along its left hand edge. */
table.data tr.is-danger td:first-child {
    box-shadow: inset 3px 0 0 var(--danger);
}

/* ----------------------------------------------------- Dropdowns, modals */

.dropdown {
    position: relative;
}

.dropdown__panel {
    position: absolute;
    top: calc(100% + 0.55rem);
    right: 0;
    z-index: 80;
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 210px;
    padding: 0.45rem;
    background: var(--panel);
    border: 1px solid var(--border-strong);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    animation: menu-drop 0.14s ease;
}

.dropdown__panel[hidden] {
    display: none;
}

@keyframes menu-drop {
    from {
        opacity: 0;
        transform: translateY(-0.35rem);
    }
}

.dropdown__panel--wide {
    min-width: 16.5rem;
}

.dropdown__card {
    display: flex;
    align-items: center;
    gap: 0.7rem;
    min-width: 0;
    margin-bottom: 0.35rem;
    padding: 0.7rem 0.75rem;
    background: var(--panel-alt);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.dropdown__identity {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.15rem;
    min-width: 0;
}

.dropdown__identity strong {
    color: var(--text-strong);
}

.dropdown__panel form {
    margin: 0;
}

.dropdown__item {
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: 100%;
    padding: 0.6rem;
    background: transparent;
    border: 0;
    border-radius: var(--radius);
    color: var(--text);
    font-family: inherit;
    font-size: 0.84rem;
    font-weight: 600;
    text-align: left;
    text-decoration: none;
    cursor: pointer;
}

.dropdown__item .icon {
    flex: none;
    color: var(--text-dim);
    transition: color 0.15s ease;
}

.dropdown__item:hover,
.dropdown__item:focus-visible {
    background: var(--panel-hover);
    color: var(--text-strong);
    outline: none;
}

.dropdown__item:hover .icon,
.dropdown__item:focus-visible .icon {
    color: var(--accent);
}

.dropdown__item.is-active {
    color: var(--accent);
}

/* The way out is the last item and the one which cannot be undone by pressing it again. */
.dropdown__item--danger {
    color: #f0736a;
}

.dropdown__panel > form:last-child > .dropdown__item--danger {
    margin-top: 0.35rem;
    padding-top: 0.7rem;
    border-top: 1px solid var(--border);
    border-radius: 0 0 var(--radius) var(--radius);
}

.dropdown__item--danger .icon {
    color: inherit;
}

.dropdown__item--danger:hover,
.dropdown__item--danger:focus-visible {
    background: rgba(226, 33, 47, 0.14);
    color: #ff8a80;
}

.dropdown__item--danger:hover .icon,
.dropdown__item--danger:focus-visible .icon {
    color: inherit;
}

.dropdown__item[disabled] {
    opacity: 0.45;
    pointer-events: none;
}

/* The language panel: a heading over a rule, and each language with its code in a small box. */
.language-panel {
    min-width: 12.5rem;
}

.language-panel__head {
    margin-bottom: 0.35rem;
    padding: 0.5rem 0.6rem 0.75rem;
    border-bottom: 1px solid var(--border);
}

.language-panel__head strong {
    color: var(--text-strong);
    font-size: 0.88rem;
}

.language-panel__item {
    justify-content: flex-start;
}

.language-panel__code {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 2.1rem;
    padding: 0.1rem 0.35rem;
    background: var(--panel-alt);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text-dim);
    font-family: var(--mono);
    font-size: 0.68rem;
    font-weight: 600;
}

.language-panel__item.is-active {
    color: var(--accent);
}

.language-panel__item.is-active .language-panel__code {
    border-color: rgba(227, 79, 14, 0.45);
    color: var(--accent);
}

.language-panel__item .icon:last-child {
    margin-left: auto;
    color: var(--accent);
}

/*
 * Dialogs, the same as the TechCraft portal draws them: a native <dialog>,
 * so the focus trap, the Escape key and the inert page behind it are the
 * browser's own doing rather than ours.
 */
.modal {
    /*
     * Pinned to the window and centred in it by the margins, said here in as
     * many words rather than left to the stylesheet of the browser: every
     * browser centres a modal dialog, but not every one the same way, and
     * one which placed it against the top of a page scrolled half way down
     * drew half of it off the screen.
     */
    position: fixed;
    inset: 0;
    width: min(30rem, calc(100vw - 2rem));
    height: fit-content;
    /*
     * Never taller than the window it is drawn in: a dialog is centred by the
     * browser, so one taller than the window would lose its heading off the
     * top with no way to scroll up to it.
     */
    max-height: calc(100vh - 2rem);
    max-height: calc(100svh - 2rem);
    margin: auto;
    padding: 0;
    background: var(--panel);
    /*
     * An opaque grey rather than the translucent white of the other frames.
     * A dialog sits in the top layer over its darkened backdrop, and the
     * translucent line took its colour from whatever was under it - clearly
     * visible over a light picture, all but gone over a dark page.
     * This is the colour that line has over the panel, on every page alike.
     */
    border: 1px solid #55524d;
    border-radius: var(--radius);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.35), 0 18px 48px rgba(0, 0, 0, 0.6);
    color: var(--text);
    overflow: hidden;
}

.modal::backdrop {
    background: rgba(0, 0, 0, 0.6);
}

/*
 * What does not fit the window scrolls, and the frame of the dialog stays.
 * Its parts keep their own height: shrunk to fit, a long table was cut off
 * inside its box and there was nothing left to scroll.
 */
.modal__inner > * {
    flex-shrink: 0;
}

.modal__title {
    display: flex;
    align-items: center;
    gap: 0.55rem;
}

/*
 * A dialog drawn by a script keeps its heading and its buttons in place and
 * scrolls only the body between them, so a long table never takes the name
 * of the dialog away with it.
 */
.modal__inner--fixed {
    overflow: hidden;
}

.modal__inner--fixed > .modal__title {
    margin-bottom: 0.5rem;
}

.modal__inner > .modal__scroll {
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
    flex: 1 1 auto;
    min-height: 0;
    margin: 0 -0.5rem;
    padding: 0 0.5rem;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.modal__scroll > * {
    flex-shrink: 0;
}

.modal__inner {
    display: flex;
    flex-direction: column;
    gap: 0.7rem;
    max-height: inherit;
    padding: 1.25rem;
    overflow-y: auto;
    overscroll-behavior: contain;
}

.modal__title {
    margin: 0;
    color: var(--text-strong);
    font-size: 1.05rem;
}

.modal__text {
    margin: 0;
    font-size: 0.9rem;
    line-height: 1.55;
}

.modal__actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.6rem;
    margin-top: 0.5rem;
}

/* A dialog carrying a form needs the room a question does not. */
.modal:has(.field) {
    width: min(34rem, calc(100vw - 2rem));
}

/* A dialog somebody works in for a while - a longer text, a list to pick from - needs more room still. */
.modal--editor,
.modal--editor:has(.field) {
    width: min(46rem, calc(100vw - 2rem));
}

/* Wide enough for a table, and for the picture or the film the viewer shows. */
.modal--huge,
.modal--huge:has(.field) {
    width: min(66rem, calc(100vw - 2rem));
}

.modal .field {
    margin: 0;
}

/* What is about to be deleted, large enough to be read before it is typed again. */
.destroy-name code {
    font-size: 1rem;
}

/* ---------------------------------------------------------- Administration */

.admin-layout {
    display: grid;
    grid-template-columns: 230px minmax(0, 1fr);
    gap: 1.5rem;
    width: 100%;
    max-width: 1600px;
    margin: 0 auto;
    padding: 1.75rem 1.25rem 3rem;
}

.admin-sidebar {
    align-self: start;
    position: sticky;
    top: calc(var(--header-height) + 1rem);
    min-width: 0;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
}

.admin-sidebar__title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.85rem 1.05rem;
    background: var(--panel-alt);
    border-bottom: 1px solid var(--border);
    color: var(--text-dim);
    font-size: 0.7rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    text-transform: uppercase;
}

.admin-sidebar nav {
    display: flex;
    flex-direction: column;
    padding: 0.45rem;
}

.admin-sidebar nav a {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    min-height: 38px;
    padding: 0.5rem 0.7rem;
    border-radius: var(--radius);
    color: var(--text);
    font-size: 0.86rem;
    font-weight: 600;
}

.admin-sidebar nav a .icon {
    color: var(--text-dim);
}

.admin-sidebar nav a:hover {
    background: var(--panel-hover);
    color: var(--text-strong);
}

.admin-sidebar nav a.is-active {
    background: var(--accent-soft);
    color: var(--accent);
}

.admin-sidebar nav a.is-active .icon {
    color: var(--accent);
}

/* The sections where the sidebar has no room beside the page (see the media query below). */
.admin-menu {
    display: none;
}

.admin-content {
    min-width: 0;
}

.admin-header {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.4rem;
}

.admin-header > div {
    min-width: 0;
}

.admin-header h1 {
    margin-bottom: 0.3rem;
    overflow-wrap: anywhere;
}

/* The login under the name of an account, with what is known about it. */
.account-head {
    display: flex;
    align-items: baseline;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin: 0 0 0.25rem;
    color: var(--text-dim);
    font-size: 0.95rem;
}

.account-head strong {
    color: var(--text);
    font-family: var(--mono);
    font-size: 0.9rem;
}

.admin-header p {
    margin: 0;
    color: var(--text-dim);
}

.admin-columns {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem;
    margin-bottom: 1.25rem;
    align-items: start;
}

.toolbar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.8rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.toolbar select {
    width: auto;
    min-width: 220px;
}

.search-box {
    position: relative;
    flex: 1 1 260px;
    max-width: 420px;
    margin: 0;
}

.search-box .icon {
    position: absolute;
    left: 0.7rem;
    top: 50%;
    transform: translateY(-50%);
    color: var(--text-dim);
    pointer-events: none;
}

.search-box input {
    padding-left: 2.2rem;
}

.stat-grid {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 1rem;
    margin-bottom: 1.25rem;
}

.stat-card {
    display: flex;
    align-items: center;
    gap: 0.9rem;
    padding: 1.1rem 1.2rem;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text);
    transition: border-color 0.18s ease;
}

a.stat-card:hover {
    border-color: var(--accent);
    color: var(--text);
}

.stat-card__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    flex: none;
    background: var(--accent-soft);
    border-radius: var(--radius);
    color: var(--accent);
}

.stat-card.is-warn .stat-card__icon {
    background: rgba(217, 158, 43, 0.14);
    color: var(--warn);
}

.stat-card.is-danger .stat-card__icon {
    background: rgba(226, 33, 47, 0.14);
    color: var(--danger);
}

.stat-card__body {
    display: flex;
    flex-direction: column;
    min-width: 0;
}

.stat-card__body strong {
    color: var(--text-strong);
    font-size: 1.35rem;
    line-height: 1.2;
    overflow-wrap: anywhere;
    /* Two sizes which take two lines break between them, not before the unit of the second. */
    text-wrap: balance;
}

.stat-card__body span {
    color: var(--text-dim);
    font-size: 0.78rem;
}

.facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 0.9rem;
    margin: 0;
}

.facts div {
    min-width: 0;
}

.facts dt {
    color: var(--text-dim);
    font-size: 0.7rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.facts dd {
    margin: 0.15rem 0 0;
    color: var(--text-strong);
    overflow-wrap: anywhere;
}

/* A heading with the one button which belongs to it, at the other end of the line. */
.panel__row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 0.6rem;
}

.panel__row .panel__title {
    margin: 0;
}

/* ---------------------------------------------------- Sign in, error pages */

body.is-auth {
    background: var(--bg);
}

body.is-auth .site-footer {
    border-top: 0;
    justify-content: center;
}

.auth-card {
    width: 100%;
    max-width: 430px;
    margin: 0 auto;
    padding: 3.5rem 1.25rem 2rem;
}

.auth-card--wide {
    max-width: 720px;
}

.auth-card__brand {
    margin-bottom: 1.4rem;
    text-align: center;
}

.auth-card__brand img {
    margin-bottom: 0.6rem;
}

.auth-card__brand p {
    color: var(--text-dim);
}

.auth-card .panel {
    padding: 1.5rem;
}

.auth-card .field + .field {
    margin-top: 1rem;
}

.auth-card__note {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    color: var(--text-dim);
    font-size: 0.78rem;
    text-align: center;
}

.error-page {
    max-width: 560px;
    margin: 3rem auto;
    text-align: center;
}

.error-page__glyph {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 72px;
    height: 72px;
    margin-bottom: 1rem;
    background: var(--accent-soft);
    border-radius: 50%;
    color: var(--accent);
}

.error-page__code {
    margin: 0;
    color: var(--accent);
    font-size: 0.8rem;
    font-weight: 700;
    letter-spacing: 0.2em;
}

.error-page__message {
    color: var(--text);
}

.error-page__address,
.error-page__reference {
    color: var(--text-dim);
    font-size: 0.85rem;
}

/* ------------------------------------------------------ Page progress bar */

.page-progress {
    position: fixed;
    top: 0;
    left: 0;
    z-index: 400;
    width: 0;
    height: 3px;
    background: var(--accent);
    box-shadow: 0 0 8px rgba(227, 79, 14, 0.6);
    opacity: 0;
    pointer-events: none;
}

/*
 * Quick at first and ever slower, so it never reaches the end before the page
 * does - a bar which is full and still waiting is worse than no bar.
 */
.page-progress.is-running {
    opacity: 1;
    animation: page-progress 8s cubic-bezier(0.1, 0.8, 0.2, 1) forwards;
}

@keyframes page-progress {
    0% {
        width: 0;
    }

    10% {
        width: 45%;
    }

    100% {
        width: 92%;
    }
}

/* ---------------------------------------------- Permissions and storages */

/* A form which may be read but not changed keeps its look, only its controls rest. */
.plain-fieldset {
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
}

.plain-fieldset[disabled] input,
.plain-fieldset[disabled] select,
.plain-fieldset[disabled] textarea {
    cursor: not-allowed;
}

.panel__body {
    padding: 1rem 1.4rem;
}

.panel__foot {
    margin: 0;
    padding: 0.75rem 1.4rem;
    border-top: 1px solid var(--border);
}

/*
 * The foot of a panel which saves what it holds. A panel with no padding of
 * its own would otherwise have its button against the edge, and there is no
 * rule drawn above it - the button belongs to the panel, not after it.
 */
.panel__actions {
    margin: 0;
    padding: 0.2rem 1.4rem 1.2rem;
}

/* The pages of a list inside a panel, under what they page through. */
.panel__pagination {
    padding: 0 1.4rem;
}

/* What a narrowed list says about itself, right under the search. */
.toolbar-note {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    margin: -0.6rem 0 1rem;
}

/*
 * A table which is part of what a panel says rather than the whole of it:
 * drawn in a frame of its own, inside the padding of the panel, the way the
 * boxes of the permissions and the storages are.
 *
 * The frame and the scrolling are two elements on purpose. A frame which
 * scrolls its own content cannot draw a line the content does not reach, so
 * a table wider than the panel lost its right hand edge; this way the frame
 * stands still and closed while the table slides inside it.
 */
.table-frame {
    /* Never `width: 100%`: with the margins beside it that is wider than the
       panel, and a flush panel clips whatever sticks out - which is how the
       right hand edge of the frame went missing. */
    margin: 0.9rem 1.4rem 1.2rem;
    border: 1px solid var(--border);
    border-radius: var(--radius);
    overflow: hidden;
}

.table-frame table.data tbody tr:last-child td {
    border-bottom: 0;
}

.notice--info {
    border-color: rgba(227, 79, 14, 0.45);
    background: var(--accent-faint);
}

.notice--info .icon {
    color: var(--accent);
}

.facts--stack {
    grid-template-columns: repeat(2, minmax(0, 1fr));
}

.access-form__heading {
    margin: 0;
    color: var(--text-dim);
    font-size: 0.74rem;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.access-form > .plain-fieldset {
    padding: 1.3rem 1.4rem 1.4rem;
}

.access-form > .notice {
    margin: 1rem 1.4rem 0;
}

/* The role and the permissions, split by a hairline. */
.access-section + .access-section {
    margin-top: 1.4rem;
    padding-top: 1.4rem;
    border-top: 1px solid var(--border);
}

.access-section__head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.6rem;
    margin-bottom: 0.7rem;
}

.access-section__lead {
    margin: -0.3rem 0 0.8rem;
}

.access-section__count {
    font-variant-numeric: tabular-nums;
}

.access-section__note {
    margin: 0.6rem 0 0;
}

.role-choice {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
    gap: 0.6rem;
}

.role-choice__option {
    position: relative;
    display: flex;
    gap: 0.65rem;
    padding: 0.8rem 0.9rem;
    background: var(--panel-alt);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease;
}

.role-choice__option:hover {
    border-color: var(--border-strong);
}

.role-choice__option:has(input:checked) {
    background: var(--accent-faint);
    border-color: var(--accent);
}

.role-choice__option input {
    margin-top: 0.2rem;
}

.role-choice__body {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.role-choice__title {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--text-strong);
    font-weight: 600;
}

.role-choice__title .icon {
    color: inherit;
}

.access-form__admin-note {
    display: none;
    margin: 0 0 0.8rem;
}

.access-form.is-admin-role .access-form__admin-note {
    display: flex;
}

.access-form.is-admin-role .permission-grid {
    opacity: 0.45;
    pointer-events: none;
}

.access-form__needs-access {
    display: none;
    margin: 0.6rem 0 0;
}

.access-form.is-without-access .access-form__needs-access {
    display: block;
}

/* Every permission in one grid, as TechCraft lists them: no group leaves a gap. */
.permission-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
    gap: 0.6rem;
    transition: opacity 0.2s ease;
}

.permission-item {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    padding: 0.6rem 0.7rem;
    background: var(--panel-alt);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    cursor: pointer;
    transition: border-color 0.15s ease, background-color 0.15s ease, opacity 0.2s ease;
}

.permission-item:hover {
    border-color: var(--border-strong);
}

.permission-item:has(input:checked) {
    background: var(--accent-faint);
    border-color: rgba(227, 79, 14, 0.5);
}

.permission-item input {
    margin-top: 0.2rem;
    flex: none;
}

.permission-item.is-locked {
    border-style: dashed;
    cursor: not-allowed;
}

.permission-item.is-inactive {
    opacity: 0.5;
}

.permission-item__body {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.permission-item__name {
    display: flex;
    align-items: center;
    gap: 0.35rem;
    color: var(--text-strong);
    font-size: 0.86rem;
    font-weight: 600;
}

.permission-item__name .icon {
    color: var(--text-dim);
}

.permission-item .field__hint {
    font-size: 0.76rem;
    line-height: 1.45;
}

.permission-item__meta {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin-top: 0.2rem;
}

.permission-item__meta code {
    color: var(--text-dim);
    font-size: 0.68rem;
}

/* The size of a new storage: the slider of the page of a storage, under a label of a field. */
.new-quota__label {
    display: block;
    margin-bottom: 0.5rem;
    color: var(--text-strong);
    font-size: 0.72rem;
    font-weight: 700;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

/* A size nobody here may choose: greyed out, the slider and the buttons alike. */
.quota-fieldset:disabled {
    opacity: 0.55;
}

.quota-fieldset:disabled button,
.quota-fieldset:disabled input[type="range"] {
    cursor: not-allowed;
}

.reach-panel__grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
    gap: 1rem;
}

.reach-panel .panel__subtitle {
    margin-top: 0;
}

.reach-panel .chip-row {
    margin: 0;
    padding: 0;
    list-style: none;
}

/* -------------------------------------------- Responsive and accessibility */

/*
 * A table of rights on anything but a wide screen. It is a column for every
 * right, and six names written out beside each other need more than what is
 * left beside the sections of the administration - the rights past the edge
 * of the table were the ones nobody saw they could give. So the name of a
 * right goes under its symbol, in letters small enough for the longest of
 * them, and every cell gives up some of the room around it.
 */
@media (max-width: 1440px) {
    table.grant-table th,
    table.grant-table td {
        padding-left: 0.5rem;
        padding-right: 0.5rem;
    }

    table.grant-table th:first-child,
    table.grant-table td:first-child {
        padding-left: 0.9rem;
    }

    .column-head--right {
        flex-direction: column;
        gap: 0.3rem;
    }

    .column-head--right .column-head__label {
        font-size: 0.62rem;
        letter-spacing: 0.02em;
        line-height: 1.25;
        text-align: center;
        white-space: normal;
    }
}

/*
 * The sections of the administration fold into one bar here already, not only
 * on a phone: its tables are a column for every right and for every fact, and
 * beside the sections a table has some 340 pixels less than the window. The
 * widest of the lists - every share link, with who made it, when, until when
 * and how often it was used - needs close to 800 of its own, so in anything
 * narrower than this its last column, the one with the button, lay past the
 * edge.
 *
 * A strip of a dozen links scrolled sideways hid most of them past the edge
 * with nothing to say they were there. One bar naming the section instead,
 * which unfolds into all of them.
 */
@media (max-width: 1180px) {
    .admin-layout {
        grid-template-columns: minmax(0, 1fr);
        gap: 1rem;
        padding-top: 1rem;
    }

    .admin-sidebar {
        display: none;
    }

    .admin-menu {
        display: block;
        background: var(--panel);
        border: 1px solid var(--border);
        border-radius: var(--radius);
        overflow: hidden;
    }

    .admin-menu__toggle {
        display: flex;
        align-items: center;
        gap: 0.75rem;
        min-height: 52px;
        padding: 0.6rem 1rem;
        color: var(--text-strong);
        cursor: pointer;
        list-style: none;
        user-select: none;
    }

    .admin-menu__toggle::-webkit-details-marker {
        display: none;
    }

    .admin-menu__toggle > .icon:first-child {
        color: var(--accent);
    }

    .admin-menu__label {
        display: flex;
        flex-direction: column;
        min-width: 0;
        line-height: 1.25;
    }

    .admin-menu__label small {
        color: var(--text-dim);
        font-size: 0.66rem;
        font-weight: 700;
        letter-spacing: 0.12em;
        text-transform: uppercase;
    }

    .admin-menu__label strong {
        overflow: hidden;
        font-size: 0.98rem;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    .admin-menu__chevron {
        margin-left: auto;
        color: var(--text-dim);
        transition: transform 0.15s ease;
    }

    .admin-menu[open] .admin-menu__chevron {
        transform: rotate(180deg);
    }

    .admin-menu[open] .admin-menu__toggle {
        border-bottom: 1px solid var(--border);
        background: var(--panel-alt);
    }

    .admin-menu nav {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        gap: 0.25rem;
        padding: 0.5rem;
    }

    .admin-menu nav a {
        display: flex;
        align-items: center;
        gap: 0.6rem;
        min-width: 0;
        min-height: 46px;
        padding: 0.55rem 0.75rem;
        border-radius: var(--radius);
        color: var(--text);
        font-size: 0.9rem;
        font-weight: 600;
    }

    /* A long name takes a second line rather than losing its end. */
    .admin-menu nav a span {
        min-width: 0;
        line-height: 1.25;
        overflow-wrap: anywhere;
    }

    .admin-menu nav a .icon {
        flex: none;
        color: var(--text-dim);
    }

    .admin-menu nav a:hover {
        background: var(--panel-hover);
        color: var(--text-strong);
    }

    .admin-menu nav a.is-active {
        background: var(--accent-soft);
        color: var(--accent);
    }

    .admin-menu nav a.is-active .icon {
        color: var(--accent);
    }
}

@media (max-width: 1100px) {
    .stat-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .admin-columns {
        grid-template-columns: minmax(0, 1fr);
    }

    .user-chip__name {
        display: none;
    }
}

@media (max-width: 900px) {
    .form-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    /*
     * No room even for the name of a right under its symbol: the symbol
     * stands alone. The name stays where a screen reader finds it, and the
     * title of the heading says it to a pointer.
     */
    .column-head--right .column-head__label {
        position: absolute;
        width: 1px;
        height: 1px;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
    }
}

/* The narrowest phones: one section a row, so no name is cut short. */
@media (max-width: 380px) {
    .admin-menu nav {
        grid-template-columns: minmax(0, 1fr);
    }
}

@media (max-width: 640px) {
    .facts--stack {
        grid-template-columns: minmax(0, 1fr);
    }

    .access-form > .plain-fieldset {
        padding: 1rem;
    }

    h1 {
        font-size: 1.4rem;
    }

    .wrapper {
        padding: 1.25rem 0.9rem 2rem;
    }

    .admin-layout {
        padding-left: 0.75rem;
        padding-right: 0.75rem;
    }

    .panel {
        padding: 1.1rem;
    }

    /* A flush panel stays flush: its table or list pads itself. */
    .panel--flush {
        padding: 0;
    }

    .stat-grid {
        grid-template-columns: minmax(0, 1fr);
    }

    .site-header {
        padding: 0 0.75rem;
        gap: 0.6rem;
    }

    .site-header__name {
        display: none;
    }

    /* A table of accounts becomes a stack of cards, each cell labelled. */
    table.data--stack thead {
        display: none;
    }

    table.data--stack,
    table.data--stack tbody,
    table.data--stack tr,
    table.data--stack td {
        display: block;
        width: 100%;
    }

    table.data--stack tr {
        padding: 0.7rem 0.9rem;
        border-bottom: 1px solid var(--border);
    }

    table.data--stack td {
        display: flex;
        align-items: center;
        justify-content: space-between;
        gap: 1rem;
        padding: 0.3rem 0;
        border: 0;
        text-align: right;
    }

    table.data--stack td[data-label]::before {
        content: attr(data-label);
        flex: none;
        color: var(--text-dim);
        font-size: 0.68rem;
        font-weight: 700;
        letter-spacing: 0.08em;
        text-transform: uppercase;
        text-align: left;
    }

    table.data--stack td.actions {
        justify-content: flex-end;
        padding-top: 0.5rem;
    }

    .flash-stack {
        right: 0.5rem;
        left: 0.5rem;
        bottom: 0.5rem;
        width: auto;
    }
}

:focus-visible {
    outline: 2px solid var(--accent);
    outline-offset: 2px;
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        transition-duration: 0.01ms !important;
    }
}

/* ---------------------------------------------- Storages and files pages */

.manage-heading {
    display: flex;
    align-items: flex-end;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.1rem;
}

.manage-heading__title {
    min-width: 0;
}

.manage-heading__title h1 {
    margin-bottom: 0.2rem;
}

.manage-heading__title p {
    margin: 0;
    color: var(--text-dim);
    overflow-wrap: anywhere;
}

/*
 * The pills are all alike - a symbol and a name - and stand in rows: the
 * first one is filled, and what does not fit goes on in the next.
 */
.storage-switcher {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    margin-bottom: 1.25rem;
}

.storage-switcher__item {
    display: inline-flex;
    align-items: center;
    gap: 0.6rem;
    flex: none;
    max-width: 280px;
    padding: 0.35rem 0.7rem;
    background: var(--panel);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text);
}

.storage-switcher__item:hover {
    border-color: var(--border-strong);
    color: var(--text-strong);
}

.storage-switcher__item.is-active {
    background: var(--accent-soft);
    border-color: var(--accent);
    color: var(--text-strong);
}

.storage-switcher__item .icon {
    flex: none;
    color: var(--accent);
}

.storage-switcher__item strong {
    min-width: 0;
    overflow: hidden;
    font-size: 0.85rem;
    font-weight: 600;
    line-height: 1.25;
    text-overflow: ellipsis;
    white-space: nowrap;
}

/* The box a file is chosen by, as narrow as the box itself. */
.file-table__check {
    width: 1%;
}

.file-table td {
    padding-top: 0.55rem;
    padding-bottom: 0.55rem;
}

.file-name {
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding-left: calc(var(--depth, 0) * 1.6rem);
    min-width: 0;
}

.file-name__icon {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    flex: none;
    background: var(--panel-alt);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--accent);
}

.file-name__text {
    display: flex;
    flex-direction: column;
    gap: 0.15rem;
    min-width: 0;
}

.file-name__text strong {
    color: var(--text-strong);
    font-weight: 600;
    overflow-wrap: anywhere;
}

@media (max-width: 900px) {
    .manage-heading {
        align-items: flex-start;
    }
}

@media (max-width: 640px) {
    .file-name {
        padding-left: calc(var(--depth, 0) * 0.9rem);
    }

    /* The name of a file needs no label and starts where the card does. Found
       by what the cell holds rather than by its place in the row: the box in
       front of it is only there for whoever may change the files. */
    table.data--stack.file-table td:has(> .file-link),
    table.data--stack.file-table td:has(> .file-name) {
        justify-content: flex-start;
        text-align: left;
    }

    table.data--stack.file-table td:has(> .file-link)::before,
    table.data--stack.file-table td:has(> .file-name)::before {
        display: none;
    }
}

/* ----------------------------------------------------- Size of a storage */

/*
 * The bar of how full a storage is: the same in the administration and beside
 * the listing of its files. Orange while there is room, yellow once the
 * storage fills up, red when it is almost or completely full.
 */
.usage-bar {
    position: relative;
    height: 6px;
    overflow: hidden;
    background: rgba(255, 255, 255, 0.07);
    border: 1px solid var(--border);
    border-radius: 999px;
}

.usage-bar > span {
    display: block;
    width: 0;
    height: 100%;
    background: var(--accent);
    border-radius: inherit;
    transition: width 0.45s ease, background-color 0.2s ease;
}

.usage-bar--warn > span {
    background: var(--warn);
}

.usage-bar--critical > span,
.usage-bar--full > span {
    background: var(--danger);
}

/*
 * The bar where a storage is one row among others: the two sizes in words
 * and the bar under them, never narrower than a bar can be read at.
 */
.usage-meter {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    min-width: 8rem;
    font-size: 0.82rem;
    font-variant-numeric: tabular-nums;
}

.quota-panel {
    display: flex;
    flex-direction: column;
    gap: 1.1rem;
}

/*
 * How full the storage is, in the panel beside the one which sets its size:
 * the whole of it on one bar, and then folder by folder.
 */
.usage-report {
    display: flex;
    flex-direction: column;
    gap: 0.55rem;
    margin-top: 0.9rem;
    padding: 0.85rem 0.95rem;
    background: var(--panel-alt);
    border: 1px solid var(--border);
    border-radius: var(--radius);
}

.usage-report .usage-bar {
    height: 8px;
}

.usage-report__line {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    font-size: 0.85rem;
}

.usage-report__line strong {
    color: var(--text-strong);
    font-variant-numeric: tabular-nums;
}

.usage-report--warn .usage-report__line strong {
    color: var(--warn);
}

.usage-report--critical .usage-report__line strong,
.usage-report--full .usage-report__line strong {
    color: var(--danger);
}

.quota-control {
    display: flex;
    align-items: center;
    gap: 1rem;
}

/* The slider: a thin track filled in the accent up to the chosen size. */
.quota-control input[type="range"] {
    --fill: 0%;
    flex: 1 1 auto;
    min-width: 0;
    height: 6px;
    margin: 0;
    appearance: none;
    background: linear-gradient(90deg, var(--accent) 0 var(--fill), rgba(255, 255, 255, 0.09) var(--fill) 100%);
    border-radius: 999px;
    cursor: pointer;
}

.quota-control input[type="range"]::-webkit-slider-thumb {
    width: 18px;
    height: 18px;
    appearance: none;
    background: var(--text-strong);
    border: 3px solid var(--accent);
    border-radius: 50%;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
    transition: transform 0.12s ease;
}

.quota-control input[type="range"]::-moz-range-thumb {
    width: 12px;
    height: 12px;
    background: var(--text-strong);
    border: 3px solid var(--accent);
    border-radius: 50%;
    box-shadow: 0 1px 6px rgba(0, 0, 0, 0.5);
}

.quota-control input[type="range"]:hover::-webkit-slider-thumb,
.quota-control input[type="range"]:focus-visible::-webkit-slider-thumb {
    transform: scale(1.12);
}

.quota-control input[type="range"]:focus-visible {
    outline: 2px solid var(--accent-soft);
    outline-offset: 6px;
}

.quota-control input[type="range"]:disabled {
    cursor: not-allowed;
    opacity: 0.55;
}

.quota-control__value {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    flex: none;
    color: var(--text-dim);
    font-size: 0.8rem;
    font-weight: 700;
}

.quota-control__value input[type="number"] {
    width: 5.5rem;
    text-align: right;
    font-variant-numeric: tabular-nums;
}

.quota-scale {
    display: flex;
    justify-content: space-between;
    margin: -0.55rem calc(5.5rem + 2.4rem) 0 0;
    color: var(--text-dim);
    font-size: 0.68rem;
    font-variant-numeric: tabular-nums;
}

/*
 * The scale as the script draws it: the slider stops at round sizes which
 * lie closer together where storages are small, so a size is named where the
 * slider reaches it rather than at an even distance from the next. Each name
 * is held by the point of it which is as far along the name as the name is
 * along the track - the first by its left edge, the last by its right one -
 * so none of them hangs over an end of the track.
 */
.quota-scale.is-placed {
    position: relative;
    display: block;
    height: 1.6em;
}

.quota-scale.is-placed span {
    position: absolute;
    left: var(--at);
    transform: translateX(calc(var(--at) * -1));
    white-space: nowrap;
}

/* A line of its own, well away from the scale of the slider above it. */
.quota-presets {
    display: flex;
    align-items: center;
    gap: 0.4rem;
    flex-wrap: wrap;
    margin-top: 1.8rem;
}

.quota-presets .field__hint {
    margin: 0 0.3rem 0 0;
}

.quota-presets__item {
    padding: 0.3rem 0.65rem;
    background: var(--panel-alt);
    border: 1px solid var(--border);
    border-radius: var(--radius);
    color: var(--text);
    font: inherit;
    font-size: 0.76rem;
    font-weight: 600;
    cursor: pointer;
    transition: border-color 0.15s ease, color 0.15s ease, background-color 0.15s ease;
}

.quota-presets__item:hover:not(:disabled) {
    border-color: var(--border-strong);
    color: var(--text-strong);
}

.quota-presets__item.is-active {
    background: var(--accent-faint);
    border-color: var(--accent);
    color: var(--text-strong);
}

.quota-presets__item:disabled {
    cursor: not-allowed;
    opacity: 0.55;
}

.quota-warning {
    margin: 0;
}

/*
 * On a phone the slider takes the whole width, with its scale right under it
 * and the size in numbers under the two of them. The scale is written after
 * the field of the number, so the three are laid out as one column and put in
 * that order here - left in the order they are written, the scale was drawn
 * across the field it follows.
 */
@media (max-width: 640px) {
    .quota-fieldset {
        display: grid;
    }

    .quota-control {
        display: contents;
    }

    .quota-control input[type="range"] {
        order: 1;
        width: 100%;
    }

    .quota-scale {
        order: 2;
        margin: 0.5rem 0 0;
    }

    .quota-control__value {
        order: 3;
        justify-content: flex-end;
        margin-top: 0.9rem;
    }

    .quota-presets {
        order: 4;
        margin-top: 1.1rem;
    }

    .quota-warning {
        order: 5;
        margin-top: 0.9rem;
    }
}

/* ---------------------------------------------------------------- Account */

.account-card {
    display: flex;
    align-items: center;
    gap: 0.9rem;
}

.account-card__body {
    display: flex;
    flex-direction: column;
    gap: 0.2rem;
    min-width: 0;
}

.account-card__name {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    flex-wrap: wrap;
    color: var(--text-strong);
    font-size: 1.02rem;
    overflow-wrap: anywhere;
}

.account-lead {
    margin: -0.4rem 0 1rem;
}

/* ----------------------------------------------- Storages administration */

/*
 * A fact too long for one cell of its row - where a storage lies on the
 * disk - takes the whole of the row, so a path breaks where it has to
 * rather than after every few letters.
 */
.facts__wide {
    grid-column: 1 / -1;
}
