@import url("fonts-wCVGAQk.css");
@import url("variables-5Lpms5N.css");
@import url("bunnies-7QSnmvU.css");
@import url("utils-fvI5n4e.css");

/* ============================================
   buncol: ideas are bunnies, projects are colonies. Plain on purpose: the content and the
   bunnies carry the colour.
   Element styles are wrapped in :where() so they weigh nothing and any class (the world editor's
   panels, the editor's toolbar) can restyle an element without fighting them.
   ============================================ */

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

* {
    margin: 0;
    padding: 0;
}

html {
    background-color: var(--bg);
    -webkit-text-size-adjust: 100%;
}

body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    overflow-x: clip;
    background-color: var(--bg);
    color: var(--ink);
    font: 400 15px/1.5 var(--font-sans);
}

body.menu-open {
    overflow: hidden;
}

[hidden="hidden"] {
    display: none;
}

::selection {
    background-color: rgb(34 96 158 / 0.2);
}

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

:where(a) {
    color: var(--link);
    text-decoration: none;

    &:hover {
        color: var(--link-hi);
        text-decoration: underline;
    }
}

:where(svg) {
    fill: currentColor;
    vertical-align: middle;
}

:where(img) {
    max-width: 100%;
}

:where(strong, b) {
    font-weight: 700;
}

:where(small):where(:not(.world-editor *)) {
    color: var(--ink-3);
    font-size: 13px;
}

:where(time) {
    font-variant-numeric: tabular-nums;
}

:where(code, kbd):where(:not(.world-editor *)) {
    padding: 1px 5px;
    border-radius: var(--r-1);
    background-color: var(--line-row);
    font-family: var(--font-mono);
    font-size: 0.86em;
}

:where(pre) {
    padding: 12px 14px;
    overflow-x: auto;
    border: 1px solid var(--line);
    border-radius: var(--r-2);
    background-color: var(--surface-2);
    font-family: var(--font-mono);
    font-size: 14px;
}

:where(blockquote) {
    padding: 2px 0 2px 14px;
    border-left: 2px solid var(--line-strong);
    color: var(--ink-2);
}

:where(hr) {
    border: 0;
    border-top: 1px solid var(--line);
}

/* Lists lose their bullets in navigation; content lists keep theirs (see Running text). */
:where(nav) :where(ul, ol) {
    list-style: none;
}

/* ============================================
   Buttons
   One filled carrot button per view at most: the submit button of a form, or .button--primary.
   Other actions are grey buttons, links, or the small text actions of a list or a post.
   ============================================ */

:where(button, input[type="submit"], input[type="button"], input[type="reset"]):where(:not(.world-editor *)),
.button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
    min-height: 36px;
    padding: 0 16px;
    border: 0;
    border-radius: var(--r-2);
    background-color: var(--surface-3);
    color: var(--ink);
    font: 600 14px/1.2 var(--font-sans);
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;
    transition: background-color 0.12s, color 0.12s;

    &:hover {
        background-color: var(--surface-4);
        color: var(--ink);
        text-decoration: none;
    }

    &:disabled {
        cursor: not-allowed;
        opacity: 0.5;
    }

    & svg {
        width: 16px;
        height: 16px;
    }
}

:where(form:not(.world-editor *)) :where(button[type="submit"], button:not([type])),
:where(input[type="submit"]:not(.world-editor *)),
.button--primary {
    background-color: var(--carrot);
    color: var(--carrot-ink);

    &:hover {
        background-color: var(--carrot-hi);
        color: var(--carrot-ink);
    }
}

/* A second submit button in the same form is the alternative, not the main action. */
:where(form:not(.world-editor *)) :where(button[type="submit"]) ~ :where(button[type="submit"]) {
    background-color: var(--surface-3);
    color: var(--ink);

    &:hover {
        background-color: var(--surface-4);
    }
}

.button--danger,
:where(form) button.is-danger:not(form.inline-form button) {
    background-color: var(--surface-3);
    color: var(--rose);

    &:hover {
        background-color: var(--rose);
        color: #fff;
    }
}

/* A form wrapping a single button that sits inline, like a link (a POST action in a list) */
form.inline-form {
    display: inline;
}

form.inline-form button:not(.button),
.action {
    display: inline;
    min-height: 0;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: none;
    color: var(--link);
    font: inherit;
    text-decoration: none;
    white-space: nowrap;
    cursor: pointer;

    &:hover {
        background: none;
        color: var(--link-hi);
        text-decoration: underline;
    }

    &.is-danger {
        color: var(--rose);
    }
}

/* An inline form with a field (a reason, a role): a small grey button next to it */
form.inline-form :is(input:not([type="hidden"]), select) ~ button:not(.button) {
    display: inline-flex;
    align-items: center;
    min-height: 30px;
    padding: 0 10px;
    border-radius: var(--r-1);
    background-color: var(--surface-3);
    color: var(--ink);
    font: 600 14px/1.2 var(--font-sans);

    &:hover {
        background-color: var(--surface-4);
        color: var(--ink);
        text-decoration: none;
    }
}

/* Icon-only actions: next to a title, in an actions column, or a POST button with an icon */
:is(h1, h2) > a[aria-label],
td a[aria-label],
form.inline-form button[aria-label]:not(.button),
.icon-button {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    min-height: 0;
    padding: 0;
    border: 0;
    border-radius: var(--r-2);
    background-color: transparent;
    color: var(--ink-2);
    font-size: 18px;
    font-weight: 400;
    line-height: 1;
    text-decoration: none;
    vertical-align: middle;

    &:hover {
        background-color: var(--surface-3);
        color: var(--ink);
        text-decoration: none;
    }

    &.is-danger:hover {
        background-color: var(--rose-soft);
        color: var(--rose);
    }

    & svg {
        width: 18px;
        height: 18px;
    }
}

/* Buttons that belong together: Accept and Decline, Let in and Not now */
.button-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
}

/* ============================================
   Fields
   ============================================ */

:where(label:not(.world-editor *)) {
    display: block;
    margin: 14px 0 4px;
    color: var(--ink);
    font-size: 14px;
    font-weight: 700;
}

:where(input:not([type]), input[type="text"], input[type="email"], input[type="search"], input[type="number"], input[type="url"], input[type="password"], input[type="tel"], input[type="date"], input[type="datetime-local"], input[type="time"], select, textarea):where(:not(.world-editor *)) {
    max-width: 100%;
    min-height: 36px;
    padding: 6px 10px;
    border: 1px solid var(--line-field);
    border-radius: var(--r-1);
    background-color: var(--surface);
    color: var(--ink);
    font: 400 15px/1.4 var(--font-sans);
    transition: border-color 0.12s, box-shadow 0.12s;

    &:hover {
        border-color: #aab4be;
    }

    &:focus {
        outline: none;
        border-color: var(--link);
        box-shadow: 0 0 0 3px rgb(34 96 158 / 0.18);
    }

    &::placeholder {
        color: var(--ink-3);
    }

    &:disabled {
        background-color: var(--surface-2);
        opacity: 0.7;
    }
}

:where(select:not(.world-editor *)) {
    padding-right: 32px;
    appearance: none;
    background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%235a6672' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M6 9l6 6 6-6'/%3E%3C/svg%3E");
    background-position: right 9px center;
    background-repeat: no-repeat;
    background-size: 16px;
}

:where(textarea:not(.world-editor *)) {
    width: 100%;
    min-height: 120px;
    padding: 10px 12px;
    line-height: 1.5;
    resize: vertical;
}

:where(input[type="checkbox"], input[type="radio"], input[type="range"]) {
    accent-color: var(--carrot);
}

:where(input[type="checkbox"], input[type="radio"]):where(:not(.world-editor *)) {
    width: 16px;
    height: 16px;
    vertical-align: -3px;
    cursor: pointer;
}

/* A box with its label after it reads as one line */
:is(input[type="checkbox"], input[type="radio"]) + label {
    display: inline;
    margin: 0 16px 0 8px;
    font-weight: 400;
    cursor: pointer;
}

/* Symfony's choices: one option per line, the text wrapping beside its box */
.panel section form div:has(> :is(input[type="checkbox"], input[type="radio"]) + label) {
    display: grid;
    grid-template-columns: 16px minmax(0, 1fr);
    align-items: start;
    gap: 6px 10px;
    margin-top: 4px;

    & > input {
        margin-top: 3px;
    }

    & > label {
        margin: 0;
    }
}

:where(input[type="file"]:not(.world-editor *)) {
    max-width: 100%;
    color: var(--ink-2);
    font: inherit;
    font-size: 14px;

    &::file-selector-button {
        margin-right: 12px;
        padding: 8px 14px;
        border: 0;
        border-radius: var(--r-2);
        background-color: var(--surface-3);
        color: var(--ink);
        font: 600 14px var(--font-sans);
        cursor: pointer;
    }
}

:where(fieldset:not(.world-editor *)) {
    margin-top: 14px;
    padding: 10px 16px 14px;
    border: 1px solid var(--line);
    border-radius: var(--r-2);
}

:where(legend:not(.world-editor *)) {
    padding: 0 6px;
    color: var(--ink);
    font-size: 14px;
    font-weight: 700;
}

/* The forms of the panel: fields fill the line up to a comfortable width */
.panel section form:not(.inline-form) :is(input:not([type]), input[type="text"], input[type="email"], input[type="search"], input[type="number"], input[type="url"], input[type="password"], select) {
    width: 100%;
    max-width: 520px;
}

.panel section form:not(.inline-form) > :is(button, input[type="submit"]),
.panel section form:not(.inline-form) > div > :is(button, input[type="submit"]),
.panel section form:not(.inline-form) > div > div > button {
    display: flex;
    width: fit-content;
    margin-top: 18px;
}

/* Two answers to one question (accept or reject an appeal) stand side by side */
.panel section form:not(.inline-form) > button:has(+ button),
.panel section form:not(.inline-form) > button + button {
    display: inline-flex;
}

.panel section form:not(.inline-form) > button + button {
    margin-left: 8px;
}

.panel section form:not(.inline-form) > p:not(.help-text) {
    margin-top: 8px;
}

/* Symfony puts a field's errors in a list before it (lists in the text of an editor are text) */
.panel section form ul:not([class]):not(.rich-text *) {
    margin: 6px 0;
    padding: 0;
    list-style: none;

    & li {
        color: var(--rose);
        font-size: 14px;
    }
}

.panel section form .help-text {
    margin-top: 4px;
}

