:root {
    --ink: #3b2f1e;
    --ink-light: #6b5d48;
    --parchment: #f5f0e1;
    --parchment-dark: #ebe3cc;
    --gold: #e8c45a;
    --gold-dark: #b89635;
    --rust: #a04830;
    --moss: #5a7a3a;
    --rule: #d4c8a8;
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
    font-family: 'Inter', 'Source Sans 3', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    font-size: 1rem;
    line-height: 1.65;
    color: var(--ink);
    background-color: var(--parchment);
    background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='200' height='200'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/><feColorMatrix values='0 0 0 0 0.23 0 0 0 0 0.18 0 0 0 0 0.12 0 0 0 0.07 0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
}
h1, h2, h3, h4 {
    font-family: 'EB Garamond', 'Cormorant Garamond', Georgia, serif;
    color: var(--ink);
    font-weight: 600;
    letter-spacing: -0.01em;
}
h1 { font-size: 2.5rem; line-height: 1.15; margin-bottom: 1rem; }
h2 { font-size: 1.75rem; line-height: 1.2; margin-top: 2rem; margin-bottom: 0.75rem; }
h3 { font-size: 1.25rem; line-height: 1.3; }
p { margin-bottom: 0.75rem; }
a { color: var(--ink); text-decoration-color: var(--gold-dark); text-underline-offset: 3px; }
a:hover { text-decoration-color: var(--ink); }
.meta { color: var(--ink-light); font-size: 0.875rem; }
time, .num { font-variant-numeric: tabular-nums; }

/* Layout */
main {
    max-width: 42rem;
    margin: 2rem auto;
    padding: 0 1.5rem;
}
/* Pages that show event cards get more horizontal room so the text
   column is not squeezed between datestamp and image. The search form
   stays at the same width whether or not there are results, so the
   layout doesn't jump when the result set is empty. */
main:has(.event-row),
main:has(.search-form) {
    max-width: 56rem;
}
.container-wide {
    max-width: 64rem;
    margin: 0 auto;
    padding: 0 1.5rem;
}

/* Navigation */
.nav {
    border-bottom: 1px solid var(--rule);
    background: var(--parchment-dark);
}
.nav-inner {
    max-width: 64rem;
    margin: 0 auto;
    padding: 0.85rem 1.5rem;
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    /* Matches the inter-anchor margin inside .nav-links so the
       Oppsanket → avatar gap reads the same as Søk → Oppsanket. */
    gap: 1.5rem;
}
/* Logo + nav-links cluster left as "site navigation"; the avatar
   gets pushed to the right edge as the distinct "account" surface.
   Auto margin on .nav-user eats the slack between the two groups.
   For anonymous visitors (no avatar), .nav-anon-actions takes the
   same role — Logg inn / Registrer pin to the right edge. */
.nav-user, .nav-anon-actions { margin-left: auto; }
.nav-logo {
    font-family: 'EB Garamond', Georgia, serif;
    font-weight: 600;
    font-size: 1.5rem;
    color: var(--ink);
    text-decoration: none;
    letter-spacing: 0.02em;
}
.nav-links a {
    color: var(--ink);
    text-decoration: none;
    margin-left: 1.5rem;
    font-size: 0.95rem;
    border-bottom: 1px solid transparent;
    transition: border-color 0.1s;
}
.nav-links a:first-child { margin-left: 0; }
.nav-links a:hover {
    border-bottom-color: var(--gold-dark);
}
/* Pending-forespørsler counter next to Oppsanket. Inline so it sits
   on the same baseline as the link text; gold-dark fill matches the
   nav hover underline so the two affordances read as related. */
.nav-badge {
    display: inline-block;
    min-width: 1.25rem;
    padding: 0 0.4rem;
    background: var(--gold-dark);
    color: var(--paper);
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 600;
    line-height: 1.25rem;
    text-align: center;
    vertical-align: 1px;
}
/* User menu: <details> disclosure with the avatar (or text handle
   fallback) as the toggle and account links + logout inside the
   popup. No-JS native, mirrors the same pattern as .share-dropdown.
   Lives as a sibling of .nav-links (not inside it) so it stays
   visible on mobile next to the burger when .nav-links collapses. */
.nav-user {
    position: relative;
}
.nav-user-summary {
    cursor: pointer;
    list-style: none;
    color: var(--ink-light);
    font-size: 0.9rem;
    font-family: 'Inter', system-ui, sans-serif;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    gap: 0.25rem;
}
.nav-user-summary::-webkit-details-marker { display: none; }
.nav-user-summary::after {
    content: "\25BE"; /* ▾ */
    font-size: 0.75em;
    opacity: 0.7;
}
/* Hover affordance lives on the avatar (gold ring) when there is
   one; the text-handle fallback (no personal organizer) gets a
   caret-only hint. */
.nav-user-summary:hover .avatar {
    border-color: var(--gold-dark);
}
/* Header at the top of the popup: large display name + muted
   handle, separated from the menu items by a thin rule. */
