
/* Tokens are the only raw values. Classes are named after what a thing is, not what
   it looks like; variants are a second class (`.button.brand`). */

:root {
    /* Spacing: a 4px scale. */
    --space-2xs: 0.25rem;
    --space-xs: 0.5rem;
    --space-s: 0.75rem;
    --space-m: 1rem;
    --space-l: 1.5rem;
    --space-xl: 2rem;
    --space-2xl: 3rem;

    --radius-s: 4px;
    --radius-m: 6px;
    --radius-l: 10px;
    --radius-pill: 999px;

    --color-text: #1a1d24;
    --color-text-quiet: #5c636e;
    --color-surface: #ffffff;
    --color-surface-sunken: #f7f8f9;
    --color-fill-quiet: #f1f3f4;
    --color-border: #cdd1d8;
    --color-border-quiet: #e2e4e9;

    --color-brand: #3a5ccc;
    --color-brand-hover: #314fb0;
    --color-brand-text: #ffffff;
    --color-brand-quiet: #e8edfc;
    --color-brand-quiet-hover: #dde5fb;

    --color-danger: #b3261e;
    --color-danger-quiet: #fdecea;
    --color-success-quiet: #e7f4ea;
    --color-success-border: #9cc9a6;
    --color-warning-quiet: #fdf3e0;
    --color-warning-border: #e3c07d;
    /* Behind something raised over the page, and the raised thing's shadow. */
    --color-backdrop: rgb(0 0 0 / 35%);
    --shadow-raised: 0 6px 24px rgb(0 0 0 / 12%);

    --font-sans: system-ui, "Segoe UI", Roboto, "Helvetica Neue", Arial,
        "Hiragino Kaku Gothic ProN", "Noto Sans JP", sans-serif;
    --font-code: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
    --font-size-xs: 0.75rem;
    --font-size-s: 0.875rem;
    --font-size-m: 1rem;
    --font-size-l: 1.125rem;
    --font-size-xl: 1.375rem;
    --weight-normal: 400;
    --weight-semibold: 600;

    --focus-ring: 2px solid var(--color-brand);
}

/* --- base --- */

/* Author styles beat the UA stylesheet at any specificity, so any `display` rule of
   ours would silently defeat `[hidden]`. */
[hidden] {
    display: none !important;
}

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

body {
    margin: 0;
    background: var(--color-surface);
    color: var(--color-text);
    font-family: var(--font-sans);
    font-size: var(--font-size-m);
    line-height: 1.6;
}

h1,
h2,
h3 {
    line-height: 1.3;
}

a {
    color: var(--color-brand);
}

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

code,
pre,
.mono {
    font-family: var(--font-code);
}

.quiet,
.empty {
    color: var(--color-text-quiet);
}

app-icon {
    display: inline-flex;
    flex: none;
    width: 1.25em;
    height: 1.25em;
}

app-icon svg {
    width: 100%;
    height: 100%;
}

/* --- buttons --- */
.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    padding: 0.5rem 1rem;
    border: 1px solid transparent;
    border-radius: var(--radius-m);
    background: var(--color-fill-quiet);
    color: var(--color-text);
    font: inherit;
    font-weight: var(--weight-semibold);
    line-height: 1.2;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.button:hover {
    background: var(--color-border-quiet);
}

.button.brand {
    background: var(--color-brand);
    color: var(--color-brand-text);
}

.button.brand:hover {
    background: var(--color-brand-hover);
}

.button.outlined {
    background: var(--color-surface);
    border-color: var(--color-border);
    color: var(--color-text);
}

.button.outlined:hover {
    background: var(--color-fill-quiet);
}

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

.button.outlined.danger:hover {
    background: var(--color-danger-quiet);
}

.button.plain {
    background: none;
    border-color: transparent;
    color: var(--color-text-quiet);
    padding: var(--space-2xs);
}

.button.plain:hover {
    background: var(--color-fill-quiet);
    color: var(--color-text);
}

.button.small {
    padding: 0.25rem 0.5rem;
    font-size: var(--font-size-s);
}

.button.plain.small {
    padding: var(--space-2xs);
}

.button:has(> app-icon:only-child) {
    padding-inline: 0.5rem;
}

