/* social.css — the network's application shell and surfaces.

   BUILT ONLY FROM TOKENS site.css DEFINES. The first cut used --gray-1,
   --bg-card, --ink-strong and friends, which live in the ENGINE's app.css and
   do not exist here. var() fails silently, so the pages rendered in fallback
   colours belonging to no palette while every test passed. Everything below
   uses: --paper --ground --ground-alt, --ink/-70/-50/-35, --rule --rule-soft,
   --steel --amber --danger, --card-r --gutter, --ease, and the display / sans
   / mono families.

   --card-r is clamp(12px, 1.2vw, 18px) — already the generous, continuous
   corner language this needed, and it was sitting unused while pages
   hardcoded 8px. Using the token is why the geometry stays right when the
   token moves.

   ELEVATION FOLLOWS THE SITE, which is a hairline design: three box-shadows
   in the whole of site.css. Weight comes from rules and ground contrast.
   Shadow is spent only where something genuinely lifts — a menu, a focused
   composer — never as decoration on a resting card. */

/* Interior radii are DERIVED from --card-r rather than picked. A nav item
   inside a card and a menu item inside a menu should be concentric with the
   surface containing them, not a nearby round number — and derived values
   move when the token moves, which is the whole point of having one.
   test_the_rounded_geometry_comes_from_the_token caught four of these. */

/* ═══════════════════════════════════════════════════════════════════════
   SHELL
   ═══════════════════════════════════════════════════════════════════════ */
.app-body { background: var(--ground); min-height: 100vh; min-height: 100dvh; }

.app-top {
    position: sticky; top: 0; z-index: 40;
    background: color-mix(in srgb, var(--paper) 88%, transparent);
    -webkit-backdrop-filter: saturate(140%) blur(10px);
    backdrop-filter: saturate(140%) blur(10px);
    border-bottom: 1px solid var(--rule);
}
.app-top__in {
    width: 100%; box-sizing: border-box;
    max-width: 1180px; margin: 0 auto;
    padding: 0 clamp(14px, 2.4vw, 28px);
    height: 58px; display: flex; align-items: center; gap: clamp(10px, 2vw, 22px);
}
.app-brand { display: flex; align-items: center; gap: 9px; text-decoration: none; color: var(--ink); flex: 0 0 auto; }
/* site.css's global a:hover underlines every link; the wordmark is a logo,
   not body text, so it must opt out on hover as well as at rest. */
.app-brand:hover { text-decoration: none; color: var(--ink); }
/* The mark was 34px against a 58px bar and read as a decoration someone had
   left in the corner rather than the product's name. It is the only brand on
   this page — the network has no hero and no masthead — so it carries the
   whole identity and is sized to say so. */
.app-brand svg { width: 46px; height: 23px; color: var(--steel); }
.app-brand__txt { font-family: var(--display); font-weight: var(--display-w); font-size: 21px; font-style: italic; }
.app-brand__txt em { font-style: italic; font-weight: 700; color: var(--steel); }

/* Search sits in the bar because finding a person is the second thing anyone
   does here, after reading. On a phone it is what the bar is FOR: the
   destinations move to the bottom tabs and search takes the width. */
.app-search { flex: 1 1 auto; max-width: 340px; position: relative; }
.app-search input {
    width: 100%; height: 36px;
    border: 1px solid var(--rule); border-radius: 999px;
    background: var(--ground); color: var(--ink);
    padding: 0 14px 0 36px; font: inherit; font-size: 14px;
    transition: border-color 160ms var(--ease), background-color 160ms var(--ease);
}
.app-search input:focus { border-color: var(--steel); background: var(--paper); outline: none; }
.app-search__icon { position: absolute; left: 11px; top: 50%; transform: translateY(-50%); color: var(--ink-35); pointer-events: none; display: flex; }
.app-search__out {
    position: absolute; top: calc(100% + 8px); left: 0; right: 0; z-index: 50;
    background: var(--paper); border: 1px solid var(--rule); border-radius: var(--card-r);
    box-shadow: 0 14px 38px rgba(25, 32, 37, .13); overflow: hidden;
}
.app-search__out:empty { display: none; }

.app-nav { margin-left: auto; display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }
.app-nav__i {
    display: flex; flex-direction: column; align-items: center; gap: 3px;
    min-width: 62px; min-height: 44px; justify-content: center;
    padding: 4px 8px; border-radius: calc(var(--card-r) * .6);
    color: var(--ink-50); text-decoration: none;
    font: 500 10.5px/1 var(--sans); letter-spacing: .02em;
    transition: color 160ms var(--ease), background-color 160ms var(--ease);
}
.app-nav__i:hover { color: var(--ink); background: var(--ground-alt); text-decoration: none; }
.app-nav__i[aria-current="page"] { color: var(--ink); }
.app-nav__i[aria-current="page"] svg { color: var(--steel); }

/* ═══════════════════════════════════════════════════════════════════════
   THREE COLUMNS
   ═══════════════════════════════════════════════════════════════════════ */
/* site.css lays body out as a flex column. In a flex column an item with
   auto margins is sized to its content, so the grid shrank to whatever the
   stream happened to hold — the feed looked right only because long posts
   pushed it to the max. Ask for the width outright. */
.app {
    width: 100%; box-sizing: border-box;
    max-width: 1180px; margin: 0 auto;
    padding: clamp(16px, 2.4vw, 26px) clamp(14px, 2.4vw, 28px) 96px;
    display: grid; gap: clamp(14px, 1.8vw, 24px);
    grid-template-columns: 232px minmax(0, 1fr) 286px;
    align-items: start;
}
.rail, .aside { position: sticky; top: 74px; display: grid; grid-template-columns: minmax(0, 1fr); gap: 14px; min-width: 0; }
@media (max-width: 1080px) {
    .app { grid-template-columns: 208px minmax(0, 1fr); }
    .aside { display: none; }
}
@media (max-width: 760px) {
    .app { grid-template-columns: minmax(0, 1fr); padding-bottom: calc(96px + env(safe-area-inset-bottom, 0px)); }
    .rail { display: none; }
    .app-nav { display: none; }
    .app-search { max-width: none; }
    .app-brand__txt { display: none; }
}
/* Two-column surfaces: Messages needs the width for a chat pane, and People
   is already a page of people — a "people to follow" rail beside it repeated
   the main column. */
.app--wide { grid-template-columns: 232px minmax(0, 1fr); }
@media (max-width: 1080px) { .app--wide { grid-template-columns: 208px minmax(0, 1fr); } }
@media (max-width: 760px)  { .app--wide { grid-template-columns: minmax(0, 1fr); } }

/* ═══════════════════════════════════════════════════════════════════════
   SURFACES
   ═══════════════════════════════════════════════════════════════════════ */
.surface { background: var(--paper); border: 1px solid var(--rule); border-radius: var(--card-r); }
.surface__pad { padding: clamp(13px, 1.7vw, 17px); }
.surface__head {
    padding: 12px clamp(13px, 1.7vw, 17px);
    border-bottom: 1px solid var(--rule-soft);
    font: 500 11px/1 var(--mono); letter-spacing: .14em; text-transform: uppercase; color: var(--ink-50);
}

/* ── rail: your card + the engine ─────────────────────────────────────── */
.me-card { text-align: center; padding: 18px 14px 14px; }
.me-card__link { display: block; color: inherit; text-decoration: none; }
.me-card__link:hover { text-decoration: none; }
.me-card__link:hover .me-card__name { color: var(--steel); }
.me-card__name { font-weight: 600; font-size: 15px; margin: 10px 0 0; display: flex; align-items: center; justify-content: center; gap: 2px; transition: color 160ms var(--ease); }
.me-card__head { font-size: 12.5px; color: var(--ink-50); margin: 3px 0 0; }
.me-card__stats { display: flex; justify-content: center; gap: 18px; margin: 12px 0 0; padding-top: 12px; border-top: 1px solid var(--rule-soft); font-size: 12.5px; color: var(--ink-50); }
.me-card__stats b { color: var(--ink); font-variant-numeric: tabular-nums; }

.rail-engine {
    display: flex; align-items: center; gap: 11px;
    padding: 12px 14px; color: var(--ink); text-decoration: none;
    transition: border-color 160ms var(--ease), background-color 160ms var(--ease);
}
.rail-engine:hover { border-color: var(--steel); text-decoration: none; }
.rail-engine > svg:first-child { color: var(--steel); flex: 0 0 auto; }
.rail-engine > svg:last-child { color: var(--ink-35); margin-left: auto; flex: 0 0 auto; }
.rail-engine span { display: flex; flex-direction: column; min-width: 0; }
.rail-engine b { font-weight: 600; font-size: 14px; }
.rail-engine small { font-size: 12px; color: var(--ink-50); line-height: 1.35; }

/* ── bottom bar, small screens only ───────────────────────────────────── */
/* A floating capsule, not a bar welded to the bottom edge: inset from the
   sides, lifted off the safe area, frosted over whatever scrolls beneath it,
   the current tab sitting in its own pill. The device iOS has settled on,
   and it makes the bar read as a control rather than as the end of the
   page. */
.app-tabs { display: none; }
@media (max-width: 760px) {
    .app-tabs {
        position: fixed; left: 0; right: 0; z-index: 45;
        bottom: calc(12px + env(safe-area-inset-bottom, 0px));
        width: min(100% - 28px, 400px); margin: 0 auto;
        display: flex; padding: 5px;
        background: color-mix(in srgb, var(--paper) 78%, transparent);
        -webkit-backdrop-filter: saturate(160%) blur(18px);
        backdrop-filter: saturate(160%) blur(18px);
        border: 1px solid color-mix(in srgb, var(--rule) 75%, transparent);
        border-radius: 999px;
        box-shadow: 0 12px 32px rgba(25, 32, 37, .16), inset 0 1px 0 rgba(255, 255, 255, .55);
    }
    .app-tabs a {
        flex: 1 1 0; min-height: 50px; border-radius: 999px;
        display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 3px;
        color: var(--ink-50); text-decoration: none; font: 500 10px/1 var(--sans);
        transition: background-color 160ms var(--ease), color 160ms var(--ease);
    }
    .app-tabs a[aria-current="page"] { color: var(--ink); background: color-mix(in srgb, var(--ink) 7%, transparent); }
    .app-tabs a[aria-current="page"] svg { color: var(--steel); }
}

/* ═══════════════════════════════════════════════════════════════════════
   TYPE
   ═══════════════════════════════════════════════════════════════════════ */
.s-eyebrow { font: 500 11px/1 var(--mono); letter-spacing: .16em; text-transform: uppercase; color: var(--ink-50); margin: 0 0 9px; }
.s-title { font-family: var(--display); font-weight: var(--display-w); font-size: var(--d-4); line-height: 1.12; margin: 0; text-wrap: balance; }
.s-title--tight { margin-bottom: 14px; }
.s-status { font-size: 13.5px; color: var(--ink-70); min-height: 1.3em; margin: 10px 0 0; }
.s-status[data-kind="error"] { color: var(--danger); }

/* ═══════════════════════════════════════════════════════════════════════
   CONTROLS
   ═══════════════════════════════════════════════════════════════════════ */
/* site.css's .btn is a landing-page call to action: 15px of padding and
   .14em of tracking, meant to appear once. A feed has a dozen buttons on
   screen. .btn--sm is the site's own smaller cut; these give it a hit box
   and a third, resting state — "Following", which is neither a call to
   action nor an outline inviting a click. */
.btn.btn--sm { min-height: 36px; padding: 0 16px; }
.btn.btn--quiet { background: var(--ground-alt); color: var(--ink-50); border-color: transparent; }
.btn.btn--quiet:hover { background: var(--ground-alt); color: var(--ink); border-color: var(--rule); }
/* the button gives a little under the press — the same tactile scale the row
   of reactions uses, so every pressable thing on the network answers alike */