.forum-form :is(input[type="text"], textarea) {
    width: 100%;
    max-width: none;
}

/* A checkbox with a title and an explanation, as on the role form */
label:has(> input[type="checkbox"]):not(.world-editor *) {
    display: grid;
    grid-template-columns: 16px minmax(0, 1fr);
    align-items: start;
    column-gap: 10px;
    margin: 10px 0 0;
    font-weight: 400;
    cursor: pointer;

    & > input {
        margin-top: 3px;
    }

    & > strong {
        font-weight: 600;
    }

    & > .help-text {
        grid-column: 2;
    }
}

/* ============================================
   Header
   The logo, Home, Explore and Help, then the viewer's own links. On a phone the links move into
   the menu, a full-screen sheet.
   ============================================ */

.site-header {
    position: sticky;
    top: 0;
    z-index: 50;
    border-bottom: 1px solid var(--line-strong);
    background-color: var(--surface);
}

.site-header__inner {
    display: flex;
    align-items: center;
    gap: 4px 28px;
    max-width: calc(var(--content-width) + 2 * var(--gutter));
    min-height: var(--header-height);
    margin: 0 auto;
    padding: 0 var(--gutter);
}

/* A random bunny in a .bunny-spot, then the wordmark, which stands a little above the bunny's feet */
.logo {
    display: inline-flex;
    flex: none;
    align-items: flex-end;
    gap: 8px;
    color: var(--ink);
    text-decoration: none;

    & .bunny {
        transition: translate 0.2s;
    }

    & .wordmark {
        width: 62px;
        height: 18px;
        margin-bottom: 6px;
    }

    & .wordmark--text {
        width: auto;
        height: auto;
        font-size: 20px;
        font-weight: 700;
        letter-spacing: -0.02em;
        text-transform: lowercase;
    }

    &:hover {
        color: var(--ink);
        text-decoration: none;

        & .bunny {
            translate: 0 -2px;
        }
    }
}

.site-nav {
    display: flex;
    align-self: stretch;

    & a {
        display: inline-flex;
        align-items: center;
        gap: 6px;
        padding: 0 12px;
        border-bottom: 2px solid transparent;
        color: var(--ink-3);
        font-weight: 600;
        text-decoration: none;

        &:hover {
            color: var(--ink);
            text-decoration: none;
        }

        &[aria-current="page"] {
            border-bottom-color: var(--carrot);
            color: var(--ink);
        }
    }
}

.site-tools {
    display: flex;
    align-items: center;
    gap: 18px;
    margin-left: auto;
    font-size: 14px;

    & > a,
    & > form.inline-form button {
        color: var(--ink-3);
        white-space: nowrap;

        &:hover {
            color: var(--ink);
        }
    }

    & > .site-tools__strong {
        color: var(--ink);
        font-weight: 600;
    }

    & > .menu-trigger {
        display: none;
    }
}

/* The site menu: on a phone only, a full-screen sheet of rows */
.menu-overlay {
    display: none;
}

@media (max-width: 767px) {
    .site-header__inner {
        min-height: 56px;
        padding: 6px 8px 6px 14px;
    }

    .site-nav,
    .site-tools > a:not(.menu-trigger),
    .site-tools > form.inline-form {
        display: none;
    }

    .site-tools > .menu-trigger {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 44px;
        height: 44px;
        border-radius: var(--r-2);
        color: var(--ink);

        & svg {
            width: 22px;
            height: 22px;
        }

        &:hover {
            background-color: var(--line-row);
        }
    }

    .menu-overlay {
        position: fixed;
        inset: 0;
        z-index: 1000;
        flex-direction: column;
        gap: 10px;
        padding-bottom: 24px;
        overflow-y: auto;
        background-color: var(--bg);
        font-size: 16px;

        &.active {
            display: flex;
        }
    }
}

.menu-overlay__head {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 6px 8px 6px 14px;
    border-bottom: 1px solid var(--line-strong);
    background-color: var(--surface);
}

.menu-overlay__who {
    display: flex;
    flex-direction: column;
    line-height: 1.25;

    & a {
        font-size: 13px;
    }
}

.menu-overlay__head .menu-close-btn {
    width: 44px;
    height: 44px;
    margin-left: auto;
    padding: 0;
    background: transparent;
    color: var(--ink);

    & svg {
        width: 22px;
        height: 22px;
    }

    &:hover {
        background-color: var(--line-row);
    }
}

.menu-overlay-content {
    display: flex;
    flex-direction: column;
    gap: 10px;
}

.menu-section {
    border-top: 1px solid var(--line-strong);
    border-bottom: 1px solid var(--line-strong);
    background-color: var(--surface);

    & h2 {
        padding: 8px 14px 2px;
        color: var(--ink-3);
        font-size: 13px;
        font-weight: 700;
        line-height: 1.5;
    }

    & ul {
        display: flex;
        flex-direction: column;
    }

    & li :is(a, form.inline-form button) {
        display: flex;
        align-items: center;
        gap: 12px;
        width: 100%;
        min-height: 48px;
        padding: 0 14px;
        border-top: 1px solid var(--line-row);
        color: var(--ink);
        font-weight: 600;
        text-decoration: none;

        & svg {
            flex: none;
            width: 20px;
            height: 20px;
            color: var(--ink-3);
        }

        & .inline-badge {
            margin-left: auto;
        }

        &:hover,
        &[aria-current="page"] {
            background-color: var(--line-row);
            color: var(--ink);
            text-decoration: none;
        }

        &[aria-current="page"] {
            font-weight: 700;
        }
    }
}

/* /menu, the page the menu button opens without JavaScript: the same rows in the panel */
.panel > .menu-section {
    border: 0;

    & + .menu-section {
        border-top: 1px solid var(--line);
    }
}

/* ============================================
   The page: one panel
   The parts of a page (its <section>s, the project bar) make one white surface, split by
   hairlines rather than floated apart as cards. Notices and a row of breadcrumbs sit above it.
   ============================================ */

body > main {
    display: flex;
    flex: 1 0 auto;
    flex-direction: column;
    gap: 12px;
    width: 100%;
    max-width: calc(var(--content-width) + 2 * var(--gutter));
    margin: 0 auto;
    padding: 20px var(--gutter) 0;
}

.panel {
    --part-x: 20px;

    min-width: 0;
    overflow: clip;
    border: 1px solid var(--line-strong);
    border-radius: var(--r-2);
    background-color: var(--surface);

    & > * + * {
        border-top: 1px solid var(--line);
    }
}

@media (max-width: 600px) {
    body > main {
        padding-top: 12px;
        padding-inline: 8px;
    }

    .panel {
        --part-x: 14px;
    }
}

.panel > section {
    min-width: 0;
    padding: 16px var(--part-x) 20px;
    overflow-x: auto;

    & > * + * {
        margin-top: 12px;
    }

    & > * + :is(h2, h3) {
        margin-top: 24px;
    }
}

/* A panel for a short form: logging in, a report */
.panel:has(> section.narrow) {
    width: 100%;
    max-width: 480px;
    margin-inline: auto;
}

/* The editors cover the window: no panel around them */
.panel:has(> .world-editor) {
    display: contents;
}

/* Running text keeps to a readable line length; tables and forms still use the whole panel */
.panel > section > :is(p, ul:not([class]), ol:not([class])) {
    max-width: 80ch;
}

main :where(h1, h2, h3):where(:not(.world-editor *)) {
    color: var(--ink);
    text-wrap: balance;
}

main :where(h1):where(:not(.world-editor *)) {
    font-size: 24px;
    font-weight: 700;
    line-height: 1.25;
}

main :where(h2):where(:not(.world-editor *)) {
    font-size: 20px;
    font-weight: 700;
    line-height: 1.3;
}

main :where(h3):where(:not(.world-editor *)) {
    font-size: 15px;
    font-weight: 700;
    line-height: 1.4;
}

@media (max-width: 600px) {
    main :where(h1) {
        font-size: 22px;
    }
}

/* A heading that is a link stays in the ink of headings */
main :where(h1, h2, h3) > a:not([aria-label]) {
    color: inherit;

    &:hover {
        color: var(--link-hi);
    }
}

/* A part's title with its icon actions behind it */
.panel > section > :is(h1, h2) {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 8px;

    & > small {
        font-size: 13px;
        font-weight: 400;
    }
}

/* A heading with a link or a note on the right: "Projects to explore … Browse all" */
.heading-row {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 4px 16px;

    & > a,
    & > form {
        font-size: 14px;
        font-weight: 600;
    }
}

/* Running text: paragraphs, content lists, and rich text (.rich-text: the read pages, the
   editor and its preview, all alike) */
main section :where(ul, ol):not([class]):not(nav *):not(form *),
main article:not([class]) :where(ul, ol),
.rich-text :where(ul, ol) {
    padding-left: 1.4em;

    & > li + li {
        margin-top: 4px;
    }

    & > li::marker {
        color: var(--ink-3);
    }
}

main section :where(ol):not([class]):not(nav *):not(form *) > li,
main article:not([class]) :where(ol) > li,
.rich-text :where(ol) > li {
    list-style-type: decimal;
}

main article:not([class]),
.rich-text {
    max-width: 72ch;
    font-size: 16px;
    line-height: 1.65;
    overflow-wrap: anywhere;

    & > * + *,
    & > .ProseMirror > * + * {
        margin-top: 0.8em;
    }

    & :where(li > * + *) {
        margin-top: 4px;
    }

    & :where(h1) {
        font-size: 22px;
    }

    & :where(h2) {
        font-size: 20px;
    }

    & * + :is(h1, h2, h3) {
        margin-top: 1.3em;
    }

    /* Links in running text are underlined: blue alone is too close to the text */
    & a {
        text-decoration: underline;
        text-decoration-color: rgb(34 96 158 / 0.4);
        text-underline-offset: 2px;

        &:hover {
            text-decoration-color: currentColor;
        }
    }

    & .text-align-center {
        text-align: center;
    }

    & .text-align-right {
        text-align: right;
    }

    & .text-align-justify {
        text-align: justify;
    }

    & pre code {
        padding: 0;
        background: none;
        font-size: inherit;
    }

    /* Writing the reader may not open, or that is gone, by its kind only */
    & :is(.mention--hidden, .mention--missing) {
        color: var(--ink-3);
        font-style: italic;
    }
}

