/* ==========================================================================
   pages.css - sub-page content.

   The reference pages carry markup written for the old skin: a decorative
   3x3 "tabletype1" wrapper, per-page class prefixes (cs-, ec-, rule-) and
   faction classes. Rather than rewrite ~60KB of hand-authored game data by
   hand - which risks silently mangling numbers - the old class names are
   restyled here against the new tokens. The content ports verbatim; only its
   appearance changes.
   ========================================================================== */

/* =============================================================== layout == */

.page {
    padding: 26px 0 48px;
}

.page-title {
    margin-bottom: 18px;
    font-size: 1.4rem;
    font-weight: 600;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--c-text);
}

/* Reference pages render at the FULL content width. No measure cap.

   There was a `max-width: 78ch` here, on the reasonable-sounding grounds that a
   1200px line of prose is hard to track back from. It was wrong for these pages
   and it is the whole of WE-0008:

     * It capped the CONTAINER, so it caught the tables too - `max-width: none`
       on a table cannot widen it past its containing block. Every one of the
       six pages rendered at roughly half width; 78ch is about 560px against a
       1200px content area.
     * Moving the cap to the children fixed the tables and left the prose at
       78ch. These pages OPEN with a contents box and several paragraphs, so the
       top of every one of them still read as half empty. Still not fixed.
     * The original site, which this markup was ported from, has no
       `.reference-content` rule at all and no character measure anywhere in its
       stylesheet. These pages are meant to be full width.

   They are reference material - contents lists, attribute tables, stat tables -
   not long-form prose, and `.shell` already bounds the line length at 1240px. */
.reference-content { max-width: none; }

.reference-content p { margin: 0 0 12px; color: var(--c-text); }
.reference-content h2 {
    margin: 30px 0 12px;
    font-size: var(--fs-lead);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-accent);
}
.reference-content h3 { margin: 22px 0 8px; font-size: var(--fs-body); }

.attribtitle {
    margin: 20px 0 6px !important;
    font-weight: 600;
    color: var(--c-accent);
}

/* Invisible scroll targets for the in-page contents lists. scroll-margin
   keeps the sticky header from covering whatever you just jumped to. */
.anchor { display: block; height: 0; scroll-margin-top: 76px; }

.contents {
    margin: 0 0 24px;
    padding: 14px 18px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
}
.contents li { padding: 3px 0; }
.contents li::before { content: "› "; color: var(--c-muted); }

.placeholder-note {
    padding: 14px;
    background: var(--c-subhead);
    border-left: 2px solid var(--c-accent);
    color: var(--c-muted);
    font-size: var(--fs-meta);
}

/* =============================================================== tables == */

/* The old skin drew borders with a 3x3 grid of decorative cells wrapped around
   the real table. Hiding those eight leaves two empty rows that collapse to
   nothing, and the inner table below picks up the real styling. */
.tabletype1 { width: 100%; border-collapse: collapse; background: none; }
.tabletype1 > tbody > tr > .tbltopleft,
.tabletype1 > tbody > tr > .tbltop,
.tabletype1 > tbody > tr > .tbltopright,
.tabletype1 > tbody > tr > .tblleft,
.tabletype1 > tbody > tr > .tblright,
.tabletype1 > tbody > tr > .tblbottomleft,
.tabletype1 > tbody > tr > .tblbottom,
.tabletype1 > tbody > tr > .tblbottomright { display: none; }
.tabletype1 > tbody > tr > td { padding: 0; }

/* Every data table on the site, however it was authored. */
.reference-content table,
.data-table,
.maptable {
    width: 100%;
    margin: 0 0 22px;
    border-collapse: collapse;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
    overflow: hidden;
    font-size: var(--fs-meta);
}

/* 14px horizontal to match .card-head, so a table's column labels line up with
   the card title directly above them instead of sitting 2px inside it. */
.reference-content th,
.data-table th,
.maptable th {
    padding: 9px 14px;
    background: var(--c-head);
    border-bottom: 1px solid var(--c-border);
    text-align: left;
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-muted);
    white-space: nowrap;
}

.reference-content td,
.data-table td,
.maptable td {
    padding: 8px 14px;
    border-bottom: 1px solid var(--c-rule);
    color: var(--c-text);
    vertical-align: top;
}

.reference-content tr:last-child td,
.data-table tr:last-child td { border-bottom: 0; }

/* The tabletype1 wrapper is scaffolding, not data. It has to out-specify the
   generic ".reference-content table" rule above (0,1,1), or it takes the card
   background and border and draws a second frame around the real table. */
.reference-content table.tabletype1 {
    margin: 0 0 22px;
    background: none;
    border: 0;
    border-radius: 0;
}
.reference-content table.tabletype1 > tbody > tr > td {
    padding: 0;
    border: 0;
    background: none;
}

/* Hover highlights a ROW, and only in real tables.
   The wrapper's middle cell contains the entire inner table, so letting it
   match tr:hover lit up everything at once. ":not(.tabletype1)" keeps the
   wrapper out, and the child combinator stops a hovered row from tinting cells
   of any table nested inside it. */
.reference-content table:not(.tabletype1) tbody tr:hover > td,
.data-table tbody tr:hover > td { background: var(--c-hover); }

/* Wide game-data tables must scroll inside their own box. Without this the
   page itself scrolls sideways on a phone, which breaks every other section. */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }

/* Emphasis columns, carried over from the old skin. */
.data-table td.col-name   { color: var(--c-accent); font-weight: 600; }
.data-table td.col-killer { font-weight: 600; }
.rank { color: var(--c-muted); font-variant-numeric: tabular-nums; width: 46px; }
.num  { text-align: right; font-variant-numeric: tabular-nums; }

/* ============================================================== factions == */

/* The old markup uses .ares / .elv for both nation names AND for good/bad
   emphasis in the spell tables. Same tints as the launcher. */
.ares, .nation-aresden { color: var(--c-aresden); }
.elv,  .nation-elvine  { color: var(--c-elvine); }

/* ================================================================ rules == */

.rule-card {
    margin-bottom: 14px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
    overflow: hidden;
}
.rule-head {
    display: flex;
    align-items: baseline;
    gap: 10px;
    padding: 11px 14px;
    background: var(--c-head);
    border-bottom: 1px solid var(--c-border);
}
.rule-num { color: var(--c-accent); font-weight: 700; font-variant-numeric: tabular-nums; }
.rule-title {
    font-size: var(--fs-body);
    font-weight: 600;
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
}
.rule-list { padding: 12px 14px 12px 32px; }
.rule-list li { margin-bottom: 7px; list-style: disc; color: var(--c-text); }
.rule-list li::marker { color: var(--c-muted); }
.toc-num { color: var(--c-accent); font-variant-numeric: tabular-nums; }
.rl-id { color: var(--c-muted); font-size: var(--fs-micro); }

