        :root {
            --color-bg: #fff;
            --color-fg: #000;
            --color-dim: #999;
            --color-dimmer: #ccc;
            --color-danger: #c00;
            --dist: 3px;
            --gap-page: 3rem;
            --gap-sections: 4em;
        }

        html {
            font-family: monospace;
            font-size: 12px;
        }

        body {
            min-height: 100vh;
            min-height: 100dvh;
            display: flex;
            flex-direction: column;
            row-gap: var(--gap-page);
        }

        main {
            flex: 1;
        }

        /* vertical rhythm between the sections inside a container */
        .flex-container {
            display: flex;
            flex-direction: column;
            row-gap: var(--gap-sections);
        }

        .container {
            max-width: 100rem;
            margin-inline: auto;
            padding: 1.5rem 1.25rem;
        }

        .grid-table {
            display: grid;
            /* the column tracks (and the min-width that forces the overflow)
               come from the per-table .cols-* class */
            gap: 1px;
            background: var(--color-dimmer);
        }

        /* rows are real elements so they can be dragged, but they borrow the
           parent's column tracks so cells still line up across rows */
        .grid-table>* {
            display: grid;
            grid-template-columns: subgrid;
            grid-column: 1 / -1;
        }

        .grid-table .cell {
            background: var(--color-bg);
            padding: 0.5rem 0.8rem;
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
        }

        .head-row .cell {
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }

        .num {
            text-align: right;
            font-variant-numeric: tabular-nums;
        }

        .table-scroll {
            overflow-x: auto;
            overscroll-behavior-x: contain;
            border: 2px solid var(--color-fg);
            /* moved off .grid-table */
            box-shadow: var(--dist) var(--dist) 0 var(--color-fg);
            margin-bottom: var(--dist);
        }

        /* toolbar sits at the right end of the header row */
        .table-toolbar {
            display: flex;
            justify-content: flex-end;
        }

        /* snap button: fixed black base, offset face that snaps flush on click */
        .btn-snap {
            position: relative;
            display: inline-block;
        }

        .btn-snap .base {
            position: absolute;
            inset: 0;
            background: var(--color-fg);
        }

        .btn-snap .face {
            position: relative;
            display: inline-block;
            font: inherit;
            padding: 0.5rem 1rem;
            background: var(--color-bg);
            color: var(--color-fg);
            border: 2px solid var(--color-fg);
            cursor: pointer;
            text-transform: uppercase;
            letter-spacing: 0.04em;
            transform: translate(calc(var(--dist) * -1), calc(var(--dist) * -1));
            transition: transform 80ms ease;
        }

        .btn-snap .face:active {
            transform: translate(0, 0);
        }

        /* modal: visibility is driven purely by data-open on the overlay */
        .modal {
            position: fixed;
            inset: 0;
            z-index: 100;
            display: grid;
            place-items: center;
            /* closed state. display can't transition, so the overlay stays laid
               out and fades instead; visibility is delayed by the full duration
               so it is still painted while it fades out */
            background: rgb(0 0 0 / 0);
            opacity: 0;
            visibility: hidden;
            pointer-events: none;
            transition: opacity 160ms ease, background 160ms ease, visibility 0s linear 160ms;
        }

        .modal[data-open="true"] {
            background: rgb(0 0 0 / 0.4);
            opacity: 1;
            visibility: visible;
            pointer-events: auto;
            transition: opacity 160ms ease, background 160ms ease, visibility 0s linear 0s;
        }

        .modal .modal-box {
            background: var(--color-bg);
            border: 2px solid var(--color-fg);
            box-shadow: var(--dist) var(--dist) 0 var(--color-fg);
            width: min(680px, calc(100vw - 4rem));
            padding: 1.25rem;
            transform: scale(0.96) translateY(-8px);
            transition: transform 160ms ease;
        }

        .modal[data-open="true"] .modal-box {
            transform: scale(1) translateY(0);
        }

        .modal .modal-title {
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.04em;
            margin-bottom: 1rem;
        }

        .modal .field {
            display: flex;
            flex-direction: column;
            gap: 0.35rem;
            margin-bottom: 1.25rem;
        }

        .modal .field label {
            color: var(--color-dim);
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }

        /* the guide's plain-text inputs: one line and, for columns the schema
           marks multi-line, the same box grown taller. Only the resize handle
           and the wrapping differ. */
        .modal .field input,
        .modal .field textarea {
            font: inherit;
            padding: 0.4rem 0.5rem;
            border: 1px solid var(--color-dimmer);
            border-radius: 0;
            background: var(--color-bg);
        }

        .modal .field textarea {
            resize: vertical;
            min-height: 5.5rem;
            line-height: 1.5;
        }

        .modal .field input:focus,
        .modal .field textarea:focus {
            outline: 2px solid var(--color-fg);
            outline-offset: -1px;
            border-color: var(--color-fg);
        }

        .modal .modal-actions {
            display: flex;
            justify-content: flex-end;
            gap: 0.75rem;
            margin-top: 1.25rem;
        }

        .btn-snap .face.fill {
            background: var(--color-fg);
            color: var(--color-bg);
        }

        .btn-snap .face.danger {
            background: var(--color-danger);
            border-color: var(--color-danger);
            color: var(--color-bg);
        }

        /* confirm dialogs have prose instead of fields */
        .modal .modal-text {
            line-height: 1.5;
        }

        .modal .modal-text strong {
            font-weight: 600;
        }

        /* drag handle column */
        .handle {
            cursor: grab;
            padding-inline: 0.6rem;
            color: var(--color-dim);
            text-align: center;
            user-select: none;
        }

        .handle:hover {
            color: var(--color-fg);
        }

        .row.sortable-chosen .handle {
            cursor: grabbing;
        }

        /* action columns */
        .cell.action {
            padding: 0;
        }

        .cell.action button {
            display: grid;
            place-items: center;
            width: 100%;
            height: 100%;
            padding: 0.5rem 0.7rem;
            border: 0;
            background: none;
            color: var(--color-dim);
            cursor: pointer;
        }

        .cell.action button:hover {
            color: var(--color-fg);
        }

        .cell.action button.delete:hover {
            color: var(--color-danger);
        }

        .cell.action svg {
            width: 1.15em;
            height: 1.15em;
            display: block;
        }

        /* while a drag is in progress, the rows that aren't being dragged
           step back to grey; the dragged row keeps its normal look */
        .grid-table.is-dragging .row:not(.sortable-ghost):not(.sortable-drag) .cell {
            color: var(--color-dim);
        }

        /* the row following the pointer is transparent, so restore the
           grid-line colour behind its 1px gaps */
        .sortable-drag {
            background: var(--color-dimmer);
        }

        /* per-table column tracks. .grid-table itself no longer hard-codes them.
           min-width is the same for every table for now. */
        .cols-team {
            grid-template-columns: auto auto auto 1fr auto auto;
            min-width: 760px;
        }

        .cols-links {
            grid-template-columns: auto auto 1fr auto auto;
            min-width: 760px;
        }

        .cols-gallery {
            grid-template-columns: auto auto 1fr auto auto;
            min-width: 760px;
        }

        .cols-users {
            grid-template-columns: auto 1fr auto auto;
            min-width: 760px;
        }

        /* contact runs vertically: one row per key. Column 1 is the field name,
           column 2 the value, so there is nothing to scroll sideways and no
           min-width forcing an overflow like the record tables above. The lead
           track is the shared spacer that keeps every table's left edge aligned. */
        .cols-contact {
            grid-template-columns: auto minmax(10rem, max-content) 1fr;
        }

        .cols-contact .cell.key {
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }

        /* the whole point of the vertical layout: multi-line values keep their
           breaks instead of being flattened into middots */
        .cols-contact .cell.multiline {
            white-space: pre-line;
            overflow: visible;
            text-overflow: clip;
        }

        /* users are unordered in the schema, so the lead cell is an empty
           spacer sized like a handle instead of a drag grip */
        .cell.spacer {
            padding-inline: 0.6rem;
            width: calc(1.2rem + 1ch);
        }

        /* header: brand on the left, current user + logout on the right */
        .header-bar {
            display: flex;
            align-items: baseline;
            justify-content: space-between;
            gap: 1rem;
            flex-wrap: wrap;
        }

        .header-brand,
        .header-user {
            display: flex;
            align-items: baseline;
            gap: 1rem;
        }

        .brand-title {
            font-size: 1.5rem;
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }

        .brand-link {
            color: var(--color-fg);
            text-decoration: underline;
        }

        .user-email {
            color: var(--color-dim);
        }

        /* the URL and File columns hold addresses, so they read as links even
           though the cell is plain text; column 3 in both tables */
        .cols-links .row .cell:nth-child(3) {
            text-decoration: underline;
        }

        /* heading and its create button share one baseline-free flex row */
        .table-header {
            display: flex;
            align-items: center;
            justify-content: space-between;
            gap: 1rem;
            margin-bottom: 0.75rem;
        }

        .section-title {
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }

        /* file field: native control is hidden behind a snap button, the
           current file name is echoed next to it */
        .modal .field input[type="file"] {
            position: absolute;
            width: 1px;
            height: 1px;
            opacity: 0;
            pointer-events: none;
        }

        .modal .file-row {
            display: flex;
            align-items: center;
            gap: 0.75rem;
            min-width: 0;
        }

        .modal .file-name {
            flex: 1;
            min-width: 0;
            overflow: hidden;
            text-overflow: ellipsis;
            white-space: nowrap;
            color: var(--color-dim);
        }

        .modal .file-hint {
            color: var(--color-dim);
            margin-top: 0.25rem;
        }

        .btn-snap .face.small {
            padding: 0.3rem 0.7rem;
        }

        /* gallery table: a fixed-size thumbnail stands in for the cropped
           derivative the backend will generate from the stored rectangle */
        .cell.thumb {
            padding: 0.35rem 0.8rem;
        }

        .cell.thumb img {
            display: block;
            width: 64px;
            height: 48px;
            object-fit: cover;
            border: 1px solid var(--color-fg);
        }

        /* team portraits are stored square, so the row shows a square crop */
        .cell.thumb.avatar img {
            width: 48px;
            height: 48px;
        }

        /* cropper.js replaces the <img> with its own container; height has to
           be pinned here or it collapses to nothing */
        .crop-stage {
            border: 1px solid var(--color-fg);
            background: var(--color-dimmer);
            height: 300px;
            overflow: hidden;
        }

        /* only matters for the split second before cropper.js takes over */
        .crop-stage img {
            display: block;
            max-width: 100%;
            max-height: 100%;
        }

        /* square off cropper's default rounded handles to match the rest */
        .cropper-view-box,
        .cropper-face {
            border-radius: 0;
        }

        .cropper-point {
            width: 7px;
            height: 7px;
            background: var(--color-fg);
            opacity: 1;
        }

        /* footer sits at the bottom of the viewport on short pages because
           body is a flex column with main taking the slack */
        .footer-credit {
            text-align: center;
            color: var(--color-dim);
        }

        /* rich-text bio: Squire owns .rte-body, everything around it is the
           same flat-bordered box the plain inputs use */
        .modal .field .rte-label {
            color: var(--color-dim);
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }

        .modal .rte {
            border: 1px solid var(--color-dimmer);
            background: var(--color-bg);
        }

        /* the outline sits on the wrapper, because focus lands on the
           contenteditable child and the border belongs to the whole box */
        .modal .rte:focus-within {
            outline: 2px solid var(--color-fg);
            outline-offset: -1px;
            border-color: var(--color-fg);
        }

        .modal .rte-tools {
            display: flex;
            gap: 0.25rem;
            padding: 0.3rem;
            border-bottom: 1px solid var(--color-dimmer);
        }

        .modal .rte-tools button {
            font: inherit;
            min-width: 1.9rem;
            padding: 0.15rem 0.4rem;
            border: 1px solid transparent;
            background: transparent;
            color: var(--color-fg);
            cursor: pointer;
        }

        .modal .rte-tools button:hover {
            border-color: var(--color-dimmer);
        }

        /* aria-pressed is the only state: no parallel class to keep in sync,
           and the indicator is what a screen reader reads out */
        .modal .rte-tools button[aria-pressed="true"] {
            background: var(--color-fg);
            color: var(--color-bg);
            border-color: var(--color-fg);
        }

        .modal .rte-body {
            min-height: 12rem;
            overflow-y: visible;
            padding: 0.4rem 0.5rem;
            outline: none;
        }

        /* the reset strips list markers and block spacing globally, so the
           editor has to put them back for its own content */
        .modal .rte-body p {
            margin: 0 0 0.5rem;
        }

        .modal .rte-body p:last-child {
            margin-bottom: 0;
        }

        .modal .rte-body ul {
            list-style: disc;
            padding-left: 1.25rem;
            margin: 0 0 0.5rem;
        }

        /* ------------------------------------------------------------------
           additions for the live admin (login, toast, image fields, pages)
           ------------------------------------------------------------------ */

        [hidden] {
            display: none !important;
        }

        /* login / forgot / reset: one centred box instead of the tables */
        .auth-view {
            min-height: 100vh;
            display: grid;
            place-items: center;
            padding: 1.25rem;
        }

        .auth-box {
            width: min(380px, 100%);
            border: 2px solid var(--color-fg);
            box-shadow: var(--dist) var(--dist) 0 var(--color-fg);
            padding: 1.5rem;
            background: var(--color-bg);
        }

        .auth-box .brand-title {
            display: block;
            margin-bottom: 1.25rem;
        }

        /* the auth forms reuse the modal's field styles */
        .auth-form .field {
            display: flex;
            flex-direction: column;
            gap: 0.25rem;
            margin-bottom: 0.75rem;
        }

        .auth-form .field label {
            color: var(--color-dim);
            text-transform: uppercase;
            letter-spacing: 0.04em;
        }

        .auth-form .field input {
            font: inherit;
            padding: 0.4rem 0.5rem;
            border: 1px solid var(--color-dimmer);
            border-radius: 0;
            background: var(--color-bg);
        }

        .auth-form .field input:focus {
            outline: 2px solid var(--color-fg);
            outline-offset: -1px;
            border-color: var(--color-fg);
        }

        .auth-form .modal-actions {
            display: flex;
            justify-content: space-between;
            align-items: center;
            gap: 0.75rem;
            margin-top: 1.25rem;
        }

        .auth-text {
            line-height: 1.5;
            margin-bottom: 1rem;
        }

        /* text-only button used for "Passwort vergessen" and "Entfernen" */
        .link-btn {
            font: inherit;
            border: 0;
            background: none;
            padding: 0;
            color: var(--color-fg);
            text-decoration: underline;
            cursor: pointer;
        }

        .link-btn:hover {
            color: var(--color-danger);
        }

        /* the edit modal is a form so Enter submits it */
        /* the edit form is a drawer that slides in from the right and fills
           the height. The fields sit in a 680px column on its left edge;
           the white space right of them is room to scroll. The delete
           confirm stays a small centred dialog. */
        #edit-modal {
            justify-items: end;
            align-items: stretch;
        }

        #edit-modal .modal-box {
            width: min(1100px, 100vw);
            height: 100vh;
            height: 100dvh;
            max-height: none;
            margin: 0;
            padding: 2.5rem 2rem 2.5rem 3rem;
            border-width: 0 0 0 2px;
            box-shadow: none;
            transform: translateX(100%);
            transition: transform 200ms ease;
        }

        #edit-modal[data-open="true"] .modal-box {
            transform: none;
        }

        #edit-modal .modal-box > * {
            max-width: 680px;
            margin-left: 0;
            margin-right: auto;
        }

        #edit-modal .modal-actions {
            margin-top: 4rem;
        }

        /* the box scrolls inside a padded overlay, so there is always some
           backdrop left and right to grab the page or click to close */
        .modal .modal-box {
            max-height: calc(100vh - 4rem);
            overflow-y: auto;
            margin: 2rem;
        }

        .modal .field input:disabled,
        .btn-snap .face:disabled {
            opacity: 0.5;
            cursor: default;
        }

        /* pages table: name, text preview, edit */
        .cols-pages {
            grid-template-columns: auto minmax(8rem, max-content) 1fr auto;
            min-width: 760px;
        }

        /* the team card aspect (600x410) instead of the square prototype */
        .cell.thumb.avatar img {
            width: 64px;
            height: 44px;
        }

        .cols-gallery .cell.thumb img {
            width: 48px;
            height: 48px;
        }

        .no-image {
            display: grid;
            place-items: center;
            color: var(--color-dim);
            border: 1px dashed var(--color-dimmer);
        }

        .cols-links .row .cell a {
            color: inherit;
            text-decoration: underline;
        }

        .cols-contact .cell.value {
            white-space: pre-line;
            overflow: visible;
            text-overflow: clip;
        }

        /* rich text: h3 inside the editor */
        .modal .rte-body h3 {
            font-weight: 600;
            text-transform: uppercase;
            letter-spacing: 0.04em;
            margin: 0.75rem 0 0.35rem;
        }

        .modal .rte-body a {
            text-decoration: underline;
        }

        .modal .rte-body ul li {
            margin-bottom: 0.15rem;
        }

        /* status message bottom centre */
        .toast {
            position: fixed;
            left: 50%;
            bottom: 1.5rem;
            transform: translateX(-50%);
            z-index: 200;
            background: var(--color-fg);
            color: var(--color-bg);
            padding: 0.6rem 1rem;
            border: 2px solid var(--color-fg);
            box-shadow: var(--dist) var(--dist) 0 var(--color-dimmer);
            max-width: calc(100vw - 2.5rem);
        }

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