/* Images in rich text (RichTextHtmlRenderer, #11): a third, two thirds or the whole of the
   column wide (half and whole on a phone), but never blown up past their own size, so pixel art
   stays sharp. Their width and height attributes keep the room while they load. The editor
   shows the same sizes. */
.rich-text-image {
    display: block;
    margin-block: 1.2em;

    &:first-child {
        margin-top: 0;
    }

    &:last-child {
        margin-bottom: 0;
    }

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

.rich-text-image--small {
    width: 33%;
}

.rich-text-image--medium {
    width: 67%;
}

.rich-text-image--full {
    width: 100%;
}

@media (max-width: 600px) {
    .rich-text-image--small {
        width: 50%;
    }

    .rich-text-image--medium {
        width: 100%;
    }
}

/* In place of an image the reader cannot see (gone, of another library, hidden): its alt text
   in a quiet box, like a hidden file in a media library */
.rich-text-image--placeholder {
    display: flex;
    flex-direction: column;
    gap: 2px;
    width: fit-content;
    max-width: 100%;
    padding: 8px 14px;
    border: 1px dashed var(--line-field);
    border-radius: var(--r-2);
    background-color: var(--surface-2);
    color: var(--ink-3);
    font-size: 14px;
    line-height: 1.5;

    & > span {
        font-style: italic;
    }

    & > small {
        font-size: 13px;
    }
}

/* Sounds in rich text (RichTextHtmlRenderer, #11): the browser's own player across the column, up
   to the width of a phone, with its caption under it. The editor shows the same. */
.rich-text-audio {
    display: block;
    width: min(100%, 480px);
    margin-block: 1.2em;

    &:first-child {
        margin-top: 0;
    }

    &:last-child {
        margin-bottom: 0;
    }

    & audio {
        display: block;
        width: 100%;
    }

    & figcaption {
        margin-top: 4px;
        color: var(--ink-2);
        font-size: 14px;
        line-height: 1.5;
    }
}

/* In place of a sound the reader cannot play (gone, of another library, hidden, not a sound): its
   caption in the same quiet box as an image's alt text */
.rich-text-audio--placeholder {
    display: flex;
    flex-direction: column;
    gap: 2px;
    width: fit-content;
    max-width: 100%;
    padding: 8px 14px;
    border: 1px dashed var(--line-field);
    border-radius: var(--r-2);
    background-color: var(--surface-2);
    color: var(--ink-3);
    font-size: 14px;
    line-height: 1.5;

    & > span {
        font-style: italic;
    }

    & > small {
        font-size: 13px;
    }
}

/* Where a page is, as links: "Forum › Section" */
.breadcrumbs {
    color: var(--ink-3);
    font-size: 14px;

    & span[aria-hidden] {
        margin: 0 4px;
    }
}

/* The same above the panel, with the project's bunny, as on a forum thread */
.crumbs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 4px 12px;
    padding: 0 2px;
    color: var(--ink-3);
    font-size: 14px;

    & .crumbs__project {
        color: var(--ink);
        font-weight: 700;
    }
}

.kicker {
    color: var(--carrot-text);
    font-size: 14px;
    font-weight: 600;
}

/* ============================================
   Two columns in the panel: a quieter side column next to the main one, one above the other
   on narrow screens
   ============================================ */

.split {
    display: grid;
    grid-template-columns: minmax(0, 1fr);

    & > * + * {
        border-top: 1px solid var(--line);
    }
}

.split__side {
    background-color: var(--surface-2);
}

@media (min-width: 900px) {
    .split {
        grid-template-columns: minmax(0, 1fr) 300px;

        & > * + * {
            border-top: 0;
            border-left: 1px solid var(--line);
        }
    }

    .split--side-first {
        grid-template-columns: var(--side-width) minmax(0, 1fr);
    }
}

.split__main > section {
    padding: 16px var(--part-x) 20px;

    & > * + * {
        margin-top: 12px;
    }

    & + section {
        border-top: 1px solid var(--line-row);
    }
}

.split__side > section {
    padding: 16px 16px 6px;

    &:last-child {
        padding-bottom: 18px;
    }

    & h2 {
        font-size: 15px;
    }

    & > h2,
    & > .heading-row {
        margin-bottom: 6px;
    }

    & + section {
        padding-top: 12px;
    }
}

/* Rows of links in the side column: a name, and what is in it on the right */
.link-rows {
    list-style: none;

    & > li > a,
    & > li > span {
        display: flex;
        justify-content: space-between;
        gap: 12px;
        padding: 7px 0;
        border-top: 1px solid var(--line);
    }

    & > li > a {
        &:hover {
            text-decoration: none;

            & > :first-child {
                text-decoration: underline;
            }
        }
    }

    & .meta {
        flex: none;
        text-align: right;
    }
}

.split__main .link-rows > li > a {
    border-top-color: var(--line-row);
}

/* ============================================
   Tables
   ============================================ */

main :where(table) {
    width: calc(100% + 2 * var(--part-x, 0px));
    margin-inline: calc(-1 * var(--part-x, 0px));
    border-collapse: collapse;
    font-size: 15px;
}

main :where(th) {
    padding: 8px 12px;
    border-bottom: 1px solid var(--line-strong);
    color: var(--ink-2);
    font-size: 13px;
    font-weight: 700;
    text-align: left;
    vertical-align: bottom;
    white-space: nowrap;
}

main :where(th, td):first-child {
    padding-left: var(--part-x, 12px);
}

main :where(th, td):last-child {
    padding-right: var(--part-x, 12px);
}

/* A row header, as on Your account: a label, not a column title */
main :where(th[scope="row"]) {
    width: 32%;
    padding-top: 12px;
    padding-bottom: 12px;
    border-bottom: 1px solid var(--line-row);
    color: var(--ink-2);
    font-size: 14px;
    font-weight: 600;
    vertical-align: top;
    white-space: normal;
}

main :where(td) {
    padding: 10px 12px;
    border-bottom: 1px solid var(--line-row);
    text-align: left;
    vertical-align: top;
}

main :where(tbody tr:last-child) > :where(td, th) {
    border-bottom: 0;
}

/* A row with a bunny in it lines its cells up with the bunny's middle */
main tr:has(> td .bunnicon) > td {
    vertical-align: middle;
}

main :where(tbody tr) {
    transition: background-color 0.12s;

    &:hover {
        background-color: var(--surface-2);
    }
}

/* Lists with an actions column (writing, world): fixed columns, a narrow last one for icon buttons */
main table.actions-table {
    table-layout: fixed;

    & :is(td, th):last-child {
        width: calc(124px + var(--part-x, 0px));
        text-align: right;
    }

    & td:last-child > p,
    & td:last-child {
        white-space: nowrap;
    }

    & td:last-child > p {
        display: inline-flex;
        gap: 2px;
    }

    & td:last-child {
        padding-top: 6px;
        padding-bottom: 6px;
    }

    /* The content column: truncated, the whole text pops out over the row on hover */
    & td:first-child {
        position: relative;
        overflow: visible;
    }

    & .table-cell-wrapper {
        position: relative;
        display: block;
        width: 100%;
    }

    & .table-cell-static {
        display: block;
        width: 100%;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;

        & a {
            display: inline-block;
            max-width: 100%;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            vertical-align: middle;
        }

        & > * {
            display: inline;
        }
    }

    & .table-cell-hover {
        display: none;
    }

    & .table-cell-wrapper:hover {
        & .table-cell-static {
            visibility: hidden;
        }

        & .table-cell-hover {
            position: absolute;
            top: -9px;
            left: -9px;
            z-index: 100;
            display: block;
            width: calc(100% + 18px);
            padding: 8px;
            border: 1px solid var(--line-strong);
            border-radius: var(--r-2);
            background-color: var(--surface);
            box-shadow: var(--shadow-pop);
            white-space: normal;
            overflow-wrap: anywhere;
        }
    }
}

/* The search and paging bar above a writing table */
nav.inline {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;

    & input[type="search"] {
        flex: 1 1 220px;
    }

    & button {
        min-height: 36px;
        padding: 0 12px;
    }

    & span {
        color: var(--ink-3);
        font-size: 13px;
    }
}

/* Pages of a list: numbered squares, the current one dark */
.pager {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: flex-end;
    gap: 6px;
    font-size: 14px;

    & .pager__label {
        margin-right: 6px;
        color: var(--ink-3);
    }

    & .pager__page {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-width: 30px;
        min-height: 30px;
        padding: 0 6px;
        border-radius: var(--r-1);
        background-color: var(--surface-3);
        color: var(--ink);
        font-weight: 600;
        text-decoration: none;

        &:hover {
            background-color: var(--surface-4);
        }

        &[aria-current="page"] {
            background-color: var(--ink);
            color: #fff;
            font-weight: 700;
        }
    }

    & .pager__gap {
        color: var(--ink-3);
    }

    & a[rel] {
        font-weight: 600;
    }

    & a[rel="prev"] {
        margin-right: 6px;
    }

    & a[rel="next"] {
        margin-left: 6px;
    }
}

/* ============================================
   Notices
   ============================================ */

.flash-message-container {
    display: flex;
    flex-direction: column;
    gap: 8px;
}

p[class^="flash-"] {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    padding: 10px 14px;
    border: 1px solid rgb(34 96 158 / 0.3);
    border-radius: var(--r-2);
    background-color: var(--link-soft);
    color: var(--ink);

    & > svg {
        flex: none;
        width: 20px;
        height: 20px;
        margin-top: 1px;
        color: var(--link);
    }
}

p.flash-success {
    border-color: rgb(60 122 58 / 0.35);
    background-color: var(--clover-soft);

    & > svg {
        color: var(--clover);
    }
}

p.flash-warning {
    border-color: rgb(138 106 0 / 0.35);
    background-color: var(--mustard-soft);

    & > svg {
        color: var(--mustard);
    }
}

p.flash-error,
p.flash-danger {
    border-color: rgb(179 38 30 / 0.3);
    background-color: var(--rose-soft);

    & > svg {
        color: var(--rose);
    }
}

/* Something waiting for the viewer's answer */
.callout {
    padding: 12px 14px;
    border: 1px solid rgb(181 80 28 / 0.3);
    border-radius: var(--r-2);
    background-color: #fbf1eb;

    & > * + * {
        margin-top: 8px;
    }
}

/* A media library's images as tiles: the thumbnail on a quiet square, its title and size below.
   Marked for deletion fades, like a deleted account's bunny. */