/* ================================================================ forms == */

.form { max-width: 520px; }
.form label {
    display: block;
    margin: 0 0 5px;
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-muted);
}
.form-row { margin-bottom: 14px; }

/* `search` belongs in this list: the admin account picker and the news archive
   both use type="search" for the clear button and the on-screen keyboard it
   gets on mobile, and without it here they render as unstyled browser boxes. */
input[type="text"], input[type="email"], input[type="password"],
input[type="number"], input[type="search"],
select, textarea, .cs-input, .ec-input, .cs-num {
    width: 100%;
    padding: 9px 11px;
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: var(--r-ctl);
    color: var(--c-text);
    font: inherit;
    font-size: var(--fs-body);
}
input:focus, select:focus, textarea:focus { border-color: var(--c-accent); outline: none; }
textarea { min-height: 130px; resize: vertical; }

.form-msg { margin-top: 12px; font-size: var(--fs-meta); }
.form-msg.ok  { color: var(--c-online); }
.form-msg.err { color: var(--c-offline); }

/* ================================================= calculators / tools == */
/*
   Both tools pack many small numeric fields into a small space. Giving each
   label+field pair a full-width row - which is what a naive form layout does -
   turns them into a scroll of ~40 stacked rows and hides the relationship
   between the inputs and the numbers they drive.

   So: pairs are inline and compact, sections sit side by side, and the fields
   are only as wide as the values they hold.
*/

/* One padding value for the whole section, and the title strip pulls itself
   back out to the edges with negative margins. The earlier approach - zero
   padding on the section, then re-adding it as margins on each child - gave
   every block a slightly different inset depending on what it was, which is
   what made the panels look assembled rather than laid out. */
.cs-section, .ec-section {
    margin-bottom: 14px;
    padding: 14px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
}

.cs-section-title, .ec-section-title {
    margin: -14px -14px 14px;
    padding: 10px 14px;
    background: var(--c-head);
    border-bottom: 1px solid var(--c-border);
    border-radius: var(--r-card) var(--r-card) 0 0;
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--c-accent);
}

/* Last block in a section should not add trailing space on top of the padding. */
.cs-section > *:last-child, .ec-section > *:last-child { margin-bottom: 0; }

/* --- compact label/field pairs ------------------------------------------ */

.cs-toolbar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 9px;
    margin-bottom: 12px;
}
.cs-toolbar input { flex: 1 1 220px; }

.cs-header-row {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 22px;
    margin-bottom: 12px;
}

.cs-pair, .cs-skill-pair, .ec-row, .ec-picker {
    display: flex;
    align-items: center;
    gap: 9px;
    margin-bottom: 9px;
}
.cs-header-row .cs-pair { margin-bottom: 0; }

.cs-pair > label, .cs-skill-pair > label, .ec-row > label,
.ec-label, .ec-picker-label, .cs-mod-row-label, .cs-resource-name {
    color: var(--c-muted);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    white-space: nowrap;
}
/* The field is pushed right so a column of them lines up regardless of how
   long each label happens to be. */
.cs-skill-pair > label, .ec-row > label, .ec-label { flex: 1; }

/* Narrow, right-aligned fields. input.<class> ties on specificity with the
   generic input[type=...] rule above and wins by coming later. */
input.cs-num, input.cs-skill-input, input.cs-input {
    width: 82px;
    padding: 6px 9px;
    text-align: right;
    font-variant-numeric: tabular-nums;
}
input.ec-input { width: 104px; padding: 6px 9px; text-align: right; }
select.cs-select, select.ec-select { width: auto; min-width: 118px; padding: 6px 9px; }
.ec-picker select.ec-select { flex: 1; }

/* Values the tool computes rather than the user typing. */
input.cs-num-derived { background: var(--c-subhead); color: var(--c-accent); }

/* --- multi-column arrangement ------------------------------------------- */

/* The two result sections sit beside the inputs instead of far below them. */
.cs-wrap, .ec-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
    gap: 14px;
    align-items: start;
}

.cs-skill-grid, .cs-resource-grid, .ec-info-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    gap: 4px 22px;
}

/* --- stat allocation ----------------------------------------------------
   The header strip and every stat row are both eight cells: name, points, and
   six adjust buttons. They MUST share one column template - sizing each row on
   its own content is exactly why the buttons drifted out of line from STR to
   FAI. Declared once here and used by both. */
.cs-section { --stat-cols: 42px 46px repeat(6, minmax(0, 1fr)); }

.cs-headline, .cs-stat-row {
    display: grid;
    grid-template-columns: var(--stat-cols);
    align-items: center;
    gap: 6px;
}

.cs-headline {
    padding-bottom: 8px;
    border-bottom: 1px solid var(--c-border);
}
.cs-headline > span {
    color: var(--c-muted);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
}

.cs-points-left {
    padding: 8px 12px;
    background: var(--c-subhead);
    border-left: 2px solid var(--c-accent);
    border-radius: var(--r-ctl);
    font-size: var(--fs-meta);
}
.cs-points-left b, .cs-points-left strong { color: var(--c-accent); }

.cs-sim-note { color: var(--c-muted); font-size: var(--fs-meta); }

/* --- computed rows ------------------------------------------------------ */

.cs-stat-row {
    padding: 5px 0;
    border-bottom: 1px solid var(--c-rule);
}
.cs-stat-row:last-child { border-bottom: 0; }

.cs-stat-name {
    color: var(--c-text);
    font-size: var(--fs-meta);
    font-weight: 600;
    letter-spacing: var(--ls-micro);
}
.cs-stat-points, .cs-resource-value {
    color: var(--c-accent);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}

/* Adjust buttons. Uniform width inside their shared grid column so the six of
   them read as one control group rather than six loose chips. */
.btn-stat {
    width: 100%;
    padding: 4px 0;
    background: var(--c-active);
    border: 1px solid transparent;
    border-radius: var(--r-ctl);
    color: var(--c-text);
    font-size: var(--fs-micro);
    font-variant-numeric: tabular-nums;
    line-height: 1.5;
}
.btn-stat:hover { background: var(--c-hover); border-color: var(--c-border); }
.btn-stat-plus  { color: var(--c-accent); }
.btn-stat-minus { color: var(--c-muted); }

/* --- resources ---------------------------------------------------------- */

.cs-resource {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 6px 0;
    border-bottom: 1px solid var(--c-rule);
}
.cs-resource:last-child { border-bottom: 0; }
/* The value and its regen rate are adjacent spans with nothing between them,
   which rendered as "291 to 2 / sec". */
.cs-resource-regen {
    margin-left: 6px;
    color: var(--c-muted);
    font-size: var(--fs-micro);
}

