/* ═══════════════════════════════════════════════════════════════════════════
   Time to Bloom — brand stylesheet
   Palette, type, and elements from docs/BrandColors.png.

   Colour use is deliberate: Evergreen carries text, Plum carries primary
   action, Sage and Heather carry secondary action, and Soft Gold is reserved
   for rules, borders, and flourishes — it does not have the contrast to be
   text on ivory.
   ═══════════════════════════════════════════════════════════════════════════ */

:root {
    /* Brand palette */
    --evergreen:        #4B5E48;
    --sage:             #B9C8AF;
    --heather:          #B8A4C8;
    --lilac-mist:       #D8C8E3;
    --warm-ivory:       #F8F5EF;
    --soft-gold:        #D7BE8A;

    /* Accents */
    --dusty-plum:       #705A7D;
    --moss-green:       #8D9D80;
    --blush-petal:      #F3D9E7;
    --wildflower-white: #FFFFFF;

    /* Derived, for contrast where the brand tones are too light for text */
    --ink:              #3B4A39;
    --ink-soft:         #4D584A;
    --plum-deep:        #5C4867;
    --rule:             rgba(215, 190, 138, 0.55);
    --rule-soft:        rgba(185, 200, 175, 0.45);

    /* Washes and states. Derived rather than literal so a theme reaches them:
       a dark ground needs different alphas, and #7A3B55 reads as an error only
       against Blush Petal. */
    /* Tints. Heather and Lilac Mist have nowhere near the contrast to carry
       text on ivory, so they earn their place as washes behind darker ink
       rather than as ink themselves. */
    --tint-sage:        rgba(185, 200, 175, 0.38);
    --tint-moss:        rgba(141, 157, 128, 0.26);
    --tint-heather:     rgba(184, 164, 200, 0.34);
    --tint-lilac:       rgba(216, 200, 227, 0.55);
    --tint-gold:        rgba(215, 190, 138, 0.34);
    --tint-blush:      rgba(243, 217, 231, 0.75);

    /* The tints above, already composited on the card. A petal must be opaque:
       a facet's leaf tucks under its fan, and a translucent fan shows it through
       as a smudge rather than as depth. */
    --petal-sage:        #E4EAE1;
    --petal-moss:        #E1E6DE;
    --petal-heather:     #E7E0EC;
    --petal-lilac:       #EAE1F0;
    --petal-gold:        #F1E9D7;

    --gold-wash:        rgba(215, 190, 138, 0.10);
    --gold-ring:        rgba(215, 190, 138, 0.25);
    --sage-wash:        rgba(185, 200, 175, 0.20);
    --error-ink:        #7A3B55;

    /* The mirror frame's own bronze, sampled from mirror_frame.png. Its
       highlight is #C5A579, a shade off Soft Gold -- the two drawings were
       always close, and the bloom simply drew its gold at a quarter strength
       while the frame is solid. These carry the bloom's structural edges so
       moving between the two pages is less of a step. */
    --bronze:           #815D37;
    --bronze-rim:       rgba(129, 93, 55, 0.55);
    --bronze-edge:      rgba(129, 93, 55, 0.30);

    /* The ground inside the mirror, sampled from Jessica's composite. A stand-in
       until her landscape arrives -- an empty glass reads worse than a horizon. */
    --glass-sky:        #D2CEC4;
    --glass-haze:       #E4DACC;
    --glass-field:      #D6C9B4;
    --glass-verge:      #9F9472;
    --glass-earth:      #3B2E1D;
    --glass-deep:       #2E2416;
    /* Depth over the soil texture: clear at the surface, nearly dark at the
       bottom of the glass, so the quilting is read as ground and not as paper. */
    --earth-veil-top:   rgba(46, 36, 22, 0);
    --earth-veil-low:   rgba(21, 16, 10, 0.78);

    /* var() cannot reach inside a data: URI, so the whole URL is the token and
       a theme swaps it wholesale. Keep the fill in sync with --ink-soft. */
    --select-arrow:     url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 8'%3E%3Cpath fill='%234D584A' d='M1 1l5 5 5-5'/%3E%3C/svg%3E");

    --radius:           14px;
    --radius-pill:      999px;
    --shadow:           0 2px 20px rgba(75, 94, 72, 0.07);
    --shadow-lift:      0 6px 28px rgba(75, 94, 72, 0.12);

    --font-display:     "Lora", Georgia, "Times New Roman", serif;
    --font-body:        "Raleway", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
}

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

/* A component that sets its own display silently defeats [hidden];
   this keeps the attribute meaning what it says. */
[hidden] { display: none !important; }

body {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    background: var(--warm-ivory);
    color: var(--ink);
    font-family: var(--font-body);
    font-size: 17px;
    line-height: 1.65;
    -webkit-font-smoothing: antialiased;
}

h1, h2, h3 {
    font-family: var(--font-display);
    font-weight: 500;
    color: var(--evergreen);
    line-height: 1.25;
    margin: 0 0 0.4em;
}

h1 { font-size: 2.1rem; letter-spacing: 0.01em; }
h2 { font-size: 1.4rem; }
h3 { font-size: 1.1rem; }

a { color: var(--plum-deep); text-decoration-color: var(--rule); text-underline-offset: 3px; }
a:hover { color: var(--plum-deep); }

/* ── Section label — the letterspaced small caps from the brand board ────── */
.label {
    font-size: 0.72rem;
    letter-spacing: 0.22em;
    text-transform: uppercase;
    color: var(--plum-deep);
    font-weight: 600;
    margin-bottom: 0.6em;
}

.muted { color: var(--ink-soft); }
.tagline {
    font-family: var(--font-display);
    font-style: italic;
    color: var(--ink-soft);
    font-size: 1.02rem;
}

/* ── Botanical divider ──────────────────────────────────────────────────── */
.divider {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.8rem;
    margin: 1.4rem 0;
    color: var(--soft-gold);
}
.divider::before, .divider::after {
    content: "";
    height: 1px;
    flex: 1;
    max-width: 130px;
    background: linear-gradient(to right, transparent, var(--rule), transparent);
}
.divider svg { width: 26px; height: 26px; display: block; }

/* ── Layout ─────────────────────────────────────────────────────────────── */
.site-header {
    background: var(--wildflower-white);
    border-bottom: 1px solid var(--rule-soft);
    padding: 0.9rem 1.5rem;
}
.header-inner {
    max-width: 1000px;
    margin: 0 auto;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    flex-wrap: wrap;
}
.wordmark {
    font-family: var(--font-display);
    font-size: 1.5rem;
    letter-spacing: 0.16em;
    color: var(--evergreen);
    text-decoration: none;
    display: flex;
    align-items: center;
    gap: 0.55rem;
}
.wordmark:hover { color: var(--evergreen); }
.wordmark svg { width: 26px; height: 26px; color: var(--soft-gold); }

.site-nav {
    display: flex; align-items: center; justify-content: flex-end;
    flex-wrap: wrap; gap: 0.5rem 1.3rem; font-size: 0.93rem;
}
/* Four items run past the edge of a narrow phone. Wrapping the row is fine and
   breaking "My Garden" across two lines is not, so the links hold together and
   the row gives way instead. The sizes below buy enough width that it rarely
   has to. */
.site-nav a:not(.btn) { text-decoration: none; color: var(--ink-soft); white-space: nowrap; }
.site-nav a:not(.btn):hover { color: var(--evergreen); }

@media (max-width: 460px) {
    .site-nav { gap: 0.4rem 0.75rem; font-size: 0.84rem; }
}
@media (max-width: 380px) {
    .site-nav { gap: 0.35rem 0.6rem; font-size: 0.78rem; }
}

/* ── Account menu ───────────────────────────────────────────────────────── */
.usermenu { position: relative; }
.usermenu > summary {
    list-style: none; cursor: pointer; display: block;
    border-radius: 50%; line-height: 0;
}
.usermenu > summary::-webkit-details-marker { display: none; }
.usermenu > summary:focus-visible { outline: 2px solid var(--dusty-plum); outline-offset: 3px; }
.usermenu-face {
    display: block; width: 38px; height: 38px;
    box-shadow: 0 0 0 1px var(--rule); border-radius: 50%;
    transition: box-shadow 0.15s ease;
}
.usermenu[open] .usermenu-face, .usermenu > summary:hover .usermenu-face {
    box-shadow: 0 0 0 2px var(--dusty-plum);
}
.usermenu-panel {
    position: absolute; right: 0; top: calc(100% + 0.55rem); z-index: 60;
    min-width: 190px; padding: 0.5rem;
    background: var(--wildflower-white);
    border: 1px solid var(--rule-soft); border-radius: var(--radius);
    box-shadow: var(--shadow-lift);
    display: flex; flex-direction: column; gap: 0.1rem;
}
.usermenu-who {
    font-family: var(--font-display); color: var(--evergreen);
    padding: 0.35rem 0.7rem 0.5rem; border-bottom: 1px solid var(--rule-soft);
    margin-bottom: 0.3rem;
}
.usermenu-panel a, .usermenu-panel button {
    display: block; width: 100%; text-align: left;
    padding: 0.45rem 0.7rem; border-radius: 8px;
    font-family: var(--font-body); font-size: 0.9rem;
    color: var(--ink-soft); background: none; border: none; cursor: pointer;
    text-decoration: none;
}
.usermenu-panel a:hover, .usermenu-panel button:hover {
    background: var(--tint-sage); color: var(--evergreen);
}
.usermenu-panel form { margin: 0; }
.usermenu > summary { position: relative; }
/* Something unread on News (§4.8): a mark, not a banner -- the banner is the
   prompt's alone. */
.usermenu-dot {
    position: absolute; top: 0; right: 0; width: 10px; height: 10px;
    border-radius: 50%; background: var(--dusty-plum);
    box-shadow: 0 0 0 2px var(--wildflower-white);
}
.news-count {
    display: inline-block; min-width: 1.3em; padding: 0 0.35em; margin-left: 0.3em;
    border-radius: 999px; background: var(--dusty-plum); color: var(--wildflower-white);
    font-size: 0.75rem; line-height: 1.5; text-align: center;
}

/* ── Announcements (§4.8) ───────────────────────────────────────────────── */
.people-pick {
    max-height: 16rem; overflow-y: auto; padding: 0.6rem 0.8rem;
    border: 1px solid var(--rule-soft); border-radius: 8px; background: var(--wildflower-white);
}
.people-pick[hidden] { display: none; }
.mail-preview {
    width: 100%; min-height: 32rem; border: 1px solid var(--rule-soft);
    border-radius: var(--radius); background: var(--warm-ivory);
}
.recipient-list { columns: 2 14rem; margin: 0.6rem 0 0; padding: 0; list-style: none; font-size: 0.9rem; }
.recipient-list li { break-inside: avoid; margin-bottom: 0.2rem; }
.recipient-list .muted { font-size: 0.8rem; }
.news-row { display: block; padding: 0.9rem 0; border-bottom: 1px solid var(--rule-soft); text-decoration: none; }
.news-row:last-child { border-bottom: none; }
.news-row h2 { font-size: 1.1rem; margin: 0 0 0.2rem; color: var(--evergreen); }
.news-row.is-unread h2::before {
    content: ""; display: inline-block; width: 8px; height: 8px; margin-right: 0.5rem;
    border-radius: 50%; background: var(--dusty-plum); vertical-align: middle;
}
.news-body p { line-height: 1.65; }

/* Unverified members are reminded, not blocked — see people/verification.py. */
.verify-bar {
    display: flex; align-items: center; justify-content: center;
    gap: 0.9rem; flex-wrap: wrap;
    background: var(--tint-gold); border-bottom: 1px solid var(--soft-gold);
    padding: 0.6rem 1.2rem; font-size: 0.88rem; color: var(--ink);
}
.verify-bar form { margin: 0; }
.verify-bar button {
    background: none; border: none; padding: 0; cursor: pointer;
    font-family: var(--font-body); font-size: 0.88rem;
    color: var(--plum-deep); text-decoration: underline;
    text-underline-offset: 3px;
}

main { flex: 1; width: 100%; max-width: 1000px; margin: 0 auto; padding: 2.4rem 1.5rem 3rem; }
.narrow { max-width: 560px; margin-inline: auto; }

.consent {
    font-size: 0.88rem;
    color: var(--ink-soft);
    background: var(--tint-sage);
    border-radius: var(--radius);
    padding: 0.75rem 1rem;
    margin: 1.4rem 0 0;
}
.footer-links { margin: 0.5rem 0 0; font-size: 0.82rem; }

