/*
 * One hand-written stylesheet, served from this origin. No framework, no CDN,
 * no web font - the whole site is a landing page and forms, and
 * Bootstrap would be more bytes than everything else here combined.
 *
 * Dark by default and deliberately not theme-switching: there is no JavaScript
 * on this site to remember a preference, and a single committed look is
 * honest about that rather than half-implementing it.
 */

:root {
    /* Black and red. The greys are near-neutral with a trace of red in them so
       the surfaces sit under the accent rather than beside it. */
    --bg: #0a0a0c;
    --surface: #131316;
    --surface-raised: #1a1a1f;
    --border: #2b2b32;
    --text: #ececee;
    --text-muted: #9a9aa4;

    /* TWO reds, and the split is load-bearing. --accent fills things - buttons,
       borders, the focus ring - where it sits under white text. --accent-soft is
       the one that IS the text: #d21f27 as small type on #0a0a0c is under 4:1
       and fails to read, while the same red lightened clears 6:1. Using one for
       both is how a red site ends up with unreadable links. */
    --accent: #d21f27;
    --accent-soft: #ff6a63;

    /* The offline red is deliberately NOT the accent. They are both red, so the
       thing that separates "this is our colour" from "this is bad news" is that
       the state red is lighter and warmer - and, as ever, that the heading says
       the word. */
    --online: #3fb950;
    --offline: #ff8178;
    --unknown: #d29922;

    /* Two washes, used only behind the hero: a red ember from above and a
       darker one from below. Both are alpha so they sit on --surface rather
       than replacing it - a hero on a page with the maintenance banner up
       should still read as the same surface. */
    --glow-warm: rgba(210, 31, 39, 0.26);
    --glow-cool: rgba(120, 8, 16, 0.35);

    /* The card wash. Every box that holds text - hero, panel, form, feature,
       step, status card - wears this, so no page has flat black cards next to
       another page's lit red ones. The translucent dark base is what keeps the
       text readable over the backdrop art; the two glows sit on top of it. */
    --card-wash:
        radial-gradient(90% 120% at 50% -20%, var(--glow-warm), transparent 62%),
        radial-gradient(70% 90% at 12% 115%, var(--glow-cool), transparent 60%),
        linear-gradient(180deg, rgba(29, 32, 41, 0.76) 0%, rgba(19, 19, 22, 0.68) 55%, rgba(23, 26, 33, 0.76) 100%);

    /* Discord's blurple is reserved for the community panel's background wash. */
    --discord: #5865f2;
}

* {
    box-sizing: border-box;
}

html {
    /* The system stack. No web font means no third-party request, no layout
       shift while one loads, and nothing to fail closed on a slow connection. */
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
    line-height: 1.55;
}

body {
    margin: 0;
    background: var(--bg);
    color: var(--text);
    display: flex;
    flex-direction: column;
    min-height: 100vh;

    /* position: relative with no offset changes nothing about layout - it exists
       so body establishes its own stacking context. Without it, .abyss-backdrop's
       z-index: -1 below escapes past body's own background entirely (it has
       nothing to be "-1 relative to" except the root), which paints the solid
       --bg straight over it and the backdrop simply never appears. This is what
       makes the fixed z-index: -1 trick behave the way it looks like it should. */
    position: relative;
}

.wrap {
    width: 100%;
    max-width: 46rem;
    margin: 0 auto;
    padding: 0 1.25rem;
}

/* Opted into by the landing page, the shop and the account access page, which
   lay cards out in a grid. 46rem is a reading measure and the right default for
   the forms and prose; it is the wrong one for six cards, which end up two
   columns of nearly nothing. The layout puts this class on the header, banner, body and footer
   together - widening only the body would leave the brand hanging inside the
   content it sits above. */
.wrap.wide {
    max-width: 64rem;
}

/* The landing page needs room for its original content measure plus the sticky
   community sidebar. Other wide pages keep the regular 64rem measure. */
.wrap.wide.landing-wide {
    max-width: 90rem;
}