.ec-info-body { font-size: var(--fs-meta); color: var(--c-muted); }

/* --- modifier table ----------------------------------------------------- */

/* Despite the name this is NOT a table - it is a div whose children flow in
   triplets (label, computed total, item-mod input) after three header cells.
   Table styling did nothing to it, which is why the header and the values ended
   up on completely different grids. Three columns, everything aligned. */
.cs-mod-table {
    display: grid;
    grid-template-columns: minmax(0, 1fr) 62px 86px;
    align-items: center;
    column-gap: 12px;
    row-gap: 3px;
    font-size: var(--fs-meta);
}

.cs-mod-head {
    padding-bottom: 8px;
    margin-bottom: 3px;
    border-bottom: 1px solid var(--c-border);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-muted);
}
/* Columns two and three hold numbers, so their headers sit over them. */
.cs-mod-head:nth-child(2), .cs-mod-head:nth-child(3) { text-align: right; }

.cs-mod-row-label { color: var(--c-text); }
.cs-mod-cell {
    text-align: right;
    color: var(--c-accent);
    font-weight: 600;
    font-variant-numeric: tabular-nums;
}
.cs-mod-cell--gray { color: var(--c-muted); font-weight: 400; }
/* The item-mod field is the third cell of each row; the shared column width
   keeps every one of them the same size down the column. */
.cs-mod-table > input.cs-input { width: 100%; }

/* --- buttons ------------------------------------------------------------ */

.cs-btn {
    padding: 7px 14px;
    background: var(--c-active);
    border: 1px solid var(--c-border);
    border-radius: var(--r-ctl);
    color: var(--c-text);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    white-space: nowrap;
}
.cs-btn:hover { background: var(--c-hover); border-color: var(--c-accent); color: var(--c-text); }

/* ============================================================= download == */

.dl-intro {
    max-width: 72ch;
    margin-bottom: 20px;
    color: var(--c-muted);
}

/* auto-fit rather than a fixed pair: the cards stay side by side while there is
   room and stack on their own once there is not, with no breakpoint to tune.

   align-items: stretch (the default) rather than start - these cards are read
   side by side and compared, so their spec rows and buttons have to sit on the
   same lines. With "start" each card sized to its own text and the longer
   description shunted everything below it out of step with its neighbour. */
.dl-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(330px, 1fr));
    gap: 14px;
    margin-bottom: 14px;
}

/* Equal height is right for the two download cards, which are read side by side
   and compared row for row. It is wrong for prose panels of unequal length -
   stretching a four-line list to match a much longer one just opens a void
   under it. These size to their own content instead. */
.dl-grid.is-prose { align-items: start; }

/* A section standing on its own needs the same 14px beneath it that the grid
   puts between cards. Zeroing it unconditionally left System Requirements
   welded to the panels below while everything else had a gap. Inside a grid the
   gap already handles spacing, so it is zeroed only there. */
.dl-card, .dl-section { margin-bottom: 14px; display: flex; flex-direction: column; }
.dl-grid > .dl-card, .dl-grid > .dl-section { margin-bottom: 0; }
/* 14px everywhere, matching .card-head, so the head and body share one edge. */
.dl-body { padding: 14px; flex: 1; display: flex; flex-direction: column; }

/* The description absorbs the slack, which is what pulls the facts, button and
   note into line across both cards regardless of how long the copy runs. */
.dl-desc {
    flex: 1;
    margin-bottom: 14px;
    color: var(--c-muted);
    font-size: var(--fs-meta);
}

.dl-badge {
    padding: 3px 9px;
    background: var(--c-active);
    border-radius: var(--r-chip);
    color: var(--c-muted);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    white-space: nowrap;
}
.dl-badge.is-primary { background: var(--c-accent); color: var(--c-on-cta); font-weight: 600; }

/* Spec pairs as a definition list - it is genuinely term/value data, and the
   markup says so to a screen reader instead of faking it with divs. */
.dl-facts {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
    gap: 10px 16px;
    margin: 0 0 16px;
    padding: 12px 0;
    border-top: 1px solid var(--c-rule);
    border-bottom: 1px solid var(--c-rule);
}
.dl-facts dt {
    color: var(--c-muted);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
}
.dl-facts dd { margin: 2px 0 0; color: var(--c-text); font-weight: 600; }

.dl-btn { width: 100%; justify-content: center; }

/* Not a <button disabled>: there is nothing to press, so it is a span. Styled
   inert and marked aria-disabled so assistive tech announces it as such. */
.btn.is-disabled {
    background: var(--c-active);
    border-color: var(--c-border);
    color: var(--c-muted);
    cursor: not-allowed;
    box-shadow: none;
}

.dl-note { margin-top: 10px; color: var(--c-muted); font-size: var(--fs-micro); text-align: center; }

/* A .data-table inside a .card picks up the generic table rule's own card
   treatment - background, border, radius and a 22px bottom margin - which draws
   a second frame inside the first and leaves stray space under it. Inside a
   card the table IS the card's content, so it gives all of that back. */
.card .data-table,
.card .table-scroll > .data-table {
    margin: 0;
    border: 0;
    border-radius: 0;
    background: none;
}
.card .table-scroll { border-radius: 0 0 var(--r-card) var(--r-card); }

.dl-req td:first-child { color: var(--c-muted); }
.dl-req td:last-child  { color: var(--c-accent); }

/* NOT a grid or flex list item.
   Making the <li> a grid turned every one of its children into a grid item -
   so a step containing an inline <code> was split into three cells ("Run", the
   code, then the rest) and wrapped onto separate rows. Only steps made of a
   single text node survived it.
   A block item with one padding-left and an absolutely-positioned marker keeps
   the text as one continuous flow, and still gives a single consistent indent
   instead of the three stacked ones this replaced. */
.dl-steps { padding-left: 0; counter-reset: step; }
.dl-steps li {
    position: relative;
    margin-bottom: 11px;
    padding-left: 24px;
    list-style: none;
    color: var(--c-text);
    font-size: var(--fs-meta);
}
.dl-steps li:last-child { margin-bottom: 0; }
.dl-steps li::before {
    counter-increment: step;
    content: counter(step);
    position: absolute;
    left: 0;
    top: 0;
    color: var(--c-accent);
    font-weight: 700;
    font-variant-numeric: tabular-nums;
}

.dl-faq dt {
    margin-bottom: 4px;
    color: var(--c-text);
    font-size: var(--fs-meta);
    font-weight: 600;
}
.dl-faq dd {
    margin: 0 0 14px;
    color: var(--c-muted);
    font-size: var(--fs-meta);
}
.dl-faq dd:last-child { margin-bottom: 0; }

