:root {
  --accent: #f2c072;
  --accent-soft: rgba(242, 192, 114, 0.25);
  /* Default raised from 0.62 when .panel lost its backdrop-filter: the blur
     was softening whatever showed through, and a little more opacity keeps
     the panel reading as a distinct surface against the artwork.
     Split into an alpha channel so the Backdrop buttons can adjust it at
     runtime - see display.js. */
  --panel-alpha: 0.78;
  --panel-bg: rgba(15, 10, 30, var(--panel-alpha));
  /* Archive listing width, driven by the Panel buttons - see display.js.
     Same custom-property approach as --panel-alpha above. */
  --panel-max: min(1400px, 95vw);
  --panel-border: rgba(255, 200, 120, 0.28);
  --text: #f5e9d0;
  --muted: #b8ac94;
  --danger: #e07b7b;
}

* { box-sizing: border-box; }

html, body {
  margin: 0;
  padding: 0;
  min-height: 100vh;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  color: var(--text);
  background: #0a0612;
}
/* Belt-and-suspenders: even if some grid child manages to overflow
   despite the per-card wrap rules, the page itself won't allow
   horizontal scroll. Prevents the "background doesn't follow"
   look reported on mobile when horizontal scroll was possible.
   On html ONLY: an overflow value on body makes body its own scroll
   container, and position: sticky anywhere on the page then sticks to
   body (which never scrolls) instead of the viewport - the docs
   sidebars silently stopped floating because of exactly that. */
html { overflow-x: hidden; }

/* The base colour stays on `html` so it shows while the image loads, but
   `body` must be transparent: the background layer below is a body::before
   at z-index -1, which paints behind body's own background. Leaving the
   opaque colour on body would hide the image entirely. */
body { background: transparent; }

/* The background lives on its own fixed layer rather than on `body` with
   `background-attachment: fixed`. Visually identical - it still holds
   position while the content scrolls - but `background-attachment: fixed`
   forces a full-viewport repaint on every scroll frame, and with `.panel`
   blurring over the top that made scrolling visibly laggy. As a separate
   fixed element the browser composites it once and leaves it alone. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background-image: url('https://raw.githubusercontent.com/veyra-empire/assets/master/bg-install.webp');
  background-image: image-set(
    url('https://raw.githubusercontent.com/veyra-empire/assets/master/bg-install.webp') 1x,
    url('https://raw.githubusercontent.com/veyra-empire/assets/master/bg-install-2x.webp') 2x
  );
  background-image: -webkit-image-set(
    url('https://raw.githubusercontent.com/veyra-empire/assets/master/bg-install.webp') 1x,
    url('https://raw.githubusercontent.com/veyra-empire/assets/master/bg-install-2x.webp') 2x
  );
  background-size: cover;
  background-position: center bottom;
  background-repeat: no-repeat;
}

@media (max-width: 768px) and (orientation: portrait) {
  body::before {
    background-image: url('https://raw.githubusercontent.com/veyra-empire/assets/master/bg-install-m.webp');
  }
}

.overlay {
  min-height: 100vh;
  background: linear-gradient(180deg, rgba(10, 6, 18, 0.35) 0%, rgba(10, 6, 18, 0.1) 30%, rgba(10, 6, 18, 0.6) 100%);
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 8vh 20px 40px;
}

/* Widened for the archive listing only. `.panel` is shared with the sign-in
   and denied states, which look absurd stretched across a wide monitor, so
   this is scoped to the state that actually holds a grid. */
.panel:has(> #state-scripts:not([hidden])) {
  max-width: var(--panel-max);
}

/* "Panel: Off" - show the artwork with nothing over it.
   Deliberately scoped through the same :has() as the width rule above, so it
   can only ever hide the archive listing. If it applied to .panel generally,
   a member could hide the UI, sign out, and be left with no way back in.
   Transient by design: nothing about this is written to localStorage, so a
   reload always brings the UI back. */
[data-ui="off"] .panel:has(> #state-scripts:not([hidden])) { display: none; }
/* .overlay dims the artwork independently of the panel, so it has to lift
   too - otherwise "just the backdrop" is still a washed-out backdrop. */
[data-ui="off"] .overlay { background: none; }

/* Lives outside .panel so it can never be hidden along with it. Paired with
   the Escape key, so a mis-click is never a dead end. */
.ui-restore {
  display: none;
  position: fixed;
  bottom: 16px;
  right: 16px;
  z-index: 2147483000;
  padding: 8px 16px;
  border-radius: 999px;
  border: 1px solid var(--panel-border);
  background: rgba(15, 10, 30, 0.82);
  color: var(--accent);
  font: 600 0.8rem/1.3 inherit;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
}
.ui-restore:hover { background: rgba(15, 10, 30, 0.95); border-color: var(--accent); }
[data-ui="off"] .ui-restore { display: inline-block; }

/* Says what the background listing refresh changed. Fixed like
   .ui-restore so it is visible wherever the member is scrolled to, and
   muted because it reports rather than asks for anything. */
.listing-notice {
  position: fixed;
  bottom: 16px;
  left: 16px;
  z-index: 2147483000;
  margin: 0;
  max-width: min(360px, calc(100vw - 32px));
  padding: 8px 14px;
  border-radius: 999px;
  border: 1px solid var(--panel-border);
  background: rgba(15, 10, 30, 0.88);
  color: var(--muted);
  font-size: 0.78rem;
  line-height: 1.3;
  transition: opacity 400ms ease;
}
.listing-notice[data-fading="1"] { opacity: 0; }
.listing-notice-action {
  padding: 0;
  border: 0;
  background: none;
  font: inherit;
  color: var(--accent);
  text-decoration: underline;
  cursor: pointer;
}

/* A changelog entry with no notes ("No patch notes provided."). */
.recent-notes-empty { color: var(--muted); font-style: italic; }

/* Flash the card an Updates-window row points at, so the eye lands on it
   after the scroll rather than hunting the column. */
/* Holds at full highlight before fading: scrollIntoView takes roughly half a
   second to arrive, and the old ease-out spent most of its life almost faded,
   so the card was back to normal by the time the eye reached it. Keep the
   duration and scrollToItem's cleanup timeout in step. */
@keyframes card-flash {
  0%, 30% { border-color: var(--accent); background: rgba(242, 192, 114, 0.14); }
  100%    { border-color: rgba(255, 255, 255, 0.06); background: rgba(0, 0, 0, 0.28); }
}
.script-card.card-flash { animation: card-flash 3.2s ease-in-out; }
@media (prefers-reduced-motion: reduce) {
  .script-card.card-flash { animation-duration: 0.01s; }
}

.panel {
  width: 100%;
  max-width: 720px;
  background: var(--panel-bg);
  border: 1px solid var(--panel-border);
  border-radius: 14px;
  /* No backdrop-filter here, deliberately. On the archive listing this
     element is roughly 1200 x 3900 px, and a blurred backdrop that size has
     to be re-sampled and re-blurred every scrolled frame - it was the main
     cause of the scroll lag, and widening the panel for multi-column layout
     made it 69% worse. Unlike box-shadow below, which rasterises once and is
     cached, this cost is unavoidably per-frame. The two fixed overlays
     further down keep their blur: they are small and nothing scrolls behind
     them. --panel-bg was raised to compensate. */
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.45);
  padding: 36px 36px 28px;
}

h1 {
  font-family: 'Cinzel', serif;
  font-weight: 700;
  font-size: 2.4rem;
  letter-spacing: 0.18em;
  margin: 0 0 6px;
  text-align: center;
  color: var(--accent);
  text-shadow: 0 2px 20px rgba(242, 192, 114, 0.3);
}

.subtitle {
  font-family: 'Cinzel', serif;
  font-size: 0.85rem;
  letter-spacing: 0.35em;
  text-transform: uppercase;
  text-align: center;
  margin: 0 0 28px;
  color: var(--muted);
}

form.email-form {
  display: flex;
  gap: 10px;
  margin: 20px 0 14px;
}

input[type="email"] {
  flex: 1;
  padding: 12px 14px;
  font-size: 1rem;
  font-family: inherit;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  color: var(--text);
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}
input[type="email"]:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft);
}