.button.plain:has(> app-icon:only-child) {
    padding: var(--space-2xs);
}

/* --- form fields --- */
.field {
    display: grid;
    gap: var(--space-2xs);
}

.field-label {
    font-size: var(--font-size-s);
    font-weight: var(--weight-semibold);
}

.field-label .required {
    color: var(--color-danger);
    margin-inline-start: 0.15em;
}

.field-hint {
    font-size: var(--font-size-xs);
    color: var(--color-text-quiet);
}

.field input,
.field select,
.field textarea,
.input-group {
    width: 100%;
    padding: 0.5rem 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-m);
    background: var(--color-surface);
    color: inherit;
    font: inherit;
}

.field select {
    width: max-content;
    max-width: 100%;
}

.input-group {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    padding-inline-end: 0;
}

.input-group:focus-within {
    outline: var(--focus-ring);
    outline-offset: 2px;
}

.input-group input {
    flex: 1;
    min-width: 0;
    border: 0;
    padding: 0;
    background: none;
    border-radius: 0;
}

.input-group input:focus-visible {
    outline: none;
}

.input-prefix {
    color: var(--color-text-quiet);
    white-space: nowrap;
}

/* --- callouts --- */
.callout {
    padding: var(--space-s) var(--space-m);
    border: 1px solid var(--color-border-quiet);
    border-radius: var(--radius-m);
    background: var(--color-surface-sunken);
}

.callout.danger {
    border-color: var(--color-danger);
    background: var(--color-danger-quiet);
}

.callout.success {
    border-color: var(--color-success-border);
    background: var(--color-success-quiet);
}

.callout.warning {
    border-color: var(--color-warning-border);
    background: var(--color-warning-quiet);
}

.card {
    padding: var(--space-l);
    border: 1px solid var(--color-border-quiet);
    border-radius: var(--radius-l);
    background: var(--color-surface);
}

/* --- tables --- */
table {
    width: 100%;
    border-collapse: collapse;
}

table th {
    text-align: start;
    color: var(--color-text-quiet);
    font-weight: var(--weight-semibold);
    font-size: var(--font-size-s);
    padding: var(--space-xs) var(--space-s);
    border-bottom: 1px solid var(--color-border-quiet);
}

table td {
    vertical-align: middle;
    padding: var(--space-xs) var(--space-s);
    border-bottom: 1px solid var(--color-border-quiet);
}

.hover-rows tbody tr:hover {
    background: var(--color-fill-quiet);
}

/* A form that is one control and a button, inside a table cell. */
.inline-form {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs);
}

/* --- dropping files on a folder (files.rs, <app-dropzone>) --- */
app-dropzone {
    display: block;
    border-radius: var(--radius-m);
}

app-dropzone.dropping {
    outline: 2px dashed var(--color-brand);
    outline-offset: 4px;
    background: var(--color-brand-quiet);
}

app-dropzone.uploading {
    opacity: 0.5;
    cursor: progress;
}

/* Only said where it is true: with the script. */
.drop-hint {
    display: none;
    margin-top: var(--space-s);
    font-size: var(--font-size-s);
}

app-dropzone:defined .drop-hint {
    display: block;
}

/* --- a file that is not text (files/path.rs) --- */
.file-image {
    margin: var(--space-m) 0 0;
}

.file-image img {
    display: block;
    max-width: 100%;
    max-height: 70vh;
    border: 1px solid var(--color-border-quiet);
    border-radius: var(--radius-m);
    /* A checkerboard, so a transparent image shows where it is transparent. */
    background: repeating-conic-gradient(var(--color-fill-quiet) 0 25%, transparent 0 50%) 0 0 / 16px 16px;
}

.file-image figcaption {
    margin-top: var(--space-2xs);
    font-size: var(--font-size-s);
}

/* --- log viewer (src/components/log_viewer.rs) --- */
.log-filter {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-xs);
    margin-block-end: var(--space-m);
    font-size: var(--font-size-s);
}

/* With the script, the filter applies as it changes; the button is for without. */
app-filter:defined .log-filter button[type="submit"] {
    display: none;
}

.pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2xs);
    margin-block-start: var(--space-m);
}