/* --- Ambient backdrop ------------------------------------------------------ */
/*
 * "Eternal Abyss" behind every page: a rift of broken rings and cracks, radiating
 * from a point above the header, the hero's own warm/cool wash stretched across
 * the whole viewport, and - underneath both - the key art on a dark scrim.
 * The rings, cracks and gradients are inline SVG/CSS, same technique as the
 * icons; the key art is the one raster asset on the site, served from this
 * origin (wwwroot/img/), so it needs no CSP allowance beyond the img-src 'self'
 * nginx already sends.
 *
 * Fixed and z-index: -1 so it sits behind the header, the body and the footer
 * rather than above them - see the comment on `body` for the stacking-context
 * reason that actually makes that work. The scrim (a flat linear-gradient used
 * as an opacity trick, since background-image has no opacity of its own) is
 * most of the read here: the art has to stay texture behind the panels, never
 * compete with them for attention or drop a heading below the contrast this
 * site holds everywhere else - the rings and glows still have to be legible
 * drawn on top of it.
 */

.abyss-backdrop {
    position: fixed;
    inset: 0;
    z-index: -1;
    overflow: hidden;
    pointer-events: none;

    background:
        radial-gradient(65% 50% at 50% 0%, var(--glow-warm), transparent 72%),
        radial-gradient(55% 45% at 8% 100%, var(--glow-cool), transparent 68%),
        linear-gradient(rgba(10, 10, 12, 0.55), rgba(10, 10, 12, 0.55)),
        url("/img/abyss-backdrop.jpg") center / cover no-repeat;
}

.abyss-backdrop svg {
    width: 100%;
    height: 100%;
    display: block;
}

.abyss-backdrop .rift-ring {
    fill: none;
    stroke: var(--accent);
    stroke-width: 0.15;
    opacity: 0.3;
}

.abyss-backdrop .rift-crack {
    fill: none;
    stroke: var(--accent-soft);
    stroke-width: 0.12;
    opacity: 0.22;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* --- Header and footer --------------------------------------------------- */

.site-header {
    border-bottom: 1px solid var(--border);
    background: var(--surface);
}

.site-header .wrap {
    display: flex;
    align-items: center;
    justify-content: space-between;
    flex-wrap: wrap;
    gap: 0.5rem 1rem;
    min-height: 3.5rem;
    padding-top: 0.5rem;
    padding-bottom: 0.5rem;
}

.brand {
    display: flex;
    align-items: center;
    text-decoration: none;
}

.brand-logo {
    display: block;
    width: 8rem;
    height: 3rem;
    object-fit: contain;
}

nav {
    display: flex;
    /* Wraps, because the bar went from three entries to five or six and a
       narrow phone has nowhere to put them in one line. Column gap smaller than
       it was for the same reason. */
    flex-wrap: wrap;
    justify-content: flex-end;
    gap: 0.35rem 0.9rem;
}

nav a {
    color: var(--text-muted);
    text-decoration: none;
    padding: 0.25rem 0;
}

nav a:hover,
nav a:focus,
.brand:hover,
.brand:focus {
    color: var(--text);
}

main {
    flex: 1 0 auto;
    padding: 2rem 1.25rem 3rem;
}

.site-footer {
    border-top: 1px solid var(--border);
    background: var(--surface);
    color: var(--text-muted);
    font-size: 0.875rem;
    padding: 1rem 0;
}

/* One line until the Discord link joined it. Space-between rather than a gap so
   the two ends stay at the two ends of whatever measure the page chose, and
   wrap so they stack instead of colliding on a phone. */
.site-footer .wrap {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    gap: 0.35rem 1rem;
}

.site-footer a {
    color: var(--text-muted);
}

.site-footer a:hover,
.site-footer a:focus {
    color: var(--text);
}

/* --- Maintenance banner -------------------------------------------------- */

.banner {
    background: var(--unknown);
    color: #1a1600;
    font-weight: 600;
    padding: 0.75rem 0;
}

/* --- Status card --------------------------------------------------------- */

.status-card {
    background: var(--card-wash);
    border: 1px solid var(--border);

    /* The state is carried by a colour *and* by the wording in the heading.
       Colour alone would leave the page unreadable to anyone who cannot
       distinguish red from green, which for a two-state indicator is the whole
       message. */
    border-left: 4px solid var(--border);
    border-radius: 8px;
    padding: 1.5rem;
}

.status-card h1,
.status-card h2 {
    margin: 0;
    font-size: 1.5rem;
    font-weight: 400;
}

.status-card h1 strong,
.status-card h2 strong {
    font-weight: 700;
}

.status-card.online {
    border-left-color: var(--online);
}

.status-card.online h1 strong,
.status-card.online h2 strong {
    color: var(--online);
}

.status-card.offline {
    border-left-color: var(--offline);
}

.status-card.offline h1 strong,
.status-card.offline h2 strong {
    color: var(--offline);
}

.status-card.unknown {
    border-left-color: var(--unknown);
}

.status-card.unknown h1 strong,
.status-card.unknown h2 strong {
    color: var(--unknown);
}

.detail {
    margin: 0.75rem 0 0;
    color: var(--text-muted);
}

/* --- Panels -------------------------------------------------------------- */

.panel {
    background: var(--card-wash);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 1.25rem 1.5rem;
    margin-top: 1.5rem;
}

.panel h2 {
    margin: 0 0 0.5rem;
    font-size: 1rem;
    text-transform: uppercase;
    letter-spacing: 0.06em;
    color: var(--text-muted);
}

.panel p {
    margin: 0;
}

.panel.muted,
.muted-text {
    color: var(--text-muted);
    font-size: 0.9375rem;
}

/* --- Forms --------------------------------------------------------------- */

.page-title {
    margin: 0 0 1.5rem;
    font-size: 1.5rem;
    font-weight: 400;
}

.access-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1.25rem;
    align-items: start;
}

