/* Atlas core — tokens and primitives shared by every page on the design
   system. Load this first, then the page's own sheet, which may override.

   The language: the artwork is the atmosphere, and everything factual is an
   instrument. Each page derives its accent from its own imagery via
   atlas-palette.js; this file only supplies the fallback and the plumbing.

   Naming, because these two collided during extraction:
     .am-select       compact inline select (toolbars, filter rows)
     .am-select-full  full-width form select (dialogs, forms)
*/

/* ---------------------------------------------------------------- tokens */
:root {
  --am-void: #06080b;
  --am-ink: #f3f4f6;
  --am-ink-2: #a9b1bc;
  --am-ink-3: #6b7480;

  --am-line: rgba(255, 255, 255, .10);
  --am-line-soft: rgba(255, 255, 255, .055);
  --am-panel: rgba(255, 255, 255, .028);
  --am-panel-2: rgba(255, 255, 255, .055);

  /* Replaced at runtime by atlas-palette.js from the page's own artwork. */
  --am-accent: #6fd0f2;
  --am-accent-ink: #04121a;
  --am-glow: 111, 208, 242;

  --am-paid: #e8bd5c;
  --am-danger: #f4788c;

  --am-display: "Space Grotesk", Inter, system-ui, sans-serif;
  --am-body: Inter, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --am-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, monospace;

  --am-r: 4px;
  --am-shell: 88rem;
  --am-ease: cubic-bezier(.2, .7, .2, 1);
}

/* ==========================================================================
   DO NOT REMOVE.

   Tailwind emits its utilities inside `@layer utilities`. These stylesheets
   are unlayered, and unlayered rules beat layered ones regardless of
   specificity — so every component rule here outranks every Tailwind utility.

   The page JS gates all role-based UI with the `.hidden` class: owner-only and
   admin-only menu items, the comment composer button, the creator-ownership
   panel. Any component rule that sets `display` silently defeats that gating
   and leaks those controls to every visitor.

   Repeated in every atlas-*.css on purpose — the guard test asserts per file,
   so the invariant cannot be lost if a page loads sheets in another order.
   Guarded by tests/smoke/design-system-hidden-guard.test.mjs (`npm run verify`).
   ========================================================================== */
[hidden],
.hidden { display: none !important; }

/* ----------------------------------------------------------------- canvas */
html { background: var(--am-void); }

body.am {
  position: relative;
  font-family: var(--am-body);
  /* Must stay transparent. body creates no stacking context, so its background
     would paint *after* the negative-z ambient layers and hide them. The void
     colour lives on html and propagates to the canvas. */
  background: transparent;
  color: var(--am-ink);
  -webkit-font-smoothing: antialiased;

  /* Alpha for accent-tinted surfaces, scaled by the page's floor so the single
     --am-floor dial turns the whole treatment on or off. Declared here rather
     than on :root because custom properties resolve against the element that
     declares them: at :root, --am-floor is always its 0 fallback. */
  --am-tint: calc(.055 * var(--am-floor, 0));
}

/* Structure only. Each page sets its own height, focal point and veil, since
   how far the atmosphere reaches is a per-page decision.

   Below the floor (-2), not above it. This layer is opaque where it ends — the
   veil resolves to solid --am-void so the blurred artwork's hard bottom cut
   never shows — and it is absolute, so at the top of the page it covers only
   the first 46-92vh depending on the page. Painted over the floor it therefore
   masked the floor down to its own bottom edge and released it below, drawing
   a hard horizontal line across the viewport at exactly that height: on the
   home page, a seam at 648px of a 900px window. Scrolling carried the ambient
   away and the line vanished, which is why it only appeared near the top. */
.am-ambient {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  z-index: -3;
  pointer-events: none;
  overflow: hidden;
}

.am-ambient__img {
  position: absolute;
  /* Over-inset so the blur never shows a soft edge against the viewport. */
  inset: -18%;
  background-image: var(--am-art, none);
  background-size: cover;
  transform: scale(1.15);
  opacity: 0;
  transition: opacity .9s var(--am-ease);
}
.am-ambient.is-lit .am-ambient__img { opacity: 1; }

.am-ambient__veil { position: absolute; inset: 0; }

/* The blurred artwork is one source of atmosphere; the accent is the other.
   ::after rather than ::before, because the veil is a child and its whole job
   is to darken what sits beneath it — a wash underneath would be veiled along
   with the image. This lays the page's colour over the finished plate. */
.am-ambient::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  opacity: var(--am-floor, 0);
  background: radial-gradient(92% 78% at 50% -8%, rgba(var(--am-glow), .22), transparent 72%);
}

.am-grain {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
  opacity: .32;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)' opacity='.42'/%3E%3C/svg%3E");
}

/* ------------------------------------------------------------------ floor */
/* The ambient above is absolute, top-anchored and finite: on a creator page it
   covers 46vh of a 3500px document — about a tenth of it — and then scrolls
   away, which is why long pages read as coloured at the top and black
   everywhere after.

   This is the other half. Fixed, so it stays with the viewport for the whole
   scroll and its strength does not depend on how long the page happens to be:
   a creator with 200 mods gets the same atmosphere as one with 8, where a
   gradient stretched over the document would give them different ones. Light
   pools in the corners and the middle stays clear, so card artwork keeps its
   contrast against the canvas.

   Sits ABOVE the ambient (-3) and below the grain (-1), so the noise textures
   it and nothing masks it. The order matters: the ambient is opaque where it
   ends, so with the floor beneath it the two layers met in a hard line at the
   ambient's bottom edge — see the note there. A fixed layer only reads as
   atmosphere while nothing interrupts it.

   Off unless a page opts in with --am-floor, which is also the dial: set it to
   0 to take that page back to bare canvas. */