.site-footer {
    border-top: 1px solid var(--rule-soft);
    padding: 1.4rem 1.5rem;
    text-align: center;
    font-size: 0.85rem;
    color: var(--ink-soft);
}

/* ── Cards ──────────────────────────────────────────────────────────────── */
.card {
    background: var(--wildflower-white);
    border: 1px solid var(--rule-soft);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    padding: 2rem 2.1rem;
}
.card + .card { margin-top: 1.4rem; }
.card-head { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }

/* ── Buttons — the pill shapes from the brand board ─────────────────────── */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.45rem;
    min-height: 44px;
    padding: 0.6rem 1.7rem;
    border: 1px solid transparent;
    border-radius: var(--radius-pill);
    font-family: var(--font-body);
    font-size: 0.93rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: none;
    cursor: pointer;
    transition: transform 0.12s ease, box-shadow 0.12s ease, background 0.12s ease;
}
.btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-lift); }
.btn:active { transform: none; }
.btn:focus-visible { outline: 2px solid var(--dusty-plum); outline-offset: 3px; }

.btn-bloom   { background: var(--dusty-plum); color: var(--wildflower-white); }
.btn-bloom:hover { background: var(--plum-deep); color: var(--wildflower-white); }
.btn-grow    { background: var(--sage); color: var(--evergreen); }
.btn-grow:hover { color: var(--evergreen); }
.btn-connect { background: var(--lilac-mist); color: var(--plum-deep); }
.btn-connect:hover { background: var(--heather); color: var(--plum-deep); }
.btn-quiet {
    background: transparent;
    color: var(--ink-soft);
    border-color: var(--rule);
}
.btn-quiet:hover { color: var(--evergreen); background: var(--gold-wash); }

.btn-xs {
    min-height: 30px;
    padding: 0.2rem 0.9rem;
    font-size: 0.72rem;
    letter-spacing: 0.06em;
}
.btn-sm {
    min-height: 36px;
    padding: 0.35rem 1.2rem;
    font-size: 0.82rem;
}

.btn-row-center { justify-content: center; }

.btn-row { display: flex; gap: 0.8rem; flex-wrap: wrap; align-items: center; margin-top: 1.6rem; }

/* ── Forms ──────────────────────────────────────────────────────────────── */
.field { margin-bottom: 1.25rem; }
.field label {
    display: block;
    font-size: 0.82rem;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    font-weight: 600;
    color: var(--ink-soft);
    margin-bottom: 0.4rem;
}
.field-input {
    width: 100%;
    padding: 0.7rem 0.9rem;
    font-family: var(--font-body);
    font-size: 1rem;
    color: var(--ink);
    background: var(--warm-ivory);
    border: 1px solid var(--rule-soft);
    border-radius: 10px;
    transition: border-color 0.15s ease, box-shadow 0.15s ease;
}
.field-input:focus {
    outline: none;
    border-color: var(--soft-gold);
    box-shadow: 0 0 0 3px var(--gold-ring);
    background: var(--wildflower-white);
}
textarea.field-input { resize: vertical; line-height: 1.6; }
select.field-input { appearance: none;
    background-image: var(--select-arrow);
    background-repeat: no-repeat; background-position: right 0.9rem center; background-size: 11px;
    padding-right: 2.4rem;
}
.helptext { display: block; font-size: 0.83rem; color: var(--ink-soft); margin-top: 0.35rem; }

/* Image upload — thumbnail beside the control, not a storage key */
.image-field { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; }
.image-preview {
    width: 64px; height: 64px; flex: none;
    border-radius: 50%;
    object-fit: cover;
    background: var(--tint-lilac);
    box-shadow: 0 0 0 1px var(--rule);
}
/* Dimmed while "remove current photo" is ticked, so the effect of the
   checkbox is visible before saving. */
.image-field-clearing .image-preview { opacity: 0.35; filter: grayscale(1); }
.image-preview, .image-field-clearing .image-preview { transition: opacity 0.15s ease, filter 0.15s ease; }
.image-controls { display: flex; flex-direction: column; gap: 0.4rem; }
.image-file { font-family: var(--font-body); font-size: 0.88rem; color: var(--ink-soft); }
.image-file::file-selector-button {
    font-family: var(--font-body);
    font-size: 0.82rem;
    font-weight: 600;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--evergreen);
    background: var(--sage);
    border: none;
    border-radius: var(--radius-pill);
    padding: 0.4rem 1.1rem;
    margin-right: 0.7rem;
    cursor: pointer;
}
.field label.image-clear, .image-clear {
    display: flex; align-items: center; gap: 0.45rem;
    text-transform: none; letter-spacing: normal;
    font-size: 0.88rem; font-weight: 400; color: var(--ink-soft);
    margin-bottom: 0; cursor: pointer;
}
.image-clear input { accent-color: var(--plum-deep); }

/* ── Avatar picker ──────────────────────────────────────────────────────── */
.avatar-picker { margin-bottom: 1.5rem; }
.ap-live { display: flex; align-items: center; gap: 1rem; margin-bottom: 1.4rem; }
.ap-preview .av { width: 82px; height: 82px; }

.ap-group + .ap-group { margin-top: 1.4rem; }
.ap-title {
    display: block; font-size: 0.72rem; letter-spacing: 0.14em;
    text-transform: uppercase; color: var(--ink-soft); margin-bottom: 0.6rem;
}
.ap-swatches { display: flex; flex-wrap: wrap; gap: 0.9rem; }

.ap-swatch { display: flex; flex-direction: column; align-items: center; gap: 0.35rem;
    cursor: pointer; text-transform: none; letter-spacing: normal;
    font-size: 0.72rem; font-weight: 400; color: var(--ink-soft); margin-bottom: 0; }
.ap-swatch input { position: absolute; opacity: 0; pointer-events: none; }
.ap-face {
    width: 54px; height: 54px; border-radius: 50%;
    display: grid; place-items: center; overflow: hidden;
    box-shadow: 0 0 0 1px var(--rule-soft);
    transition: box-shadow 0.15s ease, transform 0.15s ease;
}
.ap-face img { width: 100%; height: 100%; object-fit: contain; }
.ap-face-full img { object-fit: cover; }
.ap-chars { font-family: var(--font-display); font-size: 1.05rem; color: var(--plum-deep); }
.ap-swatch input:checked + .ap-face {
    box-shadow: 0 0 0 2px var(--dusty-plum), 0 0 0 5px var(--wildflower-white);
    transform: scale(1.06);
}
.ap-swatch input:focus-visible + .ap-face { box-shadow: 0 0 0 3px var(--gold-ring); }
.ap-swatch input:checked ~ .ap-name { color: var(--evergreen); font-weight: 600; }

.ap-sub { display: flex; align-items: center; gap: 1rem; flex-wrap: wrap; margin-top: 0.8rem; }
.ap-sub label { text-transform: uppercase; font-size: 0.7rem; letter-spacing: 0.12em; margin: 0; }
.avatar-text-input { width: 6rem; }
.ap-tints { display: flex; gap: 0.4rem; }
.ap-tint { margin: 0; cursor: pointer; }
.ap-tint input { position: absolute; opacity: 0; pointer-events: none; }
.ap-tint-face { display: block; width: 26px; height: 26px; border-radius: 50%;
    box-shadow: 0 0 0 1px var(--rule-soft); transition: box-shadow 0.15s ease; }
.ap-tint input:checked + .ap-tint-face { box-shadow: 0 0 0 2px var(--dusty-plum); }

/* ── Avatar, wherever it is drawn ───────────────────────────────────────── */
.av { display: grid; place-items: center; width: 100%; height: 100%;
      border-radius: 50%; overflow: hidden;
      /* Sized against the disc, so characters fit whether the avatar is 30px in
         the bloom or 82px on a profile. A fixed size overflowed the small ones. */
      container-type: size; }
.av-photo { object-fit: cover; }
.av-mark { width: 100%; height: 100%; object-fit: contain; }
.av-text {
    font-family: var(--font-display);
    color: var(--plum-deep);
    font-size: 1.6rem;
    font-size: 38cqmin;
    line-height: 1;
}
.avatar-slot { display: block; width: 82px; height: 82px; flex: none;
    box-shadow: 0 0 0 4px var(--warm-ivory), 0 0 0 5px var(--rule); border-radius: 50%; }

.pronouns { font-size: 0.8rem; color: var(--ink-soft); margin-left: 0.5rem; }
.element-row { display: flex; gap: 0.4rem; flex-wrap: wrap; }
.element-chip { padding: 0.2rem 0.7rem; border-radius: var(--radius-pill);
    font-size: 0.74rem; text-transform: capitalize; color: var(--ink); }

/* Whether the address has been confirmed, beside it in the profile. Quiet on
   purpose: the banner in base.html is what asks for action, and this only
   records where things stand once the banner is gone. Built from existing
   tokens rather than new ones -- a confirmation marker is not a new colour. */
.email-state {
    margin-left: 0.5rem;
    padding: 0.15rem 0.6rem;
    border-radius: var(--radius-pill);
    font-size: 0.72rem;
    white-space: nowrap;
    color: var(--ink-soft);
}
.email-state.is-confirmed { background: var(--sage-wash); color: var(--evergreen); }

/* What can be done with a reflection already written (§4.5): add, edit,
   delete. Its own line under the date, so the words stay the thing being
   read and the actions are found in one place rather than trailing a
   sentence about when it was written. */
.facet-actions { margin-top: 0.3rem; }
/* Delete carries the error tone -- the one irreversible thing on the page
   should not look like its neighbours. A token, never a literal (CLAUDE.md). */
.danger-link { color: var(--error-ink); }

/* The reflection being deleted, quoted back in full: nobody should have to
   remember which one the page is asking about. */
.delete-quote {
    margin: 1rem 0; padding-left: 1rem;
    border-left: 2px solid var(--rule);
}

/* A lone checkbox: box beside its words, like the multi-select groups. The
   generic field layout puts a label above its control, which for one box
   leaves it floating under a heading of its own. */
.field-check label {
    display: flex; align-items: flex-start; gap: 0.6rem;
    text-transform: none; letter-spacing: normal;
    font-size: 0.98rem; font-weight: 400; color: var(--ink); cursor: pointer;
}
.field-check input { margin-top: 0.25rem; }

/* Radio group — used for directory visibility */
.field ul { list-style: none; margin: 0; padding: 0; }
.field ul li { margin-bottom: 0.45rem; }
.field ul label {
    display: flex;
    align-items: flex-start;
    gap: 0.6rem;
    text-transform: none;
    letter-spacing: normal;
    font-size: 0.98rem;
    font-weight: 400;
    color: var(--ink);
    cursor: pointer;
}
.field input[type="radio"] { margin-top: 0.35rem; accent-color: var(--plum-deep); }

.errorlist {
    list-style: none;
    margin: 0 0 0.6rem;
    padding: 0.6rem 0.9rem;
    background: var(--blush-petal);
    border-radius: 10px;
    color: var(--error-ink);
    font-size: 0.88rem;
}

/* ── Messages ───────────────────────────────────────────────────────────── */
.messages { list-style: none; margin: 0 0 1.6rem; padding: 0; }
.messages li {
    padding: 0.85rem 1.1rem;
    border-radius: 10px;
    border-left: 3px solid var(--sage);
    background: var(--sage-wash);
    font-size: 0.95rem;
    margin-bottom: 0.6rem;
}
.messages li.error { border-left-color: var(--heather); background: var(--blush-petal); }

/* ── Avatar — brand-styled initials until R2 storage lands ──────────────── */
.avatar {
    width: 82px;
    height: 82px;
    flex: none;
    border-radius: 50%;
    display: grid;
    place-items: center;
    background: var(--tint-lilac);
    color: var(--plum-deep);
    font-family: var(--font-display);
    font-size: 1.9rem;
    letter-spacing: 0.04em;
    box-shadow: 0 0 0 4px var(--warm-ivory), 0 0 0 5px var(--rule);
}

img.avatar { object-fit: cover; }

/* ── Profile ────────────────────────────────────────────────────────────── */
.profile-head { display: flex; align-items: center; gap: 1.4rem; flex-wrap: wrap; }
.profile-head h1 { margin-bottom: 0.15rem; }

.pill {
    display: inline-block;
    padding: 0.22rem 0.85rem;
    border-radius: var(--radius-pill);
    font-size: 0.74rem;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    font-weight: 600;
}
.pill-member { background: var(--sage); color: var(--evergreen); }
.pill-provider { background: var(--lilac-mist); color: var(--plum-deep); }