.nav-user-header {
    padding: 0.4rem 0.6rem 0.5rem;
    margin-bottom: 0.25rem;
    border-bottom: 1px solid var(--rule);
}
.nav-user-name {
    font-weight: 600;
    color: var(--ink);
    font-size: 0.95rem;
    line-height: 1.3;
}
.nav-user-handle {
    color: var(--ink-light);
    font-size: 0.8rem;
    line-height: 1.3;
    word-break: break-all;
}
.nav-user-menu {
    position: absolute;
    right: 0;
    top: calc(100% + 4px);
    min-width: 160px;
    background: var(--parchment-dark);
    border: 1px solid var(--rule);
    border-radius: 4px;
    padding: 0.4rem;
    z-index: 20;
    box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
.nav-user-form { margin: 0; padding: 0; }
.nav-user-item, button.nav-user-item {
    display: block;
    width: 100%;
    margin: 0;
    padding: 0.4rem 0.6rem;
    text-align: left;
    text-decoration: none;
    background: none;
    border: none;
    border-radius: 3px;
    color: var(--ink);
    font: inherit;
    font-size: 0.95rem;
    cursor: pointer;
}
.nav-user-item:hover, button.nav-user-item:hover {
    background: var(--parchment);
    color: var(--ink);
}
/* Visual rule between Innstillinger and Logg ut: the destructive
   action sits in its own block so a slip of the finger / cursor
   can't easily land on it. */
.nav-user-divider {
    border: none;
    border-top: 1px solid var(--rule);
    margin: 0.35rem 0;
}
/* No burger — the nav has at most three top-level items (Søk,
   Oppsanket, avatar) and the avatar holds the rest in its popup, so
   there's nothing to collapse. nav-inner's flex-wrap handles the
   narrow-screen case by letting items wrap to a second row if the
   instance name + nav items overflow. */
/* Narrow-phone tightening so the avatar stays on the same line as
   the rest of the nav. Default desktop spacing (gap 1.5rem, anchor
   margin 1.5rem, outer padding 1.5rem) eats too much horizontal
   budget on a 360–400px viewport once the instance name is more
   than a few characters. */
@media (max-width: 480px) {
    .nav-inner {
        padding-left: 0.85rem;
        padding-right: 0.85rem;
        /* Asymmetric spacing on phones: gap between flex groups
           (logo / nav-links / avatar) stays roomy at 1.25rem so the
           logo reads as the brand mark, while the inter-anchor
           margin inside .nav-links shrinks to 0.5rem to keep the
           whole row inside a 375px viewport. */
        gap: 1.25rem;
    }
    .nav-links a { margin-left: 0.5rem; }
}

/* Installed-PWA app mode on narrow screens: the user has explicitly
   opted into the app experience, so we relocate the nav from the top
   to a fixed bottom bar — thumb-reachable, app-conventional, and frees
   the top for content. The logo drops entirely; "Søk" doubles as the
   home affordance (tap to return to the root listing), and the avatar
   menu sits at the right edge as the "you" tab. Triggers strictly on
   display-mode: standalone, so in-browser narrow viewers keep the
   familiar top nav. */
@media (display-mode: standalone) and (max-width: 480px) {
    .nav {
        position: fixed;
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 10;
        border-bottom: none;
        border-top: 1px solid var(--rule);
        /* iOS home-indicator clearance — without this, the bottom row
           of nav items overlaps the gesture bar on notched devices. */
        padding-bottom: env(safe-area-inset-bottom);
    }
    .nav-logo { display: none; }
    /* Promote nav-links' anchors to direct flex children of
       .nav-inner so Søk / Oppsanket / avatar distribute as three
       evenly-spaced tabs instead of a left-clustered group + right
       avatar. Resets the inter-anchor margin too, since spacing now
       comes from justify-content. */
    .nav-inner {
        justify-content: space-around;
        gap: 0.5rem;
        /* Tighter than the default 0.85rem so the bar sits closer to
           native iOS tab-bar height (~49pt) rather than reading as a
           desktop nav that happens to be at the bottom. */
        padding-top: 0.5rem;
        padding-bottom: 0.5rem;
    }
    .nav-links { display: contents; }
    .nav-links a, .nav-links a:first-child { margin-left: 0; }
    /* Cancel the auto-margin that pinned the avatar/anon-actions to
       the right edge; with space-around they distribute on their own. */
    .nav-user, .nav-anon-actions { margin-left: 0; }
    /* Avatar drops from 32px to 28px in this mode — better balanced
       against the tightened bar, and closer to native tab-bar icon
       proportions. */
    .nav-user-summary .avatar {
        width: 28px;
        height: 28px;
    }
    /* Popup must open upward when the toggle sits at the bottom of
       the viewport — otherwise the menu renders off-screen. */
    .nav-user-menu {
        top: auto;
        bottom: calc(100% + 4px);
    }
    /* Keep the footer above the fixed bar. ~2.75rem covers nav-inner's
       0.5rem vertical padding + the 28px avatar; safe-area adds the
       home-indicator clearance on top of that. */
    body {
        padding-bottom: calc(2.75rem + env(safe-area-inset-bottom));
    }
}

/* Footer */
.footer {
    max-width: 64rem;
    margin: 2rem auto 1.5rem;
    padding: 1rem 1.5rem 0;
    border-top: 1px solid var(--rule);
    text-align: center;
    color: var(--ink-light);
    font-size: 0.875rem;
}
.footer p { margin: 0; }

/* Page header */
.page-header {
    display: flex;
    justify-content: space-between;
    align-items: flex-end;
    gap: 1rem;
    margin-bottom: 2rem;
    flex-wrap: wrap;
}
.page-header h1 { margin-bottom: 0.25rem; }
.page-header .meta { margin: 0; }
.page-header-actions {
    display: flex;
    gap: 0.5rem;
    align-items: center;
    flex-wrap: wrap;
}

/* Share dropdown (uses <details>) */
.share-dropdown {
    position: relative;
}
.share-dropdown > summary {
    cursor: pointer;
    list-style: none;
}
.share-dropdown > summary::-webkit-details-marker { display: none; }
.share-dropdown-menu {
    position: absolute;
    right: 0;
    top: calc(100% + 4px);
    min-width: 240px;
    background: var(--parchment-dark);
    border: 1px solid var(--rule);
    border-radius: 4px;
    padding: 0.5rem;
    z-index: 20;
    box-shadow: 0 4px 12px rgba(0,0,0,0.08);
}
.share-dropdown-menu ul {
    list-style: none;
    padding: 0;
    margin: 0;
}
/* Every interactive row in the dropdown — Mastodon links, Bluesky link, the
   copy-link button — should look identical: full-width, left-aligned,
   transparent background, light hover. */
.share-dropdown-menu a,
.share-dropdown-menu .share-copy {
    display: block;
    width: 100%;
    padding: 0.4rem 0.6rem;
    text-align: left;
    text-decoration: none;
    background: none;
    border: none;
    border-radius: 3px;
    color: inherit;
    font: inherit;
    cursor: pointer;
}
.share-dropdown-menu a:hover,
.share-dropdown-menu .share-copy:hover {
    background: var(--parchment);
    color: var(--ink);
}
.share-dropdown-menu .meta {
    font-size: 0.85rem;
    opacity: 0.75;
}
.share-external-row,
.share-copy-row {
    margin-top: 0.4rem;
    padding-top: 0.4rem;
    border-top: 1px solid var(--rule);
}
.share-external-row:first-child,
.share-copy-row:first-child {
    margin-top: 0;
    padding-top: 0;
    border-top: none;
}

/* OAuth providers (login/register) */
.oauth-providers {
    margin-bottom: 1rem;
}
.oauth-form .form-actions {
    margin-top: 0.5rem;
}
.oauth-or {
    text-align: center;
    margin: 1rem 0;
    position: relative;
    color: var(--ink-light);
    font-size: 0.9rem;
}
.oauth-or::before,
.oauth-or::after {
    content: "";
    position: absolute;
    top: 50%;
    width: calc(50% - 2rem);
    border-top: 1px solid var(--rule);
}
.oauth-or::before { left: 0; }
.oauth-or::after { right: 0; }

.settings-manual-add {
    margin-top: 1.5rem;
}
.settings-manual-add > summary {
    cursor: pointer;
    color: var(--ink-light);
    font-size: 0.95rem;
    margin-bottom: 0.5rem;
}

/* Card */
.card {
    background: var(--parchment-dark);
    border: 1px solid var(--rule);
    border-radius: 4px;
    padding: 1.25rem 1.5rem;
    margin-bottom: 1rem;
    position: relative;
}
.card::before {
    content: "";
    position: absolute;
    top: 0; left: 0; right: 0;
    height: 2px;
    background: var(--gold);
    border-radius: 4px 4px 0 0;
}
.card h3 {
    margin: 0 0 0.25rem;
    font-size: 1.25rem;
}
.card h3 a {
    color: var(--ink);
    text-decoration: none;
}
.card h3 a:hover {
    text-decoration: underline;
    text-decoration-color: var(--gold-dark);
    text-underline-offset: 3px;
}
.card .meta { margin: 0 0 0.75rem; }
.card > *:last-child { margin-bottom: 0; }

/* Buttons */
.btn, button {
    display: inline-block;
    padding: 0.55rem 1.25rem;
    font-family: inherit;
    font-size: 1rem;
    font-weight: 500;
    line-height: 1.4;
    color: var(--ink);
    background: var(--gold);
    border: 1px solid var(--gold-dark);
    border-radius: 3px;
    text-decoration: none;
    cursor: pointer;
    transition: background 0.1s ease;
}
.btn:hover, button:hover {
    background: var(--gold-dark);
    color: var(--parchment);
}
.btn-secondary, button.btn-secondary {
    background: transparent;
    border-color: var(--ink);
    color: var(--ink);
}
.btn-secondary:hover, button.btn-secondary:hover {
    background: var(--ink);
    color: var(--parchment);
}
.btn-danger, button.btn-danger {
    background: var(--rust);
    border-color: var(--rust);
    color: var(--parchment);
}
.btn-danger:hover, button.btn-danger:hover {
    background: #8a3c28;
}
/* Form-action button styled to look like a regular link.
   Used when a textual link must POST (e.g. "Glemt passord?" that
   carries the already-typed identifier so the user doesn't re-type
   on the next page). */
.inline-form { display: inline; }
.link-button, button.link-button {
    background: none;
    border: none;
    padding: 0;
    color: var(--ink);
    text-decoration: underline;
    text-decoration-color: var(--gold-dark);
    text-underline-offset: 3px;
    cursor: pointer;
    font-size: inherit;
    font-family: inherit;
    font-weight: inherit;
}
.link-button:hover, button.link-button:hover {
    background: none;
    color: var(--gold-dark);
}

/* Form fields */
.field { margin-bottom: 1.25rem; }
.field label {
    display: block;
    font-weight: 500;
    margin-bottom: 0.35rem;
    color: var(--ink);
}
.field input:not([type="checkbox"]):not([type="radio"]):not([type="file"]):not([type="submit"]):not([type="button"]):not([type="reset"]):not([type="hidden"]):not([type="image"]):not([type="range"]):not([type="color"]),
.field textarea,
.field select {
    width: 100%;
    padding: 0.55rem 0.75rem;
    font-family: inherit;
    font-size: 1rem;
    color: var(--ink);
    background: var(--parchment);
    border: 1px solid var(--rule);
    border-radius: 3px;
    transition: border-color 0.1s, box-shadow 0.1s;
}
.field input:focus,
.field textarea:focus,
.field select:focus {
    outline: none;
    border-color: var(--gold-dark);
    box-shadow: 0 0 0 3px rgba(232, 196, 90, 0.25);
}
.field textarea {
    resize: vertical;
    min-height: 6rem;
}
.field-help {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.875rem;
    color: var(--ink-light);
}
/* Per-field validation error rendered inline by PATCH_SUBMIT_SCRIPT. */
.field-error {
    display: block;
    margin-top: 0.25rem;
    font-size: 0.875rem;
    color: var(--rust);
}
/* Form-level status (success or generic error) revealed by the
   JS submit helper. Hidden via the [hidden] attribute initially. */
.form-status {
    display: block;
    margin-top: 0.75rem;
    padding: 0.5rem 0.75rem;
    border-radius: 4px;
    font-size: 0.9rem;
}
.form-status[hidden] { display: none; }
.form-status-ok { background: var(--parchment-dark); color: var(--ink); border-left: 3px solid var(--moss); }
.form-status-err { background: var(--parchment-dark); color: var(--ink); border-left: 3px solid var(--rust); }
/* Two related inputs sharing one row (lat/lng, width/height, etc.). */
.field-row {
    display: flex;
    gap: 0.5rem;
}
.field-row > * { flex: 1; min-width: 0; }

/* Form actions */
.form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 0.75rem;
    margin-top: 1.5rem;
}
/* Login page: identifier input + submit on one line — bypasses the
   .form-actions divider so the page reads as one compact entry
   rather than form-then-button. */