.access-option > h2 {
    margin: 0 0 0.75rem;
    font-size: 1.25rem;
}

.form-note {
    margin: 1rem 0 0;
}

@media (max-width: 52rem) {
    .access-grid {
        grid-template-columns: 1fr;
    }
}

.form {
    background: var(--card-wash);
    border: 1px solid var(--border);
    border-radius: 8px;
    padding: 1.5rem;
}

.field {
    margin-bottom: 1.25rem;
}

.field label {
    display: block;
    margin-bottom: 0.35rem;
    font-weight: 600;
}

.field input {
    width: 100%;
    padding: 0.6rem 0.7rem;
    background: var(--bg);
    color: var(--text);
    border: 1px solid var(--border);
    border-radius: 6px;
    font: inherit;
}

.field input:focus {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.hint {
    margin: 0.35rem 0 0;
    font-size: 0.875rem;
    color: var(--text-muted);
}

/* Errors are red AND are text next to the field they belong to. Colour alone
   would leave the message invisible to anyone who cannot see it, on the one
   part of the page whose whole job is to say what went wrong. */
.field-error {
    display: block;
    margin-top: 0.35rem;
    color: var(--offline);
    font-size: 0.9375rem;
}

.field-error:empty {
    display: none;
}

.field-error p {
    margin: 0 0 0.25rem;
}

/* A radio group inside a .field, which is only used by the reset link's
   "which account?" question. Issue #92.

   A fieldset rather than a bare list of labels, because the legend is what
   tells a screen reader that these radios are one question rather than several
   unrelated checkboxes. The cost is two browser defaults that match nothing
   else on these forms - the fieldset's own border and padding - and the
   inherited `.field input { width: 100% }`, which is right for a text box and
   absurd for a radio button. Both are undone here rather than by avoiding the
   fieldset. */
fieldset.field {
    border: 0;
    padding: 0;
    margin: 0 0 1.25rem;

    /* Fieldsets default to min-width:min-content, which stops them shrinking
       inside a flex or grid parent. Nothing here does that today; the line is
       one character of insurance against a layout change that would otherwise
       look like a bug in this rule. */
    min-width: 0;
}

fieldset.field legend {
    padding: 0;
    margin-bottom: 0.35rem;
    font-weight: 600;
}

/* .field label wins over a bare .choice on specificity, so the selector names
   both. The whole row is the label, so the account name is a click target
   rather than the 13-pixel circle beside it. */
.field label.choice {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0.5rem 0 0;
    padding: 0.55rem 0.7rem;
    border: 1px solid var(--border);
    border-radius: 6px;
    font-weight: 400;
    cursor: pointer;
}

.field label.choice:hover {
    border-color: var(--accent);
}

/* On the row, not the input: the radio's own outline would be drawn inside the
   bordered row and read as a smudge. */
.field label.choice:focus-within {
    outline: 2px solid var(--accent);
    outline-offset: 1px;
}

.field label.choice input[type="radio"] {
    width: auto;
    flex: none;
    margin: 0;
    accent-color: var(--accent);
}

.button {
    display: inline-block;
    padding: 0.6rem 1.4rem;
    background: var(--accent);

    /* White, not the near-black the gold button used. On #d21f27 the dark text
       that read well on gold drops to about 2:1; white clears 5:1. */
    color: #ffffff;
    border: none;
    border-radius: 6px;
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

.button:hover,
.button:focus {
    filter: brightness(1.1);
}

.button.secondary {
    background: transparent;
    color: var(--text);
    border: 1px solid var(--border);
}

.panel.notice {
    border-left: 4px solid var(--unknown);
}

code {
    background: rgba(255, 255, 255, 0.06);
    border: 1px solid var(--border);
    border-radius: 4px;
    padding: 0.1rem 0.35rem;
    font-size: 0.9em;
}

a {
    color: var(--accent-soft);
}

/* --- Landing page -------------------------------------------------------- */
/*
 * Everything below here exists for the home page and the shop. It is all CSS
 * and inline SVG: nginx sets style-src 'self', so there is no inline style
 * attribute anywhere in this project, and default-src 'none' means there is no
 * web font either. What life the page has, it has from gradients, one emblem
 * and a handful of icons drawn as paths.
 */

.hero {
    position: relative;
    overflow: hidden;
    border: 1px solid var(--border);
    border-radius: 14px;
    padding: 3rem 1.75rem 2.5rem;
    text-align: center;

    /* Warm from above, cool from below-left, on the same surface every other
       card uses. Layered gradients rather than an image: nothing to download,
       nothing to go stale, and it survives being rendered at any width. */
    background: var(--card-wash);
}

.hero-logo {
    display: block;
    width: min(100%, 48rem);
    height: auto;
    margin: 0 auto;
}

.hero.compact {
    padding: 2.25rem 1.75rem 2rem;
}

.hero h1 {
    margin: 0.75rem 0 0;
    font-size: 2.5rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);
}

.hero h2 {
    margin: 0.75rem 0 0;
    font-size: 1.75rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: var(--text);

    /* Overrides the .panel h2 rule, which is uppercase and muted. Nothing here
       is a panel, but the shop page puts a hero next to panels and the two
       headings must not read as the same level. */
    text-transform: none;
}

.tagline {
    margin: 0.6rem auto 0;
    max-width: 34rem;
    color: var(--text-muted);
    font-size: 1.0625rem;
}

.hero-note {
    margin: 0.9rem 0 0;
    color: var(--text-muted);
    font-size: 0.875rem;
}

/* The emblem: the text logo at the top of every compact hero. Width-led,
   because the art is 2.5:1 and a fixed height would squash it on a phone. */
.emblem {
    display: block;
    width: min(100%, 16rem);
    height: auto;
    margin: 0 auto;
    filter: drop-shadow(0 0 14px rgba(210, 31, 39, 0.55));
}

/* --- Status pill --------------------------------------------------------- */
/*
 * The status indicator, small enough to sit in a hero. The state is carried
 * by the words as well as the
 * colour, so the dot is decoration and never the message.
 */

.status-pill {
    display: inline-flex;
    align-items: center;

    /* Wraps rather than stretching into two tall lines of broken words: on a
       narrow phone the state and the timestamp stack, each still whole. */
    flex-wrap: wrap;
    justify-content: center;
    max-width: 100%;
    gap: 0.2rem 0.55rem;
    margin-top: 1.5rem;
    padding: 0.5rem 1rem;
    border: 1px solid var(--border);
    border-radius: 999px;
    background: rgba(0, 0, 0, 0.25);
    color: var(--text);
    font-size: 0.9375rem;
    text-decoration: none;
}

.status-pill .dot {
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: var(--unknown);
    box-shadow: 0 0 0 3px rgba(210, 153, 34, 0.18);
}

.status-pill .pill-state {
    font-weight: 600;
    white-space: nowrap;
}

.status-pill .pill-detail {
    color: var(--text-muted);
    white-space: nowrap;
}

.status-pill.online .dot {
    background: var(--online);

    /* The only animation on the site, and only on the state that is good news.
       Turned off below for anyone who has asked for less motion. */
    animation: pulse 2.4s ease-in-out infinite;
}

.status-pill.online .pill-state {
    color: var(--online);
}

.status-pill.offline .dot {
    background: var(--offline);
    box-shadow: 0 0 0 3px rgba(255, 129, 120, 0.18);
}

.status-pill.offline .pill-state {
    color: var(--offline);
}

@keyframes pulse {
    0%, 100% { box-shadow: 0 0 0 3px rgba(63, 185, 80, 0.20); }
    50%      { box-shadow: 0 0 0 6px rgba(63, 185, 80, 0.05); }
}

@media (prefers-reduced-motion: reduce) {
    .status-pill.online .dot {
        animation: none;
        box-shadow: 0 0 0 3px rgba(63, 185, 80, 0.20);
    }
}

/* --- Calls to action ----------------------------------------------------- */

.cta-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.75rem;
    margin: 1.5rem 0 0;
}