.btn { transition: transform 120ms var(--ease), background-color 160ms var(--ease), color 160ms var(--ease), border-color 160ms var(--ease); }
.btn:active { transform: scale(.97); }

.field { position: relative; margin-bottom: 14px; }
.field input {
    width: 100%; min-height: 44px;
    border: 1px solid var(--rule); border-radius: 999px;
    padding: 10px 16px; font: inherit; font-size: 15px;
    background: var(--paper); color: var(--ink);
    transition: border-color 160ms var(--ease);
}
.field input:focus { border-color: var(--steel); outline: none; }
.field--search input { padding-left: 42px; }
.field--search > svg { position: absolute; left: 15px; top: 50%; transform: translateY(-50%); color: var(--ink-35); pointer-events: none; }

/* ═══════════════════════════════════════════════════════════════════════
   BADGE + AVATAR
   ═══════════════════════════════════════════════════════════════════════ */
/* Gold check, Instagram's shape. The tick is INK: --amber is a light yellow
   and a white tick on it is close to invisible at this size — it read as an
   unexplained gold dot, which invites a worse guess than a legible mark. */
/* 1.18em, not 1em. At the name's own size the seal sat inside the x-height and
   read as punctuation; a badge has to be legible as a shape at a glance or it
   is just a coloured dot after someone's name. */
.sv-badge { display: inline-flex; width: 1.18em; height: 1.18em; vertical-align: -.18em; margin-left: 5px; flex: 0 0 auto; }
.sv-badge svg { width: 100%; height: 100%; fill: var(--amber); }
/* No outline on the seal — tried, and it read as cheap. The tick is the
   site's blue: the two brand colours on one mark, and it stays legible on
   gold where an ink tick was heavy. */
.sv-badge__tick { stroke: var(--steel); }

/* Monogram on a deterministic hue — the device Mission Control already uses
   for saved work, so a person and their project are identified the same way
   rather than by two unrelated systems. */
.av { flex: 0 0 auto; width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; font: 600 15px/1 var(--sans); color: var(--ink); border: 1px solid var(--rule); user-select: none; overflow: hidden; }
.av--sm { width: 32px; height: 32px; font-size: 12px; }
.av--lg { width: 68px; height: 68px; font-size: 24px; margin: 0 auto; }
.av__img { width: 100%; height: 100%; min-width:0; min-height:0; object-fit: cover; display: block; }
/* On the navigation the mark replaces a 20px glyph, so it matches the glyph's
   box rather than the 32px disc used in a list of people. */
.av--nav { width: 22px; height: 22px; font-size: 10px; }

/* ═══════════════════════════════════════════════════════════════════════
   COMPOSER
   ═══════════════════════════════════════════════════════════════════════ */
/* The composer is a WELL, not a card. Posts are paper cards on the ground;
   the place you write is a recess in that ground with a paper field set into
   it — a different object at a glance. At rest it is one pill; it opens into
   a writing surface when touched, and sits a clear step above the feed. */
.composer {
    margin: 0 0 22px; padding: 12px;
    background: var(--ground-alt); border: 0; border-radius: var(--card-r);
}
.composer__row1 { display: flex; gap: 10px; align-items: center; }
.composer.is-open .composer__row1 { align-items: flex-start; }
.composer__field {
    flex: 1 1 auto; width: 100%; resize: none;
    min-height: 44px; max-height: 60vh; overflow-y: auto;
    border: 1px solid var(--rule); border-radius: 999px;
    padding: 10px 18px; background: var(--paper); color: var(--ink);
    font: inherit; font-size: 15.5px; line-height: 1.5; outline: none;
    transition: border-color 160ms var(--ease), border-radius 160ms var(--ease);
}
.composer__field::placeholder { color: var(--ink-50); }
.composer:not(.is-open) .composer__field { overflow: hidden; white-space: nowrap; }
.composer__field:focus { border-color: var(--ink-35); }
.composer.is-open .composer__field { border-radius: calc(var(--card-r) * .7); min-height: 96px; padding: 12px 14px; }
.composer:not(.is-open) .composer__bar,
.composer:not(.is-open) #drafts { display: none; }
.composer__bar { display: flex; align-items: center; gap: 8px; margin-top: 10px; }
.composer__spacer { flex: 1 1 auto; }
.composer__hint { font-size: 13px; color: var(--ink-50); }
@media (max-width: 480px) { .composer__hint { display: none; } }

/* The plus. One affordance for every kind of attachment, rather than a
   single "Attach a project" button that told researchers this network was
   only for TuringDNA work. */
.plus {
    width: 40px; height: 40px; flex: 0 0 auto;
    display: grid; place-items: center;
    border: 1px solid var(--rule); border-radius: 50%;
    background: var(--paper); color: var(--ink-70); cursor: pointer;
    transition: transform 180ms var(--ease), background-color 160ms var(--ease), color 160ms var(--ease), border-color 160ms var(--ease);
}
.plus:hover { background: var(--ground-alt); color: var(--ink); border-color: var(--ink-35); }
.plus[aria-expanded="true"] { background: var(--ink); color: var(--paper); border-color: var(--ink); transform: rotate(45deg); }

/* ── attachment drafts ────────────────────────────────────────────────── */
.draft { margin-top: 10px; border: 1px solid var(--rule); border-radius: calc(var(--card-r) * .7); overflow: hidden; background: var(--paper); }
.draft__head { display: flex; align-items: center; gap: 8px; padding: 9px 12px; border-bottom: 1px solid var(--rule-soft); font: 500 11px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-50); }
.draft__x { margin-left: auto; }
.draft__body { padding: 12px; display: grid; gap: 8px; }
.draft__body input { min-height: 44px; border: 1px solid var(--rule); border-radius: calc(var(--card-r) * .55); padding: 10px 12px; font: inherit; font-size: 15px; background: var(--paper); color: var(--ink); transition: border-color 160ms var(--ease); }
.draft__body input:focus { border-color: var(--steel); outline: none; }
.draft__grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 8px; }
.draft__img { display: block; width: 100%; max-height: 320px; object-fit: cover; }
/* The preview is the shape the post will be, so nobody finds out after
   uploading that their clip sits in a letterbox. */
.draft__vid { width: min(100%, 190px); aspect-ratio: 9 / 16; margin: 0 auto; display: grid; place-items: center; background: var(--ground-alt); border-radius: calc(var(--card-r) * .55); overflow: hidden; }
.draft__vid video { width: 100%; height: 100%; object-fit: contain; display: block; }

/* ═══════════════════════════════════════════════════════════════════════
   POSTS
   ═══════════════════════════════════════════════════════════════════════ */
.post { margin-bottom: 12px; }
.post__top { display: flex; align-items: flex-start; gap: 12px; }
.post__who { flex: 1 1 auto; min-width: 0; }
.post__name { font-weight: 600; font-size: 15px; color: var(--ink); text-decoration: none; display: inline-flex; align-items: center; }
.post__name:hover { color: var(--steel); text-decoration: none; }
.post__meta { font-size: 12.5px; color: var(--ink-50); margin: 1px 0 0; }
/* 15.5px, the composer's size: a feed is read at the size it is written,
   and the site's 17px reading measure made every post look like an
   article. */
.post__body { margin: 12px 0 0; font-size: 15.5px; line-height: 1.55; white-space: pre-wrap; overflow-wrap: anywhere; }
.post__body--lead { margin-top: 0; }
/* Retracted long post: clamped to a preview, cleanly at a line boundary with
   an ellipsis. -webkit-box is the only cross-browser line-clamp, and it still
   honours the pre-wrap newlines above. "See more" (JS) drops the class. */
.post__body--clamp {
    display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 8;
    overflow: hidden;
}
.post__more {
    margin: 5px 0 0; padding: 0; border: 0; background: none;
    color: var(--steel); font: 600 14px/1.2 var(--sans); cursor: pointer;
}
.post__more:hover { text-decoration: underline; }
.post__more:active { opacity: .7; }
.post__meta--foot { margin-top: 12px; }
.post__reposted { font-size: 12.5px; color: var(--ink-50); margin: 0 0 11px; display: flex; align-items: center; gap: 6px; }
.post__reposted a { color: var(--ink-70); font-weight: 600; text-decoration: none; }
.post__reposted a:hover { color: var(--steel); text-decoration: none; }
.post__reposted svg { color: var(--ink-35); }

.post__img { margin: 13px -1px 0; border-top: 1px solid var(--rule-soft); border-bottom: 1px solid var(--rule-soft); background: var(--ground-alt); }
.post__img img { display: block; width: 100%; max-height: 520px; object-fit: contain; }

/* Vertical video in a horizontal column. The frame is the phone's shape and a
   fixed size, not the column's — a full-bleed 9:16 in a 600px stream is one
   post per screen and a feed nobody scrolls. Letterboxed on --ground-alt so a
   clip that is not exactly 9:16 is framed rather than stretched, and the box
   is reserved before the metadata loads so arriving video does not shove the
   rest of the feed down the page. */
.post__vid {
    margin: 13px auto 0; width: min(100%, 300px); aspect-ratio: 9 / 16;
    display: grid; place-items: center;
    background: var(--ground-alt);
    border: 1px solid var(--rule-soft);
    border-radius: calc(var(--card-r) * .7);
    overflow: hidden;
}
/* Fills the frame rather than sitting at its natural size inside it: a clip
   smaller than the frame would otherwise float in the middle of a grey box.
   `contain` keeps a clip that is not exactly 9:16 letterboxed, not cropped. */
.post__vid video { display: block; width: 100%; height: 100%; object-fit: contain; }

/* A link is judged by its domain, so the domain leads. */
.lcard { display: flex; gap: 11px; align-items: center; margin-top: 13px; padding: 12px 14px; border: 1px solid var(--rule-soft); border-radius: var(--card-r); background: var(--ground-alt); color: var(--ink); text-decoration: none; transition: border-color 160ms var(--ease); }
.lcard:hover { border-color: var(--steel); text-decoration: none; }
.lcard svg { flex: 0 0 auto; color: var(--steel); }
.lcard__c { min-width: 0; }
.lcard__t { font-weight: 600; font-size: 15px; line-height: 1.4; margin: 0; overflow-wrap: anywhere; }
.lcard__d { font: 500 11.5px/1.4 var(--mono); color: var(--ink-50); margin: 2px 0 0; }

/* The project card. Metadata only — 0032 gives a post no path to a sequence. */
.pcard { margin-top: 13px; padding: 12px 14px; border: 1px solid var(--rule-soft); border-left: 3px solid var(--steel); border-radius: 0 var(--card-r) var(--card-r) 0; background: var(--ground-alt); }
.pcard__name { font-weight: 600; font-size: 15px; margin: 0; display: flex; align-items: center; gap: 7px; }
.pcard__name svg { color: var(--steel); }
.pcard__meta { display: flex; flex-wrap: wrap; gap: 4px 14px; margin: 5px 0 0; font: 500 11.5px/1.5 var(--mono); letter-spacing: .04em; color: var(--ink-50); }

/* ═══════════════════════════════════════════════════════════════════════
   ACTIONS
   ═══════════════════════════════════════════════════════════════════════ */
.acts { display: flex; align-items: center; gap: 3px; margin-top: 8px; }
.act {
    /* 44px is the accessibility floor, but a pill that tall looks clumsy
       beside 13px type — so the visual height stays 36px and ::after grows
       the hit box, the same trick the engine's tab strip uses. */
    position: relative; min-height: 36px;
    display: inline-flex; align-items: center; gap: 7px;
    border: 0; background: none; color: var(--ink-50);
    font: 500 13px/1 var(--sans); padding: 0 9px; border-radius: 999px; cursor: pointer;
    transition: background-color 160ms var(--ease), color 160ms var(--ease), transform 120ms var(--ease);
}
.act::after { content: ''; position: absolute; inset: -4px 0; }
.act svg { width: 23px; height: 23px; }
.act:hover { background: var(--ground-alt); color: var(--ink); }
.act:active { transform: scale(.96); }
.act__n { font-variant-numeric: tabular-nums; }
/* Per-ROLE, never on the bare attribute: aria-pressed is correct on any
   toggle, and colouring it painted the composer's own button danger-red. */