body.am::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  pointer-events: none;
  opacity: var(--am-floor, 0);
  background:
    radial-gradient(72% 56% at 4% 100%, rgba(var(--am-glow), .13), transparent 70%),
    radial-gradient(60% 46% at 97% 88%, rgba(var(--am-glow), .09), transparent 68%),
    radial-gradient(52% 40% at 100% 0%, rgba(var(--am-glow), .06), transparent 70%);
}

::selection { background: rgba(var(--am-glow), .26); color: var(--am-ink); }

.am-shell {
  width: min(100%, var(--am-shell));
  margin-inline: auto;
  padding-inline: 1.15rem;
}
@media (min-width: 48rem) { .am-shell { padding-inline: 2rem; } }

/* ------------------------------------------------------------- typography */
.brand { font-family: var(--am-display); letter-spacing: -.02em; }

.am-mono,
.am-eyebrow {
  font-family: var(--am-mono);
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  color: var(--am-ink-3);
}

/* A label with a hairline running off to the right. */
.am-rule {
  display: flex;
  align-items: center;
  gap: .9rem;
  margin-bottom: 1.1rem;
}
.am-rule > span {
  font-family: var(--am-mono);
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--am-ink-3);
  white-space: nowrap;
}
.am-rule::after {
  content: "";
  flex: 1 1 auto;
  height: 1px;
  background: linear-gradient(90deg, var(--am-line), transparent);
}

:where(a, button, input, select, textarea):focus-visible {
  outline: 1px solid var(--am-accent);
  outline-offset: 3px;
}

/* -------------------------------------------------------------------- bar */
.am-bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 1.15rem;
}
.am-bar__side { display: flex; align-items: center; gap: .7rem; min-width: 0; }

.am-logo { height: 1.6rem; width: auto; opacity: .9; }

.am-wordmark {
  font-family: var(--am-mono);
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .26em;
  text-transform: uppercase;
  color: var(--am-ink-3);
  text-decoration: none;
  transition: color .18s var(--am-ease);
}
.am-wordmark:hover { color: var(--am-ink-2); }

.am-iconbtn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2rem;
  width: 2rem;
  flex: 0 0 auto;
  border: 1px solid var(--am-line);
  border-radius: 999px;
  background: rgba(6, 8, 11, .4);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  color: var(--am-ink-2);
  transition: color .18s var(--am-ease), border-color .18s var(--am-ease);
}
.am-iconbtn:hover { color: var(--am-ink); border-color: rgba(255, 255, 255, .22); }
.am-iconbtn svg { height: 1rem; width: 1rem; }

/* ---------------------------------------------------------------- buttons */
.am-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .4rem;
  height: 2.2rem;
  padding-inline: .8rem;
  border: 1px solid var(--am-line);
  border-radius: var(--am-r);
  background: var(--am-panel);
  color: var(--am-ink-2);
  font-family: var(--am-mono);
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  white-space: nowrap;
  cursor: pointer;
  transition: color .18s var(--am-ease), border-color .18s var(--am-ease), background .18s var(--am-ease);
}
.am-btn:hover { color: var(--am-ink); border-color: rgba(255, 255, 255, .24); background: var(--am-panel-2); }
.am-btn:disabled { opacity: .4; cursor: not-allowed; }
.am-btn svg { width: 14px; height: 14px; }

.am-btn--accent {
  border-color: rgba(var(--am-glow), .45);
  background: rgba(var(--am-glow), .12);
  color: var(--am-ink);
}
.am-btn--accent:hover { border-color: rgba(var(--am-glow), .7); background: rgba(var(--am-glow), .2); }

.am-btn--solid {
  border-color: var(--am-accent);
  background: var(--am-accent);
  color: var(--am-accent-ink);
}
.am-btn--solid:hover { filter: brightness(1.1); background: var(--am-accent); }

.am-btn--danger { border-color: rgba(244, 120, 140, .4); color: var(--am-danger); }
.am-btn--danger:hover { border-color: rgba(244, 120, 140, .7); background: rgba(244, 120, 140, .1); }

/* Still used by the submit dialog's primary button. */
.btn-primary {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.2rem;
  padding-inline: 1rem;
  border: 1px solid var(--am-accent);
  border-radius: var(--am-r);
  background: var(--am-accent);
  color: var(--am-accent-ink);
  font-family: var(--am-mono);
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  cursor: pointer;
}
.btn-primary:hover { filter: brightness(1.1); }

/* Blurple is reserved for controls that actually hand off to Discord — signing
   in on the account hub, restarting a lapsed signup. Anything that happens on
   our side keeps the Atlas accent. The mark itself is inline markup in the two
   pages that use it. */
.am-discord {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: .55rem;
  width: 100%;
  height: 2.6rem;
  border: 1px solid #5865f2;
  border-radius: var(--am-r);
  background: #5865f2;
  color: #fff;
  font-family: var(--am-mono);
  font-size: .6875rem;
  font-weight: 500;
  letter-spacing: .12em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: filter .18s var(--am-ease);
}
.am-discord:hover { filter: brightness(1.08); }
.am-discord svg { width: 18px; height: 18px; flex: 0 0 auto; }