/* inline-block + nowrap so a filename never splits across two lines. A wrapped
   inline element carrying padding and a border draws that box on BOTH lines,
   which is what overlapped the text beside it. */
code {
    display: inline-block;
    padding: 1px 5px;
    background: var(--c-subhead);
    border: 1px solid var(--c-border);
    border-radius: var(--r-chip);
    color: var(--c-accent);
    font-size: 0.92em;
    white-space: nowrap;
    vertical-align: baseline;
}

/* ============================================================ responsive == */

@media (max-width: 860px) {
    .reference-content { max-width: none; }
    /* Game-data tables are too wide for a phone in any layout, so they scroll
       rather than being crushed into unreadable columns. */
    .reference-content table,
    .data-table,
    .maptable { display: block; overflow-x: auto; white-space: nowrap; }
    .cs-pair, .cs-skill-pair, .ec-row { grid-template-columns: minmax(0, 1fr) 96px; }
}

/* ============================================================== profile == */

.pf-grid {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
    gap: 14px;
    align-items: start;
}
.pf-body { padding: 14px; }

.pf-head {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-bottom: 18px;
}
.pf-avatar {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 64px; height: 64px;
    overflow: hidden;
    border-radius: 50%;
    background: var(--c-active);
    border: 1px solid var(--c-border);
    color: var(--c-muted);
    font-size: 1.5rem;
    font-weight: 600;
    flex: none;
}
.pf-avatar img { width: 100%; height: 100%; object-fit: cover; }
.pf-name { font-size: 1.25rem; font-weight: 600; }
.pf-email { color: var(--c-muted); font-size: var(--fs-meta); }

/* Character rows share one column template with their header strip, so the
   level and location columns line up down the list. */
.pf-chars { --char-cols: 34px minmax(0, 1fr) 84px; }
.pf-char-head, .pf-char {
    display: grid;
    grid-template-columns: var(--char-cols);
    align-items: center;
    gap: 10px;
}
.pf-char-head {
    padding: 6px 14px;
    background: var(--c-subhead);
    border-bottom: 1px solid var(--c-border);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-muted);
}
.pf-char { padding: 9px 14px; border-bottom: 1px solid var(--c-rule); }
.pf-char:last-child { border-bottom: 0; }

.pf-initial {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 26px; height: 26px;
    border-radius: 50%;
    background: var(--c-active);
    font-size: var(--fs-meta);
    font-weight: 600;
}
.pf-char-name { font-size: var(--fs-body); font-weight: 600; }
.pf-char-where { font-size: var(--fs-micro); color: var(--c-muted); }
.pf-level { text-align: right; font-variant-numeric: tabular-nums; }
.pf-online { color: var(--c-online); font-size: var(--fs-micro); }

.pf-coins {
    display: flex;
    align-items: baseline;
    gap: 8px;
    font-size: 1.6rem;
    font-weight: 600;
    color: var(--c-accent);
    font-variant-numeric: tabular-nums;
}
.pf-coins small { font-size: var(--fs-micro); letter-spacing: var(--ls-micro);
                  text-transform: uppercase; color: var(--c-muted); font-weight: 400; }

.pf-signedout { padding: 46px 20px; text-align: center; }
.pf-signedout p { margin-bottom: 18px; color: var(--c-muted); }

/* ============================================================== sign-in == */
/*
   A page, not a dialog. The modal this replaced was cramped because a dialog
   has to stay small; a page can give the form room, which is what a sign-in
   screen wants. It is also the landing point for the launcher's browser flow,
   which arrives at a URL and cannot open a modal on a page not yet loaded.
*/

.auth-page {
    display: flex;
    align-items: flex-start;
    justify-content: center;
    /* Offset for the sticky header so the card sits optically centred rather
       than mathematically centred and looking low. */
    min-height: calc(100vh - 56px);
    padding: 8vh 20px 60px;
}

.auth-card { width: 100%; max-width: 430px; }

.auth-body { padding: 32px 34px 28px; }

.auth-title {
    margin-bottom: 8px;
    font-size: 1.5rem;
    font-weight: 600;
    letter-spacing: var(--ls-micro);
}

.auth-sub {
    margin-bottom: 26px;
    color: var(--c-muted);
    font-size: var(--fs-meta);
    line-height: 1.6;
}

.auth-field { margin-bottom: 18px; }
.auth-field label {
    display: block;
    margin-bottom: 7px;
    color: var(--c-muted);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
}
/* Taller than a stock field: this is the one control on the page, and a login
   box people mistype in is worth the extra few pixels. */
.auth-field input {
    width: 100%;
    padding: 12px 13px;
    font-size: var(--fs-body);
}

.auth-submit {
    width: 100%;
    justify-content: center;
    margin-top: 4px;
    padding: 13px 22px;
}

#auth-error { margin: 0 0 14px; }

.auth-links {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: 10px;
    margin-top: 22px;
    font-size: var(--fs-meta);
}
.auth-sep { color: var(--c-border); }

.auth-foot {
    margin-top: 22px;
    padding-top: 18px;
    border-top: 1px solid var(--c-rule);
    color: var(--c-muted);
    font-size: var(--fs-micro);
    line-height: 1.7;
    text-align: center;
}

/* Launcher mode only - hidden for an ordinary browser visitor. */
.auth-banner {
    display: flex;
    align-items: center;
    gap: 12px;
    padding: 13px 18px;
    background: var(--c-subhead);
    border-bottom: 1px solid var(--c-border);
    border-radius: var(--r-card) var(--r-card) 0 0;
    font-size: var(--fs-meta);
}
.auth-banner strong { display: block; color: var(--c-text); }
.auth-banner span { color: var(--c-muted); }
.auth-banner-icon { color: var(--c-online); font-size: 0.7rem; flex: none; }

@media (max-width: 560px) {
    .auth-page { padding: 4vh 14px 40px; }
    .auth-body { padding: 24px 20px 22px; }
}

/* The launcher's authored coin, reused so the currency mark is identical in
   both products. Sized against the figure it sits beside rather than fixed. */
.pf-coin-mark { width: 30px; height: 30px; flex: none; align-self: center; }

/* --- recovery / reset: multi-card auth pages ---------------------------- */

.auth-stack { width: 100%; max-width: 520px; }
.auth-stack-title { margin-bottom: 8px; text-align: center; }
.auth-stack-sub   { margin-bottom: 22px; text-align: center; }
.auth-stack-foot  { border-top: 0; margin-top: 18px; padding-top: 0; }
.auth-card-wide   { margin-bottom: 14px; }
.auth-card-wide:last-of-type { margin-bottom: 0; }

/* An invalid or expired link is the common case on this page, so it reads as a
   real message rather than muted helper text. */
.auth-sub-error { color: var(--c-offline); }

/* Recovery replies are usually the deliberately vague "if that account exists"
   message - success-coloured, since nothing went wrong. */