.detail-list { margin: 0; }
.detail-list dt {
    font-size: 0.72rem;
    letter-spacing: 0.18em;
    text-transform: uppercase;
    color: var(--plum-deep);
    font-weight: 600;
    margin-top: 1.3rem;
}
.detail-list dd { margin: 0.3rem 0 0; }
.detail-list dd.empty { color: var(--ink-soft); font-style: italic; }

/* Jessica's border element, in place of the rule I drew. */
.divider-art {
    display: block;
    width: min(456px, 70%);
    height: auto;
    margin: 1.1rem auto 1.3rem;
    opacity: 0.85;
}

/* ── Offerings (§4.2.7) ─────────────────────────────────────────────────── */
/* How a picked offering reads on a profile: a quiet pill in the same rhythm
   as the element chips beside it, without a tint -- offerings are not one of
   the five, and a coloured pill would claim to be. */
.offer-chip {
    display: inline-block; padding: 0.2rem 0.7rem; border-radius: var(--radius-pill);
    font-size: 0.74rem; color: var(--ink);
    background: var(--wildflower-white); border: 1px solid var(--rule-soft);
}

/* The picker on the profile form: a search over the list, then the list, then
   the box for what is not on it. The list scrolls past a dozen or so rows so
   the form below it stays reachable as the community names more. */
.offer-picker {
    border: 1px solid var(--rule-soft); border-radius: var(--radius);
    padding: 1rem 1.1rem 0.6rem; margin: 0 0 1.4rem;
}
.offer-picker legend {
    padding: 0 0.4rem; font-size: 0.72rem; letter-spacing: 0.16em;
    text-transform: uppercase; font-weight: 600; color: var(--plum-deep);
}
.offer-picker > .helptext { display: block; margin-bottom: 0.8rem; }
.offer-picker [data-offer-search] { margin-bottom: 0.6rem; }
.offer-options { max-height: 16rem; overflow-y: auto; padding-right: 0.3rem; }
/* Django draws a checkbox group as a div of divs, one per option. */
.offer-options > div {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: 0.15rem 1rem;
}
.offer-options > div > div[hidden] { display: none; }
.offer-options label {
    display: flex; align-items: flex-start; gap: 0.6rem;
    text-transform: none; letter-spacing: normal;
    font-size: 0.96rem; font-weight: 400; color: var(--ink); cursor: pointer;
    padding: 0.2rem 0;
}
.offer-none { margin-bottom: 0.8rem; }
.offer-picker .field { margin-top: 0.8rem; }

/* Invitations (§4.4). The state pill reuses the confirmation marker's
   shapes: outstanding is the gold tint
   because it is waiting on somebody, accepted is the sage wash that already
   means "done" beside the email address, and revoked carries no fill at all. */
.invite-row {
    display: flex; align-items: flex-start; justify-content: space-between;
    gap: 1rem; flex-wrap: wrap;
    padding: 0.8rem 0; border-bottom: 1px solid var(--rule-soft);
}
.invite-who { min-width: 0; }
.invite-email {
    font-family: var(--font-display); color: var(--evergreen);
    word-break: break-word;
}
.invite-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.invite-state {
    margin-left: 0.4rem; padding: 0.15rem 0.6rem;
    border-radius: var(--radius-pill);
    font-size: 0.72rem; text-transform: capitalize; color: var(--ink-soft);
}
.invite-state.is-outstanding { background: var(--tint-gold); color: var(--ink); }
.invite-state.is-accepted { background: var(--sage-wash); color: var(--evergreen); }

/* ── My Garden (§4.5) ───────────────────────────────────────────────────── */
/* The garden gets its own width. .narrow caps a page at 560px, which is right
   for prose and wrong for a ring of twenty-one things -- it was rendering at
   little over half the space the layout was designed against. */
.garden-page { max-width: 860px; margin-inline: auto; }
/* The negative side margins let the drawing break out of a card's padding.
   There is no card now, so they would only pull it off the page. */
.garden { margin: 1.4rem 0 0.4rem; position: relative; }
.garden-stage { position: relative; }
.garden-svg {
    display: block; width: 100%; height: auto; overflow: visible;
    /* Four fifths, at Brooklin's direction. The whole drawing shrinks together
       -- petals, wedges, marks and names -- because it is one scaled box and
       not a set of sizes. */
    max-width: 80%; margin-inline: auto;
}


/* The symbol sprite. width="0" height="0" makes it draw nothing, but it is
   still an inline element, so it generates a line box -- about 28px of empty
   space at the top of every page that defines the marks. Out of flow entirely. */
.facet-marks { position: absolute; width: 0; height: 0; overflow: hidden; }

/* ── The bloom ──────────────────────────────────────────────────────────── */
/* Three rings: the heart, five element wedges, and each element's three facets
   as petals on its own outer edge. Every shape is a path, so fill and stroke
   still mean draw-in and release exactly as they did on the circles. */
.bloom-wedge path { fill: var(--tint-sage); stroke: var(--bronze-edge); stroke-width: 0.5; }
.bloom-wedge.tint-moss    path { fill: var(--tint-moss); }
.bloom-wedge.tint-heather path { fill: var(--tint-heather); }
.bloom-wedge.tint-lilac   path { fill: var(--tint-lilac); }
.bloom-wedge.tint-gold    path { fill: var(--tint-gold); }
.bloom-label {
    font-family: var(--font-display); font-size: 3.1px;
    fill: var(--evergreen); letter-spacing: 0.04em;
}

/* Attract fills, clear outlines. A facet nobody has reflected on is a dashed
   outline: "not yet said" is a real state and must not read as "fine".
   pointer-events:all so the whole petal is a target and not just its edge --
   with fill:none SVG hit-tests the stroke alone, which on an untouched garden
   left every target half a unit wide. */
/* Bronze for a petal with nothing in it, like the wedges and the rim. A petal
   a member has written in overrides this inline with the colour they chose to
   release, so this only ever draws the empty ones. */
.bloom-petal path {
    fill: var(--wildflower-white); stroke: var(--bronze-edge); stroke-width: 0.6;
}
.bloom-petal.is-focus path { stroke-width: 0.95; }
.bloom-petal.is-empty path {
    fill: none; stroke-dasharray: 1.6 1.4; pointer-events: all;
}

/* Under a lens the other two rings stay drawn -- the shape a member learns is
   the same either way -- but step back, so the ring being asked about is the
   one that reads. On the group, so a petal's mark fades with it. */
.bloom-petal.is-muted { opacity: 0.22; }

/* The facet marks. Line art over whatever colour a member chose, so they are
   stroked in the soft ink rather than filled, and held back a little: the mark
   says which facet this is, the colour says how it is. */
.bloom-mark, .lens-mark, .facet-mark, .nav-mark {
    fill: none; stroke: var(--ink-soft); stroke-width: 1.7;
    stroke-linecap: round; stroke-linejoin: round;
}
.bloom-mark { opacity: 0.55; }

.garden-lenses a { display: flex; align-items: center; gap: 0.4rem; }
.lens-mark { width: 1.05em; height: 1.05em; flex: none; }
.garden-lenses a.is-active .lens-mark { stroke: var(--evergreen); }

/* The same marks in prose: an element's three rows, a reflection as it is
   written, and the journal. Sized in em so each one matches the text it names
   rather than a fixed pixel size that is right in only one of those places. */
.facet-mark { width: 1.15em; height: 1.15em; flex: none; }
.facet-row-head .facet-mark { stroke: var(--evergreen); }
.facet-badge {
    display: flex; align-items: center; gap: 0.45rem;
    margin: 0 0 1rem; color: var(--ink-soft);
    font-family: var(--font-display);
}
.facet-badge .facet-mark { width: 1.25em; height: 1.25em; }

/* The lens selector. Tucked into a corner of the drawing rather than stacked
   above it: the garden is already the tallest thing on the page and a row of
   controls over the top would push the ring further down for no gain. */
/* Corner links, mirroring the lens selector on the other side. Both sit inside
   the drawing rather than above it: the garden is the tallest thing on the page
   and a row of controls over the top pushes the ring further down for no gain. */
/* At the foot of the drawing rather than the head of it: the same place the
   mirror keeps them, under the flower, and the same place a phone puts them. */
.garden-links {
    position: absolute; bottom: 0; right: 0; z-index: 1;
    display: flex; flex-direction: column; align-items: flex-end; gap: 0.35rem;
}
/* These sit in the corners of the drawing rather than in a row of their own,
   which had them shrinking to stay out of the way. Corner is not the same as
   small: 13px was below what this page asks anyone to read. */
/* A border and a ground, because as bare words they read as captions on the
   drawing beside a lens list that is genuinely a control (Jessica, 2026-08-31).
   Not the filter chip: that is set at 0.78rem, and the size here was raised
   deliberately -- a corner is not an invitation to shrink. */
.garden-links a {
    display: flex; align-items: center; gap: 0.4rem;
    font-size: 0.95rem; text-decoration: none; color: var(--ink-soft);
    padding: 0.28rem 0.75rem; border-radius: var(--radius-pill);
    border: 1px solid var(--rule-soft); background: var(--wildflower-white);
}
.nav-mark { width: 1.15em; height: 1.15em; flex: none; }
.garden-links a:hover .nav-mark { stroke: var(--evergreen); }
.garden-links a:hover { color: var(--evergreen); background: var(--gold-wash); }

.garden-lenses {
    position: absolute; bottom: 0; left: 0; z-index: 1;
    display: flex; flex-direction: column; align-items: flex-start; gap: 0.35rem;
}
/* The same ground and border as the links opposite. The lens is the more
   control-like of the two -- it changes this page rather than leaving it --
   so it cannot be the one that reads as a caption. */
.garden-lenses a {
    display: flex; align-items: center; gap: 0.4rem;
    font-size: 0.95rem; text-decoration: none; color: var(--ink-soft);
    padding: 0.28rem 0.75rem; border-radius: var(--radius-pill);
    border: 1px solid var(--rule-soft); background: var(--wildflower-white);
}
.garden-lenses a:hover { color: var(--evergreen); background: var(--gold-wash); }
.garden-lenses a.is-active {
    color: var(--evergreen); background: var(--sage-wash);
    border-color: var(--gold-ring); font-weight: 600;
}

/* A lens replaces the fifteen bubbles with the words themselves. */
.garden-words { font-size: 2.7px; fill: var(--ink); }
.garden-words .is-empty { fill: var(--ink-soft); font-style: italic; }

/* The facets used to be hidden on a phone: fifteen bubbles at 5.5 units landed
   at roughly half a comfortable tap target on a 375px screen. A petal is a
   twenty-four degree wedge of the rim, several times that area, so they stay. */
@media (max-width: 640px) {
    .garden-lenses, .garden-links {
        position: static; flex-direction: row; flex-wrap: wrap;
        align-items: center; justify-content: center; margin-bottom: 0.6rem;
    }
}

/* ── One element, whoever is looking ────────────────────────────────────── */
/* The title row is the disclosure. A row of its own saying "what water means"
   was a row spent on a label, and the element's name is the obvious thing to
   press to find out what it means. */
.element-about > summary {
    list-style: none; cursor: pointer;
    display: block; text-align: left; border-radius: var(--radius);
}
.element-about > summary::-webkit-details-marker { display: none; }
.element-about .element-head {
    display: flex; align-items: center; gap: 1rem; margin-bottom: 0;
    flex-wrap: wrap;
}
.element-about .element-mark { margin: 0; flex: none; }
.element-about .element-head h1 { margin: 0; }
.element-about .element-tagline { margin: 0; }
/* The sentence, always on the page. The description is what folds away. */
.element-summary {
    display: block; margin-top: 0.7rem;
    font-family: var(--font-display); font-size: 1.06rem;
    line-height: 1.5; color: var(--evergreen);
}
.element-about-mark {
    margin-left: auto; flex: none;
    width: 1.5rem; height: 1.5rem; stroke: var(--dusty-plum);
}
.element-about > summary:hover .element-about-mark { stroke: var(--plum-deep); }
.element-about > summary:focus-visible {
    outline: 2px solid var(--dusty-plum); outline-offset: 3px;
}
.element-about[open] .element-body { margin-top: 0.7rem; }

.element-section { margin-top: 1.8rem; }
.element-section > h2 a { color: inherit; text-decoration: none; }
/* An element heading carries its own icon and its name at reading size. The
   small letterspaced label the sections share weighed the same as the facet
   rows beneath it, so five of them ran together. */