/* Not a link: it does not answer to the pointer like the buttons beside it. */
.button.pager-current,
.button.pager-current:hover {
    color: var(--color-brand-text);
    background: var(--color-brand);
    cursor: default;
}

.log-table td {
    font-size: var(--font-size-s);
    vertical-align: top;
}

.log-path {
    overflow-wrap: anywhere;
}

/* Columns whose longest value is known never wrap, and are sized to it rather than
   to the page at hand, so they stay put from one page to the next. Widths are the
   longest value in a monospace `ch`: `MM-DD HH:MM:SS`, `ERROR` (the level shares
   the status column), `OPTIONS`, `same-origin`. */
.log-time,
.log-status,
.log-method,
.log-mode,
.log-ms {
    white-space: nowrap;
}

/* Content-box so the width is the value's and the padding comes on top. */
td.log-time,
td.log-status,
td.log-method,
td.log-mode {
    box-sizing: content-box;
}

td.log-time { width: 14ch; }
td.log-status { width: 5ch; }
td.log-method { width: 7ch; }
td.log-mode { width: 11ch; }

.log-failed td {
    background: var(--color-danger-quiet);
}

.log-detail {
    margin: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-size: var(--font-size-xs);
}

/* --- app shell (src/app/_app.rs) --- */
.app {
    min-height: 100vh;
    display: grid;
    grid-template-columns: 200px minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas:
        "header header"
        "nav main";
}

@media (max-width: 40rem) {
    .app {
        grid-template-columns: minmax(0, 1fr);
        /* Three rows here, not two: without this the nav inherits the wide layout's
           `1fr` and takes the whole screen. */
        grid-template-rows: auto auto minmax(0, 1fr);
        grid-template-areas:
            "header"
            "nav"
            "main";
    }
}

#app-topbar {
    grid-area: header;
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: var(--space-s) var(--space-l);
    border-bottom: 1px solid var(--color-border-quiet);
}

#app-topbar-title {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    font-size: var(--font-size-l);
    font-weight: var(--weight-semibold);
    color: inherit;
    text-decoration: none;
}

/* sovrio-logo.svg is 102x128, not square. */
#app-logo,
#guest-logo {
    height: 24px;
    width: auto;
}

#app-nav {
    grid-area: nav;
    display: flex;
    flex-direction: column;
    gap: var(--space-2xs);
    padding: var(--space-s);
    border-right: 1px solid var(--color-border-quiet);
}

@media (max-width: 40rem) {
    #app-nav {
        flex-direction: row;
        border-right: 0;
        border-bottom: 1px solid var(--color-border-quiet);
    }
}

#app-nav a {
    display: block;
    padding: var(--space-xs) var(--space-m);
    border-radius: var(--radius-pill);
    color: var(--color-text);
    text-decoration: none;
}

#app-nav a:hover {
    background: var(--color-fill-quiet);
}

#app-nav a[aria-current="page"] {
    background: var(--color-brand-quiet);
    color: var(--color-brand);
    font-weight: var(--weight-semibold);
}

#app-nav a[aria-current="page"]:hover {
    background: var(--color-brand-quiet-hover);
}

#app-main {
    grid-area: main;
    padding: var(--space-l);
}

/* --- menu --- */
app-menu {
    display: inline-flex;
}

.menu-popup {
    position-anchor: auto;
    top: calc(anchor(bottom) + var(--space-2xs));
    right: anchor(right);
    left: auto;
    bottom: auto;
    position-try-fallbacks: flip-inline;
    margin: 0;
    min-width: 12rem;
    padding: var(--space-2xs);
    border: 1px solid var(--color-border-quiet);
    border-radius: var(--radius-m);
    background: var(--color-surface);
    box-shadow: var(--shadow-raised);
}

.menu-header {
    margin: 0 0 var(--space-2xs);
    padding: var(--space-xs) var(--space-s);
    border-bottom: 1px solid var(--color-border-quiet);
    color: var(--color-text-quiet);
    font-size: var(--font-size-s);
    white-space: nowrap;
}

.menu-item {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    width: 100%;
    padding: var(--space-xs) var(--space-s);
    border: 0;
    border-radius: var(--radius-s);
    background: none;
    color: inherit;
    font: inherit;
    text-align: start;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
}

