/* diagrams.rhys.wtf, in rhys.wtf's design language. The fonts, palette,
   tokens, dark scheme, header, toggle, apps mark and menu, section
   headings, footer and form controls are copied from profiles'
   static/main.css (itself from rhyswtf-rs/style/main.css): keep them in
   step. Diagrams' own parts are at the end. Recoleta is
   licensed for rhys.wtf sites only. */

@font-face {
    font-family: Recoleta;
    src: url('/static/Recoleta.woff2') format('woff2');
    font-display: swap;
}

@font-face {
    font-family: RecoletaBold;
    src: url('/static/RecoletaBold.woff2') format('woff2');
    font-display: swap;
}

@font-face {
    font-family: Figtree;
    src: url('/static/Figtree-Regular.woff2') format('woff2');
    font-display: swap;
}

@font-face {
    font-family: Lora-Italic;
    src: url('/static/Lora-Italic-VariableFont_wght.woff2') format('woff2');
    font-display: swap;
}

:root {
    /* The rhys.wtf type system: Recoleta Bold for headings, Recoleta for
       reading, Figtree for the interface, Lora Italic for the logo only. */
    --font-body: Recoleta, system-ui, -apple-system, sans-serif;
    --font-display: RecoletaBold, Recoleta, system-ui, sans-serif;
    --font-ui: Figtree, system-ui, -apple-system, sans-serif;
    --font-italic: Lora-Italic, Georgia, serif;

    /* Gruvbox light palette — https://github.com/morhetz/gruvbox */
    --gruvbox-bg0-hard: #f9f5d7;
    --gruvbox-bg0: #fbf1c7;
    --gruvbox-bg0-soft: #f2e5bc;
    --gruvbox-bg1: #ebdbb2;
    --gruvbox-bg2: #d5c4a1;
    --gruvbox-bg3: #bdae93;
    --gruvbox-bg4: #a89984;

    --gruvbox-fg0: #282828;
    --gruvbox-fg1: #3c3836;
    --gruvbox-fg2: #504945;
    --gruvbox-fg3: #665c54;
    --gruvbox-fg4: #7c6f64;

    --gruvbox-gray: #928374;

    --gruvbox-red: #cc241d;
    --gruvbox-green: #98971a;
    --gruvbox-yellow: #d79921;
    --gruvbox-blue: #458588;
    --gruvbox-purple: #b16286;
    --gruvbox-aqua: #689d6a;
    --gruvbox-orange: #d65d0e;

    --gruvbox-red-faded: #9d0006;
    --gruvbox-green-faded: #79740e;
    --gruvbox-yellow-faded: #b57614;
    --gruvbox-blue-faded: #076678;
    --gruvbox-purple-faded: #8f3f71;
    --gruvbox-aqua-faded: #427b58;
    --gruvbox-orange-faded: #af3a03;

    /* Semantic tokens — change these to retheme without touching components.
       They reference only the --gruvbox-* slots, which palettes.css (loaded
       after this file) redefines for each palette but Gruvbox: keep it so. */
    --color-bg: var(--gruvbox-bg0);
    --color-surface: var(--gruvbox-bg0-hard);
    --color-border: var(--gruvbox-fg0);
    --color-text: var(--gruvbox-fg1);
    --color-text-strong: var(--gruvbox-fg3);
    --color-muted: var(--gruvbox-fg3);
    --color-link: var(--gruvbox-fg1);
    --color-link-hover: var(--gruvbox-blue-faded);
    --color-error: var(--gruvbox-red-faded);
    /* Empty part of progress bars. */
    --color-track: var(--gruvbox-bg1);
    /* Glyphs on an accent fill (app icons), the same in both schemes.
       palettes.css sets it for each palette. */
    --color-on-accent: #fbf1c7;

    --spacing: 1rem;
    --radius: 1rem;

    /* Form controls and scrollbars follow the palette in each scheme. */
    color-scheme: light;

    /* Gruvbox dark palette, held here and applied by the two blocks below
       (once for the OS preference, once for the explicit choice) so the
       values exist in exactly one place. The plain accents are the same in
       both schemes, as in Gruvbox itself; the "faded" slots, which this
       stylesheet uses for emphasis, take the dark scheme's bright variants. */
    --gruvbox-dark-bg0-hard: #1d2021;
    --gruvbox-dark-bg0: #282828;
    --gruvbox-dark-bg0-soft: #32302f;
    --gruvbox-dark-bg1: #3c3836;
    --gruvbox-dark-bg2: #504945;
    --gruvbox-dark-bg3: #665c54;
    --gruvbox-dark-bg4: #7c6f64;
    --gruvbox-dark-fg0: #fbf1c7;
    --gruvbox-dark-fg1: #ebdbb2;
    --gruvbox-dark-fg2: #d5c4a1;
    --gruvbox-dark-fg3: #bdae93;
    --gruvbox-dark-fg4: #a89984;
    --gruvbox-dark-red-bright: #fb4934;
    --gruvbox-dark-green-bright: #b8bb26;
    --gruvbox-dark-yellow-bright: #fabd2f;
    --gruvbox-dark-blue-bright: #83a598;
    --gruvbox-dark-purple-bright: #d3869b;
    --gruvbox-dark-aqua-bright: #8ec07c;
    --gruvbox-dark-orange-bright: #fe8019;
}

/* Home hero, as rhys.wtf's greeting. */
.greeting {
    text-align: center;
    margin: 2rem 0 3rem;
}

.greeting__hello {
    font-family: var(--font-display);
    font-size: clamp(3rem, 12vw, 6rem);
    font-weight: normal;
    color: var(--color-text-strong);
    margin: 0;
    line-height: 1;
}

.greeting__welcome {
    font-family: var(--font-body);
    font-size: clamp(1.5rem, 5vw, 2.5rem);
    color: var(--color-text-strong);
    margin: 0.5rem 0 0;
}