.element-section > h2.element-heading {
    display: flex; align-items: center; gap: 0.6rem;
    font-family: var(--font-display); font-size: 1.3rem; font-weight: 500;
    letter-spacing: 0.01em; text-transform: none; color: var(--evergreen);
    padding-bottom: 0.45rem;
}
.element-section > h2.element-heading img {
    width: 2rem; height: 2rem; object-fit: contain; flex: none;
}
.element-section > h2 a:hover { color: var(--evergreen); }
.element-section > h2 {
    font-size: 0.78rem; font-weight: 600;
    letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--ink-soft); margin-bottom: 0.5rem;
    padding-bottom: 0.4rem; border-bottom: 1px solid var(--rule);
}
.element-section .facet-row-head .facet-mark { stroke: var(--evergreen); }
/* How many more are queued behind this one, as a number beside the facet it
   belongs to. It was "5 waiting" three times down the page, which on a phone
   was a column of prose spent on one digit. */
.facet-count { margin-left: -0.15rem; font-size: 0.85em; font-weight: 600; color: var(--plum-deep); }
/* The way in sits on the facet's own line rather than under its question --
   one row saved per facet, six down the page. It keeps its words on one line
   and the row wraps instead, because a button broken across two lines is
   harder to read than a row that is one taller. */
.facet-row-head { flex-wrap: wrap; }
.facet-row-head .btn { margin-left: auto; white-space: nowrap; }
/* The facet under what it names, rather than a heading over it: at label size
   it says which of the three this is without competing with the question, and
   the marks are sized in em so they come down with it. */
.facet-line { margin-top: 0.35rem; gap: 0.45rem; }
.facet-line .facet-name { font-size: 0.92rem; }
/* An outline the width of its words. Filled plum was the loudest thing on a
   page whose point is the question above it. */
.facet-line .btn {
    min-height: 26px; padding: 0.12rem 0.7rem;
    font-size: 0.72rem; letter-spacing: 0.05em;
}
.facet-row > :first-child { margin-top: 0; }
/* A question already answered: kept, because which question was settled is
   the interesting part, but not dressed as something to act on. */
.facet-text.is-settled {
    display: flex; align-items: flex-start; gap: 0.45rem;
    color: var(--evergreen);
    /* .facet-text keeps a member's own line breaks, which is right for what
       they wrote and wrong here: this is one question, and the newlines around
       it in the template were becoming real breaks that pushed the tick off. */
    white-space: normal;
}
.facet-text.is-settled .note-tick { flex: none; width: 1.05em; height: 1.05em; margin-top: 0.15em; }
.element-all { margin-top: 1rem; font-size: 0.88rem; }

/* Element page */
.element-head { display: flex; align-items: center; gap: 1rem; margin-bottom: 0.6rem; }
.element-head h1 { margin-bottom: 0.1rem; }
.element-disc {
    flex: none; width: 74px; height: 74px; border-radius: 50%;
    display: flex; align-items: center; justify-content: center;
    background: var(--tint-sage);
}
.element-disc img { width: 46px; height: 46px; }

.facet-row { padding: 0.9rem 0; border-bottom: 1px solid var(--rule-soft); }
.facet-row:last-child { border-bottom: none; }
.facet-row-head { display: flex; align-items: center; gap: 0.55rem; }
.facet-name { font-family: var(--font-display); color: var(--evergreen); }
/* The two colors of one reflection, each named. What replaced a single dot
   whose fill and border meant two different things and said so nowhere. */
.color-pair { display: inline-flex; align-items: center; gap: 0.7rem; }
.color-note {
    display: inline-flex; align-items: center; gap: 0.35rem;
    font-size: 0.78rem; color: var(--ink-soft); white-space: nowrap;
}
.color-dot {
    width: 15px; height: 15px; border-radius: 50%; flex: none;
    border: 1px solid var(--rule-soft);
}
/* Released is a ring, drawn in is filled: the same distinction the petal
   makes, so the key below the bloom and the rows here teach one thing. */
.color-dot.is-ring { background: transparent; border-width: 4px; }
.color-pair.is-compact { gap: 0.3rem; }
.color-pair.is-compact .color-word {
    position: absolute; width: 1px; height: 1px;
    overflow: hidden; clip-path: inset(50%); white-space: nowrap;
}
.facet-text { margin: 0.4rem 0 0.3rem; white-space: pre-line; }
/* The prompt banner. Sage rather than the gold of the confirmation bar: one is
   an unfinished task, this is an invitation, and they should not look alike. */
/* The buttons sit under the question rather than beside it: a question can run
   to a couple of lines, and side by side that either squeezes the words into a
   column or pushes the actions off the end of a phone. */
.prompt-bar {
    display: flex; flex-direction: column; align-items: center;
    gap: 0.55rem;
    padding: 0.8rem 1.5rem;
    background: var(--sage-wash);
    border-bottom: 1px solid var(--rule-soft);
}
.prompt-bar-text {
    font-family: var(--font-display); color: var(--evergreen);
    max-width: 44rem; text-align: center; line-height: 1.5;
}
.prompt-bar-actions { display: flex; align-items: center; gap: 0.5rem; }

.answered { color: var(--evergreen); }
/* The question leads its row and carries the weight: it is what the eye
   should land on, and what everything under it is about. */
.prompt-question { font-family: var(--font-display); font-size: 1.1rem;
                   font-weight: 600; color: var(--evergreen);
                   line-height: 1.4; margin-bottom: 0; }

/* The question somebody arrived from, with the two ways to decline it. Sage
   like the banner, because it is the same thing arriving in a different place
   -- an invitation, not an unfinished task. */
.asked {
    background: var(--sage-wash); border-radius: var(--radius);
    padding: 0.9rem 1.1rem; margin-bottom: 1.2rem;
}
.asked-question {
    font-family: var(--font-display); color: var(--evergreen);
    line-height: 1.5; margin-bottom: 0.7rem;
}
.asked-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }

/* On the writing page the element is context, not a tag: it gets a name you
   can read and the passage that says what it means. */
.element-context { margin-bottom: 1.2rem; }
.element-context h2 {
    font-family: var(--font-display); font-size: 1.35rem;
    color: var(--evergreen); margin-bottom: 0.4rem;
}
.element-context p { color: var(--ink-soft); }

/* A colour input renders as a small swatch; the label reads better beside it. */
.field-colour { display: flex; align-items: center; gap: 0.7rem; }
.field-colour input[type="color"] {
    width: 52px; height: 34px; padding: 2px; cursor: pointer;
    border: 1px solid var(--rule-soft); border-radius: 8px; background: none;
}

/* The hover card replaces SVG <title>, whose native tooltip cannot be sized or
   styled. It is now the only place a facet's own words appear on this page. */
.garden-tip {
    position: absolute; z-index: 2; pointer-events: none;
    max-width: 17rem; padding: 0.6rem 0.8rem;
    background: var(--wildflower-white);
    border: 1px solid var(--rule-soft); border-radius: var(--radius);
    box-shadow: var(--shadow-lift);
}
.garden-tip-title {
    display: block; font-family: var(--font-display);
    font-size: 0.95rem; color: var(--evergreen);
}
.garden-tip-body {
    display: block; margin-top: 0.2rem;
    font-size: 0.88rem; line-height: 1.5; color: var(--ink-soft);
}

/* The heart. Five colours drifting behind a blur rather than one flat average:
   averaging many hues collapses toward grey, so a rich garden would read duller
   than a sparse one. A garden nobody has written in rests on the palette. */
.garden-heart-ground { fill: var(--warm-ivory); }
.garden-heart-rim { fill: none; stroke: var(--bronze-rim); stroke-width: 0.75; }
/* The way back to the mirror. fill:none would hit-test the stroke alone, so
   the target is a filled circle that happens to be invisible. */
.garden-heart-hit { fill: transparent; cursor: pointer; }
.garden-heart-link .garden-heart-rim { transition: stroke 140ms ease, stroke-width 140ms ease; }
.garden-heart-link:hover .garden-heart-rim,
.garden-heart-link:focus-visible .garden-heart-rim {
    stroke: var(--soft-gold); stroke-width: 1.1;
}
.garden-blob { fill: var(--sage); }
.garden-blob.tint-sage    { fill: var(--sage); }
.garden-blob.tint-heather { fill: var(--heather); }
.garden-blob.tint-lilac   { fill: var(--lilac-mist); }
.garden-blob.tint-gold    { fill: var(--soft-gold); }
.garden-blob.tint-moss    { fill: var(--moss-green); }

.garden-heart-spin {
    transform-box: view-box; transform-origin: 50px 50px;
    animation: garden-drift 54s linear infinite;
}
@keyframes garden-drift { to { transform: rotate(360deg); } }

/* Somebody who has asked their device to stop animating gets a still heart.
   This is a wellness application; that request is not a preference to override. */
@media (prefers-reduced-motion: reduce) { .garden-heart-spin { animation: none; } }

.garden-key {
    font-size: 0.84rem; color: var(--ink-soft); line-height: 1.6;
    max-width: 34rem; margin: 0.2rem auto 0; text-align: center;
}
.garden-key strong { font-weight: 500; color: var(--evergreen); }

/* A checkbox reads as a sentence, not as a labelled field above a control. */
.field-check { display: flex; align-items: baseline; gap: 0.5rem; flex-wrap: wrap; }
.field-check .helptext { flex-basis: 100%; margin-top: 0.2rem; }

.notice {
    background: var(--tint-gold); border: 1px solid var(--soft-gold);
    border-radius: var(--radius); padding: 0.75rem 1rem; margin: 1rem 0;
    font-size: 0.9rem;
}

/* ── My Garden as a mirror (Jessica's composite, 2026-08-30) ───────────── */
/* The frame is the stage and everything else is placed inside its opening, as
   a percentage of that opening rather than of the page. Two consequences worth
   keeping: the arrangement holds at any width without a media query, and a
   redrawn frame only changes the four numbers on .mirror-glass.

   No card behind it -- the artwork is cut out of white and the page is ivory,
   which is the one ground it meets without a seam. */
.mirror-page { max-width: 860px; margin-inline: auto; }
/* Less air above than a page of prose wants. The two drawings are the tallest
   things in the application and every row given to the gap above one is a row
   taken off the bottom of it. */
main.drawing { padding-top: 1.2rem; }

.mirror-stage {
    position: relative;
    width: min(100%, 460px);
    margin-inline: auto;
}

.mirror-frame { display: block; width: 100%; height: auto; position: relative; z-index: 1; }

/* The lavender sits behind the frame and spills past its base, so it reads as
   growing around the mirror rather than being pasted beside it. One drawing,
   flipped for the far side. */
.mirror-sprig {
    display: none;                     /* a flourish for the wide view only */
    position: absolute; bottom: 0; width: 19%; height: auto;
    z-index: 0; pointer-events: none;
}
.mirror-sprig.is-left  { left: 26%;  transform: rotate(-64deg); transform-origin: bottom center; }
.mirror-sprig.is-right { right: 26%; transform: scaleX(-1) rotate(-64deg); transform-origin: bottom center; }

/* ── The desktop annotation ─────────────────────────────────────────────── */
/* A phone gets the mirror and nothing else: there is no room beside it, and
   the picture is the point. Wider than that, the five are named around it --
   split by where they live in the glass, sky to the right and earth to the
   left, so no label is stranded away from the thing it names. */
.mirror-annotated { display: grid; justify-content: center; }
.mirror-notes { display: none; }