.menu-item:hover {
    background: var(--color-fill-quiet);
}

.menu-popup form {
    margin: 0;
}

.avatar {
    display: inline-flex;
    border: 0;
    padding: 0;
    font: inherit;
    cursor: pointer;
    align-items: center;
    justify-content: center;
    width: 2.25rem;
    height: 2.25rem;
    border-radius: var(--radius-pill);
    background: var(--color-fill-quiet);
    color: var(--color-text-quiet);
}

.avatar:hover {
    background: var(--color-border-quiet);
}

/* --- signed-out pages (login, register) --- */
#guest-header {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    padding: var(--space-m) var(--space-l);
    font-size: var(--font-size-l);
    font-weight: var(--weight-semibold);
}

#guest-main {
    display: flex;
    justify-content: center;
    padding: var(--space-2xl) var(--space-l);
}

.auth-card {
    width: 100%;
    max-width: 360px;
}

.auth-card h1 {
    margin-top: 0;
    font-size: var(--font-size-xl);
}

.auth-form {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: var(--space-m);
}

#register-done {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-s);
    text-align: center;
}

/* --- the site toolbar (sites/site_id.rs) --- */
/* Always above a site's screens: which site, and its tabs. */
.site-bar {
    display: flex;
    align-items: center;
    gap: var(--space-s);
    padding-block-end: var(--space-s);
    margin-block-end: var(--space-l);
    border-block-end: 1px solid var(--color-border-quiet);
}

.site-bar h1 {
    margin: 0;
    font-size: var(--font-size-xl);
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.site-bar .back {
    display: inline-flex;
    color: var(--color-text-quiet);
}

.site-tabs {
    display: flex;
    gap: var(--space-2xs);
    margin-inline-start: auto;
}

.site-tabs a {
    display: inline-flex;
    padding: var(--space-xs);
    border-radius: var(--radius-m);
    color: var(--color-text-quiet);
}

.site-tabs a:hover {
    background: var(--color-fill-quiet);
    color: var(--color-text);
}

.site-tabs a[aria-current="page"] {
    background: var(--color-brand-quiet);
    color: var(--color-brand);
}

/* Switching between siblings inside one screen -- the post types. */
.subnav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs);
    margin-block-end: var(--space-s);
}

.subnav a:not(.button) {
    padding: var(--space-2xs) var(--space-s);
    border-radius: var(--radius-m);
    color: var(--color-text-quiet);
    text-decoration: none;
}

.subnav a:not(.button):hover {
    background: var(--color-fill-quiet);
    color: var(--color-text);
}

.subnav a[aria-current="page"] {
    background: var(--color-brand-quiet);
    color: var(--color-brand);
}

/* The post body's editor: a toolbar over the surface Squire edits, or over the
   textarea when writing HTML. One box, so switching does not move the page. */
app-editor {
    display: grid;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-m);
    background: var(--color-surface);
}

.editor-toolbar {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2xs);
    padding: var(--space-2xs);
    border-bottom: 1px solid var(--color-border);
}

.editor-toolbar [data-command="html"] {
    margin-inline-start: auto;
}

.editor-toolbar [aria-pressed="true"] {
    background: var(--color-brand-quiet);
    color: var(--color-brand);
}

.editor-toolbar button:disabled {
    opacity: 0.4;
}

/* `.field` in front: its own rule for a textarea would otherwise win. */
.editor-surface,
.field app-editor textarea {
    min-height: 18rem;
    padding: var(--space-s) var(--space-m);
    border: 0;
    border-radius: 0 0 var(--radius-m) var(--radius-m);
}

.editor-surface {
    line-height: 1.8;
    outline: none;
}

.editor-surface:focus-visible {
    box-shadow: inset 0 0 0 2px var(--color-brand-quiet);
}

.editor-surface > :first-child {
    margin-top: 0;
}

.editor-surface h2 {
    font-size: var(--font-size-xl);
}

.editor-surface h3 {
    font-size: var(--font-size-l);
}

.editor-surface blockquote {
    margin-inline: 0;
    padding-inline-start: var(--space-m);
    border-inline-start: 3px solid var(--color-border);
    color: var(--color-text-quiet);
}