button, .install-btn {
  padding: 12px 22px;
  font-size: 0.95rem;
  font-family: inherit;
  font-weight: 600;
  background: var(--accent);
  color: #1a0d05;
  border: none;
  border-radius: 8px;
  cursor: pointer;
  text-decoration: none;
  display: inline-block;
  transition: transform 0.1s, box-shadow 0.15s, background 0.15s;
}
button:hover, .install-btn:hover {
  background: #ffd18a;
  box-shadow: 0 4px 16px rgba(242, 192, 114, 0.35);
  transform: translateY(-1px);
}

.footer-note {
  margin-top: 18px;
  font-size: 0.85rem;
  color: var(--muted);
  text-align: center;
}

.greeting {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding-bottom: 18px;
  border-bottom: 1px solid var(--panel-border);
  margin-bottom: 22px;
  flex-wrap: wrap;
}
.greeting h2 {
  font-family: 'Cinzel', serif;
  font-weight: 400;
  font-size: 1.3rem;
  margin: 0;
  letter-spacing: 0.05em;
}
.greeting .email-line {
  font-size: 0.82rem;
  color: var(--muted);
  margin-top: 4px;
}

.tier-badge {
  font-family: 'Cinzel', serif;
  font-size: 0.75rem;
  letter-spacing: 0.2em;
  text-transform: uppercase;
  padding: 6px 14px;
  border-radius: 999px;
  border: 1px solid currentColor;
}
.tier-probationary { color: #9aa4af; }
.tier-member       { color: #d7dbe0; }
.tier-tester       { color: #f2c072; }
.tier-owner        { color: #e87070; }

.scripts-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
}
@media (max-width: 600px) {
  .scripts-grid { grid-template-columns: 1fr; }
  .panel { padding: 24px 20px; }
  h1 { font-size: 1.8rem; }
}
/* Edges: Full (display.js sets data-edge only on a narrow viewport). The
   panel runs to the screen's edges with a small gutter, so a phone's
   reading width is the screen, not the screen minus the backdrop. */
html[data-edge="full"] .overlay { padding: 0 0 32px; }
html[data-edge="full"] .panel { max-width: none; border-left: 0; border-right: 0; border-radius: 0; padding-left: 14px; padding-right: 14px; }
html[data-edge="full"] .panel-docs { padding-left: 0; padding-right: 0; }
@media (min-width: 761px) { .bar-group.edge-group { display: none; } }

/* Manual column count, set by the Columns buttons and remembered per
   browser. Deliberately confined to this media query rather than applied as
   an inline style: an inline style would outrank the mobile rules above and
   force a saved desktop preference of 4 onto a phone. Below 900px the
   buttons are hidden and the grids stay width-driven.
   minmax(0, 1fr) rather than minmax(280px, 1fr) so a chosen count cannot
   overflow a window too narrow to hold it. */
@media (min-width: 900px) {
  #state-scripts[data-cols="2"] .scripts-grid,
  #state-scripts[data-cols="2"] .resources-grid,
  #state-scripts[data-cols="2"] .extensions-grid {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
  #state-scripts[data-cols="3"] .scripts-grid,
  #state-scripts[data-cols="3"] .resources-grid,
  #state-scripts[data-cols="3"] .extensions-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
  #state-scripts[data-cols="4"] .scripts-grid,
  #state-scripts[data-cols="4"] .resources-grid,
  #state-scripts[data-cols="4"] .extensions-grid {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }
}

/* Every cluster in the sort bar has the same shape: a label followed by its
   buttons. 6px within a group against the bar's own 10px, and 22px between
   groups on the options row, so the clusters read as deliberate. */
.bar-group {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  /* .bar-options wraps the groups relative to each other, but each group is
     its own flex line - without this the six Thumbs buttons refuse to wrap
     and run past a phone's viewport, where html's overflow-x:hidden clips
     them into being unreachable rather than showing a scrollbar. */
  flex-wrap: wrap;
}

/* Sort is used constantly and stays visible; Backdrop and Columns are set
   once and forgotten, so they live behind this toggle. It is the only thing
   claiming the free space now. */
.bar-toggle { margin-left: auto; }
/* The gear that opens it. Specific enough to beat .sort-btn's padding. */
.sort-btn.bar-gear { display: inline-flex; align-items: center; align-self: center; padding: 7px 9px; line-height: 1; }  /* 31px tall, like its neighbours */
.bar-gear svg { display: block; }

/* Revealed row. flex-basis:100% uses .sort-bar's existing flex-wrap to force
   a line break, so the options sit under the sort controls rather than
   cramming in beside them. */
.bar-options {
  flex-basis: 100%;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 22px;
  margin-top: 10px;
  padding-top: 12px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.bar-options[hidden] { display: none; }

/* Below 900px only Panel and Columns drop out: the grids are width-driven
   there and there is no room for extra columns, whereas Thumbs and Backdrop
   work at any width and matter more on a phone, where screenshots dominate
   the scroll. The toggle and the options row itself stay.
   A stored Panel width is harmless here regardless - every option exceeds a
   phone's available width, so width:100% governs either way. A stored column
   count is genuinely ignored, by the min-width media query above, because
   forcing four columns onto a phone would break the layout. */
@media (max-width: 899px) {
  #widthGroup,
  .width-group,
  #colsGroup { display: none; }
}

.script-card {
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 10px;
  padding: 16px 18px;
  display: flex;
  flex-direction: column;
  gap: 8px;
  transition: border-color 0.15s, background 0.15s;
  /* Grid children default to min-width:auto (intrinsic content width),
     which lets long unbreakable strings inside a card push its width
     past the grid cell -> the whole panel overflows the viewport.
     min-width:0 lets the card shrink; the text-wrap rules below then
     handle the actual breaking. */
  min-width: 0;
}
.script-card:hover {
  border-color: var(--panel-border);
  background: rgba(0, 0, 0, 0.38);
}
.script-card h3 {
  font-family: 'Cinzel', serif;
  font-weight: 400;
  font-size: 1.05rem;
  margin: 0;
  color: var(--accent);
  letter-spacing: 0.04em;
  /* Safety net for scripts with unusually long names / no natural
     break points. anywhere is stronger than break-word - it will
     break mid-word if that's what it takes to fit. */
  overflow-wrap: anywhere;
}
.script-meta {
  font-size: 0.78rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}

/* The name Tampermonkey lists the script under, when it differs from the
   archive title. Quieter than .script-meta - it is a reference detail, only
   wanted when someone is matching a card against their dashboard.
   overflow-wrap matters: these names are long and cards can be ~150px at
   Narrow width with 4 columns. */
.script-install-name {
  font-size: 0.72rem;
  color: var(--muted);
  opacity: 0.75;
  margin-top: 3px;
  overflow-wrap: anywhere;
}
.script-desc {
  font-size: 0.88rem;
  line-height: 1.45;
  color: var(--text);
  flex: 1;
  /* User-provided description text. Long hashes, URLs, install
     paths etc. would otherwise force horizontal scroll on mobile
     because the string acts as one unbreakable "word". */
  overflow-wrap: anywhere;
}

.script-thumb {
  align-self: flex-start;
  padding: 0;
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.35);
  cursor: zoom-in;
  overflow: hidden;
  line-height: 0;
  transition: border-color 0.12s, transform 0.12s;
}
.script-thumb:hover {
  border-color: var(--accent);
  transform: translateY(-1px);
}
.script-thumb img {
  display: block;
  /* Scaled by the Thumbs buttons - see applyThumbs() in app.js.
     min(100%, ...) is load-bearing: at Large inside a Narrow panel with 4
     columns a card can be ~150px wide, and a bare 320px cap would overflow
     it, which is the same failure the mobile overflow fix dealt with. */
  max-width: min(100%, calc(200px * var(--thumb-scale, 1)));
  max-height: calc(120px * var(--thumb-scale, 1));
  width: auto;
  height: auto;
  object-fit: cover;
}

/* Off is display:none rather than --thumb-scale:0, because a zero-sized
   image would still be fetched. With no layout box the lazy loader never
   requests it, so this skips the screenshots entirely - about 2.5 MB. */
[data-thumbs="off"] .script-thumb { display: none; }
.install-btn {
  align-self: flex-start;
  margin-top: 4px;
  padding: 8px 18px;
  font-size: 0.88rem;
}

/* Discord's own button look (brand blurple, its logo), drawn inline; small
   and centred under the links. */
.discord-corner { text-align: center; margin-top: 18px; }
.discord-btn {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 6px 12px; border-radius: 6px;
  background: #5865F2; color: #fff; font-weight: 600; font-size: 0.78rem;
  text-decoration: none; transition: background 0.15s;
}
.discord-btn:hover { background: #4752C4; color: #fff; text-decoration: none; }
.discord-mark { width: 17px; height: 13px; }

.tier-pill {
  display: inline-block;
  font-family: 'Cinzel', serif;
  font-size: 0.68rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  padding: 3px 10px;
  border-radius: 999px;
  border: 1px solid currentColor;
  vertical-align: middle;
  margin-left: 6px;
}

/* Card title row: name + version + optional type tag in one flex row. */
.card-title {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 8px;
}
.version-pill {
  display: inline-block;
  font-family: ui-monospace, 'Cascadia Code', Consolas, monospace;
  font-size: 0.72rem;
  color: var(--muted);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 4px;
  padding: 1px 7px;
  letter-spacing: 0.02em;
}
.extension-tag {
  display: inline-block;
  font-size: 0.68rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(242, 192, 114, 0.08);
  color: var(--accent);
  border: 1px solid rgba(242, 192, 114, 0.25);
}

/* Changelog disclosure on script + extension cards. */
.card-changelog,
.card-instructions {
  font-size: 0.82rem;
  border-top: 1px dashed rgba(255, 255, 255, 0.08);
  padding-top: 8px;
  margin-top: 2px;
}
.card-changelog > summary,
.card-instructions > summary {
  cursor: pointer;
  color: var(--muted);
  user-select: none;
  list-style: none;
  padding: 2px 0;
}
.card-changelog > summary::-webkit-details-marker,
.card-instructions > summary::-webkit-details-marker {
  display: none;
}
.card-changelog > summary::before,
.card-instructions > summary::before {
  content: '▸ ';
  display: inline-block;
  width: 1em;
  transition: transform 120ms ease;
}
.card-changelog[open] > summary::before,
.card-instructions[open] > summary::before {
  transform: rotate(90deg);
}
.card-changelog > summary:hover,
.card-instructions > summary:hover {
  color: var(--text);
}
.card-changelog-list {
  margin-top: 6px;
  display: flex;
  flex-direction: column;
  gap: 10px;
}
.card-changelog-item {
  border-left: 2px solid rgba(242, 192, 114, 0.25);
  padding-left: 10px;
}
.card-changelog-head {
  font-family: ui-monospace, 'Cascadia Code', Consolas, monospace;
  font-size: 0.75rem;
  color: var(--accent);
  letter-spacing: 0.02em;
  /* Monospace + likely to contain version strings; break anywhere
     so long tags don't push the card wider than mobile viewport. */
  overflow-wrap: anywhere;
}
.card-changelog-notes {
  margin-top: 4px;
  /* pre-wrap preserves author-typed newlines but does NOT break
     unbreakable strings on its own. Pair with overflow-wrap so long
     paths / URLs / hashes in changelog notes still wrap. */
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  color: var(--text);
  font-size: 0.82rem;
  line-height: 1.45;
}
.card-instructions-list {
  margin: 6px 0 0 0;
  padding-left: 22px;
  color: var(--text);
  font-size: 0.82rem;
  line-height: 1.5;
}
.card-instructions-list li { margin-bottom: 4px; }

/* Extensions section: its own heading + grid identical to scripts-grid. */
.section-heading {
  font-family: 'Cinzel', serif;
  font-weight: 400;
  font-size: 1.15rem;
  letter-spacing: 0.1em;
  color: var(--accent);
  margin: 28px 0 6px;
  text-transform: uppercase;
}
/* Sections fold under their heading (app.js, sections). */
.section-toggle {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  font: inherit;
  letter-spacing: inherit;
  text-transform: inherit;
  cursor: pointer;
}
.section-toggle:hover { color: var(--text); }
.section-chevron {
  width: 8px;
  height: 8px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  transform: rotate(45deg) translate(-2px, -2px);
  transition: transform 0.15s;
}
.section.collapsed .section-chevron { transform: rotate(-45deg) translate(-1px, 1px); }
.section-count { color: var(--muted); font-size: 0.85em; letter-spacing: 0.04em; }
.section.collapsed .section-body { display: none; }
.section.collapsed .section-heading { margin-bottom: 14px; }
/* The sort bar and the search/filters stay pinned while scrolling the
   Userscripts on a wide screen. Their containing block is the section body,
   which ends with the scripts grid, so they let go exactly when the next
   heading arrives. Not on phones: there the block would be a third of the
   screen. (Per-section scroll boxes were tried and dropped: they did not
   feel right.) */
@media (min-width: 900px) {
  .scripts-sticky {
    position: sticky;
    top: 0;
    z-index: 3;
    margin: 0 -8px;
    padding: 8px 8px 0;
    background: rgb(21, 13, 34);
    border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  }
}
.extensions-grid,
.resources-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
  gap: 14px;
}
.extension-btn {
  background: rgba(242, 192, 114, 0.12);
  border: 1px solid rgba(242, 192, 114, 0.5);
  color: var(--accent);
}
.extension-btn:hover {
  background: rgba(242, 192, 114, 0.2);
  color: var(--accent);
}

/* Resource cards: same visual family as extensions but with a subtly
   different tag + button accent so members can tell at a glance the
   flow is different (not a Tampermonkey install, not a Drive unpack). */
.resource-tag {
  background: rgba(136, 180, 255, 0.14);
  border-color: rgba(136, 180, 255, 0.5);
  color: #9ec2ff;
}
.resource-btn {
  background: rgba(136, 180, 255, 0.12);
  border: 1px solid rgba(136, 180, 255, 0.5);
  color: #9ec2ff;
}
.resource-btn:hover {
  background: rgba(136, 180, 255, 0.2);
  color: #b8d2ff;
}
.resource-updated {
  font-size: 0.78rem;
  color: var(--muted);
  margin: 2px 0 4px;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.02em;
}

.script-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 4px;
  flex-wrap: wrap;
}

.thread-link {
  font-size: 0.82rem;
  color: var(--muted);
  text-decoration: none;
  border-bottom: 1px dotted var(--muted);
  padding-bottom: 1px;
  transition: color 0.12s, border-color 0.12s;
}
.thread-link:hover {
  color: var(--accent);
  border-bottom-color: var(--accent);
}

.sort-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin-bottom: 16px;
  padding: 10px 14px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 10px;
}
.sort-bar .label {
  font-size: 0.78rem;
  color: var(--muted);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  margin-right: 4px;
}
.sort-btn {
  padding: 6px 14px;
  font-size: 0.82rem;
  font-family: inherit;
  background: transparent;
  color: var(--text);
  border: 1px solid rgba(255, 255, 255, 0.12);
  border-radius: 6px;
  cursor: pointer;
  transition: border-color 0.12s, color 0.12s, background 0.12s;
}
.sort-btn:hover { border-color: var(--accent-soft); color: var(--accent); }
.sort-btn.active {
  color: var(--accent);
  border-color: var(--accent);
  background: rgba(242, 192, 114, 0.08);
}
.sort-dir {
  /* No margin-left:auto. It dates from when Sort was the only cluster in the
     bar; once Backdrop and Columns arrived, two competing auto margins split
     the free space and stranded this arrow in the middle of the bar. It
     belongs beside the buttons it modifies. */
  min-width: 42px;
  text-align: center;
  font-weight: 600;
}

.denied-icon {
  font-size: 3rem;
  text-align: center;
  color: var(--danger);
  margin-bottom: 12px;
}
.denied-msg {
  text-align: center;
  font-size: 1rem;
  line-height: 1.55;
  margin-bottom: 22px;
}

.empty-state {
  text-align: center;
  padding: 20px 0 10px;
  color: var(--muted);
}

.back-link {
  display: inline-block;
  margin-top: 22px;
  color: var(--muted);
  text-decoration: none;
  font-size: 0.85rem;
  border-bottom: 1px dotted var(--muted);
}
.back-link:hover { color: var(--accent); border-bottom-color: var(--accent); }

.tampermonkey-hint {
  margin-top: 10px;
  font-size: 0.78rem;
  color: var(--muted);
  text-align: center;
}
.tampermonkey-hint a,
.footer-note a { color: var(--accent); }

.trust-notice {
  margin: 0 0 18px;
  padding: 10px 0;
  border-top: 1px dotted var(--panel-border);
  border-bottom: 1px dotted var(--panel-border);
  font-size: 0.82rem;
  line-height: 1.5;
  color: var(--muted);
  text-align: center;
}
.trust-notice strong {
  color: var(--text);
  letter-spacing: 0.04em;
}

.tm-banner {
  margin: 0 0 18px;
  padding: 10px 14px;
  background: rgba(242, 192, 114, 0.08);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  font-size: 0.85rem;
  line-height: 1.5;
  color: var(--text);
  text-align: center;
}
.tm-banner a { color: var(--accent); }
.tm-banner { display: flex; align-items: center; gap: 10px; }
.tm-banner > span { flex: 1; }
.tm-banner-close { padding: 0 6px; border: 0; background: none; color: var(--muted); font-size: 1.2rem; line-height: 1; cursor: pointer; }
.tm-banner-close:hover { color: var(--text); }

/* The Emperor's Outdated mark. */
.outdated-pill {
  display: inline-block;
  padding: 2px 8px;
  border-radius: 999px;
  background: rgba(230, 150, 60, 0.18);
  border: 1px solid rgba(230, 150, 60, 0.6);
  color: #f0b060;
  font-size: 0.68rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}
.card-outdated h3, .card-outdated .script-desc { color: var(--muted); }
.outdated-btn { font-size: 0.74rem; margin-left: auto; }
.upd-outdated { margin-left: 6px; color: #f0b060; font-size: 0.68rem; letter-spacing: 0.08em; text-transform: uppercase; }

/* Submission form (submit.html) */
.panel-wide { max-width: 820px; }

.form-row {
  margin-bottom: 16px;
}
.form-label {
  display: block;
  font-family: 'Cinzel', serif;
  font-size: 0.78rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 6px;
}
.form-optional {
  font-family: inherit;
  font-size: 0.75rem;
  letter-spacing: normal;
  text-transform: none;
  color: rgba(184, 172, 148, 0.6);
  margin-left: 6px;
}
.form-hint {
  margin: 6px 0 0;
  font-size: 0.78rem;
  color: var(--muted);
  line-height: 1.4;
}
.form-warning {
  margin-top: 8px;
  padding: 8px 12px;
  background: rgba(242, 192, 114, 0.1);
  border: 1px solid rgba(242, 192, 114, 0.35);
  border-radius: 6px;
  font-size: 0.82rem;
  line-height: 1.45;
  color: #f2c072;
}
.form-warning strong { color: #f5e9d0; font-weight: 600; }
.form-input {
  width: 100%;
  padding: 10px 12px;
  font-size: 0.95rem;
  font-family: inherit;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  color: var(--text);
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
  box-sizing: border-box;
}
.form-input:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent-soft);
}
.form-source {
  font-family: ui-monospace, 'Cascadia Code', 'Fira Code', Consolas, monospace;
  font-size: 0.82rem;
  resize: vertical;
  min-height: 180px;
}
.form-source.drag-over {
  border-color: var(--accent);
  background: rgba(242, 192, 114, 0.06);
}

.source-toolbar {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 8px;
  flex-wrap: wrap;
}
.source-upload-input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}
.source-upload-btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  background: rgba(242, 192, 114, 0.14);
  border: 1px solid rgba(242, 192, 114, 0.5);
  border-radius: 6px;
  color: var(--accent);
  font-size: 0.85rem;
  font-weight: 600;
  cursor: pointer;
  user-select: none;
  transition: background 120ms ease;
}
.source-upload-btn:hover  { background: rgba(242, 192, 114, 0.22); }
.source-upload-btn:active { background: rgba(242, 192, 114, 0.3); }
.source-upload-input:focus + .source-upload-hint,
.source-upload-btn:focus-within {
  box-shadow: 0 0 0 2px var(--accent-soft);
}
.source-upload-hint {
  font-size: 0.78rem;
  color: var(--muted);
  flex: 1 1 auto;
  min-width: 0;
}