@media (min-width: 900px) {
    .mirror-page { max-width: none; }
    .mirror-sprig { display: block; }
    .mirror-reflect { font-size: 1.55rem; }
    .mirror-annotated {
        grid-template-columns: minmax(0, 1fr) 460px minmax(0, 1fr);
        gap: 1.5rem;
        align-items: stretch;
        max-width: 62rem; margin-inline: auto;
    }
    /* Above the drawing's own column. The lavender is rotated about its base,
       which throws its box a long way past the stage it sits in -- and a note
       full of questions now reaches down to meet it. Words win. */
    .mirror-notes {
        display: block; position: relative; z-index: 2;
        list-style: none; margin: 0; padding: 0;
    }
    /* Direct children only. The questions under a note are a list of their
       own, and `.mirror-notes li` positioned those absolutely too -- at their
       parent's row, which they inherit, so each note landed on top of itself.

       Every note hangs from its row rather than being centred on it. Centred,
       a note grew upward as questions were added and reached the one above;
       hanging, it only ever grows down into the space left for it. */
    .mirror-notes > li {
        position: absolute; left: 0; right: 0; top: var(--row);
    }

    /* Words only. The drawings are already in the mirror, and a second small
       copy of each beside it competed with the thing it was labelling.

       Name and words run on as one line, wrapping together. Two stacked lines
       cost about seventeen pixels a note that the questions underneath now
       want, and the name reads as a name either way. */
    /* The font size belongs on the anchor, not only on the spans inside it. A
       block's line box is at least as tall as its own strut, and the strut is
       built from the block's font size -- so 0.78rem text in a 17px anchor was
       being spaced as though it were 17px. */
    .mirror-note {
        display: block; font-size: 0.86rem; line-height: 1.35;
        padding: 0.4rem 0.6rem 0.15rem; border-radius: var(--radius);
        text-decoration: none; color: inherit;
        transition: background-color 120ms ease;
    }
    /* Left on both sides. The column mirrored the drawing while it held two
       words; now it holds a name, a description and a list of questions, and
       all of that is read rather than glanced at. Reading starts in the same
       place either side of the mirror. */
    .mirror-note-name {
        font-weight: 600; letter-spacing: 0.13em;
        text-transform: uppercase; color: var(--evergreen);
    }
    /* Both inline, so the line box takes the tallest line-height among them --
       leaving it to the page's own 1.65 spread the wrapped lines far enough
       apart to read as two paragraphs rather than one sentence. */
    .mirror-note-words { color: var(--ink-soft); }

    /* The questions waiting under an element. They live inside the note's own
       row, which has room for three: the rows are 200px apart and a note with
       its three is about 145 of that. */
    /* A hairline where the element stops describing itself and starts asking.
       Only drawn when there is something below it to separate. */
    .mirror-notes ul.note-prompts {
        list-style: none; margin: 0.15rem 0.6rem 0; padding: 0.35rem 0 0;
        border-top: 1px solid var(--rule-soft);
        display: flex; flex-direction: column; gap: 0.3rem;
    }
    /* Left, and the mark first, on both sides. The name and its words are
       labels and mirror each other across the drawing; a question is something
       to read, and reading starts in the same place on either side. */
    .note-prompt {
        display: flex; align-items: flex-start; gap: 0.4rem;
        font-size: 0.82rem; line-height: 1.35; text-align: left;
        color: var(--ink-soft); text-decoration: none;
    }
    .note-prompt .nav-mark {
        width: 1.35em; height: 1.35em; margin-top: 0.02em; opacity: 0.8;
    }
    /* Two lines at most. Three questions under one element, each running to a
       third line, is taller than the gap to the next element. */
    .note-prompt-text {
        flex: 1;
        display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
        overflow: hidden;
    }
    .note-prompt-more {
        font-size: 0.72rem; font-weight: 600; color: var(--plum-deep);
    }
    a.note-prompt:hover { color: var(--evergreen); }
    a.note-prompt:hover .nav-mark { stroke: var(--evergreen); opacity: 1; }
    /* Answered is a state, not an invitation, so it does not look pressable --
       but it is something done rather than something missing, so it is not
       faded out either. */
    .note-prompt.is-answered { color: var(--evergreen); }
    .note-prompt.is-answered .note-prompt-text { -webkit-line-clamp: 1; }
    .note-prompt.is-answered .nav-mark { opacity: 0.7; stroke: var(--evergreen); }
    .note-prompt .note-tick { width: 1.1em; height: 1.1em; opacity: 1; flex: none; }

    .mirror-note:hover, .mirror-note:focus-visible { background: var(--gold-wash); }
    .mirror-note:hover .mirror-note-name { color: var(--plum-deep); }

    /* Naming a thing and pointing at it are the same gesture: hovering a label
       lights the drawing it belongs to, inside the glass. */
    .mirror-annotated:has(.mirror-note.is-sun:hover) .mirror-part.is-sun img,
    .mirror-annotated:has(.mirror-note.is-water:hover) .mirror-part.is-water img,
    .mirror-annotated:has(.mirror-note.is-roots:hover) .mirror-part.is-roots img,
    .mirror-annotated:has(.mirror-note.is-seed:hover) .mirror-part.is-seed img,
    .mirror-annotated:has(.mirror-note.is-flower:hover) .mirror-part.is-flower img {
        filter: drop-shadow(0 0 5px var(--soft-gold))
                drop-shadow(0 0 13px var(--gold-ring));
    }
    .mirror-annotated:has(.mirror-note.is-soil:hover) .mirror-part.mirror-earth::after {
        opacity: 1;
    }
}

/* Over the frame, not under it: the frame arrived with its glass painted in,
   so a scene beneath it would be hidden. The opening was measured off that
   file, which is why the ellipse lands inside the bevel rather than over it. */
/* Above the frame, which is itself above the lavender: the frame arrived with
   its glass painted in, so the scene has to sit on top of that paint. Giving
   the glass a layer of its own also contains the parts inside it, so their
   depths stack against each other and not against the frame. */
.mirror-glass {
    position: absolute;
    z-index: 2;
    border-radius: 50%;
    overflow: hidden;
}

.mirror-ground {
    position: absolute; inset: 0;
    background: linear-gradient(
        to bottom,
        var(--glass-sky) 0%,
        var(--glass-haze) 34%,
        var(--glass-field) 56%,
        var(--glass-verge) calc(var(--horizon) - 5%),
        var(--glass-earth) calc(var(--horizon) + 1%),
        var(--glass-deep) 100%);
}

.mirror-part {
    position: absolute;
    left: var(--cx); top: var(--cy); width: var(--w);
    transform: translate(-50%, -50%);
    z-index: var(--depth);
    display: block;
    text-decoration: none;
}
.mirror-part img { display: block; width: 100%; height: auto; }

/* The flower opens over two seconds and then settles back to a third, and the
   invitation arrives in the space that leaves. The resting state is the base
   rule, not the animation's last frame, so the two agree and no fill mode is
   needed to hold it -- which is also what leaves :hover able to bring the
   flower back afterwards. */
@keyframes flower-opens {
    0%   { opacity: 0; }
    50%  { opacity: 1; }
    100% { opacity: 0.3; }
}
@keyframes reflect-arrives {
    from { opacity: 0; }
    to   { opacity: 1; }
}

.mirror-part.is-flower img {
    opacity: 0.3;
    animation: flower-opens 4s ease-in-out;
    transition: opacity 320ms ease;
}

/* Level with the tip of the upper-left leaf, and halfway between that tip and
   the mirror's inner edge at the same height. Both measured off the drawing:
   the leaf reaches 39.6% across the glass, and the ellipse is at 0.3% there. */
.mirror-reflect {
    position: absolute; left: 19.96%; top: 44.41%;
    transform: translate(-50%, -50%);
    z-index: 10;
    font-family: var(--font-display); font-style: italic; font-size: 1.3rem;
    letter-spacing: 0.03em; color: var(--evergreen);
    text-decoration: none; white-space: nowrap;
    /* Backwards, so it holds its first frame through the four seconds it is
       waiting rather than showing before the flower has finished. */
    animation: reflect-arrives 0.8s ease-out 4s backwards;
}
.mirror-reflect:hover, .mirror-reflect:focus-visible { color: var(--plum-deep); }

/* The word and the flower are one control in two places, so pointing at either
   brings the bloom back up. */
.mirror-glass:has(.mirror-reflect:hover) .mirror-part.is-flower img,
.mirror-glass:has(.mirror-reflect:focus-visible) .mirror-part.is-flower img,
.mirror-part.is-flower:hover img,
.mirror-part.is-flower:focus-visible img { opacity: 1; }

@media (prefers-reduced-motion: reduce) {
    .mirror-part.is-flower img, .mirror-reflect { animation: none; }
}

/* The one part with no drawing of its own: it is the ground, so it takes the
   whole opening from the horizon down and lets the ellipse crop it. */
.mirror-part.mirror-earth {
    left: 0; top: var(--horizon); right: 0; bottom: 0;
    width: auto; height: auto; transform: none;
    background: linear-gradient(to bottom, var(--earth-veil-top), var(--earth-veil-low)),
                var(--soil) center / cover no-repeat;
}

/* A rectangle cannot glow along its own outline the way a cut-out does, so the
   ground answers with a lit surface and a warmer face. */
.mirror-part.mirror-earth::after {
    content: ""; position: absolute; inset: 0;
    background: var(--gold-wash);
    border-top: 2px solid var(--soft-gold);
    opacity: 0; transition: opacity 140ms ease;
}
.mirror-part.mirror-earth:hover::after,
.mirror-part.mirror-earth:focus-visible::after { opacity: 1; }
/* Off to one side, clear of the stem: the ground sits below the flower in the
   stack, so a name centred under it is read through the plant. */
.mirror-part.mirror-earth .mirror-caption {
    top: 0; left: 26%; transform: translate(-50%, 0.4rem);
}

/* The seed lies at the bottom of the glass, where there is no room beneath it
   -- its name went under the frame. It reads upward instead. */
.mirror-part.is-seed .mirror-caption {
    top: auto; bottom: 100%; transform: translate(-50%, -0.2rem);
}

/* The glow follows the drawing's own alpha rather than its box, which is the
   whole reason these arrived as separate cut-outs. */
.mirror-part.is-live img { transition: filter 140ms ease; }
.mirror-part.is-live:hover img,
.mirror-part.is-live:focus-visible img {
    filter: drop-shadow(0 0 5px var(--soft-gold))
            drop-shadow(0 0 13px var(--gold-ring));
}
.mirror-part.is-live:focus-visible { outline: none; }

/* Whatever is being pointed at comes to the front, so its glow and its name are
   not drawn over by whatever happens to stack above it. */
.mirror-part.is-live:hover,
.mirror-part.is-live:focus-visible { z-index: 20; }

/* Except the ground, which is under the roots and the seed by definition --
   lifting it on hover buried the two things standing in it. */
.mirror-part.mirror-earth:hover,
.mirror-part.mirror-earth:focus-visible { z-index: var(--depth); }

.mirror-caption {
    position: absolute; left: 50%; top: 100%;
    transform: translate(-50%, 0.2rem);
    font-size: 0.72rem; font-weight: 600;
    letter-spacing: 0.12em; text-transform: uppercase;
    color: var(--evergreen); background: var(--wildflower-white);
    padding: 0.12rem 0.5rem; border-radius: var(--radius-pill);
    white-space: nowrap; opacity: 0; pointer-events: none;
    transition: opacity 140ms ease;
}
.mirror-part.is-live:hover .mirror-caption,
.mirror-part.is-live:focus-visible .mirror-caption { opacity: 1; }

.mirror-hint {
    max-width: 26rem; margin: 1.5rem auto 0; text-align: center;
    font-size: 0.9rem; color: var(--ink-soft);
}

/* ── Home ───────────────────────────────────────────────────────────────── */
/* No top padding of its own: main already gives the page its top margin,
   and the hero was stacking a second one on top of it. */
.hero { text-align: center; padding: 0 0 0.5rem; }
main.hero-page { padding-top: 2rem; }
.hero h1 { font-size: 2.7rem; letter-spacing: 0.08em; }
/* One measure for everything in the hero, wide enough that its edges sit with
   the row of elements rather than in a column a third of its width. 30rem was
   a reading measure for prose; this page is a short introduction above a row
   of five icons, and the narrow column left it scrolling past them. */
.hero p, .hero .what, .hero .essay { max-width: 44rem; margin-inline: auto; }

.opening {
    max-width: 33rem;
    margin: 0.9rem auto 0;
    color: var(--ink);
}
.opening-invite { color: var(--plum-deep); margin-top: 1.2rem; }

/* The essay below the aspects reads as prose, so it is left-aligned and
   measured — centred text stops being readable past a couple of lines. */
.essay { max-width: 30rem; margin: 0 auto; text-align: left; }
.essay p { margin: 0 0 1rem; }
.essay-lead {
    font-family: var(--font-display);
    font-size: 1.1rem;
    color: var(--evergreen);
    margin-top: 2rem !important;
}
.essay-close {
    font-family: var(--font-display);
    font-style: italic;
    font-size: 1.2rem;
    color: var(--plum-deep);
    text-align: center;
    margin-top: 1.6rem !important;
}
.essay-source { font-size: 0.86rem; color: var(--ink-soft); text-align: center; }

/* The About page is the essay alone, so it takes the hero's measure rather
   than the 30rem it had tucked under the elements, and lines up with its own
   heading instead of sitting indented beneath it. */
.about { max-width: 42rem; margin-inline: auto; }
.about .essay { max-width: none; }

/* The policy page: three long documents, so real headings to scan by rather
   than the essay's display leads, and space enough between the three that
   each reads as its own. */