/* Section heading: title and rule. */
.section-header {
    margin-bottom: 1rem;
}

.section-header__title {
    font-family: var(--font-display);
    font-size: 2rem;
    font-weight: normal;
    color: var(--color-text-strong);
    margin: 0 0 -0.25rem 0;
}

.section-header__rule {
    border: 0;
    border-top: 1px solid var(--color-border);
    margin: 0;
}

.narrow-form {
    max-width: 24rem;
}

input[type="text"],
input[type="email"],
input[type="password"],
input[type="number"],
input[type="time"],
select,
textarea {
    width: 100%;
    min-width: 0;
    padding: 0.5rem;
    font-size: 1rem;
    font-family: var(--font-ui);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
}

.prefixed {
    display: flex;
    align-items: stretch;
}

/* The prefix keeps its width and stays on one line ("/d/" would
   otherwise break at each slash); the input takes the rest of the row. */
.prefixed__prefix {
    flex: none;
    white-space: nowrap;
    display: flex;
    align-items: center;
    padding: 0 0.6rem;
    border: 1px solid var(--color-border);
    border-right: 0;
    border-radius: var(--radius) 0 0 var(--radius);
    background: var(--gruvbox-bg0-soft);
    color: var(--color-muted);
}

.prefixed input {
    flex: 1;
    width: auto;
    border-radius: 0 var(--radius) var(--radius) 0;
}

.list__item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    padding: 0.6rem 0;
    border-bottom: 1px solid var(--color-border);
}

.list__item form {
    margin: 0;
}

@media (max-width: 30rem) {
    .facts {
        grid-template-columns: 1fr;
    }

    .facts dd {
        margin-bottom: 0.4rem;
    }
}

/* ------------------------------------------------------------------ */
/* Diagrams' own parts.                                                 */

.narrow__subtitle {
    font-family: var(--font-display);
    font-weight: normal;
    font-size: 1.4rem;
    margin: 0 0 0.5rem;
}

.narrow--left {
    margin-left: 0;
}

.code-form {
    display: flex;
    gap: 0.5rem;
    max-width: 24rem;
}

.code-form input {
    flex: 1;
    min-width: 0;
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    letter-spacing: 0.08em;
    text-transform: uppercase;
}

.list-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
    margin-bottom: 0.75rem;
}

.list-head .page-title {
    min-width: 0;
    overflow-wrap: anywhere;
}

.list-head .page-title {
    margin: 0;
}

.list-head__end {
    display: flex;
    align-items: center;
    gap: 0.75rem 1rem;
    flex-wrap: wrap;
    font-family: var(--font-ui);
}

.diagram-list {
    list-style: none;
    margin: 0 0 2rem;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(16rem, 100%), 1fr));
    gap: 1rem;
}

.diagram-card {
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    height: 100%;
    padding: 1rem 1.25rem;
    border: 1px solid var(--color-border);
    border-top: 0.4rem solid var(--gruvbox-aqua-faded);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    text-decoration: none;
}

.diagram-card__thumb {
    display: block;
    aspect-ratio: 16 / 9;
    margin-bottom: 0.4rem;
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: calc(var(--radius) / 2);
    /* What shows until a diagram has a thumbnail. */
    background: var(--color-track);
}

.diagram-card__thumb img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* A portrait page's picture is the whole page, 3:4, at 60% of the
   card's width so it's not much taller than a landscape one. */
.diagram-card__thumb--portrait {
    aspect-ratio: 3 / 4;
    width: 60%;
    margin-inline: auto;
}

.diagram-card__title {
    font-family: var(--font-ui);
    font-size: 1.15rem;
    text-decoration: underline;
    text-underline-offset: 0.12em;
}

a.diagram-card:hover .diagram-card__title {
    color: var(--color-link-hover);
}

.diagram-card__meta {
    font-family: var(--font-ui);
    font-size: 0.95rem;
    color: var(--color-muted);
}

.badge {
    font-family: var(--font-ui);
    font-size: 0.8rem;
    color: var(--gruvbox-aqua-faded);
    border: 1px solid currentColor;
    border-radius: var(--radius);
    padding: 0 0.5rem;
}

.badge--public {
    color: var(--gruvbox-purple-faded);
}

a.badge {
    text-decoration: none;
}

a.badge:hover {
    background: var(--color-bg);
}

.settings__section {
    margin: 2.5rem 0;
}

/* The list page's header: a breadcrumb in a folder, the title with the
   view switch beside it, then New diagram, New folder and, to the right
   (below them on a narrow screen), watching with a code. */
.breadcrumbs {
    font-family: var(--font-ui);
    margin-bottom: 0.25rem;
}

.breadcrumbs ol {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.1rem 0.4rem;
    margin: 0;
    padding: 0;
}

.breadcrumbs li {
    min-width: 0;
    overflow-wrap: anywhere;
}

.breadcrumbs li + li::before {
    content: "›" / "";
    margin-right: 0.4rem;
    color: var(--color-muted);
}

.breadcrumbs [aria-current] {
    color: var(--color-muted);
}

.list-tools {
    /* The pop-ups below anchor here, not to their buttons, so they fit
       a phone's width. */
    position: relative;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem 1rem;
    flex-wrap: wrap;
    margin-bottom: 1.25rem;
}