.mode-row { display: flex; flex-direction: column; }
.mode-options { display: flex; gap: 14px; flex-wrap: wrap; }
.mode-option {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  font-size: 0.9rem;
  cursor: pointer;
}
.mode-option input { margin: 0; }
.mode-option.disabled {
  opacity: 0.4;
  cursor: not-allowed;
}

.attest {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 0.9rem;
  line-height: 1.45;
  padding: 10px 12px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
}
.attest input { margin: 3px 0 0; flex-shrink: 0; }

.form-actions {
  display: flex;
  align-items: center;
  gap: 16px;
  margin-top: 24px;
}
.form-actions .install-btn:disabled {
  opacity: 0.4;
  cursor: not-allowed;
  box-shadow: none;
  transform: none;
}
.form-actions .install-btn:disabled:hover {
  background: var(--accent);
}

.form-error {
  margin-top: 14px;
  padding: 10px 12px;
  background: rgba(224, 123, 123, 0.08);
  border: 1px solid rgba(224, 123, 123, 0.4);
  border-radius: 8px;
  color: var(--danger);
  font-size: 0.88rem;
  line-height: 1.5;
}

.version-row {
  display: flex;
  gap: 10px;
  align-items: stretch;
}
.version-row .form-input {
  flex: 1;
}
.version-row input[readonly] {
  color: var(--muted);
  background: rgba(0, 0, 0, 0.45);
  cursor: not-allowed;
}
.version-btn {
  padding: 8px 14px;
  font-size: 0.82rem;
  font-family: inherit;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  cursor: pointer;
  flex-shrink: 0;
}
.version-btn:hover { color: var(--accent); border-color: var(--accent); }
.version-btn-confirm {
  background: var(--accent);
  color: #1a0d05;
  border-color: var(--accent);
}
.version-btn-confirm:hover { background: #ffd18a; color: #1a0d05; }

.form-file {
  padding: 8px 10px;
  font-size: 0.88rem;
  cursor: pointer;
}
.form-file::file-selector-button {
  padding: 6px 12px;
  margin-right: 10px;
  font-family: inherit;
  font-size: 0.82rem;
  background: rgba(242, 192, 114, 0.12);
  color: var(--accent);
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  cursor: pointer;
}
.form-file::file-selector-button:hover {
  background: rgba(242, 192, 114, 0.22);
}

.screenshot-preview {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin-top: 10px;
  padding: 8px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
}
.screenshot-preview img {
  max-width: 220px;
  max-height: 140px;
  border-radius: 4px;
  display: block;
}
.screenshot-clear {
  padding: 6px 10px;
  font-size: 0.78rem;
  font-family: inherit;
  background: transparent;
  color: var(--muted);
  border: 1px solid var(--panel-border);
  border-radius: 6px;
  cursor: pointer;
}
.screenshot-clear:hover {
  color: var(--danger);
  border-color: rgba(224, 123, 123, 0.4);
}

.open-submissions {
  margin: 0 0 18px;
  padding: 12px 14px;
  background: rgba(224, 123, 123, 0.08);
  border: 1px solid rgba(224, 123, 123, 0.4);
  border-radius: 8px;
  color: var(--text);
  font-size: 0.88rem;
  line-height: 1.5;
}
.open-submissions-header {
  display: flex;
  align-items: baseline;
  gap: 8px;
  margin-bottom: 8px;
}
.open-submissions-header strong { color: var(--danger); }
.open-submissions-count { color: var(--muted); font-size: 0.82rem; }

.open-submissions-list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 6px;
}
.open-submissions-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 10px;
  padding: 8px 10px;
  background: rgba(0, 0, 0, 0.25);
  border-radius: 6px;
  flex-wrap: wrap;
}
.open-submissions-label { flex: 1 1 auto; min-width: 0; word-break: break-word; }
.open-submissions-label strong { color: var(--accent); font-weight: 600; }