.policy-toc { font-size: 0.95rem; }
.policy h2 {
    margin: 2.8rem 0 1rem; padding-top: 1.6rem;
    border-top: 1px solid var(--rule-soft);
}
.policy h3 { margin: 1.8rem 0 0.6rem; }
.policy ul, .policy ol { margin: 0 0 1rem; padding-left: 1.3rem; }
.policy li { margin-bottom: 0.4rem; }
.policy-address { line-height: 1.7; }
.policy-table-wrap { overflow-x: auto; margin: 0 0 1rem; }
.policy-table { border-collapse: collapse; width: 100%; font-size: 0.92rem; }
.policy-table th, .policy-table td {
    text-align: left; vertical-align: top;
    padding: 0.5rem 0.7rem 0.5rem 0;
    border-bottom: 1px solid var(--rule-soft);
}
.policy-table th { color: var(--evergreen); font-weight: 600; }

.aspect-pick {
    display: flex; flex-direction: column; align-items: center;
    background: none; border: none; padding: 0.3rem; cursor: pointer;
    font-family: var(--font-body); border-radius: var(--radius);
}
.aspect-pick .aspect { transition: transform 0.15s ease, box-shadow 0.15s ease; }
.aspect-pick:hover .aspect { transform: translateY(-2px); }
.aspect-pick { text-decoration: none; }
.aspect-pick:hover .aspect-label { color: var(--evergreen); }
.aspect-pick:focus-visible { outline: 2px solid var(--dusty-plum); outline-offset: 2px; }

/* ── An element's own page ──────────────────────────────────────────────── */
.element-head { text-align: center; }
.element-mark {
    display: grid; place-items: center;
    width: 104px; height: 104px; margin: 0 auto 0.9rem;
    border-radius: 50%; border: 1px solid var(--rule);
}
.element-mark img { width: 100%; height: 100%; object-fit: contain; }
.element-tagline {
    font-size: 0.74rem; letter-spacing: 0.16em; text-transform: uppercase;
    color: var(--ink-soft); margin: 0.2rem 0 0;
}
.element-connects {
    max-width: 32rem; margin: 1.2rem auto 0; text-align: center;
    background: var(--tint-sage); border-radius: var(--radius-pill);
    padding: 0.5rem 1.1rem; font-size: 0.9rem;
}
.element-body { max-width: 30rem; margin: 0 auto; }
.element-body p { margin: 0 0 1rem; }
.element-lead {
    font-family: var(--font-display); font-size: 1.15rem;
    color: var(--evergreen); text-align: center; margin-bottom: 1.2rem !important;
}
.element-others { margin-top: 2.6rem; text-align: center; }
.element-others .aspect-row { margin-top: 0.6rem; }
.element-others .aspect { width: 54px; height: 54px; }
.aspect-source {
    max-width: 32rem; margin: 1.8rem auto 0;
    font-size: 0.9rem; color: var(--ink-soft);
}

.aspect-row {
    display: flex;
    justify-content: center;
    gap: 1.4rem;
    flex-wrap: wrap;
    margin: 2rem 0 0.5rem;
}
.aspect-row > div {
    display: flex;
    flex-direction: column;
    align-items: center;
}

.aspect {
    width: 76px;
    height: 76px;
    border-radius: 50%;
    display: grid;
    place-items: center;
    border: 1px solid var(--rule);
    background: var(--wildflower-white);
    color: var(--evergreen);
}
.aspect svg { width: 34px; height: 34px; }
.aspect img { width: 100%; height: 100%; object-fit: contain; display: block; }

/* The brand board runs its five circular elements across the whole palette
   rather than one colour. The tint carries the hue; the stroke stays evergreen
   so a 1.2px line does not have to survive on a pale colour's contrast. */
.aspect-seed  { background: var(--tint-sage);    border-color: var(--sage); }
.aspect-soil  { background: var(--tint-moss);    border-color: var(--moss-green); }
.aspect-roots { background: var(--tint-heather); border-color: var(--heather); }
.aspect-water { background: var(--tint-lilac);   border-color: var(--heather); }
.aspect-sun   { background: var(--tint-gold);    border-color: var(--soft-gold); }
.aspect-roots, .aspect-water { color: var(--plum-deep); }
.aspect-label {
    display: block;
    text-align: center;
    font-size: 0.68rem;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    color: var(--plum-deep);
    font-weight: 600;
    margin-top: 0.5rem;
}
.aspect-meaning {
    display: block;
    text-align: center;
    font-size: 0.7rem;
    color: var(--ink-soft);
    margin-top: 0.1rem;
}

@media (max-width: 620px) {
    /* The tagline takes its own line rather than being squeezed between the
       element's name and the mark that opens its description -- and goes after
       the mark, so the mark stays up on the name's line instead of being left
       on a line of its own. */
    .element-about .element-tagline { flex-basis: 100%; order: 1; }

    body { font-size: 16px; }
    main { padding: 1.8rem 1.1rem 2.5rem; }
    .card { padding: 1.5rem 1.3rem; }
    .hero h1 { font-size: 2.1rem; }
    .header-inner { justify-content: center; }
    /* Buttons in a form's action row share the width; a card or header
       action keeps its natural size rather than reading as a primary bar. */
    .btn-row .btn { flex: 1 1 auto; }
    /* A smaller button still needs a thumb-sized target on a phone,
       where there is no cursor to aim with. */
    .btn-sm, .btn-xs { min-height: 44px; }
    /* Including the quiet one under a question, which is smaller than
       thumb-sized everywhere there is a cursor to aim with. */
    .facet-line .btn { min-height: 44px; }
}


/* ═══════════════════════════════════════════════════════════════════════════
   Directory — bloom, grid and list over one ordered list (spec §4.2.5).
   The DOM order is join order in every view; only presentation changes.
   ═══════════════════════════════════════════════════════════════════════════ */
main.wide { max-width: 1180px; }
/* The directory has no visible title, so the page starts closer to the
   header and its two control rows sit tighter: the room is for entries. */
main.directory { padding-top: 1.3rem; }
main.directory .preview-head { margin-bottom: 1rem; }

.preview-head { text-align: center; margin-bottom: 1.6rem; }
.preview-head p { max-width: 34rem; margin-inline: auto; }

.viewswitch { display: flex; gap: 0.3rem; padding: 0.25rem;
    background: var(--wildflower-white); border: 1px solid var(--rule-soft);
    border-radius: var(--radius-pill); }
.viewswitch-btn {
    border: none; background: transparent; cursor: pointer;
    font-family: var(--font-body); font-size: 0.8rem; font-weight: 600;
    letter-spacing: 0.1em; text-transform: uppercase; color: var(--ink-soft);
    padding: 0.45rem 1.15rem; border-radius: var(--radius-pill);
    transition: background 0.15s ease, color 0.15s ease;
}
.viewswitch-btn:hover { color: var(--evergreen); }
.viewswitch-btn.is-active { background: var(--dusty-plum); color: var(--wildflower-white); }