.list-tools__new {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.list-tools form {
    margin: 0;
}

/* "New diagram" with its page shape, and changing an empty one's. */
.new-diagram {
    display: flex;
    align-items: center;
    gap: 0.35rem;
}

.new-diagram .new-diagram__shape {
    width: auto;
    padding: 0.2rem 0.4rem;
    font-size: 0.85rem;
}

.code-form--head {
    flex: none;
    max-width: none;
}

.code-form--head input {
    flex: none;
    width: 9.5rem;
    padding: 0.3rem 0.75rem;
}

/* Grid or list: two buttons in one outlined pill. */
.view-switch {
    display: inline-flex;
    margin: 0;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    overflow: hidden;
    background: var(--color-surface);
}

.view-switch__button {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 0.35rem 0.65rem;
    border: 0;
    background: transparent;
    color: var(--color-text);
    cursor: pointer;
}

.view-switch__button + .view-switch__button {
    border-left: 1px solid var(--color-border);
}

.view-switch__button:hover {
    background: var(--gruvbox-bg0-soft);
}

.view-switch__button[aria-pressed="true"] {
    background: var(--color-text);
    color: var(--color-surface);
}

.view-switch__button:focus-visible {
    outline: 2px solid var(--color-link-hover);
    outline-offset: -3px;
}

/* New folder and every item's "…": pop-ups like the canvas page's. */
.new-folder,
.item-menu {
    position: relative;
}

.new-folder {
    position: static;
}

.new-folder > summary,
.new-folder[open] > summary,
.item-menu > summary,
.item-menu[open] > summary {
    list-style: none;
    text-decoration: none;
    margin: 0;
}

.new-folder > summary::-webkit-details-marker,
.item-menu > summary::-webkit-details-marker,
.item-menu__confirm > summary::-webkit-details-marker {
    display: none;
}

.new-folder .share__panel {
    left: 0;
    width: min(22rem, 100%);
}

.item-menu__button {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.1rem;
    height: 2.1rem;
    border: 1px solid transparent;
    border-radius: 50%;
    font-family: var(--font-ui);
    font-size: 1.2rem;
    line-height: 1;
    cursor: pointer;
    color: var(--color-text);
}

.item-menu__button:hover,
.item-menu[open] > .item-menu__button {
    border-color: var(--color-border);
    background: var(--color-bg);
}

.item-menu__button:focus-visible {
    outline: 2px solid var(--color-link-hover);
}

.item-menu > .item-menu__panel {
    left: auto;
    right: 0;
    width: min(20rem, calc(100vw - 2rem));
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    font-family: var(--font-ui);
    cursor: auto;
}

/* Opened near the bottom of the window, upwards (the browser bundle
   decides: web/src/lib.rs). */
.item-menu--up > .item-menu__panel {
    top: auto;
    bottom: calc(100% + 0.4rem);
}

.item-menu__open {
    font-family: var(--font-ui);
}

.item-menu__form {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin: 0;
}

.item-menu__row {
    display: flex;
    gap: 0.5rem;
    align-items: center;
}

.item-menu__row input {
    flex: 1;
    padding: 0.3rem 0.75rem;
}

.item-menu__form select {
    padding: 0.35rem 0.5rem;
}

.item-menu__confirm > summary {
    margin: 0;
    color: var(--color-error);
}

.item-menu__confirm[open] > summary {
    margin-bottom: 0.5rem;
}

.item-menu__confirm form {
    margin: 0;
}

.item-menu__panel p {
    margin: 0 0 0.6rem;
}

/* Public or private, in the "…" menus: what it is, and the button. */
.public-form {
    align-items: flex-start;
    gap: 0.5rem;
}

.share__panel .public-form__state,
.item-menu__panel .public-form__state {
    margin: 0;
    font-family: var(--font-ui);
    font-size: 0.95rem;
}

.share__panel .canvas-bar__links {
    margin: 0.6rem 0 0;
    font-size: 0.95rem;
}

.canvas-bar__rule {
    border: 0;
    border-top: 1px solid var(--color-border);
    margin: 0.9rem 0;
}

.canvas-bar__public {
    font-size: 0.9rem;
    padding: 0.05rem 0.6rem;
}

/* A wall: someone's profile, then their public diagrams in one of three
   layouts, under tabs. */
.wall-own {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 1rem;
    align-items: baseline;
    margin: 0 0 1.25rem;
    font-family: var(--font-ui);
}

.wall-own__note {
    color: var(--color-muted);
    font-size: 0.95rem;
}

.wall-head {
    display: flex;
    gap: 1.25rem;
    align-items: flex-start;
    margin: 0 0 1.75rem;
}

.wall-head__avatar {
    flex: none;
    width: 7rem;
    height: 7rem;
    border-radius: 50%;
    border: 1px solid var(--color-border);
    object-fit: cover;
    background: var(--color-track);
}

.wall-head__avatar--initial {
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: var(--font-display);
    font-size: 3rem;
    color: var(--color-muted);
    user-select: none;
}

.wall-head__text {
    min-width: 0;
    padding-top: 0.4rem;
}

.wall-head__name {
    margin: 0;
    font-family: var(--font-display);
    font-weight: normal;
    font-size: 2.2rem;
    line-height: 1.15;
    overflow-wrap: anywhere;
}

.wall-head__handle {
    margin: 0.15rem 0 0;
    font-family: var(--font-ui);
}

.wall-head__handle a {
    color: var(--color-muted);
}

.wall-head__bio {
    margin: 0.6rem 0 0;
    max-width: 40rem;
    /* Their line breaks, as on their profile. */
    white-space: pre-line;
    overflow-wrap: anywhere;
}

.wall-tabs {
    display: flex;
    gap: 0.25rem;
    margin: 0 0 1.5rem;
    border-bottom: 1px solid var(--color-border);
    font-family: var(--font-ui);
}

.wall-tabs__tab {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    padding: 0.45rem 0.9rem;
    margin-bottom: -1px;
    border: 1px solid transparent;
    border-radius: calc(var(--radius) / 2) calc(var(--radius) / 2) 0 0;
    color: var(--color-muted);
    text-decoration: none;
}

.wall-tabs__tab:hover {
    color: var(--color-link-hover);
}

.wall-tabs__tab[aria-current="page"] {
    border-color: var(--color-border);
    border-bottom-color: var(--color-bg);
    background: var(--color-bg);
    color: var(--color-text);
}

.wall-tabs__tab:focus-visible {
    outline: 2px solid var(--color-link-hover);
    outline-offset: -3px;
}

/* Large: one post per diagram, a column of them. */
.wall-posts {
    list-style: none;
    margin: 0 auto 2rem;
    padding: 0;
    max-width: 900px;
    display: flex;
    flex-direction: column;
    gap: 2rem;
}

.wall-post__link {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 1rem 1rem 1.1rem;
    border: 1px solid var(--color-border);
    border-top: 0.4rem solid var(--gruvbox-purple-faded);
    border-radius: var(--radius);
    background: var(--color-surface);
    color: var(--color-text);
    text-decoration: none;
}

.wall-post__image {
    display: block;
    aspect-ratio: 16 / 9;
    margin-bottom: 0.5rem;
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: calc(var(--radius) / 2);
    background: var(--color-track);
}

.wall-post__image img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* A portrait page, 3:4: narrower, so all of it fits on a screen. */
.wall-post__image--portrait {
    aspect-ratio: 3 / 4;
    width: min(100%, 34rem);
    align-self: center;
}

.wall-post__title {
    font-family: var(--font-display);
    font-size: 1.6rem;
    line-height: 1.2;
    text-decoration: underline;
    text-underline-offset: 0.12em;
    overflow-wrap: anywhere;
}

a.wall-post__link:hover .wall-post__title {
    color: var(--color-link-hover);
}

.wall-post__meta {
    font-family: var(--font-ui);
    font-size: 0.95rem;
    color: var(--color-muted);
}

/* Grid and list on a wall: the owner's, without the "…" menus. */
.items--public .diagram-card__meta {
    padding-right: 0;
}

.items--public.items--list .row__link {
    grid-template-columns: 4rem minmax(0, 1fr) 8rem 9.5rem;
}

.wall-pages {
    display: flex;
    justify-content: space-between;
    gap: 1rem;
    margin: 0 auto 2rem;
    max-width: 900px;
    font-family: var(--font-ui);
}

.wall-pages__older {
    margin-left: auto;
}

@media (max-width: 40rem) {
    .wall-head {
        gap: 1rem;
    }

    .wall-head__avatar {
        width: 4.5rem;
        height: 4.5rem;
    }

    .wall-head__avatar--initial {
        font-size: 2rem;
    }

    .wall-head__name {
        font-size: 1.7rem;
    }

    .wall-head__text {
        padding-top: 0.1rem;
    }

    .wall-post__link {
        padding: 0.6rem 0.6rem 0.8rem;
    }

    .wall-post__title {
        font-size: 1.3rem;
    }

    .wall-tabs__tab {
        padding: 0.4rem 0.7rem;
    }

    .items--public.items--list .row__link {
        grid-template-columns: 4rem minmax(0, 1fr);
    }
}

.move-page {
    margin: 1rem 0;
}

/* The items, in whichever view. An open menu sits above everything
   after it. */
.items {
    list-style: none;
    margin: 0 0 2rem;
    padding: 0;
}

.item {
    position: relative;
    min-width: 0;
}

.item:has(.item-menu[open]) {
    z-index: 30;
}

/* Grid: cards, the "…" in the bottom-right corner, beside the meta. */
.items--grid .item-menu {
    position: absolute;
    right: 0.75rem;
    bottom: 0.7rem;
}

.items--grid .diagram-card__meta {
    padding-right: 2.25rem;
}

/* Each row of cards shares three tracks, pictures, titles and details,
   so a landscape picture beside a portrait one sits in the middle of
   the taller track, and the titles line up. */
.items--grid > .item {
    display: grid;
    grid-row: span 3;
    grid-template-rows: subgrid;
}

.items--grid .diagram-card {
    display: grid;
    grid-row: span 3;
    grid-template-rows: subgrid;
    row-gap: 0.4rem;
}

.items--grid .diagram-card__thumb {
    align-self: center;
}

.diagram-card__title {
    overflow-wrap: anywhere;
}

.diagram-card--folder {
    border-top-color: var(--gruvbox-yellow-faded);
}

.diagram-card__thumb--folder {
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--gruvbox-yellow-faded);
    background: var(--color-bg);
}