.login-row {
    display: flex;
    gap: 0.5rem;
    align-items: stretch;
}
.login-row input { flex: 1 1 auto; }
.login-row button { flex: 0 0 auto; }

/* Avatar */
.avatar {
    width: 48px;
    height: 48px;
    border-radius: 50%;
    border: 2px solid var(--ink);
    background: var(--parchment-dark);
    object-fit: cover;
}
.avatar-sm { width: 32px; height: 32px; border-width: 1px; }
.avatar-lg { width: 96px; height: 96px; border-width: 3px; }
/* Wrap for the avatar preview in /settings — relative positioning
   gives the .image-remove-x button (form-submit, image_action=remove)
   something to anchor against. Sized inline-block to the avatar
   circle so the X sits flush against the avatar's edge. */
.avatar-preview-wrap {
    position: relative;
    display: inline-block;
    margin-bottom: 1rem;
}

/* Datestamp */
.datestamp {
    display: inline-block;
    width: 56px;
    text-align: center;
    border: 2px solid var(--ink);
    border-radius: 4px;
    background: var(--parchment);
    font-variant-numeric: tabular-nums;
    overflow: hidden;
    flex-shrink: 0;
}
.datestamp-month {
    background: var(--ink);
    color: var(--parchment);
    font-size: 0.75rem;
    font-weight: 600;
    letter-spacing: 0.1em;
    padding: 0.15rem 0;
}
.datestamp-day {
    font-family: 'EB Garamond', Georgia, serif;
    font-size: 1.5rem;
    font-weight: 600;
    color: var(--ink);
    padding: 0.25rem 0;
    line-height: 1.1;
}