/* ── Directory search ───────────────────────────────────────────────────── */
.searchbar { display: flex; justify-content: center; }
.searchbar input { width: min(380px, 40vw); }
.sr-only {
    position: absolute; width: 1px; height: 1px; padding: 0;
    margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* The signup honeypot (§4.4): off-screen rather than display:none, which some
   scripts know to skip. aria-hidden and tabindex keep people out of it. */
.hp { position: absolute; left: -10000px; width: 1px; height: 1px; overflow: hidden; }
.dir-showing { text-align: center; font-size: 0.85rem; color: var(--ink-soft); margin: 1rem 0 0; }
.dir-empty { text-align: center; color: var(--ink-soft); padding: 3rem 1rem; }
.demo-banner {
    background: var(--tint-gold); border: 1px solid var(--soft-gold);
    border-radius: var(--radius); padding: 0.7rem 1rem; margin-bottom: 1.2rem;
    font-size: 0.88rem; color: var(--ink);
}
.backlink { font-size: 0.88rem; margin: 0 0 1rem; }
a.entry-btn { text-decoration: none; color: inherit; }

/* ── Filter chips ───────────────────────────────────────────────────────── */
.filterbar {
    display: flex; flex-wrap: wrap; gap: 0.4rem;
    justify-content: center; margin-bottom: 1.4rem;
}
.chip {
    border: 1px solid var(--rule-soft); background: var(--wildflower-white);
    color: var(--ink-soft); cursor: pointer;
    font-family: var(--font-body); font-size: 0.78rem;
    padding: 0.32rem 0.9rem; border-radius: var(--radius-pill);
    transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
}
.chip:hover { color: var(--evergreen); border-color: var(--rule); }
.chip.is-active {
    background: var(--tint-heather); border-color: var(--heather);
    color: var(--plum-deep); font-weight: 600;
}
.chip:focus-visible { outline: 2px solid var(--dusty-plum); outline-offset: 2px; }

/* The reflections filter borrows these: the same gesture deserves the same
   thing to press. As links rather than buttons, because each is a real URL --
   a narrowed view can be kept, and it works with scripting off. */
a.chip {
    display: inline-flex; align-items: center; gap: 0.4rem;
    text-decoration: none;
}
a.chip img { width: 1.15em; height: 1.15em; object-fit: contain; }
a.chip.is-active .nav-mark { stroke: var(--plum-deep); }
.journal-head {
    display: flex; align-items: center; justify-content: space-between;
    gap: 1rem; flex-wrap: wrap; margin-bottom: 0.4rem;
}
.journal-head .label { margin-bottom: 0; }
.filter-rows { margin-bottom: 1.3rem; }
.filter-rows .filterbar { margin-bottom: 0.45rem; }
.filter-rows .filterbar:last-child { margin-bottom: 0; }

.sortpick { display: flex; align-items: center; gap: 0.5rem; }
.sortpick span {
    font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase;
    font-weight: 600; color: var(--plum-deep);
}
.sortpick select { padding: 0.35rem 2.2rem 0.35rem 0.7rem; font-size: 0.86rem; width: auto; }

.dircount-showing { font-size: 0.82rem; color: var(--ink-soft); min-width: 12ch; }

/* The filters column beside the entries (§4.2.5). Everything that narrows
   lives here -- search, the five elements, providers, offerings -- because
   they were three rows above the entries and a column beside them, which put
   four filters in two places. Sort and the view switch stay over the entries:
   they change how the entries are drawn, not which ones there are.

   Sticky, or scrolling a long list leaves the filters behind. */
.dir-body {
    display: grid; grid-template-columns: 13.5rem minmax(0, 1fr);
    gap: 2rem; align-items: start;
}
/* Nothing to filter: an empty directory keeps its full width and says so,
   rather than offering a column of controls that would narrow nothing. */
.dir-body:not(:has(.dir-side)) { grid-template-columns: minmax(0, 1fr); }
.dir-body > .dir-main { min-width: 0; }
/* Sticky against the entries, which is only ever a long list -- when the
   column is the taller of the two there is nothing to stick to, and a little
   scrolling shows all of it anyway. Bounded by the viewport so a short laptop
   cannot cut the bottom of it off. */
.dir-side { margin: 0; position: sticky; top: 1.3rem; }
.dir-side-body { max-height: calc(100vh - 3rem); overflow-y: auto; }
/* On a wide screen it is a column, not a disclosure: the summary is the
   phone's affordance and would be a heading with nothing to do here. */
.dir-side > summary { display: none; }
.dir-side-body {
    display: flex; flex-direction: column; align-items: stretch; gap: 0.55rem;
    /* Room for a focus ring, which an overflow container would clip. */
    padding: 2px; margin: -2px;
}
.dir-side .searchbar { margin: 0; }
.dir-side .field-input { padding: 0.42rem 0.75rem; font-size: 0.86rem; }
.dir-side-group { display: flex; flex-direction: column; align-items: flex-start; gap: 0.3rem; }
.dir-side-group .chip { text-decoration: none; text-align: left; }
.dir-side-group .chip[hidden] { display: none; }
/* Providers is a different axis from the five, so it sits apart from them
   rather than under them as a sixth. */
.dir-side-providers { margin-top: 0.35rem; padding-top: 0.7rem; border-top: 1px solid var(--rule-soft); }
.dir-side-label {
    margin-top: 0.5rem;
    font-size: 0.7rem; letter-spacing: 0.14em; text-transform: uppercase;
    font-weight: 600; color: var(--plum-deep);
}
/* The offerings list is the one that grows without limit, so it keeps a cap
   of its own: the column scrolls as a whole only on a short screen. */
.dir-side-chips { max-height: 17rem; overflow-y: auto; }
/* The row is held whether or not the link is in it: appearing on the first
   press would otherwise shove every chip down as it was being aimed at. */
.dir-clear {
    align-self: flex-start; font-size: 0.78rem; color: var(--plum-deep);
    text-underline-offset: 3px; min-height: 1.15rem;
}
.dir-clear[hidden] { display: block; visibility: hidden; }

/* What is showing, and how it is drawn. The count sits where the page title
   used to be and answers the filters beside it. */
.dir-head {
    display: flex; align-items: baseline; justify-content: space-between;
    gap: 1rem; flex-wrap: wrap; margin-bottom: 1rem; min-height: 2.1rem;
}
.dir-head-controls { display: flex; align-items: center; gap: 1rem; margin-left: auto; }
.dir-head .dir-showing { margin: 0; text-align: left; }

@media (max-width: 899px) {
    /* Stacked, and the filters fold into one closed disclosure: on a phone
       the tools were 618px of a 812px screen before a member appeared. */
    .dir-body { grid-template-columns: 1fr; gap: 0.9rem; }
    .dir-side { position: static; }
    .dir-side-body { max-height: none; overflow: visible; }
    .dir-side > summary {
        display: block; cursor: pointer; list-style: none;
        font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase;
        font-weight: 600; color: var(--plum-deep); padding: 0.4rem 0;
    }
    .dir-side > summary::-webkit-details-marker { display: none; }
    .dir-side > summary::before {
        content: ""; display: inline-block; width: 0.45em; height: 0.45em;
        margin-right: 0.6em; border-right: 1.5px solid currentColor;
        border-bottom: 1.5px solid currentColor;
        transform: rotate(-45deg) translateY(-0.1em);
        transition: transform 0.15s ease;
    }
    .dir-side[open] > summary::before { transform: rotate(45deg) translateY(-0.2em); }
    .dir-side-body { padding-bottom: 0.4rem; }
    .dir-side-chips { max-height: 12rem; }
    /* Open, the chips read as rows rather than a tall column. */
    .dir-side-group { flex-direction: row; flex-wrap: wrap; }
    .dir-head { justify-content: center; gap: 0.5rem; }
    .dir-head .dir-showing { width: 100%; text-align: center; }
    /* Sort and the view switch share one row rather than taking two: at
       375px the pair is 455px as drawn, so the word "Sort" goes (the select
       says what it is) and both give up some padding. */
    .dir-head-controls { margin: 0 auto; gap: 0.5rem; }
    .dir-head-controls .sortpick span {
        position: absolute; width: 1px; height: 1px; padding: 0;
        margin: -1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
    }
    .dir-head-controls .sortpick select { padding: 0.35rem 1.9rem 0.35rem 0.55rem; font-size: 0.8rem; }
    .dir-head-controls .viewswitch-btn { padding: 0.45rem 0.7rem; letter-spacing: 0.06em; }
}

/* The count of what is on, beside "Filters" when the column is folded away. */
.dir-side-count:not(:empty) {
    display: inline-block; margin-left: 0.5em; padding: 0.05em 0.5em;
    border-radius: var(--radius-pill); background: var(--tint-heather);
    letter-spacing: normal;
}

/* The watering can beside a provider's name. Meaning, not decoration, so it
   sits at text size and carries alt text; the same drawing on the Providers
   chip is what makes the chip legible without a label. */
.provider-mark {
    display: inline-block; width: 1.3em; height: 1.3em;
    vertical-align: -0.25em; margin-left: 0.2em; object-fit: contain;
}

/* ── Stage ──────────────────────────────────────────────────────────────── */
.dirstage { list-style: none; margin: 0; padding: 0; }

[data-mode="bloom"] .dirstage {
    position: relative; height: 620px;
    transition: transform 0.35s cubic-bezier(0.2, 0.7, 0.3, 1);
    will-change: transform;
}
/* The stem: a drawn line behind a handful of members, so a short column reads
   as a stem rather than as a narrow list. */
[data-mode="bloom"] .dirstage[data-phase="stem"]::before {
    content: "";
    position: absolute;
    left: 50%; top: 12%; bottom: 12%;
    width: 1px;
    transform: translateX(-0.5px);
    background: linear-gradient(to bottom,
                transparent, var(--rule) 12%, var(--rule) 88%, transparent);
}

[data-mode="bloom"] .entry {
    position: absolute;
    transform: translate(-50%, -50%);
    /* Gentle: atmosphere, not hierarchy. */
    opacity: calc(1 - var(--depth, 0) * 0.28);
    transition: opacity 0.25s ease, filter 0.25s ease;
}
[data-mode="bloom"] .entry-btn { width: var(--size, 46px); height: var(--size, 46px); }
[data-mode="bloom"] .entry-info { display: none; }
[data-mode="bloom"] .entry.is-focused { opacity: 1; z-index: 999 !important; }
[data-mode="bloom"] .entry.is-focused .entry-btn { transform: scale(1.5); }
/* As wide as its content and no wider, up to a measure: a short card stays
   snug under its avatar, and a member with many offerings gets a second line
   rather than a single one that runs off the page. Nowrap did that -- one
   long modalities field made the card wider than the viewport. The measure
   looks small because the card lives inside the button, which the focus
   state scales by 1.5 on top of the stage's 1.28: 13rem here is ~25rem on
   screen. The vw bound keeps it on a phone. */
[data-mode="bloom"] .entry.is-focused .entry-info {
    display: block; position: absolute; left: 50%; top: calc(100% + 0.5rem);
    transform: translateX(-50%);
    width: max-content; max-width: min(13rem, 45vw);
    white-space: normal; text-wrap: balance; text-align: center;
    background: var(--wildflower-white); border: 1px solid var(--rule);
    border-radius: 10px; padding: 0.5rem 0.85rem; box-shadow: var(--shadow-lift);
}
[data-mode="bloom"].is-focusing .entry:not(.is-focused) { filter: blur(0.6px); }

/* ── Grid and list ──────────────────────────────────────────────────────── */
[data-mode="grid"] .dirstage {
    display: grid; gap: 1.1rem;
    grid-template-columns: repeat(auto-fill, minmax(148px, 1fr));
}
[data-mode="grid"] .entry-btn { flex-direction: column; text-align: center; gap: 0.6rem; }

[data-mode="list"] .dirstage { display: flex; flex-direction: column; }
[data-mode="list"] .entry + .entry { border-top: 1px solid var(--rule-soft); }
[data-mode="list"] .entry-btn { gap: 0.9rem; padding: 0.6rem 0.4rem; }
[data-mode="list"] .entry-avatar { width: 38px; height: 38px; }
/* A row, not floated inline text — float let the two collide as soon as
   either ran long. */
[data-mode="list"] .entry-info {
    display: flex; align-items: baseline; gap: 1rem; flex: 1; min-width: 0;
    text-align: left;
}
[data-mode="list"] .entry-name { flex: 0 0 auto; }
[data-mode="list"] .entry-modalities {
    flex: 1; min-width: 0;
    overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* The elements, on the right where "member since" used to be. Icons on
   tinted discs rather than bare, because the icons were drawn to be held by
   a coloured ring and a pale droplet on ivory is invisible at this size. */
[data-mode="list"] .entry-elements {
    display: inline-flex; gap: 0.3rem; flex: 0 0 auto; margin-left: auto;
    align-self: center;
}
.entry-elements { display: none; }
.entry-element {
    display: inline-grid; place-items: center;
    width: 28px; height: 28px; border-radius: 50%;
}
.entry-element img { width: 64%; height: 64%; object-fit: contain; display: block; }

/* ── The entry itself ───────────────────────────────────────────────────── */
.entry { margin: 0; }
.entry-btn {
    display: flex; align-items: center; width: 100%;
    background: none; border: none; padding: 0; cursor: pointer;
    font-family: var(--font-body); color: inherit;
    transition: transform 0.25s cubic-bezier(0.2, 0.7, 0.3, 1);
}
.entry-btn:focus-visible { outline: 2px solid var(--dusty-plum); outline-offset: 4px; border-radius: 50%; }
.entry-avatar {
    display: grid; place-items: center;
    width: 100%; height: 100%; aspect-ratio: 1; flex: none;
    border-radius: 50%; box-shadow: 0 0 0 1px var(--rule);
    color: var(--evergreen);
}
.tint-sage    { background: var(--tint-sage); }
.tint-moss    { background: var(--tint-moss); }
.tint-heather { background: var(--tint-heather); color: var(--plum-deep); }
.tint-lilac   { background: var(--lilac-mist);  color: var(--plum-deep); }
.tint-gold    { background: var(--tint-gold); }
.tint-blush   { background: var(--tint-blush);  color: var(--plum-deep); }

.entry-mark { width: 58%; height: 58%; fill: none; stroke: currentColor;
    stroke-width: 1.2; stroke-linecap: round; stroke-linejoin: round; }
.entry-chars { font-family: var(--font-display); font-size: 0.9em; letter-spacing: 0.03em; }

/* A pattern avatar is the whole disc, so it needs no tint behind it. */
.entry-avatar.is-pattern { background: none; }
.entry-pattern { width: 100%; height: 100%; border-radius: 50%; object-fit: cover; display: block; }

.entry-info { display: block; }
.entry-name { display: block; font-family: var(--font-display);
    font-size: 0.98rem; color: var(--evergreen); }
.entry-modalities { display: block; font-size: 0.82rem; color: var(--ink-soft); }

/* ── The count control ──────────────────────────────────────────────────── */
.dircount {
    display: flex; align-items: center; justify-content: center; gap: 1rem;
    margin-top: 1.8rem; padding-top: 1.4rem; border-top: 1px solid var(--rule-soft);
}
.dircount label { font-size: 0.72rem; letter-spacing: 0.18em;
    text-transform: uppercase; font-weight: 600; color: var(--plum-deep); }
.dircount input[type="range"] { flex: 1; max-width: 460px; accent-color: var(--plum-deep); }
.dircount output { font-family: var(--font-display); font-size: 1.2rem;
    color: var(--evergreen); min-width: 3ch; text-align: right; }

@media (prefers-reduced-motion: reduce) {
    .dirstage, .entry, .entry-btn { transition: none !important; }
}

@media (max-width: 720px) {
    [data-mode="bloom"] .dirstage { height: 420px; }
    .searchbar { width: 100%; }
    .searchbar input { width: 100%; }
}

/* The content screen: five rows, each one an element as it currently reads.
   The element's own mark and name, so the row is recognised the way it is
   everywhere else rather than by a line of text. */
.element-heading-row { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.5rem; }
/* The mark and the heading are both centred where they usually appear, and
   carry the auto margins that do it. In a flex row those absorb the free
   space and push the row apart, so they are cleared here. */
.element-heading-row > * { margin-left: 0; margin-right: 0; }
.element-heading-row .element-mark { flex: none; width: 44px; height: 44px; }
.element-heading-row h1 { margin: 0; }
.element-heading-words { display: flex; flex-direction: column; gap: 0.1rem; }
.content-name { font-family: var(--font-display); font-size: 1.15rem; color: var(--evergreen); }
.content-tagline {
    font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase;
    color: var(--ink-soft);
}
.element-heading-row .btn { margin-left: auto; }

/* What to do with the drawing, above the drawing; and the line under it that
   answers the feeling of an unfinished picture. */
.garden-lede {
    text-align: center; color: var(--ink-soft);
    margin: 0 auto 0.9rem; max-width: 32rem;
}
.garden-reassure { margin-top: 0.5rem; }

/* The bloom's introduction, shown once. Sage like the prompt banner: both are
   an invitation rather than an unfinished task, and neither is an error. */
.bloom-intro {
    max-width: 34rem; margin: 0 auto 1.2rem;
    padding: 1rem 1.25rem; border-radius: var(--radius-card);
    background: var(--sage-wash); border: 1px solid var(--rule-soft);
}
.bloom-intro-lead { font-family: var(--font-display); color: var(--evergreen); }
.bloom-intro-list { margin: 0.6rem 0 0.9rem; padding-left: 1.1rem; }
.bloom-intro-list li { margin-bottom: 0.25rem; }
.bloom-intro-list .nav-mark { vertical-align: -0.15em; }

/* A thumb-sized way in to the small drawings. On a phone the seed is about
   23x36 and the droplets 39x50: fine to look at, under a finger's target to
   press. An invisible pad centred on each reaches 44 in both directions
   without moving the artwork or changing its proportions. The bloom needs
   none of this -- its smallest petal is already 45x46 there. */
@media (max-width: 640px) {
    .mirror-part.is-live::after {
        content: ""; position: absolute; left: 50%; top: 50%;
        transform: translate(-50%, -50%);
        width: max(100%, 44px); height: max(100%, 44px);
    }
}

/* Who is asking. Small and quiet -- it is a provenance note, not a heading:
   which of the two a question is matters, but only once you have read it. */
/* Uppercase and letterspaced, it was half again as wide and pushed the way
   in onto a second line on some rows and not others. A byline reads as a
   byline without shouting. */
.prompt-source {
    font-size: 0.78rem; font-style: italic;
    color: var(--ink-soft); white-space: nowrap;
}
.facet-line .prompt-source { margin-left: 0.2rem; }
/* Setting yourself a question is the other primary action on this page, so it
   sits with the sentence that describes what is waiting rather than in a
   corner. Quiet, because it is an alternative and not a louder path. */
.prompts-mine-action { margin: 0.2rem 0 1.1rem; }
/* Two actions at the end of a row rather than one: only the first takes the
   free space, or they separate to opposite edges. */
.facet-line .mine-edit { margin-left: auto; }
.facet-line .mine-edit + form .btn { margin-left: 0; }

/* The invitation before the writing. The question sits in the same sage block
   it does on the writing page, and the ask below it is a question in the
   page's own voice rather than a heading over one. */
.invite-ask { font-family: var(--font-display); color: var(--evergreen);
              font-size: 1.05rem; margin: 1.1rem 0 0.7rem; }
.invite-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.5rem; }

/* What the application is for, before the essay that says what it means.
   Centred like the rest of the hero, except the list: three lines of ragged
   centre is a shape rather than something to read down. */
/* Space under it as well as over: without it the essay's first line ran
   on from the privacy note as though it were the next sentence. */
.what { margin: 1.6rem auto 2.2rem; }
.what-lead { font-family: var(--font-display); font-size: 1.1rem; color: var(--evergreen);
             margin-top: 1.4rem; }
.what-sub { margin-top: 0.9rem; }
.what-list {
    text-align: left; display: inline-block;
    margin: 1rem 0 0; padding-left: 1.2rem;
}
.what-list li { margin-bottom: 0.35rem; }
.what-privacy {
    margin-top: 1.2rem; padding-top: 1rem;
    border-top: 1px solid var(--rule-soft);
    font-size: 0.92rem; color: var(--ink-soft);
}

/* ═══════════════════════════════════════════════════════════════════════════
   The calendar (§4.7) — the directory's frame, with a month in the space the
   entries take there. Events are heather and gatherings sage, the same pair
   that carries primary and secondary action: the provider's thing and the
   member's thing. No new colours; every value below is a token.
   ═══════════════════════════════════════════════════════════════════════════ */
.cal-side { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }
.cal-side .dir-side { position: static; }
.cal-actions { display: flex; flex-direction: column; gap: 0.5rem; }
.cal-actions .btn { width: 100%; padding-inline: 0.8rem; }
.cal-note { font-size: 0.84rem; color: var(--ink-soft); margin: 0; }
.dir-side-label .provider-mark { width: 1.2em; height: 1.2em; margin: 0 0.35em 0 0; }

.cal-swatch { display: inline-block; width: 0.8em; height: 0.8em; border-radius: 50%; }
.cal-swatch-event { background: var(--heather); }
.cal-swatch-gathering { background: var(--sage); }

.cal-head { align-items: center; }
.cal-month { display: flex; align-items: center; gap: 0.4rem; flex-wrap: wrap; }
.cal-month h2 { margin: 0; min-width: 9.5ch; text-align: center; font-size: 1.5rem; }
.cal-step {
    display: inline-grid; place-items: center; width: 2.2rem; height: 2.2rem;
    border-radius: 50%; text-decoration: none; font-size: 1.4rem; line-height: 1;
    color: var(--plum-deep); border: 1px solid var(--rule-soft);
    background: var(--wildflower-white);
}
.cal-step:hover { background: var(--tint-heather); }
.cal-step.is-off { visibility: hidden; }
.cal-today { font-size: 0.8rem; margin-left: 0.4rem; }
a.viewswitch-btn { text-decoration: none; }

/* The month grid. */
.cal-grid {
    background: var(--wildflower-white); border: 1px solid var(--rule-soft);
    border-radius: var(--radius); box-shadow: var(--shadow); overflow: hidden;
}
.cal-row { display: grid; grid-template-columns: repeat(7, minmax(0, 1fr)); }
.cal-row + .cal-row { border-top: 1px solid var(--rule-soft); }
.cal-weekday {
    padding: 0.55rem 0.6rem; text-align: center;
    font-size: 0.7rem; letter-spacing: 0.16em; text-transform: uppercase;
    font-weight: 600; color: var(--plum-deep); background: var(--gold-wash);
}
.cal-day {
    min-height: 7.2rem; padding: 0.4rem 0.35rem 0.5rem;
    display: flex; flex-direction: column; gap: 0.22rem; min-width: 0;
}
.cal-day + .cal-day { border-left: 1px solid var(--rule-soft); }
.cal-day.is-outside { background: var(--warm-ivory); }
.cal-day.is-outside .cal-date { color: var(--moss-green); }
.cal-date {
    align-self: flex-start; display: inline-grid; place-items: center;
    min-width: 1.75rem; height: 1.75rem; padding: 0 0.3rem; border-radius: var(--radius-pill);
    font-size: 0.82rem; color: var(--ink-soft); font-variant-numeric: tabular-nums;
}
.cal-day.is-today .cal-date { background: var(--dusty-plum); color: var(--wildflower-white); font-weight: 600; }
.cal-day.is-past:not(.is-today) .cal-item { opacity: 0.7; }

.cal-item {
    display: block; padding: 0.2rem 0.45rem; border-radius: 7px;
    font-size: 0.76rem; line-height: 1.3; text-decoration: none; color: var(--ink);
    border-left: 3px solid transparent; overflow-wrap: anywhere;
    transition: box-shadow 0.12s ease, transform 0.12s ease;
}
.cal-item:hover { box-shadow: var(--shadow-lift); transform: translateY(-1px); color: var(--ink); }
.cal-item:focus-visible { outline: 2px solid var(--dusty-plum); outline-offset: 1px; }
.cal-item-event { background: var(--tint-heather); border-left-color: var(--heather); color: var(--plum-deep); }
.cal-item-gathering { background: var(--tint-sage); border-left-color: var(--sage); color: var(--evergreen); }
/* Time over title, and the title allowed two lines: in a column a seventh
   of the page wide, one line held the time and two letters of the name. */
.cal-time { display: block; font-weight: 600; font-size: 0.7rem; font-variant-numeric: tabular-nums; }
.cal-title {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
    line-clamp: 2; overflow: hidden;
}
.cal-item.is-cancelled, .cal-row-link.is-cancelled .cal-row-title { text-decoration: line-through; }
.cal-item.is-cancelled { opacity: 0.6; background: var(--warm-ivory); }

/* The list: a day to a row, the date as a block at the left. */
.cal-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.7rem; }
.cal-list-day {
    display: grid; grid-template-columns: 4.2rem minmax(0, 1fr); gap: 1rem;
    background: var(--wildflower-white); border: 1px solid var(--rule-soft);
    border-radius: var(--radius); box-shadow: var(--shadow); padding: 0.9rem 1.1rem;
}
.cal-list-day.is-past { opacity: 0.72; }
.cal-list-day.is-today { box-shadow: 0 0 0 2px var(--heather), var(--shadow); }
.cal-list-date {
    display: flex; flex-direction: column; align-items: center; justify-content: flex-start;
    border-right: 1px solid var(--rule); padding-right: 0.9rem;
}
.cal-list-weekday {
    font-size: 0.68rem; letter-spacing: 0.16em; text-transform: uppercase;
    font-weight: 600; color: var(--plum-deep);
}
.cal-list-num { font-family: var(--font-display); font-size: 1.9rem; line-height: 1.1; color: var(--evergreen); }
.cal-list-items { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 0.35rem; }
.cal-row-link {
    display: grid; gap: 0.05rem; padding: 0.45rem 0.7rem; border-radius: 10px;
    text-decoration: none; color: var(--ink); border-left: 3px solid transparent;
}
.cal-row-link:hover { background: var(--gold-wash); color: var(--ink); }
.cal-row-event { border-left-color: var(--heather); }
.cal-row-gathering { border-left-color: var(--sage); }
.cal-row-when { font-size: 0.8rem; color: var(--ink-soft); font-variant-numeric: tabular-nums; }
.cal-row-title { font-family: var(--font-display); font-size: 1.1rem; color: var(--evergreen); }
.cal-row-meta { font-size: 0.82rem; color: var(--ink-soft); display: flex; gap: 0.5rem; align-items: center; flex-wrap: wrap; }
.cal-kind {
    padding: 0.05rem 0.55rem; border-radius: var(--radius-pill);
    font-size: 0.66rem; letter-spacing: 0.12em; text-transform: uppercase; font-weight: 600;
}
.cal-kind-event { background: var(--tint-heather); color: var(--plum-deep); }
.cal-kind-gathering { background: var(--tint-sage); color: var(--evergreen); }
.cal-kind-cancelled { background: var(--blush-petal); color: var(--error-ink); }
.cal-foot { margin-top: 1rem; }