.form-msg { margin: 0 0 14px; font-size: var(--fs-meta); line-height: 1.5; }

/* ==================================================== contact form == */

.cf-wrap { max-width: 560px; }
.cf-blurb { margin-bottom: 20px; color: var(--c-muted); font-size: var(--fs-meta); line-height: 1.6; }
.cf-row { margin-bottom: 14px; }
.cf-row label {
    display: block;
    margin-bottom: 6px;
    color: var(--c-muted);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
}
/* Inherits .btn's look without needing the class added to the markup. */
.cf-btn, .ec-cta {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding: 11px 22px;
    background: var(--c-cta);
    border: 1px solid transparent;
    border-radius: var(--r-ctl);
    color: var(--c-on-cta);
    font-size: var(--fs-body);
    font-weight: 600;
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    transition: background 0.12s ease;
}
.cf-btn:hover, .ec-cta:hover { background: var(--c-cta-hi); }
.cf-btn:disabled, .ec-cta:disabled {
    background: var(--c-active); color: var(--c-muted); cursor: not-allowed;
}

/* ========================================================== rules == */

.rules-intro {
    margin-bottom: 18px;
    padding: 14px 16px;
    background: var(--c-subhead);
    border-left: 2px solid var(--c-accent);
    border-radius: 0 var(--r-ctl) var(--r-ctl) 0;
    color: var(--c-text);
    font-size: var(--fs-meta);
    line-height: 1.65;
}

.rules-toc {
    margin-bottom: 22px;
    padding: 14px 18px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
    columns: 2;
    column-gap: 28px;
    font-size: var(--fs-meta);
}
.rules-toc a { display: block; padding: 3px 0; break-inside: avoid; }

/* Consequence callout inside a rule card - warning-toned so it reads as the
   penalty rather than more rule text. */
.punish-box {
    margin: 10px 14px 14px;
    padding: 10px 12px;
    background: var(--c-subhead);
    border-left: 2px solid var(--c-combat);
    border-radius: 0 var(--r-ctl) var(--r-ctl) 0;
    font-size: var(--fs-meta);
    color: var(--c-text);
}
.punish-label {
    display: block;
    margin-bottom: 4px;
    color: var(--c-combat);
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
}

/* =========================================== monsters and drops == */

/* Browser layout: a searchable list beside the selected monster's drops. */
.md-wrap {
    display: grid;
    grid-template-columns: 300px minmax(0, 1fr);
    gap: 14px;
    align-items: start;
}

.md-card {
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
    overflow: hidden;
}

.md-section-title {
    margin: 0;
    padding: 10px 14px;
    background: var(--c-head);
    border-bottom: 1px solid var(--c-border);
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--c-accent);
}

.md-search {
    width: 100%;
    border: 0;
    border-bottom: 1px solid var(--c-border);
    border-radius: 0;
    background: var(--c-subhead);
}
.md-search:focus { border-bottom-color: var(--c-accent); }

/* The one place an inner scroll region is right: a long monster list beside a
   short drop panel, where the page itself should not grow to match. */
.md-list { max-height: 60vh; overflow-y: auto; }
/* The row's clickable area is the ANCHOR, not the <li>.
   The handler is delegated via e.target.closest('a[data-key]'), and an inline
   <a> is only as wide as its text - so padding on the <li> left a dead margin
   either side that swallowed clicks. Making the anchor a block that carries the
   padding means the whole row is the target.
   The selected state is toggled onto the <a> as .active by the page script, so
   that is what gets styled here rather than a class on the <li>. */
.md-list li { border-bottom: 1px solid var(--c-rule); }
.md-list li:last-child { border-bottom: 0; }

.md-list a {
    display: block;
    padding: 8px 14px;
    color: var(--c-text);
    font-size: var(--fs-meta);
}
.md-list a:hover { background: var(--c-hover); color: var(--c-text); }
.md-list a.active {
    background: var(--c-active);
    color: var(--c-accent);
    font-weight: 600;
}

.md-empty { padding: 34px 16px; text-align: center; color: var(--c-muted); font-size: var(--fs-meta); }

/* ============================================ enchant calculator == */

.ec-note { margin-bottom: 16px; color: var(--c-muted); font-size: var(--fs-meta); line-height: 1.6; }

.ec-info {
    margin-bottom: 14px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
}
.ec-info > summary {
    padding: 10px 14px;
    cursor: pointer;
    font-size: var(--fs-meta);
    color: var(--c-accent);
    list-style: none;
}
.ec-info > summary::-webkit-details-marker { display: none; }
.ec-info > summary::before { content: "▸ "; }
.ec-info[open] > summary::before { content: "▾ "; }
.ec-info-body { padding: 0 14px 14px; }

.ec-cta-row { text-align: center; }

/* =========================================== small page blocks == */

.nation-stats-block {
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
    padding: 16px;
}

/* The block is three labelled pairs rather than a list, so the gap lives here
   instead of on an inline style the renderer would have to reapply per row. */
.nation-stats-block > div + div { margin-top: 12px; }

.lookup-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-bottom: 16px;
    padding: 12px 14px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
}
.lookup-bar input { width: auto; flex: 1 1 200px; }

@media (max-width: 860px) {
    .md-wrap { grid-template-columns: minmax(0, 1fr); }
    .md-list { max-height: 40vh; }
    .rules-toc { columns: 1; }
}

/* --- monsters and drops: the JS-built detail panel ---------------------- */

.md-detail-header {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    justify-content: space-between;
    gap: 10px;
    padding: 12px 14px;
    background: var(--c-head);
    border-bottom: 1px solid var(--c-border);
}
.md-monster-name { margin: 0; font-size: var(--fs-lead); font-weight: 600; }
.md-monster-name strong {
    color: var(--c-muted);
    font-size: var(--fs-micro);
    font-weight: 600;
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
}
.md-count {
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-muted);
    white-space: nowrap;
}

/* One flat list, flowed into as many columns as fit.

   This replaced a Weapons / Armours / Rares / Parts grid. Those four groups
   were an editorial split inherited from the old site and nothing in the game
   database expresses them, so the page was asserting a classification it could
   not source (WE-0009). `columns` keeps a 72-item list from becoming one very
   long ribbon without claiming the groups mean anything. */
.md-item-pad {
    padding: 12px 14px;
    background: var(--c-card);
}
.md-items {
    columns: 190px auto;
    column-gap: 22px;
}
.md-items li {
    padding: 3px 0;
    font-size: var(--fs-meta);
    color: var(--c-text);
    line-height: 1.5;
    /* Without this a name can be split down the middle by a column break. */
    break-inside: avoid;
}
.r-empty { color: var(--c-muted); }

