/* =====================================================================
   Discord client skin.

   A faithful-enough reproduction of Discord's current dark theme, sized
   to sit inside the site's column — which is fluid, so the client caps
   itself rather than taking whatever it is given. Everything here is
   presentation only — the demos in assets/js/demo.js decide what goes
   in it.

   Channel names, categories and colours are taken from the bot itself
   (tibia-bot @ dev); see demo.js for the per-value citations.
   ===================================================================== */

/* ---------------------------------------------------------------------
   The Discord typeface.

   Discord's own stack is `"gg sans", "Noto Sans", ...`. gg sans is
   proprietary — bundled with their app and served from their CDN — so it
   is neither shippable nor hotlinkable. Noto Sans is Discord's own first
   fallback and is what Discord itself renders when gg sans is missing,
   so vendoring it is both the closest match and the clean licensing
   answer (SIL OFL).

   Without this the stack fell through to Segoe UI on Windows, which is
   noticeably narrower and differently drawn — the client read as "a dark
   web page" rather than as Discord.

   Latin subset only: every string these demos render is Latin, and the
   full family is an order of magnitude larger for glyphs nothing uses.
   --------------------------------------------------------------------- */
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/noto-sans-latin-400-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 500;
  font-display: swap;
  src: url('../fonts/noto-sans-latin-500-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('../fonts/noto-sans-latin-600-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Noto Sans';
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url('../fonts/noto-sans-latin-700-normal.woff2') format('woff2');
}
/* Italic carries the guild rank on every death and activity embed. */
@font-face {
  font-family: 'Noto Sans';
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url('../fonts/noto-sans-latin-400-italic.woff2') format('woff2');
}

:root {
  --dc-rail: #1e1f22;
  --dc-side: #2b2d31;
  --dc-chat: #313338;
  --dc-embed: #2b2d31;
  --dc-text: #dbdee1;
  --dc-muted: #949ba4;
  --dc-inter: #b5bac1;
  --dc-strong: #f2f3f5;
  --dc-sel: #404249;
  --dc-hover: #35373c;
  --dc-link: #00a8fc;
  --dc-blurple: #5865f2;
  --dc-blurple-hi: #4752c4;
  --dc-green: #248046;
  --dc-green-hi: #1a6334;
  --dc-red: #da373c;
  --dc-red-hi: #a12828;
  --dc-grey: #4e5058;
  --dc-grey-hi: #6d6f78;
  --dc-bot: #e5ad3c;
  --dc-divider: #3f4147;
  --dc-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace;
}

/* ---------------------------------------------------------------- shell */
.dc {
  display: grid;
  /* Discord's geometry at 13/16 scale, so the whole client shrinks
     together rather than only the type. Discord: 16px text, 240px
     sidebar, 48px header, 40px avatar in a 72px gutter, 520px embed cap,
     80px thumbnail cap. Everything below is roughly that times 0.8125,
     which is what lets it still read as Discord rather than as a dark
     web page.

     The sidebar is that scale exactly — 240 x 0.8125. It used to be 172,
     trimmed below scale to buy the description column room back when the
     page was a fixed 720px and the client got 676 of it; the column is
     fluid now and that debt is paid. The avatar gutter and the thumbnail
     cap are still a little under scale, which is cheap and still buys
     the same room.

     Width is the column's, and the column is sized to this client — see
     the .wrap comment in site.css. There is no max-width here because
     there is nothing left to cap it against.

     Height is measured from #notifications, the one channel whose
     content is fixed rather than accumulating. Its Server Save
     Notifications button ends 718px into the feed and the feed's own
     bottom padding takes it to 740, so the feed needs 740, the channel
     header 40 and the two borders 2 — and the few over that are slack,
     because a client that lands exactly on its content grows a scrollbar
     the moment a font renders a pixel taller somewhere else.

     Deliberately not a vh: a share of a tall monitor cannot also be the
     height of a particular button. The longer feeds scroll, which is
     what a feed does — this is the one that should not have to. */
  grid-template-columns: 195px 1fr;
  height: 790px;
  /* Fully enclosed: nothing is attached beneath it any more. */
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--panel-border);
  /* Discord's own stack, verbatim. gg sans is listed first because a
     reader who has it installed should get the real thing; everyone else
     lands on the vendored Noto Sans above, which is what Discord falls
     back to as well. */
  font-family: "gg sans", "Noto Sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 13px;
  line-height: 1.375;
  -webkit-font-smoothing: antialiased;
}