.act--like[aria-pressed="true"] { color: var(--danger); }
.act--like[aria-pressed="true"] svg { fill: var(--danger); stroke: var(--danger); }
.act--spacer { margin-left: auto; }
/* Views are a number, not a control. Same row and same type as the buttons
   beside them, but pressing one would do nothing — so it must not offer a hit
   box, a hover state or a pointer. */
.act--stat { cursor: default; padding-right: 2px; }
.act--stat::after { content: none; }

/* Reactions — the control that replaces the heart: a tappable character plus a
   hold/hover picker, and a small per-type count breakdown. See mountReaction. */
.rx { position: relative; display: inline-flex; align-items: center; gap: 5px; }
.rx__btn { display: inline-flex; align-items: center; padding: 3px; }
/* Beat `.acts .act svg { width:24px }` (0,2,1) — the reaction button lives in
   the .acts row, so its icon needs a more specific rule or it stays tiny. */
.rx .rx__btn .rx-svg { display: block; width: 34px; height: 34px; transition: transform .12s ease, filter .12s ease; }
.rx__btn:active .rx-svg { transform: scale(.9); }
.rx__btn--empty .rx-svg { opacity: .6; }     /* haven't reacted: a faded — but still colour-coded — prompt, so it stays legible on a dark theme */
.rx__btn.is-on .rx-svg { filter: none; opacity: 1; }
.rx__counts { display: inline-flex; align-items: center; gap: 8px; }
.rx__chip { display: inline-flex; align-items: center; gap: 3px; color: var(--ink-50); font-size: 14.5px; font-weight: 600; font-variant-numeric: tabular-nums; }
.rx__chip.is-mine { color: var(--ink); }
.rx__chip .rx-svg { display: block; width: 23px; height: 23px; }
.rx-pick { position: absolute; bottom: calc(100% + 8px); left: -8px; z-index: 40; width: max-content;
           display: flex; gap: 4px; padding: 6px; background: var(--paper);
           border: 1px solid var(--rule); border-radius: 999px; box-shadow: 0 12px 32px rgba(0,0,0,.18); }
.rx-pick__b { flex: 0 0 auto; }   /* never let the narrow anchor shrink the choices */
.rx-pick__b { border: 0; background: none; padding: 4px; border-radius: 50%; cursor: pointer; line-height: 0;
              transition: transform .13s ease, background .13s ease; }
.rx-pick__b .rx-svg { display: block; width: 50px; height: 50px; }
.rx-pick__b:hover, .rx-pick__b.is-on { background: var(--ground-alt); transform: scale(1.15) translateY(-2px); }
@media (prefers-reduced-motion: reduce) { .rx-pick__b, .rx__btn .rx-svg { transition: none; } }

/* ── the characters inside a message ───────────────────────────────────────
   A drawing standing in for a word, so it is sized in em and sits on the text
   baseline — fixed pixels would stop tracking the bubble's font size and float
   off the line the moment anything else changes. */
.rx-inline { display: inline-block; vertical-align: -.32em; width: 1.4em; height: 1.4em; margin: 0 .04em; }
/* A message that is ONLY characters is a reaction, not a sentence: give them
   room rather than rendering three 20px drawings in a bubble sized for text.
   The class is set in messageBodyNodes, not matched with `:only-child` — that
   selector counts elements and cannot see the text node beside the drawing. */
.rx-inline--solo { width: 2.4em; height: 2.4em; vertical-align: -.7em; }
.bubble blockquote .rx-inline { width: 1.15em; height: 1.15em; vertical-align: -.25em; }

/* The composer's character row. Sits above the input rather than inside it:
   the input is already crowded on a phone, and a row that pushes the text
   field narrower is the thing people complain about. */
.dm-chars { display: flex; gap: 6px; padding: 6px 10px 0; }
.dm-chars__b { flex: 0 0 auto; border: 0; background: none; padding: 4px; border-radius: 50%;
               cursor: pointer; line-height: 0; transition: transform .13s ease, background .13s ease; }
.dm-chars__b:hover { background: var(--ground-alt); transform: scale(1.12) translateY(-1px); }
.dm-chars__b .rx-svg { display: block; width: 26px; height: 26px; }
@media (prefers-reduced-motion: reduce) { .dm-chars__b { transition: none; } }

/* ── the characters are alive ──────────────────────────────────────────────
   All four move. They were stills, and a still cell is a drawing of a cell.

   Animated with TRANSFORMS on groups, never by morphing path data. Morphing
   would need SMIL, and SMIL cannot be switched off from CSS — a reduced-motion
   reader would be stuck with four crawling creatures and no way to stop them.

   Each character gets a wrapper (.rx-ch--<type>, added by reactionIcon) so the
   whole creature can move, plus classes on the parts that move independently.
   Durations inside one character are deliberately non-multiples so the parts
   fall out of phase and the loop never resolves into an obvious beat — except
   the phage's legs, which share the hop's duration on purpose, because legs
   that flex out of time with the landing read as broken rather than as alive.

   transform-box + transform-origin are required on every animated group: an
   SVG child transforms about the VIEWBOX origin by default, so without them a
   creature pivots around the corner of the canvas and swings out of frame.
   That looks fine in a still screenshot and wrong the moment it moves. */
.rx-svg .rx-ch, .rx-svg .am-body, .rx-svg .am-eyes, .rx-svg .am-nucleus,
.rx-svg .am-vacuole, .rx-svg .ec-flag, .rx-svg .ec-pili, .rx-svg .sa-spikes,
.rx-svg .ph-legs {
  transform-box: fill-box;
  transform-origin: center;
  will-change: transform;
}

/* AMOEBA — crawls. The body squishes, the vacuole reaches, the nucleus drifts
   on the cytoplasmic streaming, and the hearts beat faster than any of it.
   The wrapper stays still: four parts already move, and moving the whole thing
   as well reads as a wobbling sticker rather than a cell. */
.rx-svg .am-body    { animation: am-squish 2.8s ease-in-out infinite; }
.rx-svg .am-vacuole { animation: am-reach  3.4s ease-in-out infinite; }
.rx-svg .am-nucleus { animation: am-drift  4.6s ease-in-out infinite; }
.rx-svg .am-eyes    { animation: am-beat   2.2s ease-in-out infinite; }

/* E. COLI — swims. Peritrichous flagella bundle and whip, which is what
   actually propels it, so the body's roll follows the whip rather than
   leading it. */
.rx-svg .rx-ch--ecoli { animation: ec-swim 3.1s ease-in-out infinite; }
.rx-svg .ec-flag      { animation: ec-whip 1.7s ease-in-out infinite; }
.rx-svg .ec-pili      { animation: ec-fuzz 2.6s ease-in-out infinite; }

/* CORONAVIRUS — sad, so it SIGHS rather than bounces.
   The first version moved it 2px over four seconds, which at 34px is under
   half a pixel of travel: technically animated, visibly a still. Being the
   sad one is a reason to move slowly and heavily, not imperceptibly.
   So: a real droop with a hang at the bottom, a slow head-shake, and spikes
   that deflate on the way down — the shape of a sigh. Still the slowest and
   least springy of the four, which is the characterisation; it is just
   actually visible now. */
.rx-svg .rx-ch--sars { animation: sa-sigh  3.6s ease-in-out infinite; }
.rx-svg .sa-spikes   { animation: sa-pulse 2.3s ease-in-out infinite; }

/* PHAGE — a lander. It hops, and the legs flex on the landing, so they share
   the hop's 2.9s exactly. */
.rx-svg .rx-ch--phage { animation: ph-hop  2.9s cubic-bezier(.4,0,.5,1) infinite; }
.rx-svg .ph-legs      { animation: ph-flex 2.9s cubic-bezier(.4,0,.5,1) infinite; }

@keyframes am-squish {
  0%, 100% { transform: scale(1, 1) rotate(0deg); }
  25%      { transform: scale(1.06, 0.95) rotate(-2.5deg); }
  50%      { transform: scale(0.96, 1.05) rotate(0deg); }
  75%      { transform: scale(1.04, 0.97) rotate(2.5deg); }
}
@keyframes am-reach {
  0%, 100% { transform: scale(1, 1) translate(0, 0); }
  30%      { transform: scale(1.18, 0.9) translate(-1.5px, 0); }
  65%      { transform: scale(0.88, 1.14) translate(1px, 1px); }
}
@keyframes am-drift {
  0%, 100% { transform: translate(0, 0); }
  33%      { transform: translate(-3px, 2px); }
  66%      { transform: translate(2px, -3px); }
}
@keyframes am-beat {
  0%, 100%  { transform: scale(1); }
  14%       { transform: scale(1.14); }
  28%       { transform: scale(1); }
  42%       { transform: scale(1.09); }
  56%       { transform: scale(1); }
}
@keyframes ec-swim {
  0%, 100% { transform: translate(0, 0) rotate(0deg); }
  30%      { transform: translate(1px, -1.5px) rotate(2.5deg); }
  70%      { transform: translate(-1px, 1.5px) rotate(-2.5deg); }
}
@keyframes ec-whip {
  0%, 100% { transform: skewX(0deg) scaleY(1); }
  25%      { transform: skewX(5deg) scaleY(1.05); }
  75%      { transform: skewX(-5deg) scaleY(0.95); }
}
@keyframes ec-fuzz {
  0%, 100% { transform: scale(1); }
  50%      { transform: scale(1.05); }
}
@keyframes sa-sigh {
  0%       { transform: translateY(-1px) rotate(-4deg) scale(1); }
  30%      { transform: translateY(3px)  rotate(2deg)  scale(0.96, 1.04); }
  /* The hang. A sigh is mostly the pause at the bottom of it. */
  55%      { transform: translateY(3.5px) rotate(3deg) scale(0.95, 1.05); }
  78%      { transform: translateY(-0.5px) rotate(-2deg) scale(1.03, 0.97); }
  100%     { transform: translateY(-1px) rotate(-4deg) scale(1); }
}
@keyframes sa-pulse {
  0%, 100% { transform: scale(1.06); }
  40%      { transform: scale(0.9); }   /* deflate */
  70%      { transform: scale(1.02); }
}
@keyframes ph-hop {
  0%, 62%, 100% { transform: translateY(0) scale(1, 1); }
  70%           { transform: translateY(1.5px) scale(1.06, 0.92); }  /* crouch */
  82%           { transform: translateY(-4px) scale(0.96, 1.06); }   /* up */
  92%           { transform: translateY(0) scale(1.04, 0.95); }      /* land */
}
@keyframes ph-flex {
  0%, 62%, 100% { transform: scaleY(1) scaleX(1); }
  70%           { transform: scaleY(0.86) scaleX(1.08); }
  82%           { transform: scaleY(1.1) scaleX(0.94); }
  92%           { transform: scaleY(0.92) scaleX(1.04); }
}

/* Off entirely, not merely slowed. Eleven looping animations across a feed row
   of reactions is exactly what this preference exists to stop, and every
   character's still frame is a complete drawing, so nothing is lost. */
@media (prefers-reduced-motion: reduce) {
  .rx-svg .rx-ch, .rx-svg .am-body, .rx-svg .am-eyes, .rx-svg .am-nucleus,
  .rx-svg .am-vacuole, .rx-svg .ec-flag, .rx-svg .ec-pili, .rx-svg .sa-spikes,
  .rx-svg .ph-legs {
    animation: none;
    will-change: auto;
  }
}
.act--stat:hover { background: none; color: var(--ink-50); }

/* ── micro-interactions ────────────────────────────────────────────────────
   The like's moment, the count that swaps, the post that arrives. All of it
   comes off under prefers-reduced-motion (see the block at the foot of the
   file) — the state still changes, it just stops moving. */