/* List: rows under a rule. */
.row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    border-bottom: 1px solid var(--color-border);
}

.items--list .row:first-child {
    border-top: 1px solid var(--color-border);
}

.row__link {
    flex: 1;
    min-width: 0;
    display: grid;
    align-items: center;
    gap: 0 1rem;
    padding: 0.5rem 0.25rem;
    color: var(--color-text);
    text-decoration: none;
    font-family: var(--font-ui);
}

.row__title {
    min-width: 0;
    font-family: var(--font-ui);
    font-size: 1.05rem;
    text-decoration: underline;
    text-underline-offset: 0.12em;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

a.row__link:hover .row__title {
    color: var(--color-link-hover);
}

.row__pages,
.row__edited {
    color: var(--color-muted);
    font-size: 0.95rem;
    white-space: nowrap;
}

.row__meta {
    display: contents;
}

.items--list .row__link {
    grid-template-columns: 4rem minmax(0, 1fr) 8rem 9.5rem 4.5rem;
}

.row__icon {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 4rem;
    height: 2.25rem;
    overflow: hidden;
    border: 1px solid var(--color-border);
    border-radius: 0.35rem;
    background: var(--color-track);
}

.row__icon img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* A portrait page's: as tall, 3:4, in the middle of the same 4rem. */
.row__icon--portrait {
    width: 1.6875rem;
    margin-inline: 1.15625rem;
}

.row__icon--folder {
    border-color: transparent;
    background: transparent;
    color: var(--gruvbox-yellow-faded);
}

.empty {
    margin: 2rem 0;
}

.empty__actions {
    align-items: center;
}

.empty__folder {
    display: flex;
    gap: 0.5rem;
}

.empty__folder input {
    width: 12rem;
    padding: 0.3rem 0.75rem;
}

@media (max-width: 40rem) {
    /* Narrow: the title on its own line, the details under it. */
    .items--list .row__link {
        grid-template-columns: 4rem minmax(0, 1fr);
    }

    .items--list .row__icon {
        grid-row: span 2;
    }

    .items--list .row__meta {
        display: flex;
        flex-wrap: wrap;
        gap: 0 0.6rem;
        align-items: center;
    }

    .items--list .row__edited:empty,
    .items--list .row__shared:empty {
        display: none;
    }
}

/* The drawing and watching pages: header, a slim bar, then the canvas
   filling the rest of the window. */
body.canvas-page {
    height: 100vh;
    height: 100dvh;
    min-height: 0;
    /* Clipped, not `hidden`: a hidden page is still scrolled by a focus
       or an anchor, which moved the whole layout up out of the window,
       leaving bare background under it, with no way to scroll it back.
       A clipped one can't be scrolled at all, and being positioned it
       clips the absolutely positioned bits inside it too. The regions
       inside it (the pages, the comments drawer) scroll instead. */
    position: relative;
    overflow: hidden;
    overflow: clip;
}

/* Its own overflow on the root, so the body's isn't carried up to the
   window (where `clip` would count as `hidden` again). */
html:has(> body.canvas-page) {
    overflow: hidden;
}

.canvas-page .site-header__title {
    font-size: 2.2rem;
}

.canvas-main {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

.canvas-bar {
    display: flex;
    align-items: center;
    gap: 0.75rem;
    flex-wrap: wrap;
    padding: 0.4rem 1rem 0.6rem;
    font-family: var(--font-ui);
    border-bottom: 1px solid var(--color-border);
}

.canvas-bar__back {
    white-space: nowrap;
}

.canvas-bar__title {
    display: flex;
    gap: 0.5rem;
    flex: 1;
    min-width: min(100%, 16rem);
    max-width: 32rem;
    margin: 0;
}

.canvas-bar__title input {
    flex: 1;
    min-width: 0;
    padding: 0.3rem 0.75rem;
    font-family: var(--font-display);
    font-size: 1.1rem;
}

.canvas-bar__watching strong {
    font-family: var(--font-display);
}

.share,
.canvas-bar__more {
    position: relative;
}

.share > summary,
.canvas-bar__more > summary,
.share[open] > summary,
.canvas-bar__more[open] > summary {
    list-style: none;
    text-decoration: none;
    /* Including when open: the site's `details[open] summary` margin
       would otherwise lift the button in the bar. */
    margin: 0;
}

.share > summary::-webkit-details-marker,
.canvas-bar__more > summary::-webkit-details-marker {
    display: none;
}

.share__panel {
    position: absolute;
    left: 0;
    top: calc(100% + 0.4rem);
    z-index: 25;
    width: min(24rem, 90vw);
    padding: 1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.15);
}

.canvas-bar__more .share__panel {
    left: auto;
    right: 0;
}

.share__panel p {
    margin: 0 0 0.75rem;
}

.share__code {
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: 1.8rem;
    letter-spacing: 0.12em;
    text-align: center;
    color: var(--gruvbox-aqua-faded);
}

.share__link {
    width: 100%;
    margin: 0.25rem 0 0.75rem;
    font-size: 0.9rem;
}

.inline-actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.inline-actions form {
    margin: 0;
}

/* The drawing app (client/), restyled from the proof of concept in the
   site's tokens. Ids and classes are the client's contract. */
#app {
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
    font-family: var(--font-ui);
}