.editor-surface a {
    color: var(--color-brand);
}

.editor-surface img {
    max-width: 100%;
}

/* The forms inbox: one row per submission, across the page. */
.inbox-list {
    display: grid;
    border-top: 1px solid var(--color-border);
}

.inbox-item {
    display: grid;
    grid-template-columns: minmax(8rem, 12rem) minmax(0, 1fr) auto;
    align-items: baseline;
    gap: var(--space-m);
    padding: var(--space-xs) var(--space-s);
    border-bottom: 1px solid var(--color-border);
    color: var(--color-text);
    text-decoration: none;
}

.inbox-item:hover {
    background: var(--color-fill-quiet);
}

.inbox-item[aria-current="true"] {
    background: var(--color-brand-quiet);
}

/* Unread: the form's name in bold, after a dot. */
.inbox-item.unread .inbox-form {
    font-weight: var(--weight-semibold);
}

.inbox-item.unread .inbox-form::before {
    content: "";
    display: inline-block;
    width: 0.5em;
    height: 0.5em;
    margin-inline-end: var(--space-2xs);
    border-radius: 50%;
    background: var(--color-brand);
    vertical-align: middle;
}

.inbox-summary {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.inbox-time {
    color: var(--color-text-quiet);
    font-size: var(--font-size-s);
}

/* Narrow: the form and the time on one line, what was sent under them. */
@media (max-width: 40rem) {
    .inbox-item {
        grid-template-columns: minmax(0, 1fr) auto;
        gap: var(--space-2xs) var(--space-s);
    }

    .inbox-summary {
        grid-column: 1 / -1;
        grid-row: 2;
        color: var(--color-text-quiet);
        font-size: var(--font-size-s);
    }
}

/* A table that may be wider than the page scrolls on its own. */
.table-scroll {
    overflow-x: auto;
}

/* A form's submissions as a table: unread rows in bold, the opened one marked. */
.submissions-table td {
    white-space: nowrap;
}

.submissions-table tr.unread td {
    font-weight: var(--weight-semibold);
}

.submissions-table tr[aria-current="true"] td {
    background: var(--color-brand-quiet);
}

/* Something opened over the page: the page dimmed behind it, a click there being
   a way back. Fixed rather than a <dialog>, because the server opens it. */
.modal-backdrop {
    position: fixed;
    inset: 0;
    z-index: 20;
    background: var(--color-backdrop);
}

.modal {
    position: fixed;
    top: 50%;
    left: 50%;
    z-index: 21;
    display: grid;
    gap: var(--space-m);
    align-content: start;
    width: min(42rem, calc(100vw - 2 * var(--space-m)));
    max-height: calc(100vh - 2 * var(--space-xl));
    overflow-y: auto;
    padding: var(--space-l);
    border-radius: var(--radius-l);
    background: var(--color-surface);
    box-shadow: var(--shadow-raised);
    transform: translate(-50%, -50%);
}

/* One submission: each label over what was sent under it, kept as written. */
.submission {
    display: grid;
    grid-template-columns: minmax(8rem, max-content) minmax(0, 1fr);
    gap: var(--space-xs) var(--space-l);
    margin: 0;
}

.submission dt {
    color: var(--color-text-quiet);
}

.submission dd {
    margin: 0;
    white-space: pre-wrap;
    overflow-wrap: anywhere;
}

/* A filter, and -- when it is the one picked -- the button that edits what it names. */
.subnav-item {
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs);
}

/* Rows of small inputs under one set of column labels -- a post type's items. */
.field-grid {
    display: grid;
    gap: var(--space-2xs);
}

.field-row {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) 9rem 6rem;
    align-items: center;
    gap: var(--space-2xs);
}

.field-row-head {
    font-size: var(--font-size-s);
    color: var(--color-text-quiet);
}

.field-row input[type="text"],
.field-row select {
    width: 100%;
}

/* "+ 項目を追加": once open, the row takes the button's place. Only the first
   closed one is offered -- every one after a closed one is hidden -- so the next
   button appears under the row just opened. */
.field-more:not([open]) ~ .field-more {
    display: none;
}