/* the heart springs: a quick dip, an overshoot past full, then settle */
@keyframes act-pop {
    0%   { transform: scale(1); }
    28%  { transform: scale(.8); }
    62%  { transform: scale(1.26); }
    100% { transform: scale(1); }
}
.act--pop svg { animation: act-pop 420ms cubic-bezier(.34, 1.56, .64, 1); transform-origin: 50% 55%; }

/* the burst rides over the icon on the left of the button */
.burst { position: absolute; left: 20px; top: 50%; width: 0; height: 0; pointer-events: none; z-index: 1; }
.burst__ring {
    position: absolute; left: -13px; top: -13px; width: 26px; height: 26px;
    border: 2px solid var(--danger); border-radius: 50%;
    animation: burst-ring 440ms var(--ease) forwards;
}
@keyframes burst-ring {
    0%   { transform: scale(.35); opacity: .6; }
    100% { transform: scale(1.65); opacity: 0; }
}
.burst__s {
    --a: 0deg;   /* the throw angle; JS sets one per spark, this is the fallback */
    position: absolute; left: -2px; top: -2px; width: 4px; height: 4px;
    border-radius: 50%; background: var(--danger); opacity: 0;
    animation: burst-s 520ms var(--ease) forwards;
}
@keyframes burst-s {
    0%   { opacity: 0; transform: rotate(var(--a)) translateY(-2px) scale(1); }
    25%  { opacity: 1; }
    100% { opacity: 0; transform: rotate(var(--a)) translateY(-18px) scale(.2); }
}

/* a count that changes is seen to change */
@keyframes count-bump {
    0%   { transform: translateY(0); }
    45%  { transform: translateY(-3px); }
    100% { transform: translateY(0); }
}
.act__n.is-bumped { animation: count-bump 320ms var(--ease); }

/* posts arrive rather than blink in — a short rise on first paint (staggered
   in JS) and on the post you just made, which also warms briefly to steel */
@keyframes post-enter {
    from { opacity: 0; transform: translateY(9px); }
    to   { opacity: 1; transform: none; }
}
.post--enter { animation: post-enter 380ms var(--ease) both; }
@keyframes fresh-wash {
    0%   { background: color-mix(in srgb, var(--steel) 13%, var(--paper)); }
    100% { background: var(--paper); }
}
.post--fresh { animation: post-enter 380ms var(--ease) both, fresh-wash 1600ms var(--ease) both; }

/* ── the kebab ────────────────────────────────────────────────────────── */
.menu-wrap { position: relative; margin-left: auto; }
/* The composer's plus and a profile's kebab sit at the LEFT of their row;
   a menu hanging off their right edge ran under the rail. */
.menu-wrap--left { margin-left: 0; }
.menu-wrap--left .menu { right: auto; left: 0; }
.kebab { width: 36px; height: 36px; padding: 0; justify-content: center; color: var(--danger); }
.kebab:hover { background: color-mix(in srgb, var(--danger) 9%, transparent); color: var(--danger); }
.menu {
    position: absolute; right: 0; top: calc(100% + 6px); z-index: 30;
    min-width: 212px; padding: 6px;
    background: var(--paper); border: 1px solid var(--rule); border-radius: var(--card-r);
    box-shadow: 0 16px 40px rgba(25, 32, 37, .15);
    animation: menu-in 150ms var(--ease);
}
@keyframes menu-in { from { opacity: 0; transform: translateY(-4px); } }
.menu[hidden] { display: none; }
.menu button {
    display: flex; align-items: center; gap: 10px; width: 100%;
    min-height: 44px; padding: 0 11px; border: 0; border-radius: calc(var(--card-r) * .55);
    background: none; color: var(--ink-70); font: inherit; font-size: 14px;
    text-align: left; cursor: pointer;
    transition: background-color 140ms var(--ease), color 140ms var(--ease);
}
.menu button:hover { background: var(--ground-alt); color: var(--ink); }
.menu button svg { flex: 0 0 auto; color: var(--ink-50); }
.menu__sep { height: 1px; background: var(--rule-soft); margin: 5px 7px; }
.menu__note { margin: 6px 4px 4px; padding: 8px 8px 4px; border-top: 1px solid var(--rule-soft); font-size: 12px; line-height: 1.4; color: var(--ink-50); max-width: 240px; }
/* Destructive last and visually separated — the platform rule, and the
   reason Block sits under a divider rather than beside Report. */
.menu button.is-danger, .menu button.is-danger svg { color: var(--danger); }
.menu button.is-danger:hover { background: color-mix(in srgb, var(--danger) 9%, transparent); }

/* ═══════════════════════════════════════════════════════════════════════
   COMMENTS
   ═══════════════════════════════════════════════════════════════════════ */
.comments { margin-top: 12px; padding-top: 11px; border-top: 1px solid var(--rule-soft); }
.comment { display: flex; gap: 10px; padding: 7px 0; }
.comment__col { min-width: 0; }
.comment__body { margin: 2px 0 0; font-size: 15px; line-height: 1.55; overflow-wrap: anywhere; }
/* threaded replies indent under their parent with a hairline guide */
.comment--reply { margin-left: 34px; padding-left: 12px; border-left: 2px solid var(--rule-soft); }
/* reaction + reply row under a comment; a smaller reaction than a post's */
.comment__actions { display: flex; align-items: center; gap: 10px; margin-top: 4px; }
.comment__actions .rx__btn .rx-svg { width: 22px; height: 22px; }
.comment__actions .rx__chip .rx-svg { width: 16px; height: 16px; }
.comment__reply-btn { border: 0; background: none; padding: 2px 4px; margin: 0; font: 600 12px var(--sans); color: var(--ink-50); cursor: pointer; letter-spacing: .01em; }
.comment__reply-btn:hover { color: var(--ink); text-decoration: underline; }
.reply-form { margin-top: 8px; }
/* @mentions in a rendered body */
.mention { color: var(--steel); font-weight: 600; text-decoration: none; }
.mention:hover { text-decoration: underline; }
/* composer @mention picker */
.mention-suggest { position: absolute; left: 0; right: 0; top: calc(100% + 4px); z-index: 50; max-height: 260px; overflow-y: auto;
  background: var(--paper); border: 1px solid var(--rule); border-radius: var(--card-r); box-shadow: 0 10px 30px rgba(0,0,0,.14); padding: 4px; }