.media-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(150px, 1fr));
    gap: 14px;
    margin-top: 14px;
    list-style: none;

    & > li {
        display: flex;
        flex-direction: column;
        gap: 4px;
        min-width: 0;
    }

    & a {
        display: flex;
        flex-direction: column;
        gap: 6px;
    }

    & img {
        width: 100%;
        height: auto;
        aspect-ratio: 1;
        /* Never blown up: a small image (pixel art) keeps its own size instead of blurring. */
        object-fit: scale-down;
        border: 1px solid var(--line);
        border-radius: var(--r-2);
        background-color: var(--surface-2);
    }

    & span {
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }

    & small {
        color: var(--ink-2);
    }

    /* A file without a thumbnail (hidden from the viewer, or a sound): a square with an icon where its thumbnail would be */
    & .media-grid__placeholder {
        display: grid;
        place-items: center;
        aspect-ratio: 1;
        border: 1px dashed var(--line);
        border-radius: var(--r-2);
        background-color: var(--surface-2);
        color: var(--ink-3);
    }

    & > li.is-marked {
        opacity: 0.55;
    }
}

/* A media file's own page: the image at most as wide as the panel and most of the window high */
.media-preview img {
    width: auto;
    max-width: 100%;
    height: auto;
    max-height: 70vh;
    border: 1px solid var(--line);
    border-radius: var(--r-2);
    background-color: var(--surface-2);
}

/* A sound's page: the browser's own player, as wide as a phone */
.media-preview audio {
    display: block;
    width: min(100%, 480px);
}

/* How full a project's storage is (the Storage section of the project settings) */
.storage-meter {
    display: block;
    width: 100%;
    height: 14px;
}

/* ============================================
   Bunnies
   ============================================ */

/* A sprite from images/bunnies.svg at its own pixel size (or exactly twice it): never scaled in
   between, so every pixel stays square. Its coat class gives the colours. */
.bunny {
    display: inline-block;
    flex: none;
    shape-rendering: crispEdges;
}

.bunny--mirror {
    transform: scaleX(-1);
}

/* A fixed spot for a random bunny, so what sits next to it stays put whichever sprite the page got
   (they run from 20 to 52px wide and 17 to 46px tall): the bunny stands on the bottom edge, centred,
   and a bigger one sticks out without catching clicks. The logo and the phone menu's head. */
.bunny-spot {
    display: inline-flex;
    flex: none;
    align-items: flex-end;
    justify-content: center;
    width: 40px;
    height: 36px;

    & > .bunny {
        pointer-events: none;
    }
}

/* The bunny next to a project or a person, any random one, on a pale tile of its coat: 40px with
   the sprite at 1×, 72px at 2×. The bunny stands on the tile's bottom edge, centred, and a bigger
   one sticks out: ears over the top, a long body past the sides, up to 6px beside and above a 1×
   tile and 16px beside and 20px above a 2× one. Positioned, it never moves the tile or anything
   around it and catches no clicks; it paints over its neighbours, under the header and the menu.
   The panel clips at its edge; its sections cut off what goes past their top or left padding and
   would scroll sideways for what goes past their right. So every place leaves it that room in its
   padding or gaps (see .project-list, .project-bar__head--full and the forum's posts and reply
   box); on a phone the project head's is 2px short. */
.bunnicon {
    position: relative;
    display: inline-block;
    flex: none;
    width: 40px;
    height: 40px;
    border-radius: var(--r-2);
    background-color: var(--bun-tile);
    vertical-align: middle;

    /* Centred by its auto margins in a box twice the tile's width */
    & > .bunny {
        position: absolute;
        right: -50%;
        bottom: 0;
        left: -50%;
        margin-inline: auto;
        pointer-events: none;
    }
}

.bunnicon--big {
    width: 72px;
    height: 72px;
}

/* A person's avatar (#10) instead of the bunny: the square image fills the tile, with its corners,
   and nothing sticks out. No coat: a plain tile shows only while it loads or through a see-through
   avatar. */
.bunnicon--avatar {
    background-color: var(--surface-3);

    & > img {
        display: block;
        width: 100%;
        height: 100%;
        border-radius: inherit;
        object-fit: cover;
    }
}

/* A deleted account: still a random bunny, faded to grey */
.bunnicon--deleted {
    opacity: 0.5;
    filter: grayscale(1);
}

/* The loader: a bunny that moves on the spot until the thing it waits for is there. Every page load
   picks a loader and a coat at random (partials/loader_attributes.html.twig on <html>); everything
   that shows the bunny (this, .disabled in utils.css, the 3D editors' loading screen) uses these
   properties. The images hold the frames side by side and a row per coat (eight); bunnies.css sets
   the coat's --loader-row and each loader's frame size and count (--loader-w, --loader-h,
   --loader-frames). The values on :root alone (the hop, agouti) are only a fallback for markup
   without those attributes, never a pick. */
:root {
    --loader-image: url("../images/bunny-hop-2524CQ9.svg");
    --loader-motion: bunny-hop 0.9s cubic-bezier(0.3, 0, 0.3, 1) infinite;
    --loader-shadow: bunny-shadow 0.9s ease-in-out infinite;
    --loader-row: 14.286%;
}

/* The binky: a twisting jump that lands facing the other way, then back again */
:root[data-loader="binky"] {
    --loader-image: url("../images/bunny-binky-jmCMD6i.svg");
    --loader-motion: bunny-binky 2.4s linear infinite;
    --loader-shadow: bunny-shadow-binky 2.4s ease-in-out infinite;
}

/* The periscope: crouched, twitches its nose, sits up tall, looks one way and the other, drops down */
:root[data-loader="periscope"] {
    --loader-image: url("../images/bunny-periscope-FvjgEuY.svg");
    --loader-motion: bunny-periscope 2.8s ease-in-out infinite;
    --loader-shadow: bunny-shadow-periscope 2.8s ease-in-out infinite;
}

/* The wash: sits, licks a paw, washes its face twice, sits again */
:root[data-loader="wash"] {
    --loader-image: url("../images/bunny-wash-ns27DP9.svg");
    --loader-motion: bunny-wash 2.6s ease-out infinite;
    --loader-shadow: none;
}

/* The zoomies: races across, skids, turns and races back. It runs past its own frame, so the
   .loader is wider (--loader-reach frames) to keep it off whatever sits next to it. */
:root[data-loader="zoomies"] {
    --loader-image: url("../images/bunny-zoomies-ctZO-Q3.svg");
    --loader-motion: bunny-zoomies 2.2s linear infinite;
    --loader-shadow: bunny-shadow-zoomies 2.2s linear infinite;
    --loader-reach: 2.1;
}

/* The nibble: sits up munching a stalk, chews, takes another bite */
:root[data-loader="nibble"] {
    --loader-image: url("../images/bunny-nibble-iBjErl8.svg");
    --loader-motion: bunny-nibble 2s ease-in-out infinite;
    --loader-shadow: none;
}

.loader {
    position: relative;
    display: inline-block;
    width: calc(var(--loader-w) * var(--loader-reach, 1));
    height: calc(var(--loader-h) + 22px);

    &::before {
        content: "";
        position: absolute;
        bottom: 4px;
        left: calc(50% - var(--loader-w) / 2);
        width: var(--loader-w);
        height: var(--loader-h);
        background: var(--loader-image) 0 var(--loader-row) / calc(var(--loader-frames) * 100%) 800% no-repeat;
        animation: var(--loader-motion);
        transform-origin: 50% 100%;
    }

    &::after {
        content: "";
        position: absolute;
        bottom: 0;
        left: calc(50% - var(--loader-w) * 0.4);
        width: calc(var(--loader-w) * 0.8);
        height: 4px;
        border-radius: 50%;
        background-color: rgb(31 38 45 / 0.22);
        animation: var(--loader-shadow);
    }
}

/* The frame switches (background-position-x) live in the same @keyframes as the transform so the
   browser runs both on the main thread instead of jumping in a frozen pose while a 3D editor builds
   its meshes. */

/* The hop: crouching on the ground, in the air from take-off to landing */
@keyframes bunny-hop {
    0%, 22% { background-position-x: 0; }
    22.01%, 78% { background-position-x: 100%; }
    78.01%, 100% { background-position-x: 0; }
    0% { transform: translateY(0) scale(1.06, 0.9); }
    18% { transform: translateY(0) scale(0.96, 1.06); }
    50% { transform: translateY(-55%) scale(1, 1); }
    80% { transform: translateY(0) scale(1, 1.02); }
    88% { transform: translateY(0) scale(1.08, 0.88); }
    100% { transform: translateY(0) scale(1.06, 0.9); }
}

@keyframes bunny-shadow {
    0%, 18%, 88%, 100% {
        opacity: 1;
        transform: scaleX(1);
    }

    50% {
        opacity: 0.4;
        transform: scaleX(0.45);
    }
}

/* The binky, two jumps per cycle: crouch, spring up nose first, twist round at the top (edge-on for a
   moment), come down nose first facing the other way, land with a squash; then the same back. */
@keyframes bunny-binky {
    0%, 12% { background-position-x: 0; }
    12.01%, 37% { background-position-x: 100%; }
    37.01%, 62% { background-position-x: 0; }
    62.01%, 87% { background-position-x: 100%; }
    87.01%, 100% { background-position-x: 0; }
    0% { transform: translateY(0) rotate(0) scale(1, 1); }
    6% { transform: translateY(0) rotate(0) scale(1.08, 0.86); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
    12% { transform: translateY(0) rotate(-6deg) scale(0.95, 1.08); animation-timing-function: cubic-bezier(0.1, 0.6, 0.4, 1); }
    21% { transform: translateY(-56%) rotate(-16deg) scale(1, 1); animation-timing-function: ease-in-out; }
    25% { transform: translateY(-64%) rotate(-4deg) scale(0.12, 1); animation-timing-function: ease-in-out; }
    29% { transform: translateY(-56%) rotate(-12deg) scale(-1, 1); animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.5); }
    37% { transform: translateY(0) rotate(0) scale(-1, 1.03); }
    42% { transform: translateY(0) rotate(0) scale(-1.1, 0.86); animation-timing-function: ease-out; }
    50% { transform: translateY(0) rotate(0) scale(-1, 1); }
    56% { transform: translateY(0) rotate(0) scale(-1.08, 0.86); animation-timing-function: cubic-bezier(0.2, 0.7, 0.4, 1); }
    62% { transform: translateY(0) rotate(6deg) scale(-0.95, 1.08); animation-timing-function: cubic-bezier(0.1, 0.6, 0.4, 1); }
    71% { transform: translateY(-56%) rotate(16deg) scale(-1, 1); animation-timing-function: ease-in-out; }
    75% { transform: translateY(-64%) rotate(4deg) scale(-0.12, 1); animation-timing-function: ease-in-out; }
    79% { transform: translateY(-56%) rotate(12deg) scale(1, 1); animation-timing-function: cubic-bezier(0.5, 0, 0.9, 0.5); }
    87% { transform: translateY(0) rotate(0) scale(1, 1.03); }
    92% { transform: translateY(0) rotate(0) scale(1.1, 0.86); animation-timing-function: ease-out; }
    100% { transform: translateY(0) rotate(0) scale(1, 1); }
}