/* A block, unlike other buttons, so the auto margin can push it to the right. */
.field-more > summary {
    display: flex;
    list-style: none;
    width: fit-content;
    margin-inline-start: auto;
    padding: var(--space-2xs);
}

.field-more > summary::-webkit-details-marker {
    display: none;
}

.field-more[open] > summary {
    display: none;
}


fieldset.field {
    margin: 0;
    padding: 0;
    border: 0;
}

/* A "?" whose words are its tooltip, drawn here rather than left to `title`, which
   browsers show late or not at all. Shown on hover and on keyboard focus. */
.help {
    position: relative;
    display: inline-flex;
    vertical-align: middle;
    padding: 0;
    border: 0;
    background: none;
    color: var(--color-text-quiet);
    cursor: help;
}

.help::after {
    content: attr(data-tip);
    position: absolute;
    top: calc(100% + var(--space-2xs));
    left: 0;
    z-index: 10;
    width: max-content;
    max-width: 22rem;
    padding: var(--space-xs) var(--space-s);
    border-radius: var(--radius-m);
    background: var(--color-text);
    color: var(--color-surface);
    font-size: var(--font-size-s);
    font-weight: var(--weight-normal);
    line-height: 1.6;
    text-align: start;
    white-space: normal;
    pointer-events: none;
    visibility: hidden;
}

.help:hover::after,
.help:focus-visible::after {
    visibility: visible;
}

/* A URL's fixed part beside the box for the part a person may change. */
.slug-row {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
}

.slug-row input {
    flex: 1;
}

/* The preview tab is the site under the toolbar, so it takes what is left. */
.preview-full {
    display: block;
    width: 100%;
    height: calc(100vh - 13rem);
    min-height: 24rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-m);
    background: var(--color-surface);
}

.page-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    gap: var(--space-m);
    flex-wrap: wrap;
    margin-block-end: var(--space-l);
}

.page-header .title {
    display: flex;
    align-items: center;
    gap: var(--space-s);
    min-width: 0;
}

.page-header h1 {
    margin: 0;
    font-size: var(--font-size-xl);
}

.page-header .back {
    display: inline-flex;
    color: var(--color-text-quiet);
    padding: var(--space-2xs);
    border-radius: var(--radius-m);
}

.page-header .back:hover {
    color: var(--color-text);
    background: var(--color-fill-quiet);
}

.page-header .back app-icon {
    width: 1.5em;
    height: 1.5em;
}

.actions {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    flex-wrap: wrap;
}

.actions form {
    display: contents;
}

.row-actions {
    justify-content: flex-end;
    flex-wrap: nowrap;
}

td.actions-cell,
th.actions-col {
    width: 1%;
    white-space: nowrap;
}

.danger-zone {
    margin-top: var(--space-2xl);
    padding-top: var(--space-m);
    border-top: 1px solid var(--color-border-quiet);
}

/* --- forms (sites/new.rs, site_id/edit.rs, site_id/new_file.rs) --- */
.form-panel {
    display: grid;
    gap: var(--space-l);
    max-width: 34rem;
}

.form-actions {
    display: flex;
    gap: var(--space-s);
}

/* --- file browser (sites/site_id/files.rs) --- */
.crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: var(--space-2xs);
    font-size: var(--font-size-l);
    font-weight: var(--weight-semibold);
    min-width: 0;
}

.crumbs a {
    color: var(--color-brand);
    text-decoration: none;
}

.crumbs a:hover {
    text-decoration: underline;
}

.crumbs .sep {
    color: var(--color-text-quiet);
    font-weight: var(--weight-normal);
}

.crumbs .current {
    color: var(--color-text);
    overflow-wrap: anywhere;
}

.tree {
    list-style: none;
    margin: 0;
    padding: 0;
    border: 1px solid var(--color-border-quiet);
    border-radius: var(--radius-m);
    overflow: hidden;
}

.tree-row {
    display: flex;
    align-items: center;
    gap: var(--space-s);
    padding: var(--space-2xs) var(--space-m);
    min-height: 2.5rem;
    border-top: 1px solid var(--color-border-quiet);
}

.tree-row:first-child,
.tree-empty:first-child {
    border-top: 0;
}

.tree-row:hover {
    background: var(--color-fill-quiet);
}