.cancel-banner-btn {
  padding: 6px 12px;
  font-size: 0.78rem;
  font-family: inherit;
  font-weight: 600;
  background: var(--danger);
  color: #1a0d05;
  border: none;
  border-radius: 6px;
  cursor: pointer;
  flex-shrink: 0;
  transition: background 0.12s, transform 0.1s;
}
.cancel-banner-btn:hover { background: #f09999; transform: translateY(-1px); }
.cancel-banner-btn:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }

/* Floating toasts (fixed top-right). Click to dismiss; auto-dismiss after 6s. */
.toast-container {
  position: fixed;
  top: 20px;
  right: 20px;
  z-index: 9999;
  display: flex;
  flex-direction: column;
  gap: 10px;
  max-width: calc(100vw - 40px);
  width: 380px;
  pointer-events: none;
}
.toast {
  pointer-events: auto;
  padding: 12px 16px;
  border-radius: 10px;
  font-size: 0.88rem;
  line-height: 1.45;
  cursor: pointer;
  background: rgba(15, 10, 30, 0.92);
  color: var(--text);
  border: 1px solid var(--panel-border);
  box-shadow: 0 10px 30px rgba(0, 0, 0, 0.45);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  opacity: 0;
  transform: translateX(20px);
  transition: opacity 0.2s ease, transform 0.2s ease;
}
.toast.show { opacity: 1; transform: translateX(0); }
.toast-success { border-color: rgba(130, 200, 130, 0.45); }
.toast-error   { border-color: rgba(224, 123, 123, 0.55); }
.toast-info    { border-color: var(--panel-border); }