/* --- contact form status ------------------------------------------------ */

.cf-msg { margin-top: 14px; font-size: var(--fs-meta); }
.cf-msg.ok  { color: var(--c-online); }
.cf-msg.err { color: var(--c-offline); }

/* --- kill-feed victim column -------------------------------------------- */

.data-table td.col-victim { color: var(--c-text); }

/* ==========================================================================
   Profile dashboard
   --------------------------------------------------------------------------
   A sidebar on wide screens, a horizontal strip of tabs on narrow ones. Same
   markup either way - only the grid direction changes - so there is one nav to
   keep in sync rather than a desktop copy and a mobile copy that drift.
   ========================================================================== */

.dash {
    display: grid;
    grid-template-columns: 190px minmax(0, 1fr);
    gap: 18px;
    align-items: start;
}

.dash-nav {
    display: flex;
    flex-direction: column;
    gap: 2px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
    padding: 6px;
    position: sticky;
    top: 74px;
}

.dash-tab {
    display: flex;
    align-items: center;
    gap: 9px;
    padding: 9px 11px;
    border: 0;
    border-radius: var(--r-ctl);
    background: none;
    color: var(--c-text);
    font: inherit;
    font-size: var(--fs-meta);
    text-align: left;
    cursor: pointer;
    white-space: nowrap;
}

.dash-tab:hover { background: var(--c-hover); }

.dash-tab[aria-selected="true"] {
    background: var(--c-active);
    color: var(--c-accent);
    font-weight: 600;
}

/* The glyph is decorative, but in a vertical list it also has to form a COLUMN.
   These are different characters with very different advance widths - `?` is
   about half of `⛨` - so a box sized to the glyph (flex: 0 0 auto) makes every
   label start at a different x, and the list reads as ragged.
   See CODING_STANDARDS.md, "Lists of icon + text".

   A FIXED box with the glyph centred inside it aligns both columns at once:
   icons under icons, labels under labels, whatever glyphs get used later.
   inline-flex rather than text-align because these dingbats carry wildly
   different intrinsic metrics, and centring both axes is the only thing that
   survives mixing them. */
.dash-tab-icon {
    flex: 0 0 1.25em;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    opacity: .75;
    font-size: var(--fs-body);
    line-height: 1;
}

.dash-panel { display: none; }
.dash-panel.is-active { display: block; }

.dash-section-title {
    font-size: var(--fs-lead);
    font-weight: 600;
    margin: 0 0 4px;
}

.dash-section-sub {
    color: var(--c-muted);
    font-size: var(--fs-meta);
    margin: 0 0 14px;
}

/* --- forms inside the dashboard ------------------------------------------ */

.dash-form {
    max-width: 420px;
    padding: 16px;
}

.dash-form .auth-field { margin-bottom: 12px; }

.dash-form .btn { margin-top: 4px; }

.dash-note {
    color: var(--c-muted);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    margin-top: 12px;
    line-height: 1.5;
}

/* Read-only facts (account name, member since). */
.dash-facts {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    gap: 7px 16px;
    margin: 0;
    font-size: var(--fs-meta);
}

.dash-facts dt { color: var(--c-muted); }
.dash-facts dd { margin: 0; }

@media (max-width: 720px) {
    .dash { grid-template-columns: minmax(0, 1fr); }

    .dash-nav {
        flex-direction: row;
        position: static;
        /* Tabs can outgrow a phone; scroll them rather than wrap into a
           two-row nav that pushes the content down. */
        overflow-x: auto;
        -webkit-overflow-scrolling: touch;
    }

    .dash-tab { flex: 0 0 auto; }
}

/* --- dashboard: summary rows with an explicit action ---------------------- */

.dash-row {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    padding: 13px 15px;
    border-bottom: 1px solid var(--c-rule);
}

.dash-row:last-child { border-bottom: 0; }

.dash-row-label {
    color: var(--c-muted);
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
}

.dash-row-value {
    font-size: var(--fs-body);
    margin-top: 2px;
    /* Long addresses must not push the button off the card. */
    overflow-wrap: anywhere;
}

.dash-row-action { flex: 0 0 auto; }

/* --- modal --------------------------------------------------------------- */
/*
   Native <dialog>, not a hand-rolled overlay. showModal() gives focus
   trapping, Escape-to-close, inertness of the page behind it and correct
   stacking for free - all things a div-based modal gets subtly wrong.
*/

.dlg {
    width: min(420px, calc(100vw - 32px));
    padding: 0;
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
    background: var(--c-card);
    color: var(--c-text);
}

.dlg::backdrop {
    background: rgba(0, 0, 0, .62);
    backdrop-filter: blur(2px);
}

.dlg-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
    padding: 13px 15px;
    border-bottom: 1px solid var(--c-rule);
    background: var(--c-head);
    border-radius: var(--r-card) var(--r-card) 0 0;
}

.dlg-title { font-size: var(--fs-lead); font-weight: 600; }

.dlg-close {
    border: 0;
    background: none;
    color: var(--c-muted);
    font-size: 20px;
    line-height: 1;
    padding: 2px 6px;
    border-radius: var(--r-ctl);
    cursor: pointer;
}

.dlg-close:hover { background: var(--c-hover); color: var(--c-text); }

.dlg-body { padding: 15px; }

.dlg-sub {
    color: var(--c-muted);
    font-size: var(--fs-meta);
    margin: 0 0 14px;
}

.dlg-actions {
    display: flex;
    gap: 8px;
    justify-content: flex-end;
    margin-top: 4px;
}

.btn-ghost {
    background: none;
    border: 1px solid var(--c-border);
    color: var(--c-text);
}

.btn-ghost:hover { background: var(--c-hover); }

/* ==========================================================================
   Cash shop
   ========================================================================== */

/* Full remaining width. The checkout is the primary content of its tab, and
   a narrow column beside empty space made it read as a secondary widget. */
.shop-card { padding: 18px; }

/* --- amount picker -------------------------------------------------------- */

.shop-quick {
    display: grid;
    /* auto-fit rather than a fixed 4 columns: the quick amounts come from the
       API, so the row has to survive there being three of them or five. */
    grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: 12px;
    margin-bottom: 18px;
}

.shop-chip {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 4px;
    padding: 18px 12px 15px;
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
    background:
        radial-gradient(120% 100% at 50% 0%,
                        rgba(255, 255, 255, .045), transparent 70%),
        var(--c-bg);
    color: var(--c-text);
    font: inherit;
    cursor: pointer;
    transition: transform .12s ease, border-color .12s ease, background .12s ease;
}

.shop-chip:hover {
    border-color: var(--c-cta-lo);
    /* A small lift reads as "these are pickable" far faster than a colour
       change alone, especially on a dark surface. */
    transform: translateY(-2px);
}