/* Event row */
.event-row { display: flex; gap: 1rem; align-items: flex-start; }
.event-body { flex: 1; min-width: 0; }
.event-body h3 { margin-top: 0; }
.event-body .meta { margin-bottom: 0; }

/* Alerts */
.alert {
    padding: 0.75rem 1rem;
    border-radius: 3px;
    margin-bottom: 1rem;
    border-left: 3px solid;
}
.alert-info { background: rgba(212, 200, 168, 0.3); border-left-color: var(--ink-light); color: var(--ink); }
.alert-success { background: rgba(90, 122, 58, 0.12); border-left-color: var(--moss); color: var(--ink); }
.alert-warning { background: rgba(232, 196, 90, 0.18); border-left-color: var(--gold-dark); color: var(--ink); }
.alert-danger { background: rgba(160, 72, 48, 0.12); border-left-color: var(--rust); color: var(--ink); }

/* Skillelinje */
.rule { border: none; height: 1px; background: var(--rule); margin: 2rem 0; }
/* Section-closer rule used on /settings and /instance. Asymmetric
   margin (small top, normal bottom) makes the rule visually belong
   to the section above it — "below the button" — instead of feeling
   like it's introducing the section below. */
.section-end { border: none; height: 1px; background: var(--rule); margin: 0.5rem 0 2rem; }

/* Badges */
.badge {
    display: inline-block;
    padding: 0.15rem 0.55rem;
    font-size: 0.75rem;
    font-weight: 500;
    letter-spacing: 0.03em;
    border-radius: 2px;
    background: var(--parchment-dark);
    color: var(--ink);
    border: 1px solid var(--rule);
    vertical-align: middle;
}
.badge-gold { background: var(--gold); border-color: var(--gold-dark); }
.badge-muted { background: transparent; color: var(--ink-light); font-style: italic; }
/* Unread-conversation count next to "Se forslag →"-link on invitation
   cards. Uses the rust accent so it reads as "needs attention" without
   shouting like a red dot. */
.badge-unread {
    background: var(--rust);
    color: var(--parchment);
    border-color: var(--rust);
    font-weight: 600;
    min-width: 1.4rem;
    text-align: center;
}

/* Tag chips */
.tag-chips { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0.4rem 0 0.25rem; }
.tag-chip {
    display: inline-block;
    padding: 0.15rem 0.6rem;
    font-size: 0.8rem;
    background: var(--parchment);
    color: var(--ink);
    border: 1px solid var(--rule);
    border-radius: 999px;
    text-decoration: none;
}
a.tag-chip:hover {
    border-color: var(--ink-light);
}

/* Search form */
.search-form {
    margin: 0 0 1.5rem;
    padding: 1rem 1.25rem;
    background: var(--parchment-dark);
    border: 1px solid var(--rule);
    border-radius: 4px;
}
.search-row { display: flex; gap: 1rem; flex-wrap: wrap; align-items: end; }
.search-row .field { margin-bottom: 0; }
.search-row .field-grow { flex: 1 1 240px; }
.coordinate-row { display: flex; gap: 0.5rem; align-items: stretch; flex-wrap: wrap; }
.coordinate-row input { flex: 1 1 240px; }

/* Production form — each showing row reads as a discrete block.
   Light rule above + breathing room so the eye lands on row
   boundaries without the row needing its own card-shaped frame
   (which would compete with the surrounding form's hierarchy). */
.showings-list { margin-bottom: 0.75rem; }
.showing-row {
    padding: 1rem 0;
    border-top: 1px solid var(--rule);
}
.showing-row:first-child { border-top: none; padding-top: 0; }
.showing-row .field:last-of-type { margin-bottom: 0.5rem; }

/* Preview of the production's current/just-picked image. When an
   image is set, the upload/URL fields are hidden and only this
   preview shows; the X overlay (form-submit, image_action=remove)
   is the path back to "no image set". Without an image, the wrap
   is hidden via the [hidden] attribute and the fields render. */
.image-preview-wrap {
    position: relative;
    display: inline-block;
    margin-bottom: 1rem;
}
/* The class selector above wins over the user-agent's
   [hidden] { display: none }, so we have to re-state hidden
   explicitly. Without this the wrap (and the X overlay inside it)
   stays visible even when the form has no image set. */