/* Which of the two shows. On a phone, always the list: seven columns at
   375px leave a day about fifty pixels, which holds a number and no event. */
.cal-main[data-view="grid"] .cal-list { display: none; }
.cal-main[data-view="list"] .cal-grid { display: none; }
@media (max-width: 719px) {
    .cal-main[data-view] .cal-grid { display: none; }
    .cal-main[data-view] .cal-list { display: flex; }
    .cal-head .viewswitch { display: none; }
    .cal-month { width: 100%; justify-content: center; }
}
@media (max-width: 899px) {
    .cal-actions { flex-direction: row; }
    .cal-actions .btn { width: auto; flex: 1; }
}

/* One event's page. */
.event-page { max-width: 680px; margin-inline: auto; }
.event-card { padding-top: 1.6rem; }
.event-image {
    display: block; width: calc(100% + 4.2rem); max-width: none;
    margin: -1.6rem -2.1rem 1.6rem; max-height: 340px; object-fit: cover;
    border-radius: var(--radius) var(--radius) 0 0;
}
.event-title { margin-bottom: 0.6rem; }
.event-card.is-cancelled .event-title { text-decoration: line-through; text-decoration-color: var(--heather); }
.event-card.is-cancelled .event-image { filter: grayscale(0.7); opacity: 0.8; }
.event-cancelled-note {
    background: var(--blush-petal); color: var(--error-ink); border-radius: 10px;
    padding: 0.6rem 0.9rem; font-weight: 600; font-size: 0.92rem;
}
.event-facts { display: grid; grid-template-columns: auto minmax(0, 1fr); gap: 0.5rem 1.2rem; margin: 1rem 0 0; }
.event-facts dt {
    font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase;
    color: var(--plum-deep); font-weight: 600; padding-top: 0.2rem;
}
.event-facts dd { margin: 0; }
.event-own-time { display: block; font-size: 0.85rem; color: var(--ink-soft); }
.event-element-icon { width: 1.1em; height: 1.1em; vertical-align: -0.2em; margin-right: 0.3em; }
.event-actions form, .event-owner form { margin: 0; }
.event-description { overflow-wrap: anywhere; }
.event-people { margin-top: 1.6rem; display: flex; flex-direction: column; gap: 0.45rem; }
.event-people .dir-side-label:not(:first-child) { margin-top: 0.8rem; }
.event-person-link {
    display: inline-flex; align-items: center; gap: 0.7rem;
    text-decoration: none; color: var(--ink);
}
a.event-person-link:hover span { color: var(--plum-deep); }
.event-person-face { display: block; width: 40px; height: 40px; flex: none; }
.event-person-face .avatar { width: 40px; height: 40px; font-size: 1rem; box-shadow: 0 0 0 1px var(--rule); }
.event-owner { border-top: 1px solid var(--rule-soft); padding-top: 1.2rem; }
.event-when { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 0 1rem; }
/* A datetime input has an intrinsic width wider than half a narrow card. */
.event-when .field-input { min-width: 0; }
/* Matches the narrower card padding below 620px, so the image still meets
   the card's edges. */
@media (max-width: 620px) {
    .event-when { grid-template-columns: 1fr; }
    .event-image { width: calc(100% + 2.6rem); margin-inline: -1.3rem; }
}

/* The events on a profile. */
.profile-events { list-style: none; margin: 0.3rem 0 0; padding: 0; display: flex; flex-direction: column; gap: 0.3rem; }
.profile-events a { text-decoration: none; }
.profile-events .cal-row-when { margin-left: 0.4rem; }