.shop-chip:active { transform: translateY(0); }

.shop-chip.is-active {
    border-color: var(--c-cta);
    background:
        radial-gradient(120% 100% at 50% 0%,
                        rgba(232, 168, 74, .16), transparent 72%),
        var(--c-bg);
    box-shadow: inset 0 0 0 1px var(--c-cta);
}

.shop-chip-mark {
    width: 26px;
    height: 26px;
    display: block;
    filter: saturate(.85);
    transition: transform .12s ease, filter .12s ease;
}

.shop-chip:hover .shop-chip-mark { transform: scale(1.06); }
.shop-chip.is-active .shop-chip-mark { filter: saturate(1.15); }

.shop-chip-coins {
    font-size: var(--fs-lead);
    font-weight: 700;
    letter-spacing: 0;
}

.shop-chip-unit {
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-muted);
    margin-top: -3px;
}

.shop-chip-price {
    font-size: var(--fs-meta);
    color: var(--c-muted);
    margin-top: 4px;
    padding-top: 6px;
    border-top: 1px solid var(--c-rule);
    width: 100%;
    text-align: center;
}

.shop-chip.is-active .shop-chip-price { color: var(--c-accent); font-weight: 600; }

/* Badge on the largest pick. Absolutely positioned so it cannot change the
   chip's height and leave the row ragged. */
.shop-chip-badge {
    position: absolute;
    top: -8px;
    left: 50%;
    transform: translateX(-50%);
    padding: 2px 8px;
    border-radius: var(--r-chip);
    background: var(--c-cta);
    color: var(--c-on-cta);
    font-size: 9px;
    font-weight: 700;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    white-space: nowrap;
}

.shop-custom { margin-bottom: 4px; }

/* --- order summary -------------------------------------------------------- */

.shop-summary {
    margin: 14px 0;
    padding: 12px 14px;
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: var(--r-ctl);
}

.shop-summary-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    font-size: var(--fs-meta);
    color: var(--c-muted);
}

.shop-summary-row + .shop-summary-row {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--c-rule);
}

.shop-summary-row b { color: var(--c-text); font-weight: 600; }

.shop-summary-row.is-total { font-size: var(--fs-body); }
.shop-summary-row.is-total b {
    font-size: var(--fs-lead);
    color: var(--c-accent);
}

.shop-buy { width: 100%; }

/* --- catalogue ------------------------------------------------------------ */

.shop-item {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    padding: 8px 14px;
    border-bottom: 1px solid var(--c-rule);
    font-size: var(--fs-meta);
}

.shop-item:last-child { border-bottom: 0; }
.shop-item:hover { background: var(--c-hover); }

.shop-item-name { overflow-wrap: anywhere; }
.shop-item-count { color: var(--c-muted); }

.shop-item-price {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    flex: 0 0 auto;
    font-weight: 600;
    color: var(--c-accent);
}

.shop-coin-mark { width: 13px; height: 13px; display: block; }

/* --- consistent spacing between panel cards ------------------------------- */
/*
   Cards inside a dashboard panel were spaced by whatever margin each block
   happened to carry - the ranks card, the checkout card and each catalogue
   category all differed. One rule owns the gap so the rhythm is the same in
   every tab.
*/

.dash-panel > .card,
.dash-panel > div > .card { margin-bottom: 14px; }

.dash-panel > .card:last-child,
.dash-panel > div > .card:last-child { margin-bottom: 0; }

/* A heading that follows a card needs air above it, or the section title
   crowds the card it comes after. */
.dash-panel > div > .card + .dash-section-title { margin-top: 22px; }

/* --- rank bonus on the picker -------------------------------------------- */

.shop-chip-bonus {
    font-size: var(--fs-micro);
    font-weight: 700;
    letter-spacing: var(--ls-micro);
    color: var(--c-online);
    margin-top: 2px;
}

.shop-summary-row.is-bonus b { color: var(--c-online); }
.shop-summary-row.is-get b { color: var(--c-text); }

/* hidden loses to the row's display:flex, so restore it explicitly. */
.shop-summary-row[hidden] { display: none; }

/* Inset from the card edge, matching .shop-card and .dash-form so every
   panel on the page shares one padding value instead of each block inventing
   its own. */
.rank-body { padding: 18px; }

/* --- rank ladder, dressed up ---------------------------------------------
   Each tier carries its own colour from the database, so the styling is
   driven by a --tier custom property set per element rather than by a class
   per rank. Adding a tier in SQL needs no CSS.

   Restraint is the point: a thin tinted edge, a soft wash of the tier colour
   and a subtle sheen. No neon borders or animation on a page that is asking
   somebody for money - flashy reads as untrustworthy exactly where trust
   matters most.
------------------------------------------------------------------------- */

.rank-ladder {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(132px, 1fr));
    gap: 10px;
}