.image-preview-wrap[hidden] { display: none; }
.image-preview {
    display: block;
    max-width: 480px;
    max-height: 480px;
    height: auto;
    width: auto;
    border: 1px solid var(--rule);
    border-radius: 3px;
    background: var(--parchment-dark);
}
.image-remove-x {
    position: absolute;
    top: -0.5rem;
    right: -0.5rem;
    width: 1.75rem;
    height: 1.75rem;
    padding: 0;
    line-height: 1;
    font-size: 1.25rem;
    font-family: inherit;
    color: var(--parchment);
    background: var(--rust);
    border: 1px solid var(--rust);
    border-radius: 50%;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
}
.image-remove-x:hover { background: #8a3c28; }
.search-tags-disclosure {
    margin-top: 1rem;
    padding-top: 0.75rem;
    border-top: 1px solid var(--rule);
}
.search-tags-disclosure summary {
    cursor: pointer;
    font-weight: 500;
    padding: 0.15rem 0;
    user-select: none;
    list-style: none;
}
.search-tags-disclosure summary::-webkit-details-marker { display: none; }
.search-tags-disclosure summary::before {
    content: "▸";
    display: inline-block;
    margin-right: 0.4rem;
    color: var(--ink-light);
    transition: transform 0.15s;
}
.search-tags-disclosure[open] summary::before {
    transform: rotate(90deg);
}
.search-tags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin-top: 0.75rem; }
.tag-chip-toggle {
    position: relative;
    display: inline-block;
    padding: 0.15rem 0.6rem;
    font-size: 0.8rem;
    background: var(--parchment);
    border: 1px solid var(--rule);
    border-radius: 999px;
    cursor: pointer;
    user-select: none;
}
.tag-chip-toggle input {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    width: 1px;
    height: 1px;
}
.tag-chip-toggle:focus-within {
    box-shadow: 0 0 0 3px rgba(232, 196, 90, 0.3);
}
.tag-chip-toggle:has(input:checked) {
    background: var(--gold);
    border-color: var(--gold-dark);
    color: var(--ink);
}
.tag-chip-count { opacity: 0.6; font-variant-numeric: tabular-nums; }
.date-presets {
    display: flex;
    flex-wrap: wrap;
    gap: 0.4rem;
    margin: 0.6rem 0 0.25rem;
}
.date-preset {
    padding: 0.2rem 0.7rem;
    font-family: inherit;
    font-size: 0.85rem;
    background: var(--parchment);
    color: var(--ink-light);
    border: 1px solid var(--rule);
    border-radius: 999px;
    cursor: pointer;
    line-height: 1.3;
    transition: background 0.1s, border-color 0.1s, color 0.1s;
}
.date-preset:hover {
    border-color: var(--ink-light);
    color: var(--ink);
}
.date-preset.active {
    background: var(--gold);
    border-color: var(--gold-dark);
    color: var(--ink);
}
.search-actions {
    margin-top: 0.75rem;
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem;
}
.search-actions select {
    padding: 0.4rem 0.6rem;
    font-family: inherit;
    font-size: 0.95rem;
    color: var(--ink);
    background: var(--parchment);
    border: 1px solid var(--rule);
    border-radius: 3px;
}
.search-actions select:focus {
    outline: none;
    border-color: var(--gold-dark);
    box-shadow: 0 0 0 3px rgba(232, 196, 90, 0.25);
}
@media (max-width: 640px) {
    .search-reset { display: none; }
}

/* Event thumb + production hero */
.event-row { display: grid; grid-template-columns: auto 1fr auto; gap: 1.25rem; align-items: start; }
.event-thumb {
    display: block;
    width: 200px;
    line-height: 0;
    border-radius: 3px;
    overflow: hidden;
    align-self: stretch;
}
.event-thumb img {
    width: 100%;
    height: 100%;
    display: block;
    object-fit: cover;
    aspect-ratio: 4/3;
}
.production-hero {
    margin: 1rem 0 1.5rem;
    max-height: 420px;
    overflow: hidden;
    border-radius: 4px;
}
.production-hero img {
    width: 100%;
    height: auto;
    display: block;
    object-fit: cover;
}
@media (max-width: 720px) {
    .event-row { grid-template-columns: auto 1fr; }
    /* Ticket link drops to its own row below body on narrow screens
       so the title + date have full width to themselves. */
    .ticket-link {
        grid-column: 1 / -1;
        justify-self: start;
        margin-top: 0.5rem;
    }
    .event-thumb {
        grid-column: 1 / -1;
        grid-row: 1;
        width: 100%;
        margin-bottom: 0.5rem;
    }
    .event-thumb img { aspect-ratio: 16/9; }
}

/* Ticket link sits in the third grid column of the showing card
   (upper-right). Self-aligns so it doesn't stretch to fill the row
   and stays compact next to the date + body block. The same
   `.event-row` grid is used by listing cards with thumbnails on the
   right; ticket-link only renders on showing cards (no thumb), so
   the two never collide. */
.ticket-link {
    margin: 0;
    align-self: start;
    justify-self: end;
    white-space: nowrap;
}
/* `.btn`'s `display: inline-block` beats UA `[hidden] { display: none }`
   by specificity, so the show/hide-on-RSVP toggle on the invitation
   page would render the link even when the `hidden` attribute is set.
   Restate it here so the attribute does its job. */
.ticket-link[hidden] { display: none; }

/* Showing map (Leaflet) */
.showing-map {
    height: 220px;
    margin: 0.75rem 0;
    border: 1px solid var(--rule);
    border-radius: 3px;
    overflow: hidden;
}
.showing-map .leaflet-container {
    background: var(--parchment-dark);
    font-family: inherit;
}

/* Calendar subscribe block — flows inline under the Settings h2
   like the rest of the Settings sections. The wrapper class stays
   only for the inline <code> URL-chip selector below. */
.calendar-subscribe code {
    display: inline-block;
    padding: 0.1rem 0.4rem;
    background: var(--parchment);
    border: 1px solid var(--rule);
    border-radius: 3px;
    font-size: 0.8rem;
    word-break: break-all;
}

/* Empty state */
.empty-state {
    text-align: center;
    padding: 2.5rem 1.5rem;
    color: var(--ink-light);
    background: var(--parchment-dark);
    border: 1px dashed var(--rule);
    border-radius: 4px;
}
.empty-state p { margin-bottom: 1rem; }

/* Data table — for admin/config tabular data. See design-guide.md. */
.data-table {
    width: 100%;
    border-collapse: collapse;
    margin: 0 0 1rem;
    font-size: 0.95rem;
}
.data-table thead th {
    text-align: left;
    font-weight: 500;
    font-size: 0.8rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--ink-light);
    padding: 0.4rem 0.75rem;
    border-bottom: 1px solid var(--rule);
}
.data-table tbody td {
    padding: 0.55rem 0.75rem;
    border-bottom: 1px solid var(--rule);
    vertical-align: middle;
}
.data-table tbody tr:last-child td { border-bottom: none; }
.data-table .num {
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}
.data-table .row-actions {
    text-align: right;
    white-space: nowrap;
}
.data-table code {
    font-size: 0.875rem;
    background: var(--parchment-dark);
    padding: 0.05rem 0.35rem;
    border-radius: 2px;
}

/* Compact button variant for inline actions in tables and lists. */
.btn-sm, button.btn-sm {
    padding: 0.25rem 0.7rem;
    font-size: 0.85rem;
    line-height: 1.3;
}

/* No-JS confirm via <details>. First click opens the form; the actual
   POST happens from the inner button. Replaces onclick=confirm(). */
.confirm-delete > summary {
    cursor: pointer;
    list-style: none;
    display: inline-block;
}
.confirm-delete > summary::-webkit-details-marker { display: none; }
.confirm-delete[open] > summary { display: none; }
.confirm-delete-body {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
}
.confirm-delete-prompt {
    font-size: 0.85rem;
    color: var(--ink-light);
    font-style: italic;
}