/* min-height:0 on both columns. A flex child will not shrink below its
   content without it, so the inner scrollers never scroll and the client
   overflows its own height and gets clipped instead. */
.dc-side,
.dc-main { display: flex; flex-direction: column; min-width: 0; min-height: 0; }
.dc-side { background: var(--dc-side); }
.dc-main { background: var(--dc-chat); }

.dc-guild {
  height: 40px; flex: none; display: flex; align-items: center; gap: 7px;
  padding: 0 12px; color: var(--dc-strong); font-weight: 600; font-size: 14px;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2); cursor: default;
}
.dc-guild .dc-caret { margin-left: auto; color: var(--dc-inter); font-size: 11px; }

.dc-chans { flex: 1; overflow-y: auto; padding: 8px 8px 20px; }
.dc-cat {
  display: flex; align-items: center; gap: 4px;
  padding: 14px 2px 4px; font-size: 10.5px; font-weight: 700;
  text-transform: uppercase; color: var(--dc-muted); cursor: default;
  line-height: 1.3;
}
.dc-cat .arrow { font-size: 9px; flex: none; }
.dc-chan {
  display: flex; align-items: center; gap: 6px; width: 100%;
  padding: 6px 8px; margin: 1px 0; border: 0; border-radius: 4px;
  background: none; color: var(--dc-muted); font: inherit; font-weight: 500;
  cursor: pointer; text-align: left; line-height: 1.25;
}
.dc-chan .h { font-size: 15px; font-weight: 400; color: #80848e; flex: none; line-height: 1; }
.dc-chan .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 12px; }
.dc-chan:hover { background: var(--dc-hover); color: var(--dc-text); }
.dc-chan[aria-current="true"] { background: var(--dc-sel); color: var(--dc-strong); font-weight: 600; }
.dc-chan[aria-current="true"] .h { color: var(--dc-strong); }