/* ------------------------------------------------------------------ chips */
.chip {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  border: 1px solid var(--am-line);
  border-radius: 999px;
  background: var(--am-panel);
  padding: .22rem .6rem;
  font-family: var(--am-mono);
  font-size: .625rem;
  letter-spacing: .08em;
  color: var(--am-ink-2);
}
.chip.tag-chip { cursor: pointer; transition: color .18s var(--am-ease), border-color .18s var(--am-ease), background .18s var(--am-ease); }
.chip.tag-chip::before { content: "#"; opacity: .45; }
.chip.tag-chip:hover {
  color: var(--am-ink);
  border-color: rgba(var(--am-glow), .5);
  background: rgba(var(--am-glow), .1);
}

/* ---------------------------------------------------------------- spinner */
.spinner {
  width: 15px;
  height: 15px;
  border-radius: 50%;
  border: 1.5px solid rgba(255, 255, 255, .2);
  border-top-color: var(--am-ink);
  animation: am-spin .7s linear infinite;
}
@keyframes am-spin { to { transform: rotate(360deg); } }

/* ------------------------------------------------------------------ menus */
.menu-ellipsis-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 2.2rem;
  width: 2.2rem;
  flex: 0 0 auto;
  padding: 0;
  border: 1px solid var(--am-line);
  border-radius: var(--am-r);
  background: var(--am-panel);
  color: var(--am-ink-2);
  cursor: pointer;
  transition: color .18s var(--am-ease), border-color .18s var(--am-ease), background .18s var(--am-ease);
}
.menu-ellipsis-btn:hover { color: var(--am-ink); border-color: rgba(255, 255, 255, .24); background: var(--am-panel-2); }
.menu-ellipsis-icon { display: inline-flex; width: 13px; height: 13px; pointer-events: none; }

.am-menu {
  position: absolute;
  right: 0;
  top: calc(100% + .4rem);
  z-index: 40;
  min-width: 11.5rem;
  padding: .25rem;
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: var(--am-r);
  background: #0f131a;
  box-shadow: 0 24px 60px rgba(0, 0, 0, .7);
}

.am-menu__item {
  display: block;
  width: 100%;
  padding: .45rem .6rem;
  border: 0;
  border-radius: 2px;
  background: none;
  text-align: left;
  font-family: var(--am-body);
  font-size: .8125rem;
  color: var(--am-ink-2);
  text-decoration: none;
  cursor: pointer;
  transition: background .14s var(--am-ease), color .14s var(--am-ease);
}
.am-menu__item:hover { background: rgba(255, 255, 255, .06); color: var(--am-ink); }
.am-menu__item--danger { color: var(--am-danger); }
.am-menu__item--accent { color: var(--am-accent); }

/* --------------------------------------------------------------- dialogs */
dialog {
  margin: auto;
  width: 100%;
  padding: 0;
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: var(--am-r);
  background: #0d1117;
  color: var(--am-ink);
  box-shadow: 0 40px 100px rgba(0, 0, 0, .8);
}
dialog::backdrop { background: rgba(4, 6, 9, .8); backdrop-filter: blur(6px); }

.am-dialog__head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 1rem;
  padding: 1rem 1.1rem;
  border-bottom: 1px solid var(--am-line-soft);
}
.am-dialog__title {
  margin: 0;
  font-family: var(--am-display);
  font-size: 1.0625rem;
  font-weight: 600;
  letter-spacing: -.015em;
}
.am-dialog__close {
  border: 0;
  background: none;
  color: var(--am-ink-3);
  font-size: 1.1rem;
  line-height: 1;
  padding: .1rem .25rem;
  cursor: pointer;
}
.am-dialog__close:hover { color: var(--am-ink); }
.am-dialog__body { padding: 1.1rem; }

/* ------------------------------------------------------------ account gate */
/* The prompt an anonymous visitor meets when they save, like or comment.
   Built by account-entry-bootstrap.js, which every public page loads — so it
   lives here rather than in a page sheet, and it inherits whatever accent the
   page it opened over is currently wearing. */
/* The viewport term keeps it off the screen edges on a phone, where the base
   dialog width would otherwise put its border flush against them. */
.am-gate { max-width: min(25rem, calc(100vw - 2rem)); }

.am-gate__panel { position: relative; padding: 1.4rem 1.4rem 1.2rem; }

.am-gate__close {
  position: absolute;
  top: .7rem;
  right: .7rem;
  display: flex;
  align-items: center;
  justify-content: center;
  height: 1.7rem;
  width: 1.7rem;
  border: 0;
  border-radius: 999px;
  background: none;
  color: var(--am-ink-3);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  transition: color .18s var(--am-ease), background .18s var(--am-ease);
}
.am-gate__close:hover { color: var(--am-ink); background: var(--am-panel); }

.am-gate__eyebrow {
  font-family: var(--am-mono);
  font-size: .5625rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--am-accent);
}

.am-gate__title {
  margin: .5rem 0 0;
  padding-right: 1.5rem;
  font-family: var(--am-display);
  font-size: 1.25rem;
  font-weight: 700;
  line-height: 1.2;
  letter-spacing: -.02em;
  color: var(--am-ink);
}

.am-gate__body {
  margin: .5rem 0 0;
  font-size: .8125rem;
  line-height: 1.65;
  color: var(--am-ink-2);
}
.am-gate__body:empty { display: none; }

/* Why there is no password to invent. Quieter than the reason above it. */
.am-gate__note {
  margin: .45rem 0 0;
  font-size: .75rem;
  line-height: 1.6;
  color: var(--am-ink-3);
}