/* Generic alignment utility for inline action rows. */
.text-right { text-align: right; }

/* Friend rows: name + handle on the left, action button on the right,
   all on one line. The action button uses .btn-mini-danger which
   matches the discreet rsvp toggle visual: transparent default, hover
   reveals border + colour. */
.friend-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
}
.friend-row p { margin: 0; flex: 1 1 auto; }
.friend-row form { margin: 0; }
/* All friends inside one card; rows separated by a thin rule
   instead of each having its own card border. The vertical padding
   per row keeps the Fjern hit-target comfortable. */
.friends-list-card .friend-row {
    padding: 0.6rem 0;
    border-top: 1px solid var(--rule);
}
.friends-list-card .friend-row:first-child { border-top: 0; padding-top: 0; }
.friends-list-card .friend-row:last-child { padding-bottom: 0; }
.btn-mini-danger {
    font-size: 0.85rem;
    padding: 0.15rem 0.45rem;
    background: transparent;
    border: 1px solid transparent;
    color: var(--ink-light);
    cursor: pointer;
    border-radius: 0.25rem;
    line-height: 1.3;
}
.btn-mini-danger:hover {
    color: #c53030;
    border-color: currentColor;
}

/* Discreet card-level RSVP toggles. Inactive: muted text-only.
   Active (aria-pressed=true): coloured to match the full-size buttons
   (moss for kommer, gold for interessert) so the visual language is
   consistent across surfaces. */
.rsvp-form-card {
    display: inline-flex; gap: 0.4rem; margin-top: 0.5rem;
    padding: 0;
}
.rsvp-form-card button {
    font-size: 0.85rem; padding: 0.15rem 0.45rem;
    background: transparent; border: 1px solid transparent;
    color: var(--ink-light); cursor: pointer; border-radius: 0.25rem;
    line-height: 1.3;
}
.rsvp-form-card button:hover {
    color: var(--ink); border-color: var(--ink-light);
}
.rsvp-form-card .rsvp-going-mini[aria-pressed="true"] {
    color: var(--moss); border-color: var(--moss); font-weight: 600;
}
.rsvp-form-card .rsvp-maybe-mini[aria-pressed="true"] {
    color: var(--gold-dark); border-color: var(--gold-dark); font-weight: 600;
}
/* The third state is invitation-list-only (not on public events).
   Rust accent matches the design's "decline / destructive" voice
   without going as loud as .btn-danger — this is a quiet "no". */
.rsvp-form-card .rsvp-declined-mini[aria-pressed="true"] {
    color: var(--rust); border-color: var(--rust); font-weight: 600;
}

/* Invitee section on the event-edit form. The chip-list above the
   textarea lists existing invitees as inline blocks (no bullets),
   each with an X overlay; below sit two collapsible details for
   the friend-picker and the freeform textarea. */
/* One invitee per line, mirrors the friend-picker row layout:
   name on the left grows to fill, badge + (optional) remove-X
   sit on the right. The row reads as content, not chrome. */
.invitee-list {
    list-style: none;
    padding: 0;
    margin: 0 0 1rem;
}
.invitee-row {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    padding: 0.35rem 0;
    border-top: 1px solid var(--rule);
}
.invitee-row:first-child { border-top: none; }
.invitee-label { flex: 1 1 auto; min-width: 0; }
.invitee-add-section {
    margin-bottom: 0.75rem;
}
/* Sub-headline-style summary: serif, slightly smaller than h3,
   with the browser's native disclosure triangle visible in front
   so users immediately recognize the expand affordance. */
.invitee-add-section > summary {
    cursor: pointer;
    font-family: 'EB Garamond', 'Cormorant Garamond', Georgia, serif;
    font-weight: 600;
    font-size: 1.1rem;
    color: var(--ink);
    margin: 0.5rem 0 0.25rem;
}
.invitee-add-section > summary:hover {
    color: var(--gold-dark);
}
/* Friend picker rendered as a vertical list (one name per line)
   with a small "Legg til" button at the end of each row. Replaces
   the prior all-buttons row so friend names look like content,
   not chrome. */
.friend-picker-list {
    list-style: none;
    padding: 0;
    margin: 0.25rem 0 0.5rem;
}
.friend-picker-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    padding: 0.35rem 0;
    border-top: 1px solid var(--rule);
}
.friend-picker-row:first-child { border-top: none; }
/* Class selector beats UA `[hidden] { display: none }`, restate it. */
.friend-picker-row[hidden] { display: none; }
.friend-picker-name { flex: 1 1 auto; min-width: 0; }
/* Letter / note treatment for invitation cards on /my/events: the
   inviter is sending you a message that points at an event, so the
   outer container drops the standard .card chrome and reads as a
   personal note (left-edge gold rule, no box, no top stripe). The
   inner event card keeps its full chrome — that's the artifact
   being passed along. */
.invitation-card {
    background: transparent;
    border: none;
    border-radius: 0;
    padding: 0.5rem 0 1rem 1.25rem;
    border-left: 3px solid var(--gold);
    margin-bottom: 1.5rem;
}
.invitation-card::before { display: none; }

.invitation-card .invitation-from {
    margin: 0 0 0.5rem;
    font-size: 0.95rem;
    color: var(--ink-light);
    font-style: italic;
}

/* Detail-page header. Sits above the event card so it carries the
   invitation's personal voice — sized smaller than h1 so the event
   name (h1 inside the card below) stays the visual focal point. */
.page-header .invitation-from {
    margin: 0 0 0.5rem;
    font-size: 1.15rem;
    font-weight: 600;
}

.invitation-card .inviter-comment {
    margin: 0 0 0.85rem;
    padding: 0.25rem 0 0.25rem 0.85rem;
    border-left: 2px solid var(--rule);
    font-family: 'EB Garamond', 'Cormorant Garamond', Georgia, serif;
    font-size: 1.1rem;
    line-height: 1.45;
    color: var(--ink);
}

/* Inner event card — visually the focal artifact inside the note. */
.invitation-card .invitation-event {
    margin: 0 0 0.85rem;
}

.invitation-card .invitation-link {
    margin: 0.25rem 0 0;
    font-size: 0.9rem;
}
.invitation-card .invitation-link a {
    color: var(--ink-light);
}
.invitation-card .invitation-link a:hover {
    color: var(--ink);
}