@keyframes bunny-shadow-binky {
    0%, 12%, 37%, 62%, 87%, 100% {
        opacity: 1;
        transform: scaleX(1);
    }

    25%, 75% {
        opacity: 0.35;
        transform: scaleX(0.5);
    }
}

/* The periscope: two nose twitches, a squash before it sits up, then it turns to look the other way
   (flipped) and back, and drops down with a squash. */
@keyframes bunny-periscope {
    0%, 22% { background-position-x: 0; }
    22.01%, 78% { background-position-x: 100%; }
    78.01%, 100% { background-position-x: 0; }
    0% { transform: translateY(0) scale(1, 1); }
    6% { transform: translateY(0) scale(1.03, 0.96); }
    10% { transform: translateY(0) scale(1, 1); }
    14% { transform: translateY(0) scale(1.03, 0.96); }
    18% { transform: translateY(0) scale(1, 1); }
    21% { transform: translateY(0) scale(1.08, 0.86); }
    22% { transform: translateY(-8%) scale(0.94, 1.08); }
    28%, 46% { transform: translateY(0) scale(1, 1); }
    49%, 72% { transform: translateY(0) scale(-1, 1); }
    75% { transform: translateY(0) scale(1, 1); }
    78% { transform: translateY(0) scale(1, 0.98); }
    80% { transform: translateY(0) scale(1.08, 0.86); }
    88%, 100% { transform: translateY(0) scale(1, 1); }
}

@keyframes bunny-shadow-periscope {
    0%, 20%, 80%, 100% { transform: scaleX(1); }
    28%, 74% { transform: scaleX(0.7); }
}

/* The wash: sit, lick a paw, wash, paw, wash, paw, sit; a small settle on every change */
@keyframes bunny-wash {
    0%, 14% { background-position-x: 0; }
    14.01%, 30% { background-position-x: 33.333%; }
    30.01%, 44% { background-position-x: 66.667%; }
    44.01%, 58% { background-position-x: 100%; }
    58.01%, 72% { background-position-x: 66.667%; }
    72.01%, 86% { background-position-x: 100%; }
    86.01%, 100% { background-position-x: 0; }
    0%, 14%, 30%, 44%, 58%, 72%, 86%, 100% { transform: scale(1.03, 0.96); }
    4%, 18%, 34%, 48%, 62%, 76%, 90% { transform: scale(1, 1); }
}

/* The zoomies: five bounds to the right, a skid, then the same to the left. The shadow is 0.8 of
   the frame wide, so it moves by the bunny's distances divided by 0.8. */
@keyframes bunny-zoomies {
    0%, 8% { background-position-x: 0; }
    8.01%, 16% { background-position-x: 50%; }
    16.01%, 24% { background-position-x: 0; }
    24.01%, 32% { background-position-x: 50%; }
    32.01%, 40% { background-position-x: 0; }
    40.01%, 50% { background-position-x: 100%; }
    50.01%, 58% { background-position-x: 0; }
    58.01%, 66% { background-position-x: 50%; }
    66.01%, 74% { background-position-x: 0; }
    74.01%, 82% { background-position-x: 50%; }
    82.01%, 90% { background-position-x: 0; }
    90.01%, 100% { background-position-x: 100%; }
    0% { transform: translate(-45%, 0) scale(1, 1); }
    4% { transform: translate(-36%, -22%) scale(1, 1); }
    8% { transform: translate(-27%, 0) scale(1, 1); }
    12% { transform: translate(-18%, -22%) scale(1, 1); }
    16% { transform: translate(-9%, 0) scale(1, 1); }
    20% { transform: translate(0%, -22%) scale(1, 1); }
    24% { transform: translate(9%, 0) scale(1, 1); }
    28% { transform: translate(18%, -22%) scale(1, 1); }
    32% { transform: translate(27%, 0) scale(1, 1); }
    36% { transform: translate(36%, -22%) scale(1, 1); }
    40% { transform: translate(45%, 0) scale(1.06, 0.92); }
    47%, 49.99% { transform: translate(55%, 0) scale(1, 1); }
    50% { transform: translate(45%, 0) scale(-1, 1); }
    54% { transform: translate(36%, -22%) scale(-1, 1); }
    58% { transform: translate(27%, 0) scale(-1, 1); }
    62% { transform: translate(18%, -22%) scale(-1, 1); }
    66% { transform: translate(9%, 0) scale(-1, 1); }
    70% { transform: translate(0%, -22%) scale(-1, 1); }
    74% { transform: translate(-9%, 0) scale(-1, 1); }
    78% { transform: translate(-18%, -22%) scale(-1, 1); }
    82% { transform: translate(-27%, 0) scale(-1, 1); }
    86% { transform: translate(-36%, -22%) scale(-1, 1); }
    90% { transform: translate(-45%, 0) scale(-1.06, 0.92); }
    97%, 100% { transform: translate(-55%, 0) scale(-1, 1); }
}

@keyframes bunny-shadow-zoomies {
    0% { transform: translateX(-56.25%) scaleX(1); opacity: 1; }
    4% { transform: translateX(-45%) scaleX(0.7); opacity: 0.6; }
    8% { transform: translateX(-33.75%) scaleX(1); opacity: 1; }
    12% { transform: translateX(-22.5%) scaleX(0.7); opacity: 0.6; }
    16% { transform: translateX(-11.25%) scaleX(1); opacity: 1; }
    20% { transform: translateX(0%) scaleX(0.7); opacity: 0.6; }
    24% { transform: translateX(11.25%) scaleX(1); opacity: 1; }
    28% { transform: translateX(22.5%) scaleX(0.7); opacity: 0.6; }
    32% { transform: translateX(33.75%) scaleX(1); opacity: 1; }
    36% { transform: translateX(45%) scaleX(0.7); opacity: 0.6; }
    40% { transform: translateX(56.25%) scaleX(1); opacity: 1; }
    47%, 49.99% { transform: translateX(68.75%) scaleX(1); opacity: 1; }
    50% { transform: translateX(56.25%) scaleX(1); opacity: 1; }
    54% { transform: translateX(45%) scaleX(0.7); opacity: 0.6; }
    58% { transform: translateX(33.75%) scaleX(1); opacity: 1; }
    62% { transform: translateX(22.5%) scaleX(0.7); opacity: 0.6; }
    66% { transform: translateX(11.25%) scaleX(1); opacity: 1; }
    70% { transform: translateX(0%) scaleX(0.7); opacity: 0.6; }
    74% { transform: translateX(-11.25%) scaleX(1); opacity: 1; }
    78% { transform: translateX(-22.5%) scaleX(0.7); opacity: 0.6; }
    82% { transform: translateX(-33.75%) scaleX(1); opacity: 1; }
    86% { transform: translateX(-45%) scaleX(0.7); opacity: 0.6; }
    90% { transform: translateX(-56.25%) scaleX(1); opacity: 1; }
    97%, 100% { transform: translateX(-68.75%) scaleX(1); opacity: 1; }
}

/* The nibble: half the cycle munching, half chewing the stalk, a small chew every tenth */
@keyframes bunny-nibble {
    0%, 50% { background-position-x: 0; }
    50.01%, 100% { background-position-x: 100%; }
    0%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90%, 100% { transform: scale(1, 1); }
    5%, 15%, 25%, 35%, 45%, 55%, 65%, 75%, 85%, 95% { transform: scale(1.02, 0.97); }
}

/* ============================================
   Footer
   ============================================ */

.site-footer__inner {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 8px 24px;
    max-width: calc(var(--content-width) + 2 * var(--gutter));
    margin: 0 auto;
    padding: 16px calc(var(--gutter) + 2px) 40px;
    color: var(--ink-3);
    font-size: 13px;
}

.site-footer nav ul {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;

    & a {
        color: var(--ink-2);

        &:hover {
            color: var(--link-hi);
        }
    }
}

/* ============================================
   Homepage
   Your projects and invites on the side, what happened in them in the main column, then
   projects to explore. A visitor gets the pitch on the side instead.
   ============================================ */

.welcome {
    display: flex;
    flex-direction: column;
    gap: 12px;

    & h1 {
        font-size: 26px;
        line-height: 1.15;
    }

    & .meta {
        margin-top: -2px;
    }
}

/* The viewer's projects with their big bunnies. A big bunny gets its room (see .bunnicon): 16px to
   the sides (the gap), and 20px above its tile: the link's 8px padding plus 12px above the list
   (under the heading's descenders) or 12px between rows, so the ears stay clear of the row above. */
.project-list {
    display: flex;
    flex-direction: column;
    gap: 12px;
    margin: 12px -8px 0;
    list-style: none;

    & a {
        display: flex;
        align-items: center;
        gap: 16px;
        padding: 8px;
        border-radius: var(--r-2);
        color: var(--ink);
        text-decoration: none;

        &:hover {
            background-color: var(--surface);
            text-decoration: none;

            & strong {
                color: var(--link-hi);
            }
        }
    }

    & .empty {
        padding: 0 8px 8px;
        color: var(--ink-2);
    }
}

@media (max-width: 600px) {
    /* Exactly half on a phone: the 40px-ish tile with the sprite at 1× */
    .project-list .bunnicon--big {
        zoom: 0.5;
    }
}

.project-list__text {
    display: flex;
    flex-direction: column;
    min-width: 0;

    & strong {
        overflow-wrap: anywhere;
    }
}

/* What is new in a project, under its role: waiting join requests */
.project-list__news {
    color: var(--link);
    font-size: 13px;
    font-weight: 600;
}

.split__side > section.home-invites {
    margin: 10px 16px 0;
    padding: 14px 0 20px;
    border-top: 1px solid var(--line);
}