/* ---------------------------------------------------------------- header */
.dc-top {
  height: 40px; flex: none; display: flex; align-items: center; gap: 8px; padding: 0 16px;
  box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2), 0 2px 4px rgba(0, 0, 0, 0.08); z-index: 2;
  color: var(--dc-strong); font-weight: 600;
}
.dc-top .h { font-size: 17px; font-weight: 400; color: #80848e; flex: none; }
.dc-top .nm { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: none; max-width: 55%; }
.dc-top .topic {
  margin-left: 8px; padding-left: 8px; border-left: 1px solid var(--dc-divider);
  color: var(--dc-muted); font-size: 11px; font-weight: 400;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.dc-scroll { flex: 1; overflow-y: auto; overflow-x: hidden; padding: 8px 0 20px; }

/* Discord's thin scroller, which is how both of these scroll in the real
   client. The gutter is eight pixels but the thumb is four: it carries a
   two-pixel transparent border and clips its own background to the
   padding box, so the bar is narrow while the target you can grab stays
   the full width. The track is transparent — a painted one draws a grey
   channel down the side of the panel for as long as it is scrollable,
   which is what made these read as heavier than the client's.

   Deliberately no `scrollbar-width: thin` here. Declaring it hands the
   whole scrollbar to the engine's own thin rendering and takes these
   rules out of play, and the engine's idea of thin is ten pixels — wider
   than Discord's eight, and without the inset that makes the thumb read
   as a hairline. Firefox, which has no ::-webkit-scrollbar to honour,
   gets it below instead. */
.dc-scroll::-webkit-scrollbar,
.dc-chans::-webkit-scrollbar { width: 8px; height: 8px; }
.dc-scroll::-webkit-scrollbar-track,
.dc-chans::-webkit-scrollbar-track { background: transparent; }
.dc-scroll::-webkit-scrollbar-thumb,
.dc-chans::-webkit-scrollbar-thumb {
  background: #1a1b1e; background-clip: padding-box;
  border: 2px solid transparent; border-radius: 4px;
}
.dc-scroll::-webkit-scrollbar-corner,
.dc-chans::-webkit-scrollbar-corner { background: transparent; }

/* The channel list keeps its thumb out of sight until a pointer is over
   the sidebar, as Discord's does — the names are the thing, and a bar
   parked beside them the whole time is one more edge to read past. */
.dc-chans::-webkit-scrollbar-thumb { background-color: transparent; }
.dc-side:hover .dc-chans::-webkit-scrollbar-thumb { background-color: #1a1b1e; }

/* Engines with no ::-webkit-scrollbar to apply — Firefox — where the
   standard properties are the only way to say any of this. Thin is the
   closest it offers, and `scrollbar-color` carries the thumb and the
   transparent track. Kept behind the query so it never reaches an engine
   that would take it in preference to the rules above. */
@supports not selector(::-webkit-scrollbar) {
  .dc-scroll { scrollbar-width: thin; scrollbar-color: #1a1b1e transparent; }
  .dc-chans { scrollbar-width: thin; scrollbar-color: transparent transparent; }
  .dc-side:hover .dc-chans { scrollbar-color: #1a1b1e transparent; }
}

/* --------------------------------------------------------------- message */
.msg { padding: 2px 12px 2px 50px; position: relative; margin-top: 13px; }
.msg:hover { background: #2e3035; }
.msg .av { position: absolute; left: 11px; top: 1px; width: 30px; height: 30px; border-radius: 50%; }
.msg .hd { display: flex; align-items: baseline; gap: 8px; margin-bottom: 2px; flex-wrap: wrap; }
.msg .who { color: var(--dc-bot); font-weight: 500; font-size: 14px; }
.msg .bot {
  background: var(--dc-blurple); color: #fff; font-size: 10px; font-weight: 500;
  border-radius: 3px; padding: 0 4px; height: 15px; line-height: 15px;
  display: inline-flex; align-items: center; gap: 2px; align-self: center;
}
.msg .ts { color: var(--dc-muted); font-size: 11px; font-weight: 500; }

/* ----------------------------------------------------------------- embed */
/* Discord sizes an embed to its content and only then caps it, so the
   boosted-boss post is a narrow card rather than a 440px band with two
   short lines adrift in it. inline-grid + fit-content is what gives that;
   a 1fr first column would stretch every embed to the cap. */
.emb {
  /* grid, NOT inline-grid: fit-content already shrinks the box, and going
     inline made two short embeds on one message sit side by side. Discord
     stacks them. */
  display: grid; grid-template-columns: 4px auto;
  width: fit-content; max-width: 462px;
  margin-top: 4px; border-radius: 4px; overflow: hidden;
  background: var(--dc-embed);
}
.emb .in { padding: 7px 13px 13px 10px; display: grid; grid-template-columns: auto auto; gap: 10px; }
.emb .body { min-width: 0; }
.emb .etitle { font-size: 14.5px; font-weight: 600; color: var(--dc-link); margin-bottom: 3px; line-height: 1.375; }
.emb .etitle.plain { color: var(--dc-strong); }
.emb .de { font-size: 13px; color: var(--dc-text); white-space: pre-wrap; word-wrap: break-word; }
/* Discord caps a thumbnail at 80x80 and scales DOWN to fit; it never
   scales up. Tibia sprites are 32 or 64 square, so forcing them into an
   80px box was inflating every one of them. max-* with auto keeps the
   sprite at its own size until it is too big, which is what Discord does.
   Many sprites also carry transparent padding, which is what makes them
   look vertically centred against short text. */
.emb .th {
  max-width: 56px; max-height: 56px; width: auto; height: auto;
  border-radius: 3px; align-self: start; image-rendering: pixelated;
}
/* An embed's attachment. Discord fits one into roughly 550x350 and makes
   it clickable to expand, so a tall board renders narrow rather than
   cropped — `contain`, never `cover`, or the code table loses its edges.
   Not pixelated: this one is rendered text, not a sprite. */
.emb .big-img {
  grid-column: 1 / -1; max-width: 100%; max-height: 290px;
  width: auto; object-fit: contain; object-position: left top;
  border-radius: 4px; margin-top: 8px; cursor: zoom-in;
}
.emb .foot { font-size: 11px; color: var(--dc-muted); margin-top: 8px; grid-column: 1 / -1; }

/* embed fields — Discord lays inline fields out in a 3-up grid */
.emb .fields { grid-column: 1 / -1; display: grid; grid-template-columns: repeat(3, 1fr); gap: 8px; margin-top: 8px; }
.emb .fld.wide { grid-column: 1 / -1; }
.emb .fld .fn { font-size: 13px; font-weight: 600; color: var(--dc-strong); margin-bottom: 2px; }
.emb .fld .fv { font-size: 13px; color: var(--dc-text); white-space: pre-wrap; }

/* markdown inside a description */
.emb a, .dc-md a { color: var(--dc-link); text-decoration: none; font-weight: 600; }
.emb a:hover, .dc-md a:hover { text-decoration: underline; }
.emb em { font-style: italic; }
.emb strong { font-weight: 700; }
.emb code, .dc-md code {
  font-family: var(--dc-mono); font-size: 12px; background: #1e1f22;
  color: var(--dc-text); padding: 1px 3px; border-radius: 3px;
}
/* Discord's ## and ### headings, which the online list and the statistics
   post both lean on for their section structure. */
/* Discord gives a markdown heading real room above it — without it the
   boosted post reads as one run-on line instead of a label and an answer. */
.emb .h2 { font-size: 17px; font-weight: 700; color: var(--dc-strong); margin: 14px 0 6px; line-height: 1.3; }
.emb .h3 { font-size: 14px; font-weight: 700; color: var(--dc-strong); margin: 14px 0 3px; line-height: 1.3; }
.emb .h2.first, .emb .h3.first { margin-top: 0; }

/* plain (non-embed) message body, used by the online list */
.dc-md { font-size: 13px; color: var(--dc-text); white-space: pre-wrap; word-wrap: break-word; }
.dc-md .h3 { font-size: 14px; font-weight: 700; color: var(--dc-strong); margin: 14px 0 3px; line-height: 1.3; }
.dc-md .h3.first { margin-top: 0; }

/* ----------------------------------------------------------------- emoji */
.e { width: 1.2em; height: 1.2em; vertical-align: -0.22em; margin: 0 0.02em; }

/* Bar segments butt together. The default emoji margin leaves a hairline
   between the colours, and the start/mid/end shapes exist precisely so
   the run reads as one solid bar rather than a row of blocks. The images
   are emitted with no whitespace between them, so zeroing the margin is
   all that is needed — but the vertical-align has to be consistent or the
   ends sit a pixel off the middles. */
.e.barseg {
  margin: 0; width: 1.35em; height: 1.35em;
  vertical-align: -0.3em; image-rendering: auto;
}

/* Discord tints a rendered <t:…> so it reads as a value the client worked
   out, not as words the author typed. */
.dc-ts {
  background: rgba(120, 125, 140, 0.24);
  border-radius: 3px;
  padding: 0 2px;
}
.e.big { width: 1.35em; height: 1.35em; vertical-align: -0.28em; }
/* Discord draws emoji in an embed title a shade larger than body text. The
   fixtures carry plain shortcodes, so the size belongs here rather than in a
   variant the caller has to remember to ask for. */
.emb .etitle .e { width: 1.3em; height: 1.3em; vertical-align: -0.25em; }

/* --------------------------------------------------------------- buttons */
.dc-row { display: flex; flex-wrap: wrap; gap: 7px; margin-top: 7px; max-width: 462px; }
/* Also worn by an anchor, where a component has somewhere to go — hence
   the explicit colour and no underline, which a <button> never needed. */
.dc-btn {
  display: inline-flex; align-items: center; gap: 6px;
  border: 0; border-radius: 3px; padding: 0 13px; height: 28px;
  font: inherit; font-size: 13px; font-weight: 500; color: #fff;
  text-decoration: none; cursor: pointer; transition: background-color 0.15s ease;
}
.dc-btn:hover { color: #fff; }
.dc-btn.primary { background: var(--dc-blurple); }
.dc-btn.primary:hover { background: var(--dc-blurple-hi); }
.dc-btn.success { background: var(--dc-green); }
.dc-btn.success:hover { background: var(--dc-green-hi); }
.dc-btn.danger { background: var(--dc-red); }
.dc-btn.danger:hover { background: var(--dc-red-hi); }
.dc-btn.secondary { background: var(--dc-grey); }
.dc-btn.secondary:hover { background: var(--dc-grey-hi); }
.dc-btn.link { background: var(--dc-grey); }
.dc-btn[disabled] { opacity: 0.5; cursor: not-allowed; }
.dc-btn .e { width: 1.15em; height: 1.15em; vertical-align: -0.2em; }
/* An emoji-only button (the notifications role row) is square-ish rather
   than a pill with nothing in it. */
.dc-btn.bare { padding: 0 12px; }
.dc-btn.bare .e { width: 1.3em; height: 1.3em; margin: 0; }

/* ------------------------------------------------- ephemeral reply */
/* Discord's answer to a component press: visible only to whoever pressed,
   and labelled as such. */
.dc-eph {
  margin-top: 8px; max-width: 462px;
  border-left: 4px solid var(--dc-grey); border-radius: 4px;
  background: rgba(78, 80, 88, 0.16); padding: 10px 14px;
}
.dc-eph .body { font-size: 13px; color: var(--dc-text); }
.dc-eph .tag { font-size: 11px; color: var(--dc-muted); margin-top: 6px; }
.dc-eph .tag span { color: var(--dc-link); cursor: pointer; }
.dc-eph .tag span:hover { text-decoration: underline; }

/* ------------------------------------------------------------ role chips */
.dc-mention {
  background: rgba(88, 101, 242, 0.3); color: #c9cdfb; border-radius: 3px;
  padding: 0 2px; font-weight: 500;
}

/* ------------------------------------------------------- forum (#spawns) */
.fr-bar {
  flex: none; display: flex; align-items: center; gap: 8px; padding: 10px 16px;
  border-bottom: 1px solid rgba(0, 0, 0, 0.2);
}
.fr-tag {
  border: 0; border-radius: 13px; padding: 4px 12px; font: inherit; font-size: 12px;
  font-weight: 600; background: #1e1f22; color: var(--dc-muted); cursor: pointer;
  display: inline-flex; align-items: center; gap: 6px;
}
.fr-tag[aria-pressed="true"] { background: var(--dc-sel); color: var(--dc-strong); }
.fr-tag .dot { width: 8px; height: 8px; border-radius: 50%; }
.fr-count { margin-left: auto; font-size: 12px; color: var(--dc-muted); }

.fr-list { padding: 12px 16px 20px; display: grid; gap: 10px; }
.fr-post {
  background: #2b2d31; border-radius: 8px; padding: 14px 16px; cursor: pointer;
  display: grid; grid-template-columns: 1fr auto; gap: 12px; align-items: start;
  border: 1px solid transparent; transition: border-color 0.15s ease;
}
.fr-post:hover { border-color: #3f4147; background: #303338; }
.fr-post[aria-expanded="true"] { border-color: var(--dc-blurple); }
/* The pinned board post. Discord floats a pinned thread above the rest of
   the forum and marks it, which is what tells a reader the codes live
   there rather than in whichever spawn they happen to open first. */
.fr-post.pinned { background: #2f3136; border-color: #3f4147; }
.fr-post.pinned:hover { border-color: var(--dc-blurple); }
.fr-post .pin {
  display: inline-flex; align-items: center; gap: 5px; margin-bottom: 6px;
  font-size: 11px; font-weight: 600; color: var(--dc-muted);
}
.fr-post .pin img { width: 12px; height: 12px; }

.fr-post .pill {
  display: inline-flex; align-items: center; gap: 5px; border-radius: 10px;
  padding: 2px 9px; font-size: 11px; font-weight: 600; margin-bottom: 6px;
}
.fr-post .pill .dot { width: 7px; height: 7px; border-radius: 50%; }
.fr-post .pill.free { background: rgba(46, 204, 113, 0.15); color: #3ecf8e; }
.fr-post .pill.claimed { background: rgba(218, 55, 60, 0.15); color: #f0777a; }
.fr-post .pt { font-size: 14px; font-weight: 600; color: var(--dc-strong); line-height: 1.3; }
.fr-post .pm { font-size: 12px; color: var(--dc-muted); margin-top: 4px; }
.fr-post .pm b { color: var(--dc-bot); font-weight: 500; }
.fr-post .pic { width: 52px; height: 52px; object-fit: contain; border-radius: 4px; image-rendering: pixelated; }
.fr-open { grid-column: 1 / -1; margin-top: 4px; }

/* ------------------------------------------------------- arrival flash */
@keyframes dc-arrive {
  from { background: rgba(88, 101, 242, 0.14); }
  to { background: transparent; }
}
.msg.new { animation: dc-arrive 1.6s ease-out; }
@media (prefers-reduced-motion: reduce) { .msg.new { animation: none; } }

/* --------------------------------------------------------- empty states */
.dc-empty {
  padding: 56px 24px; text-align: center; color: var(--dc-muted);
  font-size: 13px; line-height: 1.8;
}
.dc-empty .mark { font-size: 30px; color: #5d6069; margin-bottom: 8px; }
.dc-empty b { color: var(--dc-strong); }

/* -------------------------------------------------------- mobile: strip */
.dc-strip { display: none; }

@media (max-width: 680px) {
  .dc { grid-template-columns: 1fr; height: 76vh; min-height: 460px; }
  .dc-side { display: none; }

  .dc-strip {
    display: flex; gap: 6px; padding: 8px 10px; overflow-x: auto;
    background: var(--dc-side); box-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
    scrollbar-width: none; flex: none;
  }
  .dc-strip::-webkit-scrollbar { display: none; }
  .dc-strip button {
    flex: none; border: 0; border-radius: 13px; padding: 5px 11px;
    background: #1e1f22; color: var(--dc-muted); font: inherit; font-size: 12px;
    font-weight: 600; white-space: nowrap; cursor: pointer;
  }
  .dc-strip button[aria-current="true"] { background: var(--dc-sel); color: var(--dc-strong); }

  /* Discord's 68px avatar gutter costs a fifth of a 375px screen, and a
     440px embed then wraps every three words. Shrink the gutter, let the
     embed use the column, and step the type down one notch. */
  .msg { padding: 2px 10px 2px 46px; }
  .msg .av { width: 28px; height: 28px; left: 10px; top: 2px; }
  .msg .who { font-size: 14px; }
  .emb, .dc-row { max-width: 100%; }
  .emb .th { max-width: 56px; max-height: 56px; }
  .emb .in { padding: 8px 12px 12px 10px; gap: 8px; }
  .emb .etitle { font-size: 15px; }
  .emb .de, .dc-md { font-size: 13.5px; }
  .emb .fields { grid-template-columns: repeat(2, 1fr); }
  .dc-top .topic { display: none; }
  .dc-btn { padding: 0 12px; font-size: 13px; }
  .fr-list { padding: 10px 12px 20px; }
}