/* Discord's own colour, not the page accent: this button is a promise about
   where it lands, and people recognise the brand faster than any label. */
.am-gate__cta {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: .55rem;
  height: 2.7rem;
  margin-top: 1.1rem;
  border-radius: var(--am-r);
  background: #5865f2;
  color: #fff;
  font-size: .8125rem;
  font-weight: 600;
  text-decoration: none;
  transition: filter .18s var(--am-ease), transform .16s var(--am-ease);
}
.am-gate__cta:hover { filter: brightness(1.08); transform: translateY(-1px); }
.am-gate__cta svg { width: 18px; height: 18px; flex: 0 0 auto; }

/* No brand mark for a provider we have no mark for. */
.am-gate__cta--plain {
  background: var(--am-accent);
  color: var(--am-accent-ink);
}

.am-gate__alt {
  display: block;
  margin-top: .8rem;
  text-align: center;
  font-size: .75rem;
  color: var(--am-ink-3);
  text-decoration: none;
}
.am-gate__alt:hover { color: var(--am-ink-2); text-decoration: underline; }

/* ---------------------------------------------------------------- cropper */
/* The crop dialog, shared by every image a member uploads about themselves.
   The frame is fixed to the aspect the site will use and the picture moves
   behind it, so what is framed here is exactly what gets stored. */
.am-crop { max-width: 32rem; }

.am-crop__stage {
  position: relative;
  overflow: hidden;
  border: 1px solid var(--am-line);
  border-radius: var(--am-r);
  background:
    repeating-conic-gradient(rgba(255, 255, 255, .03) 0% 25%, transparent 0% 50%) 50% / 16px 16px,
    #06080b;
  cursor: grab;
  touch-action: none;
}
.am-crop__stage.is-dragging { cursor: grabbing; }

.am-crop__canvas { display: block; width: 100%; height: 100%; }

/* A hairline showing the exact edge of what will be kept, plus rule-of-thirds
   guides — enough to frame against, faint enough not to fight the picture. */
.am-crop__frame {
  position: absolute;
  inset: 0;
  pointer-events: none;
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, .28);
  background-image:
    linear-gradient(90deg, transparent calc(33.333% - 1px), rgba(255, 255, 255, .12) 33.333%, transparent calc(33.333% + 1px)),
    linear-gradient(90deg, transparent calc(66.666% - 1px), rgba(255, 255, 255, .12) 66.666%, transparent calc(66.666% + 1px)),
    linear-gradient(180deg, transparent calc(33.333% - 1px), rgba(255, 255, 255, .12) 33.333%, transparent calc(33.333% + 1px)),
    linear-gradient(180deg, transparent calc(66.666% - 1px), rgba(255, 255, 255, .12) 66.666%, transparent calc(66.666% + 1px));
}

.am-crop__hint {
  margin: .7rem 0 0;
  font-size: .6875rem;
  color: var(--am-ink-3);
}

.am-crop__zoom {
  display: flex;
  align-items: center;
  gap: .7rem;
  margin-top: .7rem;
}

.am-crop__zoom-label {
  font-family: var(--am-mono);
  font-size: .5625rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--am-ink-3);
}

.am-crop__zoom input[type="range"] {
  flex: 1 1 auto;
  min-width: 0;
  accent-color: var(--am-accent);
}

.am-crop__foot {
  display: flex;
  justify-content: flex-end;
  gap: .5rem;
  margin-top: 1.1rem;
  padding-top: .9rem;
  border-top: 1px solid var(--am-line-soft);
}

/* A quiet, reusable policy gate for creator-controlled images. The native
   checkbox keeps familiar keyboard and label behaviour; only its spacing and
   colour are brought into the Atlas form language. */
.am-sfw-confirm {
  display: inline-flex;
  align-items: flex-start;
  gap: .55rem;
  margin-top: .7rem;
  color: var(--am-ink-2);
  font-size: .75rem;
  line-height: 1.45;
  cursor: pointer;
}

.am-sfw-confirm input[type="checkbox"] {
  width: 1rem;
  height: 1rem;
  margin: .05rem 0 0;
  flex: 0 0 auto;
  accent-color: var(--am-accent);
}

.am-sfw-confirm__error {
  min-height: 1.1em;
  margin: .25rem 0 0 1.55rem;
  color: var(--am-danger);
  font-size: .6875rem;
}

.am-sfw-confirm__error:empty { display: none; }

/* ------------------------------------------------------------------ forms */
.am-field { display: block; }
.am-field > span,
.am-field > label > span,
.am-field__label {
  display: block;
  margin-bottom: .35rem;
  font-family: var(--am-mono);
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--am-ink-3);
}
.am-hint { margin-top: .35rem; font-size: .6875rem; color: var(--am-ink-3); }
.am-msg { font-size: .75rem; color: var(--am-ink-3); }

.am-update-choice {
  display: flex;
  align-items: flex-start;
  gap: .7rem;
  padding: .75rem .8rem;
  border: 1px solid var(--am-line-soft);
  border-radius: var(--am-r);
  background: rgba(255, 255, 255, .025);
  color: var(--am-ink-2);
  cursor: pointer;
}
.am-update-choice input {
  width: 1rem;
  height: 1rem;
  margin-top: .1rem;
  flex: 0 0 auto;
  accent-color: var(--am-accent);
}
.am-update-choice__copy { min-width: 0; }
.am-update-choice__copy strong {
  display: block;
  font-size: .8125rem;
  font-weight: 600;
  color: var(--am-ink);
}
.am-update-choice__copy small {
  display: block;
  margin-top: .18rem;
  font-size: .6875rem;
  line-height: 1.45;
  color: var(--am-ink-3);
}