.tree-name {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    min-width: 0;
    color: inherit;
    text-decoration: none;
}

.tree-name:hover span {
    text-decoration: underline;
}

.tree-name app-icon {
    color: var(--color-text-quiet);
}

.tree-name span {
    overflow-wrap: anywhere;
}

.tree-meta {
    margin-inline-start: auto;
    display: inline-flex;
    align-items: center;
    gap: var(--space-2xs);
    color: var(--color-text-quiet);
    font-size: var(--font-size-s);
    white-space: nowrap;
}

.tree-empty {
    padding: var(--space-m);
    color: var(--color-text-quiet);
}

.site-notice {
    margin-block-end: var(--space-m);
}

/* --- chat (sites/site_id/chat/) --- */
.chat {
    display: grid;
    gap: var(--space-s);
    margin-bottom: var(--space-l);
}

.chat-line {
    padding: var(--space-s) var(--space-m);
    border-radius: var(--radius-m);
    background: var(--color-fill-quiet);
}

.chat-line.user {
    background: var(--color-brand-quiet);
}

.chat-line pre {
    margin: 0;
    font: inherit;
    white-space: pre-wrap;
}

/* The conversation and what it is proposing, side by side: reviewing a proposal is
   part of the conversation, so it should not be somewhere else. Stacks under 60rem,
   where there is no room for two columns. */
.chat-split {
    display: grid;
    gap: var(--space-l);
    grid-template-columns: minmax(0, 1fr);
}

.chat-pane {
    display: grid;
    gap: var(--space-s);
    align-content: start;
}

.preview-pane {
    display: grid;
    gap: var(--space-xs);
    align-content: start;
}

@media (min-width: 60rem) {
    .chat-split {
        /* Both columns are this tall, so the composer and the preview are both on
           screen at once and neither pushes the other down the page. */
        --pane: min(70vh, 760px);
        grid-template-columns: minmax(0, 5fr) minmax(0, 6fr);
        align-items: start;
    }

    .chat-split .chat {
        max-height: var(--pane);
        overflow-y: auto;
        padding-right: var(--space-xs);
    }

    .preview-pane {
        position: sticky;
        top: var(--space-l);
    }

    .preview-frame {
        height: var(--pane);
    }
}

.preview-head {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    flex-wrap: wrap;
}

.preview-head .actions {
    display: flex;
    align-items: center;
    gap: var(--space-2xs);
    margin-left: auto;
}

.preview-frame {
    width: 100%;
    height: min(70vh, 800px);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-m);
    background: var(--color-surface);
}

/* What the running turn is doing, inside the transcript. */
.chat-progress {
    display: grid;
    gap: var(--space-2xs);
    padding: var(--space-s) var(--space-m);
    border: 1px dashed var(--color-border-quiet);
    border-radius: var(--radius-m);
    color: var(--color-text-quiet);
}

.chat-progress p {
    margin: 0;
    white-space: pre-wrap;
}

.chat-discard {
    justify-self: end;
}

.composer {
    margin-top: var(--space-l);
}

app-composer {
    display: block;
    padding: var(--space-xs);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-l);
    background: var(--color-surface);
}

app-composer:focus-within {
    border-color: var(--color-brand);
}

app-composer.dropping {
    border-color: var(--color-brand);
    background: var(--color-brand-quiet);
}

app-composer textarea {
    display: block;
    width: 100%;
    /* The height is set by the element as you type; this is where it stops. */
    max-height: 40vh;
    padding: var(--space-xs) var(--space-s);
    border: 0;
    background: none;
    font: inherit;
    color: inherit;
    resize: none;
}

app-composer textarea:focus {
    outline: none;
}

.composer-actions {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: var(--space-2xs);
}

/* Clicking the label opens the picker; the input stays focusable so the keyboard
   can too, which is why it is clipped rather than display: none. */
.composer-actions label {
    position: relative;
    cursor: pointer;
}

.composer-actions label:focus-within {
    outline: var(--focus-ring);
    outline-offset: 2px;
    border-radius: var(--radius-m);
}

.composer-actions input[type="file"] {
    position: absolute;
    width: 1px;
    height: 1px;
    opacity: 0;
    pointer-events: none;
}