/* Only the hero centres its buttons; a panel keeps them on its own left edge. */
.panel .cta-row {
    justify-content: flex-start;
    margin-top: 1.25rem;
}

.button {
    /* Was inline-block, which is still what a submit button is. Inside a flex
       row the label has to be centred by this element rather than by the line
       box it no longer has. */
    text-align: center;
    text-decoration: none;
}

/* --- Section headings ---------------------------------------------------- */

.section-heading {
    margin: 2.5rem 0 1rem;
    font-size: 0.9375rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
}

.leaderboards-grid {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 1rem;
    margin-top: 2.5rem;
}

.leaderboards-grid .section-heading {
    margin-top: 0;
}

.leaderboards-grid .panel {
    margin-top: 0;
}

.leaderboard-card {
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1.25rem 1.5rem;
    background: var(--card-wash);
}

.nobility-rank {
    display: inline-flex;
    align-items: center;
    gap: 0.35rem;
    white-space: nowrap;
}

.nobility-place {
    min-width: 1.25rem;
    text-align: right;
}

.nobility-rank-icon {
    width: 2rem;
    height: 2rem;
    object-fit: contain;
}

.nobility-rank-text {
    width: 2.75rem;
    height: 2.75rem;
    object-fit: contain;
}

@media (max-width: 52rem) {
    .leaderboards-grid {
        grid-template-columns: 1fr;
    }
}