/* What needs an answer: each its own line with its buttons */
.answer-list {
    display: flex;
    flex-direction: column;
    gap: 14px;
    list-style: none;

    & > li {
        display: flex;
        flex-direction: column;
        gap: 6px;
    }
}

/* Projects to explore: a bunny, the name and the start of the introduction, members, joining */
.explore-list {
    margin-inline: calc(-1 * var(--part-x));
    list-style: none;

    & > li {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 4px 14px;
        padding: 12px var(--part-x);
        border-top: 1px solid var(--line-row);
    }

    & > li.empty {
        color: var(--ink-2);
    }
}

.explore-list__text {
    display: flex;
    flex: 1 1 260px;
    flex-direction: column;
    min-width: 0;

    & a {
        font-weight: 700;
    }

    & span {
        color: var(--ink-2);
    }
}

.explore-list__members {
    flex: none;
    width: 100px;
    color: var(--ink-3);
    font-size: 13px;
}

.explore-list__join {
    flex: none;
    width: 100px;
    color: var(--ink-3);
    font-size: 13px;
    font-weight: 600;
}

.explore-list__join--open {
    color: var(--clover);
}

.explore-list__join--request {
    color: var(--link);
}

@media (max-width: 600px) {
    .explore-list__members,
    .explore-list__join {
        width: auto;
        margin-left: 54px;
    }

    .explore-list__join {
        margin-left: 0;
    }
}

/* Recent activity on the homepage: what waits for an answer, then a list per day */
.home-activity > .heading-row h1 {
    font-size: 20px;
}

.split__main > section > .day-label {
    margin-top: 18px;
}

.split__main > section > .day-label + .activity-list {
    margin-top: 4px;
}

/* Who did what, with the project's or the person's bunny and the time on the right */
.activity-list {
    margin-inline: calc(-1 * var(--part-x));
    list-style: none;

    & > li {
        display: flex;
        align-items: flex-start;
        gap: 14px;
        padding: 12px var(--part-x);
        border-bottom: 1px solid var(--line-row);
    }

    & > li:last-child {
        border-bottom: 0;
    }

    & time {
        flex: none;
        color: var(--ink-3);
        font-size: 13px;
    }

    & .button-row {
        padding-top: 6px;
    }

    & .button {
        min-height: 32px;
        padding: 0 14px;
    }
}

.activity-list__text {
    display: flex;
    flex: 1 1 auto;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
    overflow-wrap: anywhere;
}

/* What someone wrote with it, such as the message of a join request */
.activity-list__quote {
    margin: 2px 0;
    padding-left: 12px;
    border-left: 2px solid var(--line-strong);
    color: var(--ink-2);
}

/* "Today", "Yesterday" over a day's activity */
.day-label {
    color: var(--ink-3);
    font-size: 13px;
    font-weight: 700;
}

/* People with their bunnies: the members table, the list of public profiles */
.person {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    vertical-align: middle;
}

.people-list {
    display: flex;
    flex-direction: column;
    list-style: none;

    & > li {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 6px 10px;
        padding: 8px 0;
        border-top: 1px solid var(--line-row);

        &:first-child {
            border-top: 0;
        }
    }
}

/* Members on a project's side column: a bunny, the name, the role on the right */
.member-rows {
    display: flex;
    flex-direction: column;
    list-style: none;

    & > li {
        display: flex;
        align-items: center;
        gap: 10px;
        padding: 5px 0;
    }

    & .member-rows__name {
        flex: 1 1 auto;
        min-width: 0;
        font-weight: 600;
        overflow-wrap: anywhere;
    }

    & + p {
        margin-top: 6px;
    }
}

.project-cell {
    display: flex;
    align-items: center;
    gap: 12px;

    & > div {
        display: flex;
        flex-direction: column;
        gap: 2px;
        min-width: 0;
    }

    & a {
        font-weight: 600;
    }
}

/* Invites on Your projects */
ul.project-invites {
    display: flex;
    flex-direction: column;
    gap: 8px;
    list-style: none;

    & > li {
        padding: 12px 14px;
        border: 1px solid rgb(181 80 28 / 0.3);
        border-radius: var(--r-2);
        background-color: #fbf1eb;
    }
}

/* ============================================
   Projects
   ============================================ */

/* The top of every project page: its bunny, name and the viewer's role, then its areas as tabs.
   On the overview the head is bigger, with the introduction and what to do. */
.project-bar__head {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    padding: 10px var(--part-x) 8px;
}

.project-bar__name {
    color: var(--ink);
    font-size: 17px;
    font-weight: 700;
    line-height: 1.25;

    &:is(a):hover {
        color: var(--link-hi);
    }
}

.project-bar__role {
    color: var(--ink-3);
    font-size: 13px;
}

/* 20px above the big bunny's tile for the ears of a tall one, below the panel's edge. On a phone the
   14px beside it is 2px short of the longest bunny (lying-long, 16px past the tile): the panel's
   edge cuts its last pixel, on purpose. An allowance on the tile (overflow-clip-margin) would clip
   the ears as well, and more padding would put the head out of line with the tabs below it. */
.project-bar__head--full {
    align-items: center;
    gap: 12px 16px;
    padding: 20px var(--part-x) 16px;

    & .project-bar__name {
        font-size: 24px;
    }
}

.project-bar__about {
    display: flex;
    flex: 1 1 320px;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
}

.project-bar__title {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 4px 10px;
}

.project-bar__intro {
    color: var(--ink-2);

    & > * + * {
        margin-top: 4px;
    }
}

.project-bar__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 14px;
    font-size: 14px;
}

.project-bar__tabs {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    padding: 0 calc(var(--part-x) - 10px);
    overflow-x: auto;
    border-top: 1px solid var(--line-row);

    & ul {
        display: flex;
        flex-wrap: wrap;
        align-items: center;
    }

    /* The two groups of tabs: the work, then running the project */
    & ul + ul::before {
        content: "";
        width: 1px;
        height: 18px;
        margin: 0 6px;
        background-color: var(--line-strong);
    }

    & li {
        display: flex;
        align-items: center;
    }

    & li a {
        display: inline-flex;
        align-items: center;
        min-height: 44px;
        padding: 0 10px;
        border-bottom: 2px solid transparent;
        color: var(--ink-3);
        font-weight: 600;
        text-decoration: none;

        &:hover {
            color: var(--ink);
            text-decoration: none;
        }

        &[aria-current="page"] {
            border-bottom-color: var(--carrot);
            color: var(--ink);
        }

        &:has(+ .count-badge) {
            padding-right: 6px;
        }
    }

    & li .count-badge {
        margin-right: 10px;
    }
}

/* On a phone the tabs stay one row that scrolls sideways, instead of wrapping under a separator */
@media (max-width: 600px) {
    .project-bar__tabs,
    .project-bar__tabs ul {
        flex-wrap: nowrap;
    }

    .project-bar__tabs li a {
        white-space: nowrap;
    }
}

/* The viewer's place in a project, under its tabs: join, answer an invite, leave */
.panel > section.project-membership {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 14px;
    padding-block: 10px;
    background-color: var(--surface-2);
    font-size: 14px;

    & > * + * {
        margin-top: 0;
    }

    & form:not(.inline-form) {
        display: flex;
        flex: 1 1 100%;
        flex-wrap: wrap;
        align-items: flex-end;
        gap: 8px 12px;

        & label {
            flex: 1 0 100%;
            margin: 0;
        }

        & textarea {
            flex: 1 1 320px;
            min-height: 60px;
        }

        & button {
            margin: 0;
        }
    }
}

/* The area filter of the audit log and the moderation log: a row of chips */
.audit-filter {
    display: flex;
    flex-wrap: wrap;
    gap: 6px;
    list-style: none;

    & a {
        display: inline-block;
        padding: 3px 10px;
        border-radius: var(--r-1);
        background-color: var(--surface-3);
        color: var(--ink);
        font-size: 13px;
        font-weight: 600;
        text-decoration: none;

        &:hover {
            background-color: var(--surface-4);
        }

        &[aria-current="page"] {
            background-color: var(--ink);
            color: #fff;
        }
    }
}

/* The audit log: one line per change, the time first */
.audit-log {
    list-style: none;

    & > li {
        padding: 9px 0;
        border-top: 1px solid var(--line-row);

        &:first-child {
            border-top: 0;
        }

        & > time {
            margin-right: 8px;
            color: var(--ink-3);
            font-size: 13px;
        }
    }
}

/* Writing, world items and places pinned to them */
.world-places {
    margin-top: 24px;
    padding: 12px 16px 14px;
    border: 1px solid var(--line);
    border-radius: var(--r-2);
    background-color: var(--surface-2);

    & h2 {
        display: flex;
        align-items: center;
        gap: 6px;
        margin-bottom: 6px;
        font-size: 15px;

        & svg {
            color: var(--ink-3);
        }
    }

    & ul {
        display: flex;
        flex-direction: column;
        gap: 4px;
        list-style: none;
    }
}

/* The "new object" form: one tile per base shape */
form.new-object {
    display: flex;
    flex-direction: column;
    gap: 12px;

    & small {
        display: block;
    }
}

.new-object__shapes {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
    gap: 10px;
}

label.new-object__shape {
    position: relative;
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin: 0;
    padding: 12px 14px;
    border: 1px solid var(--line-field);
    border-radius: var(--r-2);
    background-color: var(--surface);
    font-weight: 400;
    cursor: pointer;

    &:hover {
        border-color: #aab4be;
    }

    &:has(input[type="radio"]:checked) {
        border-color: var(--carrot);
        box-shadow: 0 0 0 1px var(--carrot);
        background-color: var(--carrot-soft);
    }

    &:has(input:focus-visible) {
        outline: 2px solid var(--link);
        outline-offset: 2px;
    }

    & input[type="radio"] {
        position: absolute;
        opacity: 0;
    }
}

.new-object__shape-name {
    display: flex;
    align-items: center;
    gap: 8px;
    font-weight: 700;

    & svg {
        color: var(--ink-2);
        font-size: 20px;
    }
}

.new-object__param {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--ink-2);
    font-size: 14px;

    & input[type="range"] {
        flex: 1;
        min-width: 0;
    }

    & output {
        font-variant-numeric: tabular-nums;
    }
}

/* ============================================
   Forum
   ============================================ */

/* A thread's title, what it is and who started it, and what to do with it */
.panel > section.thread-head {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    justify-content: space-between;
    gap: 8px 20px;
    padding-bottom: 14px;

    & > * + * {
        margin-top: 0;
    }
}