.pages-area {
    position: relative;
    flex: 1;
    min-height: 0;
    display: flex;
    flex-direction: column;
}

#pages {
    flex: 1;
    min-height: 0;
    overflow: auto;
    /* Room for the scrollbar always, so Fit's measured width doesn't
       change when one appears. */
    scrollbar-gutter: stable;
    display: flex;
    flex-direction: column;
    /* Not `center`: a page zoomed wider than the window would overflow
       to the left too, where it can't be scrolled to. Pages centre
       themselves with auto margins instead. */
    align-items: flex-start;
    gap: 28px;
    padding: 24px;
    background: var(--gruvbox-bg1);
}

/* A drawing's page. Scoped to #pages so it beats the site's own `.page`
   layout rule (900px wide, padded), which also matches these sections. */
#pages .page {
    display: flex;
    flex-direction: column;
    gap: 6px;
    /* --page-width is set by the zoom control (client/src/zoom.rs); until
       it runs, pages fill the width. */
    width: var(--page-width, min(100%, 1800px));
    max-width: none;
    padding: 0;
    margin: 0 auto;
    flex: none;
}

/* Zoom: −, the level, +, Fit; at the end of the bar above the canvas. */
.zoom {
    display: flex;
    align-items: center;
    gap: 2px;
    font-family: var(--font-ui);
}

.zoom button,
.canvas-bar .follow {
    font: inherit;
    font-size: 0.85rem;
    color: var(--color-text);
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: 0.4rem;
    padding: 0.2rem 0.55rem;
    cursor: pointer;
    min-width: 2rem;
}

.zoom button:hover,
.canvas-bar .follow:hover {
    border-color: var(--color-muted);
}

.zoom .zoom__level {
    min-width: 3.6rem;
    font-variant-numeric: tabular-nums;
}

.zoom .zoom__fit {
    margin-left: 4px;
}