/* Richer invitation card on the friends page: thumbnail-sized
   hero (don't compete with the page's own event-view), description
   and extra-dates collapsed under a details-summary so the RSVP
   buttons stay visible without scrolling. */
.invitation-card .invitation-hero {
    display: block;
    max-width: 240px;
    max-height: 240px;
    height: auto;
    width: auto;
    margin: 0.5rem 0 0.75rem;
    border: 1px solid var(--rule);
    border-radius: 3px;
}
.invitation-card .invitation-extra {
    margin: 0.4rem 0;
}
.invitation-card .invitation-extra > summary {
    cursor: pointer;
    color: var(--ink-light);
    font-size: 0.9rem;
}
.invitation-card .invitation-dates {
    list-style: none;
    padding: 0;
    margin: 0.25rem 0 0.5rem;
}
.invitation-card .invitation-dates > li {
    padding: 0.15rem 0;
    font-size: 0.9rem;
}
.invitation-card .invitation-description {
    margin-top: 0.4rem;
    font-size: 0.95rem;
}

/* Organizer roster on the event view page. Headings + plain
   lists, no browser bullets. Matches the parchment palette and
   leaves room for badge/handle/date metadata per row. */
.roster-bucket-title {
    font-size: 0.95rem;
    font-weight: 600;
    margin: 0.75rem 0 0.25rem;
    color: var(--ink);
}
.roster-bucket {
    list-style: none;
    padding: 0;
    margin: 0 0 0.75rem;
}
.roster-bucket > li {
    padding: 0.2rem 0;
    font-size: 0.9rem;
    border-top: 1px solid var(--rule);
}
.roster-bucket > li:first-child { border-top: none; }

/* Excerpt below event title in listings */
.event-body .excerpt {
    color: var(--ink);
    margin: 0.4rem 0 0;
    font-size: 0.95rem;
    line-height: 1.5;
}

/* Listing toggle (anchor-based pill nav) */
.listing-toggle {
    display: inline-flex;
    gap: 0.4rem;
    margin: 0 0 1.25rem;
}
.listing-toggle .pill {
    display: inline-block;
    padding: 0.3rem 0.85rem;
    border: 1px solid var(--rule);
    border-radius: 999px;
    background: var(--parchment);
    color: var(--ink-light);
    font-size: 0.85rem;
    text-decoration: none;
    transition: background 0.1s, border-color 0.1s, color 0.1s;
}
.listing-toggle .pill:hover {
    border-color: var(--ink-light);
    color: var(--ink);
}
.listing-toggle .pill-active {
    background: var(--gold);
    border-color: var(--gold-dark);
    color: var(--ink);
}

/* City shortcut row */
.city-shortcuts {
    margin: 0 0 1.25rem;
    font-size: 0.9rem;
    color: var(--ink-light);
}
.city-shortcuts a { color: var(--ink); }

/* Pagination */
.pagination {
    display: flex;
    flex-wrap: wrap;
    gap: 0.75rem 1rem;
    justify-content: space-between;
    align-items: center;
    margin: 1.5rem 0 0.5rem;
    padding-top: 1rem;
    border-top: 1px solid var(--rule);
}
.pagination-summary {
    font-size: 0.875rem;
    color: var(--ink-light);
}
.pagination-links {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    align-items: center;
}
.pagination-link {
    display: inline-block;
    min-width: 2rem;
    padding: 0.25rem 0.6rem;
    text-align: center;
    font-size: 0.875rem;
    line-height: 1.4;
    color: var(--ink);
    background: var(--parchment);
    border: 1px solid var(--rule);
    border-radius: 3px;
    text-decoration: none;
}
a.pagination-link:hover {
    border-color: var(--ink-light);
}
.pagination-current {
    background: var(--gold);
    border-color: var(--gold-dark);
    font-weight: 500;
}
.pagination-ellipsis {
    color: var(--ink-light);
    padding: 0 0.25rem;
}

/* Unverified email banner */
.unverified-banner {
    background: rgba(232, 196, 90, 0.18);
    border-bottom: 1px solid var(--gold-dark);
}
.unverified-banner-inner {
    max-width: 64rem;
    margin: 0 auto;
    padding: 0.5rem 1.5rem;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 0.75rem;
    flex-wrap: wrap;
    font-size: 0.9rem;
}
.unverified-banner-form { margin: 0; }
.unverified-banner-form button { padding: 0.25rem 0.75rem; font-size: 0.85rem; }

/* Visibility pills (radio toggle group) */
.visibility-pills {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin: 0.75rem 0 0.25rem;
    font-size: 0.875rem;
    color: var(--ink-light);
    flex-wrap: wrap;
}
.visibility-pills-label {
    margin-right: 0.25rem;
    font-style: italic;
}
.visibility-pills label {
    position: relative;
    cursor: pointer;
    line-height: 1;
}
.visibility-pills input[type="radio"] {
    position: absolute;
    opacity: 0;
    pointer-events: none;
    width: 1px;
    height: 1px;
}
.visibility-pills .pill {
    display: inline-block;
    padding: 0.25rem 0.7rem;
    border: 1px solid var(--rule);
    border-radius: 999px;
    background: var(--parchment);
    color: var(--ink-light);
    font-size: 0.8rem;
    line-height: 1.3;
    transition: background 0.1s, border-color 0.1s, color 0.1s;
}
.visibility-pills label:hover .pill {
    border-color: var(--ink-light);
    color: var(--ink);
}
.visibility-pills input[type="radio"]:checked + .pill {
    background: var(--gold);
    border-color: var(--gold-dark);
    color: var(--ink);
}
.visibility-pills input[type="radio"]:focus-visible + .pill {
    box-shadow: 0 0 0 3px rgba(232, 196, 90, 0.3);
    outline: none;
}

/* Narrow screens: bands break out of main's gutter and run edge-to-edge,
   while non-band content keeps a small inner gutter. */
@media (max-width: 480px) {
    main { padding: 0 0.75rem; }
    .card,
    .search-form,
    .empty-state {
        margin-left: -0.75rem;
        margin-right: -0.75rem;
        border-left: 0;
        border-right: 0;
        border-radius: 0;
        padding-left: 0.85rem;
        padding-right: 0.85rem;
    }
    .card {
        padding-top: 0.85rem;
        padding-bottom: 0.85rem;
        margin-bottom: 0.5rem;
    }
    .card::before { border-radius: 0; }
    .search-form {
        padding-top: 0.75rem;
        padding-bottom: 0.75rem;
    }
    .empty-state {
        padding-top: 2rem;
        padding-bottom: 2rem;
    }
}