.thread-head__title {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;

    & > p:not(.meta) {
        margin-top: 6px;
    }
}

.thread-head__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 14px;
    font-size: 14px;
}

/* Pinned, locked, hidden: words in the meta line, the carrot one first */
.thread-mark {
    color: var(--carrot-text);
    font-weight: 700;
}

/* The moderators' tools: a quiet strip across the panel */
.panel > section.moderation-tools {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 18px;
    padding-block: 8px;
    background-color: var(--surface-2);
    font-size: 14px;

    & > * + * {
        margin-top: 0;
    }

    & h2 {
        color: var(--ink-2);
        font-size: 13px;
    }

    & > p {
        display: flex;
        flex-wrap: wrap;
        gap: 4px 14px;
    }

    & form.inline-form:has(input, select) {
        display: inline-flex;
        flex-wrap: wrap;
        align-items: center;
        gap: 6px;
    }

    & :is(input[type="text"], select) {
        min-height: 30px;
        padding-block: 2px;
        font-size: 14px;
    }

    & input[type="text"] {
        width: 180px;
    }
}

/* The posts: who on the left, what they wrote on the right */
.panel > section.forum-posts {
    padding: 0;

    & > * + * {
        margin-top: 0;
    }

    & > .pager {
        padding: 10px var(--part-x);
    }
}

.forum-post {
    display: grid;
    grid-template-columns: 160px minmax(0, 1fr);
    grid-template-areas:
        "author meta"
        "author text"
        "author actions";
    grid-template-rows: auto 1fr auto;
    border-bottom: 1px solid var(--line-row);
    overflow-wrap: anywhere;

    /* The header holds both who posted and when; its parts take their own places in the grid */
    & > header {
        display: contents;
    }
}

/* 20px above the big bunny's tile: a tall one's ears stay inside the post, clear of the post above
   (and of the top of the posts' section, which clips) */
.forum-post__author {
    grid-area: author;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 6px;
    padding: 20px var(--part-x) 16px;
    border-right: 1px solid var(--line-row);
    background-color: #fafbfc;

    & > span {
        display: flex;
        flex-direction: column;
    }

    & strong {
        color: var(--ink);
    }
}

.forum-post__meta {
    grid-area: meta;
    padding: 16px var(--part-x) 0;
    color: var(--ink-3);
    font-size: 13px;

    & .report-link,
    & small {
        font-size: inherit;
    }
}

.forum-post__text {
    grid-area: text;
    display: flex;
    flex-direction: column;
    gap: 10px;
    padding: 10px var(--part-x) 0;

    & > p {
        max-width: 72ch;
        font-size: 16px;
        line-height: 1.65;
    }
}

.forum-post__actions {
    grid-area: actions;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 14px;
    padding: 10px var(--part-x) 16px;
    font-size: 13px;

    & form.inline-form:has(input) {
        display: inline-flex;
        align-items: center;
        gap: 6px;
    }

    & input[type="text"] {
        width: 170px;
        min-height: 28px;
        padding-block: 2px;
        font-size: 13px;
    }

    & form.inline-form :is(input:not([type="hidden"]), select) ~ button {
        min-height: 28px;
        font-size: 13px;
    }
}

@media (max-width: 600px) {
    .forum-post {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas:
            "author"
            "meta"
            "text"
            "actions";
    }

    /* The bunny, zoomed, sticks out up to 8px beside its tile and 10px above it: the gap keeps it off
       the name, the padding inside the post */
    .forum-post__author {
        flex-direction: row;
        align-items: center;
        gap: 10px;
        padding-block: 10px;
        border-right: 0;
        border-bottom: 1px solid var(--line-row);

        /* Exactly half: the sprite at 1×, still square pixels */
        & .bunnicon--big {
            zoom: 0.5;
        }
    }

    .forum-post__meta {
        padding-top: 12px;
    }
}

/* Replying: the viewer's bunny on the left, as in a post */
.panel > section.forum-reply {
    display: grid;
    grid-template-columns: 160px minmax(0, 1fr);
    padding: 0;
    background-color: var(--surface-2);

    & > * + * {
        margin-top: 0;
    }

    /* 20px above the big bunny's tile, as in a post: the section clips at its top */
    & > .forum-reply__who {
        padding: 20px var(--part-x) 16px;
    }

    & > .forum-reply__form {
        display: flex;
        flex-direction: column;
        gap: 8px;
        padding: 16px var(--part-x) 20px;

        & > * {
            margin: 0;
        }
    }

    & label {
        margin: 0;
        font-size: 15px;
    }

    /* The rich text editor, about as tall as the five lines the reply box had before it */
    & .rich-text-field {
        display: flex;
        flex-direction: column;
        gap: 8px;
        max-width: 760px;

        & > * {
            margin: 0;
        }
    }

    & :is(.rich-text-editor__surface, .rich-text-editor__preview) {
        min-height: 140px;
    }

    & .rich-text-editor__surface > .ProseMirror {
        min-height: 116px;
    }

    & .button-row {
        gap: 12px;
    }
}

@media (max-width: 600px) {
    .panel > section.forum-reply {
        grid-template-columns: minmax(0, 1fr);

        & > .forum-reply__who {
            display: none;
        }
    }
}

/* ============================================
   Accounts, reports, moderation
   ============================================ */

.auth-badge {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 8px 12px;
    border: 1px solid;
    border-radius: var(--r-2);
    font-size: 14px;
    font-weight: 600;

    & svg {
        flex: none;
        width: 18px;
        height: 18px;
    }
}

.auth-badge--full {
    border-color: rgb(60 122 58 / 0.35);
    background-color: var(--clover-soft);
    color: var(--clover);
}

.auth-badge--remembered {
    border-color: rgb(138 106 0 / 0.35);
    background-color: var(--mustard-soft);
    color: var(--mustard);
}

/* The bar that says saving needs a fresh login code (login-needed controller), above the editors */
p.login-needed {
    position: fixed;
    right: var(--gutter);
    bottom: var(--gutter);
    left: var(--gutter);
    z-index: 200;
    max-width: 640px;
    margin: 0 auto;
    box-shadow: var(--shadow-pop);

    &[hidden] {
        display: none;
    }

    & > span {
        flex: 1;
    }
}

.login-needed__close {
    flex: none;
    padding: 0;
    border: 0;
    background: none;
    color: var(--ink-2);
    cursor: pointer;

    & svg {
        width: 18px;
        height: 18px;
    }
}

/* What makes a new password easy to guess, while typing (password-strength controller) */
.panel section .password-strength {
    color: var(--clover);

    &.is-weak {
        color: var(--mustard);
    }
}

/* The danger zone of the project settings and the account deletion */
.panel > section.danger-zone > h2 {
    color: var(--rose);
}

/* Dev-only login bypass */
.panel > section.dev-login-section {
    border-top: 1px dashed var(--rose);
    background-color: var(--rose-soft);
}

.dev-login-badge {
    display: inline-block;
    padding: 1px 8px;
    border-radius: var(--r-1);
    background-color: var(--rose);
    color: #fff;
    font-size: 12px;
    font-weight: 700;
}

main input.dev-login-submit {
    background-color: var(--rose);

    &:hover {
        background-color: var(--rose-hi);
    }
}

/* A login panel: the bunny sits by the title */
.login-head {
    display: flex;
    align-items: flex-end;
    gap: 12px;
    margin-bottom: 4px;
}

/* Your avatar (#10), on its page and on Your account: the tile (the avatar, or a random bunny)
   beside what is said about it. A big bunny gets its room: 16px beside it (the gap, and the
   section's padding on the left) and 20px above (8px here and the 12px between the section's
   parts). */
.avatar-current,
.avatar-summary {
    display: flex;
    align-items: center;
    gap: 16px;

    & p + p {
        margin-top: 8px;
    }
}

.avatar-current {
    padding-top: 8px;
}

.avatar-summary {
    gap: 12px;
}

/* The cropper (avatar-crop controller): the image with the square over it, and beside it (under
   it on a phone) the previews, the size slider and the buttons. The square is placed in
   percentages of the image, so the stage is exactly the image's box; its shadow dims the rest of
   the image, cut off at the stage's edge. Without JavaScript there is no square to show. */
.avatar-crop {
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 20px;
}

.avatar-crop__stage {
    position: relative;
    max-width: 100%;
    overflow: hidden;
    border-radius: var(--r-2);
    background-color: var(--surface-2);
    cursor: crosshair;
    touch-action: none;
    -webkit-user-select: none;
    user-select: none;

    & > img {
        display: block;
        max-width: 100%;
        height: auto;
        pointer-events: none;
    }
}

/* A small image (pixel art) shown a whole number of times bigger keeps its pixels square */
.avatar-crop__stage--pixels > img {
    image-rendering: pixelated;
}

.avatar-crop__square {
    position: absolute;
    display: none;
    box-shadow: 0 0 0 9999px color-mix(in srgb, var(--ink) 55%, transparent);
    outline: 2px solid var(--surface);
    outline-offset: -2px;
    cursor: move;

    &:focus-visible {
        outline: 3px solid var(--carrot);
        outline-offset: -3px;
    }
}

.avatar-crop.is-ready .avatar-crop__square {
    display: block;
}

/* The corner that resizes the square: inside it, so the image's edge never cuts it off, with a
   bigger target around it for a finger */
.avatar-crop__handle {
    position: absolute;
    right: 0;
    bottom: 0;
    width: 14px;
    height: 14px;
    border: 2px solid var(--carrot);
    border-radius: var(--r-1);
    background-color: var(--surface);
    cursor: nwse-resize;

    &::before {
        content: "";
        position: absolute;
        inset: -10px;
    }
}

.avatar-crop.is-moving .avatar-crop__stage,
.avatar-crop.is-moving .avatar-crop__square {
    cursor: grabbing;
}

.avatar-crop.is-resizing .avatar-crop__stage,
.avatar-crop.is-resizing .avatar-crop__square {
    cursor: nwse-resize;
}

.avatar-crop__side {
    display: flex;
    flex: 1 1 240px;
    flex-direction: column;
    gap: 16px;
    min-width: 0;

    & h2 {
        font-size: 15px;
    }

    & input[type="range"] {
        width: 100%;
    }
}

.avatar-crop__previews > * + * {
    margin-top: 8px;
}

.avatar-crop__tiles {
    display: flex;
    align-items: flex-end;
    gap: 16px;
}