.zoom .zoom__fit[aria-pressed="true"],
.canvas-bar .follow[aria-pressed="true"] {
    background: var(--gruvbox-aqua-faded);
    border-color: var(--gruvbox-aqua-faded);
    color: var(--color-bg);
}

.page-bar {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 10px;
    font-size: 0.8rem;
    color: var(--color-muted);
}

.page canvas {
    display: block;
    width: 100%;
    /* Set on <body> by the canvas theme selector. */
    background: var(--canvas-bg, #ffffff);
    touch-action: none;
    border-radius: 0.4rem;
    box-shadow: 0 0 0 1px var(--color-border);
}

body.drawer .page canvas {
    cursor: none;
}

/* A page's background (client/src/pages.rs): a picture under the canvas,
   the size of it. A light canvas multiplies it, so its white is the
   canvas colour; a dark one inverts and screens it, so its black is
   (--bg-filter and --bg-blend come with the canvas theme). */
/* Its form, in the drawing's "…" menu: page numbers are short. */
.background-form .item-menu__row input[type="number"] {
    flex: 0 0 4.5rem;
}

.page .sheet {
    position: relative;
    border-radius: 0.4rem;
    isolation: isolate;
}

.page .sheet:has(> .bg) {
    background: var(--canvas-bg, #ffffff);
}

.page .sheet > .bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border-radius: 0.4rem;
    pointer-events: none;
    user-select: none;
    filter: var(--bg-filter, none);
    mix-blend-mode: var(--bg-blend, normal);
}

.page .sheet > .bg + canvas {
    position: relative;
    background: transparent;
}

/* Viewers don't draw, so touch scrolls (and pinches) over a canvas as
   anywhere else. */
body:not(.drawer) .page canvas {
    touch-action: auto;
}

.cursor-indicator {
    position: fixed;
    pointer-events: none;
    transform: translate(-50%, -50%);
    border: 1.5px solid rgba(255, 255, 255, 0.95);
    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.75);
    z-index: 20;
}

.cursor-indicator.circle { border-radius: 50%; }
.cursor-indicator.square { border-radius: 3px; }
.cursor-indicator.hidden { display: none; }

#status {
    position: absolute;
    bottom: 1rem;
    left: 1rem;
    display: flex;
    align-items: center;
    gap: 6px;
    font-size: 0.8rem;
    padding: 4px 12px;
    border-radius: 999px;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    color: var(--color-text);
    user-select: none;
    pointer-events: none;
    z-index: 30;
}

#status .dot {
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: var(--gruvbox-red-faded);
    transition: background 0.2s ease;
}

#status.connected .dot {
    background: var(--gruvbox-green-faded);
}

/* The bottom bar: drawing tools on the left (drawer only), save options
   on the right. */
.bottom-bar {
    display: flex;
    align-items: center;
    gap: 14px;
    padding: 8px 16px;
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
}

#toolbar {
    flex: 1;
    min-width: 0;
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

#toolbar.hidden {
    display: none;
}

.swatches {
    display: flex;
    gap: 6px;
}

.swatch {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    /* Swatches come from very different palettes, some close to the
       panel's own colour, so the ring has to show regardless. */
    border: 2px solid var(--gruvbox-bg3);
    cursor: pointer;
    padding: 0;
}

.swatch.selected {
    border-color: var(--color-border);
    box-shadow: 0 0 0 2px var(--color-surface), 0 0 0 3px var(--color-border);
}

.current-color {
    display: inline-block;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    border: 2px solid var(--color-border);
    flex-shrink: 0;
}

.current-color.erasing {
    background: repeating-linear-gradient(45deg, #888 0 4px, #555 4px 8px);
}

.group {
    display: flex;
    align-items: center;
    gap: 8px;
}

#toolbar input[type="color"] {
    width: 30px;
    height: 30px;
    padding: 0;
    border: none;
    background: none;
    cursor: pointer;
}

#toolbar input[type="range"] {
    width: 110px;
    accent-color: var(--gruvbox-aqua-faded);
}

#toolbar button,
.save-menu__panel button,
.save-menu__panel select,
.canvas-theme,
.page-bar button {
    font-family: var(--font-ui);
    font-size: 0.9rem;
    background: var(--color-bg);
    color: var(--color-text);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 5px 14px;
    cursor: pointer;
}

.page-bar button {
    font-size: 0.8rem;
    padding: 2px 10px;
}

#toolbar button:hover,
.save-menu__panel button:hover,
.page-bar button:hover {
    background: var(--gruvbox-bg0-soft);
}

#toolbar button.active {
    background: var(--gruvbox-aqua-faded);
    border-color: var(--gruvbox-aqua-faded);
    color: var(--gruvbox-bg0-hard);
}

#toolbar button.danger:hover,
.page-bar button.danger:hover {
    background: var(--color-error);
    color: var(--color-bg);
}

#toolbar button:disabled,
.save-menu__panel button:disabled,
.save-menu__panel select:disabled {
    opacity: 0.4;
    cursor: default;
}

/* Icon buttons: Eraser, Undo, Redo, Add page. */
#toolbar .icon-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    padding: 5px 9px;
}

.icon {
    display: block;
    flex-shrink: 0;
}

/* Save options: a button showing the format, opening a panel above it. */
.save-menu {
    position: relative;
    margin-left: auto;
    flex-shrink: 0;
}

.save-menu__button {
    display: flex;
    align-items: center;
    gap: 6px;
    list-style: none;
    font-family: var(--font-ui);
    font-size: 0.9rem;
    color: var(--color-text);
    background: var(--color-bg);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    padding: 5px 14px;
    cursor: pointer;
    white-space: nowrap;
}

.save-menu > summary.save-menu__button,
.save-menu[open] > summary.save-menu__button {
    margin: 0;
    text-decoration: none;
}