/* Discreet text-style mini button — used for inline actions inside
   denser content (Svar / Slett on a message row) where a real button
   would dominate the line. Same physical size as a link, no border,
   underline on hover. */
.btn-mini-link {
    background: transparent;
    border: none;
    padding: 0;
    margin: 0;
    font: inherit;
    font-size: 0.85rem;
    color: var(--ink-light);
    cursor: pointer;
    text-decoration: none;
}
.btn-mini-link:hover {
    color: var(--ink);
    text-decoration: underline;
    text-decoration-color: var(--gold-dark);
    text-underline-offset: 2px;
}
.btn-mini-link-danger { color: var(--ink-light); }
.btn-mini-link-danger:hover {
    color: var(--rust);
    text-decoration-color: var(--rust);
}
.inline-form { display: inline; margin: 0; padding: 0; }

/* Invitation thread (under the conversation section on the
   invitation detail page). Two-level structure: a top-level message
   + a flat indented list of all descendants. Chevron is on the left
   side of the summary line so it reads naturally as "click to
   expand"; child messages sit indented with a left rule that visually
   ties them to the thread root. */
.invitation-threads {
    margin-top: 1rem;
}
.invitation-thread {
    border-top: 1px solid var(--rule);
    padding: 0.75rem 0 0.5rem;
}
.invitation-thread:first-of-type { border-top: 0; }
.invitation-thread > summary {
    cursor: pointer;
    list-style: none;
    padding: 0;
    color: var(--ink);
}
.invitation-thread > summary::-webkit-details-marker { display: none; }

/* Disclosure chevron: a real <a class="invitation-thread-toggle">
   in the side column, under the avatar. Only rendered when the
   root has replies. JS catches the click and toggles the parent
   <details>; CSS supplies the glyph based on [open] state. Wider
   click target than the inline glyph since it's a standalone
   control. */
.invitation-thread-toggle {
    display: inline-block;
    color: var(--ink-light);
    text-decoration: none;
    cursor: pointer;
    line-height: 1;
    width: 32px;
    text-align: center;
    padding: 0.15rem 0;
    font-size: 1.1rem;
}
.invitation-thread-toggle::before { content: "▸"; }
.invitation-thread[open] .invitation-thread-toggle::before { content: "▾"; }

/* Each message: side column on the left (avatar + optional thread
   toggle stacked) and content on the right. The card chrome wraps
   both columns so the side sits on the same parchment-dark surface
   as the content. */
.invitation-message {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    margin: 0 0 0.5rem;
    padding: 0.5rem 0.75rem;
    background: var(--parchment-dark);
    border-radius: 3px;
}
.invitation-message-aside {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    flex: 0 0 auto;
}
.invitation-message-avatar {
    width: 32px;
    height: 32px;
    border-width: 1px;
    flex: 0 0 auto;
}
.invitation-message-content {
    flex: 1 1 auto;
    min-width: 0;
}
.invitation-message-meta {
    margin: 0 0 0.2rem;
    font-size: 0.85rem;
    color: var(--ink-light);
}
.invitation-message-meta strong { color: var(--ink); }
.invitation-message-body {
    margin: 0;
    color: var(--ink);
    white-space: pre-wrap;
}
.invitation-message-deleted { color: var(--ink-light); font-style: italic; }
.invitation-message-actions {
    margin: 0.3rem 0 0;
    font-size: 0.85rem;
}
.invitation-message-actions > * + * { margin-left: 0.5rem; }

/* Replies — flat chronological list under the thread root, indented
   with a left rule so the parent/child relationship is clear without
   nesting deeper. */
.invitation-thread-replies {
    list-style: none;
    margin: 0.25rem 0 0;
    padding: 0 0 0 1.5rem;
    border-left: 2px solid var(--rule);
}
.invitation-thread-replies > li { margin: 0; }

/* Compose form below the thread list (new top-level message) and the
   inline reply form that appears under a row when "Svar" is clicked.
   Compact textarea, send button on the right. */
/* Compose form: Send button sits inside the textarea's bottom-right
   corner so the input feels like a single element (chat-style)
   rather than form + button-row. Textarea reserves padding-bottom
   so user-typed text doesn't slide under the button. */
.invitation-message-compose {
    margin: 0.5rem 0;
    padding: 0;
    position: relative;
}
.invitation-message-compose textarea {
    width: 100%;
    box-sizing: border-box;
    font-family: inherit;
    font-size: 0.95rem;
    padding: 0.4rem 2.5rem 0.4rem 0.5rem;
    border: 1px solid var(--rule);
    border-radius: 3px;
    background: var(--parchment);
    color: var(--ink);
    resize: vertical;
    min-height: 2.5rem;
    display: block;
}
.invitation-message-compose .form-actions {
    position: absolute;
    bottom: 0.45rem;
    right: 0.5rem;
    margin: 0;
    padding: 0;
    border: 0;
    justify-content: flex-end;
}
/* Compact icon-style send button. Sized to feel like a chat-input
   action: small ink-coloured glyph, hover lights it up. Larger
   touch target than the glyph alone via padding. */
.btn-send {
    background: transparent;
    border: 0;
    padding: 0.2rem 0.45rem;
    color: var(--ink-light);
    cursor: pointer;
    font-size: 1rem;
    line-height: 1;
    border-radius: 3px;
}
.btn-send:hover {
    color: var(--gold-dark);
}
.btn-send:disabled {
    color: var(--rule);
    cursor: default;
}
.invitation-message-reply-row {
    margin-left: 1.5rem;
}

/* Light theme — opt-in via the yplev_theme=light cookie, applied
   client-side by THEME_BOOTSTRAP_SCRIPT before first paint. Aimed
   at e-ink tablets, so the parchment palette and the SVG noise
   texture are dropped for a flat white surface. The ink/gold/rust
   accents stay; on greyscale e-ink they render as low-contrast
   greys against white, which is the desired look. */
html.theme-light {
    --parchment: #ffffff;
    --parchment-dark: #f5f5f5;
    --rule: #d0d0d0;
}
html.theme-light body {
    background-image: none;
}
