/* CosmaSpace: the mid-2000s layout on a holographic glass surface.
   Rules here stay low-specificity on purpose. User profile CSS is scoped under
   #profile and has to keep winning, so avoid IDs and !important inside a profile.
   Four blocks use !important: the site's glass, which only names site chrome, the
   theme thinning for phones, the dropdown option colors, and the locked controls at
   the end of this file. */

@font-face {
  font-family: "Inter";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url("/fonts/inter-latin-ext-wght-normal.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: "Inter";
  font-style: normal;
  font-display: swap;
  font-weight: 100 900;
  src: url("/fonts/inter-latin-wght-normal.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

/* Neon defaults, matching EMOTIONS in src/emotions.js. These are on :root alone, not
   the block below: a value on .profile-guard would hide a viewer's own colors, which
   public/js/emotion-settings.js sets on the root element. */
:root {
  --emotion-happy: #00ffcc;
  --emotion-excited: #5ff3ff;
  --emotion-peaceful: #ff2bd6;
  --emotion-calm: #b14dff;
  --emotion-neutral: #b9b9c6;
  --emotion-anxious: #ff8c00;
  --emotion-stressed: #ff3333;
  --emotion-confused: #b9b9c6;
  --emotion-focused: #b9b9c6;
  --emotion-tired: #708090;
  --emotion-sad: #708090;
  --emotion-lonely: #708090;
  --emotion-angry: #ff3333;
  --emotion-annoyed: #ff8c00;
  --emotion-bored: #708090;
  --emotion-sarcastic: #b9b9c6;
  --emotion-hype: #00ffcc;
  --emotion-mysterious: #b14dff;
  --emotion-proud: #5ff3ff;
  --emotion-grateful: #ff2bd6;
  --emotion-embarrassed: #ff2bd6;
  --emotion-shy: #b14dff;
  --emotion-guilty: #708090;
  --emotion-vulnerable: #5ff3ff;
  --emotion-inspired: #00ffcc;
  --emotion-curious: #5ff3ff;
  --emotion-mindblown: #ff2bd6;
  --emotion-nostalgic: #b14dff;
  --emotion-defensive: #ff8c00;
  --emotion-skeptical: #b9b9c6;
  --emotion-jealous: #00ffcc;
  --emotion-overwhelmed: #ff3333;
  --emotion-love: #ff4fd8;
  --emotion-hopeful: #7dff5a;
}

/* The site is one look, glass over a deep backdrop, so these aren't split by
   prefers-color-scheme. A surface is a tint of whatever is behind it. */
:root {
  color-scheme: dark;

  /* surfaces */
  --bg: #0a0c1e;
  --surface: rgb(255 255 255 / 7%);
  --surface-2: rgb(255 255 255 / 5%);
  --hover: rgb(255 255 255 / 12%);
  --hairline: rgb(255 255 255 / 14%);
  --hairline-strong: rgb(255 255 255 / 26%);
  --control: #1b1f33; /* the locked controls stay solid, so a page can't show through them */
  --control-hover: #272c45;

  /* text */
  --ink: #f0f2fa;
  --ink-2: #ccd2e2;
  --muted: #a6aec4;

  /* brand */
  --band: transparent;
  --accent: #3f6df0;
  --accent-hover: #5580f5;
  --accent-soft: #1f2a4d;
  --link: #9db9ff;
  --link-hover: #5ff3ff;
  --orange-strong: #c2410c;
  --orange-strong-hover: #d4500f;

  /* semantic */
  --danger: #ff7b7b; /* for text on glass; --danger-fill is the one white text sits on */
  --danger-fill: #c62f2f;
  --danger-hover: #dc4040;
  --danger-soft: rgb(209 58 58 / 18%);
  --danger-line: rgb(255 123 123 / 45%);
  --warn-soft: rgb(238 219 149 / 14%);
  --warn-line: rgb(238 219 149 / 40%);
  --warn-ink: #f4e3a6;
  --ok-soft: rgb(154 224 184 / 14%);
  --ok-line: rgb(154 224 184 / 40%);
  --ok-ink: #aeeeca;

  /* classic palette, still used by the profile and the views not yet restyled */
  --blue-dark: #9db9ff;
  --blue: #6699cc;
  --blue-pale: rgb(255 255 255 / 7%);
  --orange: #ff8a3d;
  --orange-pale: rgb(255 166 110 / 18%);
  --orange-wash: rgb(255 166 110 / 10%);
  --line: rgb(255 255 255 / 26%);

  --shadow-sm: 0 1px 2px rgb(0 0 0 / 30%);
  --shadow-md: 0 2px 4px rgb(0 0 0 / 30%), 0 8px 24px rgb(0 0 0 / 40%);
  --ring: 0 0 0 3px rgb(157 185 255 / 40%);
  --glow: 0 0 0 1px #29f3ff, 0 0 16px rgb(41 243 255 / 45%);
  --neon-line: #29f3ff;
}

/* A profile with a theme or hand-written CSS keeps these light values: that CSS was
   written for a white page, and some of it sets only part of the look. .profile-glass
   is the opposite case, a page with nothing of its own, so the site's tokens reach it. */
.profile-guard:not(.profile-glass) {
  color-scheme: light;

  --bg: #f4f5f9;
  --surface: #ffffff;
  --surface-2: #f8f9fc;
  --hover: #eef1f8;
  --hairline: #e3e6ef;
  --hairline-strong: #c9cfde;
  --control: #ffffff;
  --control-hover: #eef1f8;
  --ink: #171b26;
  --ink-2: #3c4456;
  --muted: #5b6478;
  --accent: #2c5ae6;
  --accent-hover: #2149c7;
  --accent-soft: #e9eefd;
  --link: #2149c7;
  --link-hover: #c2410c;
  --danger: #c02626;
  --danger-fill: #c02626;
  --danger-hover: #a11f1f;
  --blue-dark: #2149c7;
  --blue-pale: #eef1f8;
  --orange: #ff6600;
  --orange-pale: #ffcc99;
  --orange-wash: #fff3e6;
  --line: #c9cfde;
  --shadow-sm: 0 1px 2px rgb(16 27 59 / 6%);
  --shadow-md: 0 2px 4px rgb(16 27 59 / 6%), 0 8px 20px rgb(16 27 59 / 10%);
  --ring: 0 0 0 3px rgb(44 90 230 / 30%);
}

:root {
  /* 4px grid */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-5: 24px;
  --space-6: 32px;

  --text-xs: 12px;
  --text-sm: 13px;
  --text-md: 14px;
  --text-lg: 18px;
  --text-xl: 24px;

  --radius-sm: 8px;
  --radius-md: 12px;
  --radius-lg: 16px;
  --radius-full: 999px;

  --ease: 150ms cubic-bezier(.2, 0, 0, 1);
  --font-sans: "Inter", system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, monospace;
}

* { box-sizing: border-box; }
html { background: var(--bg); -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  /* The backdrop the glass shows. Fixed, so a long page doesn't stretch it. */
  background:
    radial-gradient(ellipse 70% 55% at 12% 8%, rgb(0 255 204 / 16%), transparent 70%),
    radial-gradient(ellipse 60% 60% at 88% 20%, rgb(255 0 85 / 14%), transparent 70%),
    radial-gradient(ellipse 75% 60% at 50% 100%, rgb(155 81 224 / 22%), transparent 70%),
    var(--bg);
  background-attachment: fixed;
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: var(--text-md);
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
a { color: var(--link); text-decoration: none; transition: color var(--ease); }
a:hover { color: var(--link-hover); text-decoration: underline; text-underline-offset: 2px; }
h1, h2, h3, p { margin: 0 0 var(--space-2); }
h1, h2, h3 { line-height: 1.25; letter-spacing: -.01em; }
img { max-width: 100%; }
code { font-family: var(--font-mono); font-size: .92em; }
small { font-size: var(--text-xs); color: var(--muted); }
blink { animation: blink 1s steps(2, start) infinite; }
@keyframes blink { to { visibility: hidden; } }

:focus-visible { outline: 0; box-shadow: var(--ring); border-radius: 4px; }

.site-inner { max-width: 880px; margin: 0 auto; padding-inline: var(--space-4); }

/* ---------- header ----------
   One row. The two sides start from the same width and only the middle shrinks,
   which keeps it centered on the screen however wide the logo and account text are.
   The row is full width on purpose, while .site-inner still centers the page below. */
.site-bar {
  display: flex; align-items: center; justify-content: space-between; gap: var(--space-4);
  min-height: 64px; padding: 0 24px; background: var(--band); color: #ffffff;
}
.site-bar :focus-visible { box-shadow: 0 0 0 3px rgb(255 255 255 / 55%); }
.site-brand, .site-account { flex: 1 0 200px; min-width: max-content; }
.logo { display: inline-block; color: #ffffff; font-size: var(--text-xl); font-weight: 800; line-height: 1; text-decoration: none; letter-spacing: -.03em; }
.logo:hover { color: #ffffff; text-decoration: none; }
/* The wordmark: crisp white letters with a hard cyan/magenta split and a soft holo glow.
   Shadows only, no clipped gradient, so it stays sharp and readable on every backdrop. */
.logo-word {
  display: inline-block; color: #ffffff;
  text-shadow: -1px 0 #ff2bd6, 1px 0 #00ffcc, 0 0 8px rgb(95 243 255 / 55%), 0 0 18px rgb(177 77 255 / 35%);
  transition: text-shadow var(--ease);
}
.logo:hover .logo-word { text-shadow: -2px 0 #ff2bd6, 2px 0 #00ffcc, 0 0 10px rgb(95 243 255 / 70%), 0 0 22px rgb(177 77 255 / 45%); }
.logo-tld { color: #5ff3ff; font-weight: 700; letter-spacing: 0; }
.logo em { display: block; margin-top: var(--space-1); color: #aebcdf; font-size: var(--text-xs); font-style: normal; font-weight: 400; letter-spacing: 0; }
.site-account { font-size: var(--text-sm); color: #aebcdf; text-align: right; white-space: nowrap; }
.site-account a { color: #ffffff; font-weight: 500; }
.site-account a:hover { color: #ffffff; }

.site-nav { flex: 0 1 620px; display: flex; align-items: center; justify-content: center; gap: var(--space-2); min-width: 0; }
.site-nav a {
  flex: none; padding: var(--space-2) var(--space-4); border-radius: var(--radius-full); text-align: center;
  font-size: var(--text-md); font-weight: 600; line-height: 20px; color: #dbe3f5; text-decoration: none; white-space: nowrap;
  transition: background var(--ease), color var(--ease);
}
.site-nav a:hover { background: rgb(255 255 255 / 12%); color: #ffffff; text-decoration: none; }
.site-nav a[aria-current="page"] { background: rgb(255 255 255 / 16%); color: #ffffff; }
.site-search { position: relative; flex: 1 1 340px; min-width: 120px; max-width: 400px; }
.site-search input {
  display: block; width: 100%; padding: var(--space-2) 40px var(--space-2) var(--space-4); appearance: none;
  border: 1px solid var(--hairline-strong); border-radius: var(--radius-full); background: var(--surface-2);
  color: var(--ink); font: inherit; line-height: 20px;
  transition: border-color var(--ease), box-shadow var(--ease), background var(--ease);
}
.site-search input:hover { border-color: var(--muted); }
.site-search input:focus { outline: 0; border-color: var(--neon-line); background: var(--surface); box-shadow: var(--glow); }
.site-search input::-webkit-search-cancel-button { display: none; }
.site-search button {
  position: absolute; inset: 0 var(--space-1) 0 auto; display: grid; place-items: center; width: 32px; padding: 0;
  border: 0; border-radius: var(--radius-full); background: none; color: var(--muted); cursor: pointer; transition: color var(--ease);
}
.site-search button:hover, .site-search input:focus + button { color: var(--neon-line); }
.search-toggle { display: none; } /* the search bar is always out above 768px */

/* Tall enough to hold the footer at the bottom of a short page: the header and footer are about 132px. */
.site-main { padding-block: var(--space-5); min-height: calc(100vh - 132px); }
.site-footer { text-align: center; font-size: var(--text-xs); color: var(--muted); padding-block: var(--space-5); border-top: 1px solid var(--hairline); }
.site-footer p { margin: 0; }

.flash { background: var(--warn-soft); border: 1px solid var(--warn-line); color: var(--warn-ink); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3); margin: var(--space-3) 0 0; }

/* ---------- boxes and layout ---------- */
.box { background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-md); box-shadow: var(--shadow-sm); margin-bottom: var(--space-4); overflow: hidden; }
.box-title { display: flex; align-items: center; gap: var(--space-2); margin: 0; padding: var(--space-3) var(--space-4); border-bottom: 1px solid var(--hairline); color: var(--ink); font-size: var(--text-sm); font-weight: 600; letter-spacing: 0; }
.box-title::before { content: ""; flex: none; width: 3px; height: 14px; border-radius: var(--radius-full); background: var(--orange); }
.box-body { padding: var(--space-4); }
.box-body > :last-child { margin-bottom: 0; }
.columns { display: grid; grid-template-columns: minmax(0, 1fr) 230px; gap: var(--space-4); }
.columns.reverse { grid-template-columns: 230px minmax(0, 1fr); }
.plain { list-style: none; margin: 0 0 var(--space-3); padding: 0; }
.plain li { padding-block: 2px; }
.avatar { display: block; margin: 0 auto var(--space-3); border: 1px solid var(--hairline); border-radius: var(--radius-lg); object-fit: cover; }
.alerts { display: grid; gap: var(--space-2); margin-bottom: var(--space-4); }
.alert {
  display: block; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm);
  background: var(--danger-soft); border: 1px solid var(--danger-line); color: var(--danger); font-size: var(--text-sm); font-weight: 600;
  transition: border-color var(--ease);
}
.alert:hover { color: var(--danger); border-color: var(--danger); text-decoration: none; }
.button.signup-cta { display: block; margin-top: var(--space-2); text-align: center; background: var(--orange-strong); font-size: var(--text-md); }
.button.signup-cta:hover { background: var(--orange-strong-hover); }
.box-body .top-8 + p, .box-body .friend-grid + p { margin-top: var(--space-3); }
.button + a { margin-left: var(--space-2); }

/* ---------- home feed ---------- */
.feed { max-width: 620px; margin-inline: auto; }
.composer, .post-card { display: flex; gap: var(--space-3); background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-lg); }
.composer { padding: var(--space-4); margin-bottom: var(--space-5); box-shadow: var(--shadow-md); }
.composer img, .post-card img { display: block; width: 48px; height: 48px; border-radius: 50%; object-fit: cover; }
.composer-main, .post-main { flex: 1; min-width: 0; }
.composer textarea {
  display: block; width: 100%; min-height: 76px; padding: var(--space-2) var(--space-3); resize: vertical;
  font: inherit; font-size: 15px; color: var(--ink); background: var(--surface-2);
  border: 1px solid var(--hairline); border-radius: var(--radius-md);
  transition: border-color var(--ease), box-shadow var(--ease), background var(--ease);
}
.composer textarea:hover { border-color: var(--hairline-strong); }
.composer textarea:focus { outline: 0; background: var(--surface); border-color: var(--accent); box-shadow: var(--ring); }
.composer-foot { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-top: var(--space-3); }
.feed-head { display: flex; flex-wrap: wrap; align-items: baseline; justify-content: space-between; gap: var(--space-1) var(--space-3); margin-bottom: var(--space-3); }
.feed-head h1 { margin: 0; font-size: var(--text-lg); font-weight: 700; overflow-wrap: anywhere; }
.location-picker { font-size: var(--text-sm); }
.location-picker summary { cursor: pointer; color: var(--link); }
.location-picker[open] { flex-basis: 100%; }
.location-picker form { margin-top: var(--space-2); }
.location-picker .button { white-space: nowrap; }
.location-picker .hint { margin: 0; }
.post-card { padding: var(--space-3) var(--space-4); margin-bottom: var(--space-3); box-shadow: var(--shadow-sm); }
.post-text { margin: var(--space-1) 0 0; white-space: pre-wrap; overflow-wrap: anywhere; }
/* @mentions and #hashtags: a pill of the same holographic glass, tinted thin enough
   that the text color underneath still carries the contrast. Inline, so a long tag
   wraps with the sentence it sits in. */
.mention, .hashtag {
  font-weight: 600;
  padding: 0 0.3em;
  border-radius: 0.4em;
  border: 1px solid rgba(255, 255, 255, 0.18);
  background: linear-gradient(135deg, rgba(0, 255, 204, 0.14), rgba(155, 81, 224, 0.14)) 0% 50% / 200% 200%;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
  text-decoration: none;
  transition: background-position 400ms ease, box-shadow var(--ease);
}
.hashtag { background-image: linear-gradient(135deg, rgba(95, 243, 255, 0.14), rgba(255, 43, 214, 0.14)); }
.mention:hover, .hashtag:hover { background-position: 100% 50%; box-shadow: 0 0 8px rgba(95, 243, 255, 0.35); text-decoration: none; }
.mention:focus-visible, .hashtag:focus-visible { outline: 0; box-shadow: var(--ring); }
.feed-search { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); margin-bottom: var(--space-3); }
.feed-search input { flex: 1 1 12rem; min-width: 0; }
.feed-empty { padding: var(--space-6) var(--space-4); text-align: center; color: var(--muted); }

/* ---------- the Literary Lounge, see src/routes/stories.js ----------
   Story cards are .post-card, so they take the same glass as the Home feed. The text is
   set for reading: a larger size, longer leading and room between paragraphs. */
.story-lounge { max-width: 680px; }
.story-filters { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-bottom: var(--space-4); }
.story-filters a {
  padding: 2px var(--space-3); border: 1px solid var(--hairline); border-radius: var(--radius-full);
  font-size: var(--text-xs); color: var(--ink); text-decoration: none; background: var(--surface-2);
}
.story-filters a:hover { border-color: var(--hairline-strong); text-decoration: none; }
.story-filters a[aria-current="page"] { border-color: var(--neon-line); box-shadow: var(--glow); }
.story-card { padding: var(--space-4); }
.story-avatar { flex: none; align-self: flex-start; }
.story-avatar > canvas { display: block; } /* the Pixel Avatar, without the base inline gap */
.story-head { margin-bottom: var(--space-2); }
.story-category {
  display: inline-block; padding: 0 var(--space-2); border: 1px solid var(--hairline-strong); border-radius: var(--radius-full);
  font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--link); text-decoration: none;
}
.story-title { margin: var(--space-1) 0 2px; font-size: var(--text-lg); line-height: 1.25; overflow-wrap: anywhere; }
.story-title a { color: inherit; text-decoration: none; }
.story-title a:hover { text-decoration: underline; }
.story-handle { opacity: 0.8; }
.story-text { font-size: 16px; line-height: 1.7; overflow-wrap: anywhere; }
.story-text p { margin: 0 0 var(--space-3); white-space: pre-wrap; }
.story-text p:last-child { margin-bottom: 0; }
.story-back { margin-bottom: var(--space-3); }
/* Two classes so it outranks .form's 560px cap, which left the composer narrower than the
   story cards and pinned to the left of the column. It spans the column like they do. */
.story-lounge .story-composer {
  max-width: none; margin: var(--space-5) 0 0; padding: var(--space-4);
  background: var(--surface); border: 1px solid var(--hairline); border-radius: var(--radius-lg); box-shadow: var(--shadow-md);
}
.story-composer-title { margin: 0 0 var(--space-2); font-size: var(--text-md); }
.story-composer textarea { min-height: 220px; resize: vertical; line-height: 1.6; }
.story-prompt { margin: 0; padding: var(--space-3); border: 1px dashed var(--hairline-strong); border-radius: var(--radius-md); font-size: var(--text-sm); line-height: 1.6; }
.story-prompt code { white-space: nowrap; }
.story-palette summary { cursor: pointer; color: var(--link); font-size: var(--text-sm); }
.story-palette-body { display: grid; gap: var(--space-2); margin-top: var(--space-2); }
.story-palette-group { display: flex; flex-wrap: wrap; align-items: center; gap: 4px; }
.story-palette-label { flex-basis: 100%; font-size: 11px; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--muted); }
.token-button {
  min-height: 28px; padding: 0 var(--space-2); border: 1px solid var(--hairline); border-radius: var(--radius-sm); cursor: pointer;
  font: 600 12px/1 "Courier New", Courier, monospace; background: var(--surface-2);
}
.token-button:not(.emotion) { color: var(--ink); }
.token-button.emotion { padding: 0 var(--space-2); border-radius: var(--radius-sm); } /* .emotion comes later and would win */
.token-button .tfx-marquee { width: 6em; }
.token-button:hover { border-color: var(--hairline-strong); }
.token-button:focus-visible { outline: 2px solid var(--neon-line); outline-offset: 1px; }
@media (pointer: coarse) { .token-button { min-height: 36px; } }

/* ---------- search ---------- */
.search-head { margin-bottom: var(--space-3); font-size: var(--text-md); overflow-wrap: anywhere; }
.search-group .box-title::before { background: var(--neon-line); box-shadow: 0 0 8px var(--neon-line); }
.search-group .list-table { margin-bottom: 0; }
.search-group .list-table img { display: block; object-fit: cover; border-radius: var(--radius-sm); }
.search-group .list-table td:has(> a > img) { width: 62px; }
.search-group .post-card { margin-bottom: var(--space-2); box-shadow: none; }
.search-more { margin: var(--space-3) 0 0; font-size: var(--text-sm); }

/* ---------- friends ---------- */
.friend-grid, .top-8 { display: grid; grid-template-columns: repeat(auto-fill, minmax(100px, 1fr)); gap: var(--space-3) var(--space-2); }
.top-8 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.friend { text-align: center; min-width: 0; font-size: var(--text-xs); }
.friend-name { display: block; margin-bottom: var(--space-1); font-weight: 600; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.friend img {
  display: block; margin: 0 auto var(--space-1); width: 90px; height: 90px; aspect-ratio: 1; object-fit: cover;
  border: 1px solid var(--hairline); border-radius: var(--radius-md);
  transition: transform var(--ease), box-shadow var(--ease);
}
.friend a:hover img { transform: translateY(-2px); box-shadow: var(--shadow-md); }
.online-now {
  display: inline-flex; align-items: center; gap: var(--space-1); padding: 0 var(--space-2); border-radius: var(--radius-full);
  background: #dff6e7; color: #17603a; font-size: 11px; font-weight: 600; line-height: 18px; white-space: nowrap;
}
.online-now::before { content: ""; width: 6px; height: 6px; border-radius: 50%; background: #1f9d5a; }

/* ---------- forms ---------- */
.form { display: grid; gap: var(--space-3); max-width: 560px; }
.form label { display: grid; gap: var(--space-1); font-weight: 600; font-size: var(--text-sm); }
.form .check { display: flex; gap: var(--space-2); align-items: center; font-weight: 400; }
.form.compact { display: flex; gap: var(--space-2); max-width: none; margin-bottom: var(--space-2); }
.form.compact input { flex: 1 1 auto; min-width: 0; }
.form input:not([type=checkbox]), .form textarea, .form select, .comment-form textarea {
  width: 100%; padding: 6px var(--space-3); font: inherit; font-weight: 400; color: var(--ink);
  background: var(--surface); border: 1px solid var(--hairline-strong); border-radius: var(--radius-sm);
  transition: border-color var(--ease), box-shadow var(--ease);
}
.form input:not([type=checkbox]):hover, .form textarea:hover, .form select:hover, .comment-form textarea:hover { border-color: var(--muted); }
.form input:not([type=checkbox]):focus, .form textarea:focus, .form select:focus, .comment-form textarea:focus { outline: 0; border-color: var(--accent); box-shadow: var(--ring); }
/* An open dropdown's list is drawn by the browser over whatever glass sits behind it, and
   the holographic masks washed its labels out. Solid black on white, always, so a visitor
   picking a theme can read every choice. !important because member CSS can't reach site
   pages, but a browser's dark color-scheme and the glass tokens can. */
.theme-select-dropdown option,
select option {
  color: #000000 !important;
  background-color: #ffffff !important;
}
/* The layout style titles over each group of presets (Classic Mid-2000s Split, Stacked
   Modular Canvas, Borderless Immersive Matrix). An optgroup isn't an option, so it took
   the select's pale glass ink and nearly vanished on the white list. Deep indigo, bold. */
.theme-select-dropdown optgroup,
select optgroup {
  color: #1a0f3d !important;
  background-color: #eef0f8 !important;
  font-weight: 800;
  font-style: normal;
  text-shadow: none;
}
::placeholder { color: var(--muted); opacity: .8; }
.form fieldset { border: 1px solid var(--hairline); border-radius: var(--radius-sm); display: grid; gap: var(--space-3); }
.form textarea.code { font: 12px/1.5 var(--font-mono); white-space: pre; overflow-x: auto; }
.hint { color: var(--muted); font-size: var(--text-xs); }
.form .privacy-toggle { display: block; margin: 0; padding: 0; border: 0; }
.privacy-toggle legend { font-weight: 600; font-size: var(--text-sm); padding: 0 0 var(--space-1); }
.privacy-options { display: inline-flex; overflow: hidden; border: 1px solid var(--hairline-strong); border-radius: var(--radius-sm); }
.form .privacy-toggle label { display: block; position: relative; font-weight: 400; }
.form .privacy-toggle input[type=radio] { position: absolute; width: 1px; height: 1px; padding: 0; opacity: 0; }
.privacy-toggle span { display: block; padding: 6px var(--space-4); cursor: pointer; color: var(--ink); }
.privacy-toggle label + label span { border-left: 1px solid var(--hairline); }
.privacy-toggle input:checked + span { background: var(--accent); color: #fff; font-weight: 600; }
.privacy-toggle input:focus-visible + span { outline: 2px solid var(--accent); outline-offset: -4px; }
.error { color: var(--danger); font-weight: 600; }
.notice { background: var(--ok-soft); border: 1px solid var(--ok-line); color: var(--ok-ink); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3); }
.warnings { background: var(--danger-soft); border: 1px solid var(--danger-line); border-radius: var(--radius-sm); padding: var(--space-2) var(--space-3); margin-bottom: var(--space-2); }
.warnings ul { margin: var(--space-1) 0 0; padding-left: var(--space-4); }

/* The CSS Cheat Sheet under the Custom CSS box, from cssGuide() in src/routes/edit.js. */
.css-guide { display: grid; gap: var(--space-3); margin-top: var(--space-4); padding: var(--space-4); border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface-2); }
.css-guide h3, .css-guide h4, .css-guide p { margin: 0; }
.css-guide h3 { font-size: 1.05em; }
.css-guide h4 { font-size: .95em; color: var(--link); }
.css-guide p { color: var(--ink-2); line-height: 1.5; }
.css-guide-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: var(--space-3); }
.css-guide-card, .css-guide-shield { display: grid; gap: var(--space-2); align-content: start; min-width: 0; padding: var(--space-3); border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface); }
.css-guide-shield { border-color: var(--danger-line); background: var(--danger-soft); }
.css-guide pre { margin: 0; padding: var(--space-2) var(--space-3); overflow-x: auto; border-radius: var(--radius-sm); background: var(--control); font-size: var(--text-xs); line-height: 1.55; white-space: pre; }

.button {
  display: inline-block; padding: 6px var(--space-4); border: 1px solid transparent; border-radius: var(--radius-full);
  background: var(--accent); color: #ffffff; font: inherit; font-size: var(--text-sm); font-weight: 600; line-height: 20px;
  text-decoration: none; cursor: pointer; box-shadow: var(--shadow-sm);
  transition: background var(--ease), border-color var(--ease), box-shadow var(--ease), transform var(--ease);
}
.button:hover { background: var(--accent-hover); color: #ffffff; text-decoration: none; box-shadow: var(--shadow-md); transform: translateY(-1px); }
.button:active { transform: translateY(0); box-shadow: var(--shadow-sm); }
.button:focus-visible { border-radius: var(--radius-full); box-shadow: var(--ring); }
.button.secondary { background: var(--surface); color: var(--ink); border-color: var(--hairline-strong); }
.button.secondary:hover { background: var(--hover); color: var(--ink); }
.button.danger { background: var(--danger-fill); color: #ffffff; }
.button.danger:hover { background: var(--danger-hover); }
.inline-form { display: inline; }
.actions { margin-bottom: var(--space-2); }
.link-button { background: none; border: 0; padding: 0; font: inherit; color: var(--link); cursor: pointer; transition: color var(--ease); }
.link-button:hover { color: var(--link-hover); text-decoration: underline; text-underline-offset: 2px; }
.link-button.light { color: #ffffff; font-weight: 500; }
.link-button.light:hover { color: #ffffff; }

/* ---------- tables and lists ---------- */
.list-table { width: 100%; border-collapse: collapse; font-size: var(--text-sm); margin-bottom: var(--space-3); }
.list-table th, .list-table td { padding: var(--space-2); border-bottom: 1px solid var(--hairline); vertical-align: top; }
.list-table th { padding-top: 0; color: var(--muted); font-size: var(--text-xs); font-weight: 600; text-align: left; }
.list-table th:first-child, .list-table td:first-child { padding-left: 0; }
.list-table th:last-child, .list-table td:last-child { padding-right: 0; }
.list-table tr:last-child td { border-bottom: 0; }
.list-table td.nowrap { color: var(--muted); font-size: var(--text-xs); line-height: 20px; }
.list-table tr.unread td { font-weight: 600; background: var(--orange-wash); }
.nowrap { white-space: nowrap; }
.pager, .filters { font-size: var(--text-sm); color: var(--muted); }
.byline { color: var(--muted); font-size: var(--text-xs); }
.tabs { display: flex; flex-wrap: wrap; gap: var(--space-1); margin-bottom: var(--space-3); font-size: var(--text-sm); }
.tabs a { background: var(--blue-pale); border: 1px solid var(--line); border-radius: var(--radius-full); padding: var(--space-1) var(--space-3); text-decoration: none; font-weight: 600; }
.tabs a.active { background: var(--accent); border-color: var(--accent); color: #ffffff; }
.thread-row, .message-head { display: flex; gap: var(--space-2); padding-block: var(--space-2); border-bottom: 1px solid var(--hairline); }
.thread-row > div { min-width: 0; flex: 1; }
.user-content { overflow-wrap: anywhere; padding-block: var(--space-1); }
.user-content a { text-decoration: underline; text-underline-offset: 2px; }
.user-content img { height: auto; }
.user-content table { max-width: 100%; }

.photo-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(170px, 1fr)); gap: var(--space-3); }
.photo-grid figure { margin: 0; font-size: var(--text-xs); min-width: 0; }
.photo-grid img { display: block; width: 100%; height: 150px; object-fit: cover; border: 1px solid var(--hairline); border-radius: var(--radius-sm); }
.photo-grid code { display: block; word-break: break-all; }

/* ---------- Top 8 editor ---------- */
.top8-grid { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); gap: var(--space-2); }
.top8-slot { border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--blue-pale); padding: var(--space-2); text-align: center; cursor: grab; min-width: 0; }
.top8-slot.drag-over { outline: 2px dashed var(--orange); }
.top8-slot img { display: block; margin: 2px auto var(--space-1); width: 90px; height: 90px; object-fit: cover; border-radius: var(--radius-sm); }
.top8-slot select { width: 100%; font-size: var(--text-xs); }
.slot-number { font-weight: 700; color: var(--link-hover); }

/* ---------- games ---------- */
.game-list { display: grid; grid-template-columns: repeat(auto-fill, minmax(230px, 1fr)); gap: var(--space-3); }
.game-card { border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--blue-pale); padding: var(--space-2); }
.login-help { margin-top: var(--space-2); }
.arcade-card { display: flex; flex-direction: column; padding: 0; overflow: hidden; border-radius: var(--radius-md); box-shadow: var(--shadow-sm); transition: box-shadow var(--ease), transform var(--ease); }
.arcade-card:hover { box-shadow: var(--shadow-md); transform: translateY(-2px); }
.arcade-thumb { position: relative; display: block; aspect-ratio: 16 / 9; overflow: hidden; background: #101030; color: #ffffff; text-decoration: none; }
.arcade-thumb:hover { color: #ffffff; text-decoration: none; }
.arcade-thumb img { display: block; width: 100%; height: 100%; object-fit: cover; transition: transform var(--ease); }
.arcade-thumb:hover img { transform: scale(1.05); }
.arcade-thumb::after { content: ""; position: absolute; inset: 0; background: linear-gradient(180deg, transparent 45%, rgb(8 10 28 / 85%)); }
.arcade-thumb h3 { position: absolute; inset: auto var(--space-3) var(--space-2); z-index: 1; margin: 0; color: #ffffff; font-size: var(--text-lg); line-height: 1.2; text-shadow: 0 1px 3px #000000; }
.arcade-info { display: flex; flex: 1; flex-direction: column; gap: var(--space-1); padding: var(--space-3); }
.arcade-info p { margin: 0; }
.arcade-info .byline { margin-top: auto; }
.arcade-add .button { width: 100%; }
.arcade-add .button:disabled { opacity: .6; cursor: default; }
/* ---------- the Arcade's Feature Title Showcase ----------
   AnimaShift RPG's hero, above the grid: frosted glass inside a neon frame. The frame is a
   conic gradient on ::before, spun by transform only, and ::after is the glass laid over it
   3px in, so only a rim of the gradient shows. Reduced motion holds it still. */
.arcade-feature { position: relative; isolation: isolate; overflow: hidden; overflow: clip; margin-bottom: var(--space-4); padding: 3px; border-radius: 22px;
  box-shadow: 0 0 22px rgb(255 43 214 / 35%), 0 0 60px rgb(95 243 255 / 18%); animation: feature-glow 3.2s ease-in-out infinite alternate; }
.arcade-feature::before { content: ""; position: absolute; z-index: -2; left: 50%; top: 50%; width: max(160%, 1300px); aspect-ratio: 1;
  transform: translate(-50%, -50%); background: conic-gradient(from 0deg, #ff2bd6, #5ff3ff, #fff27a, #b14dff, #ff2bd6); animation: feature-spin 7s linear infinite; }
.arcade-feature::after { content: ""; position: absolute; z-index: -1; inset: 3px; border-radius: 19px;
  background: linear-gradient(135deg, rgb(32 18 84 / 92%), rgb(12 14 40 / 94%) 55%, rgb(60 14 72 / 92%)); }
.arcade-feature-inner { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.25fr); gap: var(--space-4); align-items: center; padding: var(--space-4);
  border-radius: 19px; color: #f4f1ff; -webkit-backdrop-filter: blur(14px) saturate(140%); backdrop-filter: blur(14px) saturate(140%);
  background: radial-gradient(120% 90% at 0% 0%, rgb(255 122 217 / 18%), transparent 60%), radial-gradient(90% 80% at 100% 100%, rgb(95 243 255 / 14%), transparent 60%); }
.feature-copy { min-width: 0; }
.feature-kicker { margin: 0 0 var(--space-2); display: flex; align-items: center; gap: 8px; flex-wrap: wrap; font-size: 12px; letter-spacing: .14em; text-transform: uppercase; color: #cfc6ff; }
.feature-badge { padding: 3px 10px; border-radius: 999px; background: linear-gradient(90deg, #ff2bd6, #b14dff); color: #ffffff; letter-spacing: .08em; box-shadow: 0 0 12px rgb(255 43 214 / 55%); }
.feature-title { margin: 0 0 var(--space-2); font-size: clamp(30px, 5vw, 48px); line-height: 1.05; font-weight: 900; letter-spacing: -.01em;
  background: linear-gradient(90deg, #ff7ad9, #fff27a 45%, #7ff6ff); -webkit-background-clip: text; background-clip: text; color: transparent;
  filter: drop-shadow(0 0 14px rgb(255 122 217 / 45%)); }
.feature-lede { margin: 0 0 var(--space-3); line-height: 1.55; color: #e9e4ff; }
.feature-lede strong { color: #fff27a; }
.feature-points { list-style: none; margin: 0 0 var(--space-3); padding: 0; display: grid; gap: 6px; font-size: 14px; color: #e9e4ff; }
.feature-points span { display: inline-block; width: 1.6em; }
.feature-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; }
.feature-launch { font-size: 17px; padding: 12px 22px; border-radius: 999px; border: 0; color: #1b0838; font-weight: 800; text-decoration: none;
  background: linear-gradient(90deg, #fff27a, #ff9de6 50%, #7ff6ff); box-shadow: 0 6px 24px rgb(255 122 217 / 45%), inset 0 1px 0 rgb(255 255 255 / 70%);
  transition: transform var(--ease), box-shadow var(--ease); }
.feature-launch:hover { color: #1b0838; text-decoration: none; transform: translateY(-2px); box-shadow: 0 10px 30px rgb(255 122 217 / 60%), inset 0 1px 0 rgb(255 255 255 / 70%); }
.feature-launch small { font-weight: 700; opacity: .75; }
.feature-controls { margin: var(--space-3) 0 0; color: #b9b2e6; }
.feature-champion { color: #fff27a; }
.feature-stage { min-width: 0; border-radius: 16px; overflow: hidden; box-shadow: 0 16px 40px rgb(0 0 0 / 45%), 0 0 0 1px rgb(255 255 255 / 18%); }
.feature-stage .game-player { margin: 0; background: #0b0a20; }
.feature-stage .game-start { width: 100%; aspect-ratio: 16 / 10; min-height: 0; border: 0; border-radius: 0; color: #ffffff; font-family: inherit; font-size: 20px; font-weight: 800;
  background: linear-gradient(180deg, transparent 55%, rgb(11 10 32 / 85%)), url("/img/games/animashift.svg") center / cover no-repeat;
  display: flex; align-items: flex-end; justify-content: center; padding-bottom: 18px; text-shadow: 0 2px 8px #000000; }
@keyframes feature-spin { from { transform: translate(-50%, -50%) rotate(0); } to { transform: translate(-50%, -50%) rotate(1turn); } }
@keyframes feature-glow { to { box-shadow: 0 0 30px rgb(95 243 255 / 40%), 0 0 70px rgb(255 43 214 / 22%); } }
@media (max-width: 760px) { .arcade-feature-inner { grid-template-columns: minmax(0, 1fr); padding: var(--space-3); } .feature-stage { order: -1; } }
@media (prefers-reduced-motion: reduce) { .arcade-feature, .arcade-feature::before { animation: none; } }

/* The CosmaIM Turn-Based Tabletop Hub on /arcade (src/routes/arcade.js): a glass panel of
   preview cards. The little boards are CSS grids of spans, so there are no images. */
.tabletop-hub {
  margin-bottom: var(--space-4); padding: var(--space-4); border-radius: 18px; color: #f4f1ff;
  border: 1px solid rgb(255 255 255 / 20%);
  background: radial-gradient(110% 90% at 0% 0%, rgb(95 243 255 / 16%), transparent 60%), radial-gradient(90% 80% at 100% 100%, rgb(255 43 214 / 16%), transparent 60%), rgb(14 14 40 / 72%);
  -webkit-backdrop-filter: blur(14px) saturate(150%); backdrop-filter: blur(14px) saturate(150%);
  box-shadow: 0 10px 30px rgb(0 0 0 / 35%), inset 0 1px 0 rgb(255 255 255 / 18%);
}
.tabletop-head h2 { margin: 0 0 var(--space-1); color: #ffffff; font-size: var(--text-xl, 1.4rem); text-shadow: 0 0 12px rgb(95 243 255 / 45%); }
.tabletop-head p { margin: 0 0 var(--space-3); color: #d6d9f2; }
.tabletop-head .tabletop-badge {
  display: inline-block; margin-bottom: var(--space-2); padding: 2px 10px; border-radius: 999px; font-size: 11px; font-weight: 700;
  letter-spacing: .08em; text-transform: uppercase; color: #0b0d22; background: linear-gradient(135deg, #5ff3ff, #ff71ce);
}
.tabletop-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 280px), 1fr)); gap: var(--space-3); }
.tabletop-card {
  display: flex; flex-direction: column; gap: var(--space-3); padding: var(--space-3); border-radius: 14px;
  border: 1px solid rgb(255 255 255 / 16%); background: rgb(255 255 255 / 6%); transition: transform var(--ease), box-shadow var(--ease);
}
.tabletop-card:hover { transform: translateY(-2px); box-shadow: 0 0 18px rgb(95 243 255 / 22%); }
.tabletop-card h3 { margin: 0 0 var(--space-1); color: #ffffff; }
.tabletop-card p { margin: 0 0 var(--space-2); color: #d6d9f2; font-size: var(--text-sm); }
.tabletop-kicker { margin: 0 !important; font-size: 11px !important; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: #9ff7ff !important; }
.tabletop-points { margin: 0; padding-left: 1.1em; color: #c3c8e6; font-size: var(--text-xs); }
.tabletop-preview { display: grid; place-items: center; padding: var(--space-3); border-radius: 12px; background: rgb(6 8 28 / 65%); }
.mini-c4 {
  display: grid; grid-template-columns: repeat(7, 1fr); gap: 5px; width: min(100%, 230px); padding: 8px; border-radius: 10px;
  background: linear-gradient(135deg, rgb(60 90 220 / 55%), rgb(150 60 220 / 50%));
}
.mini-c4 span { aspect-ratio: 1; border-radius: 50%; background: rgb(5 6 24 / 75%); }
.mini-c4 .is-p1 { background: radial-gradient(circle at 35% 35%, #ffffff, #5ff3ff 40%, #0b6f8a); box-shadow: 0 0 8px #5ff3ff; }
.mini-c4 .is-p2 { background: radial-gradient(circle at 35% 35%, #ffffff, #ff2bd6 40%, #7a1066); box-shadow: 0 0 8px #ff2bd6; }
.mini-radar {
  display: grid; grid-template-columns: repeat(8, 1fr); gap: 2px; width: min(100%, 200px); padding: 6px; border-radius: 10px;
  background: radial-gradient(circle, rgb(20 90 90 / 70%), rgb(6 8 28 / 90%));
}
.mini-radar .cell { aspect-ratio: 1; border-radius: 3px; border: 1px solid rgb(95 243 255 / 22%); }
.mini-radar .is-miss { background: radial-gradient(circle, rgb(220 235 255 / 70%) 18%, transparent 24%); }
.mini-radar .is-hit { background: radial-gradient(circle, #ff2bd6 30%, rgb(255 43 214 / 25%) 60%); box-shadow: 0 0 6px #ff2bd6; }
.mini-radar .is-sunk { background: rgb(255 90 90 / 40%); border-color: #ff2bd6; }
.tabletop-actions { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); margin-top: var(--space-3); }
.tabletop-actions .hint { margin: 0; color: #c3c8e6; }
.tabletop-launch {
  padding: 10px 18px; font-weight: 700; color: #0b0d22 !important; border: 0; border-radius: 999px;
  background: linear-gradient(135deg, #5ff3ff, #ff71ce); box-shadow: 0 0 16px rgb(255 113 206 / 45%);
}
.tabletop-launch:hover { text-decoration: none; filter: brightness(1.08); }
@media (max-width: 600px) {
  .tabletop-hub { padding: var(--space-3); }
  .tabletop-launch { width: 100%; text-align: center; }
}

/* Trophy flags on a profile card, awarded by the server, see user_trophies. */
.trophy-flags { list-style: none; margin: 4px 0; padding: 0; display: flex; flex-wrap: wrap; gap: 4px; }
.trophy-flag { display: inline-flex; align-items: center; gap: 4px; padding: 2px 8px 2px 4px; border-radius: 999px; font-size: 11px; font-weight: 700;
  color: #2a0f4a; background: linear-gradient(90deg, #fff27a, #ff9de6); box-shadow: 0 0 10px rgb(255 122 217 / 45%); }

.game-player { position: relative; background: #000000; margin-bottom: var(--space-2); }
.game-player:fullscreen { display: flex; flex-direction: column; justify-content: center; margin: 0; }
.game-player:fullscreen iframe { flex: 1; height: 100%; }
.game-fullscreen {
  position: absolute; top: 6px; right: 6px; z-index: 2; display: grid; place-items: center;
  min-width: 36px; min-height: 36px; padding: 0 8px; border-radius: 6px; cursor: pointer;
  color: #ffcc00; font: bold 18px/1 "Courier New", monospace;
  border: 1px solid color-mix(in srgb, currentColor 55%, rgb(255 255 255 / 20%));
  background: linear-gradient(180deg, rgb(255 255 255 / 18%), rgb(255 255 255 / 3%) 50%, rgb(0 0 0 / 25%)), rgb(10 12 30 / 60%);
  backdrop-filter: blur(6px); box-shadow: inset 0 1px 0 rgb(255 255 255 / 28%), 0 0 10px color-mix(in srgb, currentColor 50%, transparent);
  text-shadow: 0 0 4px currentColor;
}
.game-fullscreen:hover { box-shadow: inset 0 1px 0 rgb(255 255 255 / 28%), 0 0 14px currentColor; }
.game-fullscreen:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
@media (pointer: coarse) { .game-fullscreen { min-width: 44px; min-height: 44px; } }
.game-player iframe { display: block; width: 100%; border: 0; background: #000000; }
.game-start {
  display: block; width: 100%; min-height: 160px; border: 0; cursor: pointer;
  background: repeating-linear-gradient(0deg, #101030, #101030 3px, #16164a 3px, #16164a 6px);
  color: #ffcc00; font: bold 16px "Courier New", monospace; text-shadow: 2px 2px 0 #cc0000;
}
.game-start:hover { color: #ffffff; }

/* ---------- profile ----------
   .profile-guard is unreachable from user CSS, which is scoped to #profile.
   It clips anything a profile absolutely positions, sizes or transforms to the
   profile area, and isolation stops blend modes and backdrop-filter reaching site
   chrome. overflow: clip, unlike hidden, leaves position: sticky working.
   sanitizeCss refuses position: fixed, the one value that escapes the clipping.
   The z-index below is the second layer: if fixed ever got through, isolation
   would still trap it under the chrome. Keep both, so that one mistake cannot
   let a profile cover the real header with a fake one.
   Colors are set here so the site's light text cannot leak into a themed profile. */
.profile-guard { position: relative; isolation: isolate; overflow: hidden; overflow: clip; color: var(--ink); }
.site-header, .site-footer, .flash { position: relative; z-index: 1; }
#profile { background: #ffffff; min-height: calc(100vh - 132px); padding-block: 14px; }
.profile-inner { max-width: 880px; margin: 0 auto; padding-inline: 16px; display: grid; grid-template-columns: 320px minmax(0, 1fr); gap: 16px; }
.profile-left, .profile-right { min-width: 0; }
.profile-name { font-size: 22px; margin-bottom: 4px; }
.profile-card { border-collapse: collapse; margin-bottom: 6px; width: 100%; }
.profile-card td { vertical-align: top; padding: 0 8px 0 0; }
.profile-pic { display: block; border: 1px solid var(--line); object-fit: cover; }
.profile-facts { font-size: 12px; }
.profile-facts p { margin: 0 0 3px; }
.headline { font-style: italic; }
.last-login { font-size: 11px; color: #555555; margin-top: 6px !important; }
.mood, .view-my { font-size: 12px; margin-bottom: 8px; }
.music-player { border: 1px solid var(--line); border-radius: 8px; background: var(--blue-pale); padding: 6px; margin-bottom: 8px; color: #222222; overflow: hidden; }
.music-player audio { width: 100%; display: block; }
.song-title { font-weight: bold; font-size: 12px; margin-bottom: 4px; }
.song-title span { font-weight: normal; }
.music-embed { overflow: hidden; border-radius: 8px; }
.music-embed iframe { display: block; width: 100%; border: 0; border-radius: 8px; }
.music-start {
  display: block; width: 100%; min-height: 44px; border: 1px solid var(--line); border-radius: 8px; cursor: pointer;
  background: #ffffff; color: #222222; font-weight: bold; font-size: 12px;
}
.music-start:hover { background: var(--blue-pale); }
.music-link { font-size: 11px; margin-top: 4px; }
.music-hint { font-size: 11px; margin: 4px 0; }
.music-hint:empty { display: none; }
/* ---------- the retro deck: the profile music player ----------
   A late-90s desktop media player in glass. Every accent is currentColor, and the
   colored parts (.deck-screen, .deck-button, .deck-video, .deck-num) take one color
   between them: neon cyan here, a stock theme's accent from skin() in src/themes.js,
   the Customizer's glow color from src/visual.js, or whatever a member's own CSS sets.
   So borders, glows, icons and the scrolling title all follow the profile's look. */
.retro-deck .deck-screen, .retro-deck .deck-button, .retro-deck .deck-video, .retro-deck .deck-num { color: #29f3ff; }
.deck-shell {
  position: relative; padding: 6px; border: 1px solid rgb(255 255 255 / 22%); border-radius: 10px;
  background: linear-gradient(180deg, rgb(255 255 255 / 16%), rgb(255 255 255 / 4%) 42%, rgb(0 0 0 / 22%)), rgb(14 14 34 / 55%);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 30%), inset 0 -1px 0 rgb(0 0 0 / 35%), 0 4px 14px rgb(0 0 0 / 30%);
  -webkit-backdrop-filter: blur(10px) saturate(160%); backdrop-filter: blur(10px) saturate(160%);
}
/* The grip ridges across the top of an old player's title bar. */
.deck-shell::before {
  content: ""; display: block; height: 3px; margin: 0 18% 5px; border-radius: 2px; opacity: 0.5;
  background: repeating-linear-gradient(90deg, rgb(255 255 255 / 55%) 0 2px, transparent 2px 4px);
}
.deck-screen {
  padding: 5px 7px 6px; border: 1px solid color-mix(in srgb, currentColor 45%, transparent); border-radius: 6px;
  font: 700 11px/1.2 "Courier New", Courier, monospace; letter-spacing: 0.06em;
  text-shadow: 0 0 4px currentColor, 0 0 10px color-mix(in srgb, currentColor 55%, transparent);
  /* dot-matrix pixels and scanlines over a dark glass well */
  background:
    radial-gradient(circle, rgb(255 255 255 / 7%) 0.7px, transparent 1px) 0 0 / 3px 3px,
    repeating-linear-gradient(180deg, rgb(0 0 0 / 22%) 0 1px, transparent 1px 3px),
    linear-gradient(180deg, rgb(0 0 0 / 70%), rgb(0 0 0 / 52%));
  box-shadow: inset 0 0 14px color-mix(in srgb, currentColor 22%, transparent), 0 0 8px color-mix(in srgb, currentColor 25%, transparent);
}
.deck-readout { display: flex; align-items: center; gap: 6px; font-size: 10px; opacity: 0.9; }
.deck-led { width: 7px; height: 7px; border-radius: 50%; background: currentColor; opacity: 0.3; box-shadow: 0 0 6px currentColor; }
.deck-count { font-variant-numeric: tabular-nums; }
.deck-eq { display: flex; align-items: flex-end; gap: 2px; height: 10px; margin-left: auto; }
.deck-eq i { width: 3px; height: 30%; background: currentColor; box-shadow: 0 0 4px currentColor; transform-origin: bottom; }
.deck-eq i:nth-child(2) { height: 55%; }
.deck-eq i:nth-child(3) { height: 40%; }
.deck-eq i:nth-child(4) { height: 70%; }
.deck-marquee {
  overflow: hidden; margin-top: 4px; white-space: nowrap; font-size: 15px; line-height: 22px;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000000 8%, #000000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000000 8%, #000000 92%, transparent);
}
/* Starts a third of the way in, so the title is on screen from the first frame. */
.deck-title { display: inline-block; padding-left: 100%; animation: deck-scroll var(--deck-scroll, 12s) linear calc(var(--deck-scroll, 12s) * -0.33) infinite; }
@keyframes deck-scroll { from { transform: translateX(0); } to { transform: translateX(-100%); } }
.retro-deck.is-playing .deck-led { opacity: 1; animation: deck-blink 1.2s steps(2, jump-none) infinite; }
.retro-deck.is-playing .deck-eq i { animation: deck-eq 0.9s ease-in-out infinite alternate; }
.retro-deck.is-playing .deck-eq i:nth-child(2) { animation-delay: -0.3s; animation-duration: 0.7s; }
.retro-deck.is-playing .deck-eq i:nth-child(3) { animation-delay: -0.6s; animation-duration: 1.1s; }
.retro-deck.is-playing .deck-eq i:nth-child(4) { animation-delay: -0.15s; animation-duration: 0.8s; }
.retro-deck.is-playing .deck-eq i:nth-child(5) { animation-delay: -0.45s; }
@keyframes deck-blink { 50% { opacity: 0.35; } }
@keyframes deck-eq { from { transform: scaleY(0.35); } to { transform: scaleY(2.6); } }
.deck-controls { display: grid; grid-template-columns: repeat(6, 1fr); gap: 6px; margin-top: 6px; }
.deck-button {
  display: grid; place-items: center; min-height: 34px; padding: 0; border-radius: 6px; cursor: pointer;
  border: 1px solid color-mix(in srgb, currentColor 50%, rgb(255 255 255 / 20%));
  background: linear-gradient(180deg, rgb(255 255 255 / 18%), rgb(255 255 255 / 3%) 50%, rgb(0 0 0 / 20%)), rgb(10 12 30 / 60%);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 28%), 0 2px 4px rgb(0 0 0 / 35%);
  transition: box-shadow 160ms ease, background-color 160ms ease, transform 80ms ease;
}
.deck-button svg { filter: drop-shadow(0 0 3px currentColor); }
.deck-button:hover { background-color: rgb(30 34 70 / 70%); box-shadow: inset 0 1px 0 rgb(255 255 255 / 28%), 0 0 10px color-mix(in srgb, currentColor 65%, transparent); }
.deck-button:active { transform: translateY(1px); box-shadow: inset 0 2px 4px rgb(0 0 0 / 45%); }
.deck-button:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }
.deck-button[aria-pressed="true"], .deck-button[aria-expanded="true"] {
  background: linear-gradient(180deg, color-mix(in srgb, currentColor 35%, transparent), color-mix(in srgb, currentColor 12%, transparent)), rgb(10 12 30 / 60%);
  box-shadow: inset 0 0 8px color-mix(in srgb, currentColor 45%, transparent), 0 0 12px color-mix(in srgb, currentColor 70%, transparent);
}
/* The glass video window. Shut at 0px for audio, it opens to 16:9 under the deck only
   while a YouTube video is the active track and the visualizer is shut: opening FX sets
   [hidden] on it (public/js/site.js), and that wins over every rule here. */
.deck-video {
  max-height: 0; margin-top: 0; overflow: hidden; border-radius: 8px; border: 0 solid color-mix(in srgb, currentColor 45%, transparent);
  transition: max-height 450ms ease, margin-top 450ms ease, border-width 450ms ease;
}
.deck-video[data-kind="video"] {
  max-height: 480px; margin-top: 6px; border-width: 1px; padding: 3px; background: rgb(0 0 0 / 35%);
  box-shadow: 0 0 14px color-mix(in srgb, currentColor 30%, transparent), inset 0 0 10px rgb(255 255 255 / 8%);
}
/* The window holds no frame of its own: its slot is a 16:9 space the media dock lays the
   video over (public/js/media-core.js), so the video survives the page around it. */
.retro-deck { position: relative; }
.deck-video[hidden] { display: none !important; }
.deck-video[data-kind="video"] .deck-video-slot { aspect-ratio: 16 / 9; }
/* The FX visualizer, under the controls. A 0fr grid row slides open to its content's own
   height, so there is no guessed max-height and nothing below it jumps. The canvas is
   contained: drawing on it never makes the browser lay out or repaint the page around it. */
.deck-fx { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 360ms ease, margin-top 360ms ease; }
.deck-fx[data-open="true"] { grid-template-rows: 1fr; margin-top: 6px; }
.deck-fx-inner { min-height: 0; overflow: hidden; }
.deck-fx-canvas {
  display: block; width: 100%; height: 120px; contain: strict; border-radius: 6px;
  border: 1px solid color-mix(in srgb, currentColor 45%, transparent); background: #05060f;
}
.deck-fx-presets { display: grid; grid-template-columns: repeat(5, 1fr); gap: 4px; margin-top: 5px; }
.deck-fx-project {
  display: flex; align-items: center; justify-content: center; gap: 6px; width: 100%; min-height: 28px; margin-top: 5px;
  font: 700 10px/1 "Courier New", Courier, monospace; letter-spacing: 0.06em; text-transform: uppercase; text-shadow: 0 0 4px currentColor;
}
.deck-fx-preset { min-height: 24px; font: 700 9px/1 "Courier New", Courier, monospace; letter-spacing: 0.04em; text-transform: uppercase; text-shadow: 0 0 4px currentColor; }
/* "Project to Background": the visitor's own view, added by public/js/site.js. The layer is
   a child of .profile-guard, outside #profile, so member CSS can't reach it. At z-index -1
   and first in the guard, it paints over a theme's backdrop (-3), its particles (-2) are
   hidden (below), and it sits under the readability overlay, #profile::after, which comes later at the same -1. The
   layer spans the profile, but its canvas is one window tall and sticks to the top, so the
   bitmap never grows with the page, and scrolling moves a composited layer and repaints
   nothing. #profile's own fill would cover it, so it goes clear while projecting. */
.profile-projection { position: absolute; inset: 0; z-index: -1; pointer-events: none; display: none; }
.profile-guard.is-projecting > .profile-projection { display: block; }
.profile-projection canvas { position: sticky; top: 0; display: block; width: 100%; height: 100vh; contain: strict; will-change: transform; background: #05060f; }
.profile-guard.is-projecting #profile { background: transparent !important; }
/* A stock theme's particles go while projecting. The canvas is opaque, so they would only
   cost paint, and any host with a stacking context of its own (an opacity, transform or
   filter on it, from a theme copy saved before a fix or from member CSS) paints its layers
   above the canvas, which is how Cybernetic Digital Rain's columns once streamed over it.
   Saved copies are text that src/themes.js never rewrites, so this rule is what reaches
   them; !important is what beats #profile-scoped theme rules, and member CSS can't use it. */
.profile-guard.profile-themed.is-projecting :is(.profile-inner, .profile-left, .profile-right, .profile-name, .profile-card, .view-my, .profile-facts, .last-login)::before,
.profile-guard.profile-themed.is-projecting :is(.profile-inner, .profile-left, .profile-right, .profile-name, .profile-card, .view-my, .profile-facts, .last-login)::after { display: none !important; }
/* An unthemed profile has dark text written for a white page. */
.profile-guard.is-projecting:not(.profile-themed) :is(.profile-name, .profile-facts, .headline, .last-login, .mood, .view-my) {
  color: #f2f2f7 !important; text-shadow: 0 1px 4px #000000;
}
/* ---------- the media dock: the one player a tab has ----------
   public/js/media-core.js builds it as the last child of <body> and navigation.js swaps
   pages around it, so the player frame inside is never removed or moved, and plays on
   through every page change. Only the dock's own position changes:
   - mini: on any page but the one the music came from, a small player in the corner.
   - bound: on that page, where the deck is the controls. A video is laid exactly over
     the deck's slot (the core sets left, top and width), and the bar stays hidden.
   Spotify, and a bound video while the deck's visualizer is open, keep playing in a frame
   held at a real size but clipped to nothing, transparent and out of the pointer's reach. */
.media-dock { display: none; }
.media-dock[data-mode="mini"] {
  display: block; position: fixed; z-index: 50;
  right: max(16px, env(safe-area-inset-right)); bottom: max(16px, env(safe-area-inset-bottom));
  width: min(320px, calc(100vw - 32px));
}
.media-dock[data-mode="bound"] { display: block; position: absolute; z-index: 1; }
.media-dock[data-mode="bound"] .media-dock-bar { display: none; }
.media-dock-stage iframe { display: block; width: 100%; border: 0; border-radius: 6px; }
.media-dock-stage[data-kind="video"] iframe { aspect-ratio: 16 / 9; height: auto; }
.media-dock[data-mode="mini"] .media-dock-stage[data-kind="video"] {
  margin-bottom: 6px; padding: 3px; border: 1px solid color-mix(in srgb, currentColor 45%, transparent); border-radius: 8px;
  background: rgb(0 0 0 / 55%); box-shadow: 0 6px 20px rgb(0 0 0 / 45%);
}
.media-dock-stage[data-kind="audio"], .media-dock[data-mode="bound"][data-overlay="false"] .media-dock-stage {
  position: fixed; left: 0; top: 0; width: 300px; opacity: 0; pointer-events: none; clip-path: inset(50%); overflow: hidden;
}
.media-dock[data-mode="mini"] .media-dock-bar { box-shadow: 0 6px 20px rgb(0 0 0 / 45%); }
.media-dock :is(.deck-screen, .deck-button, .media-dock-stage) { color: #29f3ff; }
.media-dock-controls { display: grid; grid-template-columns: repeat(5, 1fr); gap: 6px; margin-top: 6px; }
.media-dock .deck-button { min-height: 30px; }
.media-dock-home {
  margin-left: auto; max-width: 60%; overflow: hidden; color: inherit; text-overflow: ellipsis; white-space: nowrap;
}
.media-dock-home:hover { color: #ffffff; }
html.is-navigating { cursor: progress; }

/* ---------- the Graffiti Wall, see src/graffiti.js ----------
   Not in sanitize.js's LAYOUT_CLASSES, so no profile CSS can select any of this: the
   wall and its tray look the same on every profile. The stickers are SVG positioned by
   their own x and y attributes. The board and the canvas are each their own composited
   layer (will-change: transform) with paint containment, so the glass panels scrolling
   over the profile backdrop never repaint the stickers, and a new sticker repaints only
   the board. */
.graffiti {
  width: 100%; max-width: 100%; min-width: 0; box-sizing: border-box; overflow-wrap: anywhere;
  margin-bottom: 14px; padding: 8px; border: 1px solid rgb(255 255 255 / 22%); border-radius: 8px; color: var(--ink);
  background: linear-gradient(135deg, rgb(0 255 204 / 10%), rgb(255 0 85 / 10%), rgb(155 81 224 / 10%)), rgb(14 14 34 / 62%);
  -webkit-backdrop-filter: blur(16px) saturate(180%); backdrop-filter: blur(16px) saturate(180%);
}
.graffiti-defs { position: absolute; width: 0; height: 0; overflow: hidden; }
.graffiti-board {
  position: relative; width: 100%; max-width: 100%; box-sizing: border-box;
  aspect-ratio: 16 / 7; min-height: clamp(120px, 40vw, 160px); overflow: hidden; border-radius: 6px;
  border: 1px solid rgb(255 255 255 / 18%); contain: layout paint; will-change: transform;
  background:
    linear-gradient(rgb(255 255 255 / 4%) 1px, transparent 1px) 0 0 / 24px 24px,
    linear-gradient(90deg, rgb(255 255 255 / 4%) 1px, transparent 1px) 0 0 / 24px 24px,
    radial-gradient(ellipse at 30% 20%, rgb(177 77 255 / 28%), transparent 60%),
    radial-gradient(ellipse at 80% 90%, rgb(0 255 204 / 18%), transparent 55%),
    #0b0d22;
}
.graffiti-canvas { position: absolute; inset: 0; display: block; width: 100%; max-width: 100%; height: 100%; box-sizing: border-box; will-change: transform; touch-action: manipulation; }
.graffiti-canvas:focus-visible { outline: 2px solid #5ff3ff; outline-offset: -2px; }
.graffiti.is-armed .graffiti-canvas { cursor: crosshair; }
.graffiti-sticker { filter: drop-shadow(0 2px 0 rgb(0 0 0 / 45%)); }
.graffiti-aim {
  position: absolute; width: 22px; height: 22px; margin: -11px 0 0 -11px; pointer-events: none; border-radius: 50%;
  border: 2px dashed #5ff3ff; box-shadow: 0 0 8px #5ff3ff; will-change: transform;
}
.graffiti-empty {
  position: absolute; inset: 0; display: grid; place-items: center; margin: 0; pointer-events: none;
  color: #a6aec4; font-size: 12px; text-align: center;
}
.graffiti-empty[hidden], .graffiti-aim[hidden] { display: none; }
.graffiti-tray { display: flex; flex-wrap: wrap; gap: 4px; margin-top: 8px; will-change: transform; }
.graffiti-pick {
  display: grid; place-items: center; width: 50px; height: 50px; padding: 0; cursor: pointer; border-radius: 6px;
  border: 1px solid rgb(255 255 255 / 18%); background: rgb(255 255 255 / 6%);
  transition: background-color var(--ease), box-shadow var(--ease), transform var(--ease);
}
.graffiti-pick:hover { background: rgb(255 255 255 / 14%); transform: translateY(-1px); }
.graffiti-pick[aria-pressed="true"] { border-color: #5ff3ff; background: rgb(95 243 255 / 16%); box-shadow: 0 0 10px rgb(95 243 255 / 55%); }
.graffiti-icon { display: block; max-width: 42px; max-height: 42px; }
.graffiti-hint { margin: 6px 0 0; font-size: 11px; color: var(--muted); }
.graffiti-actions { display: flex; flex-wrap: wrap; gap: 4px 12px; margin-top: 4px; font-size: 12px; }
.graffiti-tray, .graffiti-hint, .graffiti-actions { max-width: 100%; min-width: 0; }
@media (max-width: 380px) {
  .graffiti { padding: 6px; }
  .graffiti-tray { gap: 6px; }
}
.graffiti-actions [hidden] { display: none; }
.graffiti[aria-busy="true"] .graffiti-canvas { cursor: progress; }
@media (pointer: coarse) { .graffiti-pick { width: 52px; height: 52px; } }

/* ---------- Audio Greeting, see src/greeting.js ---------- */
.profile-greeting { margin: 0 0 8px; }
.greeting-play {
  display: inline-flex; align-items: center; gap: 6px; min-height: 30px; padding: 4px 10px; cursor: pointer; border-radius: 999px;
  font: 600 12px/1 inherit; color: #29f3ff; border: 1px solid color-mix(in srgb, #29f3ff 45%, transparent); background: rgb(14 14 34 / 70%);
  box-shadow: 0 0 8px rgb(41 243 255 / 25%);
}
.greeting-play:hover { background: rgb(14 14 34 / 90%); color: #ffffff; }
@media (pointer: coarse) { .greeting-play { min-height: 44px; } }

/* ---------- CosmaIM, the floating messenger, see public/js/dreamim.js ----------
   A child of <body> like the media dock, so it's outside .profile-guard and no profile
   CSS can reach it. It moves by transform alone (set by the script), and has its own
   layer, so dragging it over the glass never relays out the page or repaints what's
   behind. The bubbles hold the server's emotionalText markup, so every .emotion-* color
   and .tfx-* effect works in them as anywhere else. */
.dreamim {
  position: fixed; left: 0; top: 0; z-index: 60; display: flex; flex-direction: column;
  width: min(300px, calc(100vw - 24px)); height: min(440px, calc(100vh - 24px)); overflow: hidden;
  color: var(--ink); border: 1px solid rgb(255 255 255 / 24%); border-radius: 12px;
  background: linear-gradient(135deg, rgb(0 255 204 / 14%), rgb(255 0 85 / 10%), rgb(155 81 224 / 16%)), rgb(12 12 32 / 58%);
  -webkit-backdrop-filter: blur(16px) saturate(180%); backdrop-filter: blur(16px) saturate(180%);
  box-shadow: 0 12px 36px rgb(0 0 0 / 50%), inset 0 1px 0 rgb(255 255 255 / 25%);
  will-change: transform; contain: layout paint;
}
.dreamim[hidden] { display: none; }
.dreamim.is-dragging { cursor: grabbing; user-select: none; }
.dreamim-bar {
  display: flex; align-items: center; gap: 6px; padding: 6px 8px; cursor: grab; touch-action: none; user-select: none;
  background: linear-gradient(180deg, rgb(255 255 255 / 16%), rgb(255 255 255 / 4%)); border-bottom: 1px solid rgb(255 255 255 / 16%);
}
.dreamim-logo { font: 700 11px/1 "Courier New", monospace; letter-spacing: .08em; color: #29f3ff; text-shadow: 0 0 6px #29f3ff; }
.dreamim-title { flex: 1; min-width: 0; overflow: hidden; font-size: 12px; font-weight: 600; text-overflow: ellipsis; white-space: nowrap; }
.dreamim-button {
  display: grid; place-items: center; width: 26px; height: 26px; padding: 0; cursor: pointer; border-radius: 6px;
  font-size: 16px; line-height: 1; color: inherit; border: 1px solid rgb(255 255 255 / 20%); background: rgb(255 255 255 / 8%);
}
.dreamim-button:hover { background: rgb(255 255 255 / 18%); }
.dreamim:not([data-view="chat"], [data-view="group"]) .dreamim-back { display: none; }
/* Create Group Chat: a glowing + in the header, wherever there's no conversation open. */
.dreamim-group {
  color: #0b0d22; font-weight: 700; border-color: rgb(95 243 255 / 70%);
  background: linear-gradient(135deg, #5ff3ff, #ff71ce); box-shadow: 0 0 8px rgb(95 243 255 / 55%);
}
.dreamim-group:hover { background: linear-gradient(135deg, #8ff7ff, #ff9bdc); }
.dreamim:is([data-view="chat"], [data-view="group"]) .dreamim-group { display: none; }
.dreamim-tabs { display: flex; gap: 4px; padding: 6px 8px 0; }
.dreamim:is([data-view="chat"], [data-view="group"]) .dreamim-tabs { display: none; }
.dreamim-tabs button {
  flex: 1; padding: 5px; cursor: pointer; font: inherit; font-size: 12px; color: inherit; border-radius: 6px 6px 0 0;
  border: 1px solid rgb(255 255 255 / 16%); border-bottom: 0; background: rgb(255 255 255 / 5%);
}
.dreamim-tabs button[aria-selected="true"] { background: rgb(255 255 255 / 16%); }
.dreamim-pane { display: none; flex: 1; min-height: 0; flex-direction: column; }
.dreamim[data-view="buddies"] [data-pane="buddies"], .dreamim[data-view="mail"] [data-pane="mail"], .dreamim[data-view="chat"] [data-pane="chat"],
.dreamim[data-view="group"] [data-pane="group"] { display: flex; }
.dreamim [data-pane="buddies"] { overflow-y: auto; overscroll-behavior: contain; }
.dreamim-buddies, .dreamim-mail, .dreamim-log { flex: 1; min-height: 0; margin: 0; padding: 6px 8px; overflow-y: auto; list-style: none; overscroll-behavior: contain; }
.dreamim [data-pane="buddies"] .dreamim-buddies { flex: none; overflow: visible; }
.dreamim-heading { margin: 0; padding: 8px 12px 0; font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.dreamim-heading[hidden], .dreamim-rooms[hidden] { display: none; }
.dreamim-rooms { margin: 0; padding: 4px 8px 0; list-style: none; }
.dreamim-room-icon {
  display: grid; place-items: center; flex: none; width: 28px; height: 28px; border-radius: 50%;
  font-size: 11px; font-weight: 700; color: #0b0d22; background: conic-gradient(#5ff3ff, #ff71ce, #b967ff, #5ff3ff);
}
/* The Create Group Chat pane: name, search, then the friend checklist. */
.dreamim-group-form { display: flex; flex: 1; min-height: 0; flex-direction: column; gap: 6px; padding: 8px; }
.dreamim-field {
  width: 100%; padding: 6px 8px; font: inherit; font-size: 13px; color: var(--ink);
  border: 1px solid rgb(255 255 255 / 22%); border-radius: 8px; background: rgb(255 255 255 / 8%);
}
.dreamim-field:focus { outline: 0; border-color: #5ff3ff; box-shadow: 0 0 0 2px rgb(95 243 255 / 30%); }
.dreamim-picked { margin: 0; font-size: 11px; color: var(--muted); }
.dreamim-picks { flex: 1; min-height: 0; margin: 0; padding: 0; overflow-y: auto; list-style: none; overscroll-behavior: contain; }
.dreamim-picks li[hidden] { display: none; }
.dreamim-pick { display: flex; align-items: center; gap: 8px; padding: 5px 6px; cursor: pointer; border-radius: 6px; font-size: 13px; }
.dreamim-pick:hover { background: rgb(255 255 255 / 10%); }
.dreamim-pick:has(input:checked) { background: rgb(95 243 255 / 16%); box-shadow: inset 0 0 0 1px rgb(95 243 255 / 45%); }
.dreamim-pick input { flex: none; accent-color: #5ff3ff; }
.dreamim-pick img { flex: none; border-radius: 4px; object-fit: cover; }
.dreamim-handle { flex: none; font-size: 11px; color: var(--muted); }
.dreamim-create { padding: 8px 12px; }
.dreamim-create[disabled] { opacity: .5; cursor: not-allowed; }
.dreamim-group-form[aria-busy="true"] .dreamim-create { opacity: .6; cursor: progress; }
/* A group chat's members, and the way out. */
.dreamim-roominfo { display: flex; align-items: center; gap: 6px; margin: 0; padding: 4px 8px; font-size: 11px; color: var(--muted); border-bottom: 1px solid rgb(255 255 255 / 10%); }
.dreamim-roominfo[hidden] { display: none; }
.dreamim-members { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dreamim-leave { width: auto; height: 22px; padding: 0 8px; font-size: 11px; }
.dreamim-buddy {
  display: flex; align-items: center; gap: 8px; width: 100%; padding: 5px 6px; cursor: pointer; text-align: left;
  font: inherit; font-size: 13px; color: inherit; border: 0; border-radius: 6px; background: transparent;
}
.dreamim-buddy:hover, .dreamim-buddy:focus-visible { background: rgb(255 255 255 / 12%); }
.dreamim-buddy img { flex: none; border-radius: 4px; object-fit: cover; }
.dreamim-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.dreamim-dot { flex: none; width: 8px; height: 8px; border-radius: 50%; background: #708090; }
.dreamim-dot.is-online { background: #7dff5a; box-shadow: 0 0 6px #7dff5a; }
.dreamim-count { flex: none; min-width: 18px; padding: 1px 5px; border-radius: 999px; font-size: 11px; text-align: center; color: #0b0d22; background: #ff2bd6; }
.dreamim-empty, .im-empty { padding: 10px 4px; font-size: 12px; color: var(--muted); text-align: center; }
.dreamim-mail li { padding-block: 4px; border-bottom: 1px solid rgb(255 255 255 / 12%); font-size: 12px; overflow-wrap: anywhere; }
.dreamim-mail a { display: block; }
.dreamim-links { margin: 0; padding: 6px 8px; font-size: 12px; }
.dreamim-status { margin: 0; padding: 0 8px; font-size: 11px; color: #ffb4b4; }
.dreamim-status:empty { display: none; }
.dreamim-form { display: flex; gap: 6px; padding: 6px 8px 8px; border-top: 1px solid rgb(255 255 255 / 14%); }
.dreamim-form textarea {
  flex: 1; min-width: 0; resize: none; padding: 6px 8px; font: inherit; font-size: 13px; color: var(--ink);
  border: 1px solid rgb(255 255 255 / 22%); border-radius: 8px; background: rgb(255 255 255 / 8%);
}
.dreamim-form textarea:focus { outline: 0; border-color: #5ff3ff; box-shadow: 0 0 0 2px rgb(95 243 255 / 30%); }
.dreamim-send { padding: 0 12px; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; color: #0b0d22; border: 0; border-radius: 8px; background: #5ff3ff; }
.dreamim-form[aria-busy="true"] .dreamim-send { opacity: .6; cursor: progress; }
/* The bubbles, here and on the plain /im/:username page. */
.im-log { margin: 0; padding: 0; list-style: none; }
.im-msg { display: flex; flex-direction: column; max-width: 85%; margin: 0 0 6px; will-change: transform; contain: layout paint; }
/* In a group chat, who said it. Each bubble is its own layer, so $wave and $glitch animate without repainting the log. */
.im-from { display: flex; align-items: center; gap: 4px; margin-bottom: 2px; font-size: 11px; }
.im-handle { font-weight: 600; }
.im-mine { margin-left: auto; align-items: flex-end; }
.im-theirs { margin-right: auto; align-items: flex-start; }
.im-text {
  margin: 0; padding: 6px 9px; font-size: 13px; line-height: 1.4; white-space: pre-wrap; overflow-wrap: anywhere;
  border-radius: 12px; border: 1px solid rgb(255 255 255 / 16%);
}
.im-mine .im-text { border-bottom-right-radius: 3px; background: rgb(63 109 240 / 45%); }
.im-theirs .im-text { border-bottom-left-radius: 3px; background: rgb(255 255 255 / 10%); }
.im-text .tfx-marquee { width: 10em; }
.im-time { margin-top: 2px; font-size: 10px; color: var(--muted); }
.im-log-page { max-height: 60vh; overflow-y: auto; margin-bottom: var(--space-3); }
.im-buddies { margin: 0; padding: 0; list-style: none; }
.im-buddy { display: flex; align-items: center; gap: 8px; padding: 6px 0; }
.im-buddy img { border-radius: 4px; }
.im-unread { color: #ff2bd6; }
/* The header link and its unread badge. */
.dreamim-badge { display: inline-block; min-width: 16px; margin-left: 4px; padding: 0 4px; border-radius: 999px; font-size: 10px; line-height: 16px; text-align: center; color: #0b0d22; background: #ff2bd6; }
.dreamim-badge[hidden] { display: none; }
.dreamim-launcher .mail-summary { margin: 0 0 8px; font-size: 12px; }
/* The Turn-Based Tabletop Hub inside CosmaIM: the controller button, the game picker
   accordion, invite cards in the log, and the board drawer that splits the chat pane. */
.dreamim-games { font-size: 14px; border-color: rgb(255 113 206 / 55%); background: rgb(255 113 206 / 14%); box-shadow: 0 0 8px rgb(255 113 206 / 30%); }
.dreamim-games[aria-expanded="true"] { background: rgb(255 113 206 / 32%); }
.dreamim:not([data-view="chat"]) .dreamim-games, .dreamim[data-chat="room"] .dreamim-games { display: none; }
/* The picker slides open by animating a grid row from 0fr to 1fr, so no height is ever guessed. */
.dreamim-picker { display: grid; grid-template-rows: 0fr; flex: none; transition: grid-template-rows .25s ease; border-bottom: 1px solid transparent; }
.dreamim-picker[data-open="true"] { grid-template-rows: 1fr; border-bottom-color: rgb(255 255 255 / 14%); }
.dreamim-picker-inner { display: flex; min-height: 0; flex-direction: column; gap: 6px; overflow: hidden; padding: 0 8px; }
.dreamim-picker[data-open="true"] .dreamim-picker-inner { padding-block: 8px; }
.dreamim-picker-head { margin: 0; font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--muted); }
.dreamim-pickgame {
  display: flex; align-items: center; gap: 10px; width: 100%; padding: 8px; cursor: pointer; text-align: left; font: inherit; color: inherit;
  border: 1px solid rgb(255 255 255 / 18%); border-radius: 10px; background: linear-gradient(135deg, rgb(95 243 255 / 10%), rgb(255 113 206 / 10%));
  transition: background .15s ease, box-shadow .15s ease;
}
.dreamim-pickgame:hover, .dreamim-pickgame:focus-visible { background: linear-gradient(135deg, rgb(95 243 255 / 22%), rgb(255 113 206 / 22%)); box-shadow: 0 0 10px rgb(95 243 255 / 30%); }
.dreamim-pickgame-icon { flex: none; font-size: 22px; }
.dreamim-pickgame-copy { display: flex; min-width: 0; flex-direction: column; gap: 2px; }
.dreamim-pickgame-copy strong { font-size: 13px; }
.dreamim-pickgame-copy small { font-size: 11px; color: var(--muted); }
.dreamim-status[data-tone="info"] { color: #9ff7ff; }

/* Invite cards: a glass ticket in the message log. */
.im-game-card { max-width: 92%; }
.im-game-invite {
  display: grid; grid-template-columns: auto 1fr; gap: 4px 8px; align-items: center;
  background: linear-gradient(135deg, rgb(95 243 255 / 16%), rgb(255 43 214 / 16%)) !important; border-color: rgb(95 243 255 / 40%) !important;
  box-shadow: 0 0 12px rgb(95 243 255 / 18%);
}
.im-game-icon { font-size: 20px; }
.im-game-line { margin: 0; font-weight: 600; white-space: normal; }
.im-game-actions { display: flex; flex-wrap: wrap; grid-column: 1 / -1; gap: 6px; align-items: center; }
.im-game-actions .inline-form { display: inline; margin: 0; }
.im-game-note { flex: 1 1 auto; font-size: 11px; color: var(--muted); }
.im-game-btn {
  padding: 4px 10px; cursor: pointer; font: inherit; font-size: 12px; font-weight: 700; color: inherit;
  border: 1px solid rgb(255 255 255 / 26%); border-radius: 999px; background: rgb(255 255 255 / 10%);
}
.im-game-btn:hover { background: rgb(255 255 255 / 20%); }
.im-game-btn.is-primary { color: #0b0d22; border-color: transparent; background: linear-gradient(135deg, #5ff3ff, #ff71ce); }

/* The board drawer splits the chat pane: board on top, the log keeps the rest. */
.dreamim.has-board { width: min(340px, calc(100vw - 24px)); height: min(720px, calc(100vh - 24px)); }
.dreamim-board {
  display: flex; flex: none; flex-direction: column; max-height: 72%; overflow-y: auto; overscroll-behavior: contain;
  border-bottom: 1px solid rgb(255 255 255 / 16%);
  background: radial-gradient(120% 80% at 0% 0%, rgb(95 243 255 / 12%), transparent 60%), radial-gradient(100% 80% at 100% 100%, rgb(255 43 214 / 12%), transparent 60%), rgb(8 8 26 / 35%);
}
.dreamim-board[hidden] { display: none; }
.dreamim-board-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; }
.dreamim-board-heading { display: flex; flex: 1; min-width: 0; flex-direction: column; }
.dreamim-board-title { font-size: 12px; letter-spacing: .04em; color: #9ff7ff; text-shadow: 0 0 6px rgb(95 243 255 / 60%); }
.dreamim-board-status { margin: 0; font-size: 11px; color: var(--muted); }
.dreamim-board[data-status="active"][data-turn="me"] .dreamim-board-status { color: #7dff5a; }
.dreamim-board-body { display: flex; flex-direction: column; gap: 6px; padding: 0 8px 8px; }
.dreamim-board[data-collapsed="true"] .dreamim-board-body { display: none; }
.dreamim-board-tabs { display: flex; gap: 4px; }
.dreamim-board-tabs[hidden] { display: none; }
.dreamim-board-tab {
  flex: 1; padding: 5px 4px; cursor: pointer; font: inherit; font-size: 11px; font-weight: 600; color: inherit;
  border: 1px solid rgb(255 255 255 / 16%); border-radius: 8px; background: rgb(255 255 255 / 5%);
}
.dreamim-board-tab[aria-selected="true"] { color: #0b0d22; background: linear-gradient(135deg, #5ff3ff, #b967ff); border-color: transparent; }
.dreamim-canvas { display: block; width: 100%; max-width: 300px; height: auto; margin: 0 auto; cursor: pointer; touch-action: manipulation; border-radius: 12px; }
.dreamim-canvas[hidden] { display: none; }
.dreamim-canvas:focus-visible { outline: 2px solid #5ff3ff; outline-offset: 2px; }
.dreamim-board[data-turn="them"] .dreamim-canvas, .dreamim-board:not([data-status="active"]) .dreamim-canvas { cursor: default; }
.dreamim-board-tools { display: flex; flex-direction: column; gap: 6px; }
.dreamim-board-tools[hidden] { display: none; }
.dreamim-ships, .dreamim-board-row { display: flex; flex-wrap: wrap; gap: 4px; }
.dreamim-ship {
  padding: 3px 8px; cursor: pointer; font: inherit; font-size: 11px; color: inherit;
  border: 1px solid rgb(255 255 255 / 20%); border-radius: 999px; background: rgb(255 255 255 / 6%);
}
.dreamim-ship.is-placed { color: #9ff7ff; border-color: rgb(95 243 255 / 45%); background: rgb(95 243 255 / 12%); }
.dreamim-ship.is-selected { color: #0b0d22; background: #7dff5a; border-color: transparent; }
.dreamim-board-row .dreamim-button, .dreamim-board-foot .dreamim-button { width: auto; height: 26px; padding: 0 10px; font-size: 12px; }
.dreamim-deploy { color: #0b0d22; font-weight: 700; border-color: transparent; background: linear-gradient(135deg, #5ff3ff, #ff71ce); }
.dreamim-deploy[disabled] { opacity: .45; cursor: not-allowed; }
.dreamim-board-foot { display: flex; justify-content: flex-end; }
.dreamim-forfeit[hidden] { display: none; }
.dreamim.has-board .dreamim-log { min-height: 80px; }
@media (prefers-reduced-motion: reduce) { .dreamim-picker { transition: none; } }
@media (max-width: 600px) {
  /* A bottom sheet on a phone: there's no room to drag a window around. */
  .dreamim { left: 8px; right: 8px; top: auto; bottom: max(8px, env(safe-area-inset-bottom)); width: auto; height: min(70vh, 480px); transform: none !important; }
  .dreamim-bar { cursor: default; }
  .dreamim-field, .dreamim-form textarea { font-size: 16px; } /* under 16px, iOS zooms the page on focus */
  .dreamim-button { width: 32px; height: 32px; } /* a fingertip-sized target */
  /* With a board open the sheet grows tall; the board keeps most of it and the chat scrolls under it. */
  .dreamim.has-board { width: auto; height: min(92vh, 760px); }
  .dreamim-board { max-height: 66%; }
  .dreamim-board-row .dreamim-button, .dreamim-board-foot .dreamim-button { height: 32px; }
  .im-game-btn, .dreamim-ship { min-height: 32px; }
}

/* ---------- ambient: the member's own look behind the site's pages ----------
   src/ambient.js moves a theme's layers off the profile onto this layer, which layout()
   draws first in <body> on every page that isn't a profile. It's fixed to the window and
   inert, and at z-index -1 it sits under all of the page, so it can only ever be scenery.
   The hosts are static, so each layer's absolute position resolves against the window. */
body.site-ambient { background: transparent; }
.ambient { position: fixed; inset: 0; z-index: -1; overflow: hidden; pointer-events: none; contain: strict; }
.ambient > i { display: block; position: static; }
/* Last / Next step through these. They hold no text and never show. */
.deck-queue { display: none; }
.deck-num { font: 700 11px "Courier New", Courier, monospace; text-shadow: 0 0 6px currentColor; }
@media (pointer: coarse) { .deck-button { min-height: 44px; } .deck-fx-preset { min-height: 36px; } }
.track-form { display: flex; gap: var(--space-2); }
.track-form input {
  flex: 1; min-width: 0; padding: 6px var(--space-3); font: inherit; color: var(--ink);
  background: var(--surface); border: 1px solid var(--hairline-strong); border-radius: var(--radius-sm);
}
.track-form input:focus { outline: 0; border-color: var(--accent); box-shadow: var(--ring); }
.track-form + .hint { margin-top: var(--space-2); }
.track-list { margin: var(--space-3) 0 0; padding-left: var(--space-5); }
.track-list li { padding: var(--space-1) 0; }
.track-name { display: inline-block; min-width: 130px; font-weight: 600; }

.interests, .details { width: 100%; border: 1px solid var(--blue); border-collapse: collapse; margin-bottom: 10px; font-size: 12px; background: #ffffff; }
.interests th, .details th { background: var(--blue); color: #ffffff; text-align: left; padding: 3px 6px; }
.interests td, .details td { padding: 4px 6px; vertical-align: top; overflow-wrap: anywhere; }
.interests .label, .details .label { background: var(--orange-pale); color: var(--blue-dark); font-weight: bold; width: 92px; }
.extended-network { border: 2px solid var(--orange); background: #ffffff; padding: 10px; text-align: center; margin-bottom: 12px; color: var(--orange); font-size: 14px; }

.section-title { background: var(--orange); color: #ffffff; font-size: 13px; padding: 4px 8px; margin: 0 0 8px; }
.friends-block, .blurbs, .profile-mail, .games, .friend-space, .comments, .profile-panel { margin-bottom: 14px; }
/* Colors stay inherited, as on .profile-tabs: a theme saved before this panel existed
   has no rule for it, and a fixed color here would be unreadable on its background. */
.profile-mail > summary { display: flex; justify-content: space-between; margin: 0; cursor: pointer; list-style: none; user-select: none; }
.profile-mail > summary::-webkit-details-marker { display: none; }
.profile-mail > summary::after { content: "\25BE"; transition: transform var(--ease); }
.profile-mail[open] > summary { margin-bottom: 8px; }
.profile-mail[open] > summary::after { transform: rotate(180deg); }
.mail-list { margin: 0 0 8px; padding: 0; list-style: none; font-size: 12px; }
.mail-list li { padding-block: 4px; border-bottom: 1px solid var(--line); overflow-wrap: anywhere; }
.mail-list a { display: block; }
.mail-unread a { font-weight: bold; }
.mail-meta { display: block; font-size: 11px; opacity: .8; }
.mail-empty, .mail-links { margin-bottom: 0; font-size: 12px; }
.profile-tabs { display: flex; gap: 4px; margin-bottom: 12px; }
/* Transparent so a theme's link color stays readable on the theme's own background. */
.profile-tabs a { padding: 4px 12px; border: 1px solid var(--line); font-size: 12px; font-weight: bold; text-decoration: none; }
.profile-tabs a.profile-tab-active { border-color: var(--orange); background: var(--orange); color: #ffffff; }
.post-public { margin-left: 4px; font-weight: normal; opacity: .75; }
.comment-form.mood-form { display: flex; gap: 4px; margin: 0 0 8px; }
.mood-form input { flex: 1; min-width: 0; font: inherit; font-size: 12px; }
.blurbs h3, .game-box h3 { font-size: 13px; color: var(--orange); margin-bottom: 2px; }
.friend-count, .comment-count { font-size: 12px; }
.view-all { text-align: right; font-size: 11px; margin-top: 6px; }

.comment { width: 100%; border-collapse: separate; border-spacing: 2px; table-layout: fixed; }
.comment td { vertical-align: top; padding: 6px; }
.comment-author { width: 112px; background: var(--orange-pale); text-align: center; font-size: 11px; font-weight: bold; }
.comment-author img { display: block; margin: 3px auto; width: 90px; height: 90px; object-fit: cover; }
.comment-body { background: var(--orange-wash); }
.comment-date { font-size: 11px; font-weight: bold; }
.comment-form { margin-top: 8px; display: grid; gap: 4px; }
.comment-form label { font-weight: bold; }
.comment-form .button { justify-self: start; }

/* ---------- small screens ---------- */
/* Too narrow for one row: the logo and account share the first line, the nav the second. */
@media (max-width: 820px) {
  .site-bar { flex-wrap: wrap; gap: var(--space-2) var(--space-4); padding-block: var(--space-3); }
  .site-brand, .site-account { flex: 0 1 auto; }
  .site-nav { order: 1; flex-basis: 100%; }
}
@media (max-width: 768px) {
  .columns, .columns.reverse, .profile-inner { grid-template-columns: minmax(0, 1fr); }
  .columns, .columns.reverse { gap: 0; }
}
@media (max-width: 460px) {
  .top-8 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .top8-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .comment-author { width: 92px; }
  .comment-author img { width: 72px; height: 72px; }
  .list-table .nowrap { white-space: normal; }
  .site-bar { padding-inline: var(--space-4); }
  .site-nav { gap: var(--space-1); }
  .site-nav a { padding-inline: var(--space-2); }
  .location-picker .form.compact { flex-wrap: wrap; }
}
@media (prefers-reduced-motion: reduce) {
  blink { animation: none; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
  .button:hover, .friend a:hover img { transform: none; }
  /* The title stops scrolling, so it sits in view and trails off instead. */
  .deck-title { display: block; padding-left: 0; overflow: hidden; text-overflow: ellipsis; }
}

/* ---------- emotion tags, emoji and attachments ----------
   These sit after the form and avatar rules so they win without raising specificity.
   The dark chip keeps neon readable on the white cards as well as the dark ones. */
.emotion {
  padding: .05em .35em; border-radius: .35em; background: #0b0f1a; font-weight: 600;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
}
.emotion-happy { color: var(--emotion-happy); }
.emotion-excited { color: var(--emotion-excited); }
.emotion-peaceful { color: var(--emotion-peaceful); }
.emotion-calm { color: var(--emotion-calm); }
.emotion-neutral { color: var(--emotion-neutral); }
.emotion-anxious { color: var(--emotion-anxious); }
.emotion-stressed { color: var(--emotion-stressed); }
.emotion-confused { color: var(--emotion-confused); }
.emotion-focused { color: var(--emotion-focused); }
.emotion-tired { color: var(--emotion-tired); }
.emotion-sad { color: var(--emotion-sad); }
.emotion-lonely { color: var(--emotion-lonely); }
.emotion-angry { color: var(--emotion-angry); }
.emotion-annoyed { color: var(--emotion-annoyed); }
.emotion-bored { color: var(--emotion-bored); }
.emotion-sarcastic { color: var(--emotion-sarcastic); }
.emotion-hype { color: var(--emotion-hype); }
.emotion-mysterious { color: var(--emotion-mysterious); }
.emotion-proud { color: var(--emotion-proud); }
.emotion-grateful { color: var(--emotion-grateful); }
.emotion-embarrassed { color: var(--emotion-embarrassed); }
.emotion-shy { color: var(--emotion-shy); }
.emotion-guilty { color: var(--emotion-guilty); }
.emotion-vulnerable { color: var(--emotion-vulnerable); }
.emotion-inspired { color: var(--emotion-inspired); }
.emotion-curious { color: var(--emotion-curious); }
.emotion-mindblown { color: var(--emotion-mindblown); }
.emotion-nostalgic { color: var(--emotion-nostalgic); }
.emotion-defensive { color: var(--emotion-defensive); }
.emotion-skeptical { color: var(--emotion-skeptical); }
.emotion-jealous { color: var(--emotion-jealous); }
.emotion-overwhelmed { color: var(--emotion-overwhelmed); }
.emotion-love { color: var(--emotion-love); }
.emotion-hopeful { color: var(--emotion-hopeful); }

/* ---------- Mood Legend ----------
   One chip per emotion a card uses. The swatch carries .emotion-<name>, so currentcolor
   is the viewer's own color from the --emotion-* tokens. */
.mood-legend {
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2);
  margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px dashed var(--hairline);
  font-size: var(--text-xs); color: var(--muted);
}
.mood-legend-title { font-weight: 600; text-transform: uppercase; letter-spacing: .08em; }
.mood-chip { display: inline-flex; align-items: center; gap: 6px; padding: 1px 8px 1px 6px; border: 1px solid var(--hairline); border-radius: var(--radius-full); }
.mood-swatch { flex: none; width: 9px; height: 9px; border-radius: 2px; background: currentcolor; box-shadow: 0 0 6px currentcolor, 0 0 0 1px var(--hairline-strong); }

/* ---------- text effects ----------
   The twenty $name: effects in src/emotions.js (TEXT_EFFECTS). Each is a class on a
   span around the text; nothing typed reaches CSS. Only transform, opacity, filter,
   clip-path, color, text-shadow and background-position move, so no frame needs a
   layout pass. The prefers-reduced-motion rule above stops all of them. */
.tfx { will-change: transform, opacity; }
.tfx-pulse, .tfx-glitch,
.tfx-datamosh, .tfx-quake, .tfx-shake, .tfx-float, .tfx-heartbeat, .tfx-drip, .tfx-blur { display: inline-block; max-width: 100%; }
.tfx-char { display: inline-block; white-space: pre; will-change: transform; animation: tfx-wave 1.6s ease-in-out infinite; }
.tfx-wave { will-change: auto; }
.tfx-char:nth-child(8n+2) { animation-delay: -1.4s; }
.tfx-char:nth-child(8n+3) { animation-delay: -1.2s; }
.tfx-char:nth-child(8n+4) { animation-delay: -1s; }
.tfx-char:nth-child(8n+5) { animation-delay: -.8s; }
.tfx-char:nth-child(8n+6) { animation-delay: -.6s; }
.tfx-char:nth-child(8n+7) { animation-delay: -.4s; }
.tfx-char:nth-child(8n) { animation-delay: -.2s; }
@keyframes tfx-wave {
  0%, 100% { transform: translateY(0); }
  25% { transform: translateY(-.28em); }
  75% { transform: translateY(.12em); }
}

.tfx-pulse { animation: tfx-pulse 2.4s ease-in-out infinite; text-shadow: 0 0 .35em currentcolor; }
@keyframes tfx-pulse {
  0%, 100% { transform: scale(1); opacity: .82; }
  50% { transform: scale(1.05); opacity: 1; }
}

.tfx-marquee { display: inline-block; width: 14em; max-width: 100%; overflow: hidden; vertical-align: bottom; white-space: nowrap; will-change: auto; }
.tfx-track { display: inline-block; padding-left: 100%; will-change: transform; animation: tfx-marquee 9s linear infinite; }
@keyframes tfx-marquee { from { transform: translateX(0); } to { transform: translateX(-100%); } }

/* Long idle stretches between bursts, so it reads as sporadic, not as a loop. */
.tfx-glitch { animation: tfx-glitch 3.2s steps(1, end) infinite; text-shadow: -1px 0 #ff2bd6, 1px 0 #00ffcc; }
@keyframes tfx-glitch {
  0%, 12%, 40%, 64%, 100% { transform: translateX(0); clip-path: inset(0 0 0 0); }
  8% { transform: translateX(-3px); clip-path: inset(18% 0 52% 0); }
  10% { transform: translateX(3px); clip-path: inset(62% 0 8% 0); }
  36% { transform: translateX(2px); clip-path: inset(4% 0 78% 0); }
  38% { transform: translateX(-2px); clip-path: inset(44% 0 30% 0); }
  60% { transform: translateX(-4px); clip-path: inset(70% 0 2% 0); }
  62% { transform: translateX(1px); clip-path: inset(10% 0 60% 0); }
}

.tfx-shimmer {
  background: linear-gradient(105deg, currentcolor 0 38%, #ffffff 48%, #d7f9ff 52%, currentcolor 62% 100%) 100% 0 / 260% 100% no-repeat;
  -webkit-background-clip: text; background-clip: text; -webkit-text-fill-color: transparent;
  -webkit-box-decoration-break: clone; box-decoration-break: clone;
  will-change: background-position; animation: tfx-shimmer 2.8s ease-in-out infinite;
}
/* A chip or emoji inside paints its own text, or the clip would leave it blank. */
.tfx-shimmer .emotion, .tfx-shimmer .emoji { -webkit-text-fill-color: currentcolor; }
@keyframes tfx-shimmer { from { background-position: 100% 0; } to { background-position: 0 0; } }

.tfx-rainbow { will-change: auto; animation: tfx-rainbow 6s linear infinite; }
@keyframes tfx-rainbow {
  0%, 100% { color: #ff2bd6; }
  17% { color: #b14dff; }
  33% { color: #5ff3ff; }
  50% { color: #00ffcc; }
  67% { color: #7dff5a; }
  83% { color: #ff8c00; }
}

/* ---------- the fourteen newer effects ---------- */

/* Slide: the same clipped box as marquee, but the track eases back and forth. */
.tfx-slide { display: inline-block; width: 12em; max-width: 100%; overflow: hidden; vertical-align: bottom; white-space: nowrap; will-change: auto; }
.tfx-slide > .tfx-track { animation: tfx-slide 7s ease-in-out infinite alternate; }
@keyframes tfx-slide { from { transform: translateX(0); } to { transform: translateX(-100%); } }
.token-button .tfx-slide { width: 6em; }
.im-text .tfx-slide { width: 10em; }

/* Datamosh: glitch's heavier cousin, with uneven gaps so the loop doesn't read as one. */
.tfx-datamosh { animation: tfx-datamosh 4.7s steps(1, end) infinite; }
@keyframes tfx-datamosh {
  0%, 9%, 31%, 47%, 73%, 100% { transform: none; clip-path: inset(0 0 0 0); text-shadow: none; }
  5% { transform: translateX(-5px) skewX(-8deg); clip-path: inset(0 12% 46% 0); text-shadow: 3px 0 #ff2bd6, -3px 0 #00ffcc; }
  7% { transform: translateX(4px); clip-path: inset(38% 0 0 18%); text-shadow: -4px 0 #ff3333, 4px 0 #5ff3ff; }
  27% { transform: translateX(2px) skewX(6deg); clip-path: inset(0 30% 0 0); text-shadow: 2px 0 #b14dff, -2px 0 #7dff5a; }
  44% { transform: translateX(-3px); clip-path: inset(60% 0 4% 6%); text-shadow: 5px 0 #ff2bd6, -5px 0 #00ffcc; }
  69% { transform: translateX(6px) skewX(-4deg); clip-path: inset(8% 4% 70% 0); text-shadow: -3px 0 #ff8c00, 3px 0 #5ff3ff; }
  71% { transform: translateX(-6px); clip-path: inset(30% 0 30% 0); text-shadow: 4px 0 #ff2bd6, -4px 0 #00ffcc; }
}

/* Quake: still for most of the loop, then one heavy rock. */
.tfx-quake { animation: tfx-quake 3.6s ease-in-out infinite; }
@keyframes tfx-quake {
  0%, 78%, 100% { transform: none; }
  80% { transform: translateX(-6px) rotate(-2deg); }
  83% { transform: translateX(6px) rotate(2deg); }
  86% { transform: translateX(-5px) rotate(-1.5deg); }
  89% { transform: translateX(4px) rotate(1deg); }
  92% { transform: translateX(-2px); }
  95% { transform: translateX(1px); }
}

/* Shake: a fast, never-quite-repeating rumble. */
.tfx-shake { animation: tfx-shake .32s linear infinite; }
@keyframes tfx-shake {
  0%, 100% { transform: translate(0, 0); }
  12% { transform: translate(-1px, 1px) rotate(-.5deg); }
  25% { transform: translate(1px, -1px); }
  37% { transform: translate(-1.5px, 0) rotate(.5deg); }
  50% { transform: translate(1px, 1px); }
  62% { transform: translate(-1px, -1px) rotate(-.5deg); }
  75% { transform: translate(1.5px, .5px); }
  87% { transform: translate(-.5px, -1px) rotate(.5deg); }
}

.tfx-float { animation: tfx-float 3.4s ease-in-out infinite; }
@keyframes tfx-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-.3em); }
}

/* Heartbeat: lub-dub, then a rest. */
.tfx-heartbeat { animation: tfx-heartbeat 1.2s ease-in-out infinite; }
@keyframes tfx-heartbeat {
  0%, 40%, 100% { transform: scale(1); }
  12% { transform: scale(1.16); }
  24% { transform: scale(1.02); }
  32% { transform: scale(1.12); }
}

/* Drip: hangs from the top edge, so it stretches down, not both ways. */
.tfx-drip { transform-origin: 50% 0; will-change: transform, filter; animation: tfx-drip 3s ease-in infinite; }
@keyframes tfx-drip {
  0%, 30%, 100% { transform: scaleY(1) translateY(0); filter: blur(0); }
  70% { transform: scaleY(1.35) translateY(.06em); filter: blur(.6px); opacity: .9; }
  85% { transform: scaleY(1.5) translateY(.1em); filter: blur(1.2px); opacity: .7; }
}

/* Blur: a slow drift out of focus, then a snap back. */
.tfx-blur { will-change: filter, opacity; animation: tfx-blur 4s ease-in infinite; }
@keyframes tfx-blur {
  0%, 20% { filter: blur(0); opacity: 1; }
  88% { filter: blur(6px); opacity: .55; }
  89%, 100% { filter: blur(0); opacity: 1; }
}

/* Ghost: two faint copies drift away from the text and fade. */
.tfx-ghost { will-change: auto; animation: tfx-ghost 3.6s ease-out infinite; }
@keyframes tfx-ghost {
  0% { text-shadow: 0 0 0 color-mix(in srgb, currentcolor 60%, transparent), 0 0 0 color-mix(in srgb, currentcolor 60%, transparent); }
  100% { text-shadow: -.45em -.2em 4px transparent, .45em .2em 4px transparent; }
}

.tfx-fire { will-change: auto; color: #ffd27a; animation: tfx-fire 1.1s steps(1, end) infinite; }
@keyframes tfx-fire {
  0%, 100% { text-shadow: 0 0 4px #ffd700, 0 -2px 8px #ff8c00, 0 -4px 14px #ff3333; }
  25% { text-shadow: 0 0 3px #ffd700, 1px -3px 10px #ff8c00, -1px -6px 16px #dc143c; }
  50% { text-shadow: 0 0 5px #ffe27a, -1px -2px 7px #ff7a00, 1px -5px 12px #ff3333; }
  75% { text-shadow: 0 0 4px #ffd700, 0 -4px 11px #ff8c00, 0 -7px 18px #b0102c; }
}

.tfx-neon { will-change: auto; animation: tfx-neon 3s ease-in-out infinite; }
@keyframes tfx-neon {
  0%, 100% { color: #e6ffff; text-shadow: 0 0 2px #ffffff, 0 0 6px #5ff3ff, 0 0 14px #5ff3ff, 0 0 22px #00c8ff; }
  45%, 55% { color: #ffe6f8; text-shadow: 0 0 2px #ffffff, 0 0 6px #ff2bd6, 0 0 14px #ff2bd6, 0 0 22px #ff0090; }
  50% { text-shadow: 0 0 1px #ffffff, 0 0 3px #ff2bd6; }
}

.tfx-matrix { will-change: auto; font-family: var(--font-mono); animation: tfx-matrix .9s steps(1, end) infinite; }
@keyframes tfx-matrix {
  0%, 100% { color: #00ff41; text-shadow: 0 0 6px #00ff41; }
  20% { color: #ffffff; text-shadow: 0 0 8px #b6ffc8; }
  35% { color: #008f11; text-shadow: 0 0 4px #00ff41; }
  55% { color: #39ff14; text-shadow: 0 0 6px #39ff14; }
  70% { color: #e8ffe8; text-shadow: 0 0 8px #00ff41; }
  85% { color: #00c032; text-shadow: 0 0 5px #008f11; }
}

/* Spectrum: the full hue wheel, red to red, at a steady speed. */
.tfx-spectrum { will-change: auto; animation: tfx-spectrum 5s linear infinite; }
@keyframes tfx-spectrum {
  0%, 100% { color: hsl(0 100% 60%); }
  17% { color: hsl(60 100% 55%); }
  33% { color: hsl(120 100% 50%); }
  50% { color: hsl(180 100% 50%); }
  67% { color: hsl(240 100% 70%); }
  83% { color: hsl(300 100% 62%); }
}

/* Sparkle: each character is a .tfx-glint (inside .tfx-char when it also waves). Most
   of the loop is idle, and offset delays on a 7- and 5-step pattern scatter the flashes
   so they look random. */
.tfx-sparkle { will-change: auto; }
.tfx-glint { display: inline-block; white-space: pre; animation: tfx-sparkle 2.6s ease-out infinite; }
.tfx-glint:nth-child(7n+2), :nth-child(7n+2) > .tfx-glint { animation-delay: -1.9s; }
.tfx-glint:nth-child(7n+3), :nth-child(7n+3) > .tfx-glint { animation-delay: -.7s; }
.tfx-glint:nth-child(7n+4), :nth-child(7n+4) > .tfx-glint { animation-delay: -2.3s; }
.tfx-glint:nth-child(7n+5), :nth-child(7n+5) > .tfx-glint { animation-delay: -1.2s; }
.tfx-glint:nth-child(7n+6), :nth-child(7n+6) > .tfx-glint { animation-delay: -.3s; }
.tfx-glint:nth-child(7n), :nth-child(7n) > .tfx-glint { animation-delay: -1.6s; }
.tfx-glint:nth-child(5n+3), :nth-child(5n+3) > .tfx-glint { animation-duration: 3.4s; }
.tfx-glint:nth-child(5n), :nth-child(5n) > .tfx-glint { animation-duration: 1.9s; }
@keyframes tfx-sparkle {
  0%, 82%, 100% { text-shadow: none; }
  88% { color: #fff6c8; text-shadow: 0 0 2px #ffffff, 0 0 6px #ffd700, 0 0 12px #ffb300; }
  94% { text-shadow: 0 0 1px #fff6c8, 0 0 4px #ffd700; }
}

/* The Text Effects catalog on the Emotion Tones screen. */
.effects-catalog { display: grid; grid-template-columns: repeat(auto-fill, minmax(240px, 1fr)); gap: var(--space-3); margin-top: var(--space-2); }
.effect-card { display: grid; gap: var(--space-2); align-content: start; padding: var(--space-3); border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--surface-2); }
.effect-card h4 { margin: 0; font-size: var(--text-sm); }
.effect-card p { margin: 0; font-size: var(--text-xs); color: var(--muted); }
.effect-syntax { justify-self: start; font: 400 var(--text-xs) var(--font-mono); }
.effect-preview { display: flex; align-items: center; min-height: 3em; overflow: hidden; padding: var(--space-2) var(--space-3); border-radius: var(--radius-sm); background: #0b0f1a; color: #e9ecf8; font-size: var(--text-md); font-weight: 600; }

/* ---------- Emotion Tones ----------
   The wheel is pure CSS: with hue on a conic gradient, white toward the center for
   saturation and black over it for brightness, every pixel is the HSV value the
   script computes from its position. --tone-* are set through the CSSOM, because
   the CSP forbids style attributes. */
.tone-group { margin-bottom: var(--space-4); }
.tone-group h3 { margin-bottom: var(--space-1); color: var(--muted); font-size: var(--text-xs); font-weight: 600; }
.tone-row { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); padding-block: var(--space-2); border-bottom: 1px solid var(--hairline); }
.tone-label { flex: 0 0 104px; }
.tone-presets { display: flex; gap: var(--space-1); }
.tone-swatch {
  appearance: none; flex: none; width: 22px; height: 22px; margin: 0; border: 1px solid var(--hairline-strong);
  border-radius: 4px; cursor: pointer; transition: transform var(--ease);
}
.tone-swatch:hover { transform: scale(1.12); }
.tone-swatch:checked { outline: 2px solid var(--ink); outline-offset: 1px; }
.swatch-00ffcc { background: #00ffcc; }
.swatch-5ff3ff { background: #5ff3ff; }
.swatch-b14dff { background: #b14dff; }
.swatch-ff2bd6 { background: #ff2bd6; }
.swatch-ff3333 { background: #ff3333; }
.swatch-ff8c00 { background: #ff8c00; }
.swatch-b9b9c6 { background: #b9b9c6; }
.swatch-708090 { background: #708090; }
.tone-custom { display: inline-flex; align-items: center; gap: var(--space-2); margin-left: auto; padding: 2px var(--space-3); white-space: nowrap; }
.tone-dot { flex: none; width: 12px; height: 12px; border-radius: 50%; background: currentcolor; box-shadow: 0 0 0 1px var(--hairline-strong); }
.tone-picker { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-4); margin-top: var(--space-2); padding: var(--space-4); border: 1px solid var(--hairline); border-radius: var(--radius-md); background: var(--surface-2); }
.tone-picker[hidden] { display: none; }
.tone-wheel {
  position: relative; flex: none; width: 200px; height: 200px; margin-inline: auto; border-radius: 50%; cursor: crosshair; touch-action: none;
  background: radial-gradient(closest-side, #ffffff, transparent), conic-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
}
.tone-wheel::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: #000000; opacity: var(--tone-dim, 0); pointer-events: none; }
.tone-wheel:focus-visible { border-radius: 50%; }
.tone-marker {
  position: absolute; z-index: 1; left: var(--tone-x, 50%); top: var(--tone-y, 50%); width: 16px; height: 16px; margin: -8px 0 0 -8px;
  border: 2px solid #ffffff; border-radius: 50%; background: var(--tone-color, #000000); box-shadow: 0 0 0 1px #000000; pointer-events: none;
}
.tone-controls { flex: 1 1 220px; display: grid; gap: var(--space-3); min-width: 0; }
.tone-controls label { display: grid; gap: var(--space-1); font-size: var(--text-sm); font-weight: 600; }
.tone-controls .hint { margin: 0; }
.tone-slider { appearance: none; width: 100%; height: 12px; margin: 0; border-radius: var(--radius-full); cursor: pointer; }
.tone-hue { background: linear-gradient(90deg, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000); }
.tone-brightness { background: linear-gradient(90deg, #000000, var(--tone-full, #ffffff)); }
.tone-slider::-webkit-slider-thumb { appearance: none; width: 18px; height: 18px; border: 2px solid #ffffff; border-radius: 50%; background: #171b26; box-shadow: 0 0 0 1px #000000; }
.tone-slider::-moz-range-thumb { width: 14px; height: 14px; border: 2px solid #ffffff; border-radius: 50%; background: #171b26; box-shadow: 0 0 0 1px #000000; }
.tone-hex { width: 110px; padding: 6px var(--space-3); font: 400 var(--text-md) var(--font-mono); color: var(--ink); background: var(--surface); border: 1px solid var(--hairline-strong); border-radius: var(--radius-sm); }
.tone-hex[aria-invalid="true"] { border-color: var(--danger); }
.tone-foot { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2) var(--space-3); }

/* line-height: 1 stops a taller emoji font from opening up the line. */
.emoji {
  font-family: "Apple Color Emoji", "Segoe UI Emoji", "Noto Color Emoji", sans-serif;
  font-size: 1.15em; font-style: normal; font-weight: 400; line-height: 1; letter-spacing: 0; vertical-align: -.08em;
}

.media-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: var(--space-1); margin-top: var(--space-2); overflow: hidden; border-radius: var(--radius-md); }
.media-grid img { display: block; width: 100%; height: auto; aspect-ratio: 1; object-fit: cover; border-radius: 0; background: var(--surface-2); }
.media-grid.media-single { display: block; width: fit-content; max-width: 100%; }
.media-grid.media-single img { width: auto; max-width: 100%; max-height: 420px; aspect-ratio: auto; object-fit: contain; }

.composer-tools { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-1) var(--space-2); margin-top: var(--space-2); }
.composer-tools .tool-button {
  display: inline-flex; align-items: center; gap: var(--space-1); padding: 2px var(--space-2); border: 1px solid;
  border-radius: var(--radius-full); background: none; color: inherit; font-size: var(--text-xs); font-weight: 600; line-height: 20px;
  cursor: pointer; list-style: none; transition: background var(--ease);
}
.composer-tools .tool-button:hover { opacity: .75; }
.composer-tools .tool-button:focus-within { box-shadow: var(--ring); }
.composer-tools .tool-button::-webkit-details-marker { display: none; }
.composer-tools input[type=file] { position: absolute; width: 1px; height: 1px; padding: 0; border: 0; opacity: 0; }
.tool-menu[open] { flex-basis: 100%; }
.tool-panel { margin-top: var(--space-1); }
.composer-tools input[type=text] {
  width: 100%; padding: 6px var(--space-3); font: inherit; font-weight: 400; color: var(--ink);
  background: var(--surface); border: 1px solid var(--hairline-strong); border-radius: var(--radius-sm);
}
.emoji-grid { display: flex; flex-wrap: wrap; gap: 2px; }
.emoji-button { width: 34px; height: 34px; padding: 0; border: 0; border-radius: var(--radius-sm); background: none; font-size: 18px; line-height: 1; cursor: pointer; }
.emoji-button:hover { background: var(--hover); }
/* Inherited, not --muted: a profile theme can put these on a dark page while
   .profile-guard holds the tokens at their light values. */
.tool-status { min-width: 0; font-size: var(--text-xs); overflow-wrap: anywhere; }
.composer-hint { flex-basis: 100%; margin: 0; font-size: var(--text-xs); opacity: .8; }

/* ---------- Visual Customizer ---------- */
.visual-layout { display: grid; grid-template-columns: minmax(0, 1fr) 240px; gap: var(--space-5); margin-bottom: var(--space-4); }
.visual-form { max-width: none; }
.visual-form legend { padding-inline: var(--space-1); font-size: var(--text-sm); font-weight: 600; }
.visual-form fieldset { padding: var(--space-3); }
.visual-form input:disabled { opacity: .45; cursor: default; }
.visual-form [hidden] { display: none; }
.visual-scale { display: flex; justify-content: space-between; color: var(--muted); font-size: var(--text-xs); font-weight: 400; }
.visual-preview-panel { align-self: start; position: sticky; top: var(--space-4); }
.visual-preview { display: grid; place-items: center; min-height: 190px; padding: var(--space-3); border-radius: var(--radius-md); overflow: hidden; background: conic-gradient(from 45deg, #ff2bd6, #5ff3ff, #7dff5a, #ffb020, #ff2bd6); }
.visual-sample { width: 100%; padding: var(--space-3); border: 1px solid rgb(255 255 255 / 30%); border-radius: 8px; background: rgb(255 255 255 / 12%); color: #f2f2f7; text-shadow: 0 1px 2px #000000; }
.visual-sample h3 { margin-bottom: var(--space-1); font-size: var(--text-md); }
.visual-sample p { margin: 0; font-size: var(--text-sm); }
@media (max-width: 768px) {
  .visual-layout { grid-template-columns: minmax(0, 1fr); }
  .visual-preview-panel { position: static; order: -1; }
}

/* ---------- game studio ----------
   Painted from public/js/studio-editor.js by class alone, since the CSP has no inline styles. */
.studio-tools { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-2); }
.studio-tool { display: inline-flex; flex: none; align-items: center; gap: var(--space-1); white-space: nowrap; }
.form .studio-tool input { flex: none; width: 16px; height: 16px; min-height: 0; margin: 0; padding: 0; }
.studio-swatch { display: inline-block; flex: none; width: 18px; height: 18px; border: 1px solid var(--line); }
.studio-grid {
  display: grid;
  grid-template-columns: repeat(16, minmax(0, 1fr));
  width: 100%;
  max-width: 512px;
  aspect-ratio: 1;
  margin-bottom: var(--space-2);
  background: #0b0a20;
  touch-action: none;
  user-select: none;
}
.studio-grid.size-32 { grid-template-columns: repeat(32, minmax(0, 1fr)); }
.studio-grid button { min-width: 0; min-height: 0; padding: 0; border: 0; border-right: 1px solid #ffffff14; border-bottom: 1px solid #ffffff14; border-radius: 0; cursor: crosshair; }
.studio-grid button:focus-visible { outline: 2px solid #ffffff; outline-offset: -2px; }
/* The tile layers, colored as the game draws them. Monster, node and start add a mark,
   so the map reads without relying on color alone. */
.tile-floor { background: #1f3b2a; }
.tile-wall { background: #4a4f6a; }
.tile-hazard { background: #ff5a36; }
.tile-monster { background: radial-gradient(circle, #ece6d6 0 30%, #1f3b2a 32%); }
.tile-node { background: radial-gradient(circle at 50% 40%, #3fa34d 0 34%, #8a8fa6 36% 46%, #1f3b2a 48%); }
.tile-start { background: #ffe66d; box-shadow: inset 0 0 0 3px #0b0a20; }
.studio-asset { display: flex; align-items: center; gap: var(--space-2); }
.studio-asset img { max-width: 128px; max-height: 64px; image-rendering: pixelated; background: #0b0a20; }

/* ---------- phones ----------
   After the site's own rules so it wins ties with them. It stays ahead of the glass
   block, which a test holds free of !important through to the locked controls.
   The left column comes first in the HTML, so one column already puts it above the wall.
   The two !important rules hold that against a profile's own grid, which would otherwise
   out-specify this through #profile. */
.site-header { padding-inline: env(safe-area-inset-left, 0px) env(safe-area-inset-right, 0px); padding-top: env(safe-area-inset-top, 0px); }
.site-footer { padding-bottom: calc(var(--space-5) + env(safe-area-inset-bottom, 0px)); }
.site-main { min-height: calc(100dvh - 132px); }
#profile { min-height: calc(100dvh - 132px); }

@media (max-width: 768px) {
  :root { --gutter: clamp(12px, 4vw, 16px); }
  .site-inner, .profile-inner {
    padding-inline: max(var(--gutter), env(safe-area-inset-left, 0px)) max(var(--gutter), env(safe-area-inset-right, 0px));
  }

  /* Logo and account share the first row. Home, Profile, Arcade, Stories and the search icon share
     the second, and search opens on a row of its own, so it can't reach the account links. */
  .site-bar { padding-inline: var(--gutter); }
  .logo { font-size: clamp(20px, 6vw, 24px); }
  .site-nav { flex-wrap: wrap; justify-content: flex-start; gap: var(--space-1); }
  .site-nav a { display: flex; align-items: center; min-height: 44px; padding-inline: var(--space-3); }
  .search-toggle { display: block; flex: none; margin-left: auto; }
  .search-toggle > summary {
    display: grid; place-items: center; width: 44px; height: 44px; border-radius: 50%;
    color: #dbe3f5; cursor: pointer; list-style: none; transition: background var(--ease);
  }
  .search-toggle > summary::-webkit-details-marker { display: none; }
  .search-toggle[open] > summary { background: rgb(255 255 255 / 16%); color: #ffffff; }
  .search-toggle:not([open]) + .site-search { display: none; }
  .site-search { flex: 1 0 100%; max-width: none; }
  .site-search button { width: 44px; }

  /* Under 16px, iOS zooms the whole page whenever one of these takes focus. */
  .site-search input, .composer textarea, .comment-form textarea, .mood-form input, .track-form input, .tone-hex,
  .composer-tools input[type=text], .form input:not([type=checkbox]), .form textarea, .form select { font-size: 16px; }

  .box-body { padding: clamp(12px, 3.5vw, 16px); overflow-x: auto; }
  .composer, .post-card, .story-lounge .story-composer { padding: var(--space-3); }
  .button { min-height: 36px; }

  .profile-guard .profile-inner { grid-template-columns: minmax(0, 1fr) !important; }
  .profile-guard :is(.profile-left, .profile-right) { grid-column: 1 !important; }
  .profile-guard .profile-left { order: 0 !important; }
  .profile-guard .profile-right { order: 1 !important; }
  .profile-name { font-size: clamp(20px, 6vw, 22px); overflow-wrap: anywhere; }
  .profile-pic { width: clamp(110px, 38vw, 170px); height: auto; aspect-ratio: 1; }
  .profile-tabs { flex-wrap: wrap; }
  .profile-tabs a { padding-block: var(--space-2); }
  .profile-mail > summary { align-items: center; min-height: 44px; }
  .mail-list a { padding-block: var(--space-1); }
}

/* ---------- touch performance ----------
   For small screens and for any touch device, tablets in landscape included. */
@media (max-width: 768px), (pointer: coarse) {
  /* A fixed layer is moved by the compositor, where a fixed body background repaints on
     every scroll, and iOS ignores that one anyway. Everything glass blurs this instead. */
  html::before {
    content: ""; position: fixed; inset: 0 0 auto; z-index: -1; height: 100vh; height: 100lvh; pointer-events: none;
    background:
      radial-gradient(ellipse 70% 55% at 12% 8%, rgb(0 255 204 / 16%), transparent 70%),
      radial-gradient(ellipse 60% 60% at 88% 20%, rgb(255 0 85 / 14%), transparent 70%),
      radial-gradient(ellipse 75% 60% at 50% 100%, rgb(155 81 224 / 22%), transparent 70%),
      var(--bg);
    will-change: transform;
  }
  body { background: transparent; }

  /* Stock themes are CSS only, so their particle density is a count of pseudo-elements.
     These drop each theme to about half its layers. The .profile-inner and .profile-left
     pairs stay because Retro Vapor-Grid and Weeping Cherry draw their scenery there, and
     one host each stays from the card, view-my and facts, which are all the Pond's
     ripples have. !important is what reaches a theme already saved as text in custom_css,
     and it also beats the keyframes, since sanitizeCss strips it from member CSS. */
  .profile-themed .profile-right::after,
  .profile-themed .profile-name::before, .profile-themed .profile-name::after,
  .profile-themed .profile-card::after, .profile-themed .view-my::after, .profile-themed .profile-facts::after,
  .profile-themed .last-login::before, .profile-themed .last-login::after { display: none !important; }

  .profile-themed :is(.profile-inner, .profile-left, .profile-right, .profile-card, .view-my, .profile-facts)::before,
  .profile-themed :is(.profile-inner, .profile-left)::after {
    will-change: transform;
    filter: none !important; /* a filter repaints each frame, and the Lucid theme animates one */
  }

  /* These two animate background and mask positions, which repaint a full-page layer and
     every panel blurring it. Only transform and opacity animations are left running. */
  .profile-themed #profile::before { animation: none !important; }
  .profile-themed .profile-left::before, .profile-themed .profile-left::after { -webkit-mask-position: 0 0 !important; mask-position: 0 0 !important; }

  /* The same thinning for the ambient layer, host for host: see HOSTS in src/ambient.js. */
  .ambient .ambient-3::after,
  .ambient .ambient-4::before, .ambient .ambient-4::after,
  .ambient .ambient-5::after, .ambient .ambient-6::after, .ambient .ambient-7::after,
  .ambient .ambient-8::before, .ambient .ambient-8::after { display: none !important; }
  .ambient :is(.ambient-1, .ambient-2, .ambient-3, .ambient-5, .ambient-6, .ambient-7)::before,
  .ambient :is(.ambient-1, .ambient-2)::after { will-change: transform; filter: none !important; }
  .ambient::before { animation: none !important; }
  .ambient .ambient-2::before, .ambient .ambient-2::after { -webkit-mask-position: 0 0 !important; mask-position: 0 0 !important; }
}

/* ---------- Pixel Avatar, mascots, Mixtape, tickets, group chat ----------
   Every canvas here is a fixed backing store (32x32 avatars, 16x16 mascots) scaled by CSS
   with image-rendering: pixelated, so a repaint never changes layout. will-change and
   contain put each on its own compositor layer, so painting a frame or scrolling a long
   chat doesn't repaint what's around it. */
.visually-hidden { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }

.pixel-avatar {
  display: inline-block; vertical-align: middle; image-rendering: pixelated; image-rendering: crisp-edges;
  will-change: transform; contain: strict; transform: translateZ(0);
  background: rgb(255 255 255 / 6%); border: 1px solid rgb(255 255 255 / 18%); border-radius: 6px;
}
.pixel-avatar-sm { width: 24px; height: 24px; margin-right: 6px; border-radius: 4px; }
.pixel-avatar-md { width: 48px; height: 48px; }
.pixel-avatar-lg { width: 96px; height: 96px; margin-bottom: 6px; }
.pixel-avatar-xl { width: 160px; height: 160px; border-radius: 10px; }
.comment-author .pixel-avatar { display: block; margin: 6px auto 0; }

/* Beside the display name. The box is fixed and its negative block margins take it out of
   the line's height, so swapping a mood, or a mascot at all, never moves the header. */
.mascot-badge {
  display: inline-block; width: 1.15em; height: 1.15em; margin: -0.3em 0 -0.3em 0.3em; vertical-align: middle;
  image-rendering: pixelated; image-rendering: crisp-edges; will-change: transform; contain: strict; transform: translateZ(0);
}

/* ---------- the settings dashboard ----------
   Profile Settings and the Visual Customizer as a grid of translucent glass cards, every
   value picked from a picture: color squares and a wheel, font cards, slider cards and
   avatar thumbnails, see src/controls.js. Underneath they are radios, ranges and color
   inputs, so all of it saves with a plain form post. Colors live in classes here, never in
   style attributes, because the CSP forbids inline style. */
.settings-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 340px), 1fr)); gap: var(--space-4); align-items: start; }
.settings-grid > .box { margin-bottom: 0; }
.settings-wide { grid-column: 1 / -1; }
.settings-grid > .box, .glass-card, .glass-panel {
  border: 1px solid rgb(255 255 255 / 20%); border-radius: var(--radius-md);
  background: linear-gradient(135deg, rgb(0 255 204 / 7%), rgb(255 0 85 / 4%), rgb(155 81 224 / 8%)), var(--surface);
  -webkit-backdrop-filter: blur(16px) saturate(160%); backdrop-filter: blur(16px) saturate(160%);
  box-shadow: 0 8px 28px rgb(0 0 0 / 22%), inset 0 1px 0 rgb(255 255 255 / 18%);
}
fieldset.glass-card { margin: 0; padding: var(--space-4); min-width: 0; }
fieldset.glass-card > legend { padding: 2px var(--space-2); border-radius: var(--radius-full); font-size: var(--text-sm); font-weight: 700; background: var(--surface-2); border: 1px solid var(--hairline); }
.settings-stack { display: grid; gap: var(--space-4); max-width: none; }
.settings-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); }

/* Profile Details: labelled tiles in a grid, not a single column of rows. */
.field-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 200px), 1fr)); gap: var(--space-3); margin-bottom: var(--space-3); }
.field-tile { display: grid; gap: 4px; padding: var(--space-2) var(--space-3); border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface-2); transition: border-color var(--ease), box-shadow var(--ease); }
.field-tile:focus-within { border-color: var(--neon-line); box-shadow: var(--glow); }
.field-tile-wide { grid-column: 1 / -1; }
.field-name, .slider-name { font-size: var(--text-xs); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.field-tile input, .field-tile textarea { width: 100%; padding: 2px 0; border: 0; border-radius: 0; background: transparent; box-shadow: none; color: var(--ink); font: inherit; }
.field-tile input:focus, .field-tile textarea:focus { outline: 0; box-shadow: none; }

/* A preset color matrix: squares six across, and a custom square that opens onto the wheel. */
.color-control { display: grid; gap: var(--space-3); margin: var(--space-3) 0 0; padding: var(--space-3); min-width: 0; border: 1px solid var(--hairline); border-radius: var(--radius-sm); }
.color-control > legend { padding: 0 4px; font-size: var(--text-sm); font-weight: 600; }
.color-control.is-off { opacity: .45; }
.color-matrix { display: grid; grid-template-columns: repeat(auto-fill, 30px); gap: 6px; }
.color-square {
  position: relative; display: block; width: 30px; height: 30px; cursor: pointer; border-radius: 7px;
  border: 1px solid rgb(255 255 255 / 35%); box-shadow: inset 0 1px 0 rgb(255 255 255 / 30%), 0 1px 3px rgb(0 0 0 / 30%);
  transition: transform var(--ease), box-shadow var(--ease);
}
.color-square:hover { transform: scale(1.1); }
.color-square input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.color-square:has(input:checked) { box-shadow: 0 0 0 2px var(--ink), 0 0 12px rgb(95 243 255 / 70%); transform: scale(1.06); }
.color-square:has(input:focus-visible) { outline: 2px solid var(--neon-line); outline-offset: 2px; }
.color-square-custom { background: conic-gradient(#ff2bd6, #ffd700, #7dff5a, #5ff3ff, #7a2cff, #ff2bd6); }
.color-square-custom::after { content: "+"; position: absolute; inset: 0; display: grid; place-items: center; font-weight: 800; color: #ffffff; text-shadow: 0 1px 2px #000000; }
.skin-swatch { border-radius: 50%; }
.swatch-ff71ce { background: #ff71ce; }
.swatch-7a2cff { background: #7a2cff; }
.swatch-7dff5a { background: #7dff5a; }
.swatch-fffb96 { background: #fffb96; }
.swatch-ffd700 { background: #ffd700; }
.swatch-c41e3a { background: #c41e3a; }
.swatch-1b1530 { background: #1b1530; }
.swatch-3b2219 { background: #3b2219; }
.swatch-5c3a21 { background: #5c3a21; }
.swatch-8d5524 { background: #8d5524; }
.swatch-c68642 { background: #c68642; }
.swatch-e0ac69 { background: #e0ac69; }
.swatch-f4f1e8 { background: #f4f1e8; }
.swatch-3b6ea5 { background: #3b6ea5; }
.swatch-2ecc71 { background: #2ecc71; }
.swatch-d6b8ff { background: #d6b8ff; }

/* The wheel: hue on a conic gradient, white toward the middle, black over it for brightness.
   --wheel-* come from public/js/color-controls.js through the CSSOM. */
.color-studio { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-3); }
.color-chip { flex: none; width: 44px; height: 44px; padding: 0; cursor: pointer; border: 2px solid rgb(255 255 255 / 40%); border-radius: 50%; background: none; overflow: hidden; }
.color-chip::-webkit-color-swatch-wrapper { padding: 0; }
.color-chip::-webkit-color-swatch { border: 0; border-radius: 50%; }
.color-chip::-moz-color-swatch { border: 0; border-radius: 50%; }
.color-live { display: flex; flex: 1; flex-wrap: wrap; align-items: center; gap: var(--space-3); min-width: 0; }
.color-live[hidden] { display: none; }
.color-wheel {
  position: relative; flex: none; width: 120px; height: 120px; cursor: crosshair; touch-action: none; border-radius: 50%;
  background: radial-gradient(circle closest-side, #ffffff, transparent), conic-gradient(#ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
  box-shadow: 0 0 0 1px var(--hairline-strong), 0 0 18px rgb(95 243 255 / 25%);
}
.color-wheel::after { content: ""; position: absolute; inset: 0; border-radius: 50%; background: #000000; opacity: var(--wheel-dim, 0); pointer-events: none; }
.color-wheel:focus-visible { outline: 2px solid var(--neon-line); outline-offset: 3px; }
.color-wheel-marker {
  position: absolute; z-index: 1; left: var(--wheel-x, 50%); top: var(--wheel-y, 50%); width: 16px; height: 16px; margin: -8px 0 0 -8px;
  border: 2px solid #ffffff; border-radius: 50%; background: var(--wheel-color, transparent); box-shadow: 0 0 0 1px #000000, 0 2px 6px rgb(0 0 0 / 50%); pointer-events: none;
}
.color-sliders { display: grid; flex: 1; gap: var(--space-2); min-width: 150px; }
.slider-row { display: grid; gap: 4px; }

/* Range inputs as glowing bars. The hue bar is the spectrum; brightness runs black to the full color. */
.settings-grid input[type=range], .visual-form input[type=range] {
  width: 100%; height: 22px; padding: 0; -webkit-appearance: none; appearance: none; background: transparent; cursor: pointer; accent-color: var(--neon-line);
}
.settings-grid input[type=range]::-webkit-slider-runnable-track, .visual-form input[type=range]::-webkit-slider-runnable-track {
  height: 8px; border-radius: var(--radius-full); background: linear-gradient(90deg, #5ff3ff, #ff71ce); box-shadow: inset 0 0 0 1px rgb(255 255 255 / 25%);
}
.settings-grid input[type=range]::-moz-range-track, .visual-form input[type=range]::-moz-range-track {
  height: 8px; border-radius: var(--radius-full); background: linear-gradient(90deg, #5ff3ff, #ff71ce);
}
.settings-grid input[type=range]::-webkit-slider-thumb, .visual-form input[type=range]::-webkit-slider-thumb {
  width: 20px; height: 20px; margin-top: -6px; -webkit-appearance: none; appearance: none; border: 2px solid #ffffff; border-radius: 50%; background: #0b0d22; box-shadow: 0 0 8px #5ff3ff;
}
.settings-grid input[type=range]::-moz-range-thumb, .visual-form input[type=range]::-moz-range-thumb {
  width: 16px; height: 16px; border: 2px solid #ffffff; border-radius: 50%; background: #0b0d22; box-shadow: 0 0 8px #5ff3ff;
}
.settings-grid input.hue-slider::-webkit-slider-runnable-track, .visual-form input.hue-slider::-webkit-slider-runnable-track {
  background: linear-gradient(90deg, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
}
.settings-grid input.hue-slider::-moz-range-track, .visual-form input.hue-slider::-moz-range-track {
  background: linear-gradient(90deg, #ff0000, #ffff00, #00ff00, #00ffff, #0000ff, #ff00ff, #ff0000);
}
.settings-grid input.value-slider::-webkit-slider-runnable-track, .visual-form input.value-slider::-webkit-slider-runnable-track { background: linear-gradient(90deg, #000000, var(--wheel-full, #ffffff)); }
.settings-grid input.value-slider::-moz-range-track, .visual-form input.value-slider::-moz-range-track { background: linear-gradient(90deg, #000000, var(--wheel-full, #ffffff)); }
.visual-form input[type=range]:disabled { opacity: .4; cursor: default; }

.slider-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 220px), 1fr)); gap: var(--space-3); margin-top: var(--space-3); }
.slider-card { display: grid; gap: 6px; padding: var(--space-3); border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface-2); }
.slider-head { display: flex; justify-content: space-between; align-items: baseline; }
.slider-value { padding: 1px 8px; border-radius: var(--radius-full); font: 700 var(--text-xs) var(--font-mono); color: #0b0d22; background: #5ff3ff; }

/* An on/off switch, a checkbox underneath. */
.toggle-switch { display: inline-flex; align-items: center; gap: var(--space-2); cursor: pointer; font-weight: 600; }
.toggle-switch input { position: absolute; opacity: 0; width: 1px; height: 1px; }
.toggle-track { position: relative; flex: none; width: 40px; height: 22px; border-radius: var(--radius-full); background: var(--hairline-strong); transition: background var(--ease); }
.toggle-track::after { content: ""; position: absolute; top: 3px; left: 3px; width: 16px; height: 16px; border-radius: 50%; background: #ffffff; box-shadow: 0 1px 3px rgb(0 0 0 / 40%); transition: transform var(--ease); }
.toggle-switch input:checked + .toggle-track { background: linear-gradient(90deg, #00ffcc, #ff2bd6); box-shadow: 0 0 10px rgb(95 243 255 / 50%); }
.toggle-switch input:checked + .toggle-track::after { transform: translateX(18px); }
.toggle-switch input:focus-visible + .toggle-track { outline: 2px solid var(--neon-line); outline-offset: 2px; }

/* Font style cards, each name in its own face. The stacks match FONTS in src/visual.js. */
.font-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 140px), 1fr)); gap: var(--space-2); }
.font-card, .picture-card, .mascot-card {
  position: relative; display: grid; gap: 4px; justify-items: center; padding: var(--space-3) var(--space-2); cursor: pointer; text-align: center;
  border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface-2); transition: border-color var(--ease), box-shadow var(--ease), transform var(--ease);
}
.font-card:hover, .picture-card:hover, .mascot-card:hover { transform: translateY(-2px); border-color: var(--hairline-strong); }
.font-card input, .picture-card input, .mascot-card input, .avatar-tile input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.font-card:has(input:checked), .picture-card:has(input:checked), .mascot-card:has(input:checked), .avatar-tile:has(input:checked) {
  border-color: #5ff3ff; background: rgb(95 243 255 / 12%); box-shadow: 0 0 0 1px #5ff3ff, 0 0 16px rgb(95 243 255 / 35%);
}
.font-card:has(input:focus-visible), .picture-card:has(input:focus-visible), .mascot-card:has(input:focus-visible), .avatar-tile:has(input:focus-visible) { outline: 2px solid var(--neon-line); outline-offset: 2px; }
.font-sample { font-size: 30px; line-height: 1.1; }
.font-name { font-size: var(--text-sm); font-weight: 600; }
.font-pangram { font-size: var(--text-xs); color: var(--muted); }
.font-rounded { font-family: "Trebuchet MS", "Segoe UI", Verdana, sans-serif; }
.font-serif { font-family: Georgia, "Times New Roman", serif; }
.font-typewriter { font-family: "Courier New", Courier, monospace; }
.font-comic { font-family: "Comic Sans MS", "Comic Neue", cursive; }
.font-impact { font-family: Impact, "Arial Black", sans-serif; }
.font-elegant { font-family: Palatino, "Palatino Linotype", "Book Antiqua", serif; }

/* Background picture cards. Each tile is the theme's preview gradient from src/themes.js. */
/* A 16px gap leaves room for the hover lift and the checked glow, so neighbours never
   touch, and every row grows to its tallest card. Names wrap inside the card instead of
   being clipped by the .box around it: no fixed heights, no nowrap, and any long word
   breaks rather than pushing the card wider than its column. */
.picture-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 128px), 1fr)); grid-auto-rows: auto; align-items: stretch; gap: 16px; margin: 0; padding: 2px; }
.picture-card { grid-template-rows: auto auto auto; align-content: start; justify-items: stretch; min-width: 0; height: auto; min-height: 0; overflow: visible; }
.picture-tile { display: block; width: 100%; aspect-ratio: 16 / 10; border-radius: 6px; box-shadow: inset 0 0 0 1px rgb(255 255 255 / 20%); }
.picture-name, .picture-card .canvas-card-sub {
  display: block; min-width: 0; max-width: 100%; height: auto; white-space: normal; overflow-wrap: anywhere; hyphens: auto; text-wrap: balance;
}
.picture-name { font-size: clamp(11px, 2.6vw, var(--text-xs)); font-weight: 600; line-height: 1.3; letter-spacing: .01em; color: var(--ink); }
.picture-card .canvas-card-sub { line-height: 1.3; }
.picture-tile-default { background: linear-gradient(135deg, rgb(0 255 204 / 35%), rgb(255 0 85 / 25%), rgb(155 81 224 / 40%)), #10132a; }
.picture-tile-image { background: repeating-conic-gradient(#3a3f5c 0 25%, #252942 0 50%) 0 0 / 16px 16px; }
.picture-tile-image::after { content: "+"; display: grid; place-items: center; height: 100%; font-size: 22px; font-weight: 800; color: #ffffff; }
.theme-tile-cyberpunk-rain { background: repeating-linear-gradient(90deg, rgba(0, 255, 156, 0.7) 0 2px, rgba(0, 0, 0, 0) 2px 14px), linear-gradient(180deg, #2a0630, #03020a 60%, #04261a); }
.theme-tile-holographic-scanner { background: linear-gradient(180deg, rgba(0, 0, 0, 0) 48%, #e8ffff 50%, rgba(0, 0, 0, 0) 52%), linear-gradient(160deg, #0a1a33, #3a2a7a 55%, #0a4a5a); }
.theme-tile-y2k-vapor-pulse { background: linear-gradient(135deg, #ff9fd8, #e3c9ff 45%, #8fefff); }
.theme-tile-starfield-warp { background: radial-gradient(circle, #ffffff 0 1px, rgba(0, 0, 0, 0) 1.5px) 0 0 / 14px 14px, radial-gradient(ellipse at 50% 40%, #1b2c66, #010208 70%); }
.theme-tile-neon-synthwave-circuit { background: linear-gradient(180deg, #2a0845, #ff2bd6 48%, #ffe45c 52%, #12052a 54%, #29f3ff); }
.theme-tile-glitch-matrix { background: linear-gradient(90deg, rgba(255, 0, 90, 0.5), rgba(0, 0, 0, 0) 20% 80%, rgba(0, 255, 240, 0.5)), radial-gradient(ellipse at 50% 40%, #0a4a24, #000302 75%); }
.theme-tile-aurora-borealis { background: radial-gradient(ellipse at 30% 30%, rgba(60, 255, 170, 0.8), rgba(0, 0, 0, 0) 55%), radial-gradient(ellipse at 75% 70%, rgba(160, 90, 255, 0.8), rgba(0, 0, 0, 0) 55%), #04121f; }
.theme-tile-plasma-wave { background: conic-gradient(from 45deg, #ff3cb4, #5a6eff, #00ebc8, #ffc83c, #ff3cb4); }
.theme-tile-holo-grid-orbit { background: repeating-linear-gradient(0deg, rgba(90, 220, 255, 0.5) 0 1px, rgba(0, 0, 0, 0) 1px 12px), repeating-linear-gradient(90deg, rgba(90, 220, 255, 0.5) 0 1px, rgba(0, 0, 0, 0) 1px 12px), linear-gradient(180deg, #06122a, #0e0628); }
.url-field { display: grid; gap: 4px; margin-top: var(--space-3); }
/* The link box only matters for "My own image", and :has hides it otherwise with no script. */
.visual-form:not(:has(input[name="background"][value="image"]:checked)) .url-field { display: none; }
.picture-tile-library { background: linear-gradient(135deg, #2a1d4f, #5ff3ff 45%, #ff2bd6); }

/* ---------- Visual Canvas Editor (Profile Settings) ----------
   canvasEditorBox in src/routes/edit.js; public/js/canvas-editor.js paints the tiles and the
   preview through the CSSOM. Glass cards like the rest of the settings dashboard. */
.canvas-layout { display: grid; grid-template-columns: minmax(0, 1fr) 280px; gap: var(--space-5); align-items: start; }
.canvas-controls { min-width: 0; }
.canvas-section { display: grid; gap: var(--space-3); padding: var(--space-3); border: 1px solid var(--hairline); border-radius: var(--radius-md); }
.canvas-section legend { padding-inline: var(--space-1); font-size: var(--text-sm); font-weight: 700; color: var(--ink); }
.canvas-group-title { margin: 0; font-size: var(--text-xs); font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--ink); }
.canvas-card-sub { font-size: 11px; color: var(--muted); }
.canvas-extract { display: flex; flex-wrap: wrap; align-items: center; gap: var(--space-2); }
.canvas-library-manage { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.canvas-library-chip { display: inline-flex; align-items: center; gap: var(--space-2); padding: 2px var(--space-2); border: 1px solid var(--hairline); border-radius: var(--radius-full); background: var(--surface-2); font-size: var(--text-xs); }
.canvas-library-chip .link-button { font-size: var(--text-xs); }
.canvas-library-chip .library-toggle[data-saved="1"]::after { content: " \2715"; }
.canvas-colors { display: grid; grid-template-columns: repeat(auto-fit, minmax(min(100%, 260px), 1fr)); gap: var(--space-3); }
.canvas-colors .is-off, .canvas-editor [data-color-control].is-off { opacity: .45; }
.canvas-editor input:disabled { opacity: .45; cursor: default; }
.canvas-choices { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 150px), 1fr)); gap: var(--space-2); }
.canvas-choice {
  position: relative; display: grid; gap: 6px; align-content: start; justify-items: center; padding: var(--space-3) var(--space-2); text-align: center; cursor: pointer;
  border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface-2); transition: border-color var(--ease), box-shadow var(--ease), transform var(--ease);
}
.canvas-choice:hover { transform: translateY(-2px); border-color: var(--hairline-strong); }
.canvas-choice input { position: absolute; inset: 0; margin: 0; opacity: 0; cursor: pointer; }
.canvas-choice:has(input:checked) { border-color: #5ff3ff; background: rgb(95 243 255 / 12%); box-shadow: 0 0 0 1px #5ff3ff, 0 0 16px rgb(95 243 255 / 35%); }
.canvas-choice:has(input:focus-visible) { outline: 2px solid var(--neon-line); outline-offset: 2px; }
.canvas-choice-title { font-size: var(--text-sm); font-weight: 700; line-height: 1.25; color: var(--ink); }
.canvas-choice-letter { display: inline-grid; place-items: center; width: 20px; height: 20px; margin-right: 6px; border-radius: 50%; font-size: 11px; font-weight: 800; color: #0b0d22; background: #5ff3ff; vertical-align: 1px; }
.canvas-choice-blurb { font-size: 11px; line-height: 1.35; color: var(--muted); }
/* Border samples: a tiny box drawn in each style. */
.border-sample { display: block; width: 64px; height: 40px; border-radius: 6px; background: rgb(12 12 28 / 55%); }
.border-sample-default { border: 1px solid var(--hairline-strong); }
.border-sample-neon { border: 2px solid #ff2bd6; border-radius: 8px; box-shadow: 0 0 10px #ff2bd6, inset 0 0 8px rgb(255 43 214 / 35%); }
.border-sample-holo { border: 3px dotted #7df9ff; box-shadow: 0 0 14px rgb(125 249 255 / 30%); }
.border-sample-frameless { border-radius: 12px; box-shadow: 0 10px 24px rgb(0 0 0 / 55%), 0 0 18px rgb(32 220 210 / 20%); }
/* Layout icons: the columns of each style, in miniature. */
.layout-icon { display: grid; gap: 4px; width: 64px; height: 44px; padding: 4px; border: 1px solid var(--hairline-strong); border-radius: 6px; background: rgb(12 12 28 / 35%); }
.layout-icon > span { border-radius: 3px; background: linear-gradient(135deg, #5ff3ff, #ff2bd6); opacity: .85; }
.layout-icon-default { place-items: center; }
.layout-icon-default > span { width: 70%; height: 70%; opacity: .45; }
.layout-icon-split { grid-template-columns: 1fr 1fr; }
.layout-icon-stacked { grid-template-rows: repeat(3, 1fr); padding-inline: 10px; }
.layout-icon-matrix { grid-template-columns: 1fr 2.4fr; }
/* The live preview: a miniature profile on the chosen backdrop. */
.canvas-preview-panel { align-self: start; position: sticky; top: var(--space-4); }
.canvas-stage { padding: var(--space-3); border-radius: var(--radius-md); overflow: hidden; min-height: 240px; background: linear-gradient(135deg, rgb(0 255 204 / 35%), rgb(255 0 85 / 25%), rgb(155 81 224 / 40%)), #10132a; }
.canvas-mini { display: grid; gap: 8px; }
.canvas-mini-split { grid-template-columns: 1fr 1fr; }
.canvas-mini-stacked { grid-template-columns: minmax(0, 1fr); max-width: 86%; margin-inline: auto; }
.canvas-mini-matrix { grid-template-columns: minmax(0, 1fr) minmax(0, 2fr); gap: 10px; }
.canvas-col { display: grid; gap: 8px; align-content: start; min-width: 0; }
.canvas-box { padding: 8px; border: 1px solid rgb(255 255 255 / 30%); border-radius: 8px; background: rgb(255 255 255 / 12%); color: #f2f2f7; text-shadow: 0 1px 2px #000000; font-size: 11px; overflow-wrap: anywhere; }
.canvas-box strong { display: block; margin-bottom: 2px; font-size: 12px; color: #5ff3ff; }
.canvas-box p { margin: 0; }
.canvas-link { text-decoration: underline; }
.canvas-box.canvas-border-neon { border: 2px solid #ff2bd6; box-shadow: 0 0 8px currentcolor; }
.canvas-box.canvas-border-holo { border: 2px dotted #7df9ff; border-radius: 6px; }
.canvas-box.canvas-border-frameless { border: 0; border-radius: 12px; box-shadow: 0 10px 24px rgb(0 0 0 / 55%); }
@media (max-width: 900px) {
  .canvas-layout { grid-template-columns: minmax(0, 1fr); }
  .canvas-preview-panel { position: static; order: -1; }
}

/* The Pixel Avatar studio: a sticky preview, then a section per category of 32x32 tiles. */
.avatar-studio { display: grid; grid-template-columns: 200px minmax(0, 1fr); gap: var(--space-4); align-items: start; }
.avatar-studio .avatar-stage { position: sticky; top: var(--space-4); display: grid; gap: var(--space-2); justify-items: center; text-align: center; }
.avatar-panels { display: grid; gap: var(--space-2); min-width: 0; }
.studio-section { border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface-2); }
.studio-section > summary { display: flex; justify-content: space-between; align-items: center; padding: var(--space-2) var(--space-3); cursor: pointer; font-weight: 700; list-style: none; }
.studio-section > summary::-webkit-details-marker { display: none; }
.studio-section > summary::after { content: "\25BE"; margin-left: var(--space-2); color: var(--muted); transition: transform var(--ease); }
.studio-section:not([open]) > summary::after { transform: rotate(-90deg); }
.studio-count { margin-left: auto; padding: 1px 8px; border-radius: var(--radius-full); font-size: var(--text-xs); font-weight: 600; color: var(--muted); background: var(--surface); }
.studio-body { display: grid; gap: var(--space-3); padding: 0 var(--space-3) var(--space-3); }
.avatar-grid { margin: 0; padding: 0; min-width: 0; border: 0; }
.avatar-grid > legend { padding: 0; margin-bottom: var(--space-1); font-size: var(--text-xs); font-weight: 700; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); }
.avatar-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(76px, 1fr)); gap: var(--space-2); }
.avatar-tile {
  position: relative; display: grid; gap: 4px; justify-items: center; padding: 6px 4px; cursor: pointer;
  border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface); transition: border-color var(--ease), transform var(--ease);
}
.avatar-tile:hover { transform: translateY(-2px); border-color: var(--hairline-strong); }
.pixel-avatar-thumb { width: 64px; height: 64px; border-radius: 6px; }
.avatar-tile-label { max-width: 100%; overflow: hidden; font-size: 11px; line-height: 1.2; text-overflow: ellipsis; white-space: nowrap; }
.skin-matrix { grid-template-columns: repeat(auto-fill, 30px); }

/* Mood mascot cards: each one dances, see pixel-render.js. */
.mascot-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(96px, 1fr)); gap: var(--space-2); margin-bottom: var(--space-3); }
.mascot-preview { width: 48px; height: 48px; image-rendering: pixelated; image-rendering: crisp-edges; will-change: transform; contain: strict; transform: translateZ(0); }
.mascot-none { display: block; width: 48px; height: 48px; border: 2px dashed var(--hairline-strong); border-radius: 50%; }
.mascot-name { font-size: var(--text-xs); font-weight: 600; }

@media (max-width: 700px) {
  .avatar-studio { grid-template-columns: minmax(0, 1fr); }
  /* On a phone the preview rides along at the top while the tiles scroll under it. */
  .avatar-studio .avatar-stage { z-index: 2; grid-template-columns: auto 1fr; justify-items: start; text-align: left; padding: var(--space-2); border-radius: var(--radius-sm); background: var(--surface); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); }
  .avatar-studio .pixel-avatar-xl { width: 96px; height: 96px; grid-row: span 2; }
  .avatar-tiles { grid-template-columns: repeat(auto-fill, minmax(68px, 1fr)); }
  .pixel-avatar-thumb { width: 56px; height: 56px; }
  .field-tile input, .field-tile textarea { font-size: 16px; } /* under 16px, iOS zooms the page on focus */
}
.skin-swatch-umber { background: #3b2219; }
.skin-swatch-espresso { background: #5c3a21; }
.skin-swatch-chestnut { background: #8d5524; }
.skin-swatch-caramel { background: #c68642; }
.skin-swatch-honey { background: #e0ac69; }
.skin-swatch-sand { background: #f1c27d; }
.skin-swatch-peach { background: #ffdbac; }
.skin-swatch-porcelain { background: #fff0e1; }
.skin-swatch-cyber-mint { background: #7dffcf; }
.skin-swatch-neon-violet { background: #b98cff; }
.skin-swatch-chrome-blue { background: #7fc8ff; }
.skin-swatch-hot-magenta { background: #ff7ad9; }
.skin-swatch-neon-toxic-green { background: #9dff3a; }
.skin-swatch-neon-electric-cyan { background: #29f3ff; }
.skin-swatch-neon-ethereal-pink { background: #ffb3ec; }
.skin-swatch-neon-shadow-purple { background: #5b3a8f; }

/* Mixtape Swap. The MIX light only shows while a gifted track is up on the deck. */
.deck-mix { padding: 0 4px; border: 1px solid currentColor; border-radius: 3px; font-size: 10px; letter-spacing: 0.08em; }
.deck-mix[hidden] { display: none; }
.gift-track { margin: 10px 0; }
.gift-track .section-title { margin-bottom: 6px; }
.mixtape-requests { list-style: none; padding: 0; display: grid; gap: 8px; }
.mixtape-requests li { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; padding: 8px; border: 1px solid var(--hairline); border-radius: 8px; }
.mixtape-requests .track-name { flex: 1 1 220px; }

/* Holographic Ticket Stubs: a glass ticket with a perforated stub on the right. No
   backdrop-filter on a profile unless it's the site's own glass, see .profile-glass. */
.events-board { margin: 12px 0; }
.event-creator { margin: 8px 0 12px; }
.event-creator > summary { display: inline-block; list-style: none; cursor: pointer; }
.event-creator > summary::-webkit-details-marker { display: none; }
.event-when { display: flex; gap: 12px; flex-wrap: wrap; }
.ticket-rack { display: grid; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); gap: 14px; }
.holo-ticket {
  position: relative; display: grid; grid-template-columns: 1fr 64px; grid-template-areas: "main stub" "actions actions";
  overflow: hidden; border-radius: 14px; color: #f6f7ff;
  border: 1px solid rgb(255 255 255 / 35%);
  background: linear-gradient(115deg, rgb(0 255 204 / 18%), rgb(255 43 214 / 16%) 45%, rgb(95 243 255 / 18%) 70%, rgb(177 77 255 / 20%)) 0 0 / 240% 240%, rgb(255 255 255 / 7%);
  box-shadow: 0 0 18px rgb(95 243 255 / 22%), inset 0 0 0 1px rgb(255 255 255 / 8%);
  animation: holo-shift 9s ease-in-out infinite alternate;
}
.holo-ticket::after {
  content: ""; position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(105deg, transparent 35%, rgb(255 255 255 / 22%) 48%, transparent 60%) -150% 0 / 250% 100% no-repeat;
  animation: holo-glint 6s ease-in-out infinite;
}
.site-main .holo-ticket, .profile-glass .holo-ticket { -webkit-backdrop-filter: blur(16px) saturate(170%); backdrop-filter: blur(16px) saturate(170%); }
@keyframes holo-shift { to { background-position: 100% 100%, 0 0; } }
@keyframes holo-glint { 0%, 55% { background-position: -150% 0; } 100% { background-position: 250% 0; } }
.ticket-main { grid-area: main; padding: 12px 14px; min-width: 0; }
.ticket-kicker { margin: 0; font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase; color: #5ff3ff; }
.ticket-title { margin: 4px 0; font-size: 18px; overflow-wrap: anywhere; text-shadow: 0 0 8px rgb(255 43 214 / 55%); }
.ticket-date { margin: 0 0 6px; font-family: ui-monospace, "Courier New", monospace; font-size: 13px; color: #fffb96; }
.ticket-description { margin: 0; font-size: 13px; color: #dfe4f5; overflow-wrap: anywhere; }
.ticket-stub {
  grid-area: stub; display: flex; align-items: center; justify-content: center;
  border-left: 2px dashed rgb(255 255 255 / 45%);
  background: radial-gradient(circle at 0 0, transparent 9px, rgb(255 255 255 / 6%) 10px) top left / 100% 51% no-repeat,
    radial-gradient(circle at 0 100%, transparent 9px, rgb(255 255 255 / 6%) 10px) bottom left / 100% 51% no-repeat;
}
.ticket-serial { writing-mode: vertical-rl; font-family: ui-monospace, "Courier New", monospace; font-size: 11px; letter-spacing: 0.12em; color: #ffffffcc; }
.ticket-actions { grid-area: actions; display: flex; flex-wrap: wrap; align-items: center; gap: 10px; padding: 0 14px 12px; position: relative; z-index: 1; }
.ticket-collected { color: #7dff5a; font-weight: 600; font-size: 13px; }
.ticket-stamp { grid-column: 1 / -1; margin: 0; padding: 0 14px 10px; font-size: 11px; letter-spacing: 0.08em; text-transform: uppercase; color: #ffffffaa; }
.holo-stub { transform: rotate(-0.4deg); }
.holo-stub:nth-child(even) { transform: rotate(0.5deg); }
.ticket-book .feed-search { margin-bottom: 12px; }

@media (max-width: 768px) {
  .ticket-rack { grid-template-columns: 1fr; }
}
@media (prefers-reduced-motion: reduce) {
  .holo-ticket, .holo-ticket::after { animation: none; }
}

/* ---------- holographic glass ----------
   The site's own surfaces, and !important is safe here because none of these are in a
   profile's layout, so no theme is being overruled. The gradient is twice the size of
   its box, which leaves room for a hover to slide it. The active tab stays solid. */
.site-bar, .site-footer, .box, .composer, .story-composer, .post-card, .game-card, .top8-slot, .tabs a:not(.active), .tone-picker, .feed-empty, .flash, .notice, .warnings {
  background: linear-gradient(135deg, rgba(0, 255, 204, 0.1), rgba(255, 0, 85, 0.1), rgba(155, 81, 224, 0.1)) 0% 50% / 220% 220%, rgba(255, 255, 255, 0.07) !important;
  border: 1px solid rgba(255, 255, 255, 0.2) !important;
  -webkit-backdrop-filter: blur(16px) saturate(180%) !important;
  backdrop-filter: blur(16px) saturate(180%) !important;
  transition: background-position 700ms ease, box-shadow var(--ease), transform var(--ease);
}
.site-bar:hover, .site-footer:hover, .box:hover, .composer:hover, .story-composer:hover, .post-card:hover, .game-card:hover, .top8-slot:hover, .tabs a:not(.active):hover, .tone-picker:hover { background-position: 100% 50%, 0 0 !important; }
.site-bar { border-width: 0 0 1px !important; }
.site-footer { border-width: 1px 0 0 !important; }
.site-bar select, .form select, .top8-slot select { color-scheme: dark; }

/* A page with no theme or CSS of its own gets the same glass. No !important here, so
   the Visual Customizer's sliders still win, and no backdrop-filter on any other page,
   because it would trap a saved theme's layers inside whichever panel hosts them. */
.profile-glass #profile { background: transparent; }
.profile-glass :is(.interests, .details, .extended-network, .friends-block, .blurbs, .profile-mail, .friend-space, .comments, .games, .music-player, .profile-panel) {
  padding: 8px; border: 1px solid rgba(255, 255, 255, 0.2); border-radius: 8px; color: var(--ink);
  background: linear-gradient(135deg, rgba(0, 255, 204, 0.1), rgba(255, 0, 85, 0.1), rgba(155, 81, 224, 0.1)) 0% 50% / 220% 220%, rgba(255, 255, 255, 0.07);
  -webkit-backdrop-filter: blur(16px) saturate(180%);
  backdrop-filter: blur(16px) saturate(180%);
  transition: background-position 700ms ease;
}
.profile-glass :is(.friends-block, .blurbs, .profile-mail, .friend-space, .comments, .games, .music-player, .profile-panel):hover { background-position: 100% 50%, 0 0; }
.profile-glass :is(.interests, .details) { border-collapse: separate; border-spacing: 0; overflow: hidden; }
.profile-glass :is(.interests, .details) th, .profile-glass .section-title { background: rgb(255 255 255 / 12%); color: #ffffff; border-radius: 4px; }
.profile-glass .label { background: transparent; color: var(--link); }
.profile-glass .last-login { color: var(--muted); }
.profile-glass .extended-network { color: #ffc69c; }
.profile-glass :is(.comment-author, .comment-body) { background: rgb(255 255 255 / 5%); border-radius: 4px; }
.profile-glass .music-start { background: rgb(255 255 255 / 8%); color: var(--ink); }
.profile-glass .music-start:hover { background: rgb(255 255 255 / 16%); }
.profile-glass .comment-form textarea { background: rgb(255 255 255 / 6%); color: var(--ink); }

/* The glass stays on touch. Sliding its gradient doesn't: hover sticks after a tap, and
   each slide repaints the blur. */
@media (max-width: 768px), (pointer: coarse) {
  .site-bar, .site-footer, .box, .composer, .story-composer, .post-card, .game-card, .top8-slot, .tabs a:not(.active), .tone-picker,
  .profile-glass :is(.interests, .details, .extended-network, .friends-block, .blurbs, .profile-mail, .friend-space, .comments, .games, .music-player, .profile-panel) {
    transition: none;
  }
}

/* ---------- Top 8 Friends, the About Me capsule and the friends folder ----------
   Top 8 is the first thing in #profile, above both columns, so it sits above
   .profile-actions too. That is allowed by the rule in the locked controls below: it
   carries only friends' cards (escaped names and pictures), nothing the owner wrote. */
.top-8-showcase { margin: 0 max(16px, calc((100% - 848px) / 2)) 16px; text-align: center; }
.top-8-showcase .section-title { text-align: center; font-size: 15px; letter-spacing: 0.08em; text-transform: uppercase; }
.top-8-showcase .top-8 { grid-template-columns: repeat(8, minmax(0, 1fr)); gap: 10px; }
.top-8-showcase .friend {
  padding: 6px 4px 8px; border-radius: 10px; border: 1px solid rgb(255 255 255 / 35%);
  background: linear-gradient(135deg, rgb(0 255 204 / 14%), rgb(255 0 128 / 12%), rgb(155 81 224 / 16%)) 0% 50% / 220% 220%;
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 30%), 0 4px 12px rgb(0 0 0 / 18%);
  transition: background-position 600ms ease, transform 200ms ease;
}
.top-8-showcase .friend:hover { background-position: 100% 50%; transform: translateY(-3px); }
.top-8-showcase .friend img { border-radius: 6px; }
.top-8-showcase .friend-count { margin: 8px 0 0; }
@media (max-width: 768px) { .top-8-showcase .top-8 { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* Two rows of four even on a phone, so Top 8 never fills the first screen on its own. */
@media (max-width: 460px) {
  .top-8-showcase .top-8 { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 6px; }
  .top-8-showcase .friend { padding: 4px 2px 6px; }
  .top-8-showcase .friend img { width: 100%; height: auto; }
  .top-8-showcase .online-now { font-size: 9px; padding-inline: 3px; }
}

.about-facts { display: grid; gap: 4px; margin: 8px 0 0; font-size: 12px; }
.about-row { display: flex; align-items: center; gap: 8px; padding-top: 4px; border-top: 1px solid color-mix(in srgb, currentColor 15%, transparent); }
.about-row dt { flex: none; width: 60px; font-weight: bold; color: var(--orange); }
.about-row dd { display: flex; align-items: center; gap: 6px; min-width: 0; margin: 0; overflow-wrap: anywhere; }
.about-row .mood { margin: 0; font-size: inherit; }
.about-emotion .emotion { font-weight: 700; text-transform: capitalize; }
.about-none { font-style: italic; opacity: 0.65; }
.blurbs .mood-form { margin: 8px 0 0; }
.profile-glass .about-row dt { color: var(--link); }

/* The friends folder: a <details> that slides shut where the browser can animate to auto. */
.friends-block > summary { display: flex; justify-content: space-between; align-items: center; cursor: pointer; list-style: none; user-select: none; }
.friends-block > summary::-webkit-details-marker { display: none; }
.friends-block > summary::after { content: "\25BE"; transition: transform var(--ease); }
.friends-block:not([open]) > summary { margin-bottom: 0; }
.friends-block:not([open]) > summary::after { transform: rotate(-90deg); }
.friends-block { interpolate-size: allow-keywords; }
.friends-block::details-content { block-size: 0; overflow: clip; transition: block-size 380ms ease, content-visibility 380ms allow-discrete; }
.friends-block[open]::details-content { block-size: auto; }
@media (prefers-reduced-motion: reduce) { .friends-block::details-content { transition: none; } }

/* ---------- Media Player Styles ----------
   Five looks for the same deck, picked on Profile Settings (src/player-skins.js) and
   carried as data-skin. DreamAmp Classic is the deck above, untouched. The others only
   lay its parts out again. No skin colors the deck's parts: the accent still comes from a theme,
   the Customizer or member CSS on .deck-screen and .deck-button. A casing that should
   take that accent hangs it on .deck-screen::before: the screen is left unpositioned,
   so the pseudo-element is placed against the shell but still reads the screen's color. */
.retro-deck[data-skin] .deck-shell { isolation: isolate; }

/* Sonic Wave 2001: an oval spaceship pod with a round porthole visualizer. */
.retro-deck[data-skin="sonic-wave"] .deck-shell {
  padding: 16px 26px 18px; border-radius: 48% 48% 44% 44% / 38% 38% 30% 30%; text-align: center;
  background: radial-gradient(120% 70% at 50% 0%, rgb(255 255 255 / 34%), transparent 55%), linear-gradient(165deg, rgb(86 96 150 / 72%), rgb(16 18 46 / 84%));
  box-shadow: inset 0 2px 0 rgb(255 255 255 / 40%), inset 0 -8px 18px rgb(0 0 0 / 40%), 0 8px 22px rgb(0 0 0 / 35%);
}
.retro-deck[data-skin="sonic-wave"] .deck-shell::before { height: 5px; margin: 0 38% 8px; border-radius: 99px; opacity: 0.7; background: linear-gradient(90deg, transparent, rgb(255 255 255 / 80%), transparent); }
.retro-deck[data-skin="sonic-wave"] .deck-shell::after {
  content: ""; position: absolute; top: 26%; bottom: 26%; left: -8px; right: -8px; z-index: -2; pointer-events: none;
  border-radius: 50%; border-inline: 6px solid rgb(255 255 255 / 22%);
  /* Only the tips that stick out past the pod show: the rest would cross its face. */
  -webkit-mask-image: linear-gradient(90deg, #000000 0 7%, transparent 7% 93%, #000000 93%);
  mask-image: linear-gradient(90deg, #000000 0 7%, transparent 7% 93%, #000000 93%);
}
.retro-deck[data-skin="sonic-wave"] .deck-screen { border-radius: 999px; padding: 6px 18px; }
.retro-deck[data-skin="sonic-wave"] .deck-screen::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  border-radius: 48% 48% 44% 44% / 38% 38% 30% 30%;
  background: radial-gradient(70% 45% at 50% 105%, color-mix(in srgb, currentColor 40%, transparent), transparent 70%);
  box-shadow: inset 0 0 0 2px color-mix(in srgb, currentColor 45%, transparent);
}
.retro-deck[data-skin="sonic-wave"] .deck-readout { justify-content: center; }
.retro-deck[data-skin="sonic-wave"] .deck-eq { margin-left: 0; }
.retro-deck[data-skin="sonic-wave"] .deck-controls { display: flex; justify-content: center; align-items: center; gap: 8px; margin-top: 10px; }
.retro-deck[data-skin="sonic-wave"] .deck-controls .deck-button { width: 36px; height: 36px; min-height: 36px; border-radius: 50%; }
.retro-deck[data-skin="sonic-wave"] .deck-controls .deck-button[data-deck-action="play"] { width: 48px; height: 48px; }
@media (pointer: coarse) { .retro-deck[data-skin="sonic-wave"]:not(.deck-preview) .deck-controls .deck-button { width: 44px; height: 44px; } }
.retro-deck[data-skin="sonic-wave"] .deck-fx-canvas {
  width: 156px; height: 156px; margin: 4px auto 0; border-radius: 50%;
  box-shadow: 0 0 0 4px rgb(255 255 255 / 14%), 0 0 20px rgb(0 0 0 / 50%), inset 0 0 18px rgb(0 0 0 / 70%);
}
.retro-deck[data-skin="sonic-wave"] .deck-fx-presets { display: flex; flex-wrap: wrap; justify-content: center; }
.retro-deck[data-skin="sonic-wave"] .deck-fx-preset { padding-inline: 8px; border-radius: 99px; }
.retro-deck[data-skin="sonic-wave"] .deck-fx-project { border-radius: 99px; }

/* Cyber-Goth Component Stack: two rack units, display over transport, with screws, brushed
   steel and 7-segment counters that blink until the music starts, like a VCR at 12:00. */
.retro-deck[data-skin="cyber-goth"] .deck-shell {
  display: grid; gap: 6px; padding: 8px 16px; border-radius: 3px; border-color: rgb(255 255 255 / 16%);
  background: repeating-linear-gradient(90deg, rgb(255 255 255 / 3%) 0 1px, transparent 1px 3px), linear-gradient(180deg, #2b2b33, #15151a 55%, #0b0b0e);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 20%), inset 0 -2px 0 rgb(0 0 0 / 60%), 0 6px 16px rgb(0 0 0 / 45%);
  -webkit-backdrop-filter: none; backdrop-filter: none;
}
.retro-deck[data-skin="cyber-goth"] .deck-shell::before {
  position: absolute; inset: 5px 4px; height: auto; margin: 0; border-radius: 0; opacity: 0.9; pointer-events: none;
  background:
    radial-gradient(circle, #9a9aa6 0 1.5px, #2a2a32 2px, transparent 2.6px) 0 0 / 8px 8px no-repeat,
    radial-gradient(circle, #9a9aa6 0 1.5px, #2a2a32 2px, transparent 2.6px) 100% 0 / 8px 8px no-repeat,
    radial-gradient(circle, #9a9aa6 0 1.5px, #2a2a32 2px, transparent 2.6px) 0 100% / 8px 8px no-repeat,
    radial-gradient(circle, #9a9aa6 0 1.5px, #2a2a32 2px, transparent 2.6px) 100% 100% / 8px 8px no-repeat;
}
.retro-deck[data-skin="cyber-goth"] .deck-screen { border-radius: 2px; padding: 6px 8px; }
.retro-deck[data-skin="cyber-goth"] .deck-readout { display: grid; grid-template-columns: auto auto 1fr auto; align-items: end; gap: 8px; }
.retro-deck[data-skin="cyber-goth"] .deck-state,
.retro-deck[data-skin="cyber-goth"] .deck-count { position: relative; font-style: italic; letter-spacing: 0.14em; transform: skewX(-6deg); }
.retro-deck[data-skin="cyber-goth"] .deck-count { font-size: 20px; line-height: 1; }
/* The unlit segments behind the lit ones, as on a real LCD. */
.retro-deck[data-skin="cyber-goth"] .deck-count::before { content: "88/88"; position: absolute; inset: 0; opacity: 0.12; text-shadow: none; }
.retro-deck[data-skin="cyber-goth"]:not(.is-playing) .deck-count { animation: deck-blink 1s steps(2, jump-none) infinite; }
.retro-deck[data-skin="cyber-goth"] .deck-controls {
  margin-top: 0; padding-top: 7px; gap: 4px; border-top: 2px groove rgb(255 255 255 / 14%);
}
.retro-deck[data-skin="cyber-goth"] .deck-button {
  min-height: 28px; border-radius: 2px; border-color: rgb(0 0 0 / 70%);
  background: linear-gradient(180deg, #484852, #26262d 48%, #1b1b20 52%, #2a2a31);
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 22%), 0 2px 0 rgb(0 0 0 / 60%);
}
.retro-deck[data-skin="cyber-goth"] .deck-fx-canvas { border-radius: 2px; }

/* Y2K Fruit-Pod Capsule: see-through candy plastic in the accent color, a gloss highlight
   and frosted, pill-shaped buttons. */
.retro-deck[data-skin="fruit-pod"] .deck-shell {
  padding: 14px 14px 16px; border-radius: 30px; border-color: rgb(255 255 255 / 55%);
  background: linear-gradient(180deg, rgb(255 255 255 / 45%), rgb(255 255 255 / 8%) 28%, transparent 55%, rgb(255 255 255 / 14%));
  box-shadow: inset 0 2px 6px rgb(255 255 255 / 55%), inset 0 -8px 16px rgb(0 0 0 / 18%), 0 10px 24px rgb(0 0 0 / 28%);
  -webkit-backdrop-filter: blur(6px) saturate(200%); backdrop-filter: blur(6px) saturate(200%);
}
.retro-deck[data-skin="fruit-pod"] .deck-shell::before { height: 6px; margin: 0 30% 9px; opacity: 0.55; background: radial-gradient(circle, rgb(255 255 255 / 85%) 0 1.2px, transparent 1.6px) 0 0 / 5px 6px; }
.retro-deck[data-skin="fruit-pod"] .deck-shell::after {
  content: ""; position: absolute; top: 4px; left: 10%; width: 55%; height: 34%; z-index: -1; pointer-events: none;
  border-radius: 50%; background: radial-gradient(ellipse at 40% 30%, rgb(255 255 255 / 55%), transparent 70%);
}
.retro-deck[data-skin="fruit-pod"] .deck-screen { border-radius: 14px; background: linear-gradient(180deg, rgb(255 255 255 / 20%), rgb(255 255 255 / 4%)), rgb(8 12 28 / 58%); }
.retro-deck[data-skin="fruit-pod"] .deck-screen::before {
  content: ""; position: absolute; inset: 0; z-index: -2; pointer-events: none; border-radius: 30px;
  background: color-mix(in srgb, currentColor 34%, transparent);
}
.retro-deck[data-skin="fruit-pod"] .deck-controls { gap: 8px; margin-top: 10px; }
.retro-deck[data-skin="fruit-pod"] .deck-button,
.retro-deck[data-skin="fruit-pod"] .deck-fx-preset,
.retro-deck[data-skin="fruit-pod"] .deck-fx-project {
  border-radius: 999px; border-color: rgb(255 255 255 / 60%);
  background: linear-gradient(180deg, rgb(255 255 255 / 45%), rgb(255 255 255 / 14%) 55%, rgb(255 255 255 / 24%));
  box-shadow: inset 0 1px 0 rgb(255 255 255 / 80%), inset 0 -2px 4px rgb(0 0 0 / 12%), 0 3px 8px rgb(0 0 0 / 20%);
  -webkit-backdrop-filter: blur(4px); backdrop-filter: blur(4px);
}
.retro-deck[data-skin="fruit-pod"] .deck-fx-canvas { border-radius: 14px; }

/* Subterranean Dark Tracker: a black grid matrix with chamfered corners, thin neon lines
   and channel headers, like an old mod tracker. */
.retro-deck[data-skin="dark-tracker"] .deck-shell {
  padding: 6px; border-radius: 0; border-color: transparent;
  background: linear-gradient(rgb(255 255 255 / 5%) 1px, transparent 1px) 0 0 / 100% 8px, linear-gradient(90deg, rgb(255 255 255 / 5%) 1px, transparent 1px) 0 0 / 8px 100%, #05060a;
  clip-path: polygon(10px 0, 100% 0, 100% calc(100% - 10px), calc(100% - 10px) 100%, 0 100%, 0 10px);
  box-shadow: none; -webkit-backdrop-filter: none; backdrop-filter: none;
}
.retro-deck[data-skin="dark-tracker"] .deck-shell::before {
  content: "CH1  CH2  CH3  CH4"; height: auto; margin: 0 0 4px; border-radius: 0; opacity: 0.55; background: none; white-space: pre;
  font: 700 9px/1.4 "Courier New", Courier, monospace; letter-spacing: 0.18em; color: #c8d0e0; text-align: center;
}
.retro-deck[data-skin="dark-tracker"] .deck-screen { border-radius: 0; text-transform: uppercase; background: repeating-linear-gradient(180deg, rgb(255 255 255 / 5%) 0 11px, transparent 11px 22px), #000000; }
.retro-deck[data-skin="dark-tracker"] .deck-screen::before {
  content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
  border: 1px solid currentColor; box-shadow: inset 0 0 12px color-mix(in srgb, currentColor 35%, transparent);
}
.retro-deck[data-skin="dark-tracker"] .deck-controls { gap: 2px; margin-top: 4px; }
.retro-deck[data-skin="dark-tracker"] .deck-button,
.retro-deck[data-skin="dark-tracker"] .deck-fx-preset,
.retro-deck[data-skin="dark-tracker"] .deck-fx-project {
  min-height: 28px; border-radius: 0; border-color: currentColor; background: #07080d; box-shadow: none;
  clip-path: polygon(6px 0, 100% 0, 100% calc(100% - 6px), calc(100% - 6px) 100%, 0 100%, 0 6px);
}
.retro-deck[data-skin="dark-tracker"] .deck-fx-canvas { border-radius: 0; }

/* ---------- the dancing deck ----------
   While sound plays and the deck is on screen, public/js/site.js sets .is-dancing and three
   multipliers on it, each from 1 to 1.25: --fx-bass, --fx-mid and --fx-treble, plus
   --fx-eq1 to 5 for the readout's bars. Every rule here reads them through calc(), so
   each skin moves by its own amount, and only transform, opacity, filter and text-shadow
   change: no layout, ever. Without .is-dancing (reduced motion, paused, off screen, the
   Settings swatches) every skin is exactly as drawn above. */
.retro-deck { --fx-bass: 1; --fx-mid: 1; --fx-treble: 1; }

/* Every skin: the readout's little EQ follows the bands instead of its idle loop. */
.retro-deck.is-dancing .deck-eq i { animation: none; transform: scaleY(var(--fx-eq1, 1)); }
.retro-deck.is-dancing .deck-eq i:nth-child(2) { transform: scaleY(var(--fx-eq2, 1)); }
.retro-deck.is-dancing .deck-eq i:nth-child(3) { transform: scaleY(var(--fx-eq3, 1)); }
.retro-deck.is-dancing .deck-eq i:nth-child(4) { transform: scaleY(var(--fx-eq4, 1)); }
.retro-deck.is-dancing .deck-eq i:nth-child(5) { transform: scaleY(var(--fx-eq5, 1)); }

/* DreamAmp Classic and Dark Tracker: the bass swells the power LED and pulses the track
   counter in a neon glow. */
.retro-deck:is([data-skin="dreamamp"], [data-skin="dark-tracker"]).is-dancing .deck-led {
  transform: scale(calc(1 + (var(--fx-bass) - 1) * 2.4));
}
.retro-deck:is([data-skin="dreamamp"], [data-skin="dark-tracker"]).is-dancing .deck-count {
  transform: scale(calc(1 + (var(--fx-bass) - 1) * 0.5)); transform-origin: left center;
  text-shadow: 0 0 4px currentColor, 0 0 calc((var(--fx-bass) - 1) * 48px) currentColor,
    0 0 calc((var(--fx-bass) - 1) * 96px) color-mix(in srgb, currentColor 70%, #ff3df2);
}

/* Sonic Wave 2001 and Cyber-Goth: light rings around the frame, pink on the mids and cyan
   on the treble. The opacity is the band squared, so steady sound stays dim and peaks
   flash. Only opacity changes per frame, so the glow is composited, never repainted. */
.deck-aura { display: none; }
.retro-deck:is([data-skin="sonic-wave"], [data-skin="cyber-goth"]) .deck-aura {
  display: block; position: absolute; inset: 0; z-index: 1; pointer-events: none; border-radius: inherit;
}
.deck-aura i { position: absolute; inset: 0; border-radius: inherit; opacity: 0; will-change: opacity; }
.deck-aura-mid {
  box-shadow: inset 0 0 0 2px #ff3df2, inset 0 0 18px rgb(255 61 242 / 55%), 0 0 10px 1px rgb(255 61 242 / 75%);
}
.deck-aura .deck-aura-treble {
  inset: 3px;
  box-shadow: inset 0 0 0 1px #5ff3ff, inset 0 0 12px rgb(95 243 255 / 60%), 0 0 8px rgb(95 243 255 / 80%);
}
.retro-deck.is-dancing .deck-aura-mid { opacity: calc((var(--fx-mid) - 1) * 4 * (var(--fx-mid) - 1) * 4); }
.retro-deck.is-dancing .deck-aura-treble { opacity: calc((var(--fx-treble) - 1) * 4 * (var(--fx-treble) - 1) * 4); }

/* Y2K Fruit-Pod Capsule: the whole capsule thumps with the bass, and its candy tint and EQ
   shift hue on the treble. The scale is kept small so it never pokes out of the card. */
.retro-deck[data-skin="fruit-pod"].is-dancing .deck-shell {
  transform: scale(calc(1 + (var(--fx-bass) - 1) * 0.12)); will-change: transform;
}
.retro-deck[data-skin="fruit-pod"].is-dancing .deck-screen::before,
.retro-deck[data-skin="fruit-pod"].is-dancing .deck-eq {
  filter: hue-rotate(calc((var(--fx-treble) - 1) * 160deg));
}

/* The swatches on Profile Settings: a still miniature of each skin, picked like a mascot. */
.skin-swatches { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: var(--space-3); margin-bottom: var(--space-3); }
.skin-swatch {
  position: relative; display: grid; gap: 6px; align-content: start; padding: var(--space-3); cursor: pointer;
  border: 1px solid var(--hairline); border-radius: var(--radius-sm); background: var(--surface-2);
  transition: border-color var(--ease), box-shadow var(--ease), transform var(--ease);
}
.skin-swatch:hover { transform: translateY(-2px); border-color: var(--hairline-strong); }
.skin-swatch input { position: absolute; inset: 0; z-index: 1; margin: 0; opacity: 0; cursor: pointer; }
.skin-swatch:has(input:checked) { border-color: #5ff3ff; background: rgb(95 243 255 / 12%); box-shadow: 0 0 0 1px #5ff3ff, 0 0 16px rgb(95 243 255 / 35%); }
.skin-swatch:has(input:focus-visible) { outline: 2px solid var(--neon-line); outline-offset: 2px; }
.skin-name { font-size: var(--text-sm); font-weight: 700; }
.skin-blurb { font-size: var(--text-xs); color: var(--muted); }
.skin-swatch { min-width: 0; overflow: hidden; }
/* The miniature is the real deck's layout at a smaller zoom, so a wide skin still fits its card. */
.deck-preview { display: block; pointer-events: none; zoom: 0.7; }
.deck-preview :is(.deck-shell, .deck-screen, .deck-marquee) { display: block; }
.deck-preview .deck-controls { pointer-events: none; }
.deck-preview .deck-button { min-height: 26px; }
.retro-deck.deck-preview[data-skin="sonic-wave"] .deck-controls { display: flex; }
.retro-deck.deck-preview[data-skin="cyber-goth"] .deck-shell { display: grid; }
@media (pointer: coarse) { .deck-preview .deck-button { min-height: 26px; } }

/* The deck on phones. After every skin, so these win ties with the skins' own rules, and
   without !important, so a member's CSS can still restyle the deck. Grid and flex items
   default to their content's width as a minimum, which is what pushed the Sonic Wave
   buttons and the FX labels past the glass card: every track here may shrink to zero,
   and the parts with a fixed size give that size up for the column's width. */
@media (max-width: 768px) {
  .music-player.retro-deck { width: 100%; max-width: 100%; min-width: 0; box-sizing: border-box; }
  .retro-deck :is(.deck-shell, .deck-screen, .deck-readout, .deck-marquee, .deck-video, .deck-fx, .deck-fx-inner) { min-width: 0; max-width: 100%; }
  .retro-deck .deck-readout > * { min-width: 0; }
  .retro-deck .deck-state { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .retro-deck .deck-controls { grid-template-columns: repeat(6, minmax(0, 1fr)); gap: 4px; }
  .retro-deck .deck-button { min-width: 0; }
  .retro-deck .deck-button svg { max-width: 100%; height: auto; }
  .retro-deck .deck-fx-canvas { max-width: 100%; }
  .retro-deck .deck-fx-presets { grid-template-columns: repeat(auto-fit, minmax(52px, 1fr)); }
  .retro-deck :is(.deck-fx-preset, .deck-fx-project) { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .retro-deck .deck-video iframe { max-width: 100%; }

  /* Sonic Wave: a narrower pod, its wings tucked inside the card, and round buttons that
     share the row instead of holding 44px each. */
  .retro-deck[data-skin="sonic-wave"] .deck-shell { padding: 14px 12px 16px; }
  .retro-deck[data-skin="sonic-wave"] .deck-shell::after { left: 0; right: 0; }
  .retro-deck[data-skin="sonic-wave"] .deck-screen { padding: 6px 12px; }
  .retro-deck[data-skin="sonic-wave"] .deck-controls { flex-wrap: nowrap; gap: 6px; }
  .retro-deck[data-skin="sonic-wave"]:not(.deck-preview) .deck-controls .deck-button {
    flex: 1 1 0; width: auto; max-width: 44px; height: auto; min-height: 0; aspect-ratio: 1;
  }
  .retro-deck[data-skin="sonic-wave"]:not(.deck-preview) .deck-controls .deck-button[data-deck-action="play"] { flex-grow: 1.25; max-width: 52px; }
  .retro-deck[data-skin="sonic-wave"] .deck-fx-canvas { width: min(156px, 100%); height: auto; aspect-ratio: 1; }

  .retro-deck[data-skin="cyber-goth"] .deck-shell { padding: 8px 10px; }
  .retro-deck[data-skin="cyber-goth"] .deck-readout { grid-template-columns: auto auto minmax(0, 1fr) auto; gap: 6px; }
  .retro-deck[data-skin="cyber-goth"] .deck-count { font-size: clamp(15px, 5vw, 20px); }
  .retro-deck[data-skin="fruit-pod"] .deck-shell { padding: 12px 10px 14px; }
  .retro-deck[data-skin="fruit-pod"] .deck-controls { gap: 5px; }
}

/* ---------- signup's 18+ and Terms box ---------- */
.terms-check { display: flex; align-items: flex-start; gap: var(--space-2); font-weight: 500; }
.terms-check input { flex: none; width: 18px; height: 18px; margin-top: 2px; accent-color: #00ffcc; }

/* ---------- /terms, see src/routes/legal.js ----------
   The boxes already get the site's holographic glass. This adds the readable column, the
   glowing heading and the 18+ callout. */
.legal { max-width: 820px; margin-inline: auto; }
.legal-hero { margin: 0 0 var(--space-4); text-align: center; }
.legal-hero h1 {
  margin: 0; font-size: clamp(24px, 5vw, 34px); color: #ffffff; letter-spacing: -.02em;
  text-shadow: -1px 0 #ff2bd6, 1px 0 #00ffcc, 0 0 12px rgb(95 243 255 / 50%);
}
.legal-hero p { margin: var(--space-2) 0 0; color: var(--muted); }
.legal-toc ol { margin: 0; padding-left: var(--space-5); columns: 2 220px; }
.legal-toc li { margin-bottom: var(--space-1); }
.legal .box-body h3 { margin: var(--space-4) 0 var(--space-2); font-size: var(--text-md); color: #5ff3ff; }
.legal .box-body h3:first-child { margin-top: 0; }
.legal .box-body li { margin-bottom: var(--space-1); }
.legal-adult {
  padding: var(--space-3) var(--space-4); border: 1px solid rgb(255 43 214 / 55%); border-radius: var(--radius-md);
  background: rgb(255 43 214 / 10%); box-shadow: 0 0 14px rgb(255 43 214 / 25%);
}
.legal-adult strong { color: #ffffff; }

/* ---------- footer legal links ---------- */
.footer-links { display: flex; flex-wrap: wrap; justify-content: center; gap: var(--space-1) var(--space-4); margin-top: var(--space-2); }
.footer-links a { color: var(--muted); text-decoration: none; padding: 4px 2px; border-radius: 4px; transition: color var(--ease), text-shadow var(--ease); }
.footer-links a:hover, .footer-links a:focus-visible { color: var(--neon-line); text-shadow: 0 0 8px rgba(41, 243, 255, 0.7); }
.footer-links a:focus-visible { outline: 2px solid var(--neon-line); outline-offset: 2px; }

/* ---------- password reset ----------
   The glass card from Profile Settings, centered on its own. */
.reset-card { max-width: 440px; margin: var(--space-6, 32px) auto; }
.reset-card .box-title { text-align: center; }

/* ---------- theme marketplace ----------
   Cards are the Profile Settings glass cards. A theme's own CSS never loads on /themes:
   it only runs on /themes/:id, inside .profile-guard, the same clipped, isolated canvas as
   a real profile, and every rule in it is scoped to #profile by sanitizeCss. */
.theme-market { max-width: 1100px; margin: 0 auto; }
.theme-market-box { padding-bottom: var(--space-2); }
.theme-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); gap: var(--space-4); margin-block: var(--space-4); }
.theme-card { display: flex; flex-direction: column; overflow: hidden; min-width: 0; }
.theme-card-preview { display: block; position: relative; aspect-ratio: 16 / 9; color: #ffffff; text-decoration: none; overflow: hidden; }
.theme-card-swatch { position: absolute; inset: 0; background: linear-gradient(135deg, #00ffcc, #9b51e0 50%, #ff0055); opacity: .75; }
.theme-card:nth-child(3n+2) .theme-card-swatch { background: linear-gradient(135deg, #ffcc00, #ff0055 55%, #1b1464); }
.theme-card:nth-child(3n) .theme-card-swatch { background: linear-gradient(135deg, #00c6ff, #0072ff 50%, #1b1b2f); }
.theme-card-preview h3 { position: absolute; left: var(--space-3); right: var(--space-3); bottom: var(--space-3); margin: 0; font-size: var(--text-lg, 18px); text-shadow: 0 1px 4px #000000; overflow-wrap: anywhere; }
.theme-card-preview:hover .theme-card-swatch, .theme-card-preview:focus-visible .theme-card-swatch { opacity: 1; }
.theme-card-info { padding: var(--space-3); display: flex; flex-direction: column; gap: var(--space-2); flex: 1; }
.theme-card-info p { margin: 0; overflow-wrap: anywhere; }
.theme-card-info .byline { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: var(--text-sm, 13px); }
.theme-card-info .byline img { border-radius: 50%; object-fit: cover; }
.theme-card-actions { display: flex; flex-wrap: wrap; gap: var(--space-2); align-items: center; margin-top: auto; }
.theme-preview-bar { max-width: 880px; margin: var(--space-4) auto; padding: var(--space-3) var(--space-4); display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; justify-content: space-between; }
.theme-preview-guard { border-radius: var(--radius-md); }
.theme-publish-css { max-height: 220px; overflow: auto; white-space: pre-wrap; overflow-wrap: anywhere; font-size: 12px; }

/* ---------- theme gallery ----------
   /themes: a glass timeline, newest first, one glowing rail down the left with a marker per
   month and a matrix of cards under each. A thumbnail's backdrop is set by public/js/theme-gallery.js
   from a shielded value (see thumbnailBackground in src/theme-library.js); the gradient here is
   what shows before that, or with no script. A theme's own CSS never loads on this page: the
   live preview over it is a sandboxed frame of /themes/:id/thumb. */
.theme-gallery { max-width: 980px; margin: 0 auto; }
.theme-gallery-box { padding-bottom: var(--space-2); }
.gallery-timeline { position: relative; margin-block: var(--space-4); padding-left: 28px; }
.gallery-timeline::before { content: ""; position: absolute; left: 9px; top: 6px; bottom: 6px; width: 2px; border-radius: 2px;
  background: linear-gradient(180deg, #5ff3ff, #b14dff 50%, #ff2bd6); box-shadow: 0 0 10px rgb(95 243 255 / 45%); }
.gallery-month + .gallery-month { margin-top: var(--space-4); }
.gallery-month-label { position: relative; margin: 0 0 var(--space-3); font-size: var(--text-sm, 13px); letter-spacing: 0.12em; text-transform: uppercase; color: var(--ink-2); }
.gallery-month-label span { display: inline-block; padding: 3px 12px; border-radius: 999px; background: var(--surface); border: 1px solid var(--hairline-strong);
  -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); }
.gallery-month-label::before { content: ""; position: absolute; left: -24px; top: 50%; width: 12px; height: 12px; margin-top: -6px; border-radius: 50%;
  background: #0a0c1e; border: 2px solid #5ff3ff; box-shadow: 0 0 10px #5ff3ff; }
.gallery-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--space-4); grid-template-columns: repeat(auto-fill, minmax(min(100%, 260px), 1fr)); }
.gallery-item { position: relative; min-width: 0; display: flex; }
.gallery-dot { display: none; }
.gallery-card { display: flex; flex-direction: column; flex: 1; overflow: hidden; min-width: 0;
  background: linear-gradient(135deg, rgb(255 255 255 / 9%), rgb(255 255 255 / 3%)); border: 1px solid var(--hairline-strong);
  -webkit-backdrop-filter: blur(16px) saturate(140%); backdrop-filter: blur(16px) saturate(140%); box-shadow: 0 12px 32px rgb(0 0 0 / 30%), inset 0 1px 0 rgb(255 255 255 / 12%);
  transition: transform .2s ease, box-shadow .2s ease; }
.gallery-card:hover { transform: translateY(-2px); box-shadow: 0 16px 40px rgb(0 0 0 / 38%), 0 0 24px rgb(95 243 255 / 14%), inset 0 1px 0 rgb(255 255 255 / 16%); }
/* The preview box bounds everything in it: the static backdrop, then the live frame, which
   public/js/theme-gallery.js scales from its 1000px sample width down to the box. */
.gallery-preview { display: block; position: relative; aspect-ratio: 16 / 9; overflow: hidden; contain: strict; isolation: isolate;
  border-bottom: 1px solid var(--hairline-strong); }
.gallery-thumb, .saved-thumb { position: absolute; inset: 0; display: block; background: linear-gradient(135deg, #00ffcc, #9b51e0 50%, #ff0055); }
.gallery-thumb-empty, .saved-thumb-empty { opacity: .6; }
.gallery-live { position: absolute; left: 0; top: 0; width: 1000px; height: 563px; border: 0; pointer-events: none; transform-origin: 0 0;
  transform: scale(.28); opacity: 0; transition: opacity .5s ease; background: transparent; }
.gallery-live.is-loaded { opacity: 1; }
.theme-thumb-doc, .theme-thumb-body { margin: 0; overflow: hidden; height: 100%; background: #0a0c1e; }
.theme-thumb-body .theme-preview-guard { min-height: 100%; border-radius: 0; }
.gallery-info { padding: var(--space-3) var(--space-4); display: flex; flex-direction: column; gap: var(--space-2); min-width: 0; flex: 1; }
.gallery-info h3 { margin: 0; font-size: var(--text-lg, 18px); overflow-wrap: anywhere; }
.gallery-info h3 a { color: var(--ink); text-decoration: none; }
.gallery-info h3 a:hover { color: var(--link-hover); }
.gallery-info p { margin: 0; overflow-wrap: anywhere; }
.gallery-info .byline { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; font-size: var(--text-sm, 13px); color: var(--muted); }
.gallery-info .byline img { border-radius: 50%; object-fit: cover; }
.gallery-handle { color: var(--ink-2); }
.gallery-like { display: inline-flex; align-items: center; gap: 6px; font-variant-numeric: tabular-nums; }
.gallery-like[aria-pressed="true"] { border-color: #ff2bd6; box-shadow: 0 0 12px rgb(255 43 214 / 35%); }
.gallery-heart { color: #ff4fd8; font-size: 1.1em; line-height: 1; }
.gallery-likes { display: inline-flex; align-items: center; gap: 4px; color: var(--muted); font-size: var(--text-sm, 13px); }
/* Use Theme: the page fades out on its way to the member's profile. */
body.theme-leaving .site-main { opacity: 0; transform: scale(.985); transition: opacity .45s ease, transform .45s ease; }
@media (prefers-reduced-motion: reduce) { body.theme-leaving .site-main { transition: none; } .gallery-live { transition: none; } }

/* ---------- my saved themes ----------
   /edit/themes: the saved list beside an interactive sample profile. The sample is a real
   .profile-guard, so the theme stylesheet public/js/saved-themes.js swaps in stays clipped
   and isolated exactly as it would be on a profile. */
.saved-themes { max-width: 1180px; margin: 0 auto var(--space-5, 32px); padding-inline: 16px; display: grid; grid-template-columns: minmax(0, 340px) minmax(0, 1fr); gap: var(--space-4); align-items: start; }
.saved-theme-list { list-style: none; margin: var(--space-3) 0 0; padding: 0; display: grid; gap: var(--space-2); max-height: 70vh; overflow: auto; }
.saved-theme-row { display: flex; align-items: center; gap: var(--space-2); min-width: 0; }
.saved-theme-item { flex: 1; min-width: 0; display: flex; align-items: center; gap: var(--space-3); padding: 6px; border-radius: var(--radius-md, 10px);
  border: 1px solid var(--hairline); background: var(--surface-2); color: var(--ink); text-decoration: none; }
.saved-theme-item:hover { background: var(--hover); }
.saved-theme-item[aria-current="true"] { border-color: #5ff3ff; box-shadow: 0 0 0 1px #5ff3ff, 0 0 14px rgb(95 243 255 / 30%); }
.saved-theme-item .saved-thumb { position: relative; inset: auto; flex: none; width: 64px; height: 40px; border-radius: 6px; box-shadow: inset 0 0 0 1px rgb(255 255 255 / 20%); }
.saved-theme-text { display: flex; flex-direction: column; min-width: 0; }
.saved-theme-text strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.saved-liked { color: #ff4fd8; }
.saved-themes-stage { padding: var(--space-3); min-width: 0; overflow: hidden; }
.saved-stage-bar { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: center; justify-content: space-between; margin-bottom: var(--space-3); }
.saved-themes-stage .theme-preview-guard { max-height: 760px; }
@media (max-width: 900px) { .saved-themes { grid-template-columns: minmax(0, 1fr); } .saved-theme-list { max-height: none; } }

/* ---------- upvotes and downvotes ----------
   The arrows beside each Home post, group Discussion post and wall post, see src/votes.js.
   A vote you've cast glows: neon mint up, neon magenta down. aria-pressed is the state, so
   the look and what a screen reader hears can't disagree. On a profile these are plain
   rules under #profile, so a member's own CSS restyles them like any other panel. */
.vote {
  display: flex; flex: none; flex-direction: column; align-items: center; gap: 2px;
  min-width: 34px; margin: 0; padding: 2px 0;
  font-family: "Courier New", Courier, monospace; line-height: 1;
}
.thread-row > .vote { flex: none; }
.vote-up, .vote-down {
  display: grid; place-items: center; width: 28px; height: 22px; padding: 0;
  font: 700 13px/1 "Courier New", Courier, monospace; color: var(--muted); text-decoration: none;
  background: rgb(255 255 255 / 4%); border: 1px solid var(--hairline); border-radius: 4px;
  cursor: pointer; transition: color var(--ease), border-color var(--ease), box-shadow var(--ease), text-shadow var(--ease), background var(--ease);
}
.vote-up:hover, .vote-up:focus-visible { color: #00ffcc; border-color: rgb(0 255 204 / 55%); }
.vote-down:hover, .vote-down:focus-visible { color: #ff2bd6; border-color: rgb(255 43 214 / 55%); }
.vote-up:focus-visible, .vote-down:focus-visible { outline: 2px solid var(--link-hover); outline-offset: 1px; }
.vote-up[aria-pressed="true"] {
  color: #00ffcc; background: rgb(0 255 204 / 12%); border-color: #00ffcc;
  text-shadow: 0 0 4px #00ffcc, 0 0 10px #00ffcc; box-shadow: 0 0 8px rgb(0 255 204 / 55%), inset 0 0 6px rgb(0 255 204 / 30%);
}
.vote-down[aria-pressed="true"] {
  color: #ff2bd6; background: rgb(255 43 214 / 12%); border-color: #ff2bd6;
  text-shadow: 0 0 4px #ff2bd6, 0 0 10px #ff2bd6; box-shadow: 0 0 8px rgb(255 43 214 / 55%), inset 0 0 6px rgb(255 43 214 / 30%);
}
.vote-score { min-width: 2ch; font-size: 13px; font-weight: 700; text-align: center; color: var(--ink); font-variant-numeric: tabular-nums; }
.vote[data-mine="1"] .vote-score { color: #00ffcc; text-shadow: 0 0 6px rgb(0 255 204 / 70%); }
.vote[data-mine="-1"] .vote-score { color: #ff2bd6; text-shadow: 0 0 6px rgb(255 43 214 / 70%); }
.vote[aria-busy="true"] { opacity: 0.75; }
/* On a wall post the arrows sit across from the date, so the post keeps its full width. */
.comment-body > .vote { float: right; flex-direction: row; margin: 0 0 4px 8px; }

/* ---------- public board games on walls (src/routes/comment-games.js) ----------
   A challenge card replaces a wall comment's text. It brings its own dark glass so it
   reads on any profile theme, and only blurs on .profile-glass (see the rule above about
   backdrop-filter on profiles). Everything is sized to the comment cell: the canvases
   scale down with the card and never push the table wider. */
.comment-form-foot { display: flex; align-items: center; gap: 8px; }
.cg-picker { position: relative; }
.cg-picker-toggle {
  display: inline-flex; align-items: center; justify-content: center; width: 36px; height: 32px;
  list-style: none; cursor: pointer; font-size: 18px; border-radius: 10px;
  border: 1px solid rgb(255 113 206 / 55%); background: rgb(255 113 206 / 14%);
  box-shadow: 0 0 8px rgb(255 113 206 / 30%), inset 0 1px 0 rgb(255 255 255 / 25%);
}
.cg-picker-toggle::-webkit-details-marker { display: none; }
.cg-picker[open] .cg-picker-toggle { background: rgb(255 113 206 / 32%); }
.cg-picker-menu {
  position: absolute; z-index: 20; bottom: calc(100% + 6px); left: 0; display: grid; gap: 6px;
  width: max-content; max-width: min(260px, 80vw); padding: 10px; border-radius: 14px; color: #f4f1ff;
  border: 1px solid rgb(255 255 255 / 28%);
  background: linear-gradient(135deg, rgb(95 243 255 / 20%), rgb(255 43 214 / 20%)), rgb(12 14 40 / 82%);
  box-shadow: 0 8px 28px rgb(0 0 0 / 35%), 0 0 14px rgb(95 243 255 / 20%);
  -webkit-backdrop-filter: blur(14px) saturate(150%); backdrop-filter: blur(14px) saturate(150%);
}
.cg-picker-title { margin: 0; font-size: 11px; letter-spacing: .08em; text-transform: uppercase; color: #9ff7ff; }
.cg-picker-option {
  display: flex; align-items: center; gap: 8px; min-height: 40px; padding: 6px 12px; cursor: pointer;
  font: inherit; font-weight: 700; text-align: left; color: inherit;
  border: 1px solid rgb(255 255 255 / 24%); border-radius: 10px; background: rgb(255 255 255 / 9%);
}
.cg-picker-option:hover, .cg-picker-option:focus-visible { background: rgb(255 255 255 / 20%); outline: 0; box-shadow: 0 0 0 2px rgb(95 243 255 / 60%); }

.cg-card {
  display: grid; gap: 8px; max-width: 100%; min-width: 0; box-sizing: border-box; overflow: hidden;
  padding: 10px; border-radius: 14px; color: #f4f1ff;
  border: 1px solid rgb(95 243 255 / 40%);
  background: linear-gradient(135deg, rgb(95 243 255 / 16%), rgb(255 43 214 / 16%)), rgb(12 14 40 / 68%);
  box-shadow: 0 0 14px rgb(95 243 255 / 18%), inset 0 1px 0 rgb(255 255 255 / 14%);
}
.profile-glass .cg-card { -webkit-backdrop-filter: blur(14px) saturate(160%); backdrop-filter: blur(14px) saturate(160%); }
.cg-head { display: flex; gap: 8px; align-items: center; min-width: 0; }
.cg-icon { font-size: 24px; flex: none; }
.cg-heading { min-width: 0; }
.cg-title { margin: 0; font-size: 12px; letter-spacing: .06em; text-transform: uppercase; color: #9ff7ff; text-shadow: 0 0 6px rgb(95 243 255 / 60%); }
.cg-line { margin: 2px 0 0; font-weight: 700; overflow-wrap: anywhere; }
.cg-card[data-cg-your-turn="true"] { border-color: rgb(125 255 90 / 70%); box-shadow: 0 0 16px rgb(125 255 90 / 28%); }
.cg-card[data-cg-your-turn="true"] .cg-line { color: #9dff7d; }
.cg-stage { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; min-width: 0; }
.cg-stage:empty { display: none; }
.cg-grid { display: grid; gap: 4px; flex: 1 1 200px; max-width: 300px; min-width: 0; margin: 0; text-align: center; }
.cg-grid.is-c4 { flex-basis: 260px; max-width: 320px; }
.cg-grid figcaption { font-size: 11px; color: #cfd6ff; overflow-wrap: anywhere; }
.cg-canvas { display: block; width: 100%; height: auto; touch-action: manipulation; border-radius: 10px; }
.cg-canvas.is-live { cursor: pointer; }
.cg-tools { display: flex; flex-wrap: wrap; gap: 6px; justify-content: center; flex-basis: 100%; }
.cg-ships { display: flex; flex-wrap: wrap; gap: 4px; justify-content: center; flex-basis: 100%; }
.cg-ship { padding: 3px 8px; font: inherit; font-size: 11px; color: inherit; cursor: pointer; border: 1px solid rgb(255 255 255 / 24%); border-radius: 999px; background: rgb(255 255 255 / 8%); }
.cg-ship.is-placed { opacity: .55; text-decoration: line-through; }
.cg-ship.is-selected { border-color: #5ff3ff; box-shadow: 0 0 8px rgb(95 243 255 / 55%); }
.cg-note { margin: 0; font-size: 12px; color: #ffd27a; }
.cg-actions { display: flex; flex-wrap: wrap; gap: 6px; align-items: center; }
.cg-actions:empty { display: none; }
.cg-actions .inline-form { display: inline; margin: 0; }
.cg-btn {
  min-height: 34px; padding: 4px 14px; cursor: pointer; font: inherit; font-size: 13px; font-weight: 700; color: inherit;
  border: 1px solid rgb(255 255 255 / 26%); border-radius: 999px; background: rgb(255 255 255 / 10%);
}
.cg-btn:hover { background: rgb(255 255 255 / 20%); }
.cg-btn:disabled { opacity: .5; cursor: default; }
.cg-btn.is-primary { color: #0b0d22; border-color: transparent; background: linear-gradient(135deg, #5ff3ff, #ff71ce); box-shadow: 0 0 10px rgb(255 113 206 / 40%); }
@media (max-width: 600px) {
  .cg-grid, .cg-grid.is-c4 { flex-basis: 100%; max-width: 100%; }
}

/* ---------- stock theme layouts ----------
   The three layout styles of the presets in src/themes.js. src/routes/profile.js puts
   profile-layout-<layout> on .profile-guard for a page running one, and member CSS can't
   reach the guard or set grid columns, so only these rules decide the columns. They change
   grid tracks and alignment only: .profile-inner stays the grid and .profile-left stays
   put, as the locked controls below require. Wide screens only; a phone keeps the one
   column from the small-screen rules. No !important: the guard's two extra classes win. */
@media (min-width: 769px) {
  /* Classic Mid-2000s Split: two equal columns. */
  .profile-guard.profile-layout-split .profile-inner { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  /* Stacked Modular Canvas: one centered column of windows, every one the same width and
     lined up on the same edges. The halves used to be 90% wide and pushed to opposite
     sides, under panels nudged by percentage margins, so no two edges met and the stack
     looked skewed. The margins are gone from STACKED_LAYOUT in src/themes.js. */
  .profile-guard.profile-layout-stacked .profile-inner { grid-template-columns: minmax(0, 1fr); }
  .profile-guard.profile-layout-stacked :is(.profile-left, .profile-right) { width: 100%; max-width: 780px; justify-self: center; }
  /* Borderless Immersive Matrix: a rail and a broad column. */
  .profile-guard.profile-layout-matrix .profile-inner { grid-template-columns: minmax(260px, 1fr) minmax(0, 2.4fr); }
}

/* ---------- locked controls ----------
   A profile must not be able to disguise, stretch or hide the buttons a visitor
   acts on. Every declaration here is !important, and that only holds because
   sanitizeCss strips !important from all user CSS and caps z-index at 999. Without
   that, #profile out-specifies these rules. See test/sanitize.test.js.
   Locking only the button is not enough: opacity, transform and filter on any
   ancestor apply to it as a group and can't be undone from the child, and an
   ancestor that forms a stacking context traps its z-index. So the whole chain up
   to #profile is covered here. Put new action buttons inside .profile-actions.
   User HTML may carry any class, so selectors for .profile-actions go through
   `.profile-left >`: sanitized markup always sits inside a wrapper and can never be
   a direct child, so a blurb can't borrow this block's z-index for a forged menu.
   Known limit: content earlier in the left column can still push .profile-actions
   down, or pull it up out of view with a negative margin. That can hide the
   buttons, but what is shown is still the real, correctly labelled button. This is
   why .profile-actions renders above the card and the blurbs: nothing a member wrote
   may come before it, or a long bio would bury Block under a forged look-alike. */
.profile-guard :is(.profile-left > .profile-actions a, .profile-left > .profile-actions button, .profile-left > .profile-actions summary, .link-button, .comment-form .button) {
  all: revert !important; /* opacity, transform, size, spacing, animation and the rest */
  position: relative !important;
  z-index: 1000 !important;
  pointer-events: auto !important;
  display: inline-block !important;
  justify-self: start !important; /* or `all: revert` stretches it across a grid form */
  /* `revert` leaves inherited properties open to the parent, so these are explicit. */
  visibility: visible !important;
  padding: 1px 6px !important;
  border: 1px solid var(--hairline-strong) !important;
  border-radius: 4px !important;
  background: var(--control) !important;
  color: var(--link) !important;
  -webkit-text-fill-color: currentcolor !important;
  -webkit-text-stroke: 0 !important;
  font: 400 12px/1.4 var(--font-sans) !important;
  letter-spacing: normal !important;
  word-spacing: normal !important;
  text-align: center !important;
  text-indent: 0 !important;
  text-shadow: none !important;
  text-transform: none !important;
  text-decoration: none !important;
  white-space: nowrap !important;
  writing-mode: horizontal-tb !important;
  cursor: pointer !important;
}
.profile-guard :is(.profile-left > .profile-actions a, .profile-left > .profile-actions button, .profile-left > .profile-actions summary, .link-button, .comment-form .button):hover {
  background: var(--control-hover) !important;
  text-decoration: underline !important;
}
.profile-guard :is(.profile-left > .profile-actions a, .profile-left > .profile-actions button, .profile-left > .profile-actions summary, .link-button, .comment-form .button)::before,
.profile-guard :is(.profile-left > .profile-actions a, .profile-left > .profile-actions button, .profile-left > .profile-actions summary, .link-button, .comment-form .button)::after,
.profile-guard .profile-left > .profile-actions::before,
.profile-guard .profile-left > .profile-actions::after,
.profile-guard .profile-left > .profile-actions .profile-options::before,
.profile-guard .profile-left > .profile-actions .profile-options::after,
.profile-guard .profile-left > .profile-actions .profile-options-menu::before,
.profile-guard .profile-left > .profile-actions .profile-options-menu::after {
  content: none !important;
  display: none !important;
}
.profile-guard :is(.profile-left > .profile-actions a, .profile-left > .profile-actions button, .profile-left > .profile-actions summary, .link-button, .comment-form .button)::first-letter,
.profile-guard :is(.profile-left > .profile-actions a, .profile-left > .profile-actions button, .profile-left > .profile-actions summary, .link-button, .comment-form .button)::first-line {
  all: revert !important;
}
.profile-guard .profile-left > .profile-actions,
.profile-guard .profile-left > .profile-actions :is(.inline-form, .profile-options, .profile-options-menu) { all: revert !important; }
.profile-guard .profile-left > .profile-actions {
  display: flex !important;
  flex-wrap: wrap !important;
  align-items: center !important;
  gap: 8px !important;
  margin: 0 0 10px !important;
}
.profile-guard .profile-left > .profile-actions .inline-form { display: inline !important; }
.profile-guard .profile-left > .profile-actions .profile-options { display: block !important; position: relative !important; }
.profile-guard .profile-left > .profile-actions .button {
  padding: 6px 18px !important;
  border-color: transparent !important;
  border-radius: 999px !important;
  background: var(--accent) !important;
  color: #ffffff !important;
  font: 600 13px/20px var(--font-sans) !important;
  box-shadow: var(--shadow-sm) !important;
}
.profile-guard .profile-left > .profile-actions .button:hover {
  background: var(--accent-hover) !important;
  text-decoration: none !important;
}
.profile-guard .profile-left > .profile-actions .profile-options > summary {
  padding: 6px 14px !important;
  border-radius: 999px !important;
  color: var(--ink) !important;
  font: 600 13px/20px var(--font-sans) !important;
  list-style: none !important;
  user-select: none !important;
}
.profile-guard .profile-left > .profile-actions .profile-options > summary::-webkit-details-marker { display: none !important; }
.profile-guard .profile-left > .profile-actions .profile-options > summary:hover { text-decoration: none !important; }
.profile-guard .profile-left > .profile-actions .profile-options-menu {
  display: block !important;
  position: absolute !important;
  top: calc(100% + 6px) !important;
  left: 0 !important;
  z-index: 1001 !important;
  box-sizing: border-box !important;
  width: 200px !important;
  padding: 4px !important;
  border: 1px solid var(--hairline-strong) !important;
  border-radius: 12px !important;
  background: var(--control) !important;
  box-shadow: var(--shadow-md) !important;
}
.profile-guard .profile-left > .profile-actions .profile-options-menu :is(a, button) {
  display: block !important;
  box-sizing: border-box !important;
  width: 100% !important;
  padding: 6px 10px !important;
  border: 0 !important;
  border-radius: 8px !important;
  background: transparent !important;
  color: var(--ink) !important;
  font: 400 13px/20px var(--font-sans) !important;
  text-align: left !important;
}
.profile-guard .profile-left > .profile-actions .profile-options-menu :is(a, button):hover {
  background: var(--control-hover) !important;
  text-decoration: none !important;
}
.profile-guard .profile-left > .profile-actions .profile-options-menu .danger { color: var(--danger) !important; }
.profile-guard .profile-left > .profile-actions .profile-options-menu button:disabled {
  background: transparent !important;
  color: var(--muted) !important;
  cursor: not-allowed !important;
}
.profile-guard :is(#profile, .profile-inner, .profile-left) {
  position: static !important;
  z-index: auto !important;
  visibility: visible !important;
  opacity: 1 !important;
  overflow: visible !important;
  transform: none !important;
  translate: none !important;
  rotate: none !important;
  scale: none !important;
  transform-style: flat !important;
  perspective: none !important;
  filter: none !important;
  backdrop-filter: none !important;
  -webkit-backdrop-filter: none !important;
  mix-blend-mode: normal !important;
  isolation: auto !important;
  clip-path: none !important;
  mask: none !important;
  -webkit-mask: none !important;
}
.profile-guard #profile { display: block !important; margin: 0 !important; }
.profile-guard .profile-inner { display: grid !important; margin: 0 auto !important; }
.profile-guard .profile-left { display: block !important; float: none !important; margin: 0 !important; }