.mention-suggest__opt { display: flex; align-items: center; gap: 9px; width: 100%; border: 0; background: none; padding: 7px 9px; border-radius: var(--card-r); cursor: pointer; text-align: left; }
.mention-suggest__opt:hover { background: var(--ground); }
.mention-suggest__meta { display: flex; flex-direction: column; min-width: 0; }
.mention-suggest__meta span { font: 600 14px var(--sans); color: var(--ink); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.mention-suggest__meta small { color: var(--ink-50); font: 12px var(--mono); }
.inline-form { display: flex; gap: 8px; margin-top: 10px; }
.inline-form input { flex: 1 1 auto; min-height: 44px; border: 1px solid var(--rule); border-radius: 999px; padding: 10px 16px; font: inherit; font-size: 15px; background: var(--paper); color: var(--ink); transition: border-color 160ms var(--ease); }
.inline-form input:focus { border-color: var(--steel); outline: none; }

/* ═══════════════════════════════════════════════════════════════════════
   PEOPLE
   ═══════════════════════════════════════════════════════════════════════ */
.person { display: flex; align-items: center; gap: 11px; padding: 10px clamp(13px, 1.7vw, 17px); }
.person + .person { border-top: 1px solid var(--rule-soft); }
.person__c { flex: 1 1 auto; min-width: 0; }
.person__n { font-weight: 600; font-size: 14px; display: flex; align-items: center; color: var(--ink); text-decoration: none; }
.person__n:hover { color: var(--steel); text-decoration: none; }
.person__h { font-size: 12px; line-height: 1.35; color: var(--ink-50); margin: 1px 0 0; overflow: hidden; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2; }

/* ═══════════════════════════════════════════════════════════════════════
   PROFILE
   ═══════════════════════════════════════════════════════════════════════ */
/* The band is painted from the person's own hue (set inline by the page,
   the same hue as their avatar) — identity carried through, not a gradient
   that appears nowhere else on the site. */
.prof__cover { height: clamp(80px, 12vw, 112px); border-radius: var(--card-r) var(--card-r) 0 0; background: var(--ground-alt); }
.prof__head { padding: 0 clamp(14px, 2vw, 20px) clamp(14px, 2vw, 20px); }
.prof__av.av--lg { margin: 0 0 16px; border-width: 3px; border-color: var(--paper); }
.prof__block { margin-top: 14px; }
.prof__name { font-family: var(--display); font-weight: var(--display-w); font-size: var(--d-4); line-height: 1.15; margin: 12px 0 0; display: flex; align-items: center; flex-wrap: wrap; }
.prof__handle { font: 500 13px/1 var(--mono); color: var(--ink-50); margin: 7px 0 0; }
.prof__headline { color: var(--ink-70); margin: 9px 0 0; }
.prof__counts { display: flex; gap: 20px; margin: 13px 0 0; font-size: 14px; color: var(--ink-50); }
.prof__counts b { color: var(--ink); font-variant-numeric: tabular-nums; }
.prof__bio { margin: 14px 0 0; line-height: 1.6; white-space: pre-wrap; overflow-wrap: anywhere; max-width: 58ch; }
.prof__acts { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; margin: 15px 0 0; }

.edit label { display: block; font: 500 11px/1 var(--mono); letter-spacing: .1em; text-transform: uppercase; color: var(--ink-50); margin: 14px 0 6px; }
.edit label:first-of-type { margin-top: 0; }
.edit input, .edit textarea { width: 100%; min-height: 44px; border: 1px solid var(--rule); border-radius: calc(var(--card-r) * .55); padding: 10px 12px; font: inherit; font-size: 15px; background: var(--paper); color: var(--ink); transition: border-color 160ms var(--ease); }
.edit textarea { min-height: 96px; resize: vertical; line-height: 1.55; }
.edit input:focus, .edit textarea:focus { border-color: var(--steel); outline: none; }
.edit__submit { margin: 16px 0 0; }

/* ═══════════════════════════════════════════════════════════════════════
   MESSAGES
   ═══════════════════════════════════════════════════════════════════════ */
/* A fixed pane, like every chat: the list and the thread scroll inside it,
   and the latest line sits by the input rather than the first line sitting
   at the top over a void. */
.dm { display: grid; grid-template-columns: minmax(140px,30%) minmax(0, 1fr); height: min(72vh, 680px); min-height: 420px; }
.dm__list { border-right: 1px solid var(--rule-soft); overflow-y: auto; min-height: 0; }
.dm__row { display: flex; align-items: center; gap: 10px; width: 100%; padding: 11px 13px; border: 0; background: none; text-align: left; cursor: pointer; border-bottom: 1px solid var(--rule-soft); transition: background-color 140ms var(--ease); }
.dm__row:hover { background: var(--ground-alt); }
.dm__row[aria-current="true"] { background: var(--ground-alt); }
.dm__c { flex: 1 1 auto; min-width: 0; }
.dm__n { font-weight: 600; font-size: 14px; display: flex; align-items: center; }
.dm__p { font-size: 12.5px; color: var(--ink-50); margin: 1px 0 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dm__thread { display: flex; flex-direction: column; min-height: 0; min-width:0; }
.dm__head { padding: 12px 15px; border-bottom: 1px solid var(--rule-soft); display: flex; align-items: center; gap: 10px; }
/* The back arrow lives only on a phone, where a thread takes the panel over;
   on a wide screen the inbox is always beside you, so there is nothing to go
   back to and it stays hidden. */
.dm__back { display: none; align-items: center; justify-content: center; width: 36px; height: 36px; margin: -6px 2px -6px -8px; padding: 0; border: 0; background: none; color: var(--ink); border-radius: 999px; cursor: pointer; flex: 0 0 auto; transition: background-color 140ms var(--ease); }
.dm__back:hover { background: var(--ground-alt); }
.dm__back:active { transform: scale(.94); }
.dm__log { flex: 1 1 auto; overflow-y: auto; min-height: 0; padding: 15px; display: flex; flex-direction: column; gap: 8px; }
.dm__log > :first-child { margin-top: auto; }   /* bottom-anchored, still scrollable */
.dm__empty { font-size: 13px; color: var(--ink-50); text-align: center; margin: auto 0 0; }
.bubble { max-width: 72%; padding: 9px 13px; border-radius: var(--card-r); font-size: 15px; line-height: 1.5; overflow-wrap: anywhere; }
.bubble--them { align-self: flex-start; background: var(--ground-alt); border-bottom-left-radius: 5px; }
.bubble--me { align-self: flex-end; background: var(--steel); color: var(--paper); border-bottom-right-radius: 5px; }
/* A message row: the bubble plus its actions — a hover ⋯ on the desktop, a
   long-press on touch. Actions used to be an inline "Reply" link crammed inside
   the bubble text; this lifts them out of it. */
.msg { display: flex; align-items: flex-end; gap: 4px; max-width: 86%; }
.msg--them { align-self: flex-start; }
.msg--me { align-self: flex-end; flex-direction: row-reverse; }
.msg .bubble { align-self: auto; max-width: 100%; }
.msg__more { flex: 0 0 auto; width: 30px; height: 30px; padding: 0; border: 0; background: none; color: var(--ink-50); border-radius: 50%; display: grid; place-items: center; cursor: pointer; opacity: 0; transition: opacity .12s ease, background .12s ease; }
.msg__more svg { width: 18px; height: 18px; }
.msg:hover .msg__more, .msg__more:focus-visible { opacity: 1; outline: none; }
.msg__more:hover { background: var(--ground-alt); color: var(--ink); }
@media (hover: none) { .msg__more { display: none; } .msg .bubble { -webkit-user-select: none; user-select: none; -webkit-touch-callout: none; } }
.msg-menu-back { position: fixed; inset: 0; z-index: 60; }
.msg-menu { position: fixed; min-width: 190px; max-width: 300px; background: var(--paper); color: var(--ink); border: 1px solid var(--rule-soft); border-radius: var(--card-r); overflow: hidden; box-shadow: 0 14px 44px rgba(0,0,0,.3); }
.msg-menu button { display: block; width: 100%; text-align: left; padding: 13px 18px; border: 0; border-bottom: 1px solid var(--rule-soft); background: var(--paper); color: var(--ink); font: 600 14px var(--sans); cursor: pointer; }
.msg-menu button:hover { background: var(--ground-alt); }
.msg-menu button:last-child { border-bottom: 0; }
.msg-menu .msg-menu__danger { color: var(--danger); }
@media (max-width: 760px) {
  .msg-menu-back { background: rgba(0,0,0,.45); }
  .msg-menu { left: 12px !important; right: 12px !important; top: auto !important; bottom: calc(12px + env(safe-area-inset-bottom, 0px)); min-width: 0; max-width: none; }
  .msg-menu button { text-align: center; padding: 16px; font-size: 15px; }
}
.dm__form { display: flex; gap: 8px; padding: 12px 15px; border-top: 1px solid var(--rule-soft); }
.dm__form input { flex: 1 1 0; min-width:0; min-height: 44px; border: 1px solid var(--rule); border-radius: 999px; padding: 10px 16px; font: inherit; font-size: 15px; background: var(--paper); color: var(--ink); }
.dm__form button{flex-shrink:0}
.dm__head .post__name{min-width:0;overflow-wrap:anywhere}
.dm__form input:focus { border-color: var(--steel); outline: none; }
@media (max-width: 760px) {
    /* One screen at a time, the way a phone messenger works: the inbox, or a
       single thread that takes the whole panel over. The list is GONE while a
       conversation is open, so no other names sit above the one you're reading;
       the ← in the header returns to the inbox. */
    .dm { grid-template-columns: minmax(0, 1fr); grid-template-rows: minmax(0, 1fr); height: calc(100dvh - 58px - 96px - 120px); }
    .dm__list, .dm__thread { grid-area: 1 / 1; }   /* same cell; one is shown */
    .dm__list { border-right: 0; }
    .dm[data-view="thread"] .dm__list { display: none; }
    .dm:not([data-view="thread"]) .dm__thread { display: none; }
    .dm__back { display: inline-flex; }
}

/* ═══════════════════════════════════════════════════════════════════════
   STATES
   ═══════════════════════════════════════════════════════════════════════ */
/* ── settings rows + toggle switch ─────────────────────────────────────── */
.setrow { display: flex; align-items: flex-start; gap: 16px; padding: 16px clamp(13px, 1.7vw, 17px); border-bottom: 1px solid var(--rule-soft); }
.setrow:last-child { border-bottom: 0; }
.setrow__text { flex: 1 1 auto; min-width: 0; }
.setrow__label { font-weight: 600; font-size: 15px; margin: 0; }
.setrow__desc { font-size: 13.5px; color: var(--ink-50); margin: 3px 0 0; line-height: 1.5; }
.setnote { font-size: 12.5px; color: var(--ink-50); margin: 14px 2px 0; }
.switch { flex: 0 0 auto; position: relative; display: inline-block; width: 44px; height: 26px; }
.switch input { position: absolute; inset: 0; width: 100%; height: 100%; margin: 0; opacity: 0; cursor: pointer; }
.switch__track { position: absolute; inset: 0; background: var(--rule); border-radius: 999px; transition: background-color 160ms var(--ease); }
.switch__track::before { content: ''; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; background: var(--paper); border-radius: 50%; box-shadow: 0 1px 3px rgba(25, 32, 37, .28); transition: transform 160ms var(--ease); }
.switch input:checked + .switch__track { background: var(--steel); }
.switch input:checked + .switch__track::before { transform: translateX(18px); }
.switch input:focus-visible + .switch__track { outline: 2px solid var(--steel); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .switch__track, .switch__track::before { transition: none; } }

.empty { text-align: center; color: var(--ink-50); padding: clamp(32px, 5vw, 56px) 22px; }
.empty__t { font-family: var(--display); font-weight: var(--display-w); font-size: var(--d-4); color: var(--ink); margin: 0 0 7px; }

/* Skeletons, not a spinner: the shape of what is coming is more informative
   than the fact that something is, and it reserves the space so arriving
   content does not shift the page. */
.skel { padding: clamp(13px, 1.7vw, 17px); margin-bottom: 12px; }
.skel__l { height: 11px; border-radius: 999px; background: var(--ground-alt); animation: skel 1.4s var(--ease) infinite; }
.skel__l + .skel__l { margin-top: 9px; }
@keyframes skel { 0%, 100% { opacity: 1; } 50% { opacity: .45; } }

/* The plasmid loader (social.js plasmidLoader). Centred, so it reads as "the
   surface is working" rather than as content. --pad gives it breathing room
   when it stands alone in a column; without it, it sits inline in a tighter
   spot like a comment thread. */
.ploader { display: flex; align-items: center; justify-content: center; color: var(--ink-70); }
/* The main content loaders (feed, profile, people, messages) fill a tall
   band and sit dead centre in it. Inline ones (a comment thread, a DM
   log) stay compact. */
.ploader--block { min-height: 46vh; }
.ploader--inline { padding: 20px 0; }
/* The beating-plasmid mark, styled exactly as the engine's thinking indicator
   (app.css .td-helix): two strands in currentColor with the far one set back,
   drawn by the tdp* renderer in social.js. */
.td-helix { display: inline-flex; flex: none; line-height: 0; color: inherit; }
.td-helix svg { overflow: visible; }
.td-helix path { fill: none; stroke: currentColor; stroke-linejoin: round; stroke-linecap: round; stroke-width: 1.4; }
.td-helix .tdp-s2 { opacity: 0.42; }
.td-helix .tdp-rungs line { stroke: currentColor; stroke-linecap: round; }

@media (prefers-reduced-motion: reduce) {
    .skel__l { animation: none; }
    .menu { animation: none; }
    .act, .plus, .composer__field, .app-nav__i, .menu button,
    .inline-form input, .edit input, .edit textarea, .draft__body input { transition: none; }
    .act:active, .btn:active { transform: none; }
    .plus[aria-expanded="true"] { transform: none; }
    .act--pop svg, .burst, .act__n.is-bumped,
    .post--enter, .post--fresh { animation: none; }
    .post--fresh { background: var(--paper); }
}
/* Process updates and action feedback share the network's existing tokens. */
.sound-toggle { flex-shrink:0; min-height:44px; min-width:48px; font-size:11px; white-space:nowrap; }
/* ═══ SHARE THE PROCESS — stories, IG-grammar ═══════════════════════════
   No heading over the row (the ring row IS the affordance); a gradient collar
   in the brand's own steel→amber, a paper gap to the face, and your own tile
   is your face with a + badge — not an empty dashed circle. */
.process-section { margin:0 0 6px; padding:4px 0 14px; border-bottom:1px solid var(--rule-soft); }
.process-status { margin:0; font-size:12.5px; line-height:1.5; color:var(--ink-50); }
.process-status:not(:empty) { margin-top:12px; }
.process-status:empty { display:none; }
.process-strip { display:flex; gap:15px; overflow-x:auto; padding:6px 2px 2px; scrollbar-width:none; -ms-overflow-style:none; scroll-snap-type:x proximity; }
.process-strip::-webkit-scrollbar { display:none; }
.process-tile { scroll-snap-align:start; flex:0 0 70px; width:70px; background:transparent; border:0; color:inherit; font:inherit; cursor:pointer; display:flex; flex-direction:column; align-items:center; gap:7px; -webkit-tap-highlight-color:transparent; }
.process-tile>span:last-child { width:100%; overflow:hidden; text-overflow:ellipsis; white-space:nowrap; font-size:11.5px; color:var(--ink-70); text-align:center; }
.process-tile:active .process-ring { transform:scale(.94); }
.process-ring { position:relative; display:flex; align-items:center; justify-content:center; width:66px; height:66px; padding:3px; border-radius:50%; background:conic-gradient(from 150deg, var(--amber), var(--steel) 55%, var(--amber)); transition:transform 160ms var(--ease); }
.process-ring.is-seen { background:var(--rule); }
.process-ring .av { width:100%; height:100%; border:2.5px solid var(--paper); box-sizing:border-box; }
.process-ring--add { background:var(--ground-alt); }
.process-badge { position:absolute; right:1px; bottom:1px; width:22px; height:22px; box-sizing:border-box; display:grid; place-items:center; border-radius:50%; background:var(--steel); color:#fff; border:1.5px solid var(--paper); box-shadow:0 1px 3px rgba(12,18,24,.34); }
.process-badge svg { width:13px; height:13px; display:block; }
.process-tile:focus-visible,.process-dialog button:focus-visible { outline:2px solid var(--steel); outline-offset:4px; }
.process-dialog { color:var(--ink); background:var(--paper); border:1px solid var(--rule); border-radius:var(--card-r); padding:24px; width:min(520px,calc(100vw - 32px)); max-height:calc(100dvh - 40px); overflow:auto; box-sizing:border-box; }
.process-dialog::backdrop { background:rgba(6,16,23,.66); }
.process-dialog h2 { margin:16px 0 8px; font-size:23px; letter-spacing:-.03em; }
.process-dialog p { line-height:1.6; }
.process-close { display:block; margin-left:auto; }
.process-compose,.post-edit { display:grid; gap:12px; }
.process-compose textarea,.post-edit textarea { width:100%; box-sizing:border-box; resize:vertical; border:1px solid var(--rule); border-radius:calc(var(--card-r) * .7); padding:13px; background:var(--ground); color:var(--ink); font:inherit; line-height:1.6; }
.process-compose label { font-size:12px; line-height:1.6; }
.process-compose input[type=file] { display:block; width:100%; margin-top:8px; font:inherit; }
.process-preview img,.process-preview video,.process-view img,.process-view video { display:block; max-width:100%; max-height:50dvh; margin:auto; object-fit:contain; border-radius:calc(var(--card-r) * .7); }
.process-actions { display:flex; gap:8px; flex-wrap:wrap; }
.process-position { font-size:12px; color:var(--ink-50); }
.process-body { white-space:pre-wrap; overflow-wrap:anywhere; }
.post-edit { margin:16px 0; }
.post-edit p:empty { display:none; }
@keyframes feedback-arrive { from { opacity:.5; transform:translateY(7px); } to { opacity:1; transform:translateY(0); } }
.feedback--arrive { animation:feedback-arrive .4s ease-out both; }
.comments { animation:feedback-arrive .22s ease-out; }
@media (max-width:600px) {
  .sound-toggle { font-size:10px; padding:7px 3px; }
  .process-dialog { padding:18px; }
  .process-strip { gap:8px; }
}
@media (prefers-reduced-motion:reduce) { .feedback--arrive,.comments { animation:none; } }

/* The gallery leads; the caption and share action stay next to the preview. */
.process-dialog--compose { padding:0; width:min(520px,calc(100vw - 32px)); overflow:hidden; }
.process-dialog--compose[open] { display:flex; flex-direction:column; }
.process-dialog--compose [hidden] { display:none !important; }
.process-create-head { padding:20px 86px 16px 22px; border-bottom:1px solid var(--rule); }
.process-create-head h2 { margin:0; font-size:20px; }
.process-create-head p { margin:4px 0 0; font-size:12px; color:var(--ink-50); }
.process-dialog--compose>.process-close { position:absolute; top:16px; right:14px; min-height:44px; }
.process-dialog--compose .process-compose { display:flex; flex-direction:column; gap:0; min-height:0; overflow:auto; }
.process-stage { background:#121a21; color:#fff; min-height:220px; height:min(48dvh,460px); flex-shrink:0; position:relative; }
.process-stage.is-dragging { outline:3px solid var(--steel); outline-offset:-3px; }
.process-stage .process-preview { width:100%; height:100%; display:flex; align-items:center; justify-content:center; }
.process-stage .process-preview img,.process-stage .process-preview video { width:100%; height:100%; max-height:100%; border-radius:0; object-fit:contain; }
.process-empty { display:flex; flex-direction:column; align-items:center; justify-content:center; padding:24px; gap:12px; text-align:center; width:100%; height:100%; box-sizing:border-box; overflow:auto; }
.process-empty>p { font-size:19px; margin:0; }
.process-empty>span { color:#b9c5ce; font-size:12px; }
.process-empty .btn { margin-top:8px; flex-shrink:0; }
.process-empty .process-text-preview { white-space:pre-wrap; overflow-wrap:anywhere; font-size:23px; line-height:1.45; }
.process-create-footer { padding:16px 20px 20px; background:var(--paper); }
.process-create-footer textarea { background:transparent; border:0; padding:2px 0 8px; border-radius:0; resize:none; min-height:52px; font-size:15px; }
.process-create-tools { display:flex; gap:8px; margin:4px 0 10px; }
.process-create-tools .btn { min-height:36px; padding:6px 10px; font-size:11px; }
.process-create-status { font-size:13px; color:var(--ink-70); margin:0 0 10px; }
.process-create-status:empty { display:none; }
.process-create-actions { display:flex; align-items:center; gap:12px; justify-content:space-between; }
.process-audience { color:var(--ink-50); font-size:11px; }
.process-create-actions .btn { min-width:112px; min-height:46px; }
.process-ring { overflow:hidden; }
.process-ring>img { width:100%; height:100%; border-radius:50%; object-fit:cover; }
@media (max-width:600px) {
  .process-dialog--compose { width:100%; max-width:100%; height:100dvh; max-height:100dvh; margin:0; border:0; border-radius:0; }
  .process-create-head { padding-top:max(18px,env(safe-area-inset-top)); }
  .process-dialog--compose .process-compose { flex:1; }
  .process-stage { flex:1 0 220px; height:auto; }
  .process-create-footer { padding-bottom:max(18px,env(safe-area-inset-bottom)); }
}
/* Network application: content-led layout, quiet chrome, one type system. */
.app-body { --ground:#f8fafc; --ground-alt:#f0f4f7; --rule:#e0e7ed; --rule-soft:#edf1f5; --card-r:16px; --display:var(--sans); --display-w:600; background:var(--paper); }
[data-theme="dark"] .app-body { --ground:#111820; --ground-alt:#1a2530; --rule:#2c3946; --rule-soft:#23303b; --paper:#121c25; --ink:#ecf2f8; --ink-70:#bfccd8; --ink-50:#9bafc0; --ink-35:#8198ac; --steel:#7abbe5; --ice:#203a4e; color:var(--ink); color-scheme:dark; }
.app-body .btn { font-family:var(--sans); text-transform:none; letter-spacing:0; font-weight:600; font-size:13px; border-radius:calc(var(--card-r) * .7); }
.app-body .btn--key { background:var(--steel); border-color:var(--steel); color:white; }
.app-body .s-title { font:700 clamp(24px,3vw,34px)/1.2 var(--sans); letter-spacing:-.04em; }
.app-top { background:var(--paper); backdrop-filter:none; }
.app-top__in { max-width:1360px; height:68px; gap:22px; }
.app-search { margin-left:auto; max-width:380px; }
.app-search input { border:0; border-radius:calc(var(--card-r) * .6); height:40px; }
.app-nav { display:none; }
.app-message-link { color:var(--ink); display:flex; padding:10px; position:relative; }
/* The link's own text label is hidden on this surface — the icon carries it.
   `span` would catch the badge too, so the hide is scoped to the label. */
.app-message-link > span:not(.app-unread) { display:none; }
/* Absolute so the count never changes the header's height or nudges the
   icon sideways when it appears. min-width + padding so "1" is a circle and
   "99+" grows into a pill rather than being clipped. */
.app-unread {
  position:absolute; top:3px; right:3px;
  display:flex; align-items:center; justify-content:center;
  min-width:17px; height:17px; padding:0 5px;
  border-radius:999px; background:#e8313b; color:#fff;
  font:700 10px/1 var(--sans); letter-spacing:.01em;
  font-variant-numeric:tabular-nums;
  /* Rides on the header's own colour, so the dot keeps its shape against the
     icon underneath it in both themes. */
  box-shadow:0 0 0 2px var(--paper);
  pointer-events:none;
}
.network-more { position:relative; }
.network-more summary { display:flex; cursor:pointer; padding:12px; list-style:none; }
.network-more summary::-webkit-details-marker { display:none; }
.network-more-panel { position:absolute; top:46px; right:0; min-width:200px; display:grid; background:var(--paper); border:1px solid var(--rule); border-radius:var(--card-r); padding:8px; box-shadow:0 8px 32px #16293818; }
.network-more-panel a { padding:11px; color:var(--ink); font-size:14px; }
.app { max-width:1360px; grid-template-columns:210px minmax(0,650px) minmax(190px,250px); gap:32px; padding-top:24px; }
.app--wide { grid-template-columns:210px minmax(0,1fr); }
.rail { top:92px; gap:22px; }
.network-side-nav { display:grid; gap:5px; }
.network-side-link { display:flex; align-items:center; gap:14px; padding:12px 14px; color:var(--ink-70); font-size:15px; border-radius:calc(var(--card-r)*.7); }
.network-side-link:hover,.network-side-link[aria-current=page] { background:var(--ground-alt); color:var(--steel); text-decoration:none; }
.network-side-link[aria-current=page] { font-weight:650; }
.me-card--compact { display:none; }
.rail-engine { border:0; background:var(--ground); padding:14px; }
.rail-engine small { font-size:11px; }
.aside .surface { border:0; }
.surface__head { border:0; font:600 13px/1.4 var(--sans); letter-spacing:0; text-transform:none; color:var(--ink); }
.aside .person { padding:12px 4px; border:0; }
.aside .person__h { font-size:11px; }
.post { border:0; border-bottom:1px solid var(--rule); border-radius:0; padding:24px 0; margin-bottom:0; }
.post__top { margin-bottom:14px; }
.post__meta { font-size:12px; }
.post__body { font-size:15px; line-height:1.65; }
.post__img,.post__vid { border-radius:calc(var(--card-r)*.65); overflow:hidden; }
.post__img img { width:100%; cursor:zoom-in; }
.acts { border:0; padding-top:10px; gap:6px; }
.acts .act { min-height:40px; font-size:13px; padding:0 9px; }
.acts .act svg { width:24px; height:24px; }
.post .kebab { color:var(--ink-50); }
.lcard { background:var(--ground); border:0; }
.process-section { margin:0; padding:0 0 20px; border-bottom:0; }
.process-head { display:flex; align-items:center; justify-content:space-between; gap:12px; }
.process-head h2 { font-size:14px; margin:0; }
.process-head p { font-size:11px; max-width:240px; text-align:right; }
.process-strip { padding-top:14px; }
.process-ring { width:64px; height:64px; border-width:2px; }
.composer { border:1px solid var(--rule); background:var(--ground); box-shadow:none; margin:0 0 8px; }
.composer__field { background:transparent; }
.feed-head { display:flex; align-items:center; gap:20px; border-bottom:1px solid var(--rule); margin-bottom:8px; }
.feed-head button { background:none; border:0; color:var(--ink-50); font:600 15px var(--sans); padding:18px 0; cursor:pointer; border-bottom:2px solid transparent; }
.feed-head button[aria-selected=true] { color:var(--ink); border-bottom-color:var(--steel); }
.feed-head .feed-filter { margin-left:auto; font-size:12px; }
.network-chips { display:flex; flex-wrap:wrap; gap:7px; margin:12px 0; }
.network-chip { display:inline-flex; border:1px solid var(--rule); border-radius:999px; padding:6px 11px; font:500 12px var(--sans); color:var(--ink-70); background:var(--paper); }
button.network-chip { cursor:pointer; }
.network-chip[aria-pressed=true] { background:var(--ice); border-color:var(--steel); color:var(--steel); }
.network-heading { display:flex; align-items:center; justify-content:space-between; gap:16px; margin-bottom:22px; }
.network-heading h1 { margin:0; font-size:30px; letter-spacing:-.04em; }
.network-heading p { color:var(--ink-50); margin:6px 0 0; font-size:14px; }
.network-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,260px),1fr)); gap:18px; }
.network-card { border:1px solid var(--rule); border-radius:var(--card-r); padding:22px; background:var(--paper); }
.network-card h2 { font-size:19px; margin:0 0 10px; letter-spacing:-.02em; }
.network-card p { line-height:1.6; color:var(--ink-70); font-size:14px; }
.network-card .btn { margin:8px 6px 0 0; }
.network-form { display:grid; gap:14px; }
.network-form label { display:grid; gap:6px; font-size:13px; font-weight:550; }
.network-form input,.network-form textarea,.network-form select,.network-filter { width:100%; padding:11px 13px; border:1px solid var(--rule); background:var(--paper); color:var(--ink); border-radius:calc(var(--card-r)*.6); font:14px var(--sans); }
.network-form textarea { min-height:100px; resize:vertical; }
.network-dialog { border:1px solid var(--rule); border-radius:var(--card-r); background:var(--paper); color:var(--ink); padding:24px; width:min(560px,calc(100vw - 28px)); max-height:90dvh; overflow:auto; }
.network-dialog::backdrop { background:#101e2db0; }
.network-dialog h2 { font:650 23px var(--sans); margin:12px 0 20px; }
.network-dialog-close { float:right; }
.network-empty { text-align:center; padding:54px 24px; color:var(--ink-50); }
.network-empty h2 { color:var(--ink); font-size:21px; }
.network-note { background:var(--ground); border-left:3px solid var(--steel); padding:14px; margin:12px 0; font-size:14px; white-space:pre-wrap; }

/* ── research objects — the social layer of the engine ────────────────── */
.network-subhead { margin:26px 0 12px; font-size:15px; letter-spacing:-.01em; color:var(--ink-70); }
.research-object-grid { display:grid; grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr)); gap:16px; }
.research-object-card { border:1px solid var(--rule); border-radius:var(--card-r); padding:20px; background:var(--paper); display:flex; flex-direction:column; min-width:0; }
.research-object-card__top { display:flex; align-items:center; justify-content:space-between; gap:10px; }
.research-object-card__top small { color:var(--ink-50); font-size:11px; }
.research-object-card h2 { font-size:19px; margin:14px 0 6px; letter-spacing:-.02em; overflow-wrap:anywhere; }
.research-object-card__meta { color:var(--ink-50); font:12px/1.5 var(--mono); overflow-wrap:anywhere; margin:0; }
.research-object-card__summary { color:var(--ink-70); font-size:14px; line-height:1.55; overflow-wrap:anywhere; margin:8px 0 0; }
.research-object-stats { display:flex; flex-wrap:wrap; gap:8px; margin:12px 0 0; color:var(--ink-50); font-size:12px; }
.research-object-stats span { padding:4px 9px; background:var(--ground); border-radius:999px; }
.research-object-card__actions { display:flex; flex-wrap:wrap; gap:8px; margin-top:auto; padding-top:16px; }
.research-object-card__actions .btn { margin:0; }
.research-object-preview { border:1px solid var(--rule); border-radius:var(--card-r); padding:16px; background:var(--ground); }
.research-object-preview h3 { margin:12px 0 6px; }
.research-object-preview p { margin:6px 0; color:var(--ink-70); font-size:13px; }
.research-object-preview .research-object-card__top { margin:0; }
.research-object-preview .research-object-stats { margin-top:12px; }
.research-object-preview__methods { margin-top:12px; }
.research-object-edit { border-top:1px solid var(--rule); border-bottom:1px solid var(--rule); padding:10px 0; }
.research-object-edit > summary { cursor:pointer; color:var(--ink-70); font-size:13px; font-weight:600; }
.research-object-edit[open] > summary { margin-bottom:12px; }

/* the compact research-object card that appears inside a feed post */
.ro-feed { border:1px solid var(--rule); border-radius:var(--card-r); padding:16px; background:var(--ground); margin-top:6px; }
.ro-feed__top { display:flex; align-items:center; gap:8px; flex-wrap:wrap; }
.ro-feed__chip { display:inline-flex; align-items:center; gap:6px; font:600 11px var(--sans); letter-spacing:.04em; text-transform:uppercase; color:var(--ink-70); }
.ro-feed__status { font-size:11px; color:var(--ink-50); text-transform:capitalize; }
.ro-feed__title { display:block; font-size:16px; font-weight:600; letter-spacing:-.01em; margin:8px 0 0; color:var(--ink); text-decoration:none; overflow-wrap:anywhere; }
.ro-feed__title:hover { text-decoration:underline; }
.ro-feed__meta { color:var(--ink-50); font:12px/1.4 var(--mono); margin:4px 0 0; overflow-wrap:anywhere; }
.ro-feed__stats { color:var(--ink-50); font-size:12px; margin:6px 0 0; }
.ro-feed__foot { margin-top:12px; }
.question-details { display:grid; gap:8px; margin:16px 0; }
.question-details p { margin:0; font-size:14px; }
.question-details strong { display:block; font-size:11px; text-transform:uppercase; letter-spacing:.06em; color:var(--ink-50); }
.answer-accepted { border-left:3px solid var(--good); padding-left:12px; background:var(--ground); }
.post-gallery { display:flex; overflow:auto; scroll-snap-type:x mandatory; border-radius:calc(var(--card-r)*.7); }
.post-gallery>div { min-width:100%; scroll-snap-align:center; }
.media-lightbox { width:100vw; height:100dvh; max-width:100vw; max-height:100dvh; margin:0; border:0; background:#0c1218; padding:20px; color:white; }
.media-lightbox img { display:block; max-width:100%; max-height:calc(100dvh - 90px); margin:auto; object-fit:contain; touch-action:pinch-zoom; }
.media-lightbox .btn { color:white; border-color:#ffffff55; float:right; }
.prof__cover { display:none; }
.prof__head { padding:24px; min-width:0; overflow-wrap:anywhere; }
.prof__name { font:700 28px var(--sans); letter-spacing:-.04em; }
.prof__av { margin:0 0 16px; }
.prof__block { margin-top:22px; }
.dm { border:0; height:calc(100dvh - 160px); min-height:400px; }
.dm__form input { border:0; background:var(--ground); }
.bubble { border-radius:calc(var(--card-r)*.8); max-width:80%; }
.dm__row { padding:18px 14px; }
.dm-unread { width:8px; height:8px; border-radius:50%; background:var(--steel); margin-left:auto; }
@media(max-width:1100px){.app{grid-template-columns:190px minmax(0,1fr);gap:24px}.aside{display:none}.app--wide{grid-template-columns:190px minmax(0,1fr)}}
@media(max-width:760px){
 .app,.app--wide{display:block;padding:16px 16px 88px}.rail{display:none}
 .app-top__in{height:58px;padding:0 16px;gap:8px}.app-search{min-width:0}.app-search input{font-size:12px}
 .app-brand svg{width:34px}.app-message-link{padding:8px}.network-more summary{padding:8px}
 .app-tabs{bottom:0;width:100%;border-radius:0;border:0;border-top:1px solid var(--rule);background:var(--paper);padding:7px 6px max(7px,env(safe-area-inset-bottom));box-shadow:none;gap:0}
 .app-tabs a{flex:1;min-width:0;border-radius:0;font-size:10px}.app-tabs a[aria-current=page]{background:transparent;color:var(--steel)}
 .process-head p{display:none}.process-section{padding-bottom:10px}.process-tile{flex-basis:72px;width:72px}
 .post{padding:20px 0}.post__body{font-size:14px}.post__top .av{width:36px;height:36px}
 .network-heading h1{font-size:25px}.network-heading{align-items:flex-start}
 .network-grid{grid-template-columns:1fr}.dm{height:calc(100dvh - 180px)}
 .dm__list{min-height:0}.network-dialog{padding:18px}
}

/* Publication and scientific media */
.composer{display:flex;align-items:center;gap:12px}.composer-open{flex:1;text-align:left;border:0;background:transparent;color:var(--ink-50);font:inherit;padding:12px;cursor:pointer}
.feed-tab{border:0;border-bottom:2px solid transparent;background:transparent;padding:16px 12px;font:inherit;color:var(--ink-50);cursor:pointer}.feed-tab[aria-pressed="true"]{color:var(--ink);border-bottom-color:var(--steel);font-weight:600}
.post-gallery{display:block}.post-gallery__slides{display:flex;overflow-x:auto;scroll-snap-type:x mandatory;scrollbar-width:none}.post-gallery__slides>.post__img{min-width:100%;scroll-snap-align:start;margin:0}.post-gallery__controls{display:flex;justify-content:center;align-items:center;gap:18px;padding:6px}
.figure-open{display:block;width:100%;padding:0;border:0;background:var(--ground-alt);cursor:zoom-in}.figure-open img{max-height:650px;width:100%;object-fit:contain}.media-lightbox{overflow:auto;touch-action:pan-x pan-y pinch-zoom}.media-lightbox img{display:block;max-height:80vh;max-width:100%;object-fit:contain;margin:auto;cursor:zoom-in}.media-lightbox img.is-original{max-width:none;max-height:none;cursor:zoom-out}.media-lightbox p{color:var(--ink-50);text-align:center}.network-upload-preview{display:flex;flex-wrap:wrap;gap:8px}.network-upload-preview img,.network-upload-preview video{width:120px;height:120px;object-fit:contain;background:var(--ground-alt)}
.network-form [hidden]{display:none}.network-form input,.network-form textarea,.network-form select{box-sizing:border-box;max-width:100%}.network-dialog{max-height:90dvh;overflow-y:auto}.network-dialog-close{float:right}.research-card{display:grid;gap:14px}.research-card .person{padding:0}.research-card p{margin:0}.profile-research{padding-top:16px;display:grid;gap:10px}

.act svg{flex:0 0 auto}.activity-row{display:flex;gap:20px;align-items:center;justify-content:space-between;padding:20px 12px;border-bottom:1px solid var(--rule);color:var(--ink)}.activity-row small{white-space:nowrap;color:var(--ink-50)}.activity-unread{background:var(--ground-alt)}.dm__row.is-unread .dm__n:after{content:'';display:inline-block;width:7px;height:7px;margin-left:8px;border-radius:50%;background:var(--steel)}.bubble img{display:block;max-width:100%;max-height:300px;object-fit:contain}.bubble blockquote{margin:0 0 8px;padding:6px 10px;border-left:2px solid currentColor;font-size:12px;opacity:.8}.bubble .act{font-size:11px;opacity:.75;padding:4px 0}.dm-reply{padding:8px 14px;background:var(--ground);font-size:12px}.dm-attachment{display:flex;gap:10px;align-items:center;padding:8px 14px}.dm-attachment img{width:64px;height:64px;object-fit:cover}.network-note a{overflow-wrap:anywhere}
@media(max-width:760px){.acts{gap:4px}.acts .act{padding:0 8px;gap:6px;min-height:44px}.acts svg{width:24px;height:24px}.process-tile{width:74px;flex-basis:74px}.network-heading{flex-wrap:wrap}.network-heading .btn{margin:0}.app-top__in{padding:0 12px}}

@media(max-width:760px){.acts .act--repost span{display:none}.acts .act--save{font-size:0;gap:0}.network-form input,.network-form textarea,.network-form select,.dm__form input{font-size:16px}}

[data-theme="dark"] .app-body .btn--key{background:#2b709c;color:#fff;border-color:#2b709c}.network-more-panel .btn{justify-content:flex-start;text-align:left}.media-lightbox p{color:#b8c7d3}.app-search input::placeholder{color:var(--ink-50)}

.av{color:#25343f}

/* Bound images to the avatar rather than the image's intrinsic grid size. */
.av{position:relative;grid-template-columns:minmax(0,1fr);grid-template-rows:minmax(0,1fr)}
.av__img{position:absolute;inset:0;border-radius:inherit}
.edit__photo{margin-bottom:18px}
/* Keep composing focused; specialist fields are available on demand. */
.post-compose{padding:0;width:min(600px,calc(100vw - 28px));box-sizing:border-box}
.post-compose>h2{font-size:18px;margin:0;padding:22px 24px;border-bottom:1px solid var(--rule)}
.post-compose>.network-dialog-close{margin:12px 16px 0 8px}
.post-compose>.network-form{gap:16px;padding:20px 24px 0}
.compose-identity{display:flex;align-items:center;gap:12px}
.compose-identity>div{min-width:0;display:grid;gap:4px}
.compose-identity strong{font-size:14px;overflow-wrap:anywhere}
.compose-identity small,.compose-hint{font:12px/1.4 var(--sans);color:var(--ink-50)}
.post-compose .compose-body{font-size:0;gap:0}
.post-compose .compose-body textarea{font:17px/1.6 var(--sans);border:0;padding:8px 0;min-height:150px;background:transparent;border-radius:0}
.compose-body textarea:focus{outline:none;box-shadow:none}
.compose-body:focus-within{box-shadow:0 2px 0 var(--rule)}
.compose-tools{display:flex;gap:8px;flex-wrap:wrap}
.compose-tools .btn{display:inline-flex;align-items:center;gap:8px}
.compose-options{border-top:1px solid var(--rule-soft);padding-top:12px}
.compose-options summary,.collection-editor summary,.feed-topics summary{cursor:pointer;color:var(--ink-70);font:600 13px/1.5 var(--sans);padding:8px 0}
.compose-options>.network-form{padding:14px 0 4px}
.compose-footer{position:sticky;bottom:0;background:var(--paper);border-top:1px solid var(--rule);display:flex;align-items:center;justify-content:space-between;gap:16px;padding:16px 0;z-index:1}
.compose-footer .btn{min-width:84px}
.network-form>[role=status]:empty,.network-note:empty,.network-upload-preview:empty{display:none}
.network-upload-preview{align-items:center}
.network-upload-preview img,.network-upload-preview video{border-radius:calc(var(--card-r)*.65)}
.feed-head .feed-tab[aria-pressed=true]{color:var(--ink);border-bottom-color:var(--steel)}
.feed-topics{border-bottom:1px solid var(--rule-soft);padding:2px 0 8px}
.feed-topics summary{list-style:none}
.feed-topics summary::-webkit-details-marker{display:none}
.feed-topics summary::marker{content:""}
.feed-topics summary{color:var(--ink-50);font-weight:500}
.feed-topics .network-chips{margin:8px 0}
.collection-picker{margin-bottom:18px}
.collection-editor{border-top:1px solid var(--rule-soft);margin-top:16px;padding-top:8px}
.collection-editor .network-form{margin:12px 0}
.network-card+.network-card{margin-top:16px}
.network-grid>.network-card{margin-top:0;display:flex;flex-direction:column;align-items:flex-start}
.network-card-actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:auto;padding-top:12px}
.network-card-actions .btn{margin:0}
.network-card>.network-chip{margin-bottom:12px}
.network-card p{margin:8px 0 14px;overflow-wrap:anywhere}
.activity-row>span{min-width:0;overflow-wrap:anywhere;font-size:14px;line-height:1.5}
.activity-row small{font-size:12px}
.network-dialog{box-sizing:border-box}
.research-filters{margin:12px 0 20px}
.research-filters summary{cursor:pointer;font:600 13px/1.5 var(--sans);color:var(--ink-70);padding:8px 0}
.research-filters .network-form{padding:12px 0}
.network-grid>.research-card{display:grid;gap:12px;align-content:start;align-items:stretch}
.research-card p,.research-card .network-chips{margin:0}
@media(max-width:760px){.post-compose{width:100%;max-width:100%;max-height:100dvh;height:100dvh;margin:0;border:0;border-radius:0}.post-compose>.network-form{padding:18px 20px 0;min-height:calc(100dvh - 74px);box-sizing:border-box;align-content:start}.post-compose>h2{padding:22px 20px}.compose-footer{padding-bottom:max(16px,env(safe-area-inset-bottom))}.compose-hint{max-width:170px}.feed-head{gap:18px}.activity-row{gap:12px;padding:16px 4px}}
.network-card,.network-heading>div,.post__who,.comment__col,.dm__c,.stream{min-width:0}
.network-card,.network-heading,.profile-research,.bubble{overflow-wrap:anywhere}
.prof__acts{flex-wrap:wrap}
.profile-research p{margin:0;font-size:14px;line-height:1.55}
.profile-research .network-chips{margin:6px 0}
.s-status:empty{display:none}
.app-body:not(.network-shell-ready)::before{content:'';display:block;height:68px;flex-shrink:0;border-bottom:1px solid var(--rule)}
@media(max-width:760px){.app-body:not(.network-shell-ready)::before{height:58px}.prof__head{padding:20px}.app-tabs{box-sizing:border-box}.network-heading .btn{white-space:normal}.network-card{padding:18px}}

/* ═══════════════════════════════════════════════════════════════════════
   STORY VIEWER — full-screen, Instagram grammar
   Progress bars up top, a minimal header, tap the sides to move, press and
   hold to pause. No button row: the screen IS the control.
   ═══════════════════════════════════════════════════════════════════════ */
.pv { position:fixed; inset:0; width:100vw; height:100dvh; max-width:none; max-height:none; margin:0; padding:0; border:0; background:#0b0f13; color:#fff; overflow:hidden; }
.pv::backdrop { background:#000; }
.pv__stage { position:absolute; inset:0; display:flex; align-items:center; justify-content:center; background:#0b0f13; z-index:0; }
.pv::before { content:''; position:absolute; top:0; left:0; right:0; height:130px; z-index:1; pointer-events:none; background:linear-gradient(to bottom, rgba(0,0,0,.55), rgba(0,0,0,0)); }
.pv__stage .post__img, .pv__stage .post__vid { margin:0; width:100%; height:100dvh; max-width:none; max-height:none; aspect-ratio:auto; border:0; border-radius:0; background:transparent; display:flex; align-items:center; justify-content:center; overflow:hidden; }
.pv__stage .post__img img, .pv__stage .post__vid video { width:100%; height:100%; max-height:100dvh; object-fit:contain; cursor:default; }
.pv__text { display:flex; align-items:center; justify-content:center; text-align:center; height:100%; margin:0 auto; padding:24px; max-width:660px; font-size:clamp(19px,4.6vw,26px); line-height:1.42; font-weight:500; letter-spacing:-.01em; white-space:pre-wrap; overflow-wrap:anywhere; }
.pv__caption { position:absolute; left:0; right:0; bottom:0; margin:0; z-index:3; pointer-events:none;
    padding:44px 18px calc(20px + env(safe-area-inset-bottom,0px)); font-size:15px; line-height:1.5; color:#fff;
    background:linear-gradient(to top, rgba(0,0,0,.78), rgba(0,0,0,.36) 55%, transparent);
    white-space:pre-wrap; overflow-wrap:anywhere; max-height:42dvh; overflow:auto; }

.pv__bars { position:absolute; top:0; left:0; right:0; z-index:2; pointer-events:none;
    display:flex; gap:4px; padding:calc(9px + env(safe-area-inset-top,0px)) 9px 0; }
.pv__bar { flex:1 1 0; height:2.5px; border-radius:2px; background:rgba(255,255,255,.34); overflow:hidden; }
.pv__fill { display:block; height:100%; width:100%; background:#fff; transform:scaleX(0); transform-origin:left; will-change:transform; }
.pv__fill.is-active { animation:pv-fill 8s linear forwards; }
@keyframes pv-fill { from { transform:scaleX(0); } to { transform:scaleX(1); } }

.pv__head { position:absolute; left:0; right:0; z-index:2; pointer-events:none;
    top:calc(14px + env(safe-area-inset-top,0px)); display:flex; align-items:center; gap:8px; padding:6px 8px 0; }
.pv__head a, .pv__head button { pointer-events:auto; }
.pv__who { display:flex; align-items:center; gap:9px; min-width:0; text-decoration:none; color:#fff;
    padding:4px 6px; border-radius:999px; }
.pv__who:hover { text-decoration:none; background:rgba(255,255,255,.12); }
.pv__av { width:34px; height:34px; flex:0 0 auto; }
.pv__av .av, .pv__av img { border:2px solid rgba(255,255,255,.55); box-sizing:border-box; }
.pv__meta { display:flex; flex-direction:column; line-height:1.25; min-width:0; }
.pv__meta strong { font-size:13.5px; font-weight:600; white-space:nowrap; overflow:hidden; text-overflow:ellipsis; max-width:46vw; }
.pv__meta span { font-size:11.5px; color:rgba(255,255,255,.72); }
.pv__spacer { flex:1 1 auto; }
.pv__icon { width:42px; height:42px; display:grid; place-items:center; border:0; background:none; color:#fff; cursor:pointer; border-radius:50%; }
.pv__icon:hover { background:rgba(255,255,255,.16); }

.pv__zone { position:absolute; top:0; bottom:0; z-index:1; background:transparent; cursor:pointer; -webkit-tap-highlight-color:transparent; touch-action:none; }
.pv__zone--l { left:0; width:32%; }
.pv__zone--r { right:0; width:68%; }
/* Private story reactions: a quick bar over the tap zones; a tap DMs the author. */
.pv__react { position:absolute; left:0; right:0; bottom:calc(18px + env(safe-area-inset-bottom,0px)); z-index:4;
             display:flex; justify-content:center; gap:12px; padding:8px; pointer-events:auto; }
.pv__react-b { width:58px; height:58px; border:0; border-radius:50%; background:rgba(255,255,255,.15);
               -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px); display:grid; place-items:center;
               cursor:pointer; transition:transform .14s ease, background .14s ease; }
.pv__react-b:hover { background:rgba(255,255,255,.26); transform:scale(1.12) translateY(-3px); }
.pv__react-b:active { transform:scale(.93); }
.pv__react-b.is-sent { background:rgba(255,255,255,.36); transform:scale(1.22) translateY(-3px); }
.pv__toast { position:absolute; left:50%; bottom:calc(84px + env(safe-area-inset-bottom,0px)); transform:translateX(-50%);
             z-index:4; background:rgba(0,0,0,.68); color:#fff; font:600 13px var(--sans); padding:8px 15px;
             border-radius:999px; pointer-events:none; white-space:nowrap; }
@media (prefers-reduced-motion: reduce) { .pv__react-b { transition:none; } }

.pv__sheet-back { position:absolute; inset:0; z-index:5; display:flex; align-items:flex-end; justify-content:center; padding:16px calc(16px + env(safe-area-inset-bottom,0px)); background:rgba(0,0,0,.5); }
.pv__sheet { width:min(420px,100%); background:var(--paper); color:var(--ink); border-radius:var(--card-r); overflow:hidden; box-shadow:0 20px 60px rgba(0,0,0,.4); }
.pv__sheet-btn { display:block; width:100%; text-align:center; padding:16px; border:0; border-bottom:1px solid var(--rule-soft); background:var(--paper); color:var(--ink); font:600 15px var(--sans); cursor:pointer; }
.pv__sheet-btn:hover { background:var(--ground-alt); }
.pv__sheet-btn--danger { color:var(--danger); }
.pv__sheet-btn--plain { color:var(--ink-50); font-weight:500; }
.pv__sheet-btn:last-child { border-bottom:0; }

@media (prefers-reduced-motion: reduce) { .pv__fill.is-active { animation:none; transform:scaleX(1); } }

/* ═══ RICH LINK CARD (Facebook-style) ═══════════════════════════════════
   Image over domain / title / description. Same markup renders in the feed
   AND as the composer's live preview, so a pasted link shows exactly the card
   that will post. Falls back to the compact .lcard when there's no image. */
.lcard--rich { display: block; padding: 0; overflow: hidden; border: 1px solid var(--rule); background: var(--paper); }
.lcard--rich:hover { border-color: var(--steel); }
.lcard--rich .lcard__c { display: block; padding: 11px 14px 13px; }
.lcard__img { display: block; aspect-ratio: 1.91 / 1; background: var(--ground-alt); overflow: hidden; }
.lcard__img img { width: 100%; height: 100%; object-fit: cover; display: block; }
.lcard--rich .lcard__d { text-transform: uppercase; letter-spacing: .04em; margin: 0 0 3px; font-size: 11px; }
.lcard--rich .lcard__t { font-size: 15px; line-height: 1.35; margin: 0; }
.lcard__desc { margin: 5px 0 0; font-size: 13px; line-height: 1.45; color: var(--ink-50); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }

/* Composer link preview — the rich card the post will carry, plus a remove bar.
   Same .lcard markup as the feed, so what you see is what publishes. */
.compose-linkpreview { margin: 8px 0 2px; }
.compose-linkcard .lcard { margin-top: 0; }
.compose-linkcard__bar { display: flex; align-items: center; gap: 12px; margin-top: 8px; }
.compose-linkcard__note { margin-right: auto; font-size: 12px; color: var(--ink-50); }
.compose-linkcard__bar .btn, .compose-linkcard__bar button:not(.btn) { margin-left: auto; }

/* De-triangle the composer disclosures — a quiet toggle, not a 90s marker. */
.compose-options summary { list-style: none; }
.compose-options summary::-webkit-details-marker { display: none; }
.compose-options summary::marker { content: ""; }