/* --- Feature cards ------------------------------------------------------- */

.feature-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 1rem;
}

.home-feature-grid {
    margin-top: 2.5rem;
}

/* --- Home page news board ------------------------------------------------ */
/*
 * One card holding everything: a header, two featured posts side by side, a
 * list of rows, and a footer link. The rows are hairline-separated rather than
 * boxed so the board reads as one object, not a grid of small cards.
 */

.news-board {
    margin-top: 2.5rem;
    border: 1px solid var(--border);
    border-radius: 12px;
    background: var(--card-wash);
    overflow: hidden;
}

.news-board-head {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 1.1rem 1.35rem;
    border-bottom: 1px solid var(--border);
}

.news-board-icon {
    display: grid;
    place-items: center;
    flex: none;
    width: 2.75rem;
    height: 2.75rem;
    border: 1px solid var(--border);
    border-radius: 10px;
    background: rgba(210, 31, 39, 0.12);
}

.news-board-icon svg {
    width: 1.35rem;
    height: 1.35rem;
    fill: none;
    stroke: var(--accent-soft);
    stroke-width: 1.8;
    stroke-linecap: round;
    stroke-linejoin: round;
}

.news-board-title {
    flex: 1;
    min-width: 0;
}

.news-board-title h2 {
    margin: 0;
    font-size: 1.0625rem;
    font-weight: 600;
}

.news-board-title p {
    margin: 0.1rem 0 0;
    color: var(--text-muted);
    font-size: 0.8125rem;
}

.news-view-all {
    color: var(--text-muted);
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: none;
    white-space: nowrap;
}

.news-view-all:hover,
.news-view-all:focus-visible {
    color: var(--text);
}

/* Featured: the two newest posts. No pictures yet, so the summary fills the
   space an image would - enough to make the card worth clicking. */
.news-featured {
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    border-bottom: 1px solid var(--border);
}

.news-card {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 0.5rem;
    padding: 1.25rem 1.35rem 1.35rem;
    color: var(--text);
    text-decoration: none;
    transition: background-color 0.15s;
}

.news-card + .news-card {
    border-left: 1px solid var(--border);
}

.news-card:hover,
.news-card:focus-visible {
    background: rgba(255, 255, 255, 0.03);
}

.news-card-title {
    font-size: 1.0625rem;
    font-weight: 700;
}

.news-card-summary {
    color: var(--text-muted);
    font-size: 0.875rem;
}