@media (max-width: 600px) {
  .toast-container { top: 10px; right: 10px; width: calc(100vw - 20px); }
}

/* Lightbox for screenshot thumbnails. Backdrop click or ESC closes. */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 9998;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 12px;
  padding: 20px;
  background: rgba(10, 6, 18, 0.92);
  backdrop-filter: blur(6px);
  -webkit-backdrop-filter: blur(6px);
  cursor: zoom-out;
}
.lightbox-img {
  max-width: min(95vw, 1400px);
  max-height: calc(95vh - 60px);
  object-fit: contain;
  border-radius: 6px;
  box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
  cursor: default;
}
.lightbox-caption {
  margin: 0;
  color: var(--muted);
  font-size: 0.88rem;
  letter-spacing: 0.02em;
  text-align: center;
  max-width: 90vw;
}
.lightbox-close {
  position: absolute;
  top: 16px;
  right: 20px;
  width: 40px;
  height: 40px;
  /* padding:0 is required, not cosmetic. The generic `button` rule sets
     12px 22px, and with box-sizing:border-box that is 44px of horizontal
     padding inside a 40px-wide button - the content box collapses and the
     glyph lands off-centre. Flex centring then places it reliably instead of
     depending on the font's own metrics. */
  padding: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.8rem;
  line-height: 1;
  background: transparent;
  color: var(--text);
  border: 1px solid var(--panel-border);
  border-radius: 999px;
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}
.lightbox-close:hover {
  color: var(--accent);
  border-color: var(--accent);
  background: rgba(242, 192, 114, 0.08);
}

.loading-msg {
  text-align: center;
  color: var(--muted);
  padding: 30px 0;
  font-size: 0.95rem;
}
/* Animated ellipsis for waits that genuinely take seconds (the sign-in
   exchange). Inline with the message rather than a spinner, so the text
   stays the thing being read. */
.dots i {
  font-style: normal;
  opacity: 0.25;
  animation: dot-pulse 1.2s ease-in-out infinite;
}
.dots i:nth-child(2) { animation-delay: 0.2s; }
.dots i:nth-child(3) { animation-delay: 0.4s; }
@keyframes dot-pulse {
  0%, 80%, 100% { opacity: 0.25; }
  40%           { opacity: 1; }
}
@media (prefers-reduced-motion: reduce) {
  .dots i { animation: none; opacity: 0.7; }
}

[hidden] { display: none !important; }

/* Search + filters above the sections. Same surface as .sort-bar. */
.archive-filter {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px;
  margin: 0 0 20px;
  padding: 10px 14px;
  background: rgba(0, 0, 0, 0.25);
  border: 1px solid rgba(255, 255, 255, 0.06);
  border-radius: 10px;
}
.archive-filter .filter-search { flex: 1 1 260px; width: auto; }
.archive-filter .filter-select { flex: 0 1 200px; width: auto; }
.archive-filter .filter-status {
  flex-basis: 100%;
  margin: 0;
  font-size: 0.82rem;
  color: var(--muted);
}
.archive-filter .filter-status .listing-notice-action { margin-left: 8px; }
@media (max-width: 600px) {
  .archive-filter .filter-search,
  .archive-filter .filter-select { flex-basis: 100%; }
}

/* Tags under the author line ("PvP, Waves"), plus the Emperor's editor. */
.card-pages {
  font-size: 0.74rem;
  color: var(--muted);
  overflow-wrap: anywhere;
}
.card-pages .card-pages-edit { margin-left: 8px; font-size: inherit; }
.card-pages-editor {
  display: flex;
  flex-direction: column;
  gap: 8px;
  margin: 6px 0;
  padding: 10px;
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.3);
  font-size: 0.8rem;
}
.page-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.page-chips-empty { color: var(--muted); }
.page-chip {
  display: inline-flex;
  align-items: center;
  gap: 4px;
  padding: 2px 4px 2px 10px;
  border: 1px solid var(--panel-border);
  border-radius: 999px;
  color: var(--text);
}
.page-chip button {
  padding: 0 6px;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
}
.page-chip button:hover { color: var(--danger); }
.page-add { display: flex; gap: 6px; }
.page-add .form-input { padding: 6px 10px; font-size: 0.82rem; }
.page-auto { color: var(--muted); line-height: 1.4; }
.page-error { margin: 0; color: var(--danger); }
.page-actions { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }

/* Tag picker (tag-picker.js), on the archive and the submit form. */
.tag-picker { display: flex; flex-direction: column; gap: 6px; }
.tag-input-wrap { position: relative; }
.tag-options {
  position: absolute;
  z-index: 20;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  max-height: 220px;
  overflow-y: auto;
  margin: 0;
  padding: 4px 0;
  list-style: none;
  background: rgb(20, 14, 36);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.5);
}
.tag-option {
  padding: 6px 12px;
  font-size: 0.85rem;
  color: var(--text);
  cursor: pointer;
}
.tag-option.active { background: var(--accent-soft); }
.tag-option-hint { color: var(--muted); }
.tag-option-create { color: var(--muted); font-style: italic; }
.tag-option-invalid { color: var(--danger); cursor: default; }

/* Tampermonkey auto-update guide (guide.js). */
.guide-link { margin-left: 8px; font-size: inherit; }
html.guide-open { overflow: hidden; }
.guide-overlay {
  position: fixed;
  inset: 0;
  z-index: 2147483600;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 16px;
  background: rgba(4, 2, 10, 0.88);
}
.guide-panel {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 14px;
  width: min(1000px, 100%);
  max-height: calc(100vh - 32px);
  overflow-y: auto;
  padding: 24px 24px 18px;
  background: rgb(18, 12, 32);
  border: 1px solid var(--panel-border);
  border-radius: 12px;
  box-shadow: 0 16px 48px rgba(0, 0, 0, 0.6);
  color: var(--text);
  outline: none;
}
.guide-close {
  position: absolute;
  top: 8px;
  right: 10px;
  padding: 2px 8px;
  border: 0;
  background: none;
  color: var(--muted);
  font-size: 1.6rem;
  line-height: 1;
  cursor: pointer;
}
.guide-close:hover { color: var(--text); }
.guide-body { display: flex; flex-direction: column; gap: 12px; touch-action: pan-y; transition: transform 0.15s; }
.guide-body.guide-dragging { transition: none; user-select: none; }
/* Arrows flanking the picture (guide.js). */
.guide-arrow {
  position: absolute;
  top: 50%;
  width: 40px;
  height: 56px;
  transform: translateY(-50%);
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  background: rgba(15, 10, 30, 0.85);
  color: var(--accent);
  font-size: 2rem;
  line-height: 1;
  cursor: pointer;
}
.guide-arrow-prev { left: 8px; }
.guide-arrow-next { right: 8px; }
.guide-arrow:hover { background: rgba(242, 192, 114, 0.15); }
.guide-arrow:disabled { opacity: 0.3; cursor: default; }
.guide-title { margin: 0 32px 0 0; color: var(--accent); font-size: 1.3rem; }
.guide-count { margin: 0; color: var(--muted); font-size: 0.8rem; letter-spacing: 0.08em; text-transform: uppercase; }
.guide-img {
  -webkit-user-drag: none; user-select: none;
  display: block;
  max-width: 100%;
  max-height: 60vh;
  margin: 0 auto;
  border-radius: 8px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  cursor: pointer;
}
.guide-text { margin: 0; font-size: 1rem; line-height: 1.5; }
.guide-dots { display: flex; justify-content: center; gap: 8px; }
.guide-dots button {
  width: 10px;
  height: 10px;
  padding: 0;
  border: 1px solid var(--panel-border);
  border-radius: 50%;
  background: transparent;
  cursor: pointer;
}
.guide-dots button.active { background: var(--accent); border-color: var(--accent); }
.guide-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px; }
.guide-off { color: var(--muted); font-size: 0.85rem; }
.guide-nav { display: flex; flex-wrap: wrap; gap: 8px; }
@media (max-width: 600px) {
  .guide-panel { padding: 20px 14px 14px; }
  .guide-foot, .guide-nav { flex-direction: column; align-items: stretch; }
}