.save-menu__button::-webkit-details-marker {
    display: none;
}

.save-menu__button:hover {
    background: var(--gruvbox-bg0-soft);
}

.save-menu__panel {
    position: absolute;
    right: 0;
    bottom: calc(100% + 0.5rem);
    z-index: 25;
    display: grid;
    grid-template-columns: auto 1fr;
    align-items: center;
    gap: 10px 12px;
    width: max-content;
    max-width: 90vw;
    padding: 1rem;
    background: var(--color-surface);
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    box-shadow: 0 0.5rem 1.5rem rgba(0, 0, 0, 0.15);
}

.save-menu__wide {
    grid-column: 1 / -1;
}

/* The owner's menu is a form (export.rs): Download and Save to Files side
   by side, and under them the frame that says where it was saved. */
.save-menu__actions {
    display: flex;
    gap: 8px;
}

.save-menu__actions button {
    flex: 1;
}

.save-menu__result {
    display: block;
    width: 100%;
    max-width: 20rem;
    height: 3.2rem;
    border: 0;
    background: transparent;
}

/* Backgrounds in the file: a choice for Diagrams JSON only; transparency
   for the pictures it can mean something for. */
.save-menu__panel:not(:has(#export-format option[value="json"]:checked)) .save-menu__backgrounds,
.save-menu__panel:has(#export-format :is(option[value="jpeg"], option[value="pdf"], option[value="json"], option[value="xopp"], option[value="rnote"]):checked) .save-menu__transparent {
    display: none;
}

body.frame:has(.export-result) {
    background: var(--color-surface);
}

body.frame .export-result {
    margin: 0;
    font-family: var(--font-ui);
    font-size: 0.85rem;
    overflow-wrap: anywhere;
}

body.frame .export-result--hint {
    color: var(--color-muted);
}

body.frame .export-result--error {
    color: var(--gruvbox-red, #cc241d);
}

/* The canvas theme, beside the zoom in the bar above the canvas. */
.canvas-bar__view {
    display: flex;
    align-items: center;
    gap: 10px;
    margin-left: auto;
}

.canvas-theme {
    padding: 0.2rem 0.6rem;
    font-size: 0.85rem;
}

label.small {
    font-size: 0.8rem;
    color: var(--color-muted);
}

label.toggle {
    display: flex;
    align-items: center;
    gap: 5px;
    cursor: pointer;
}

#toast {
    position: fixed;
    bottom: 120px;
    left: 50%;
    transform: translateX(-50%);
    background: var(--color-text);
    color: var(--color-bg);
    padding: 8px 16px;
    border-radius: var(--radius);
    font-size: 0.9rem;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s ease;
    z-index: 40;
}

#toast.visible {
    opacity: 1;
}

@media (max-width: 40rem) {
    .bottom-bar,
    #toolbar {
        gap: 8px;
    }

    .bottom-bar {
        padding: 6px 10px;
    }
}

/* A diagram's picture in the formats it comes in: the <img> inside is
   what's laid out, as if the <picture> weren't there. */
picture { display: contents; }

/* Comments (comments.rhys.wtf's thread, styled by static/comments.css):
   a drawer along the bottom of the canvas page, closed until wanted so
   it takes no canvas space; and the "💬 n" in lists. */
.comments-drawer {
    flex: 0 0 auto;
    display: flex;
    flex-direction: column;
    min-height: 0;
    border-top: 1px solid var(--color-border);
    font-family: var(--font-ui);
    background: var(--color-bg);
}

/* At most half the canvas page's column while reading, three quarters
   while writing in it (a reply, a quote or an edit, with script or
   without). */
.comments-drawer[open] {
    max-height: 50%;
}

.comments-drawer[open]:focus-within,
.comments-drawer[open]:has(#comment-form:target, .comment-form--edit) {
    max-height: 75%;
}

/* Everything in a <details> but its summary is in one box of its own
   (::details-content), which isn't a flex item of the drawer's unless
   it's told to be: without this the thread, however long, spilled out of
   the drawer and off the page instead of scrolling inside it. */
.comments-drawer::details-content {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
}

.comments-drawer__summary {
    padding: 0.4rem 1rem;
    cursor: pointer;
    list-style: none;
    font-size: 0.95rem;
}

.comments-drawer__summary::-webkit-details-marker {
    display: none;
}

.comments-drawer[open] > .comments-drawer__summary {
    margin: 0;
    border-bottom: 1px solid var(--color-track);
}

.comments-drawer__body {
    flex: 1 1 auto;
    min-height: 0;
    /* A cap of its own too, for a browser without ::details-content. */
    max-height: 70vh;
    max-height: 70dvh;
    overflow-y: auto;
    overscroll-behavior: contain;
    /* What's absolutely positioned in the thread (its visually hidden
       labels) is positioned, and clipped, in here, not on the page. */
    position: relative;
    padding: 0.75rem 1rem 1.25rem;
}

.comments-drawer__unavailable {
    margin: 0;
    color: var(--color-muted);
}

.canvas-bar__comments {
    white-space: nowrap;
}

.comment-bubble {
    width: 1em;
    height: 1em;
    vertical-align: -0.15em;
    margin-right: 0.3em;
}

.comment-count {
    white-space: nowrap;
    color: var(--color-muted);
}

/* Settings: the feed's addresses, to copy into a reader. */
.feed-settings {
    max-width: 40rem;
    margin-bottom: 2rem;
}

.feed-settings__url {
    display: block;
    width: 100%;
    margin: 0.25rem 0 0.75rem;
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: 0.85rem;
}

.feed-settings__note {
    font-size: 0.9rem;
    color: var(--color-muted);
}

/* Settings: the devices signed in, each with its sign-out. */
.devices {
    list-style: none;
    padding: 0;
    margin: 0;
}