.news-list {
    margin: 0;
    padding: 0;
    list-style: none;
}

.news-list li + li {
    border-top: 1px solid var(--border);
}

.news-list a {
    display: flex;
    align-items: center;
    gap: 1rem;
    padding: 0.85rem 1.35rem;
    color: var(--text);
    text-decoration: none;
    transition: background-color 0.15s;
}

.news-list a:hover,
.news-list a:focus-visible {
    background: rgba(255, 255, 255, 0.03);
}

.news-row-title {
    flex: 1;
    min-width: 0;
}

.news-date {
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    color: var(--text-muted);
    font-size: 0.8125rem;
    white-space: nowrap;
}

.news-cal {
    width: 0.9rem;
    height: 0.9rem;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.8;
    stroke-linecap: round;
}

/* The badges. Outlined, tinted by kind; the word carries the meaning and the
   colour only helps the eye find it again. */
.news-tag {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    flex: none;
    min-width: 4.75rem;
    padding: 0.15rem 0.5rem;
    border: 1px solid currentColor;
    border-radius: 4px;
    font-size: 0.6875rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    line-height: 1.5;
}

.news-tag.tag-news        { color: var(--accent-soft); background: rgba(255, 106, 99, 0.10); }
.news-tag.tag-update      { color: #6ea8ff;            background: rgba(110, 168, 255, 0.10); }
.news-tag.tag-event       { color: #e3b341;            background: rgba(227, 179, 65, 0.10); }
.news-tag.tag-maintenance { color: #f0883e;            background: rgba(240, 136, 62, 0.10); }
.news-tag.tag-live        { color: var(--online);      background: rgba(63, 185, 80, 0.10); }

.news-tag.tag-live .dot {
    width: 0.45rem;
    height: 0.45rem;
    border-radius: 50%;
    background: var(--online);
    animation: pulse 2.4s ease-in-out infinite;
}

@media (prefers-reduced-motion: reduce) {
    .news-tag.tag-live .dot {
        animation: none;
    }
}

.news-board-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: space-between;
    gap: 0.5rem 1rem;
    margin: 0;
    padding: 0.9rem 1.35rem;
    border-top: 1px solid var(--border);
}

.news-clock {
    color: var(--text-muted);
    font-size: 0.8125rem;
}

.news-more {
    color: #e3b341;
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    text-decoration: none;
}

.news-more:hover,
.news-more:focus-visible {
    text-decoration: underline;
}

@media (max-width: 40rem) {
    .news-featured {
        grid-template-columns: minmax(0, 1fr);
    }

    .news-card + .news-card {
        border-left: 0;
        border-top: 1px solid var(--border);
    }

    /* Title on its own line, badge and date on the line under it. */
    .news-list a {
        flex-wrap: wrap;
        gap: 0.4rem 0.75rem;
    }

    .news-row-title {
        flex-basis: 100%;
        order: -1;
    }
}

/* /News */

.news-post .news-meta {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.news-post h3 {
    margin: 0.75rem 0 0.5rem;
    font-size: 1.25rem;
}

.news-post p + p {
    margin-top: 0.75rem;
}

.news-post {
    scroll-margin-top: 1rem;
}
.home-showcase-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
}

.garment-feature {
    grid-column: span 2;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: center;
    gap: 1.25rem;
}

.garment-feature h3 {
    margin-top: 0;
}

.garment-feature .feature-video {
    margin: 0;
    aspect-ratio: auto;
}

/* Four cards, not six. At the default track width they land three-and-one,
   which leaves the fourth sitting on its own with two thirds of a row beside
   it; a wider track makes it two-and-two. */
.feature-grid.pairs {
    grid-template-columns: repeat(auto-fit, minmax(24rem, 1fr));
}

.feature {
    background: var(--card-wash);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1.25rem 1.35rem 1.4rem;
}

.feature h3 {
    margin: 0.75rem 0 0.4rem;
    font-size: 1.0625rem;
    font-weight: 600;
}

.feature p {
    margin: 0;
    color: var(--text-muted);
    font-size: 0.9375rem;
}

.boss-feature {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: minmax(0, 0.8fr) minmax(0, 1.2fr);
    align-items: center;
    gap: 1.5rem;
}

.boss-feature h3 {
    margin-top: 0;
}

.feature-video {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    margin: 0;
    border-radius: 6px;
    background: #000;
    object-fit: contain;
}

@media (max-width: 42rem) {
    .home-showcase-grid {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }

    .garment-feature {
        grid-column: 1 / -1;
    }

    .boss-feature {
        grid-template-columns: 1fr;
    }
}

@media (max-width: 32rem) {
    .home-showcase-grid {
        grid-template-columns: 1fr;
    }

    .garment-feature {
        grid-template-columns: 1fr;
    }
}

/* One rule for every icon on the site. They are all 24x24 stroke drawings, so
   the fill is cleared here rather than on each path. */
.icon {
    width: 1.75rem;
    height: 1.75rem;
    fill: none;
    stroke: var(--accent-soft);
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
}

/* --- Numbered steps ------------------------------------------------------ */

.steps {
    list-style: none;
    counter-reset: step;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    gap: 1rem;
}

.steps li {
    counter-increment: step;
    background: var(--card-wash);
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1.25rem 1.35rem 1.4rem;
}

.steps li::before {
    content: counter(step);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 1.9rem;
    height: 1.9rem;
    border: 1px solid var(--accent);
    border-radius: 50%;
    color: var(--accent-soft);
    font-weight: 700;
    font-size: 0.9375rem;
}

.steps h3 {
    margin: 0.75rem 0 0.4rem;
    font-size: 1.0625rem;
    font-weight: 600;
}

.steps p {
    margin: 0;
    color: var(--text-muted);
    font-size: 0.9375rem;
}

/* --- Closing panel ------------------------------------------------------- */

.panel.closing {
    background:
        radial-gradient(80% 140% at 100% 0%, var(--glow-warm), transparent 60%),
        var(--card-wash);
}

.panel.closing h2 {
    color: var(--text);
}

/* Panels held only prose until the shop page put a list in one. */
.panel ul {
    margin: 0;
    padding-left: 1.15rem;
}

.panel li + li {
    margin-top: 0.4rem;
}

/* A feature card that is itself a link. The whole card is the target, so the
   heading is not separately clickable - one destination, one hit area. */
.feature.linked {
    display: block;
    color: inherit;
    text-decoration: none;
}

.feature.linked:hover,
.feature.linked:focus {
    border-color: var(--accent);
}

.feature.linked h3 {
    color: var(--accent-soft);
}

/* --- Landing page sidebar ------------------------------------------------ */

.landing-layout {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 24rem;
    align-items: start;
    gap: 1.5rem;
}

.landing-content {
    min-width: 0;
}

.community-sidebar {
    position: sticky;
    top: 1rem;
    align-self: start;
}

.community-sidebar .section-heading {
    display: none;
    margin-top: 0;
}

.panel.community {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    justify-items: center;
    margin-top: 0;
    padding: 1rem;

    /* Keep the shared translucent card treatment, with Discord's blue tint so
       the section reads as somewhere else before anybody reaches the heading. */
    background:
        radial-gradient(70% 130% at 0% 0%, rgba(88, 101, 242, 0.20), transparent 62%),
        var(--card-wash);
}

.panel.community h2 {
    /* The panel default is muted, which is right for a label above prose and
       wrong for the name of the thing this panel IS. */
    color: var(--text);
}

.community-widget {
    display: block;
    width: 350px;
    max-width: 100%;
    border: 0;
    border-radius: 6px;
    background: #232428;
}

@media (max-width: 80rem) {
    .wrap.wide.landing-wide {
        max-width: 64rem;
    }

    .landing-layout {
        grid-template-columns: minmax(0, 1fr);
    }

    .community-sidebar {
        position: static;
    }

    .community-sidebar .section-heading {
        display: block;
        margin-top: 2.5rem;
    }
}

/* --- Tables -------------------------------------------------------------- */
/*
 * The schedule and the server-info figures. Both are two or three columns of
 * short strings, which is a table and not a list: the reader is scanning down
 * one column for a day or a name, not reading across.
 */

.table-scroll {
    /* The page body must never scroll sideways, so the overflow belongs to the
       table's own box. Three columns of prose do not fit a 390px phone and no
       amount of shrinking will make them. */
    overflow-x: auto;

    /* A table standing on its own is a card like any other, or its rows sit
       straight on the backdrop art and are unreadable. */
    border: 1px solid var(--border);
    border-radius: 10px;
    padding: 1.25rem 1.5rem;
    background: var(--card-wash);
}

/* Already inside a card: a second border and wash would be a box in a box. */
.panel .table-scroll {
    border: 0;
    border-radius: 0;
    padding: 0;
    background: none;
}

table.data {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9375rem;
}

table.data th,
table.data td {
    padding: 0.6rem 0.9rem 0.6rem 0;
    text-align: left;
    vertical-align: top;
    border-bottom: 1px solid var(--border);
}

table.data tbody tr:last-child th,
table.data tbody tr:last-child td {
    border-bottom: none;
}

table.data thead th {
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    border-bottom-color: var(--accent);
}

table.data tbody th {
    font-weight: 600;
    color: var(--text);
    white-space: nowrap;
}

table.data td {
    color: var(--text-muted);
}

/* The column a reader is actually scanning. Kept on one line and given the
   accent so the eye can run down it without reading the rest. */
.schedule .when {
    color: var(--accent-soft);
    white-space: nowrap;
}

/* Second line inside the Where cell - the detail that would make a fourth
   column too wide to fit anywhere. */
.row-note {
    display: block;
    margin-top: 0.15rem;
    font-size: 0.875rem;
    opacity: 0.8;
}

/* A panel holding a table wants the table's own padding, not two lots. */
.panel .table-scroll {
    margin-top: 0.25rem;
}

/*
 * The schedule stops being a table on a phone.
 *
 * Three columns in 390px is not a narrow table, it is a table where the third
 * column is four words wide and every row grows to whatever that wrapping
 * costs - which was rows a screen tall with most of them empty. Sideways
 * scrolling instead only moves the problem: the column a reader came for is
 * then the one off the edge.
 *
 * So each row becomes a card and the header row goes away, its columns read
 * top to bottom instead of left to right. The markup does not change - this is
 * still a table, still one <th scope="row"> per event, and a screen reader
 * still gets the association.
 */
@media (max-width: 34rem) {
    .schedule thead {
        display: none;
    }

    .schedule,
    .schedule tbody,
    .schedule tr,
    .schedule tbody th,
    .schedule td {
        display: block;
        width: 100%;
    }

    .schedule tr {
        border: 1px solid var(--border);
        border-radius: 8px;
        padding: 0.85rem 1rem;
        margin-bottom: 0.75rem;
    }

    /* Qualified with table.data, and it has to be: the rule these override is
       `table.data th, table.data td`, which is more specific than a bare
       `.schedule td` and wins on cascade order regardless of where it sits.
       Without the qualifier the cards keep the column rules underneath every
       line. */
    table.data.schedule tbody th,
    table.data.schedule td {
        padding: 0;
        border-bottom: none;

        /* Both of these carry nowrap at full width, where they are columns. As
           blocks they have the whole card and must be allowed to use it. */
        white-space: normal;
    }

    .schedule tbody th {
        font-size: 1rem;
    }

    .schedule .when {
        margin-top: 0.1rem;
        font-weight: 600;
        white-space: normal;
    }

    .schedule td:last-child {
        margin-top: 0.4rem;
    }
}

/* --- Features page -------------------------------------------------------- */

/* .pairs's 24rem track is wider than a phone, so these grids cap the track at
   the column rather than scrolling the page sideways. */
.features-page,
.boss-roster {
    grid-template-columns: repeat(auto-fit, minmax(min(24rem, 100%), 1fr));
}

.feature-list {
    margin: 0;
    padding-left: 1.1rem;
    color: var(--text-muted);
    font-size: 0.9375rem;
}

.feature-list li + li {
    margin-top: 0.45rem;
}

.feature-list li::marker {
    color: var(--accent-soft);
}

.section-lede {
    max-width: 46rem;
    margin: -0.25rem 0 1.25rem;
    color: var(--text-muted);
}

.boss-roster .feature {
    background:
        radial-gradient(90% 120% at 100% -20%, var(--glow-warm), transparent 62%),
        var(--card-wash);
}

.boss-roster .feature h3 {
    margin-top: 0.2rem;
    font-size: 1.1875rem;
}

.feature .boss-when {
    margin: 0;
    color: var(--accent-soft);
    font-size: 0.8125rem;
    font-weight: 600;
    letter-spacing: 0.04em;
    text-transform: uppercase;
}

.panel.removed {
    margin-top: 2rem;
    border-left: 3px solid var(--accent);
}