/* Updates & installs: the floating window (updates.js). */
.upd-window {
  position: fixed;
  z-index: 2147482000;
  display: flex;
  align-items: stretch;
  max-height: 70vh;
  color: var(--text);
  font-size: 0.82rem;
  line-height: 1.4;
  background: rgb(21, 13, 34);
  border: 1px solid var(--accent);
  border-radius: 10px;
  box-shadow: 0 8px 28px rgba(0, 0, 0, 0.6);
}
[data-ui="off"] .upd-window { display: none; }
.upd-main { display: flex; flex-direction: column; width: 430px; max-width: 100vw; min-height: 0; }
.upd-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background: rgb(36, 22, 56);
  border-radius: 10px 10px 0 0;
  color: var(--accent);
  font-weight: 700;
  cursor: move;
  user-select: none;
  touch-action: none;
}
.upd-minimized .upd-head { border-radius: 10px; }
.upd-head-btns { display: flex; gap: 2px; }
.upd-hbtn { padding: 0 6px; border: 0; background: none; color: var(--muted); font-size: 1.1rem; line-height: 1; cursor: pointer; }
.upd-hbtn:hover { color: var(--text); }
.upd-dock { font-size: 0.95rem; }
/* Docked: pinned to the bottom edge, no dragging, the header is the handle.
   On a wide screen it keeps its width and sits in the bottom-right corner;
   the phone rule below stretches it across. */
.upd-docked { left: auto !important; right: 16px; top: auto !important; bottom: 0; max-height: 75vh; border-radius: 10px 10px 0 0; border-bottom-width: 0; }
.upd-docked .upd-head { cursor: pointer; border-radius: 10px 10px 0 0; }
.upd-docked.upd-minimized .upd-head { border-radius: 10px 10px 0 0; }
.upd-docked.upd-with-pane .upd-head { border-radius: 10px 0 0 0; }
.upd-tools, .upd-bar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px;
  padding: 6px 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.upd-bar { background: rgba(242, 192, 114, 0.1); }