.rank-tier {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 1px;
    padding: 12px 13px 11px;
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
    background:
        linear-gradient(160deg,
            color-mix(in srgb, var(--tier, #ffffff) 11%, transparent) 0%,
            transparent 62%),
        var(--c-bg);
    overflow: hidden;
    transition: transform .14s ease, border-color .14s ease;
}

/* The tier's colour as a bar down the leading edge - identifies the rank at a
   glance without tinting the text into unreadability. */
.rank-tier::before {
    content: "";
    position: absolute;
    inset: 0 auto 0 0;
    width: 3px;
    background: var(--tier, #ffffff);
    opacity: .9;
}

.rank-tier:hover {
    transform: translateY(-1px);
    border-color: color-mix(in srgb, var(--tier, #ffffff) 45%, var(--c-border));
}

.rank-name {
    font-weight: 700;
    font-size: var(--fs-meta);
    letter-spacing: .02em;
    color: var(--tier, var(--c-text));
    /* A faint glow of the tier's own colour: enough to read as special on a
       dark card, not enough to fight the text. */
    text-shadow: 0 0 14px color-mix(in srgb, var(--tier, #fff) 40%, transparent);
}

.rank-bonus {
    font-size: var(--fs-lead);
    font-weight: 700;
    line-height: 1.15;
    color: var(--c-text);
}

.rank-at {
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    text-transform: uppercase;
    color: var(--c-muted);
}

/* The tier the viewer currently holds. */
.rank-tier.is-current {
    border-color: color-mix(in srgb, var(--tier, #fff) 62%, var(--c-border));
    background:
        linear-gradient(160deg,
            color-mix(in srgb, var(--tier, #ffffff) 22%, transparent) 0%,
            transparent 68%),
        var(--c-bg);
}

.rank-tier.is-current::after {
    content: "Your rank";
    position: absolute;
    top: 9px;
    right: 10px;
    font-size: 9px;
    font-weight: 700;
    letter-spacing: var(--ls-label);
    text-transform: uppercase;
    color: var(--tier, var(--c-text));
    opacity: .95;
}

.rank-standing {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 6px 18px;
    margin-top: 14px;
    font-size: var(--fs-meta);
}

.rank-next { color: var(--c-accent); font-weight: 600; }

.rank-note {
    margin: 12px 0 0;
    padding-top: 12px;
    border-top: 1px solid var(--c-rule);
    color: var(--c-muted);
    font-size: var(--fs-micro);
    line-height: 1.6;
}

/* Older engines without color-mix fall back to the flat card surface, which
   still reads correctly - only the tint is lost. */
@supports not (background: color-mix(in srgb, red 10%, transparent)) {
    .rank-tier { background: var(--c-bg); }
    .rank-name { text-shadow: none; }
}

/* --- checkout dialog ------------------------------------------------------ */

.dlg-wide { width: min(460px, calc(100vw - 32px)); }

.co-review {
    padding: 14px 15px;
    background: var(--c-bg);
    border: 1px solid var(--c-border);
    border-radius: var(--r-ctl);
}

.co-row {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 12px;
    font-size: var(--fs-meta);
    color: var(--c-muted);
}

.co-row + .co-row {
    margin-top: 8px;
    padding-top: 8px;
    border-top: 1px solid var(--c-rule);
}

.co-row b { color: var(--c-text); font-weight: 600; }
.co-row.is-bonus b { color: var(--c-online); }
.co-row.is-total { font-size: var(--fs-body); }
.co-row.is-total b { font-size: var(--fs-lead); color: var(--c-accent); }

.co-order {
    margin-top: 8px;
    font-size: var(--fs-micro);
    letter-spacing: var(--ls-micro);
    color: var(--c-muted);
    text-align: right;
}

/* PayPal renders its own buttons into here; give them room and keep the
   surrounding chrome out of their way. */
.co-buttons { margin-top: 14px; min-height: 48px; }

.co-note {
    margin: 12px 0 0;
    padding-top: 12px;
    border-top: 1px solid var(--c-rule);
    color: var(--c-muted);
    font-size: var(--fs-micro);
    line-height: 1.6;
}

/* --- test-mode payment ---------------------------------------------------- */
/*
   Deliberately loud. A simulated payment that looks like a real one is how
   somebody ends up believing a charge went through, so this is the one place
   on the site where shouting is correct.
*/

.co-testmode {
    padding: 10px 12px;
    margin-bottom: 12px;
    border: 1px dashed var(--c-cta);
    border-radius: var(--r-ctl);
    background: color-mix(in srgb, var(--c-cta) 10%, transparent);
    font-size: var(--fs-meta);
    line-height: 1.5;
}

.co-testmode strong { color: var(--c-accent); }

.co-simulate { width: 100%; }

/* ==========================================================================
   News & patch notes archive, and the single post page (WE-0007)
   ========================================================================== */

.news-bar {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px;
    margin-bottom: 16px;
    padding: 12px 14px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
}

/* The search field takes the slack; the two selects stay their own size. */
.news-bar input[type="search"] { flex: 1 1 240px; width: auto; }
.news-bar select { flex: 0 0 auto; width: auto; min-width: 140px; }

/* --- the list ------------------------------------------------------------ */

/* Each row is one <a>, not a row with a link in it: the whole card is the
   target, which is what a reader expects from a headline, and it keeps one
   focus stop per post for the keyboard. */
.news-row {
    display: block;
    padding: 12px 14px;
    margin-bottom: 10px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-left: 2px solid transparent;
    border-radius: var(--r-card);
    color: inherit;
    text-decoration: none;
}

.news-row:hover {
    background: var(--c-hover);
    border-left-color: var(--c-accent);
}

.news-row-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 6px;
    font-size: var(--fs-micro);
    color: var(--c-muted);
}

.news-row-title {
    font-size: var(--fs-body);
    font-weight: 600;
    color: var(--c-text);
}
.news-row:hover .news-row-title { color: var(--c-accent); }

.news-row-summary {
    margin-top: 4px;
    font-size: var(--fs-meta);
    color: var(--c-muted);
    /* Two lines is enough to judge whether to open it; more and the archive
       stops being scannable, which is the only thing it is for. */
    display: -webkit-box;
    -webkit-line-clamp: 2;
    -webkit-box-orient: vertical;
    overflow: hidden;
}

.news-kind { color: var(--c-muted); }
.news-version { margin-left: 8px; font-weight: 400; color: var(--c-accent); }
.news-pin { color: var(--c-combat); text-transform: uppercase; letter-spacing: var(--ls-micro); }

/* --- pager --------------------------------------------------------------- */

.news-pager {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 14px;
    margin-top: 6px;
}

.news-count { font-size: var(--fs-meta); color: var(--c-muted); }
.news-pager .btn[disabled] { opacity: .4; cursor: default; }

/* --- one post ------------------------------------------------------------ */

/* No measure cap. I gave this one `max-width: 74ch` for readability and it did
   exactly what the same idea did on the reference pages: rendered every post at
   about half the content area (WE-0007, WE-0008). `.shell` bounds the line
   length at 1240px and that is the only cap this site uses. */
.post {
    padding: 18px 20px;
    background: var(--c-card);
    border: 1px solid var(--c-border);
    border-radius: var(--r-card);
}

.post-meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px;
    margin-bottom: 8px;
    font-size: var(--fs-micro);
    color: var(--c-muted);
}

.post-summary {
    margin: 0 0 14px;
    color: var(--c-muted);
    font-size: var(--fs-body);
}

.post-note {
    margin-bottom: 14px;
    padding: 9px 12px;
    border-left: 2px solid var(--c-combat);
    background: rgba(224, 163, 62, .08);
    color: var(--c-text);
    font-size: var(--fs-meta);
}

.post-body { color: var(--c-text); line-height: 1.7; }
.post-body h2, .post-body h3, .post-body h4 { margin: 18px 0 8px; color: var(--c-accent); }
.post-body p { margin: 0 0 12px; }
.post-body ul { margin: 0 0 12px; padding-left: 20px; }
.post-body li { margin-bottom: 4px; }
.post-body code {
    padding: 1px 5px;
    background: var(--c-bg);
    border-radius: var(--r-chip);
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: var(--fs-meta);
}

.post-foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 14px;
    margin-top: 20px;
    padding-top: 14px;
    border-top: 1px solid var(--c-rule);
    font-size: var(--fs-meta);
}
.post-author { color: var(--c-muted); }

.post-missing { padding: 22px 20px; }
.post-missing p { color: var(--c-muted); margin-bottom: 16px; }

@media (max-width: 560px) {
    .news-bar input[type="search"], .news-bar select { flex: 1 1 100%; }
}