.devices__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.25rem 1rem;
    padding: 0.5rem 0;
    border-bottom: 1px solid var(--color-border);
}

.devices__when {
    flex: 1 1 14rem;
    font-size: 0.9rem;
    color: var(--color-muted);
}

/* History and the trash: what's said first, under the title. */
.history__intro {
    max-width: 44rem;
    margin: 0 0 1.5rem;
    color: var(--color-muted);
}

/* History: a card per version, its picture, when, and the two ways to
   restore it. */
.version__card {
    border-top-color: var(--gruvbox-blue-faded);
}

.version__when {
    font-family: var(--font-ui);
    font-size: 1.1rem;
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 0.5rem;
    align-items: center;
}

.version__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    align-items: center;
    margin-top: auto;
    padding-top: 0.4rem;
    font-family: var(--font-ui);
}

.version__actions form {
    margin: 0;
}

.version__confirm,
.trash-item__confirm,
.trash__empty {
    font-family: var(--font-ui);
}

.version__confirm > summary,
.trash-item__confirm > summary {
    list-style: none;
    cursor: pointer;
    text-decoration: underline;
    text-underline-offset: 0.12em;
}

.version__confirm > summary::-webkit-details-marker,
.trash-item__confirm > summary::-webkit-details-marker,
.trash__empty > summary::-webkit-details-marker {
    display: none;
}

.version__confirm[open] {
    flex-basis: 100%;
}

.version__confirm p,
.trash-item__confirm p,
.trash__empty p {
    margin: 0 0 0.5rem;
    font-size: 0.95rem;
}

/* The trash: a row per thing, its buttons at the end (under it, on a
   narrow screen). */
.trash-item {
    flex-wrap: wrap;
    gap: 0.4rem 1rem;
    padding: 0.6rem 0.25rem;
    font-family: var(--font-ui);
}

.trash-item__icon {
    flex: none;
}

.trash-item__text {
    flex: 1 1 14rem;
    min-width: 0;
    display: flex;
    flex-direction: column;
}

.trash-item__title {
    font-size: 1.05rem;
    overflow-wrap: anywhere;
}

.trash-item__meta {
    color: var(--color-muted);
    font-size: 0.9rem;
}

.trash-item__actions {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    align-items: center;
}

.trash-item__actions form {
    margin: 0;
}

.trash__empty,
.trash-item__confirm {
    position: relative;
}

.trash__empty > summary {
    list-style: none;
    color: var(--color-error);
}

.trash__empty[open] form,
.trash-item__confirm[open] form {
    position: absolute;
    right: 0;
    top: calc(100% + 0.4rem);
    z-index: 20;
    width: min(18rem, calc(100vw - 2rem));
    padding: 0.9rem 1rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
}

@media (max-width: 40rem) {
    .trash-item__actions {
        flex-basis: 100%;
        padding-left: 4.5rem;
    }
}

/* An admin reading someone's diagrams (src/admin_view.rs): who's they
   are, read-only, recorded; above the list, or the canvas's bar. */
.admin-banner {
    margin: 0 0 1rem;
    padding: .6rem 1rem;
    border: 2px solid var(--gruvbox-orange-faded);
    border-radius: 1rem;
    background: var(--color-surface);
    color: var(--color-text);
    font-family: var(--font-ui);
    font-weight: bold;
}

.canvas-main > .admin-banner {
    flex: none;
    margin: .5rem var(--spacing) 0;
}

/* Transcripts (/d/<id>/transcript): the status, Transcribe, the text to
   edit, and "Make a note". */
.transcript {
    max-width: 48rem;
    margin-bottom: 2rem;
}

.transcript__status {
    margin: 0 0 0.75rem;
}

.transcript-status[data-status="queued"],
.transcript-status[data-status="running"],
.transcript-status[data-status="stale"] {
    color: var(--gruvbox-yellow-faded);
}

.transcript-status[data-status="failed"] {
    color: var(--color-error);
}

.transcript-status[data-status="none"] {
    color: var(--color-muted);
}

.transcript__note {
    font-family: var(--font-ui);
    font-size: 0.9rem;
    color: var(--color-muted);
}

.transcript__run {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
    margin: 0 0 1rem;
}

.transcript__run input[type="text"] {
    width: auto;
    flex: 1 1 12rem;
    max-width: 20rem;
}

.transcript__edit {
    display: grid;
    gap: 0.5rem;
    justify-items: start;
}

.transcript__edit textarea,
.transcript__style,
.transcript__text {
    width: 100%;
    font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
    font-size: 0.9rem;
    line-height: 1.45;
}

.transcript__text {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
    padding: 0.75rem;
    border: 1px solid var(--color-border);
    border-radius: var(--radius);
    background: var(--color-surface);
}

.transcript mark {
    background: var(--gruvbox-yellow-faded);
    color: var(--color-on-accent);
    padding: 0 0.2rem;
    border-radius: 2px;
}

.transcript__run .button {
    flex: none;
    width: auto;
}

/* "A new transcript is ready: show it", for someone who has typed in the
   editor meanwhile (put in by the pages' script). */
.transcript__fresh {
    font-family: var(--font-ui);
}

.transcript__fresh .button {
    display: inline-block;
    width: auto;
    margin: 0 0.25rem;
}

/* Without script: the status, in a frame of its own that reloads itself
   (/d/<id>/transcript/frame), in place of the page's, which would go
   stale. (With script, <noscript> holds only text, so this never
   matches.) */
.transcript__frame {
    display: block;
    width: 100%;
    height: 5.5rem;
    border: 0;
    margin: 0 0 0.5rem;
}

.transcript__state:has(+ noscript > .transcript__frame) > :not(.notice) {
    display: none;
}

body.frame {
    min-height: 0;
    display: block;
}

body.frame .transcript__note {
    margin: 0;
}