.upd-bar-text { flex: 1 1 100%; }
.upd-bar-btns { display: flex; gap: 6px; }
.upd-bar-hint { flex: 1 1 100%; color: var(--muted); font-size: 0.74rem; }
.upd-spacer { flex: 1; }
.upd-btn {
  padding: 4px 9px;
  border: 0;
  border-radius: 5px;
  background: rgb(58, 42, 85);
  color: var(--text);
  font: inherit;
  cursor: pointer;
}
.upd-btn:hover { background: rgb(74, 55, 106); }
.upd-btn:disabled { opacity: 0.5; cursor: default; }
.upd-btn.upd-go { background: var(--accent); color: #1a1020; font-weight: 700; }
.upd-list { flex: 1; min-height: 0; overflow-y: auto; }
.upd-row {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 5px 12px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.05);
}
.upd-row:hover { background: rgba(255, 255, 255, 0.04); }
.upd-row.upd-active { background: rgba(242, 192, 114, 0.12); }
.upd-row input, .upd-nocheck { flex: 0 0 14px; width: 14px; margin: 0; }
.upd-name {
  flex: 1;
  min-width: 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  cursor: pointer;
}
.upd-name:hover { color: var(--accent); }
.upd-opened .upd-name { color: var(--muted); }
.upd-ver { color: var(--muted); font-size: 0.72rem; }
.upd-when { flex: 0 0 auto; color: var(--muted); font-size: 0.72rem; white-space: nowrap; }
.upd-icon, .upd-mark {
  flex: 0 0 22px;
  width: 22px;
  height: 22px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--muted);
  font: inherit;
  cursor: pointer;
}
.upd-icon svg { display: block; margin: auto; }
.upd-icon:hover, .upd-icon.upd-icon-on { color: var(--accent); }
.upd-mark { color: #82c882; }
.upd-mark:hover:not(:disabled) { background: rgba(255, 255, 255, 0.08); }
.upd-icon:disabled, .upd-mark:disabled { cursor: default; }
.upd-more {
  padding: 6px 12px;
  border: 0;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
  background: none;
  color: var(--accent);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.upd-legend { padding: 4px 12px; border-top: 1px solid rgba(255, 255, 255, 0.08); color: var(--muted); font-size: 0.7rem; }
.upd-foot { padding: 6px 12px; border-top: 1px solid rgba(255, 255, 255, 0.08); color: var(--muted); }
.upd-minimized .upd-main > :not(.upd-head), .upd-minimized .upd-pane { display: none; }
.upd-pane {
  display: flex;
  flex-direction: column;
  width: 360px;
  min-height: 0;
  border-left: 1px solid rgba(255, 255, 255, 0.1);
}
.upd-pane-head {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 8px 12px;
  background: rgb(36, 22, 56);
  border-radius: 0 10px 0 0;
  font-weight: 700;
}
.upd-with-pane .upd-head { border-radius: 10px 0 0 0; }
.upd-pane-body { flex: 1; min-height: 0; overflow-y: auto; padding: 4px 12px 10px; }
.upd-pane-item { margin-top: 10px; padding-top: 8px; border-top: 1px solid rgba(255, 255, 255, 0.14); font-weight: 700; }
.upd-pane-item:first-child { margin-top: 4px; padding-top: 0; border-top: 0; }
.upd-inline { padding: 2px 12px 8px 34px; background: rgba(0, 0, 0, 0.25); border-bottom: 1px solid rgba(255, 255, 255, 0.05); }
.upd-entry { padding: 8px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.06); }
.upd-entry:last-child { border-bottom: 0; }
.upd-entry-head { color: var(--accent); font-size: 0.76rem; }
/* Author-typed text: keep their line breaks, break anything unbreakable. */
.upd-entry-notes { margin-top: 3px; white-space: pre-wrap; overflow-wrap: anywhere; }
.upd-entry-by { margin-top: 4px; color: var(--muted); font-size: 0.72rem; overflow-wrap: anywhere; }
@media (max-width: 700px) {
  /* Always docked, as a full-width bottom sheet; no dock button. */
  .upd-docked { left: 0 !important; right: 0; border-width: 1px 0 0; }
  .upd-docked .upd-main { width: 100%; }
  .upd-dock { display: none; }
  /* Keep the status line and the restore button clear of the sheet's header. */
  .listing-notice, .ui-restore { bottom: 52px; }
}

/* Backdrop slider (display.js). The ticks under it are the old presets. */
.backdrop-ctl { position: relative; display: inline-block; width: 180px; padding-bottom: 13px; vertical-align: middle; }
.backdrop-range { display: block; width: 100%; margin: 0; accent-color: var(--accent); cursor: pointer; }
.backdrop-ticks { position: absolute; left: 0; right: 0; bottom: 0; height: 12px; }
.backdrop-tick {
  position: absolute;
  transform: translateX(-50%);
  padding: 0;
  border: 0;
  background: none;
  color: var(--muted);
  font: inherit;
  font-size: 0.66rem;
  line-height: 1;
  cursor: pointer;
}
.backdrop-tick:hover { color: var(--accent); }
.backdrop-tick:last-child { transform: translateX(-100%); }
.backdrop-val { min-width: 2.6em; color: var(--accent); font-size: 0.8rem; }
@media (max-width: 480px) { .backdrop-ctl { width: 140px; } }

/* Docs: the reading page (docs.html) and the write-a-doc form. */
/* overflow: clip, not hidden: hidden would make the panel the sidebars'
   scroll container and their position: sticky would never engage. */
.panel-docs { max-width: var(--panel-max); padding: 0; overflow: clip; }
.panel-docs > section { padding: 28px; }
.panel-docs > #state-docs { padding: 0; }
/* The strip (menu button + brand) stays at the top; the links row below it
   scrolls away with the page. */
.docs-strip {
  position: sticky;
  top: 0;
  z-index: 6;
  display: flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  padding: 4px 16px;
  background: rgb(21, 13, 34);
  border-bottom: 1px solid var(--panel-border);
}
.docs-top {
  display: flex;
  flex-wrap: wrap;   /* the Display row (.bar-options) breaks onto its own line */
  align-items: center;
  gap: 12px;
  padding: 8px 20px;
  border-bottom: 1px solid var(--panel-border);
}
.docs-options { margin-top: 2px; }
.docs-brand { font-family: 'Cinzel', serif; font-weight: 700; color: var(--accent); text-decoration: none; letter-spacing: 0.08em; }
.docs-top-title { color: var(--muted); letter-spacing: 0.14em; text-transform: uppercase; font-size: 0.8rem; }
.docs-top-links { margin-left: auto; display: flex; gap: 16px; }
.docs-menu[hidden] { display: none; }
/* One sidebar on the left; the layout's data-side (docs.js, applyLayout)
   says whether it is a column or a drawer. Width decisions are made in JS
   from the layout's own width, not in container queries: a query cannot
   style its own container, which is how the old right column kept its
   space after its contents were hidden. */
.docs-layout {
  display: grid;
  grid-template-columns: 260px minmax(0, 1fr);
  align-items: start;
}
.docs-layout[data-side="menu"] { grid-template-columns: minmax(0, 1fr); }
.docs-side {
  position: sticky;
  top: 44px;                       /* below the strip */
  max-height: calc(100vh - 44px);
  overflow-y: auto;
  padding: 16px 16px 20px;
  border-right: 1px solid rgba(255, 255, 255, 0.08);
}
/* As a drawer it stays rendered off-screen and slides in from the left. */
.docs-layout[data-side="menu"] .docs-side {
  position: fixed;
  top: 0;
  bottom: 0;
  left: 0;
  width: min(340px, 90vw);
  max-height: none;
  z-index: 2147482500;
  background: rgb(21, 13, 34);
  border-right: 1px solid var(--accent);
  box-shadow: 8px 0 28px rgba(0, 0, 0, 0.6);
  transform: translateX(-100%);
  visibility: hidden;
  transition: transform 0.22s ease, visibility 0s linear 0.22s;
}
.docs-layout[data-side="menu"] .docs-side.open { transform: none; visibility: visible; transition: transform 0.22s ease; }
.docs-side-backdrop { position: fixed; inset: 0; z-index: 2147482400; background: rgba(0, 0, 0, 0.45); opacity: 0; pointer-events: none; transition: opacity 0.2s; }
.docs-side-backdrop.show { opacity: 1; pointer-events: auto; }
@media (prefers-reduced-motion: reduce) {
  .docs-layout[data-side="menu"] .docs-side, .docs-side-backdrop { transition: none; }
}
.docs-side-head { display: none; align-items: center; justify-content: space-between; margin-bottom: 10px; color: var(--muted); font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; }
.docs-side.open .docs-side-head { display: flex; }
.docs-side-close { padding: 0 6px; border: 0; background: none; color: var(--muted); font-size: 1.3rem; line-height: 1; cursor: pointer; }
.docs-side-close:hover { color: var(--text); }
/* Pages / Contents categories. */
.docs-cat { margin-bottom: 14px; }
.docs-cat-head { margin: 0 0 8px; font-family: 'Cinzel', serif; font-weight: 400; font-size: 0.9rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--accent); }
.docs-cat.collapsed .docs-cat-body { display: none; }
.docs-cat[hidden] { display: none; }
.docs-side .form-input { padding: 7px 10px; font-size: 0.85rem; margin-bottom: 12px; }
/* The contents list, nested by heading level. */
.docs-toc .docs-link { font-size: 0.8rem; color: var(--muted); padding: 3px 10px; }
.docs-toc-3 .docs-link { padding-left: 22px; }
.docs-toc-4 .docs-link { padding-left: 34px; font-size: 0.76rem; }
.doc-toc { margin: 0 0 18px; padding: 8px 14px; border: 1px solid var(--panel-border); border-radius: 8px; background: rgba(0, 0, 0, 0.2); }
.doc-toc[hidden] { display: none; }
.doc-toc summary { cursor: pointer; color: var(--accent); font-size: 0.8rem; letter-spacing: 0.12em; text-transform: uppercase; }
.doc-toc .docs-list { margin-top: 6px; }
.docs-group {
  margin: 14px 0 6px;
  color: var(--muted);
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
.docs-group:first-child { margin-top: 0; }
.docs-list { list-style: none; margin: 0; padding: 0; }
.docs-link {
  display: block;
  width: 100%;
  padding: 5px 10px;
  border: 0;
  border-left: 2px solid transparent;
  background: none;
  color: var(--text);
  font: inherit;
  font-size: 0.88rem;
  text-align: left;
  text-decoration: none;
  overflow-wrap: anywhere;
  cursor: pointer;
}
.docs-link:hover { color: var(--accent); }
.docs-link.active { color: var(--accent); border-left-color: var(--accent); background: rgba(242, 192, 114, 0.08); }
.docs-empty { color: var(--muted); font-size: 0.85rem; }
.docs-main { min-width: 0; padding: 28px 36px 40px; }
.docs-wait { text-align: left; }
.docs-head h1 { margin: 0 0 6px; text-align: left; font-size: 1.8rem; letter-spacing: 0.02em; }
.docs-meta { margin: 0 0 22px; color: var(--muted); font-size: 0.8rem; }
.docs-meta .docs-edit { margin-left: 14px; }
.docs-pager {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
  margin-top: 40px;
  padding-top: 20px;
  border-top: 1px solid rgba(255, 255, 255, 0.08);
}
.docs-pager-link {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 10px 14px;
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  text-decoration: none;
  color: var(--text);
}
.docs-pager-link:hover { border-color: var(--accent); }
.docs-next { text-align: right; }
.docs-pager-label { color: var(--muted); font-size: 0.72rem; text-transform: uppercase; letter-spacing: 0.1em; }
.docs-pager-name { color: var(--accent); }

/* Rendered Markdown, on the page and in the form's preview. */
.doc-body { line-height: 1.65; font-size: 0.97rem; overflow-wrap: anywhere; }
.doc-body > :first-child { margin-top: 0; }
.doc-body h1, .doc-body h2, .doc-body h3, .doc-body h4 { text-align: left; letter-spacing: 0.01em; line-height: 1.3; }
.doc-body h1 { font-size: 1.5rem; margin: 1.6em 0 0.5em; }
.doc-body h2 { font-size: 1.25rem; margin: 1.8em 0 0.5em; padding-bottom: 6px; border-bottom: 1px solid rgba(255, 255, 255, 0.1); scroll-margin-top: 56px; }
.doc-body h3 { font-size: 1.05rem; margin: 1.4em 0 0.4em; color: var(--accent); scroll-margin-top: 56px; }
.doc-body h4 { scroll-margin-top: 56px; }
.doc-body p, .doc-body ul, .doc-body ol { margin: 0 0 1em; }
.doc-body ul, .doc-body ol { padding-left: 1.5em; }
.doc-body li { margin: 0.25em 0; }
.doc-body a { color: var(--accent); }
.doc-body img { max-width: 100%; height: auto; border-radius: 8px; border: 1px solid rgba(255, 255, 255, 0.08); }
.doc-body hr { border: 0; border-top: 1px solid rgba(255, 255, 255, 0.12); margin: 2em 0; }
.doc-body code {
  padding: 0.1em 0.35em;
  border-radius: 4px;
  background: rgba(255, 255, 255, 0.08);
  font-family: ui-monospace, 'Cascadia Code', 'Fira Code', Consolas, monospace;
  font-size: 0.88em;
}
.doc-body pre {
  margin: 0 0 1em;
  padding: 12px 14px;
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.45);
  border: 1px solid rgba(255, 255, 255, 0.08);
  overflow-x: auto;
}
.doc-body pre code { padding: 0; background: none; font-size: 0.85rem; white-space: pre; overflow-wrap: normal; }
.doc-body blockquote { margin: 0 0 1em; padding: 4px 14px; border-left: 3px solid rgba(255, 255, 255, 0.2); color: var(--muted); }
.doc-body blockquote > :last-child { margin-bottom: 0; }
/* Callouts: GitHub's five kinds (plus Info as Note), each its own colour and icon. */
.doc-callout { padding: 10px 14px !important; border-radius: 0 8px 8px 0; color: var(--text) !important; background: rgba(255, 255, 255, 0.04); border-left-color: var(--callout) !important; }
.doc-callout-label { display: flex; align-items: center; gap: 6px; margin-bottom: 4px; color: var(--callout); font-size: 0.74rem; font-weight: 700; letter-spacing: 0.1em; text-transform: uppercase; }
.doc-callout-label svg { width: 16px; height: 16px; fill: none; stroke: currentColor; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; }
.doc-callout-note      { --callout: #7fa8e6; }
.doc-callout-tip       { --callout: #82c882; }
.doc-callout-important { --callout: #b58ef0; }
.doc-callout-warning   { --callout: #e6b85c; }
.doc-callout-caution   { --callout: #e8706a; }
.doc-table { margin: 0 0 1em; overflow-x: auto; }
.doc-body table { border-collapse: collapse; font-size: 0.9rem; }
.doc-body th, .doc-body td { padding: 6px 12px; border: 1px solid rgba(255, 255, 255, 0.12); text-align: left; vertical-align: top; }
.doc-body th { background: rgba(255, 255, 255, 0.06); }
.doc-body td > ul, .doc-body td > ol, .doc-body td > p { margin: 0; }
.doc-body caption { padding: 4px 0; color: var(--muted); font-size: 0.8rem; }
/* Sections fold under their h2 / h3 (markdown.js). */
.doc-fold { cursor: pointer; }
.doc-fold-chevron { display: inline-block; width: 8px; height: 8px; margin-right: 10px; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg) translate(-2px, -2px); transition: transform 0.15s; vertical-align: 2px; }
.doc-sec.collapsed > .doc-fold .doc-fold-chevron { transform: rotate(-45deg) translate(-1px, 1px); }
.doc-sec.collapsed > .doc-sec-body { display: none; }
.doc-sec.collapsed > h2 { margin-bottom: 0.9em; }
/* Code colours (highlight.js classes), in the site's palette. */
.hljs-comment, .hljs-quote { color: #8a8498; font-style: italic; }
.hljs-keyword, .hljs-selector-tag, .hljs-meta, .hljs-doctag { color: #e2b35a; }
.hljs-string, .hljs-regexp, .hljs-addition { color: #9fd49f; }
.hljs-number, .hljs-literal, .hljs-symbol, .hljs-bullet { color: #f0a070; }
.hljs-title, .hljs-section, .hljs-name, .hljs-selector-id, .hljs-selector-class { color: #8fc6ff; }
.hljs-attr, .hljs-attribute, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-built_in { color: #c9b4ff; }
.hljs-deletion { color: #e8706a; }
.hljs-emphasis { font-style: italic; }
.hljs-strong { font-weight: 700; }

/* A "Docs" link on a script card. */
.docs-card-link { margin-left: 4px; }

/* Write-a-doc form: editor and preview side by side. */
.panel-docform { max-width: min(1200px, 96vw); }
.docform-editor { display: grid; grid-template-columns: 1fr 1fr; gap: 12px; align-items: stretch; }
.docform-editor textarea { min-height: 420px; height: 100%; }
.docform-preview {
  min-width: 0;
  max-height: 640px;
  overflow-y: auto;
  padding: 10px 14px;
  border: 1px solid var(--panel-border);
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.25);
}
.docform-preview-label { margin-bottom: 8px; color: var(--muted); font-size: 0.72rem; letter-spacing: 0.12em; text-transform: uppercase; }
.docform-images { margin: 8px 0 0; padding-left: 0; list-style: none; font-size: 0.82rem; color: var(--muted); }
.docform-images li { margin: 2px 0; }
#markdown-size.over { color: var(--danger); font-weight: 700; }

/* A narrow panel (data-narrow from docs.js): tighter article padding. The
   sidebar is already the drawer there (data-side="menu"). */
.docs-layout[data-narrow="1"] .docs-main { padding: 20px 16px 32px; }
.docs-layout[data-narrow="1"] .docs-pager { grid-template-columns: 1fr; }
@media (max-width: 760px) {
  .docs-strip { padding: 4px 12px; }
  .docs-top { padding: 8px 14px; }
  .docs-top-links { width: 100%; margin-left: 0; }
  .docform-editor { grid-template-columns: 1fr; }
  .docform-editor textarea { min-height: 300px; }
}
.docs-toolbar-select { padding: 4px 6px; border: 1px solid rgba(255, 255, 255, 0.12); border-radius: 6px; background: rgb(36, 22, 56); color: var(--text); font: inherit; font-size: 0.82rem; }

/* Docs: in-page editing, history and status banners. */
.docs-h1 { margin: 0 0 6px; text-align: left; font-size: 1.6rem; letter-spacing: 0.02em; }
.docs-meta-link { margin-left: 14px; font-size: inherit; }
.docs-banner {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 12px;
  margin: 0 0 16px;
  padding: 8px 14px;
  border-radius: 8px;
  border: 1px solid var(--panel-border);
  background: rgba(0, 0, 0, 0.3);
  font-size: 0.85rem;
}
.docs-banner-ok { border-color: #82c882; color: #82c882; }
.docs-banner-warn { border-color: var(--accent); }
.docs-saving::after { content: ''; display: inline-block; width: 10px; height: 10px; border: 2px solid var(--muted); border-top-color: var(--accent); border-radius: 50%; animation: docs-spin 0.8s linear infinite; }
@keyframes docs-spin { to { transform: rotate(360deg); } }
.docs-history { margin: 0 0 16px; padding-left: 0; list-style: none; }
.docs-history li { padding: 8px 0; border-bottom: 1px solid rgba(255, 255, 255, 0.08); font-size: 0.9rem; }
.docs-history-by, .docs-history-current { color: var(--muted); }
.docs-history .listing-notice-action { margin-left: 12px; }
.docs-editor .form-row { margin-bottom: 16px; }
.docs-toolbar { display: flex; flex-wrap: wrap; gap: 4px; margin-bottom: 6px; }
.docs-toolbar button {
  padding: 4px 9px;
  border: 1px solid var(--panel-border);
  border-radius: 5px;
  background: rgba(0, 0, 0, 0.25);
  color: var(--text);
  font: inherit;
  font-size: 0.78rem;
  cursor: pointer;
}
.docs-toolbar button:hover { border-color: var(--accent); color: var(--accent); }
.docs-actions { display: flex; align-items: center; gap: 12px; }
.docs-delete { color: var(--danger); }
@media (max-width: 760px) {
  .docs-actions { flex-wrap: wrap; }
}

/* Docs copy-link buttons: in the meta line, on headings (hover), in the sidebar (hover). */
.docs-copy {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: 0;
  border-radius: 4px;
  background: none;
  color: var(--muted);
  cursor: pointer;
  vertical-align: middle;
}
.docs-copy:hover { color: var(--accent); background: rgba(255, 255, 255, 0.08); }
.docs-copy svg { display: block; }
.docs-meta-copy svg { vertical-align: -2px; margin-right: 2px; }
.doc-heading { position: relative; }
.doc-heading .docs-copy-heading { margin-left: 6px; opacity: 0; transition: opacity 0.12s; }
.doc-heading:hover .docs-copy-heading, .docs-copy-heading:focus-visible { opacity: 1; }
.docs-nav-item { display: flex; align-items: center; }
.docs-nav-item .docs-link { flex: 1; min-width: 0; }
.docs-nav-item .docs-copy-nav { flex: 0 0 24px; opacity: 0; transition: opacity 0.12s; }
.docs-nav-item:hover .docs-copy-nav, .docs-copy-nav:focus-visible { opacity: 1; }
@media (hover: none) {
  .doc-heading .docs-copy-heading, .docs-nav-item .docs-copy-nav { opacity: 1; }
}
@keyframes doc-heading-flash {
  0%, 30% { background: rgba(242, 192, 114, 0.18); }
  100%    { background: transparent; }
}
.doc-heading-flash { animation: doc-heading-flash 3.2s ease-in-out; border-radius: 4px; }
@media (prefers-reduced-motion: reduce) { .doc-heading-flash { animation-duration: 0.01s; } }
.docs-history-row {
  width: 100%;
  padding: 0;
  border: 0;
  background: none;
  color: var(--text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}
.docs-history-row:hover .docs-history-when { color: var(--accent); }