.am-input,
.am-textarea,
.am-select-full {
  width: 100%;
  border: 1px solid var(--am-line);
  border-radius: var(--am-r);
  background: rgba(255, 255, 255, .022);
  padding: .55rem .7rem;
  font-family: inherit;
  font-size: .875rem;
  color: var(--am-ink);
  color-scheme: dark;
}
.am-input:focus,
.am-textarea:focus,
.am-select-full:focus { border-color: rgba(var(--am-glow), .45); outline: none; }
.am-textarea { resize: vertical; line-height: 1.65; }

.am-description-editor { border: 1px solid rgba(255,255,255,.12); border-radius: .65rem; overflow: hidden; background: rgba(0,0,0,.18); }
.am-description-editor .am-textarea { border: 0; border-radius: 0; display: block; width: 100%; }
.am-description-editor__toolbar { display: flex; align-items: center; justify-content: space-between; gap: .5rem; padding: .35rem .45rem; border-bottom: 1px solid rgba(255,255,255,.08); background: rgba(255,255,255,.025); }
.am-description-editor__modes, .am-description-editor__controls { display: flex; align-items: center; gap: .2rem; }
.am-description-editor__mode, .am-description-editor__tool { min-height: 1.8rem; border: 0; border-radius: .35rem; background: transparent; color: rgba(238,243,248,.62); padding: .2rem .5rem; font: inherit; font-size: .72rem; cursor: pointer; }
.am-description-editor__tool { min-width: 1.8rem; padding-inline: .4rem; font-weight: 700; }
.am-description-editor__tool--italic { font-family: Georgia, serif; font-size: .9rem; font-style: italic; }
.am-description-editor__tool--label { min-width: 2.65rem; font-weight: 600; }
.am-description-editor__mode:hover, .am-description-editor__tool:hover, .am-description-editor__mode.is-active { color: rgba(238,243,248,.96); background: rgba(255,255,255,.09); }
.am-description-editor__tool:disabled { color: rgba(238,243,248,.28); cursor: default; background: transparent; }
.am-description-editor__preview { min-height: 7rem; padding: .7rem .8rem; color: rgba(238,243,248,.86); line-height: 1.65; white-space: normal; }
.am-description-editor__preview p { margin: 0 0 .8rem; }
.am-description-editor__preview p:last-child { margin-bottom: 0; }
.am-description-editor__preview ul { margin: 0 0 .8rem; padding-left: 1.2rem; list-style: disc; }
.am-description-editor__preview a { color: #7dd3fc; text-decoration: underline; text-underline-offset: 2px; }
@media (max-width: 520px) { .am-description-editor__toolbar { flex-wrap: wrap; } .am-description-editor__controls { margin-left: auto; } }
.am-select-full option { background: #0d1117; }

input[type="file"] { font-family: inherit; font-size: .8125rem; color: var(--am-ink-3); }

/* Compact inline select, for toolbars and filter rows. */
.am-select {
  height: 2.2rem;
  min-width: 8rem;
  /* Right padding keeps the label clear of the native dropdown arrow. */
  padding: 0 1.5rem 0 .55rem;
  border: 1px solid var(--am-line);
  border-radius: var(--am-r);
  background: var(--am-panel);
  color: var(--am-ink-2);
  font-family: inherit;
  font-size: .8125rem;
  color-scheme: dark;
  cursor: pointer;
  transition: color .18s var(--am-ease), border-color .18s var(--am-ease);
}
.am-select:hover { color: var(--am-ink); border-color: rgba(255, 255, 255, .2); }
.am-select option { background: #0d1117; color: var(--am-ink); }

/* ---------------------------------------------------------- file pickers */
.file-picker-row { display: flex; flex-wrap: wrap; align-items: center; gap: .6rem; }
.file-picker-control {
  position: relative;
  display: inline-flex;
  align-items: center;
  height: 2.2rem;
  overflow: hidden;
  border: 1px solid var(--am-line);
  border-radius: var(--am-r);
  background: var(--am-panel);
}
.file-picker-control:focus-within { border-color: rgba(var(--am-glow), .45); }
.file-picker-input { position: absolute; inset: 0; width: 100%; height: 100%; opacity: 0; cursor: pointer; }
.file-picker-trigger {
  pointer-events: none;
  display: inline-flex;
  align-items: center;
  gap: .45rem;
  padding-inline: .8rem;
  font-family: var(--am-mono);
  font-size: .6875rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  color: var(--am-ink-2);
}
.file-picker-trigger svg { width: 14px; height: 14px; opacity: .7; }
.file-picker-status { font-size: .75rem; color: var(--am-ink-3); }

/* ----------------------------------------------------------------- alert */
.am-alert {
  position: relative;
  width: min(92vw, 26rem);
  padding: 1.2rem;
  border: 1px solid rgba(255, 255, 255, .14);
  border-radius: var(--am-r);
  background: #0d1117;
  box-shadow: 0 40px 100px rgba(0, 0, 0, .8);
}
.am-alert__backdrop { position: absolute; inset: 0; background: rgba(4, 6, 9, .8); backdrop-filter: blur(6px); }
.am-alert__title { margin: 0; font-family: var(--am-display); font-size: 1.05rem; font-weight: 600; }

/* ==========================================================================
   Browse surface — toolbar, search, mod card, pager.

   Extracted here (T-02) once a second page needed it: the game hub and the
   creator profile both list mods, and a mod card must look the same wherever
   it appears. Written against classes rather than the hub's element IDs so a
   second consumer can adopt it without inheriting `#search` and `#pager`.
   ========================================================================== */

/* ------------------------------------------------------------ section rule */
/* Label, hairline, trailing figure — the device the mod page uses for
   About / Tags / Comments, and the creator pages for their sections. */
.am-work__head {
  display: flex;
  align-items: center;
  gap: .9rem;
  padding-bottom: .9rem;
}

.am-work__label {
  font-family: var(--am-mono);
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .2em;
  text-transform: uppercase;
  color: var(--am-ink-3);
  white-space: nowrap;
}

.am-work__rule {
  flex: 1 1 auto;
  height: 1px;
  background: var(--am-line-soft);
}

/* --------------------------------------------------------------- segments */
/* A small set of mutually exclusive filters shown as a row of counted
   buttons, so the breakdown is legible at a glance and doubles as the control.
   Used for a creator's games publicly and their mod statuses in the
   workspace. */
.am-seg {
  display: inline-grid;
  grid-auto-flow: column;
  grid-auto-columns: max-content;
  align-items: baseline;
  align-content: center;
  column-gap: .45rem;
  height: 1.9rem;
  padding-inline: .7rem;
  border: 1px solid var(--am-line-soft);
  border-radius: var(--am-r);
  background: transparent;
  color: var(--am-ink-2);
  font-family: var(--am-mono);
  font-size: .625rem;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  cursor: pointer;
  transition: color .18s var(--am-ease), border-color .18s var(--am-ease), background .18s var(--am-ease);
}
.am-seg:hover { color: var(--am-ink); border-color: var(--am-line); background: var(--am-panel); }

.am-seg__count {
  font-size: .5625rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0;
  color: var(--am-ink-3);
}

.am-seg[aria-pressed="true"] {
  border-color: rgba(var(--am-glow), .55);
  background: rgba(var(--am-glow), .1);
  color: var(--am-accent);
}
.am-seg[aria-pressed="true"] .am-seg__count { color: var(--am-accent); }

/* --------------------------------------------------------------- toolbar */
/* A floating panel, not a band.
   The wrapper paints NOTHING — no fill, no gradient, no border. Anything
   opaque here spans the full viewport width and cuts the ambient in two,
   reading as a black strip splitting the page. The atmosphere has to flow
   continuously behind the toolbar; only the contained panel is opaque, and it
   lines up exactly with the grid beneath it.

   No top padding, so when stuck the panel sits flush against the top of the
   viewport and no content is ever visible above it. */
.am-toolbar {
  position: sticky;
  top: 0;
  z-index: 30;
  padding-block: 0 .7rem;
  background: none;
}

.am-toolbar__panel {
  display: flex;
  flex-direction: column;
  gap: .5rem;
  padding: .45rem;
  border: 1px solid var(--am-line);
  border-radius: var(--am-r);
  background: rgba(13, 17, 23, .94);
  backdrop-filter: blur(16px);
  -webkit-backdrop-filter: blur(16px);
}

.am-toolbar__row { display: flex; align-items: center; gap: .45rem; }
.am-toolbar__group { display: flex; align-items: center; gap: .4rem; flex: 0 0 auto; }

/* ---------------------------------------------------------------- search */
.am-search { position: relative; flex: 1 1 auto; min-width: 0; }

.am-search__input {
  width: 100%;
  height: 2.2rem;
  border: 1px solid var(--am-line);
  border-radius: var(--am-r);
  background: var(--am-panel);
  color: var(--am-ink);
  padding: 0 4.4rem 0 2rem;
  font-family: inherit;
  font-size: .8125rem;
  transition: border-color .18s var(--am-ease), background .18s var(--am-ease);
}
.am-search__input::placeholder { color: var(--am-ink-3); }
.am-search__input:focus { border-color: rgba(var(--am-glow), .5); background: var(--am-panel-2); outline: none; }

.am-search__icon {
  position: absolute;
  left: .6rem;
  top: 50%;
  transform: translateY(-50%);
  color: var(--am-ink-3);
  pointer-events: none;
}
.am-search__icon svg { width: 14px; height: 14px; display: block; }

.am-search__clear,
.am-search__btn {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 1.6rem;
  width: 1.6rem;
  border-radius: 2px;
  color: var(--am-ink-3);
  transition: color .18s var(--am-ease), background .18s var(--am-ease);
}
.am-search__clear:hover,
.am-search__btn:hover { color: var(--am-ink); background: var(--am-panel-2); }
.am-search__clear { right: 2rem; }
.am-search__btn { right: .3rem; }

/* When there is no clear button, the search button takes the inner slot. */
.am-search--single .am-search__input { padding-right: 2.6rem; }

.am-search__suggest {
  position: absolute;
  left: 0;
  right: 0;
  top: calc(100% + .35rem);
  z-index: 40;
  max-height: 17rem;
  overflow: auto;
  border: 1px solid var(--am-line);
  border-radius: var(--am-r);
  background: #0d1117;
  box-shadow: 0 20px 50px rgba(0, 0, 0, .7);
}

@media (max-width: 63.99rem) {
  .am-toolbar__row { flex-wrap: wrap; }
  .am-search { flex: 1 1 100%; }
  .am-toolbar__group { flex: 1 1 100%; min-width: 0; }
  .am-select { min-width: 0; font-size: .75rem; padding-right: 1.3rem; }
}

/* ------------------------------------------------------------------ grid */
.mod-card-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 14px;
  /* stretch, so footers align when a title wraps to two lines */
  align-items: stretch;
  padding-top: 1.2rem;
}
@media (min-width: 44rem) { .mod-card-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (min-width: 66rem) { .mod-card-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
@media (min-width: 100rem) { .mod-card-grid { grid-template-columns: repeat(5, minmax(0, 1fr)); } }

/* ------------------------------------------------------------------ card */
/* Text sits on a solid caption below the artwork, never over it, so the render
   is never dimmed and the type is always legible. */
.mod-showcase-card {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  overflow: hidden;
  border: 1px solid var(--am-line-soft);
  border-radius: var(--am-r);
  /* Two layers, not one shorthand: a neutral plate, plus a tint in the page's
     colour that --am-floor scales to nothing when a page opts out.

     The plates cover about three quarters of the viewport once the grid
     starts, so on any page longer than a screen they — not the canvas — are
     what a visitor is actually looking at. Light behind them cannot reach
     past them; the colour has to be in them. */
  background-color: var(--am-panel);
  background-image: linear-gradient(
    rgba(var(--am-tint-rgb, var(--am-glow)), var(--am-tint, 0)),
    rgba(var(--am-tint-rgb, var(--am-glow)), var(--am-tint, 0)));
  transition: border-color .2s var(--am-ease), background-color .2s var(--am-ease);
}
.mod-showcase-card:hover {
  border-color: rgba(var(--am-glow), .4);
  background-color: var(--am-panel-2);
}

/* A hairline in the page's colour sweeps the top edge on hover.
   pointer-events:none so it never eats a click on the card. */
.mod-showcase-card::after {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 1px;
  z-index: 3;
  pointer-events: none;
  background: var(--am-accent);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .35s var(--am-ease);
}
.mod-showcase-card:hover::after { transform: scaleX(1); }

.am-card__link {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  color: inherit;
  text-decoration: none;
}

/* Stretched link: the whole card is the click target, including the footer
   strip, which sits outside the anchor because it holds the like button. */
.am-card__link::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

/* Raised above the stretched link so it stays independently clickable. */
.am-card__like { position: relative; z-index: 2; }

.am-card__media {
  position: relative;
  flex: 0 0 auto;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: #0b0f14;
}

.mod-showcase-card img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform .5s var(--am-ease);
}
.mod-showcase-card:hover img { transform: scale(1.04); }

.am-card__body { flex: 1 1 auto; padding: .6rem .65rem .1rem; }

.am-card__cats {
  display: flex;
  flex-wrap: nowrap;
  overflow: hidden;
  gap: 0;
  min-height: .9rem;
}

/* JS renders these as Tailwind pills; flatten them to mono micro-labels. */
.am-card__cats .chip {
  flex: 0 0 auto;
  border: 0 !important;
  background: none !important;
  box-shadow: none !important;
  padding: 0 !important;
  font-family: var(--am-mono);
  font-size: .5625rem !important;
  font-weight: 500;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--am-ink-3) !important;
  backdrop-filter: none !important;
}
.am-card__cats .chip:not(:first-child)::before {
  content: "·";
  margin-inline: .3rem;
  opacity: .55;
}

.mod-showcase-card h3 {
  margin: .25rem 0 0;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
  font-family: var(--am-display);
  font-size: .875rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -.015em;
  color: var(--am-ink);
  text-shadow: none;
  min-height: 2.19em;
}

.mod-showcase-card .author {
  display: block;
  margin-top: .15rem;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  font-family: var(--am-body);
  font-size: .75rem;
  font-weight: 400;
  color: var(--am-ink-3);
}

.am-card__foot {
  margin-top: auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: .5rem;
  padding: .4rem .65rem .5rem;
}

.am-card__facts {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: .25rem .55rem;
  min-width: 0;
}

/* Freshness sits in the footer beside the price, so it is built from the same
   parts as everything else there: mono and uppercase.

   New takes the page's own accent — it is the stronger signal, and it follows
   whichever hub you are on rather than staying one fixed hue. Updated is a
   quiet outline. It deliberately carries no colour of its own: the only warm
   token on a card is --am-paid, and an amber "updated" badge sat six pixels
   from an amber PAID label meant two unrelated things in one colour. */
.am-card__freshness {
  display: inline-flex;
  align-items: center;
  gap: .32em;
  min-height: 1.25rem;
  padding: .1rem .4rem;
  border: 1px solid rgba(var(--am-glow), .34);
  border-radius: var(--am-r);
  background: rgba(var(--am-glow), .12);
  font-family: var(--am-mono);
  font-size: .5625rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0;
  text-transform: uppercase;
  color: var(--am-accent);
  white-space: nowrap;
}

.am-card__freshness[data-kind="updated"] {
  border-color: var(--am-line);
  background: transparent;
  color: var(--am-ink-3);
}

/* Below 30rem the grid is two-up and the footer leaves about 77px for the
   price and this badge together — measured, not guessed: the full label needs
   115px there and overflowed into the like button. The kind alone fits, and
   the age is still on the mod page. */
@media (max-width: 29.99rem) {
  .am-card__age { display: none; }
}

/* Free / paid as a bare mono label. !important beats the inline styles the
   card renderer sets on this element. */
.mod-showcase-card .price-badge {
  background: none !important;
  border: 0 !important;
  box-shadow: none !important;
  padding: 0 !important;
  font-family: var(--am-mono);
  font-size: .5625rem !important;
  font-weight: 500;
  letter-spacing: .18em;
  text-transform: uppercase;
  backdrop-filter: none !important;
}
.mod-showcase-card.free .price-badge { color: var(--am-ink-3) !important; }
.mod-showcase-card.paid .price-badge { color: var(--am-paid) !important; }

.am-card__like .like-toggle {
  height: 1.55rem;
  min-width: 0;
  padding-inline: .45rem;
  border-radius: 999px;
  border-color: var(--am-line);
  background: rgba(0, 0, 0, .25);
  color: var(--am-ink-3);
  font-family: var(--am-mono);
  font-size: .625rem;
  font-variant-numeric: tabular-nums;
  gap: .25rem;
  cursor: pointer;
  transition: color .18s var(--am-ease), border-color .18s var(--am-ease), background .18s var(--am-ease);
}
.am-card__like .like-toggle:hover:not(:disabled) { color: var(--am-ink); border-color: rgba(255, 255, 255, .24); }

/* Liked state keys off aria-pressed: the Tailwind colour utilities the social
   JS also applies are never emitted into the built stylesheet. */
.am-card__like .like-toggle[aria-pressed="true"] {
  border-color: rgba(244, 120, 140, .55) !important;
  background: rgba(244, 120, 140, .14) !important;
  color: #ffd9e0 !important;
}

/* A count with no toggle behind it — used where liking is not wired up, so no
   control is offered that cannot act. */
.am-card__like .like-count {
  display: inline-flex;
  align-items: center;
  gap: .25rem;
  height: 1.55rem;
  padding-inline: .45rem;
  border: 1px solid var(--am-line);
  border-radius: 999px;
  background: rgba(0, 0, 0, .25);
  color: var(--am-ink-3);
  font-family: var(--am-mono);
  font-size: .625rem;
  font-variant-numeric: tabular-nums;
}

/* ----------------------------------------------------------------- empty */
/* A dashed outline rather than a filled panel: nothing is here, and a solid
   block reads as content. Shared by the account hub and the saved-mods list. */
.am-empty {
  border: 1px dashed var(--am-line);
  border-radius: var(--am-r);
  padding: 1.6rem 1rem;
  text-align: center;
  font-size: .8125rem;
  color: var(--am-ink-3);
}

/* ----------------------------------------------------------------- pager */
.am-pager {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  margin-top: 1.5rem;
  margin-bottom: 1.5rem;
  padding-top: .9rem;
  border-top: 1px solid var(--am-line-soft);
}

.am-pager__info {
  font-family: var(--am-mono);
  font-size: .625rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--am-ink-3);
}

.am-pager__nav { display: flex; align-items: center; gap: .3rem; }

.am-pager button {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  height: 1.9rem;
  padding-inline: .6rem;
  border: 1px solid var(--am-line-soft);
  border-radius: var(--am-r);
  background: transparent;
  color: var(--am-ink-3);
  font-family: var(--am-mono);
  font-size: .625rem;
  letter-spacing: .1em;
  cursor: pointer;
  transition: color .18s var(--am-ease), border-color .18s var(--am-ease), background .18s var(--am-ease);
}
.am-pager button:hover:not(:disabled) { color: var(--am-ink); border-color: var(--am-line); background: var(--am-panel); }
.am-pager button:disabled { opacity: .3; cursor: not-allowed; }

@media (max-width: 39.99rem) {
  .am-pager { flex-direction: column; align-items: stretch; gap: .65rem; }
  .am-pager__info { text-align: center; }
  .am-pager__nav { justify-content: space-between; }
  .am-pager__nav button { flex: 1 1 auto; }
}

/* ---------------------------------------------------------------- footer */
.am-foot {
  position: relative;
  margin-top: auto;
  border-top: 1px solid var(--am-line-soft);
}

/* Closes the page the way the masthead opens it. Without this the last thing
   a visitor sees is a grey rule on black, however coloured the top was. */
.am-foot::before {
  content: "";
  position: absolute;
  top: -1px;
  left: 0;
  right: 0;
  height: 1px;
  pointer-events: none;
  opacity: var(--am-floor, 0);
  background: linear-gradient(90deg, transparent, rgba(var(--am-glow), .55) 50%, transparent);
}

.am-foot__inner {
  padding-block: .5rem;
  font-size: .6875rem;
  line-height: 1.55;
  text-align: center;
  text-wrap: balance;
  color: var(--am-ink-3);
}
.am-foot__inner strong {
  font-family: var(--am-mono);
  font-weight: 500;
  letter-spacing: .2em;
  color: var(--am-ink-2);
}
.am-foot a { color: var(--am-ink-2); }

.am-privacy-link {
  padding-block: .65rem;
  color: var(--am-ink-3);
  font-family: var(--am-mono);
  font-size: .625rem;
  text-align: center;
  text-transform: uppercase;
}

.am-privacy-link a { color: var(--am-ink-2); }
.am-privacy-link a:hover { color: var(--am-ink); }

/* ---------------------------------------------------------------- motion */
.fade-in { animation: am-fade .3s var(--am-ease) both; }
@keyframes am-fade { from { opacity: 0; transform: translateY(5px); } to { opacity: 1; transform: none; } }

.am-rise { animation: am-rise .6s var(--am-ease) both; }
.am-rise--2 { animation-delay: .07s; }
.am-rise--3 { animation-delay: .14s; }
@keyframes am-rise { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: none; } }

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
  }
  .am-ambient__img { transition: none; }
}
