/* ═══════════════════════════════════════════════════════════════════
   THE SOCIAL SITE -- /network, /network/feed and /@username.
   ═══════════════════════════════════════════════════════════════════

   One stylesheet for the three pages of the Linxi Network, loaded AFTER
   css/style.css (which supplies the topbar, the post cards, the composer,
   the buttons and the theme tokens). Everything here is a token, so the
   light/dark choice made in the app (js/theme.js + /theme.css) holds on
   these pages too -- profile.html used to carry its own copy of every
   rule in hex, which is why it had no dark mode.

   A different vibe from the app on purpose: a brand-gradient cover band
   under the topbar, cards floating up into it, a wide three-column shell
   that uses the whole screen on desktop and goes edge to edge on a
   phone. The APP is dense and grey; this is a place people read. */

body.social-body { background: var(--c-page, #f4f5f7); font-family: var(--site-font-body, -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif); margin: 0; color: var(--c-text, #0f172a); }
.social-body * { box-sizing: border-box; }

/* ── The site logo in the topbar ─────────────────────────────────────
   The same pair the app header carries: the light-theme logo and the
   dark-theme one, swapped by the theme rules in style.css
   (.header-logo-light / .header-logo-dark), with siteBrand.js dropping
   the dark one when no dark logo has been uploaded (.no-dark-logo). The
   id #header-logo-dark is what that fallback looks for, so it is the
   same id here as in the app -- one topbar per page. */
/* ⚠️ The topbar's own two layout rules moved to style.css, beside the rest
   of `.info-topbar-*`. They were scoped to `.social-body` and describe the
   BAR rather than the body it sits in, so the event page -- which is
   `.site-page-body` and does not load this stylesheet -- rendered the logo
   unsized and unaligned. A component's rules live with the component. */

/* ── The cover band ─────────────────────────────────────────────── */
.social-cover { background: linear-gradient(135deg, var(--c-brand, #6366f1) 0%, var(--c-brand-alt, #8b5cf6) 55%, var(--c-pink, #ec4899) 100%); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); position: relative; overflow: hidden; }
.social-cover::after { content: ''; position: absolute; inset: 0; background: radial-gradient(ellipse at 20% 0%, color-mix(in srgb, var(--c-highlight, #ffffff) 22%, transparent), transparent 55%), radial-gradient(ellipse at 90% 100%, color-mix(in srgb, var(--c-scrim, #000000) 18%, transparent), transparent 55%); pointer-events: none; }
.social-cover-inner { position: relative; z-index: 1; width: min(1440px, 100%); margin: 0 auto; padding: 2.25rem 2rem 4.25rem; display: flex; align-items: flex-end; justify-content: space-between; gap: 1.5rem; flex-wrap: wrap; }
/* ⚠️ BLOCK, NOT FLEX (Josh, 2026-09-30). As a flex row the emoji, the
   site's name and the page word were three side-by-side boxes, so on a
   phone the NAME box was squeezed until it wrapped inside itself
   ("Sensorium / Events") with "Network" beside it. In plain text flow the
   name is one unit (style.css: headings' [data-site-brand] is
   inline-block) and the page word wraps after it. The markup's own space
   after the emoji does what the gap did. */
.social-cover h1 { margin: 0; font-size: clamp(1.5rem, 2.6vw, 2.2rem); font-weight: 900; letter-spacing: -0.01em; }
.social-cover p { margin: 0.35rem 0 0; font-size: 0.95rem; opacity: 0.9; max-width: 60ch; }
.social-cover-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.social-cover-actions a { background: color-mix(in srgb, var(--c-highlight, #ffffff) 18%, transparent); color: var(--c-on-accent, #ffffff); border: 1px solid color-mix(in srgb, var(--c-highlight, #ffffff) 35%, transparent); text-decoration: none; padding: 0.5rem 1rem; border-radius: var(--btn-radius, 8px); font-weight: 700; font-size: 0.85rem; backdrop-filter: blur(6px); }
.social-cover-actions a:hover { background: color-mix(in srgb, var(--c-highlight, #ffffff) 30%, transparent); }
.social-cover-actions a.primary { background: var(--c-surface, #ffffff); color: var(--c-brand, #6366f1); border-color: transparent; }

/* ── The shell: full width, three rails on desktop ──────────────── */
/* ⚠️⚠️ LONG TOKENS BREAK RATHER THAN RUN OFF THE PAGE. A social page is
   made of things people type: @handles, pasted links, display names with
   no spaces. `.post-body` could already break (word-break), but nothing
   else on the page could -- a card title, a rail entry or a profile name
   would simply push the column wider than the phone.
   ⚠️ `anywhere`, not `break-word`: only `anywhere` also shrinks the
   min-content size a grid track measures itself against, which is the
   figure that makes a column overflow in the first place.
   ⚠️ Inherited, so one declaration covers the rails, the feed and the
   profile without naming any of them. */
.social-container { width: min(1440px, 100%); margin: 0 auto; padding: 0 2rem 3rem; overflow-wrap: anywhere; }
/* ⚠️ EXCEPT NAMES (Josh, 2026-10-02: "Moonbea / ms Tarot ... that
   shouldnt be happening anywhere"). A name breaks between its words,
   never inside one; the profile heading shrinks to fit its longest word
   instead (js/nameFit.js). */
.social-container :is(.profile-name, .post-author, .comment-author, .nl-name) { overflow-wrap: normal; word-break: normal; }
.social-shell { display: grid; grid-template-columns: 300px minmax(0, 1fr) 320px; gap: 1.25rem; align-items: start; margin-top: -2.5rem; position: relative; z-index: 2; }
.social-shell-2 { grid-template-columns: 300px minmax(0, 1fr); }
.social-rail { display: flex; flex-direction: column; gap: 1rem; position: sticky; top: 4.25rem; }
/* ⚠️ gap, NOT MARGIN (Josh, 2026-09-28: "for the whole page there needs
   to be a little margin between the different sections"). .social-card
   never carried its own margin and the sibling rule below only ever
   zeroed one, so two stacked cards -- the /tickets page's hero, Upcoming,
   My tickets, Past events, and every other social-family page built the
   same way -- touched edge to edge with nothing but their own shadows
   between them. gap on the column is the one change that spaces every
   child uniformly, .social-card or not, so .feed-toolbar/.compose-card/
   .post-card's own margin-top: 0 below is now simply redundant with it,
   not fighting it -- left alone rather than touched for no visible
   change. */
.social-main { min-width: 0; display: flex; flex-direction: column; gap: 1.25rem; }
.social-card { background: var(--c-surface, #ffffff); border-radius: var(--r-surface, var(--r-3xl)); padding: 1.25rem; box-shadow: 0 1px 3px color-mix(in srgb, var(--c-shadow, #000000) 8%, transparent), 0 8px 24px color-mix(in srgb, var(--c-shadow, #000000) 5%, transparent); }
.social-card h3 { margin: 0 0 0.5rem; font-size: 0.95rem; font-weight: 800; }
.social-main .feed-toolbar { margin-top: 0; box-shadow: 0 1px 3px color-mix(in srgb, var(--c-shadow, #000000) 8%, transparent), 0 8px 24px color-mix(in srgb, var(--c-shadow, #000000) 5%, transparent); }
.social-main .compose-card, .social-main .post-card { box-shadow: 0 1px 3px color-mix(in srgb, var(--c-shadow, #000000) 8%, transparent), 0 8px 24px color-mix(in srgb, var(--c-shadow, #000000) 4%, transparent); }
.social-main .feed-toolbar h1, .social-main .feed-toolbar h2 { margin: 0; font-size: 1.05rem; font-weight: 800; }

/* Medium: the right rail drops under the left one, the main column keeps the width. */
@media (max-width: 1199px) {
  .social-shell { grid-template-columns: 280px minmax(0, 1fr); }
  .social-rail-left { grid-column: 1; grid-row: 1; }
  .social-rail-right { grid-column: 1; grid-row: 2; position: static; }
  .social-main { grid-column: 2; grid-row: 1 / span 2; }
}
/* Phone: one column, edge to edge, the cover shorter. */
@media (max-width: 899px) {
  .social-container { padding: 0 0.6rem 2.5rem; }
  .social-cover-inner { padding: 1.5rem 1rem 3rem; }
  .social-shell, .social-shell-2 { grid-template-columns: minmax(0, 1fr); gap: 0.85rem; margin-top: -2rem; }
  /* ⚠️⚠️ THE ITEMS NEED THE FLOOR AS WELL AS THE TRACK. A grid item
     defaults to min-width: auto, so a long link in a post, a handle with
     no spaces or a wide embed pushes its rail past the viewport and the
     whole page scrolls sideways. .social-main already carried this for
     the desktop layout; the RAILS never did, because on desktop they are
     a fixed 300px and could not overflow. On one column they can. */
  .social-shell > *, .social-shell-2 > * { min-width: 0; }
  .social-rail { position: static; gap: 0.85rem; }
  .social-rail-left, .social-rail-right, .social-main { grid-column: 1; grid-row: auto; }
  .social-rail-right { order: 3; }
  .social-card, .social-main .post-card, .social-main .compose-card, .social-main .feed-toolbar { border-radius: var(--r-2xl); }
  .page-links-inner { padding-left: 1rem; padding-right: 1rem; }
}

/* ── The rails' contents (network.html) ─────────────────────────── */
.social-me-row { display: flex; gap: 0.75rem; align-items: center; }
.social-me-avatar { width: 56px; height: 56px; border-radius: var(--r-round); object-fit: cover; flex-shrink: 0; border: 3px solid var(--c-surface, #ffffff); box-shadow: 0 0 0 1px var(--c-border, #e2e8f0); }
.social-me-avatar-fallback { background: linear-gradient(135deg, var(--c-brand, #6366f1), var(--c-purple, #a855f7)); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); display: flex; align-items: center; justify-content: center; font-weight: 800; font-size: 1.25rem; }
.social-me-body { min-width: 0; }
.social-me-name { font-weight: 800; font-size: 1.05rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.social-me-handle { font-size: 0.82rem; color: var(--c-text-muted, #64748b); text-decoration: none; }
.social-me-stats { display: flex; gap: 1.25rem; margin-top: 0.85rem; }
.social-me-stat { text-align: left; cursor: pointer; }
/* Buttons now (2026-10-01): they open your own lists. Drawn as the plain counts they were. */
button.social-me-stat { width: auto; min-width: 0; margin: 0; padding: 0.15rem 0.35rem; border: 0; border-radius: var(--r-md); background: none; box-shadow: none; font: inherit; color: inherit; }
button.social-me-stat:hover, button.social-me-stat:focus-visible { background: var(--c-surface-subtle, #f1f5f9); transform: none; }
.social-me-stat b { display: block; font-size: 1.05rem; font-weight: 800; }
.social-me-stat span { font-size: 0.72rem; color: var(--c-text-dim, #94a3b8); text-transform: uppercase; letter-spacing: 0.05em; }
.social-me-actions { display: flex; gap: 0.5rem; margin-top: 0.85rem; flex-wrap: wrap; }
.social-join h3 { font-size: 1.05rem; }
.social-join p { margin: 0 0 0.85rem; font-size: 0.85rem; color: var(--c-text-muted, #64748b); line-height: 1.5; }
.social-join-actions { display: flex; gap: 0.5rem; flex-wrap: wrap; }
.social-join-actions .compose-submit { text-decoration: none; display: inline-flex; align-items: center; }
.social-quiet { font-size: 0.8rem; color: var(--c-text-muted, #64748b); margin: 0; line-height: 1.5; }
.social-quiet a { color: var(--c-brand, #6366f1); text-decoration: none; font-weight: 600; }
.social-feed-note { margin: 0.6rem 0.25rem 0; }

.network-section-header { display: flex; align-items: center; justify-content: space-between; font-size: 0.72rem; font-weight: 800; text-transform: uppercase; letter-spacing: 0.07em; color: var(--c-text-dim, #94a3b8); margin-bottom: 0.6rem; }
.network-add-btn { background: var(--c-brand-tint, #ede9fe); border: none; color: var(--c-brand, #6366f1); cursor: pointer; font-size: 1rem; line-height: 1; width: 26px; height: 26px; border-radius: var(--r-round); display: inline-flex; align-items: center; justify-content: center; }
.network-add-btn:hover { background: var(--c-brand, #6366f1); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); }
.network-item { display: flex; align-items: center; gap: 0.6rem; padding: 0.5rem 0.6rem; cursor: pointer; border-radius: var(--r-lg); font-size: 0.85rem; color: var(--c-text-muted, #475569); }
.network-item:hover { background: var(--c-surface-sunken, #f1f5f9); color: var(--c-text, #0f172a); }
.network-item.active { background: var(--c-brand-tint, #ede9fe); color: var(--c-brand, #6366f1); font-weight: 600; }
.network-item-avatar { width: 32px; height: 32px; border-radius: var(--r-round); object-fit: cover; flex-shrink: 0; background: var(--c-border, #e2e8f0); display: flex; align-items: center; justify-content: center; font-size: 0.78rem; font-weight: 700; color: var(--c-text-muted, #64748b); }
.network-item-main { display: flex; flex-direction: column; min-width: 0; overflow: hidden; }
.network-item-main span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.network-item-workspaces { font-size: 0.7rem; color: var(--c-text-dim, #94a3b8); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; margin-top: 0.1rem; }
.network-item-unread { background: var(--c-brand, #6366f1); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); font-size: 0.65rem; font-weight: 700; padding: 0.1rem 0.4rem; border-radius: var(--r-6xl); margin-left: auto; min-width: 18px; text-align: center; }
.network-item-pending { cursor: default; }
.network-item-pending:hover { background: none; color: var(--c-text-muted, #475569); }
.network-item-pending-note { font-size: 0.7rem; margin-left: auto; white-space: nowrap; }
.network-follow-back-btn { background: var(--c-brand, #6366f1); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); border: none; border-radius: var(--btn-radius, 8px); padding: 0.35rem 0.7rem; font-size: 0.75rem; font-weight: 700; cursor: pointer; white-space: nowrap; }
.network-follow-back-btn:hover { background: var(--c-brand-strong, #4f46e5); }
.network-follow-back-btn:disabled { opacity: 0.6; cursor: default; }
.network-add-workspace-btn { background: var(--c-surface-sunken, #f1f5f9); color: var(--c-brand, #6366f1); }
.network-add-workspace-btn:hover { background: var(--c-brand-tint, #ede9fe); }
.network-follower-card { padding: 0.55rem 0.6rem; border-radius: var(--r-lg); cursor: pointer; font-size: 0.85rem; color: var(--c-text-muted, #475569); }
.network-follower-card:hover { background: var(--c-surface-sunken, #f1f5f9); }
.network-follower-header { display: flex; align-items: center; gap: 0.6rem; }
.network-follower-actions { display: flex; gap: 0.4rem; margin-top: 0.5rem; padding-left: calc(32px + 0.6rem); flex-wrap: wrap; }
.network-follower-actions .network-follow-back-btn { flex: 1; text-align: center; }

/* A conversation in the main column. */
.social-conversation { padding: 1.25rem; }
.network-chat-header { display: flex; align-items: center; gap: 0.75rem; padding-bottom: 0.75rem; border-bottom: 1px solid var(--c-border, #e5e7eb); margin-bottom: 0.75rem; }
.network-back-link { font-size: 0.85rem; font-weight: 700; color: var(--c-brand, #6366f1); text-decoration: none; margin-right: 0.25rem; white-space: nowrap; }
.network-messages { overflow-y: auto; max-height: 60vh; display: flex; flex-direction: column; gap: 0.5rem; padding: 0.25rem 0; }
.network-message { display: flex; gap: 0.6rem; align-items: flex-start; }
.network-message.outbound { flex-direction: row-reverse; }
.network-message-bubble { max-width: 72%; padding: 0.6rem 0.9rem; border-radius: var(--r-3xl); font-size: 0.9rem; line-height: 1.5; }
.network-message.inbound .network-message-bubble { background: var(--c-surface-sunken, #f1f5f9); color: var(--c-text, #0f172a); border-bottom-left-radius: var(--r-xs); }
.network-message.outbound .network-message-bubble { background: linear-gradient(135deg, var(--c-brand, #6366f1), var(--c-brand-alt, #8b5cf6)); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); border-bottom-right-radius: var(--r-xs); }
.network-message-meta { font-size: 0.68rem; opacity: 0.75; margin-top: 0.2rem; }
.network-mention { color: var(--c-brand, #6366f1); font-weight: 600; }
.network-message.outbound .network-mention { color: inherit; text-decoration: underline; }
.network-input-area { margin-top: 0.75rem; }
.network-input-wrapper { position: relative; display: flex; gap: 0.5rem; align-items: flex-end; background: var(--c-surface-subtle, #f8fafc); border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-3xl); padding: 0.5rem 0.75rem; }
.network-input { flex: 1; border: none; background: none; font-size: 0.9rem; resize: none; outline: none; max-height: 120px; min-height: 24px; font-family: inherit; color: var(--c-text, #0f172a); }
.network-input-wrapper .btn { border-radius: var(--btn-radius, 8px); }
.mention-autocomplete { position: absolute; bottom: 100%; left: 0; right: 0; margin-bottom: 0.35rem; background: var(--c-surface, #ffffff); border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-lg); box-shadow: 0 4px 15px color-mix(in srgb, var(--c-shadow, #000000) 12%, transparent); max-height: 200px; overflow-y: auto; z-index: 50; }
.mention-item { display: flex; align-items: center; gap: 0.5rem; padding: 0.45rem 0.7rem; cursor: pointer; font-size: 0.85rem; }
.mention-item:hover { background: var(--c-brand-tint, #f5f3ff); }
.social-body .modal input[type="text"] { width: 100%; }
@media (max-width: 899px) { .network-messages { max-height: none; } .network-message-bubble { max-width: 85%; } }

/* ── The profile page (profile.html) ─────────────────────────────
   Its rules, moved out of the page's own <style> and tokenised. The
   page keeps its own cover (the user's, or the brand gradient) and its
   header card floats up into it, so it does not use .social-cover. */
.profile-container { width: min(1440px, 100%); max-width: none; margin: 0 auto; padding: 0 2rem 3rem; }
.profile-body { display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: 1.25rem; align-items: start; margin-top: 1.25rem; }
.profile-side, .profile-main { min-width: 0; }
.profile-side { position: sticky; top: 4.25rem; }
.profile-main .profile-tabs { margin-top: 0; }
.profile-side .post-card { margin-top: 0; }
.profile-cover { height: 240px; }
@media (max-width: 899px) {
  .profile-container { padding: 0 0.6rem 2.5rem; }
  .profile-body { grid-template-columns: minmax(0, 1fr); gap: 0.85rem; }
  .profile-side { position: static; }
  .pe-grid, .lead-ws-list { grid-template-columns: minmax(0, 1fr); }
  .profile-cover { height: 160px; }
}
  .profile-main .profile-tabs { margin-top: 0; }
  .profile-side .post-card { margin-top: 0; }
  .plinks-head { display: flex; justify-content: space-between; align-items: center; margin-bottom: 0.6rem; }
  .plinks-head h3 { font-size: 0.95rem; font-weight: 700; margin: 0; }
  .plinks { display: flex; flex-direction: column; gap: 0.5rem; }
  /* A link is a PILL: the page's own image as a round badge, its title,
     the domain in small under it. Full-width so the titles line up. */
  .plink { display: flex; gap: 0.65rem; align-items: center; padding: 0.4rem 0.9rem 0.4rem 0.4rem; border-radius: var(--r-pill); border: 1px solid var(--c-border, #e2e8f0); text-decoration: none; color: inherit; background: linear-gradient(135deg, var(--c-surface-subtle, #f8fafc), var(--c-surface, #ffffff)); box-shadow: 0 1px 2px color-mix(in srgb, var(--c-shadow, #000000) 5%, transparent); transition: transform 0.12s ease, box-shadow 0.12s ease; }
  a.plink:hover { transform: translateY(-1px); box-shadow: 0 4px 12px color-mix(in srgb, var(--c-brand, #6366f1) 15%, transparent); border-color: var(--c-brand-border, #c7d2fe); }
  .plink-img { width: 40px; height: 40px; border-radius: var(--r-round); object-fit: cover; background: linear-gradient(135deg, var(--c-brand-tint-2, #e0e7ff), var(--c-brand-tint, #fce7f3)); flex-shrink: 0; display: flex; align-items: center; justify-content: center; font-size: 1rem; color: var(--c-brand, #6366f1); border: 2px solid var(--c-surface, #ffffff); box-shadow: 0 0 0 1px var(--c-border, #e2e8f0); }
  .plink-body { min-width: 0; flex: 1; line-height: 1.25; }
  .plink-title { font-weight: 700; font-size: 0.85rem; color: var(--c-text, #0f172a); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .plink-desc { font-size: 0.72rem; color: var(--c-text-muted, #64748b); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .plink-domain { font-size: 0.7rem; color: var(--c-text-dim, #94a3b8); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .plink-tools { display: flex; gap: 0.15rem; flex-shrink: 0; }
  .plink-tools button { background: var(--c-surface-sunken, #f1f5f9); border: none; border-radius: var(--r-sm); width: 26px; height: 26px; cursor: pointer; font-size: 0.75rem; color: var(--c-text-muted, #475569); }
  .plink-tools button:hover { background: var(--c-border, #e2e8f0); }
  .plinks-add { display: flex; gap: 0.4rem; margin-top: 0.75rem; }
  .plinks-add input { flex: 1; min-width: 0; padding: 0.5rem 0.6rem; border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-md); font-size: 0.8rem; font-family: inherit; }
  .plinks-add button { background: var(--c-brand, #6366f1); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); border: none; border-radius: var(--r-md); padding: 0 0.8rem; font-weight: 600; font-size: 0.8rem; cursor: pointer; }
  .plinks-note { font-size: 0.72rem; color: var(--c-text-dim, #94a3b8); margin: 0.5rem 0 0; }
  .plinks-empty { font-size: 0.8rem; color: var(--c-text-dim, #94a3b8); margin: 0; }

  /* The editor is ON the page, in the main column, above the feed. */
  .profile-editor { background: var(--c-surface, #ffffff); border-radius: var(--r-surface, var(--r-3xl)); padding: 1.25rem; box-shadow: 0 1px 3px color-mix(in srgb, var(--c-shadow, #000000) 8%, transparent); margin-bottom: 1rem; }
  .profile-editor h3 { margin: 0 0 1rem; font-weight: 700; font-size: 1rem; }
  .profile-editor label { font-size: 0.78rem; font-weight: 600; color: var(--c-text-muted, #475569); display: block; margin-bottom: 0.3rem; }
  .profile-editor input[type="text"], .profile-editor textarea, .profile-editor select { width: 100%; padding: 0.6rem; border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-md); font-size: 0.875rem; margin-bottom: 0.85rem; font-family: inherit; }
  .pe-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1rem; }
  .pe-check { display: flex; gap: 0.6rem; align-items: flex-start; font-size: 0.85rem; font-weight: 500; color: var(--c-text, #0f172a); margin-bottom: 0.6rem; cursor: pointer; }
  .pe-check input { margin-top: 0.2rem; }
  .pe-check small { display: block; font-size: 0.74rem; color: var(--c-text-muted, #64748b); font-weight: 400; margin-top: 0.15rem; }
  .pe-section { border-top: 1px solid var(--c-surface-sunken, #f1f5f9); padding-top: 0.85rem; margin-top: 0.25rem; }
  .pe-actions { display: flex; gap: 0.6rem; align-items: center; margin-top: 0.5rem; }
  .pe-actions .compose-submit { flex: 1; }
  .lead-ws-list { display: grid; grid-template-columns: 1fr 1fr; gap: 0.35rem 1rem; margin-bottom: 0.85rem; }

  .profile-cover {
    width: 100%; height: 200px;
    background: linear-gradient(135deg, var(--c-brand, #6366f1), var(--c-brand-alt, #8b5cf6), var(--c-pink, #ec4899));
    border-radius: var(--r-surface, 0 0 var(--r-3xl) var(--r-3xl));
    overflow: hidden; position: relative; cursor: default;
  }
  .profile-cover img { width: 100%; height: 100%; object-fit: cover; }
  /* ⚠️⚠️ TOP RIGHT, AND THE MOVE IS WHY THERE IS NO z-index HERE ANY MORE.
     At the BOTTOM this button was painted over: .profile-header below
     carries `margin-top: -2rem` with `position: relative` and no z-index,
     so it is pulled 32px up over the bottom of the cover and -- later in
     the DOM at the same stacking level -- paints on top of anything
     sitting in that strip. A z-index of 1 was holding the button above
     it. Nothing overlaps the cover's TOP edge, so that prop has been
     removed rather than left behind as cargo: a stacking value with no
     remaining reason is the kind nobody dares touch later.

     ⚠️ THE STICKY TOPBAR IS NOT A PROBLEM AND MUST NOT BE FOUGHT. It is
     z-index 100, so it correctly covers this button as the page scrolls
     past -- the cover is scrolling away underneath it. Raising the button
     to beat it would leave an Edit Cover control floating over the site
     nav. */
  .profile-cover-edit {
    position: absolute; top: 0.75rem; right: 0.75rem;
    background: color-mix(in srgb, var(--c-scrim, #000000) 55%, transparent); color: var(--c-on-accent, #ffffff); border: none;
    padding: 0.4rem 0.75rem; border-radius: var(--r-md); font-size: 0.78rem; cursor: pointer;
  }

  .profile-header {
    background: var(--c-surface, #ffffff); border-radius: var(--r-surface, var(--r-3xl)); padding: 0 1.25rem 1.25rem;
    margin-top: -2rem; position: relative; box-shadow: 0 1px 3px color-mix(in srgb, var(--c-shadow, #000000) 8%, transparent);
  }
  .profile-avatar-wrap { position: relative; display: inline-block; margin-top: -40px; padding-top: 1rem; }
  .profile-avatar {
    width: 80px; height: 80px; border-radius: var(--r-round); border: 4px solid var(--c-surface, #ffffff);
    object-fit: cover; background: var(--c-border, #e2e8f0); display: flex; align-items: center;
    justify-content: center; font-size: 2rem; font-weight: 700; color: var(--c-text-muted, #64748b);
  }
  .profile-avatar-edit {
    position: absolute; bottom: 2px; right: 2px; width: 26px; height: 26px;
    background: var(--c-brand, #6366f1); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); border: none; border-radius: var(--r-round);
    font-size: 0.7rem; cursor: pointer; display: flex; align-items: center; justify-content: center;
  }
  /* The picture, and beside it who this is: name, @username, bio (Josh,
     2026-09-30). The text starts just below the cover's edge -- the
     picture rises into the cover, the words do not. Everything else sits
     under both in .profile-head-rest. */
  /* ⚠️ A BLOCK, so the rest goes UNDER the row. style.css makes
     .profile-header a wrapping flex row (the app's contact panel shares the
     class), which on a wide screen put the counts and buttons to the right
     of the name instead. Scoped by the row it holds, so that panel keeps
     its own layout. */
  .profile-header:has(> .profile-head-row) { display: block; }
  /* The header's pictures (Josh, 2026-09-30): three across the whole
     width of the header, under who they are; on a phone, one at a time
     with arrows -- and always at least three, the site's logo filling any
     place still empty. */
  .profile-header:has(> .profile-head-main) { display: block; }
  .profile-head-main { min-width: 0; }
  .profile-media { width: 100%; margin-top: 1.25rem; }
  .profile-media-stage { position: relative; }
  .profile-media-track { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.65rem; }
  .profile-media-tile {
    position: relative; display: block; aspect-ratio: 4 / 3; overflow: hidden;
    border-radius: var(--r-lg); background: var(--c-surface-subtle, #f8fafc);
    border: 1px solid var(--sx-edge, var(--c-border, #e2e8f0));
  }
  /* ⚠️ THE TILE'S OWN PICTURE, a direct child -- a video tile also holds
     the player, whose credit has an <img> of its own. */
  .profile-media-tile > img, .profile-media-tile > video { display: block; width: 100%; height: 100%; object-fit: cover; }
  .profile-media-tile.is-logo { display: grid; place-items: center; }
  .profile-media-tile.is-logo > img { width: auto; height: 58%; max-width: 70%; object-fit: contain; opacity: 0.9; }
  .profile-media-play {
    position: absolute; left: 0.5rem; bottom: 0.5rem; display: grid; place-items: center;
    width: 2rem; height: 2rem; border-radius: var(--r-round); font-size: 0.72rem; color: #fff;
    background: color-mix(in srgb, #000 55%, transparent); pointer-events: none;
  }
  .profile-media-nav { display: none; }
  .profile-media > .profile-media-add { display: flex; width: fit-content; margin: 0.75rem auto 0; }
  @media (max-width: 640px) {
    .profile-media-track {
      display: flex; gap: 0; overflow-x: auto; scroll-snap-type: x mandatory;
      scrollbar-width: none; border-radius: var(--r-lg);
    }
    .profile-media-track::-webkit-scrollbar { display: none; }
    /* Square on a phone (Josh, 2026-10-03: "not rectangular and longer in
       width like they currently are"); 16 / 10 cut tall pictures to a band. */
    .profile-media-track .profile-media-tile { flex: 0 0 100%; aspect-ratio: 1 / 1; scroll-snap-align: start; }
    /* ⚠️ EACH PICTURE ITS OWN SHAPE (Josh, 2026-10-08): a full-length
       photo cut to a square showed "just the mid part of her body". The
       tile takes the picture's ratio (--pm-ratio, from its size or
       measured on load; the logo stays square), at most 75% of the
       screen tall, and the picture is never cropped -- one taller than
       that sits whole in the middle. The track is as tall as the slide in
       view (profileMediaStrip.js), so tiles keep their own heights. */
    .profile-media-track { align-items: flex-start; overflow-y: hidden; }
    .profile-media-track .profile-media-tile:not(.is-full) { aspect-ratio: var(--pm-ratio, 1 / 1); max-height: 75vh; max-height: 75svh; }
    .profile-media-track .profile-media-tile:not(.is-logo) > img,
    .profile-header .profile-media .profile-media-track .profile-media-tile.post-video:not(.is-full) video { object-fit: contain; }
    .profile-media-nav {
      display: grid; place-items: center; position: absolute; top: 50%; transform: translateY(-50%);
      width: 2.25rem; height: 2.25rem; padding: 0; border: 0; border-radius: var(--r-round);
      background: color-mix(in srgb, #000 50%, transparent); color: #fff; font-size: 1.4rem; line-height: 1;
      box-shadow: none; cursor: pointer; z-index: 2;
    }
    .profile-media-nav.is-prev { left: 0.5rem; }
    .profile-media-nav.is-next { right: 0.5rem; }
    .profile-media-nav:disabled { opacity: 0.3; cursor: default; }
  }
  /* ⚠️ FOUR ACROSS ON A WIDE SCREEN (Josh, 2026-09-30): "the full section
     should be 4 divs on desktop, the name div, image1, image2, image3".
     The pictures take the rest of the row beside who they are, level with
     the name (not up in the cover with the round picture), each its own
     shape -- stretched to the height of a long bio they became strips.
     Narrower screens keep them underneath, three across; phones slide. */
  @media (min-width: 900px) {
    .profile-header:has(> .profile-head-main),
    .profile-header.post-page-author:has(> .profile-media, > [data-profile-strip]) {
      display: grid; grid-template-columns: minmax(21rem, 1.2fr) minmax(0, 3fr);
      column-gap: 1.25rem; align-items: start;
    }
    .profile-header > .profile-media { margin-top: 1.25rem; min-width: 0; }
    .profile-header > .profile-media .profile-media-tile { aspect-ratio: 4 / 5; }
  }
  /* A video tile is the site's player (socialMedia.js), held to the
     tile's shape; in full screen it is the whole video again. Four classes
     deep so it outranks the post player's own sizing (socialMedia.css
     loads after this file). */
  .profile-header .profile-media .profile-media-tile.post-video { display: block; width: auto; max-width: none; max-height: none; margin: 0; background: #000;
    border-radius: var(--r-lg); border: 1px solid var(--sx-edge, var(--c-border, #e2e8f0)); }
  .profile-header .profile-media .profile-media-tile.post-video video { width: 100%; height: 100%; max-width: none; max-height: none; object-fit: cover; }
  .profile-header .profile-media .profile-media-tile.post-video.is-full { border: 0; border-radius: 0; }
  .profile-header .profile-media .profile-media-tile.post-video.is-full video { object-fit: contain; }
  /* Choosing them: three places, then a search of your Cloud. */
  .pm-slots { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 0.5rem; }
  .pm-slot {
    position: relative; aspect-ratio: 4 / 3; overflow: hidden; border-radius: var(--r-md);
    background: var(--c-surface-subtle, #f8fafc); border: 1px solid var(--c-border, #e2e8f0);
  }
  .pm-slot img { display: block; width: 100%; height: 100%; object-fit: cover; }
  .pm-slot.is-empty { display: grid; place-items: center; border-style: dashed; color: var(--c-text-dim, #94a3b8); font-size: 0.8rem; }
  .pm-remove {
    position: absolute; top: 0.3rem; right: 0.3rem; width: 1.6rem; height: 1.6rem; padding: 0;
    display: grid; place-items: center; border: 0; border-radius: var(--r-round); box-shadow: none;
    background: color-mix(in srgb, #000 60%, transparent); color: #fff; font-size: 1rem; line-height: 1; cursor: pointer;
  }
  .pm-results {
    display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: 0.4rem;
    max-height: min(40vh, 320px); overflow-y: auto;
  }
  .pm-pick {
    position: relative; display: block; aspect-ratio: 1; padding: 0; overflow: hidden; cursor: pointer;
    border: 2px solid transparent; border-radius: var(--r-md); background: var(--c-surface-subtle, #f8fafc); box-shadow: none;
  }
  .pm-pick img { display: block; width: 100%; height: 100%; object-fit: cover; }
  .pm-pick.is-picked { border-color: var(--c-brand, #6366f1); }
  .pm-pick.is-picked::after {
    content: '\2713'; position: absolute; top: 0.25rem; right: 0.25rem; width: 1.3rem; height: 1.3rem;
    display: grid; place-items: center; border-radius: var(--r-round); font-size: 0.75rem;
    background: var(--c-brand, #6366f1); color: var(--c-on-brand, #fff);
  }
  .profile-head-row { display: flex; align-items: flex-start; gap: 1.1rem; }
  .profile-head-row .profile-avatar-wrap { flex: none; }
  .profile-identity { flex: 1 1 auto; min-width: 0; padding-top: 0.85rem; }
  .profile-head-rest { margin-top: 0.35rem; }
  .profile-head-rest .pp-headline { line-height: 1.6; }
  .profile-name { font-size: 1.25rem; font-weight: 800; color: var(--c-text, #0f172a); }
  .profile-username { color: var(--c-text-dim, #94a3b8); font-size: 0.875rem; }
  .profile-bio { color: var(--c-text-muted, #475569); font-size: 0.875rem; margin-top: 0.5rem; line-height: 1.6; }
  .profile-meta { display: flex; gap: 1.25rem; margin-top: 0.5rem; font-size: 0.8rem; color: var(--c-text-dim, #94a3b8); flex-wrap: wrap; }
  .profile-meta-item { display: flex; align-items: center; gap: 0.3rem; }
  .profile-stats { display: flex; gap: 1.5rem; margin-top: 0.75rem; }
  /* Only your own counts open a list (2026-10-01): someone else's are just numbers. */
  .profile-stat { cursor: default; text-align: center; }
  .profile-stat.is-clickable { cursor: pointer; }
  .profile-stat-num { font-weight: 800; font-size: 1.1rem; color: var(--c-text, #0f172a); display: block; }
  .profile-stat-label { font-size: 0.75rem; color: var(--c-text-dim, #94a3b8); }
  .profile-actions { display: flex; gap: 0.5rem; margin-top: 1rem; flex-wrap: wrap; }

  .btn-follow {
    background: linear-gradient(135deg, var(--c-brand, #6366f1), var(--c-brand-alt, #8b5cf6)); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); border: none;
    padding: 0.5rem 1.5rem; border-radius: var(--btn-radius, 8px); font-weight: 700; font-size: 0.875rem; cursor: pointer;
  }
  /* (338) A request waiting on a private member looks like Following. */
  .btn-follow.following, .btn-follow.requested { background: var(--c-surface, #ffffff); color: var(--c-brand, #6366f1); border: 1px solid var(--c-brand, #6366f1); }
  /* ⚠⚠ `gap` IS LOAD-BEARING HERE, NOT DECORATION. This is an
     inline-FLEX box, and the network rail's button is written
     `Open <span data-site-brand>...</span>` -- a bare text node beside an
     element. Flexbox makes that text node an anonymous flex item and
     STRIPS the whitespace at its edges, so the space between "Open" and
     the site's name did not exist at render time and the button read
     "OpenSensorium Events". The space is in the markup and always was;
     nothing but a gap can put it back, because there is no text node left
     to hold it. */
  .btn-secondary-pill {
    background: var(--c-surface-sunken, #f1f5f9); color: var(--c-text-muted, #475569); border: none; padding: 0.5rem 1.25rem;
    border-radius: var(--btn-radius, 8px); font-weight: 600; font-size: 0.875rem; cursor: pointer; text-decoration: none;
    display: inline-flex; align-items: center; gap: 0.35em;
  }

  .profile-tabs {
    display: flex; background: var(--c-surface, #ffffff); border-radius: var(--r-surface, var(--r-3xl)); margin-top: 1rem;
    overflow: hidden; box-shadow: 0 1px 3px color-mix(in srgb, var(--c-shadow, #000000) 8%, transparent);
  }
  .profile-tab {
    flex: 1; padding: 0.85rem; text-align: center; font-size: 0.875rem; font-weight: 600;
    color: var(--c-text-dim, #94a3b8); cursor: pointer; border: none; background: none;
    border-bottom: 2px solid transparent;
  }
  .profile-tab.active { color: var(--c-brand, #6366f1); border-bottom-color: var(--c-brand, #6366f1); }

  .post-card { background: var(--c-surface, #ffffff); border-radius: var(--r-surface, var(--r-3xl)); padding: 1.25rem; margin-top: 0.75rem; box-shadow: 0 1px 3px color-mix(in srgb, var(--c-shadow, #000000) 6%, transparent); }
  .post-header { display: flex; align-items: center; gap: 0.75rem; margin-bottom: 0.75rem; }
  .post-avatar { width: 40px; height: 40px; border-radius: var(--r-round); object-fit: cover; background: var(--c-border, #e2e8f0); flex-shrink: 0; }
  .post-meta { flex: 1; min-width: 0; }
  .post-author { font-weight: 700; font-size: 0.9rem; color: var(--c-text, #0f172a); text-decoration: none; }
  .post-time { font-size: 0.75rem; color: var(--c-text-dim, #94a3b8); }
  .post-body { font-size: 0.9rem; color: var(--c-text, #0f172a); line-height: 1.7; margin-bottom: 0.75rem; white-space: pre-wrap; word-break: break-word; }
  /* A blank line in a post (feed.js / profilePage.js / postPage.js turn a run
     of them into this): about half an empty line (Josh, 2026-09-30). */
  .post-body .post-gap { display: block; height: 0.8em; }
  .post-body a { color: var(--c-brand, #6366f1); text-decoration: none; }
  .post-image { display: block; width: 100%; height: auto; max-height: 640px; object-fit: contain; background: var(--c-surface-subtle, #f8fafc); border-radius: var(--r-xl); margin-bottom: 0.75rem; cursor: pointer; }
/* A post's video, at its OWN true shape -- no black bars (Josh,
   2026-09-26; superseded the clamped-ratio rule of 2026-09-22, which is
   exactly what was producing them). The base rule for the profile and
   the post's own page; socialMedia.css's more specific
   .post-video.lx-player wins once js/socialMedia.js has enhanced it,
   with the same sizing idea. See its comment for why. */
.post-video { position: relative; max-width: 100%; max-height: 80vh; margin: 0 auto 0.75rem; border-radius: var(--r-xl); overflow: hidden; background: #000;
  display: flex; justify-content: center; align-items: center; width: fit-content; }
.post-video video { display: block; width: auto; height: auto; max-width: 100%; max-height: 80vh; object-fit: contain; background: #000; }
/* More room for a taller video, never past the screen (Josh, 2026-09-26
   twice over -- see the full note in socialMedia.css beside its own copy
   of this rule, the one that actually wins once js/socialMedia.js has
   enhanced the player). .is-tall is set on .post-video itself,
   server-side or by socialMedia.js's enhance(). */
.post-video.is-tall, .post-video.is-tall video { max-height: 100vh; }
/* Desktop only, turned down again -- mobile "is fine" (Josh, 2026-09-26).
   Full note in socialMedia.css beside its own copy of this rule. */
@media (min-width: 421px) {
  .post-video.is-tall, .post-video.is-tall video { max-height: 85vh; }
}
.profile-gallery { display: grid; gap: 0.25rem; margin-bottom: 0.75rem; border-radius: var(--r-xl); overflow: hidden; grid-template-columns: 1fr 1fr; }
.profile-gallery.is-one { grid-template-columns: 1fr; }
.profile-gallery img { width: 100%; height: 100%; aspect-ratio: 1 / 1; object-fit: cover; display: block; cursor: pointer; }
.profile-gallery.is-one img { aspect-ratio: auto; height: auto; max-height: 640px; object-fit: contain; background: var(--c-surface-subtle, #f8fafc); }
  /* ⚠️ color, or the whole card is the browser's default #0000ee (Josh,
     2026-09-23: "the links are also too bright of a blue"). */
  .post-link-preview { border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-xl); overflow: hidden; margin-bottom: 0.75rem; text-decoration: none; display: block; color: var(--c-text, #0f172a); }
  .post-link-image { width: 100%; height: 160px; object-fit: cover; }
  .post-link-info { padding: 0.75rem; }
  /* ⚠️⚠️ ON DESKTOP THE CARD IS 80% OF THE ROW AND THE IMAGE IS SHOWN WHOLE
     (Josh, 2026-09-22). The image above is full width and 160px tall, which
     on a ~600px feed column crops an og:image -- drawn at 1.91:1 by every
     site that makes one -- to a ~4:1 strip, so the picture the page chose
     to be shared with was mostly cut away. At its own 1.91:1 it shows
     entire, the way Facebook and LinkedIn show a large link card. Phones
     keep the rules above. */
  @media (min-width: 768px) {
    .post-link-preview { width: 80%; margin-left: auto; margin-right: auto; }
    .post-link-image { height: auto; aspect-ratio: 1.91 / 1; }
  }
  .post-link-title { font-weight: 700; font-size: 0.875rem; color: var(--c-text, #0f172a); margin-bottom: 0.25rem; }
  .post-link-desc { font-size: 0.78rem; color: var(--c-text-muted, #64748b); line-height: 1.5; }
  .post-link-domain { font-size: 0.72rem; color: var(--c-text-dim, #94a3b8); margin-top: 0.35rem; }
  .post-repost-attribution { font-size: 0.78rem; color: var(--c-text-dim, #94a3b8); margin-bottom: 0.5rem; }
  .post-repost-original { border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-xl); padding: 0.85rem; margin-bottom: 0.75rem; }

  .post-reactions { display: flex; align-items: center; gap: 0.35rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
  .reaction-btn { display: inline-flex; align-items: center; gap: 0.25rem; padding: 0.3rem 0.6rem; border-radius: var(--btn-radius, 8px); border: 1px solid var(--c-border, #e2e8f0); background: var(--c-surface, #ffffff); cursor: pointer; font-size: 0.8rem; color: var(--c-text, #0f172a); }
  .reaction-btn.active { background: var(--c-brand-tint, #f5f3ff); border-color: var(--c-brand-border, #c4b5fd); }
  .reaction-btn .reaction-count { font-weight: 700; color: var(--c-brand, #6366f1); }
  .reaction-more-btn { padding: 0.3rem 0.6rem; border-radius: var(--btn-radius, 8px); border: 1px solid var(--c-border, #e2e8f0); background: var(--c-surface, #ffffff); cursor: pointer; font-size: 0.78rem; color: var(--c-text-dim, #94a3b8); }

  .post-actions { display: flex; gap: 0.5rem; padding-top: 0.75rem; border-top: 1px solid var(--c-surface-sunken, #f1f5f9); }
  .post-action-btn { display: flex; align-items: center; gap: 0.35rem; padding: 0.4rem 0.75rem; border-radius: var(--r-md); border: none; background: none; cursor: pointer; font-size: 0.8rem; color: var(--c-text-dim, #94a3b8); font-weight: 600; }

  .post-comments { margin-top: 0.75rem; border-top: 1px solid var(--c-surface-sunken, #f1f5f9); padding-top: 0.75rem; }
  .comment-item { display: flex; gap: 0.5rem; margin-bottom: 0.75rem; }
  .comment-avatar { width: 28px; height: 28px; border-radius: var(--r-round); object-fit: cover; flex-shrink: 0; }
  .comment-bubble { background: var(--c-surface-subtle, #f8fafc); border-radius: var(--r-xl); padding: 0.5rem 0.75rem; flex: 1; }
  .comment-author { font-weight: 700; font-size: 0.78rem; color: var(--c-text, #0f172a); }
  .comment-body { font-size: 0.82rem; color: var(--c-text-muted, #475569); line-height: 1.5; margin-top: 0.15rem; }
  .comment-time { font-size: 0.7rem; color: var(--c-text-dim, #94a3b8); margin-top: 0.25rem; }
  .comment-input-wrap { display: flex; gap: 0.5rem; align-items: center; margin-top: 0.5rem; }
  /* ⚠️ min-width: 0, OR THE POST BUTTON IS CRUSHED ON A PHONE (Josh,
     2026-09-22). A flex item will not shrink below its intrinsic width, and
     an <input>'s is about 20 characters -- at the 16px every input is forced
     to on mobile (so iOS does not zoom), that is ~200px, which left the
     button whatever scraps remained. */
  .comment-input { flex: 1 1 auto; min-width: 0; border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-6xl); padding: 0.5rem 0.85rem; font-size: 0.82rem; outline: none; }
  .comment-submit { flex: 0 0 auto; white-space: nowrap; background: var(--c-brand, #6366f1); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); border: none; padding: 0.5rem 0.85rem; border-radius: var(--btn-radius, 8px); font-size: 0.78rem; font-weight: 600; cursor: pointer; }

  .compose-card { background: var(--c-surface, #ffffff); border-radius: var(--r-surface, var(--r-3xl)); padding: 1rem; margin-top: 0.75rem; box-shadow: 0 1px 3px color-mix(in srgb, var(--c-shadow, #000000) 6%, transparent); }
  .compose-input { width: 100%; border: none; outline: none; font-size: 0.95rem; resize: none; font-family: inherit; color: var(--c-text, #0f172a); min-height: 60px; background: transparent; }
  .compose-toolbar { display: flex; align-items: center; gap: 0.5rem; padding-top: 0.75rem; border-top: 1px solid var(--c-surface-sunken, #f1f5f9); margin-top: 0.5rem; }
  .compose-tool-btn { background: none; border: none; padding: 0.4rem; cursor: pointer; color: var(--c-text-dim, #94a3b8); border-radius: var(--r-sm); font-size: 1rem; }
  .compose-visibility { margin-left: auto; }
  .compose-visibility select { border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-md); padding: 0.35rem 0.6rem; font-size: 0.78rem; color: var(--c-text-muted, #475569); background: var(--c-surface, #ffffff); cursor: pointer; }
  .compose-submit { background: linear-gradient(135deg, var(--c-brand, #6366f1), var(--c-brand-alt, #8b5cf6)); color: var(--c-on-brand, var(--c-on-accent, #ffffff)); border: none; padding: 0.5rem 1.25rem; border-radius: var(--btn-radius, 8px); font-weight: 700; font-size: 0.875rem; cursor: pointer; }
  .compose-submit:disabled { opacity: 0.5; cursor: not-allowed; }
  .compose-image-preview { width: 100%; max-height: 200px; object-fit: cover; border-radius: var(--r-xl); margin-top: 0.5rem; display: none; }
  .compose-link-preview { border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-xl); overflow: hidden; margin-top: 0.5rem; display: none; }

  .private-overlay { position: fixed; inset: 0; background: color-mix(in srgb, var(--c-surface, #ffffff) 97%, transparent); display: flex; align-items: center; justify-content: center; z-index: 50; }
  .private-overlay-content { text-align: center; max-width: 400px; padding: 2rem; }

  .emoji-picker-overlay, .app-modal-overlay { position: fixed; inset: 0; z-index: 10000; background: color-mix(in srgb, var(--c-scrim, #000000) 45%, transparent); display: flex; align-items: center; justify-content: center; padding: 1rem; }
  .emoji-picker { background: var(--c-surface, #ffffff); border-radius: var(--r-3xl); padding: 1rem; width: 320px; max-height: 400px; overflow-y: auto; box-shadow: 0 20px 60px color-mix(in srgb, var(--c-shadow, #000000) 20%, transparent); }
  /* Twice the old 320px on desktop; the phone rule below still wins there. */
  .app-modal { background: var(--c-surface, #ffffff); border-radius: var(--r-3xl); padding: 1.25rem; width: min(640px, 92vw); max-height: 80vh; overflow-y: auto; box-shadow: 0 20px 60px color-mix(in srgb, var(--c-shadow, #000000) 20%, transparent); }
  .emoji-picker-search { width: 100%; padding: 0.5rem 0.75rem; border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-md); font-size: 0.875rem; margin-bottom: 0.75rem; outline: none; }
  .emoji-grid { display: grid; grid-template-columns: repeat(8, 1fr); gap: 0.25rem; }
  .emoji-btn { background: none; border: none; font-size: 1.25rem; padding: 0.35rem; cursor: pointer; border-radius: var(--r-sm); text-align: center; color: var(--c-text, #0f172a); }
  .emoji-btn:hover { background: var(--c-brand-tint, #f5f3ff); }

  .reactions-modal { background: var(--c-surface, #ffffff); border-radius: var(--r-3xl); padding: 1.25rem; width: 360px; max-height: 500px; overflow-y: auto; box-shadow: 0 20px 60px color-mix(in srgb, var(--c-shadow, #000000) 20%, transparent); }
  .reaction-user-item { display: flex; align-items: center; gap: 0.75rem; padding: 0.5rem 0; border-bottom: 1px solid var(--c-surface-sunken, #f1f5f9); }
  .reaction-user-avatar { width: 32px; height: 32px; border-radius: var(--r-round); object-fit: cover; }

  .app-modal label { font-size: 0.78rem; font-weight: 600; color: var(--c-text-muted, #475569); display: block; margin-bottom: 0.3rem; }
  .app-modal input, .app-modal textarea, .app-modal select { width: 100%; padding: 0.6rem; border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-md); font-size: 0.875rem; margin-bottom: 0.85rem; font-family: inherit; }

  @media (max-width: 640px) {
    .profile-stats { gap: 1rem; }
    .emoji-grid { grid-template-columns: repeat(6, 1fr); }
    .reactions-modal, .emoji-picker, .app-modal { width: 90vw; }
  }

/* ── One post's page (src/services/postPage.js) ──────────────────── */
.post-page-cover { height: 200px; }
/* A post's page and a chosen picture's page write the profile's own
   header markup (postPage.authorHeader), so the profile's rules above
   style them; only the name being a link is theirs. */
/* The "…" after a bio cut at 180 characters: a link to the About tab. */
.profile-bio .profile-bio-more { padding: 0 0.15em; color: var(--c-brand, #6366f1); font-weight: 700; text-decoration: none; border-radius: var(--r-xs); }
.profile-bio .profile-bio-more:hover, .profile-bio .profile-bio-more:focus-visible { background: color-mix(in srgb, var(--c-brand, #6366f1) 12%, transparent); }
.post-page-author .profile-name a { color: inherit; text-decoration: none; }
.post-page-author a.profile-stat { color: inherit; text-decoration: none; }
.post-page-body { max-width: 760px; margin: 1.25rem auto 0; }
.post-page-visibility { margin: 0 0 0.5rem; }
.post-page-more { margin: 1rem 0.25rem 0; }
.post-static .post-handle { color: var(--c-text-dim, #94a3b8); font-size: 0.78rem; margin-left: 0.25rem; }
.post-static .post-body a { color: var(--c-brand, #6366f1); text-decoration: none; }
.post-static .post-gallery { display: grid; gap: 0.35rem; margin-bottom: 0.75rem; }
.post-static .post-gallery img { width: 100%; border-radius: var(--r-lg); object-fit: cover; }
.post-static .post-gallery-1 { grid-template-columns: 1fr; }
.post-static .post-gallery-2, .post-static .post-gallery-4 { grid-template-columns: 1fr 1fr; }
.post-static .post-gallery-3 { grid-template-columns: 1fr 1fr 1fr; }
.post-static-note { margin: 0.5rem 0 0; }
.post-view-link { text-decoration: none; margin-left: auto; }
@media (max-width: 899px) {
  .post-page-cover { height: 140px; }
}

/* ── The site calendar (public/calendar.html) ─────────────────────── */
/*
 * ⚠️ THE GRID ITSELF IS style.css's `.cal-*`, reused rather than copied:
 * this page loads that stylesheet, and a second month grid would be a
 * second set of rules to keep in step for no gain. Only what is specific
 * to the PUBLIC page is here -- the chips in a square and the list rows,
 * which link out to an event page rather than opening an editor.
 */
.sitecal-head {
  display: flex; align-items: center; justify-content: space-between;
  gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.75rem;
}
.sitecal-card .cal-grid-wrap { margin: 0; }

/* The head's right-hand controls. `margin-left: auto` rather than leaning
   on the flex `space-between`, because in LIST VIEW the month nav is
   hidden and this is the only child left -- with space-between alone it
   would jump to the left edge as the toggle was pressed. */
.sitecal-head-actions {
  display: flex; align-items: center; gap: 0.5rem;
  flex-wrap: wrap; margin-left: auto;
}

/* ⚠️ The truncation note, and it is MUTED rather than a warning colour:
   "there are more further out" is a fact about the list's length, not a
   problem anybody has to solve. */
.sitecal-capped { margin: 0.75rem 0 0; font-size: 0.78rem; }

/* ⚠️⚠️ AN AUTHOR `display` RULE BEATS THE UA STYLESHEET'S
   [hidden]{display:none} AT ANY SPECIFICITY, and that is what shipped:
   the list view set `hidden` on all three month controls, the grid
   vanished, and `‹ September 2026 ›` and `Today` stayed on screen -- so
   the page opened looking like a month view with a list under it, and
   the two buttons that were still there did nothing anybody could see.

     .cal-grid-wrap   no display rule     -> hidden worked
     .cal-nav         display: inline-flex -> hidden DEFEATED
     button           display: inline-flex -> hidden DEFEATED

   Eighth instance in this codebase -- .myai-save-bar, .email-ed,
   .email-merge-panel, .email-preview-inline, .composer-actions,
   .send-countdown, .send-test-panel and .campaign-rate-row each carry
   the same two words beside them.

   ⚠️ SCOPED TO THE CARD RATHER THAN NAMED ONE BY ONE, so a control added
   to this head later is covered without anybody remembering. (0,2,0)
   beats `.cal-nav` and `button` on specificity, so it does not depend on
   which stylesheet loads last. */
.sitecal-card [hidden] { display: none; }

/* ⚠️ In list view the grid card keeps only its head bar, so the margin
   under it would leave a gap with nothing above it. Collapsed when the
   grid is away, by asking whether the grid is hidden rather than by a
   class on the body -- one fact, read where it is true. */
.sitecal-head:has(+ #sitecal-gridwrap[hidden]) { margin-bottom: 0; }

.sitecal-chip {
  display: block; font-size: 0.7rem; line-height: 1.3;
  padding: 0.1rem 0.3rem; margin-top: 0.15rem; border-radius: var(--r-xs);
  background: var(--c-brand-tint, #f5f3ff); color: var(--c-brand-deep, #4338ca);
  text-decoration: none; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.sitecal-chip:hover { background: var(--c-violet-tint-2, #ede9fe); }
/* ⚠️ The star carries the meaning as well as the colour -- "you are
   going" must not be colour alone, which is invisible in forced colours
   and to a good number of readers. Same rule as the SMS Available pill. */
.sitecal-chip.is-mine {
  background: var(--c-success-tint, #dcfce7); color: var(--c-success-text, #166534);
  font-weight: 600;
}
.sitecal-chip.is-off { text-decoration: line-through; opacity: 0.7; }

.sitecal-row {
  display: flex; gap: 0.85rem; align-items: flex-start;
  padding: 0.7rem 0.2rem; text-decoration: none; color: inherit;
  border-bottom: 1px solid var(--c-border, #e2e8f0);
}
.sitecal-row:last-child { border-bottom: none; }
.sitecal-row:hover { background: var(--c-surface-subtle, #f8fafc); }
.sitecal-row-when {
  flex: 0 0 11rem; font-size: 0.78rem; font-weight: 600;
  color: var(--c-text-muted, #64748b);
}
.sitecal-row-main { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
.sitecal-row.is-off .sitecal-row-main strong { text-decoration: line-through; }

.sitecal-tag {
  display: inline-block; align-self: flex-start;
  font-size: 0.68rem; font-weight: 600; padding: 0.05rem 0.4rem;
  border-radius: var(--r-lg); margin-top: 0.1rem;
}
.sitecal-tag.is-mine { background: var(--c-success-tint, #dcfce7); color: var(--c-success-text, #166534); }
.sitecal-tag.is-off { background: var(--c-danger-tint, #fee2e2); color: var(--c-danger, #dc2626); }

@media (max-width: 560px) {
  /* ⚠️⚠️ THE CHIPS BECOME DOTS. THEY USED TO BECOME NOTHING.
     A 7-column grid at phone width gives each square about 44px, which
     cannot hold a title -- so this was `display: none`, and every square
     in the month then looked exactly alike. The grid could no longer
     answer the one question it is FOR, which is which days have something
     on them; "the list underneath names them" was true and did not help
     anybody looking at the grid.

     44px cannot hold a title. It can hold a MARK. The list still names
     them, and siteCalendar.js opens a phone on that list -- this is what
     the reader sees when they go back to the month. */
  .sitecal-card .cal-cell {
    min-height: 3rem;
    /* Row-wrap so the marks flow along under the date rather than
       stacking one per line and pushing the square open. */
    flex-flow: row wrap;
    align-content: flex-start;
    gap: 3px;
    padding: 0.25rem 0.2rem;
  }
  /* ⚠️⚠️ A ZERO-HEIGHT SPACER IS WHAT BREAKS THE LINE, not
     `flex: 0 0 100%` on the date. The date is ALSO the today marker -- a
     filled circle 1.35rem across -- and stretching it to the width of the
     square turns that circle into a bar right across the cell. So it keeps
     its natural size, and an ::before ordered BETWEEN it and the marks
     takes a whole line and no height. */
  .sitecal-card .cal-cell::before {
    content: ''; order: 1; flex: 0 0 100%; height: 0;
  }
  .sitecal-card .cal-day-num { order: 0; }
  /* ⚠️ `font-size: 0` RATHER THAN REMOVING THE TEXT. The chip is still
     a link to the event and still carries its title, so a screen reader
     reads exactly what it read before; only the sighted presentation
     collapses. Dropping the text would have made the grid emptier for a
     reader who cannot see the dot in the first place. */
  .sitecal-chip {
    order: 2;
    display: flex; align-items: center; justify-content: center;
    flex: 0 0 auto; width: 8px; height: 8px;
    margin: 0; padding: 0; border-radius: var(--r-round);
    font-size: 0; line-height: 0; overflow: hidden;
    background: var(--c-brand, #6366f1);
  }
  /* ⚠️⚠️ THE STAR SURVIVES THE COLLAPSE, AND THAT IS THE POINT.
     "You are going" must not be carried by colour alone -- the rule the
     full-size chip already follows, and the reason it has a ★ beside the
     title at all. Two dots that differ only in hue would have quietly
     dropped that on the one screen where the label is gone too. So the
     mark for `is-mine` is a different SHAPE: the star itself, at the size
     the dot would have been. */
  .sitecal-chip.is-mine {
    width: 10px; height: 10px;
    background: none; overflow: visible;
    color: var(--c-success-text, #166534);
  }
  .sitecal-chip.is-mine > span { font-size: 10px; line-height: 1; }
  /* Cancelled is a shape too: a hollow ring. A line through an 8px dot
     is a line through nothing. */
  .sitecal-chip.is-off {
    width: 9px; height: 9px;
    background: none; opacity: 1;
    border: 1.5px solid var(--c-text-dim, #94a3b8);
    text-decoration: none;
  }
  /* ⚠️ SCOPED, because `.cal-more` is the APP calendar's class too and
     an unscoped rule here would reach a grid this file is not about.
     "+2 more" is a phrase in a 44px box; the marks already say there is
     more than one, and the list gives the count. */
  .sitecal-card .cal-more { display: none; }

  .sitecal-row { flex-direction: column; gap: 0.2rem; }
  .sitecal-row-when { flex: none; }
}

/* ── Linxi Cloud ─────────────────────────────────────────────────────
   ⚠️ EVERY TOKEN CARRIES A FALLBACK. A bare var(--x) on a token nothing
   declares is invalid at computed-value time and does NOTHING, silently
   -- CLAUDE.md lists five that shipped that way. The fallback is what
   makes these render on a deployment whose theme has not set them. */
.cloud-panel { display: flex; flex-direction: column; gap: 0.9rem; }
.cloud-head { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; }
.cloud-head h3 { font-size: 0.95rem; font-weight: 700; margin: 0; }
.cloud-actions { display: flex; gap: 0.5rem; }

.cloud-quota { display: flex; flex-direction: column; gap: 0.3rem; }
.cloud-quota-bar { height: 0.4rem; border-radius: var(--r-xs); overflow: hidden; background: var(--c-surface-2, #e2e8f0); }
.cloud-quota-bar span { display: block; height: 100%; background: var(--c-accent, #6366f1); }
.cloud-quota small { color: var(--c-text-dim, #94a3b8); font-size: 0.75rem; }

.cloud-crumbs { display: flex; align-items: center; flex-wrap: wrap; gap: 0.25rem; font-size: 0.8rem; }
.cloud-crumb { background: none; border: none; padding: 0.15rem 0.25rem; cursor: pointer; color: var(--c-accent, #6366f1); border-radius: var(--r-xs); }
.cloud-crumb-sep { color: var(--c-text-dim, #94a3b8); }

/* The upload queue (2026-10-03): one panel for the page, bottom right,
   that stays while you move between folders. */
.cloud-q { position: fixed; right: 1rem; bottom: 1rem; z-index: 9000; width: min(24rem, calc(100vw - 2rem)); max-height: min(70vh, 34rem);
  display: flex; flex-direction: column; gap: 0.5rem; padding: 0.8rem 0.9rem; box-sizing: border-box;
  background: var(--c-surface, #fff); color: var(--c-text, #0f172a); border: 1px solid var(--c-border, #e2e8f0);
  border-radius: var(--r-surface, var(--r-xl, 14px)); box-shadow: 0 18px 40px -18px rgba(15, 23, 42, 0.45); }
.cloud-q-head { display: grid; grid-template-columns: minmax(0, 1fr) auto; gap: 0 0.5rem; align-items: center; }
.cloud-q-head strong { font-size: 0.95rem; }
.cloud-q-sub { grid-column: 1; font-size: 0.78rem; color: var(--c-text-muted, #64748b); }
.cloud-q-x { grid-column: 2; grid-row: 1 / span 2; min-width: 0; min-height: 0; width: 2rem; height: 2rem; padding: 0; border-radius: var(--r-round, 999px);
  border: 1px solid var(--c-border, #e2e8f0); background: var(--c-surface, #fff); color: inherit; cursor: pointer; box-shadow: none; }
.cloud-q-bar, .cloud-q-mini { height: 6px; border-radius: var(--r-pill, 999px); background: color-mix(in srgb, var(--c-text-muted, #64748b) 18%, transparent); overflow: hidden; }
.cloud-q-mini { height: 4px; margin-top: 0.25rem; }
.cloud-q-bar span, .cloud-q-mini span { display: block; height: 100%; background: var(--c-brand, #6366f1); transition: width 0.2s ease; }
.cloud-q-note { margin: 0; font-size: 0.78rem; color: var(--c-warning-text, #b45309); }
.cloud-q-list { overflow: auto; display: flex; flex-direction: column; min-height: 0; }
.cloud-q-row { padding: 0.4rem 0; border-top: 1px dashed var(--c-border, #e2e8f0); font-size: 0.82rem; }
.cloud-q-rowtop { display: flex; justify-content: space-between; gap: 0.5rem; }
.cloud-q-name { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.cloud-q-state { flex: none; color: var(--c-text-muted, #64748b); font-variant-numeric: tabular-nums; }
.cloud-q-row.is-done .cloud-q-state { color: var(--c-success-text, #15803d); font-weight: 700; }
.cloud-q-row.is-failed .cloud-q-state, .cloud-q-row.is-failed .cloud-q-msg { color: var(--c-danger-text, #b91c1c); font-weight: 700; }
.cloud-q-msg { display: block; color: var(--c-text-muted, #64748b); font-size: 0.75rem; overflow-wrap: anywhere; }
.cloud-q-acts { display: flex; gap: 0.5rem; justify-content: flex-end; flex-wrap: wrap; }
@media (max-width: 560px) { .cloud-q { right: 0.5rem; left: 0.5rem; bottom: 0.5rem; width: auto; } }

.cloud-drop {
  border: 1px dashed var(--c-border, #cbd5e1); border-radius: var(--r-surface, var(--r-lg));
  padding: 1rem; text-align: center; font-size: 0.8rem;
  color: var(--c-text-dim, #94a3b8); cursor: pointer;
}
.cloud-drop-over { border-color: var(--c-accent, #6366f1); background: var(--c-surface-2, #f1f5f9); }

.cloud-grid { display: grid; gap: 0.6rem; }
.cloud-grid-folders { grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }
.cloud-grid-files { grid-template-columns: repeat(auto-fill, minmax(120px, 1fr)); }

.cloud-folder, .cloud-file {
  display: flex; flex-direction: column; gap: 0.2rem; text-align: left;
  padding: 0.6rem; border-radius: var(--r-lg); cursor: pointer;
  border: 1px solid var(--c-border, #e2e8f0);
  background: var(--c-surface, #fff); color: var(--c-text, #0f172a);
}
.cloud-folder:hover, .cloud-file:hover { border-color: var(--c-accent, #6366f1); }
/* The site's Google Drive in Cloud (305): a file is a link out to Drive. */
a.cloud-folder { color: inherit; text-decoration: none; align-items: center; text-align: center; }
.cloud-folder-icon img { display: block; width: 16px; height: 16px; }
/* ⚠️ THE FOLDER ICON IS A SQUARE TILE, matching .cloud-thumb below rather
   than sitting as a stray glyph above the name. Folders and files appear
   in the same view, one grid under the other, and a 1.4rem emoji beside a
   full-width square thumbnail made the two read as different components
   rather than two kinds of the same thing.

   aspect-ratio + place-items does the centring; line-height:1 stops the
   emoji's own font metrics adding a lopsided gap under it, which is what
   makes a large emoji look badly centred rather than actually being so. */
.cloud-folder-icon {
  width: 100%;
  aspect-ratio: 1;
  display: grid;
  place-items: center;
  line-height: 1;
  font-size: 3rem;
  border-radius: var(--r-sm);
  background: var(--c-surface-2, #f1f5f9);
}
.cloud-folder-name, .cloud-file-name {
  font-size: 0.8rem; font-weight: 600;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  min-width: 0; max-width: 100%;
}
/* ⚠️ A TILE IS A <button>, and buttons site-wide keep a label-sized
   minimum width (min 10rem -- "buttons never full width"). In a 120px
   grid column that made each tile wider than its cell, so tiles overlapped
   and the names above ran out of them (2026-10-02, a gallery of three).
   A tile is a card, not a labelled button: it is exactly its cell. */
.cloud-grid .cloud-folder, .cloud-grid .cloud-file { min-width: 0; max-width: none; width: 100%; }
.cloud-folder-meta, .cloud-file-meta { font-size: 0.7rem; color: var(--c-text-dim, #94a3b8); }

.cloud-thumb { width: 100%; aspect-ratio: 1; object-fit: cover; border-radius: var(--r-sm); background: var(--c-surface-2, #f1f5f9); }
/* A video has no poster frame on this install, so it gets a mark rather
   than a broken <img> -- unknown must not render as damaged. */
.cloud-thumb-none { display: grid; place-items: center; font-size: 1.6rem; }

.cloud-status { font-size: 0.75rem; color: var(--c-text-dim, #94a3b8); min-height: 1rem; margin: 0; }
.cloud-status-bad { color: var(--c-danger, #dc2626); }
.cloud-empty-line { font-size: 0.8rem; color: var(--c-text-dim, #94a3b8); }
.cloud-loading { padding: 1.5rem; text-align: center; color: var(--c-text-dim, #94a3b8); font-size: 0.85rem; }

/* ⚠️ The .modal sits INSIDE .modal-overlay and carries no positioning of
   its own; the overlay is the band at z-index 1300. */
/* ⚠️ max-width: none, OR THE WIDTH NEVER APPLIES. Every .modal is capped at
   400px (style.css), and this set a width without lifting that cap -- so
   the picker was a 400px column on a desktop (Josh, 2026-09-23). */
.cloud-picker { width: min(1040px, 94vw); max-width: none; max-height: 86vh; overflow: auto; padding: 1.25rem; }
.cloud-picker-head { display: flex; align-items: center; justify-content: space-between; margin-bottom: 0.75rem; }
.cloud-picker-head h3 { margin: 0; font-size: 0.95rem; font-weight: 700; }
.cloud-picker-close { background: none; border: none; font-size: 1.4rem; line-height: 1; cursor: pointer; color: var(--c-text-dim, #94a3b8); }

.compose-cloud-chips { display: flex; flex-wrap: wrap; gap: 0.35rem; margin-bottom: 0.4rem; }
.compose-cloud-chip {
  display: inline-flex; align-items: center; gap: 0.3rem;
  font-size: 0.72rem; padding: 0.15rem 0.45rem; border-radius: var(--r-xl);
  background: var(--c-surface-2, #f1f5f9); color: var(--c-text-3, #475569);
}
.compose-cloud-drop { background: none; border: none; cursor: pointer; color: var(--c-text-dim, #94a3b8); font-size: 0.85rem; line-height: 1; padding: 0; }

/* The folder name + privacy dialog. Native to the site rather than
   window.prompt, which cannot carry a second field or explain what each
   privacy setting means. */
.cloud-dialog { width: min(440px, 94vw); padding: 1.25rem; }
.cloud-dialog h3 { margin: 0 0 0.9rem; font-size: 1rem; font-weight: 700; }
.cloud-dialog-label { font-size: 0.78rem; font-weight: 600; margin: 0 0 0.3rem; color: var(--c-text-3, #475569); }
.cloud-dialog-input {
  width: 100%; padding: 0.55rem 0.7rem; border-radius: var(--r-md);
  border: 1px solid var(--c-border, #cbd5e1);
  background: var(--c-surface, #fff); color: var(--c-text, #0f172a);
  font-size: 0.9rem; margin-bottom: 1rem;
}
.cloud-dialog-input:focus { outline: 2px solid var(--c-accent, #6366f1); outline-offset: 1px; }

.cloud-vis-list { display: flex; flex-direction: column; gap: 0.4rem; margin-bottom: 0.75rem; }
/* ⚠️ A GRID, NOT A FLEX ROW. The radio sits in column one and both lines
   of text share column two, so the note aligns under the label instead of
   under the radio. A flex row would also eat the whitespace between the
   mark and the label. */
.cloud-vis {
  display: grid; grid-template-columns: auto 1fr; gap: 0.15rem 0.6rem;
  align-items: start; padding: 0.55rem 0.65rem; cursor: pointer;
  border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-md);
}
.cloud-vis:hover { border-color: var(--c-accent, #6366f1); }
.cloud-vis input { grid-row: 1 / span 2; margin-top: 0.2rem; }
.cloud-vis-main { font-size: 0.85rem; font-weight: 600; color: var(--c-text, #0f172a); }
.cloud-vis-note { font-size: 0.74rem; color: var(--c-text-dim, #94a3b8); }
.cloud-vis:has(input:checked) { border-color: var(--c-accent, #6366f1); background: var(--c-surface-2, #f1f5f9); }

.cloud-dialog-hint { font-size: 0.74rem; color: var(--c-text-dim, #94a3b8); margin: 0 0 0.6rem; }
/* Hidden until it has something to say -- an empty red line under a form
   reads as an error nobody can name. */
.cloud-dialog-error { font-size: 0.78rem; color: var(--c-danger, #dc2626); margin: 0 0 0.6rem; display: none; }
.cloud-dialog-error.is-shown { display: block; }
.cloud-dialog-actions { display: flex; justify-content: flex-end; gap: 0.5rem; }

.cloud-folder-wrap { position: relative; }
.cloud-folder-wrap .cloud-folder { width: 100%; }
.cloud-folder-gear {
  position: absolute; top: 0.35rem; right: 0.35rem;
  background: none; border: none; cursor: pointer; line-height: 1;
  padding: 0.15rem 0.3rem; border-radius: var(--r-xs);
  color: var(--c-text-dim, #94a3b8); font-size: 1rem;
}
.cloud-folder-gear:hover { background: var(--c-surface-2, #f1f5f9); color: var(--c-text, #0f172a); }

/* One file on its own, inside the Cloud viewer.

   ⚠️ max-height IS CAPPED IN VIEWPORT UNITS, not left to the image. A
   500×500 logo and a 6000px photo arrive through the same tag; without
   the cap the second one pushes the name, the size and every control
   below the fold, so the page opens on a wall of pixels with no way to
   tell what you are looking at or get back. contain keeps the aspect
   ratio while the cap does the work. */
.cloud-media-el {
  display: block;
  width: 100%;
  max-height: 70vh;
  object-fit: contain;
  border-radius: var(--r-md);
  background: var(--c-surface-sunken, #f1f5f9);
}
.cloud-media-meta { margin-top: 0.9rem; }
.cloud-media-meta h3 { margin: 0 0 0.2rem; font-size: 1rem; word-break: break-word; }
/* ⚠️ pre-wrap, NOT <br> INJECTION. The description is owner-typed and is
   escaped on the way in; turning its newlines into markup would mean
   emitting tags built from that text, which is the one thing that must
   not happen. CSS keeps the line breaks without any of that. */
.cloud-media-desc {
  margin: 0 0 0.5rem;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--c-text, #0f172a);
  font-size: 0.9rem;
}
/* The edit dialogue's textarea, matching .cloud-dialog-input's box. */
.cloud-dialog-area { resize: vertical; min-height: 5rem; font: inherit; }
.cloud-media-meta p {
  margin: 0 0 0.75rem;
  font-size: 0.82rem;
  color: var(--c-text-dim, #94a3b8);
}
/* The current crumb is the file, and it is not a link. */
.cloud-crumb.is-current {
  color: var(--c-text, #0f172a);
  font-weight: 600;
  padding: 0.15rem 0.3rem;
}
/* ⚠️ The actions wrap rather than overflow: Download / Back / Delete on a
   narrow phone is wider than the screen, and a row that scrolls sideways
   hides Delete behind an edge nobody thinks to drag. */
.cloud-media .cloud-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }

/* The embeddable address. */
.cloud-embed { margin: 0.9rem 0; }
.cloud-embed-label {
  display: block; font-size: 0.75rem; font-weight: 600;
  color: var(--c-text-dim, #94a3b8); margin-bottom: 0.3rem;
}
.cloud-embed-row { display: flex; gap: 0.5rem; align-items: stretch; }
/* ⚠️ min-width:0 OR THE FLEX ITEM REFUSES TO SHRINK. An <input> has an
   intrinsic default width, and in a flex row that becomes a floor -- a
   long S3-shaped URL then pushes Copy off the right edge on a phone. */
.cloud-embed-input {
  flex: 1; min-width: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
  font-size: 0.75rem; padding: 0.4rem 0.55rem;
  border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-sm);
  background: var(--c-surface-sunken, #f1f5f9); color: var(--c-text, #0f172a);
}
.cloud-embed-warn {
  margin: 0.4rem 0 0; font-size: 0.75rem;
  color: var(--c-danger, #ef4444);
}

/* Delete, on a folder and on a file.

   ⚠️ IT SITS AWAY FROM THE GEAR, not beside it. The gear opens a dialogue
   somebody can cancel; this one destroys a folder and everything under
   it. Two controls of very different weight, a few pixels apart and both
   grey, is how a misclick happens -- so delete takes the LEFT corner,
   and turns red only on hover so the grid does not read as a row of
   warnings. .cloud-file-wrap exists for the same reason .cloud-folder-wrap
   does: the × must be a SIBLING of the tile button, never nested in it. */
/* ⚠️ THE WRAP IS NOW THE GRID ITEM, not the button. Without the width
   rule the tile collapses to its content and the files grid goes ragged
   -- the same pairing .cloud-folder-wrap already needed above. */
.cloud-file-wrap { position: relative; }
.cloud-file-wrap .cloud-file { width: 100%; }
.cloud-folder-del,
.cloud-file-del {
  position: absolute; top: 0.35rem; left: 0.35rem;
  background: none; border: none; cursor: pointer; line-height: 1;
  padding: 0.15rem 0.35rem; border-radius: var(--r-xs);
  color: var(--c-text-faint, #cbd5e1); font-size: 1rem;
  opacity: 0; transition: opacity 0.12s ease;
}
.cloud-folder-wrap:hover .cloud-folder-del,
.cloud-file-wrap:hover .cloud-file-del,
.cloud-folder-del:focus-visible,
.cloud-file-del:focus-visible { opacity: 1; }
.cloud-folder-del:hover,
.cloud-file-del:hover {
  background: var(--c-danger-tint, #fee2e2);
  color: var(--c-danger, #ef4444);
}
/* ⚠️ A hover-revealed control is unreachable on a touch screen, which has
   no hover. On coarse pointers it is simply always visible. */
@media (hover: none) {
  .cloud-folder-del, .cloud-file-del { opacity: 1; }
}


/* ── The list's event cards (2026-09-24) ──────────────────────────────
   The client's /upcoming card, in SILVER (Josh: "the color for edging I
   want to use with linxi is silver") and the site's own palette and
   fonts otherwise, so it belongs on every install. */
.sitecal-tiles { display: grid; gap: 1.75rem; }
.sc-card {
  /* ⚠️ THE THEME BORDERS FINISH, not a fixed silver (Josh, 2026-09-30: gold
     showed on the event page but not here). Website -> Theme -> Theme
     borders writes --ab-* into /theme.css; silver is only the fallback. */
  --sv-hi: var(--ab-hi, #ffffff); --sv-1: var(--ab-1, #eef1f5); --sv-2: var(--ab-2, #c9d1da);
  --sv-3: var(--ab-3, #9aa5b2); --sv-4: var(--ab-4, #6b7683); --sv-ink: var(--ab-ink, #4b5563);
  --sv-w: var(--ab-w, 1);
  position: relative; overflow: hidden; border-radius: var(--r-surface, var(--r-4xl)); background: var(--c-surface, #fff);
  border: 1px solid var(--sv-2);
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.08), 0 18px 48px -18px rgba(15, 23, 42, 0.35);
  animation: scIn 0.45s cubic-bezier(.22,.61,.36,1) both;
}
@keyframes scIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: none; } }
.sc-card.is-off { filter: grayscale(0.6); }
.sc-banner { position: relative; display: block; height: clamp(180px, 26vw, 300px); overflow: hidden;
  background: linear-gradient(135deg, var(--c-brand, #6366f1), var(--c-brand-alt, var(--c-brand-strong, #4f46e5))); }
.sc-banner.no-img { height: 140px; }
.sc-banner-img { display: block; width: 100%; height: 100%; object-fit: cover; object-position: center 35%; margin: 0; border-radius: 0;
  transition: transform 0.6s cubic-bezier(.22,.61,.36,1); }
.sc-card:hover .sc-banner-img { transform: scale(1.04); }
.sc-banner::after { content: ''; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(0,0,0,0.04) 0%, rgba(0,0,0,0.12) 55%, rgba(0,0,0,0.62) 100%); }
/* The date, a silver medallion. */
.sc-date { position: absolute; top: 0.9rem; right: 0.9rem; z-index: 2; display: flex; flex-direction: column; align-items: center; justify-content: center;
  width: 78px; height: 78px; border-radius: var(--r-round); line-height: 1; color: #1f2937;
  background: radial-gradient(circle at 30% 25%, var(--sv-hi), var(--sv-1) 45%, var(--sv-2) 100%);
  border: 2px solid var(--sv-3); box-shadow: 0 0 0 4px rgba(201, 209, 218, 0.45), inset 0 1px 0 #fff, 0 8px 20px rgba(0,0,0,0.35); }
.sc-date-m { font-size: 0.66rem; font-weight: 700; letter-spacing: 0.14em; text-transform: uppercase; color: var(--sv-4); }
.sc-date-d { font-size: 1.75rem; font-weight: 800; margin: 0.08rem 0; }
.sc-date-w { font-size: 0.55rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: var(--sv-4); }
.sc-city { position: absolute; left: 1.1rem; top: 1rem; z-index: 2; max-width: calc(100% - 2.2rem); overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
  padding: 0.38rem 0.85rem; border-radius: var(--r-pill); background: rgba(15, 23, 42, 0.5); border: 1px solid rgba(226, 232, 240, 0.7);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
  font-size: 0.72rem; font-weight: 600; letter-spacing: 0.1em; text-transform: uppercase; color: #f1f5f9; }
/* The poster, set into the card in a silver frame, over the banner. */
.sc-body { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: 1.75rem; padding: 0 1.75rem 1.75rem; }
.sc-card.no-poster .sc-body { grid-template-columns: minmax(0, 1fr); }
.sc-poster { position: relative; z-index: 3; display: block; align-self: start; margin-top: -84px; padding: 5px; border-radius: var(--r-2xl);
  background: linear-gradient(145deg, var(--sv-hi) 0%, var(--sv-2) 35%, var(--sv-3) 60%, var(--sv-1) 80%, var(--sv-3) 100%);
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.8), 0 14px 32px rgba(0,0,0,0.32);
  transition: transform 0.25s ease, box-shadow 0.25s ease; }
.sc-poster img { display: block; width: 100%; height: auto; margin: 0; border-radius: var(--r-md); box-shadow: inset 0 0 0 1px rgba(0,0,0,0.2); }
.sc-poster:hover { transform: translateY(-3px); box-shadow: inset 0 1px 0 rgba(255,255,255,0.8), 0 20px 40px rgba(0,0,0,0.38); }
.sc-text { padding-top: 1.35rem; min-width: 0; }
.sc-kicker { margin: 0 0 0.35rem; font-style: italic; font-size: 1.05rem; color: var(--c-brand-deep, var(--c-brand, #4f46e5)); }
/* ⚠️ .sc-card .sc-title: `.social-card h3` would otherwise shrink it to 0.95rem. */
.sc-card .sc-title { margin: 0 0 0.45rem; font-size: clamp(1.35rem, 2.6vw, 1.85rem); font-weight: 700; line-height: 1.18; }
.sc-title a { color: var(--c-text, #0f172a); text-decoration: none; }
.sc-title a:hover { color: var(--c-brand, #6366f1); }
.sc-meta { margin: 0 0 0.85rem; font-size: 0.84rem; font-weight: 600; letter-spacing: 0.02em; color: var(--c-brand, #6366f1); }
.sc-desc { margin: 0 0 1rem; font-size: 1rem; line-height: 1.6; color: var(--c-text-muted, #475569); }
.sc-tags { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0 0 1.25rem; padding: 0; list-style: none; }
.sc-tags li { margin: 0; padding: 0.32rem 0.75rem; border-radius: var(--r-pill); font-size: 0.74rem; font-weight: 500; letter-spacing: 0.03em;
  color: var(--sv-ink); background: linear-gradient(180deg, #fbfcfd, var(--sv-1)); border: 1px solid var(--sv-2); }
.sc-tags li::before { content: '✦ '; color: var(--sv-3); }
.sc-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 0.75rem 1.25rem; }
.sc-btn { display: inline-block; padding: 0.8rem 1.6rem; border-radius: var(--btn-radius, 8px); text-decoration: none;
  background: var(--btn-grad, var(--c-brand, #6366f1)); border: 1px solid var(--sv-2); color: var(--c-on-brand, #fff);
  font-size: 0.8rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase;
  box-shadow: inset 0 1px 0 rgba(255,255,255,0.25), 0 6px 16px -6px rgba(15,23,42,0.4); transition: transform 0.2s ease, box-shadow 0.2s ease; }
.sc-btn:hover { color: var(--c-on-brand, #fff); transform: translateY(-1px); box-shadow: inset 0 1px 0 rgba(255,255,255,0.25), 0 10px 22px -6px rgba(15,23,42,0.45); }
.sc-price { font-size: 0.98rem; font-weight: 700; color: var(--c-text, #0f172a); }
.sc-host { font-size: 0.8rem; color: var(--c-text-dim, #94a3b8); }
[data-theme="dark"] .sc-card { --sv-1: #2a323d; --sv-2: #4b5563; --sv-3: #8b95a3; --sv-ink: #d1d5db; border-color: #3a4350; }
[data-theme="dark"] .sc-tags li { background: linear-gradient(180deg, #2f3742, #262d36); }
@media (max-width: 720px) {
  .sc-body { grid-template-columns: 1fr; gap: 0; padding: 0 1.1rem 1.35rem; }
  .sc-poster { width: 160px; margin: -72px auto 0; }
  .sc-text { padding-top: 1.1rem; text-align: center; }
  .sc-tags, .sc-actions { justify-content: center; }
  .sc-date { width: 64px; height: 64px; }
  .sc-city { max-width: calc(100% - 6.5rem); }
  .sc-date-d { font-size: 1.4rem; }
}
@media (prefers-reduced-motion: reduce) {
  .sc-card { animation: none; }
  .sc-banner-img, .sc-poster, .sc-btn { transition: none; }
  .sc-card:hover .sc-banner-img { transform: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   THE SOCIAL SIDE, MODERNISED (2026-09-24)
   Josh: "all of the social media pages need a full upgrade ... a full UI
   update to modernize the social side of the site". One layer over
   everything above, scoped to body.social-body -- the Network, the Feed,
   the Calendar, every profile and a post's own page -- in the site's own
   colours: softer page, a taller cover, cards with a fine edge, a
   stronger author row, reactions as soft chips, a real action bar, a
   profile header with presence, and on a phone the feed before the rails.
   ══════════════════════════════════════════════════════════════════════ */
body.social-body {
  --sx-r: var(--r-4xl);
  --sx-edge: color-mix(in srgb, var(--c-border, #e2e8f0) 85%, transparent);
  --sx-shadow: 0 1px 2px rgba(15, 23, 42, 0.05), 0 12px 32px -20px rgba(15, 23, 42, 0.28);
  --sx-shadow-hi: 0 2px 4px rgba(15, 23, 42, 0.06), 0 20px 44px -22px rgba(15, 23, 42, 0.38);
  background:
    radial-gradient(1200px 500px at 50% -120px, color-mix(in srgb, var(--c-brand, #6366f1) 7%, transparent), transparent 70%),
    var(--c-page, #f4f5f7);
  -webkit-font-smoothing: antialiased;
}

/* ── The cover band ───────────────────────────────────────────────── */
body.social-body .social-cover { min-height: 250px; display: flex; align-items: stretch; }
body.social-body .social-cover::before { content: ''; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(2, 6, 23, 0.1) 0%, rgba(2, 6, 23, 0.35) 55%, rgba(2, 6, 23, 0.55) 100%); }
body.social-body .social-cover-inner { padding: 2.75rem 2rem 5rem; align-items: flex-end; }
body.social-body .social-cover h1 { font-size: clamp(1.75rem, 3vw, 2.6rem); font-weight: 800; letter-spacing: -0.02em; text-shadow: 0 2px 12px rgba(0, 0, 0, 0.3); }
body.social-body .social-cover p { font-size: 1rem; opacity: 0.92; text-shadow: 0 1px 6px rgba(0, 0, 0, 0.3); }
body.social-body .social-cover-actions a { border-radius: var(--r-pill); padding: 0.6rem 1.15rem; box-shadow: 0 6px 18px -8px rgba(0, 0, 0, 0.45); }

/* ── The shell and its cards ──────────────────────────────────────── */
body.social-body .social-shell { gap: 1.5rem; margin-top: -3rem; }
body.social-body .social-rail { top: 5rem; gap: 1.1rem; }
body.social-body .social-card, body.social-body .social-main .feed-toolbar, body.social-body .social-main .compose-card,
body.social-body .post-card, body.social-body .profile-editor {
  border-radius: var(--r-surface, var(--sx-r)); border: 1px solid var(--sx-edge); box-shadow: var(--sx-shadow); }
body.social-body .social-card { padding: 1.3rem 1.35rem; }
body.social-body .social-card h3 { font-size: 1.02rem; letter-spacing: -0.01em; }
body.social-body .network-section-header { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-bottom: 0.8rem;
  font-size: 0.72rem; font-weight: 800; letter-spacing: 0.12em; text-transform: uppercase; color: var(--c-text-muted, #64748b); }
body.social-body .social-quiet { font-size: 0.84rem; line-height: 1.6; }
body.social-body .social-join { background:
    radial-gradient(circle at 100% 0%, color-mix(in srgb, var(--c-brand, #6366f1) 12%, transparent), transparent 55%), var(--c-surface, #fff); }
body.social-body .social-join h3 { font-size: 1.15rem; line-height: 1.3; }

/* Buttons on these pages: rounded, one height, one weight. */
body.social-body .compose-submit, body.social-body .btn-secondary-pill, body.social-body .btn-follow,
body.social-body .social-join-actions a, body.social-body .network-add-btn {
  min-height: 2.5rem; padding: 0.55rem 1.2rem; border-radius: var(--r-pill); font-weight: 700; font-size: 0.86rem; }
body.social-body .btn-secondary-pill { background: var(--c-surface, #fff); color: var(--c-text-2, #334155); border: 1px solid var(--sx-edge); box-shadow: 0 1px 2px rgba(15, 23, 42, 0.05); }
body.social-body .btn-secondary-pill:hover { border-color: var(--c-brand, #6366f1); color: var(--c-brand, #6366f1); }

/* The feed's head: title left, a connected Latest / Top switch right. */
body.social-body .social-main .feed-toolbar { padding: 0.9rem 1.1rem 0.9rem 1.35rem; }
body.social-body .social-main .feed-toolbar h1, body.social-body .social-main .feed-toolbar h2 { font-size: 1.12rem; letter-spacing: -0.01em; }
body.social-body .feed-sort-group { display: inline-flex; gap: 0; padding: 3px; border-radius: var(--r-pill); background: var(--c-surface-subtle, #f1f5f9); border: 1px solid var(--sx-edge); }
body.social-body .feed-sort-btn { margin: 0; min-height: 0; padding: 0.4rem 0.95rem; border-radius: var(--r-pill); border: 0; background: transparent;
  box-shadow: none; color: var(--c-text-muted, #64748b); font-weight: 700; font-size: 0.8rem; }
body.social-body .feed-sort-btn:hover { background: transparent; color: var(--c-text, #0f172a); transform: none; box-shadow: none; }
body.social-body .feed-sort-btn.active { background: var(--c-surface, #fff); color: var(--c-brand, #6366f1); border: 0;
  box-shadow: 0 1px 3px rgba(15, 23, 42, 0.12); }

/* Signed out: an invitation, not an alert. */
body.social-body .feed-login-banner { border-radius: var(--r-surface, var(--sx-r)); border: 1px solid color-mix(in srgb, var(--c-brand, #6366f1) 25%, transparent);
  background: radial-gradient(circle at 0% 0%, color-mix(in srgb, #ffffff 30%, transparent), transparent 45%),
    linear-gradient(135deg, color-mix(in srgb, var(--c-brand, #6366f1) 14%, var(--c-surface, #fff)), color-mix(in srgb, var(--c-brand-alt, #8b5cf6) 10%, var(--c-surface, #fff)));
  box-shadow: var(--sx-shadow); padding: 1.6rem 1.5rem; }
body.social-body .feed-login-title { font-size: 1.15rem; letter-spacing: -0.01em; }

/* ── The composer ─────────────────────────────────────────────────── */
body.social-body .compose-card { padding: 1.1rem 1.25rem; }
body.social-body .compose-card textarea { border-radius: var(--r-2xl); border: 1px solid var(--sx-edge); background: var(--c-surface-subtle, #f8fafc);
  padding: 0.85rem 1rem; font-size: 0.98rem; line-height: 1.55; transition: border-color 0.15s ease, background 0.15s ease, box-shadow 0.15s ease; }
body.social-body .compose-card textarea:focus { outline: none; background: var(--c-surface, #fff); border-color: var(--c-brand, #6366f1);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--c-brand, #6366f1) 14%, transparent); }

/* ── A post ───────────────────────────────────────────────────────── */
body.social-body .post-card { --post-pad-x: 1.3rem; padding: 1.15rem var(--post-pad-x) 0.85rem; margin-top: 1rem; transition: box-shadow 0.2s ease, border-color 0.2s ease; }
body.social-body .post-card:hover { box-shadow: var(--sx-shadow-hi); }
body.social-body .post-header { gap: 0.8rem; margin-bottom: 0.8rem; }
body.social-body .post-avatar { width: 46px; height: 46px; box-shadow: 0 0 0 2px var(--c-surface, #fff), 0 0 0 3.5px color-mix(in srgb, var(--c-brand, #6366f1) 35%, transparent); }
body.social-body .post-author { font-size: 0.97rem; font-weight: 750; letter-spacing: -0.005em; }
body.social-body .post-author:hover { text-decoration: underline; text-underline-offset: 2px; }
body.social-body .post-time { font-size: 0.78rem; }
body.social-body .post-body { font-size: 0.99rem; line-height: 1.65; margin-bottom: 0.9rem; }
body.social-body .post-image, body.social-body .post-video, body.social-body .post-gallery, body.social-body .profile-gallery {
  border-radius: var(--r-3xl); border: 1px solid var(--sx-edge); }
/* ⚠️ A POST'S PHOTOS AND VIDEO RUN THE FULL WIDTH OF ITS CARD, SQUARE
   (Josh, 2026-09-30: "we need the images and video to be full width and
   to not have border radius"). They give back the card's side padding --
   --post-pad-x, set beside that padding above so the two cannot drift --
   and lose their corners and border. A quoted repost keeps its media
   inside its own box: it is a card within the card. */
body.social-body .post-card :is(.post-image, .post-gallery, .lx-media:not(.is-one-video)):not(.post-repost-original *) {
  width: calc(100% + 2 * var(--post-pad-x));
  max-width: none;
  margin-left: calc(-1 * var(--post-pad-x));
  margin-right: calc(-1 * var(--post-pad-x));
  border: 0;
  border-radius: 0;
}
/* ⚠️ VIDEO: FULL WIDTH ON A PHONE ONLY (Josh, 2026-09-30: full width
   "made the video player presentation on desktop have a black background
   when the video is tall ... keep it as it was for desktop"). On a wide
   card a portrait video forced to the card's width is mostly black
   sides; there the player keeps its own shape (socialMedia.css,
   width: fit-content -- the 2026-09-26 "no black bars" rule), centred,
   square. On a phone the width IS the screen, and the video filling it
   (width: 100% on the <video>, so a small file scales up) is what he
   asked for. */
body.social-body .post-card .post-video:not(.post-repost-original *) {
  border: 0;
  border-radius: 0;
}
@media (max-width: 640px) {
  body.social-body .post-card .post-video:not(.post-repost-original *) {
    width: calc(100% + 2 * var(--post-pad-x));
    max-width: none;
    margin-left: calc(-1 * var(--post-pad-x));
    margin-right: calc(-1 * var(--post-pad-x));
  }
  body.social-body .post-card .post-video:not(.post-repost-original *) video {
    width: 100%;
  }
}
body.social-body .post-link-preview { border-radius: var(--r-3xl); transition: border-color 0.15s ease, box-shadow 0.15s ease; }
body.social-body .post-link-preview:hover { border-color: color-mix(in srgb, var(--c-brand, #6366f1) 45%, transparent); box-shadow: 0 8px 22px -16px rgba(15, 23, 42, 0.45); }
/* Reactions: soft chips. */
body.social-body .post-reactions { display: flex; flex-wrap: wrap; gap: 0.35rem; margin: 0.2rem 0 0.35rem; }
body.social-body .reaction-btn, body.social-body .reaction-more-btn { min-height: 2rem; padding: 0.25rem 0.7rem; border-radius: var(--r-pill); border: 1px solid transparent;
  background: var(--c-surface-subtle, #f1f5f9); box-shadow: none; font-size: 0.88rem; transition: background 0.15s ease, transform 0.15s ease; }
body.social-body .reaction-btn:hover, body.social-body .reaction-more-btn:hover { background: color-mix(in srgb, var(--c-brand, #6366f1) 10%, var(--c-surface, #fff));
  border-color: color-mix(in srgb, var(--c-brand, #6366f1) 25%, transparent); transform: translateY(-1px); box-shadow: none; }
body.social-body .reaction-btn.active, body.social-body .reaction-btn.reacted, body.social-body .reaction-btn[aria-pressed="true"] {
  background: color-mix(in srgb, var(--c-brand, #6366f1) 14%, var(--c-surface, #fff)); border-color: color-mix(in srgb, var(--c-brand, #6366f1) 45%, transparent);
  color: var(--c-brand, #6366f1); font-weight: 700; }
/* The action bar: a line above, the actions spread out. */
body.social-body .post-actions { display: flex; align-items: center; gap: 0.25rem; margin: 0.35rem -0.4rem 0; padding-top: 0.45rem;
  border-top: 1px solid var(--sx-edge); }
body.social-body .post-action-btn, body.social-body .post-icon-btn { min-height: 2.25rem; padding: 0.35rem 0.8rem; border-radius: var(--r-lg); border: 0;
  background: transparent; box-shadow: none; color: var(--c-text-muted, #64748b); font-weight: 650; font-size: 0.85rem; }
body.social-body .post-action-btn:hover, body.social-body .post-icon-btn:hover { background: var(--c-surface-subtle, #f1f5f9); color: var(--c-text, #0f172a); transform: none; box-shadow: none; }
body.social-body .post-view-link { margin-left: auto; font-weight: 650; }
body.social-body .comment-item { border-radius: var(--r-2xl); }
body.social-body .comment-input { border-radius: var(--r-pill); }

/* ── The network lists ────────────────────────────────────────────── */
body.social-body .network-item { border-radius: var(--r-2xl); padding: 0.6rem 0.65rem; transition: background 0.15s ease; }
body.social-body .network-item:hover { background: var(--c-surface-subtle, #f8fafc); }
body.social-body .social-me-avatar { width: 64px; height: 64px; box-shadow: 0 0 0 2px var(--c-surface, #fff), 0 0 0 4px color-mix(in srgb, var(--c-brand, #6366f1) 40%, transparent); }
body.social-body .social-me-name { font-size: 1.12rem; }
body.social-body .social-me-stats { gap: 0; margin-top: 1rem; border-radius: var(--r-surface, var(--r-2xl)); border: 1px solid var(--sx-edge); overflow: hidden; }
body.social-body .social-me-stat { flex: 1; padding: 0.6rem 0.75rem; text-align: center; }
body.social-body .social-me-stat + .social-me-stat { border-left: 1px solid var(--sx-edge); }
body.social-body .social-me-stat:hover { background: var(--c-surface-subtle, #f8fafc); }

/* ── A profile ────────────────────────────────────────────────────── */
body.social-body .profile-cover { height: clamp(200px, 26vw, 320px); border-radius: var(--r-surface, 0 0 var(--r-5xl) var(--r-5xl)); }
body.social-body .profile-cover::after { content: ''; position: absolute; inset: 0; pointer-events: none; background: linear-gradient(180deg, transparent 55%, rgba(2, 6, 23, 0.35)); }
body.social-body .profile-header { margin-top: -3rem; padding: 0 1.75rem 1.5rem; border-radius: var(--r-surface, var(--r-5xl)); border: 1px solid var(--sx-edge); box-shadow: var(--sx-shadow-hi); }
body.social-body .profile-avatar-wrap { margin-top: -64px; }
body.social-body .profile-avatar { width: 128px; height: 128px; border-width: 5px; font-size: 2.8rem;
  box-shadow: 0 10px 30px -12px rgba(15, 23, 42, 0.5), 0 0 0 1px color-mix(in srgb, var(--c-brand, #6366f1) 25%, transparent); }
body.social-body .profile-name { margin-top: 0.4rem; font-size: clamp(1.5rem, 2.6vw, 2rem); letter-spacing: -0.02em; line-height: 1.15; }
body.social-body .profile-username { font-size: 0.95rem; }
body.social-body .profile-bio { max-width: 75ch; margin-top: 0.8rem; font-size: 0.97rem; line-height: 1.7; color: var(--c-text-2, #334155); }
body.social-body .profile-meta { gap: 0.5rem 1.25rem; margin-top: 0.8rem; font-size: 0.85rem; color: var(--c-text-muted, #64748b); }
body.social-body .profile-stats { display: inline-flex; gap: 0; margin-top: 1rem; border: 1px solid var(--sx-edge); border-radius: var(--r-2xl); overflow: hidden; }
body.social-body .profile-stat { padding: 0.6rem 1.25rem; }
body.social-body .profile-stat + .profile-stat { border-left: 1px solid var(--sx-edge); }
body.social-body .profile-stat:hover { background: var(--c-surface-subtle, #f8fafc); }
body.social-body .profile-stat-num { font-size: 1.2rem; }
body.social-body .profile-actions { margin-top: 1.1rem; gap: 0.6rem; }
/* (2026-10-06) "Are you also one of these?" on the member's own profile. */
.profile-addprofile { margin-top: 1rem; padding-top: 0.9rem; border-top: 1px solid var(--c-border, #e2e8f0); }
.profile-addprofile[hidden] { display: none; }
.profile-addprofile-head { margin: 0; font-size: 0.9rem; color: var(--c-text-muted, #64748b); }
.profile-addprofile .profile-actions { margin-top: 0.6rem; align-items: center; }
.profile-addprofile-later { width: auto; min-width: 0; padding: 0 0.4rem; border: 0; background: none; box-shadow: none; color: var(--c-text-muted, #64748b); font-size: 0.85rem; text-decoration: underline; cursor: pointer; }
body.social-body .btn-follow { padding: 0.6rem 1.6rem; box-shadow: 0 8px 18px -10px color-mix(in srgb, var(--c-brand, #6366f1) 70%, transparent); }
body.social-body .profile-body { gap: 1.5rem; margin-top: 1.5rem; }
body.social-body .profile-side { top: 5rem; }
body.social-body .profile-tabs { gap: 0.25rem; padding: 0.35rem; border-radius: var(--r-surface, var(--r-3xl)); border: 1px solid var(--sx-edge); box-shadow: var(--sx-shadow); }
body.social-body .profile-tab { border-radius: var(--r-xl); border-bottom: 0; padding: 0.7rem; color: var(--c-text-muted, #64748b); transition: background 0.15s ease, color 0.15s ease; }
body.social-body .profile-tab:hover { background: var(--c-surface-subtle, #f1f5f9); color: var(--c-text, #0f172a); }
body.social-body .profile-tab.active { background: color-mix(in srgb, var(--c-brand, #6366f1) 11%, var(--c-surface, #fff)); color: var(--c-brand, #6366f1); }

/* ── Phone: the feed first, the rails after it ────────────────────── */
@media (max-width: 899px) {
  body.social-body .social-cover { min-height: 200px; }
  body.social-body .social-cover-inner { padding: 1.9rem 1.1rem 3.75rem; }
  body.social-body .social-shell, body.social-body .social-shell-2 { margin-top: -2.25rem; gap: 1rem; }
  body.social-body .social-main { order: 1; }
  body.social-body .social-rail-left { order: 2; }
  body.social-body .social-rail-right { order: 3; }
  body.social-body .post-card { --post-pad-x: 1.05rem; padding: 1rem var(--post-pad-x) 0.75rem; }
  body.social-body .profile-header { padding: 0 1.1rem 1.25rem; margin-top: -2.25rem; }
  body.social-body .profile-avatar { width: 104px; height: 104px; }
  body.social-body .profile-avatar-wrap { margin-top: -52px; }
  body.social-body .profile-stats { display: flex; }
  body.social-body .profile-stat { flex: 1; }
}

/* ── Dark ─────────────────────────────────────────────────────────── */
[data-theme="dark"] body.social-body { --sx-edge: rgba(148, 163, 184, 0.18); --sx-shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 12px 32px -20px rgba(0, 0, 0, 0.7); }
[data-theme="dark"] body.social-body .feed-sort-btn.active { background: #1f2937; }

@media (prefers-reduced-motion: reduce) {
  body.social-body .post-card, body.social-body .reaction-btn, body.social-body .post-link-preview { transition: none; }
  body.social-body .reaction-btn:hover { transform: none; }
}

/* ── "Upcoming events" in the right rail (socialEvents.js) ─────────── */
body.social-body .sxe-all { font-size: 0.72rem; font-weight: 700; letter-spacing: 0.02em; text-transform: none; color: var(--c-brand, #6366f1); text-decoration: none; }
body.social-body .sxe-all:hover { text-decoration: underline; }
/* The Following / Followers "View all (N) →" is a button (it opens a
   popout), dressed as the same quiet link as "Calendar →" -- none of the
   site's button fill. */
body.social-body button.network-view-all {
  background: none; border: 0; box-shadow: none; padding: 0; min-height: 0;
  cursor: pointer; font-family: inherit; line-height: 1.2;
}
body.social-body button.network-view-all:hover { background: none; box-shadow: none; transform: none; text-decoration: underline; }
/* A Following row is a link to the person's profile -- it keeps the row's
   own look rather than turning blue and underlined. */
a.network-item-link { color: inherit; text-decoration: none; }
a.network-item-link:hover span:not(.network-item-pending-note) { text-decoration: underline; }
body.social-body .sxe-list { display: flex; flex-direction: column; gap: 0.7rem; }
body.social-body .sxe-item { display: grid; grid-template-columns: 76px minmax(0, 1fr); gap: 0.75rem; align-items: center; padding: 0.4rem; margin: -0.4rem;
  border-radius: var(--r-2xl); text-decoration: none; color: inherit; transition: background 0.15s ease; }
body.social-body .sxe-item:hover { background: var(--c-surface-subtle, #f8fafc); }
body.social-body .sxe-pic { position: relative; display: block; width: 76px; height: 76px; overflow: hidden; border-radius: var(--r-xl);
  background: linear-gradient(135deg, var(--c-brand, #6366f1), var(--c-brand-alt, var(--c-brand-strong, #4f46e5))); border: 1px solid var(--sx-edge); }
body.social-body .sxe-pic img { width: 100%; height: 100%; object-fit: cover; }
body.social-body .sxe-date { position: absolute; left: 5px; top: 5px; display: grid; place-items: center; min-width: 30px; padding: 2px 4px; border-radius: var(--r-md);
  line-height: 1; background: rgba(255, 255, 255, 0.95); color: #0f172a; box-shadow: 0 2px 6px rgba(0, 0, 0, 0.25); }
body.social-body .sxe-date small { font-size: 0.52rem; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; color: var(--c-brand, #6366f1); }
body.social-body .sxe-date b { font-size: 0.9rem; font-weight: 800; }
body.social-body .sxe-body { display: flex; flex-direction: column; gap: 0.15rem; min-width: 0; }
body.social-body .sxe-title { font-size: 0.88rem; line-height: 1.3; color: var(--c-text, #0f172a); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
body.social-body .sxe-when { font-size: 0.74rem; font-weight: 700; color: var(--c-brand, #6366f1); }
body.social-body .sxe-where { font-size: 0.74rem; color: var(--c-text-muted, #64748b); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* Media never takes the whole screen: a tall video or poster is held to
   a comfortable height in the feed; its own page shows it larger.
   ⚠️ BOTH the wrapper and the video itself need the number -- the video
   is what's actually sized (width/height: auto against its OWN
   max-height, per the base .post-video video rule), so a cap that only
   touched the wrapper did nothing once the wrapper shrank to fit it. */
body.social-body .social-main .post-video,
body.social-body .social-main .post-video video,
body.social-body .social-main .post-video.lx-player video { max-height: min(560px, 70vh); }
/* More room for a taller video, same rule as the base one above, never
   past the screen (Josh, 2026-09-26), scaled to the feed's own smaller
   cap: 840px is real headroom over the feed's usual 560px ceiling, and
   100vh -- not 105vh -- is the hard outer one either way. */
body.social-body .social-main .post-video.is-tall,
body.social-body .social-main .post-video.is-tall video,
body.social-body .social-main .post-video.is-tall.lx-player video { max-height: min(840px, 100vh); }
/* ⚠️⚠️ A POST'S PHOTO FILLS THE POST (Josh, 2026-10-03: "really it should
   just have the image fill the whole post"). It was held to 560px and shown
   whole inside that box, so a tall flyer sat in the middle of grey bars. Now
   it runs the full width of the post at its own shape; only a photo taller
   than the cap is trimmed top and bottom (cover), never given side bars.
   Everywhere a post card is: the feed, profiles, the level pages. */
body.social-body .post-card .post-image:not(.post-repost-original *) {
  height: auto; max-height: min(1100px, 150vh); object-fit: cover; object-position: center; background: transparent;
}
/* Polish (2026-09-24): the sort switch never wraps its labels; on a phone
   the toolbar's title steps down a size. The calendar's head card, in list
   view, holds only the view switch -- it becomes a quiet row, not an empty
   card. */
body.social-body .feed-sort-btn { white-space: nowrap; }
@media (max-width: 560px) {
  body.social-body .social-main .feed-toolbar { padding: 0.75rem 0.8rem 0.75rem 1rem; gap: 0.5rem; }
  body.social-body .social-main .feed-toolbar h1, body.social-body .social-main .feed-toolbar h2 { font-size: 1rem; }
  body.social-body .feed-sort-btn { padding: 0.38rem 0.75rem; }
}
body.social-body .sitecal-card:has(#sitecal-gridwrap[hidden]) { background: transparent; border-color: transparent; box-shadow: none; padding: 0 0 0.25rem; }
body.social-body .sitecal-card:has(#sitecal-gridwrap[hidden]) .sitecal-head { justify-content: flex-end; margin: 0; }
/* Icon buttons on posts and in the composer are icons, not framed buttons
   (the site-wide button edge of REQ-0064 had boxed the post's × and the
   composer's photo / video / Cloud tools). */
body.social-body .post-delete-btn, body.social-body .post-icon-btn, body.social-body .compose-tool-btn, body.social-body .comment-reply-btn {
  border: 0; background: transparent; box-shadow: none; }
body.social-body .compose-tool-btn { width: 2.4rem; height: 2.4rem; padding: 0; display: inline-grid; place-items: center; border-radius: var(--r-xl);
  color: var(--c-brand, #6366f1); font-size: 1.1rem; }
body.social-body .compose-tool-btn:hover { background: color-mix(in srgb, var(--c-brand, #6366f1) 10%, transparent); transform: none; box-shadow: none; }
body.social-body .post-delete-btn { width: 2rem; height: 2rem; padding: 0; border-radius: var(--r-lg); color: var(--c-text-muted, #64748b); }
body.social-body .post-delete-btn:hover { background: color-mix(in srgb, var(--c-danger, #dc2626) 10%, transparent); color: var(--c-danger, #dc2626); transform: none; box-shadow: none; }
/* The cover always carries its darkening overlay now, so its words are
   always light -- in dark mode the brand's on-colour came out dark on
   dark. The composer's Post never breaks its one word. */
body.social-body .social-cover, body.social-body .social-cover h1, body.social-body .social-cover p { color: #fff; }
body.social-body .social-cover p a { color: #fff; }
body.social-body .compose-submit { white-space: nowrap; flex: none; }
/* The header image, from the cover and from the editor (2026-09-24). The
   access-profile badge (Practitioner, Vendor) sits top right on the cover
   and was covering the cover's own Edit button -- which now sits top left. */
body.social-body .profile-cover-edit { left: 0.9rem; right: auto; top: 0.9rem; z-index: 3; padding: 0.45rem 0.85rem; border-radius: var(--r-pill);
  font-weight: 700; backdrop-filter: blur(6px); -webkit-backdrop-filter: blur(6px); }
body.social-body .pe-cover-row { display: flex; gap: 1rem; align-items: center; margin: 0 0 1.1rem; padding: 0.8rem; border-radius: var(--r-surface, var(--r-2xl));
  background: var(--c-surface-subtle, #f8fafc); border: 1px solid var(--sx-edge); }
body.social-body .pe-cover-prev { flex: none; width: 140px; aspect-ratio: 3 / 1; border-radius: var(--r-lg); background-size: cover; background-position: center;
  background-color: var(--c-border, #e2e8f0); background-image: linear-gradient(135deg, var(--c-brand, #6366f1), var(--c-brand-alt, #8b5cf6)); }
body.social-body .pe-cover-row strong { display: block; font-size: 0.9rem; }
body.social-body .pe-cover-row small { display: block; margin: 0.15rem 0 0.5rem; font-size: 0.78rem; color: var(--c-text-muted, #64748b); }
/* (2026-10-05) The note under Display name: the same small muted line. */
body.social-body .pe-hint { display: block; margin: -0.35rem 0 0.9rem; font-size: 0.78rem; color: var(--c-text-muted, #64748b); }
@media (max-width: 560px) { body.social-body .pe-cover-row { flex-direction: column; align-items: stretch; } body.social-body .pe-cover-prev { width: 100%; } }

/* Past events (2026-09-25): the widget on /calendar and the /past-events page. */
.sitecal-list-head { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; }
.sitecal-list-head #sitecal-view-toggle { width: auto; margin: 0; }
.sitecal-past .network-section-header { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; }
.sitecal-past-all { font-size: 0.82rem; font-weight: 700; text-decoration: none; color: var(--c-brand, #6366f1); text-transform: none; letter-spacing: 0; }
.sitecal-past-all:hover { text-decoration: underline; }
.sitecal-row.is-past { opacity: 0.85; }
.sitecal-tag.is-past { background: var(--c-surface-sunken, #f1f5f9); color: var(--c-text-muted, #475569); }
.past-main { max-width: 980px; margin: 0 auto; }
.social-container > .sitecal-past { margin-top: 1.25rem; }
/* The cards: a third each on desktop, centred when there are fewer than three.
   The silver tokens live on .ev-next in style.css; this widget is not one. */
/* The Theme borders finish, like .sc-card above; silver is the fallback. */
.sitecal-past {
  --sv-hi: var(--ab-hi, #ffffff); --sv-1: var(--ab-1, #eef1f5); --sv-2: var(--ab-2, #c9d1da);
  --sv-3: var(--ab-3, #9aa5b2); --sv-4: var(--ab-4, #6b7683); --sv-ink: var(--ab-ink, #4b5563);
  --sv-w: var(--ab-w, 1);
}
.sitecal-past .ev-next-row.sitecal-past-row { display: flex; flex-wrap: wrap; justify-content: center; gap: 1.25rem; }
.sitecal-past-row > .ev-next-card { flex: 0 1 calc((100% - 2.5rem) / 3); min-width: 0; }
.sitecal-past-row .ev-next-banner { height: 170px; }
.sitecal-past-row .ev-next-banner img { filter: saturate(0.85); }
@media (max-width: 900px) { .sitecal-past-row > .ev-next-card { flex-basis: 100%; } }
@media (max-width: 899px) { .social-container > .sitecal-past { margin-top: 0.85rem; } }
.past-more-wrap { display: flex; justify-content: center; margin-top: 1rem; }
.past-more-wrap button { width: auto; }
.sc-card .sitecal-tag.is-past { align-self: center; }

/* Calendar rail (2026-09-25): the viewer's own tickets, or the next event's
   ticket preview with "Get Yours". The preview is the event page's .ev-sample
   inside this card, so its own card chrome comes off. */
.sitecal-sample .ev-sample { padding: 0; border: 0; background: none; }
.sitecal-sample .ev-sample-card { --tk-page: var(--c-surface, #ffffff); }
.sitecal-sample .ev-sample-qr { width: 132px; height: 132px; }
.sitecal-mine-item + .sitecal-mine-item { border-top: 1px solid var(--c-border, #e2e8f0); }
.sitecal-mine-item .sitecal-row { flex-direction: column; gap: 0.2rem; border-bottom: none; padding-bottom: 0.3rem; }
.sitecal-mine-item .sitecal-row-when { flex: none; }
.sitecal-mine-ticket { display: inline-block; margin: 0 0.2rem 0.7rem; font-size: 0.82rem; font-weight: 700; color: var(--c-brand, #6366f1); text-decoration: none; }
.sitecal-mine-ticket:hover { text-decoration: underline; }
.sitecal-mine-item .sitecal-tag.is-mine { display: none; }
/* Calendar (Josh, 2026-09-25): a wider left column for the ticket preview,
   the upcoming column a little narrower. Desktop only; phones stack. */
@media (min-width: 900px) {
  .social-shell-2.sitecal-shell { grid-template-columns: 360px minmax(0, 1fr); }
}
@media (min-width: 900px) and (max-width: 1199px) {
  .social-shell-2.sitecal-shell { grid-template-columns: 320px minmax(0, 1fr); }
}
/* The calendar's left column scrolls with the page (Josh, 2026-09-25):
   the ticket preview is too tall to pin. */
.sitecal-shell .social-rail { position: static; }

/* ── Room reserved for what arrives after paint (2026-09-25) ──────────
   The month grid, the event lists and the feed are filled by fetches.
   Without a floor under them the footer painted near the top of the
   screen and was shoved down as the content landed -- most of the layout
   shift measured on these pages. The floors are the content's usual
   height, so a page filled in place rather than growing into place. */
#sitecal-grid:empty { min-height: 648px; }
@media (max-width: 640px) { #sitecal-grid:empty { min-height: 456px; } }
/* While loading, tall enough that what follows is below the fold; the
   class goes when the content lands, so a short list has no hole. */
#sitecal-list.is-loading, #feed-posts-container.is-loading { min-height: 70vh; }
#past-list { min-height: 12rem; }
/* The rail's ticket preview and "You are going to" card share one slot. */
.sitecal-shell .social-rail { min-height: 12rem; }
/* The past-events widget's cards are ~26rem tall; reserved so the footer
   under it stays put while they load. */
.sitecal-past #sitecal-past-list { min-height: 26rem; }
@media (max-width: 900px) { .sitecal-past #sitecal-past-list { min-height: 12rem; } }

/* ══ A page for every account level (298, Josh 2026-10-01) ═══════════
   /network/<level> and /network/directory. Built on the social page's own
   pieces (cover, shell, rails, cards); only what is new is here. Theme
   variables throughout so light, dark and every site follow. */
.nl-cover.has-image { background-image: linear-gradient(180deg, rgba(15, 23, 42, 0.25), rgba(15, 23, 42, 0.7)), var(--nl-cover); background-size: cover; background-position: center; }
.nl-kicker { margin: 0 0 0.35rem !important; font-size: 0.75rem !important; font-weight: 800; letter-spacing: 0.08em; text-transform: uppercase; opacity: 0.85; }
.nl-kicker a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.nl-intro { max-width: 70ch !important; line-height: 1.5; }
.nl-main { display: flex; flex-direction: column; gap: 1rem; min-width: 0; }

/* The level switcher in the left rail. */
.nl-levels-list { list-style: none; margin: 0.3rem 0 0.6rem; padding: 0; display: flex; flex-direction: column; gap: 0.15rem; }
.nl-levels-list a { display: flex; justify-content: space-between; align-items: center; gap: 0.5rem; padding: 0.45rem 0.6rem; border-radius: var(--r-lg);
  color: var(--c-text); text-decoration: none; font-weight: 600; font-size: 0.9rem; }
.nl-levels-list a:hover { background: var(--c-surface-subtle, #f8fafc); }
.nl-levels-list a.is-on { background: color-mix(in srgb, var(--c-brand, #6366f1) 12%, transparent); color: var(--c-brand, #6366f1); }
.nl-levels-list b { font-size: 0.75rem; font-weight: 700; padding: 0.05rem 0.5rem; border-radius: var(--r-pill); background: var(--c-surface-subtle, #f1f5f9); color: var(--c-text-muted); }
.nl-all { font-size: 0.82rem; font-weight: 700; color: var(--c-brand, #6366f1); text-decoration: none; }

/* The members card: title, search, sort, filters, the grid. */
.nl-bar { display: flex; align-items: center; justify-content: space-between; gap: 0.75rem; flex-wrap: wrap; margin-bottom: 0.75rem; }
.nl-bar h2 { margin: 0; font-size: 1.15rem; font-weight: 900; }
.nl-tools { display: flex; gap: 0.5rem; flex: 1 1 18rem; justify-content: flex-end; min-width: 0; }
.nl-tools input[type="search"] { flex: 1 1 14rem; min-width: 0; max-width: 22rem; margin: 0; padding: 0.5rem 0.8rem; border-radius: var(--r-pill); }
.nl-tools select { width: auto; margin: 0; padding: 0.5rem 0.7rem; border-radius: var(--r-pill); }
.nl-filters { display: flex; flex-wrap: wrap; gap: 0.4rem; margin: 0 0 0.75rem; }
.nl-filter { width: auto; min-width: 0; margin: 0; padding: 0.3rem 0.8rem; border-radius: var(--r-pill); font: inherit; font-size: 0.8rem; font-weight: 700;
  color: var(--c-text); background: var(--c-surface, #fff); border: 1px solid var(--c-border-strong, #cbd5e1); box-shadow: none; cursor: pointer; }
.nl-filter span { font-weight: 600; color: var(--c-text-muted); margin-left: 0.15rem; }
.nl-filter.is-on { color: var(--c-on-brand, #fff); background: var(--btn-grad, var(--c-brand, #6366f1)); border-color: transparent; }
.nl-filter.is-on span { color: inherit; opacity: 0.85; }
.nl-count { margin: 0 0 0.6rem; font-size: 0.8rem; color: var(--c-text-muted); }
.nl-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(15rem, 1fr)); gap: 0.85rem; }
.nl-empty { grid-column: 1 / -1; margin: 1rem 0; color: var(--c-text-muted); }
.nl-more-row { display: flex; justify-content: center; margin-top: 1rem; }
.nl-more-row [hidden] { display: none; }

/* A member card: the whole card opens the profile; Follow sits above that link. */
.nl-card { position: relative; display: flex; flex-direction: column; gap: 0.6rem; min-width: 0; padding: 1rem; border-radius: var(--r-surface, var(--r-2xl));
  background: var(--c-surface-subtle, #f8fafc); border: 1px solid var(--c-border, #e2e8f0); transition: border-color 0.15s, transform 0.15s, box-shadow 0.15s; }
.nl-card:hover { border-color: var(--c-brand, #6366f1); transform: translateY(-2px); box-shadow: 0 10px 24px -16px color-mix(in srgb, var(--c-shadow, #000) 40%, transparent); }
.nl-card-link { position: absolute; inset: 0; z-index: 1; border-radius: inherit; }
.nl-card-link:focus-visible { outline: 2px solid var(--c-brand, #6366f1); outline-offset: 2px; }
.nl-card-top { display: flex; align-items: center; gap: 0.75rem; min-width: 0; }
.nl-pic { width: 3.25rem; height: 3.25rem; flex: none; border-radius: var(--r-round); object-fit: cover; background: var(--c-surface, #fff);
  box-shadow: 0 0 0 2px var(--c-surface, #fff), 0 0 0 3px var(--c-border, #e2e8f0); }
.nl-init { display: grid; place-items: center; font-weight: 900; font-size: 1.2rem; color: var(--c-on-brand, #fff); background: var(--btn-grad, var(--c-brand, #6366f1)); }
.nl-who { min-width: 0; display: flex; flex-direction: column; }
.nl-name { font-weight: 800; line-height: 1.25; color: var(--c-text); }
.nl-handle { font-size: 0.8rem; color: var(--c-text-muted); }
.nl-blurb { margin: 0; font-size: 0.86rem; line-height: 1.45; color: var(--c-text); opacity: 0.88; display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 3; overflow: hidden; }
.nl-chips { display: flex; flex-wrap: wrap; gap: 0.3rem; }
.nl-chip { font-size: 0.72rem; font-weight: 700; padding: 0.15rem 0.55rem; border-radius: var(--r-pill); color: var(--c-brand-deep, #4338ca);
  background: color-mix(in srgb, var(--c-brand, #6366f1) 10%, transparent); }
.nl-card-acts { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; margin-top: auto; padding-top: 0.2rem; }
.nl-follow { position: relative; z-index: 2; width: auto; min-width: 0; margin: 0; padding: 0.35rem 0.95rem; border-radius: var(--r-pill); font: inherit; font-size: 0.8rem; font-weight: 800;
  color: var(--c-on-brand, #fff); background: var(--btn-grad, var(--c-brand, #6366f1)); border: 1px solid transparent; box-shadow: none; cursor: pointer; }
.nl-follow.is-on { color: var(--c-text); background: var(--c-surface, #fff); border-color: var(--c-border-strong, #cbd5e1); }
.nl-follow[hidden] { display: none; }
.nl-view { position: relative; z-index: 2; font-size: 0.8rem; font-weight: 700; color: var(--c-brand, #6366f1); text-decoration: none; margin-left: auto; }
.nl-featured .nl-card { background: color-mix(in srgb, var(--c-brand, #6366f1) 6%, var(--c-surface, #fff)); }
.nl-feed .feed-toolbar h2 { font-size: 1.05rem; }
.nl-feed[hidden], .nl-events[hidden], .nl-me[hidden] { display: none; }

/* /network/directory: one tile per level. */
.nl-tiles { position: relative; z-index: 2; margin-top: -2.5rem; display: grid; grid-template-columns: repeat(auto-fill, minmax(18rem, 1fr)); gap: 1rem; }
.nl-tile { display: flex; flex-direction: column; gap: 0.6rem; color: var(--c-text); text-decoration: none; transition: transform 0.15s, box-shadow 0.15s; }
.nl-tile:hover { transform: translateY(-3px); }
.nl-tile-top { display: flex; align-items: baseline; justify-content: space-between; gap: 0.5rem; }
.nl-tile-top strong { font-size: 1.1rem; font-weight: 900; }
.nl-tile-top span { font-size: 0.78rem; font-weight: 700; color: var(--c-text-muted); white-space: nowrap; }
.nl-tile p { margin: 0; font-size: 0.88rem; line-height: 1.45; color: var(--c-text-muted); }
.nl-faces { display: flex; align-items: center; min-height: 2.5rem; }
.nl-faces img, .nl-faces span { width: 2.4rem; height: 2.4rem; border-radius: var(--r-round); object-fit: cover; margin-right: -0.55rem; box-shadow: 0 0 0 2px var(--c-surface, #fff);
  display: grid; place-items: center; font-weight: 900; color: var(--c-on-brand, #fff); background: var(--btn-grad, var(--c-brand, #6366f1)); }
.nl-faces em { font-size: 0.82rem; color: var(--c-text-muted); }
.nl-tile-go { margin-top: auto; font-size: 0.85rem; font-weight: 800; color: var(--c-brand, #6366f1); }

/* The rails follow the social page's own breakpoints (1199px, 899px). */
@media (max-width: 899px) {
  .nl-tiles { margin-top: -2rem; }
  .nl-tools { justify-content: stretch; }
  .nl-tools input[type="search"] { max-width: none; }
  .nl-grid { grid-template-columns: minmax(0, 1fr); }
}

/* ── Event appearances on a profile (Josh, 2026-10-03) ──────────────────
   On an event's schedule: the event in their header while it is on sale,
   drawn as the ticket's head made wide -- the event's picture under the
   site's head colours, the same glaze and the same text shadow
   (style.css .tk-head-image) -- and afterwards a keepsake ticket above
   their links, for good (profilePage.js loadAppearances). */
.profile-gigs { grid-column: 1 / -1; display: grid; gap: 0.65rem; margin-top: 1.25rem; }
.profile-gig {
  position: relative; display: flex; align-items: center; justify-content: space-between; gap: 1rem 1.5rem;
  min-height: 7.5rem; padding: 1.15rem 1.35rem; border-radius: var(--r-lg); overflow: hidden;
  text-decoration: none; color: var(--tk-head-ink, #fff);
  background: var(--tk-head-bg, #0f172a);
  background-image: linear-gradient(135deg, var(--tk-head-from, #28303f) 0%, var(--tk-head-to, #0c1220) 100%);
  border: 1px solid var(--sx-edge, var(--c-border, #e2e8f0));
}
/* The glaze is heavier on the left, where the words are, and leaves the
   picture to the right of them. */
.profile-gig.has-image {
  background-image:
    linear-gradient(to right,
      color-mix(in srgb, var(--tk-head-scrim, #000) 46%, transparent) 0%,
      color-mix(in srgb, var(--tk-head-scrim, #000) 22%, transparent) 60%,
      color-mix(in srgb, var(--tk-head-scrim, #000) 8%, transparent) 100%),
    var(--tk-head-img, none);
  background-size: cover, cover; background-position: center, center; background-repeat: no-repeat, no-repeat;
}
.profile-gig::after { content: ""; position: absolute; inset: 0 0 auto 0; height: 1px; background: rgba(255, 255, 255, 0.18); pointer-events: none; }
.profile-gig:hover .profile-gig-title { text-decoration: underline; }
.profile-gig-text { display: flex; flex-direction: column; gap: 0.2rem; min-width: 0; }
.profile-gig.has-image .profile-gig-text > * {
  text-shadow: 0 1px 3px color-mix(in srgb, var(--tk-head-scrim, #000) 72%, transparent), 0 1px 10px color-mix(in srgb, var(--tk-head-scrim, #000) 40%, transparent);
}
.profile-gig-kicker { color: var(--tk-head-eyebrow, #94a3b8); font-size: 0.66rem; letter-spacing: 0.2em; text-transform: uppercase; font-weight: 700; }
.profile-gig-title { font-size: 1.35rem; line-height: 1.25; font-weight: 800; color: var(--tk-head-ink, #fff); overflow-wrap: anywhere; }
.profile-gig-when { font-size: 0.85rem; color: var(--tk-head-sub, #cbd5e1); }
.profile-gig-slots { display: flex; flex-direction: column; gap: 0.1rem; margin-top: 0.35rem; }
.profile-gig-slot { font-size: 0.82rem; font-weight: 600; color: var(--tk-head-ink, #fff); }
.profile-gig-slot::before { content: "\2726"; margin-right: 0.4rem; color: var(--tk-head-eyebrow, #94a3b8); }
.profile-gig .profile-gig-cta { flex: none; display: inline-flex; align-items: center; text-shadow: none; }
@media (max-width: 640px) {
  .profile-gig { flex-direction: column; align-items: flex-start; padding: 1rem 1.1rem; }
  .profile-gig.has-image {
    background-image:
      linear-gradient(to bottom,
        color-mix(in srgb, var(--tk-head-scrim, #000) 22%, transparent) 0%,
        color-mix(in srgb, var(--tk-head-scrim, #000) 48%, transparent) 100%),
      var(--tk-head-img, none);
  }
  .profile-gig-title { font-size: 1.15rem; }
}

.profile-keepsakes { display: grid; gap: 0.85rem; margin-bottom: 1.1rem; }
.profile-keepsakes-title { font-size: 0.95rem; font-weight: 700; margin: 0; }
.profile-side a.profile-keepsake {
  --tk-page: var(--c-page, #f4f5f7);
  display: block; margin: 0; max-width: none; text-decoration: none; color: inherit;
}
.profile-side a.profile-keepsake[hidden] { display: none; }
.profile-keepsake .tk-head-image {
  min-height: 6.75rem;
  /* A little more glaze than a ticket's head: these are small, and the
     picture is busier at this size than at a ticket's. */
  background-image:
    linear-gradient(to bottom,
      color-mix(in srgb, var(--tk-head-scrim, #000) 18%, transparent) 0%,
      color-mix(in srgb, var(--tk-head-scrim, #000) 42%, transparent) 100%),
    var(--tk-head-img, none);
}
.profile-keepsake:hover .tk-title { text-decoration: underline; }
.profile-keepsake-stub { display: flex; flex-direction: column; align-items: center; gap: 0.15rem; padding: 0.75rem 1.1rem 0.95rem; text-align: center; }
.profile-keepsake-label { font-size: 0.6rem; letter-spacing: 0.16em; text-transform: uppercase; font-weight: 700; color: var(--c-text-dim, #94a3b8); }
.profile-keepsake-what { font-size: 0.9rem; font-weight: 700; color: var(--c-text, #0f172a); }
.profile-keepsakes-more { justify-self: center; }

/* The network's signed-out box (2026-10-03): its buttons are links. */
.nl-signin .nl-more-row a { text-decoration: none; }
.nl-signin .nl-more-row { display: flex; justify-content: center; gap: 0.5rem; }

/* (2026-10-06) Share to Instagram by hand (js/igShare.js), and the post
   button that publishes, hidden until the site and an account can. */
html:not(.ssh-ready) [data-social-share] { display: none !important; }
.app-modal-overlay.igs-overlay { z-index: 2147482600; }
.app-modal.igs-modal { width: min(560px, 94vw); max-height: 90vh; padding: 1.25rem; }
.igs-head { display: flex; align-items: center; justify-content: space-between; gap: 0.5rem; }
.igs-head h3 { margin: 0; font-size: 1.1rem; }
.igs-x { width: auto; min-width: 0; padding: 0.25rem 0.5rem; border: 0; background: none; box-shadow: none; font-size: 1.1rem; color: var(--c-text-muted, #64748b); cursor: pointer; }
.igs-sub { margin: 0.2rem 0 0; }
.igs-thumbs { display: flex; gap: 0.5rem; overflow-x: auto; margin: 0.9rem 0 0.4rem; padding-bottom: 0.25rem; }
.igs-thumbs img, .igs-video { flex: 0 0 auto; width: 92px; height: 115px; object-fit: cover; border-radius: var(--r-md, 10px); border: 1px solid var(--c-border, #e2e8f0); }
.igs-video { display: grid; place-items: center; font-size: 0.8rem; color: var(--c-text-muted, #64748b); background: var(--c-surface-subtle, #f1f5f9); }
.igs-label { display: grid; gap: 0.35rem; margin: 0.6rem 0 0; font-size: 0.85rem; color: var(--c-text-muted, #64748b); }
.igs-caption { width: 100%; box-sizing: border-box; padding: 0.6rem 0.7rem; font: inherit; font-size: 0.92rem; color: var(--c-text, #0f172a); background: var(--c-surface, #fff); border: 1px solid var(--c-border, #e2e8f0); border-radius: var(--r-md, 10px); resize: vertical; }
.igs-acts { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 0.8rem; }
.igs-say { min-height: 1.2em; margin: 0.6rem 0 0; }
.igs-how { margin: 0.4rem 0 0; }
.ssh-byhand { display: inline-block; margin-top: 0.6rem; width: auto; padding: 0; border: 0; background: none; box-shadow: none; color: var(--c-brand, #6366f1); text-decoration: underline; cursor: pointer; font-size: 0.88rem; }