.composer-files {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    padding: var(--space-2xs) var(--space-s) var(--space-xs);
}

.composer-file {
    position: relative;
}

.composer-file img {
    display: block;
    width: 64px;
    height: 64px;
    object-fit: cover;
    border-radius: var(--radius-m);
    border: 1px solid var(--color-border-quiet);
}

.composer-file-remove {
    position: absolute;
    top: -6px;
    right: -6px;
    display: grid;
    place-items: center;
    width: 20px;
    height: 20px;
    padding: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius-pill);
    background: var(--color-surface);
    color: var(--color-text-quiet);
    font-size: var(--font-size-xs);
    cursor: pointer;
}

.composer-file-remove:hover {
    color: var(--color-text);
}

.composer-note {
    margin-top: var(--space-xs);
}

/* --- proposal review (sites/site_id/proposals/) --- */
.proposal-file + .proposal-file {
    margin-top: var(--space-l);
}

.proposal-file h3 {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    margin-bottom: var(--space-xs);
    font-size: var(--font-size-m);
}

.badge {
    padding: 0.1rem var(--space-xs);
    border-radius: var(--radius-s);
    background: var(--color-fill-quiet);
    font-size: var(--font-size-s);
    font-weight: var(--weight-normal);
}

/* A count beside a label: submissions nobody has read. */
.count {
    min-width: 1.25rem;
    padding: 0 0.25rem;
    border-radius: var(--radius-s);
    background: var(--color-brand);
    color: var(--color-brand-text);
    font-size: var(--font-size-s);
    line-height: 1.25rem;
    text-align: center;
}

/* Lines keep their leading +/-/space, so the gutter is the diff itself. */
.diff {
    max-height: 28rem;
    overflow: auto;
    padding: var(--space-s);
    border: 1px solid var(--color-border-quiet);
    border-radius: var(--radius-m);
    background: var(--color-fill-quiet);
    font-size: var(--font-size-s);
    line-height: 1.5;
    white-space: pre;
}

/* --- file editor (sites/site_id/files/path.rs) --- */
.rename-form {
    display: flex;
    align-items: center;
    gap: var(--space-s);
    flex-wrap: wrap;
    margin-block-end: var(--space-m);
}

.rename-form .input-group {
    flex: 1 1 20rem;
    max-width: 40rem;
    padding-block: 0.25rem;
    font-size: var(--font-size-s);
}

.rename-help {
    font-size: var(--font-size-xs);
}

.editor-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 22rem;
    gap: var(--space-l);
    align-items: start;
}

@media (max-width: 64rem) {
    .editor-layout {
        grid-template-columns: 1fr;
    }
}

#editor textarea {
    width: 100%;
    min-height: 65vh;
    font-family: var(--font-code);
    font-size: var(--font-size-s);
    line-height: 1.5;
    tab-size: 2;
    padding: var(--space-s);
    border: 1px solid var(--color-border);
    border-radius: var(--radius-m);
    background: var(--color-surface);
    color: inherit;
    resize: vertical;
}

.editor-help {
    font-size: var(--font-size-s);
    padding: var(--space-m);
    border: 1px solid var(--color-border-quiet);
    border-radius: var(--radius-m);
    background: var(--color-surface-sunken);
}

.editor-help h2 {
    font-size: var(--font-size-m);
    margin: 0 0 var(--space-xs);
}

.editor-help h2:not(:first-child) {
    margin-top: var(--space-l);
}

.editor-help p,
.editor-help ul {
    margin: 0 0 var(--space-s);
}

.editor-help pre {
    margin: 0 0 var(--space-s);
    padding: var(--space-xs) var(--space-s);
    border-radius: var(--radius-s);
    background: var(--color-surface);
    border: 1px solid var(--color-border-quiet);
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    font-size: var(--font-size-xs);
    user-select: all;
}


.editor-help details {
    margin-top: var(--space-l);
}

.editor-help summary {
    cursor: pointer;
    font-weight: var(--weight-semibold);
}

.editor-help .help-table td {
    padding: var(--space-2xs) var(--space-xs) var(--space-2xs) 0;
    vertical-align: top;
    border: 0;
}