/* The two tiles an avatar is shown in, as .bunnicon--avatar: 72px next to forum posts, 40px in
   lists. The whole image lies in it, scaled and moved so the square fills the tile. */
.avatar-crop__tile {
    position: relative;
    flex: none;
    overflow: hidden;
    width: 40px;
    height: 40px;
    border-radius: var(--r-2);
    background-color: var(--surface-3);

    & > img {
        position: absolute;
        top: 0;
        left: 0;
        max-width: none;
        transform-origin: 0 0;
    }
}

.avatar-crop__tile--big {
    width: 72px;
    height: 72px;
}

/* ============================================
   Error pages
   ============================================ */

.panel > section.error-page {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 24px 40px;
    padding: 40px var(--part-x);

    & > * + * {
        margin-top: 0;
    }
}

.error-page__art {
    display: flex;
    flex: none;
    align-items: center;
    justify-content: center;
    width: 160px;
    height: 120px;
    border-radius: var(--r-2);
    background-color: var(--bun-tile);
}

.error-page__text {
    display: flex;
    flex: 1 1 320px;
    flex-direction: column;
    gap: 10px;
}

.error-page__links {
    display: flex;
    flex-wrap: wrap;
    gap: 6px 16px;
    padding: 0;
    list-style: none;
}

.error-page__code {
    color: var(--ink-3);
    font-size: 14px;
}

/* ============================================
   The rich text editor (RichTextType, rich-text_controller.js): a toolbar strip over the text,
   which wears the same .rich-text styles as the read pages, so writing looks like reading.
   ============================================ */

.rich-text-editor {
    position: relative;
    border: 1px solid var(--line-field);
    border-radius: var(--r-1);
    background-color: var(--surface);

    &:focus-within {
        border-color: var(--link);
        box-shadow: 0 0 0 3px rgb(34 96 158 / 0.18);
    }
}

.rich-text-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px 10px;
    padding: 4px 6px;
    border-bottom: 1px solid var(--line);
    border-radius: var(--r-1) var(--r-1) 0 0;
    background-color: var(--surface-2);
}

.rich-text-toolbar__group {
    display: inline-flex;
    flex-wrap: wrap;
    gap: 2px;
}

.rich-text-toolbar__button {
    min-width: 30px;
    min-height: 30px;
    padding: 0 6px;
    background-color: transparent;
    color: var(--ink-2);

    &:hover {
        background-color: var(--surface-3);
    }

    &[aria-pressed="true"] {
        background-color: var(--carrot-soft);
        color: var(--carrot-text);
    }

    & svg {
        width: 18px;
        height: 18px;
    }
}

.rich-text-toolbar__modes {
    display: inline-flex;
    margin-left: auto;
    gap: 2px;
}

.rich-text-toolbar__mode {
    min-height: 30px;
    padding: 0 10px;
    background-color: transparent;
    color: var(--ink-2);
    font-size: 13px;

    &:hover {
        background-color: var(--surface-3);
    }

    &[aria-pressed="true"] {
        box-shadow: inset 0 -2px 0 var(--carrot);
        color: var(--ink);
    }
}

.rich-text-editor__surface,
.rich-text-editor__preview {
    max-width: none;
    min-height: 220px;
    padding: 12px 14px;
}

.rich-text-editor__surface > .ProseMirror {
    min-height: 196px;
    outline: none;
}

.rich-text-editor__preview {
    background-color: var(--surface-2);
}

/* What ProseMirror needs from a stylesheet (prosemirror-view/style/prosemirror.css) */
.ProseMirror {
    position: relative;
    overflow-wrap: break-word;
    white-space: pre-wrap;
    white-space: break-spaces;
    font-variant-ligatures: none;
    font-feature-settings: "liga" 0;

    & pre {
        white-space: pre-wrap;
    }

    & li {
        position: relative;
    }

    & [draggable][contenteditable="false"] {
        user-select: text;
    }
}

.ProseMirror-hideselection *::selection {
    background: transparent;
}

.ProseMirror-hideselection {
    caret-color: transparent;
}

.ProseMirror-selectednode {
    outline: 2px solid var(--link);
    outline-offset: 1px;
}

img.ProseMirror-separator {
    display: inline !important;
    margin: 0 !important;
    border: none !important;
}

/* The @ list, the link field and the import question, under the cursor */
.rich-text-popover {
    position: absolute;
    z-index: 20;
    width: min(340px, 100%);
    padding: 6px;
    border: 1px solid var(--line-strong);
    border-radius: var(--r-2);
    background-color: var(--surface);
    box-shadow: var(--shadow-pop);
    font-size: 14px;

    & > p {
        margin: 4px 4px 8px;
    }

    & .button-row {
        display: flex;
        flex-wrap: wrap;
        gap: 6px;
    }

    & input[type="search"] {
        width: 100%;
        margin-bottom: 6px;
    }
}

.rich-text-popover__form {
    display: flex;
    gap: 6px;

    & input {
        flex: 1;
        min-width: 0;
    }
}

.rich-text-popover__list {
    max-height: 260px;
    margin: 0;
    padding: 0;
    overflow-y: auto;
    list-style: none;

    & li {
        display: flex;
        align-items: baseline;
        gap: 8px;
        padding: 5px 8px;
        border-radius: var(--r-1);
        cursor: pointer;
    }

    & li[aria-selected="true"],
    & li[role="option"]:hover {
        background-color: var(--link-soft);
    }

    & .inline-badge {
        flex: none;
    }
}

.rich-text-popover__title {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

li.rich-text-popover__empty {
    color: var(--ink-3);
    cursor: default;
}

/* Mentions in the editor: a link to writing reads as @Title, a snippet as its own text */
.rich-text-editor .mention {
    padding: 0 3px;
    border-radius: var(--r-1);
    background-color: var(--link-soft);
    color: var(--link);
    white-space: normal;
}

.rich-text-editor .mention--snippet {
    background-color: transparent;
    color: inherit;
    text-decoration: underline dotted var(--link);
    text-underline-offset: 3px;
}

.rich-text-editor :is(.mention--missing, .mention--deleted) {
    background-color: var(--rose-soft);
    color: var(--rose);
}

.rich-text-editor .doc-link {
    color: var(--link);
    text-decoration-style: dotted;
}

/* Images in the editor (#11): the read pages' sizes (.rich-text-image), room to click one that
   has not loaded, and an outline round the picture when it is selected. Under a selected image
   float its size and alt text controls; an upload holds its place with the loader bunny. */
.rich-text-editor .rich-text-image {
    min-height: 24px;

    &.ProseMirror-selectednode {
        outline: none;

        & img {
            outline: 2px solid var(--link);
            outline-offset: 2px;
        }
    }
}

.rich-text-editor .rich-text-upload {
    margin: 0 4px;
    vertical-align: bottom;
}

.rich-text-image-tools {
    position: absolute;
    z-index: 15;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 6px 12px;
    width: min(460px, 100%);
    padding: 6px 8px;
    border: 1px solid var(--line-strong);
    border-radius: var(--r-2);
    background-color: var(--surface);
    box-shadow: var(--shadow-pop);

    &[hidden] {
        display: none;
    }
}

.rich-text-image-tools__sizes {
    display: inline-flex;
    gap: 2px;
}

.rich-text-image-tools__size {
    font-size: 13px;
}

.rich-text-image-tools__alt {
    display: flex;
    flex: 1 1 220px;
    align-items: center;
    gap: 8px;
    margin: 0;
    color: var(--ink-2);
    font-size: 13px;
    font-weight: 400;

    & input {
        flex: 1;
        min-width: 0;
        min-height: 32px;
        padding: 4px 8px;
        font-size: 14px;
    }
}

/* The picker: the project's images as square thumbnails, then uploading. It holds the focus
   itself while the images load. */
.rich-text-popover--image {
    width: min(420px, 100%);

    &:focus {
        outline: none;
    }
}

.rich-text-popover__heading {
    font-weight: 700;
}

.rich-text-image-picker {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(76px, 1fr));
    gap: 6px;
    max-height: 264px;
    margin: 0 0 8px;
    padding: 2px;
    overflow-y: auto;
    list-style: none;

    & button {
        display: block;
        width: 100%;
        min-height: 0;
        aspect-ratio: 1;
        padding: 0;
        overflow: hidden;
        border: 1px solid var(--line);
        border-radius: var(--r-1);
        background-color: var(--surface-2);

        &:hover {
            border-color: var(--link);
        }
    }

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

/* Sounds in the editor (#11): the read pages' player (.rich-text-audio) with a little room round
   it, where a click selects the sound (a click on the player plays it); the outline shows it is
   selected. Under a selected sound floats its caption field, in the image tools' bar. In the
   picker a sound is a tile with an icon, its title and its length. */
.rich-text-editor .rich-text-audio {
    width: min(100% + 12px, 492px);
    margin-inline: -6px;
    padding: 6px;
    border-radius: var(--r-2);

    &:hover {
        background-color: var(--surface-2);
    }
}

.rich-text-image-picker .rich-text-image-picker__sound {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 2px;
    padding: 6px 4px;
    color: var(--ink-2);
    font-size: 12px;
    font-weight: 400;
    line-height: 1.25;

    & svg {
        flex: none;
        width: 22px;
        height: 22px;
        color: var(--ink-3);
    }
}

.rich-text-image-picker__title {
    display: -webkit-box;
    max-width: 100%;
    overflow: hidden;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    overflow-wrap: anywhere;
    text-align: center;
}

.rich-text-image-picker__duration {
    color: var(--ink-3);
    font-variant-numeric: tabular-nums;
}

/* Why an upload was refused, under the text */
.rich-text-editor__message {
    display: flex;
    align-items: flex-start;
    gap: 8px;
    padding: 4px 6px 4px 14px;
    border-top: 1px solid var(--line);
    border-radius: 0 0 var(--r-1) var(--r-1);
    background-color: var(--rose-soft);
    color: var(--rose);
    font-size: 14px;

    &[hidden] {
        display: none;
    }

    & > div {
        flex: 1;
        padding-top: 5px;
    }

    & p {
        margin: 0;
    }
}

/* ============================================
   Reduced motion: last, so it wins over every animation above
   ============================================ */

@media (prefers-reduced-motion: reduce) {
    .loader::before,
    .loader::after,
    .disabled::before {
        animation: none;
    }

    .logo .bunny {
        transition: none;
    }

    .logo:hover .bunny {
        translate: none;
    }
}
