/*
 * ugame base styles: design tokens and the shared components every page uses.
 *
 * The look follows docs/art-direction.md: a carved risograph print. Deep indigo paper, coral and
 * mustard ink, black carved keylines. Three motifs carry it through the interface:
 *   - misregistration: headings and active items carry a second ink layer slightly off register
 *     (coral text-shadow, coral offset block behind the active nav item);
 *   - carved blocks: panels, cards and buttons sit on a hard black offset shadow (--keyline), as if
 *     cut from the block; buttons press into the paper when clicked;
 *   - hand-cut rules and halftone: titles are underlined with a gouged line (--rule-*), and
 *     halftone dots shade the page corners and the premium (Void Amber) surfaces.
 * Type: Young Serif for titles and names, Archivo (condensed for labels and buttons) for text,
 * IBM Plex Mono for every number.
 *
 * Feature styles live in their own files (imported in app.js) and build on these classes and
 * variables instead of redefining them.
 */

/* The hidden attribute always hides, whatever display a component rule sets (.form-row, .rush). */
[hidden] {
    display: none !important;
}

:root {
    --ink-950: #08091b;
    --ink-900: #0d0f26;
    --ink-800: #151837;
    --ink-700: #1e2250;
    --ink-600: #2a2f6b;
    --ink-500: #3c428e;
    --ink-400: #5b62b5;
    --ink-300: #8f95e3;
    --paper: #efe6d2;
    --paper-dim: #c9bfa9;
    --paper-faint: #958d7a;
    --coral: #ff6b57;
    --coral-dark: #c8473a;
    --coral-light: #ff8d7c;
    --mustard: #e8b443;
    --mustard-dark: #b5852a;
    --mustard-light: #f3c862;
    --good: #8fcf8a;
    --bad: #ff6b57;
    --keyline: #04050f;

    --font-display: 'Young Serif', Georgia, serif;
    --font-body: 'Archivo', system-ui, sans-serif;
    --font-mono: 'IBM Plex Mono', ui-monospace, monospace;

    --radius: 2px;
    --gap: 1rem;
    --edge: rgb(239 230 210 / 14%);
    --line: 1px solid rgb(239 230 210 / 13%);
    --dash: 1px dashed rgb(239 230 210 / 14%);
    --shadow: 4px 4px 0 var(--keyline);
    --topbar-h: 4rem;

    /* Paper grain laid over panels, like ink on rough stock. */
    --grain: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix values='0 0 0 0 1 0 0 0 0 1 0 0 0 0 1 0 0 0 .06 0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");

    /* Hand-cut rules: a gouged line of uneven weight, tiled along the bottom of a title. */
    --rule-coral: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='6' viewBox='0 0 120 6'%3E%3Cpath fill='%23ff6b57' d='M0 3.2C10 2.2 18 2.6 30 2.9S52 3.8 64 3s24-.8 36 .1 14 .5 20-.1v1.4c-12 .5-24-.2-36 .2s-24 .4-36-.3-26-.2-36 .4S2 4.4 0 4.6Z'/%3E%3C/svg%3E");
    --rule-mustard: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='6' viewBox='0 0 120 6'%3E%3Cpath fill='%23e8b443' d='M0 3.2C10 2.2 18 2.6 30 2.9S52 3.8 64 3s24-.8 36 .1 14 .5 20-.1v1.4c-12 .5-24-.2-36 .2s-24 .4-36-.3-26-.2-36 .4S2 4.4 0 4.6Z'/%3E%3C/svg%3E");
    --rule-paper: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='120' height='6' viewBox='0 0 120 6'%3E%3Cpath fill='%23efe6d2' fill-opacity='.22' d='M0 3.2C10 2.2 18 2.6 30 2.9S52 3.8 64 3s24-.8 36 .1 14 .5 20-.1v1.4c-12 .5-24-.2-36 .2s-24 .4-36-.3-26-.2-36 .4S2 4.4 0 4.6Z'/%3E%3C/svg%3E");

    /* Halftone dots, as printed shading. Use as a background layer. */
    --halftone-indigo: radial-gradient(circle, rgb(143 149 227 / 28%) 0.9px, transparent 1.4px) 0 0 / 6px 6px;
    --halftone-mustard: radial-gradient(circle, rgb(232 180 67 / 22%) 0.9px, transparent 1.4px) 0 0 / 5px 5px;
    --halftone-coral: radial-gradient(circle, rgb(255 107 87 / 22%) 0.9px, transparent 1.4px) 0 0 / 5px 5px;

    /* Disabled and unavailable things are struck through with hatching. */
    --hatch: repeating-linear-gradient(-45deg, rgb(239 230 210 / 7%) 0 2px, transparent 2px 7px);
}

*, *::before, *::after {
    box-sizing: border-box;
}

html {
    color-scheme: dark;
    font-synthesis-weight: none;
    scrollbar-color: var(--ink-500) var(--ink-900);
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    min-height: 100vh;
    background: var(--ink-900) var(--grain);
    color: var(--paper);
    font: 400 15px/1.5 var(--font-body);
}

/* Halftone shading in the page corners, fixed behind everything. */
body::before {
    content: "";
    position: fixed;
    inset: 0;
    z-index: -1;
    pointer-events: none;
    background: var(--halftone-indigo);
    mask-image: radial-gradient(ellipse 60% 55% at 100% 0%, #000 0%, transparent 75%),
        radial-gradient(ellipse 45% 40% at 0% 100%, rgb(0 0 0 / 70%) 0%, transparent 75%);
}

::selection {
    background: var(--coral);
    color: var(--ink-950);
}

a {
    color: var(--mustard);
    text-decoration-thickness: 1px;
    text-underline-offset: 0.18em;
}

a:hover {
    color: var(--mustard-light);
}

h1, h2, h3, h4 {
    font-family: var(--font-display);
    font-weight: 400;
    line-height: 1.15;
    margin: 0 0 0.6em;
    text-wrap: balance;
}

p {
    text-wrap: pretty;
}

img {
    max-width: 100%;
}

strong {
    font-weight: 650;
}

.num {
    font-family: var(--font-mono);
    font-variant-numeric: tabular-nums;
}

:focus-visible {
    outline: 2px solid var(--mustard);
    outline-offset: 2px;
}

details > summary {
    cursor: pointer;
}

details > summary::marker {
    color: var(--coral);
}

hr {
    border: 0;
    height: 6px;
    margin: var(--gap) 0;
    background: var(--rule-paper) left center / 120px 6px repeat-x;
}

/* ---------- Icons (templates/_icons.html.twig) ---------- */

.icon-sprite {
    position: absolute;
    width: 0;
    height: 0;
    overflow: hidden;
}

.icon {
    width: 1.2em;
    height: 1.2em;
    flex: none;
    fill: none;
    stroke: currentcolor;
    stroke-width: 1.7;
    stroke-linecap: round;
    stroke-linejoin: round;
    vertical-align: -0.2em;
}

.skip-link {
    position: absolute;
    left: 0.75rem;
    top: -3rem;
    z-index: 50;
    padding: 0.45rem 0.8rem;
    background: var(--mustard);
    color: var(--ink-950);
    font-weight: 700;
    box-shadow: var(--shadow);
}

.skip-link:focus {
    top: 0.75rem;
}

.visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

/* ---------- Game shell: top bar ---------- */

.topbar {
    position: sticky;
    top: 0;
    z-index: 20;
    display: flex;
    align-items: center;
    gap: 1rem 1.4rem;
    min-height: var(--topbar-h);
    padding: 0.35rem clamp(0.75rem, 2vw, 1.5rem) 0.5rem;
    background: var(--ink-950) var(--grain);
    border-bottom: 1px solid var(--keyline);
}

/* The coral rule under the bar, cut by hand and printed a little off register. */
.topbar::after {
    content: "";
    position: absolute;
    left: 0;
    right: 0;
    bottom: -5px;
    height: 6px;
    background: var(--rule-coral) left top / 120px 6px repeat-x;
    pointer-events: none;
}

.topbar__brand {
    display: inline-flex;
    align-items: center;
    gap: 0.5rem;
    flex: none;
    color: var(--paper);
    text-decoration: none;
}

.topbar__brand:hover {
    color: var(--paper);
}

.topbar__sigil {
    width: 2rem;
    height: 2rem;
    color: var(--coral);
    stroke-width: 1.9;
    filter: drop-shadow(1.5px 1px 0 rgb(232 180 67 / 70%));
}

.topbar__wordmark {
    font: 400 1.55rem/1 var(--font-display);
    letter-spacing: 0.01em;
    text-shadow: 0.05em 0.04em 0 rgb(255 107 87 / 60%);
}

.topbar__player {
    margin-left: auto;
    display: flex;
    gap: 0.6rem;
    align-items: center;
    flex: none;
}

.topbar__name {
    font: 400 1rem var(--font-display);
    color: var(--paper);
}

.topbar__link {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.3rem 0.5rem;
    color: var(--paper-dim);
    font-size: 0.85rem;
    text-decoration: none;
    border: 1px solid var(--edge);
    border-radius: var(--radius);
}

.topbar__link:hover {
    color: var(--coral);
    border-color: var(--coral);
}

/* ---------- Resource bar ---------- */

.resource-bar {
    display: flex;
    align-items: stretch;
    min-width: 0;
    margin: 0;
    padding: 0;
    list-style: none;
}

.resource-bar__item {
    position: relative;
    display: grid;
    grid-template-columns: 2.15rem auto;
    grid-template-rows: auto auto;
    column-gap: 0.55rem;
    align-items: center;
    min-width: 8.6rem;
    padding: 0.3rem 0.9rem 0.55rem 0.8rem;
    border-left: var(--dash);
    cursor: default;
}

.resource-bar__item:first-child {
    border-left: 0;
}

.resource-bar__icon {
    grid-row: 1 / span 2;
    width: 2.15rem;
    height: 2.15rem;
    object-fit: cover;
    border-radius: 50%;
    box-shadow: 0 0 0 1.5px var(--keyline), 1.5px 1.5px 0 2px rgb(239 230 210 / 18%);
}

.resource-bar__label {
    align-self: end;
    font: 700 0.64rem/1.1 var(--font-body);
    font-stretch: 75%;
    letter-spacing: 0.13em;
    text-transform: uppercase;
    color: var(--paper-faint);
    white-space: nowrap;
}

.resource-bar__value {
    align-self: start;
    font: 500 1.02rem/1.25 var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--paper);
    white-space: nowrap;
}

/* Storage meter: how full the store is; --fill comes from the template and the ticker. */
.resource-bar__meter {
    position: absolute;
    left: 3.5rem;
    right: 0.9rem;
    bottom: 0.3rem;
    height: 3px;
    background: rgb(239 230 210 / 10%);
}

.resource-bar__meter::after {
    content: "";
    display: block;
    width: var(--fill, 0%);
    max-width: 100%;
    height: 100%;
    background: var(--meter, var(--paper-dim));
}

.resource-bar__item--crystal {
    --meter: var(--coral-light);
}

.resource-bar__item--deuterium {
    --meter: var(--ink-300);
}

.resource-bar__item.is-full,
.resource-bar__item.is-short {
    --meter: var(--coral);
}

.resource-bar__item.is-full .resource-bar__value,
.resource-bar__item.is-short .resource-bar__value {
    color: var(--bad);
}

.resource-bar__item.is-full .resource-bar__label::after {
    content: " · full";
    color: var(--coral);
}

.resource-bar__item.is-short .resource-bar__label::after {
    content: " · short";
    color: var(--coral);
}

/* Void Amber: the premium currency, printed in mustard over halftone. */
.resource-bar__item--premium {
    margin-left: 0.5rem;
    border: 1px solid rgb(232 180 67 / 45%);
    border-radius: var(--radius);
    background: var(--halftone-mustard), rgb(232 180 67 / 6%);
    padding-bottom: 0.35rem;
}

.resource-bar__item--premium .resource-bar__label {
    color: var(--mustard);
}

.resource-bar__item--premium .resource-bar__value {
    color: var(--mustard-light);
}

.resource-bar__item--premium .resource-bar__icon {
    box-shadow: 0 0 0 1.5px var(--keyline), 1.5px 1.5px 0 2px rgb(232 180 67 / 55%);
}

/* ---------- Game shell: columns ---------- */

.shell {
    display: grid;
    grid-template-columns: 12.5rem minmax(0, 1fr) 14rem;
    grid-template-areas: "nav content worlds";
    gap: 1.5rem;
    max-width: 1560px;
    margin: 0 auto;
    padding: 1.6rem clamp(0.75rem, 2vw, 1.5rem) 3rem;
}

/* A size container, so feature layouts can follow the page's width rather than the window's. */
.content {
    grid-area: content;
    min-width: 0;
    container-type: inline-size;
}

/* ---------- Navigation ---------- */

.sidenav {
    grid-area: nav;
    position: sticky;
    top: calc(var(--topbar-h) + 1.4rem);
    align-self: start;
    display: flex;
    flex-direction: column;
    gap: 1.1rem;
    max-height: calc(100vh - var(--topbar-h) - 2.4rem);
    overflow-y: auto;
    scrollbar-width: thin;
    padding: 0 0.5rem 0.5rem 0;
}

.sidenav__group {
    display: flex;
    flex-direction: column;
    gap: 2px;
}

.sidenav__label {
    margin: 0 0 0.3rem;
    padding: 0 0.6rem 0.35rem;
    font: 700 0.66rem/1.2 var(--font-body);
    font-stretch: 75%;
    letter-spacing: 0.17em;
    text-transform: uppercase;
    color: var(--paper-faint);
    border-bottom: var(--dash);
}

.sidenav__item {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.65rem;
    padding: 0.42rem 0.6rem;
    color: var(--paper-dim);
    font-size: 0.93rem;
    text-decoration: none;
    border-radius: var(--radius);
}

.sidenav__icon {
    width: 1.2rem;
    height: 1.2rem;
    color: var(--paper-faint);
}

.sidenav__item:hover {
    color: var(--paper);
    background: var(--ink-800);
}

.sidenav__item:hover .sidenav__icon {
    color: var(--coral);
}

/* The current page: a paper tab with its coral plate printed off register. */
.sidenav__item.is-active {
    color: var(--ink-950);
    background: var(--paper);
    font-weight: 600;
    box-shadow: 3px 3px 0 var(--coral);
}

.sidenav__item.is-active .sidenav__icon {
    color: var(--coral-dark);
    stroke-width: 2;
}

.sidenav__item .badge {
    margin-left: auto;
}

.sidenav__group--premium .sidenav__label {
    color: var(--mustard);
}

.sidenav__group--premium .sidenav__icon {
    color: var(--mustard-dark);
}

.sidenav__group--premium .sidenav__item.is-active {
    background: var(--mustard);
    box-shadow: 3px 3px 0 var(--coral);
}

.sidenav__group--premium .sidenav__item.is-active .sidenav__icon {
    color: var(--ink-950);
}

.sidenav__group--misc {
    padding-top: 0.4rem;
    border-top: var(--dash);
}

/* ---------- Worlds (colony list) ---------- */

.colonies {
    grid-area: worlds;
    position: sticky;
    top: calc(var(--topbar-h) + 1.4rem);
    align-self: start;
    min-width: 0;
}

.colonies__title {
    margin: 0 0 0.5rem;
    padding: 0 0.2rem 0.35rem;
    font: 700 0.66rem/1.2 var(--font-body);
    font-stretch: 75%;
    letter-spacing: 0.17em;
    text-transform: uppercase;
    color: var(--paper-faint);
    border-bottom: var(--dash);
}

.colonies__list {
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
}

.colony-link {
    position: relative;
    display: grid;
    grid-template-columns: 2.6rem minmax(0, 1fr);
    grid-template-rows: auto auto;
    column-gap: 0.65rem;
    align-items: center;
    padding: 0.4rem 0.5rem;
    color: var(--paper);
    text-decoration: none;
    border: 1px solid transparent;
    border-radius: var(--radius);
}

.colony-link:hover {
    color: var(--paper);
    background: var(--ink-800);
    border-color: var(--edge);
}

.colony-link.is-active {
    background: var(--ink-800) var(--grain);
    border-color: rgb(232 180 67 / 55%);
    box-shadow: var(--shadow);
}

.colony-link__image {
    grid-row: span 2;
    width: 2.6rem;
    height: 2.6rem;
    object-fit: cover;
    border-radius: 50%;
    background: var(--ink-700);
    box-shadow: 0 0 0 2px var(--ink-950), 0 0 0 3px rgb(239 230 210 / 18%);
}

.colony-link.is-active .colony-link__image {
    box-shadow: 0 0 0 2px var(--ink-950), 0 0 0 3.5px var(--mustard);
}

.colony-link__name {
    align-self: end;
    overflow: hidden;
    font: 400 0.98rem/1.2 var(--font-display);
    white-space: nowrap;
    text-overflow: ellipsis;
}

.colony-link__coords {
    align-self: start;
    font: 0.74rem var(--font-mono);
    color: var(--paper-faint);
}

/* A moon hangs off the world above it. */
.colony-link--moon {
    margin-left: 1.5rem;
    grid-template-columns: 1.9rem minmax(0, 1fr);
}

.colony-link--moon::before {
    content: "";
    position: absolute;
    left: -0.95rem;
    top: -0.45rem;
    width: 0.75rem;
    height: calc(50% + 0.45rem);
    border-left: var(--dash);
    border-bottom: var(--dash);
}

.colony-link--moon .colony-link__image {
    width: 1.9rem;
    height: 1.9rem;
}

/* ---------- Page headings and panels ---------- */

.page-title {
    margin: 0 0 1.2rem;
    font: 400 clamp(1.65rem, 1.2rem + 1.4vw, 2.35rem)/1.1 var(--font-display);
    text-shadow: 0.045em 0.04em 0 rgb(255 107 87 / 55%);
    overflow-wrap: anywhere;
}

/* Coordinates and other small print after a title. */
.page-title .num,
.page-title__sub {
    font: 400 0.5em var(--font-mono);
    color: var(--paper-dim);
    text-shadow: none;
    letter-spacing: 0;
    vertical-align: 0.2em;
    white-space: nowrap;
}

.page-title__sub .num {
    font-size: 1em;
    vertical-align: 0;
}

.panel {
    position: relative;
    isolation: isolate;
    background: var(--ink-800) var(--grain);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    padding: 1.05rem 1.2rem 1.2rem;
    margin-bottom: 1.25rem;
    box-shadow: var(--shadow);
}

/* A corner of halftone shading, as on a printed block. */
.panel::before {
    content: "";
    position: absolute;
    top: 0;
    right: 0;
    z-index: -1;
    width: min(9rem, 40%);
    height: 6rem;
    background: var(--halftone-indigo);
    mask-image: linear-gradient(215deg, #000 0%, transparent 60%);
    pointer-events: none;
}

.panel__title {
    margin: 0 0 0.9rem;
    padding-bottom: 0.55rem;
    font: 400 1.2rem/1.2 var(--font-display);
    background: var(--rule-coral) left bottom / 120px 6px repeat-x;
}

.panel__title .num {
    font-size: 0.78em;
}

/* An empty list or queue: "Nothing is being built." */
.empty-state,
.build-queue__empty,
.overview__empty,
.research-queue__empty {
    margin: 0;
    padding: 0.7rem 0.9rem;
    color: var(--paper-faint);
    font-size: 0.9rem;
    border: 1px dashed rgb(239 230 210 / 16%);
    border-radius: var(--radius);
    background: var(--hatch);
}

/* The way out of an empty state: "Open Research", a small outlined chip. */
.empty-state__link {
    display: inline-block;
    margin: 0.15rem 0 0.15rem 0.5rem;
    padding: 0.05rem 0.5rem;
    font-size: 0.82rem;
    font-weight: 600;
    white-space: nowrap;
    text-decoration: none;
    border: 1px solid rgb(232 180 67 / 55%);
    border-radius: var(--radius);
}

.empty-state__link:hover {
    background: rgb(232 180 67 / 12%);
}

.empty-state__link::after {
    content: " \2192";
}

/* ---------- Item cards (buildings, research, ships, defense, officers, classes) ---------- */

.item-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(13rem, 1fr));
    gap: 1.1rem;
}

.item-card {
    position: relative;
    display: flex;
    flex-direction: column;
    min-width: 0;
    background: var(--ink-800) var(--grain);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    box-shadow: var(--shadow);
    scroll-margin-top: calc(var(--topbar-h) + 1rem);
}

.item-card:target {
    border-color: var(--mustard);
    box-shadow: 4px 4px 0 var(--mustard-dark);
}

.item-card__image {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    object-position: center 40%;
    background: var(--ink-700);
    border-bottom: 2px solid var(--keyline);
}

/* The level (or rank, or count) is stamped onto the art. */
.item-card__level {
    position: absolute;
    top: 0.55rem;
    left: 0.55rem;
    max-width: calc(100% - 1.1rem);
    padding: 0.12rem 0.45rem;
    font: 600 0.78rem/1.35 var(--font-mono);
    color: var(--ink-950);
    background: var(--paper);
    border-radius: 1px;
    box-shadow: 2px 2px 0 var(--keyline);
    transform: rotate(-1.5deg);
}

.item-card__body {
    display: flex;
    flex-direction: column;
    gap: 0.45rem;
    padding: 0.75rem 0.8rem 0.85rem;
    flex: 1;
}

.item-card__name {
    margin: 0;
    font: 400 1.12rem/1.2 var(--font-display);
}

.item-card__description {
    margin: 0;
    font-size: 0.83rem;
    line-height: 1.45;
    color: var(--paper-dim);
}

.item-card__actions {
    margin-top: auto;
    padding-top: 0.25rem;
    display: flex;
    gap: 0.4rem;
    flex-wrap: wrap;
    align-items: center;
}

/* Locked: the art goes grey and a stamp says why the button is missing. */
.item-card.is-locked .item-card__image {
    filter: saturate(0.25) brightness(0.55) contrast(1.05);
}

.item-card.is-locked::after {
    content: "Locked";
    position: absolute;
    top: 0.6rem;
    right: 0.55rem;
    padding: 0.08rem 0.45rem;
    font: 700 0.68rem/1.4 var(--font-body);
    font-stretch: 80%;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--coral);
    background: var(--ink-950);
    border: 1.5px solid var(--coral);
    transform: rotate(2deg);
}

.item-card.is-locked .item-card__name,
.item-card.is-locked .item-card__description {
    color: var(--paper-dim);
}

/* A cost list: <ul class="cost"><li class="cost__item is-missing">...</li></ul> */
.cost {
    display: flex;
    flex-wrap: wrap;
    gap: 0.25rem 0.75rem;
    margin: 0;
    padding: 0;
    list-style: none;
    font: 500 0.84rem var(--font-mono);
    font-variant-numeric: tabular-nums;
}

.cost__item {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    white-space: nowrap;
}

/* Short of this resource: coral on a tinted chip, so it reads without colour too. */
.cost__item.is-missing {
    margin: 0 -0.25rem;
    padding: 0 0.25rem;
    font-weight: 600;
    color: var(--coral-light);
    background: rgb(255 107 87 / 14%);
    border-radius: var(--radius);
}

.requirements {
    font-size: 0.8rem;
    color: var(--paper-faint);
}

.requirements .is-met {
    color: var(--good);
}

/* ---------- Buttons ---------- */

.btn {
    --btn-bg: var(--ink-600);
    --btn-fg: var(--paper);
    --btn-hover: var(--ink-500);
    --btn-border: rgb(239 230 210 / 22%);
    position: relative;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: 0.4rem;
    padding: 0.44rem 0.9rem;
    font: 700 0.8rem/1.2 var(--font-body);
    font-stretch: 85%;
    letter-spacing: 0.07em;
    text-transform: uppercase;
    text-decoration: none;
    color: var(--btn-fg);
    background: var(--btn-bg);
    border: 1.5px solid var(--btn-border);
    border-radius: var(--radius);
    box-shadow: 3px 3px 0 var(--keyline);
    cursor: pointer;
    transition: transform 0.08s ease-out, box-shadow 0.08s ease-out, background-color 0.15s;
}

.btn:hover {
    color: var(--btn-fg);
    background: var(--btn-hover);
    transform: translate(-1px, -1px);
    box-shadow: 4px 4px 0 var(--keyline);
}

/* Pressed into the paper. */
.btn:active {
    transform: translate(2px, 2px);
    box-shadow: 1px 1px 0 var(--keyline);
}

.btn--primary {
    --btn-bg: var(--coral);
    --btn-fg: var(--ink-950);
    --btn-hover: var(--coral-light);
    --btn-border: var(--keyline);
}

.btn--premium {
    --btn-bg: var(--mustard);
    --btn-fg: var(--ink-950);
    --btn-hover: var(--mustard-light);
    --btn-border: var(--keyline);
    background: var(--halftone-coral), var(--btn-bg);
}

.btn--premium:hover {
    background: var(--halftone-coral), var(--btn-hover);
}

.btn--danger {
    --btn-bg: transparent;
    --btn-fg: var(--coral);
    --btn-hover: rgb(255 107 87 / 14%);
    --btn-border: rgb(255 107 87 / 70%);
    box-shadow: none;
}

.btn--danger:hover {
    box-shadow: 2px 2px 0 var(--keyline);
}

.btn:disabled,
.btn.is-disabled {
    color: var(--paper-faint);
    background: var(--hatch), var(--ink-800);
    border-color: var(--edge);
    box-shadow: none;
    transform: none;
    cursor: not-allowed;
}

.btn--primary:disabled,
.btn--primary.is-disabled {
    color: rgb(255 141 124 / 75%);
    background: repeating-linear-gradient(-45deg, rgb(255 107 87 / 16%) 0 2px, transparent 2px 7px), var(--ink-800);
    border-color: rgb(255 107 87 / 35%);
}

.btn--premium:disabled,
.btn--premium.is-disabled {
    color: rgb(243 200 98 / 70%);
    background: repeating-linear-gradient(-45deg, rgb(232 180 67 / 15%) 0 2px, transparent 2px 7px), var(--ink-800);
    border-color: rgb(232 180 67 / 35%);
}

.btn .num {
    letter-spacing: 0;
}

/* ---------- Forms ---------- */

.input,
.select {
    max-width: 100%;
    padding: 0.42rem 0.6rem;
    font: 500 0.9rem/1.3 var(--font-mono);
    color: var(--paper);
    background: var(--ink-950);
    border: 1px solid var(--ink-500);
    border-bottom: 2px solid var(--ink-400);
    border-radius: var(--radius);
    transition: border-color 0.15s;
}

textarea.input {
    font-family: var(--font-body);
}

.input:hover,
.select:hover {
    border-color: var(--ink-400);
}

.input:focus,
.select:focus {
    border-color: var(--mustard);
    outline: none;
    box-shadow: 0 0 0 1px var(--mustard);
}

.input::placeholder {
    color: var(--paper-faint);
    opacity: 0.7;
}

.select {
    appearance: none;
    padding-right: 1.9rem;
    background: var(--ink-950) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1.2 1.6 6 6.3l4.9-4.8' fill='none' stroke='%23e8b443' stroke-width='1.8' stroke-linecap='round'/%3E%3C/svg%3E") right 0.6rem center / 0.7rem no-repeat;
    cursor: pointer;
}

.input--small {
    width: 6rem;
}

input[type="checkbox"],
input[type="radio"] {
    accent-color: var(--coral);
}

.form-row {
    display: flex;
    flex-direction: column;
    gap: 0.3rem;
    margin-bottom: 0.9rem;
}

.form-row label {
    font-size: 0.82rem;
    font-weight: 600;
    color: var(--paper-dim);
}

/* ---------- Tables: a ledger ---------- */

.table {
    width: 100%;
    border-collapse: collapse;
    font-size: 0.9rem;
}

.table th,
.table td {
    padding: 0.5rem 0.6rem;
    border-bottom: var(--dash);
    text-align: left;
}

.table th {
    font-weight: 600;
    color: var(--paper);
}

.table thead th {
    padding-top: 0.2rem;
    font: 700 0.68rem/1.3 var(--font-body);
    font-stretch: 78%;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    color: var(--mustard);
    border-bottom: 2px solid var(--ink-500);
    vertical-align: bottom;
}

.table tbody tr:hover > * {
    background-color: rgb(91 98 181 / 9%);
}

.table tfoot th,
.table tfoot td {
    font-weight: 600;
}

.table .num {
    text-align: right;
}

/* ---------- Notices, badges, tags ---------- */

.notice {
    --notice-ink: var(--mustard);
    --notice-mark: "i";
    position: relative;
    margin: 0 0 1.1rem;
    padding: 0.65rem 0.95rem 0.65rem 2.6rem;
    background: var(--ink-700) var(--grain);
    border: 1px solid var(--edge);
    border-radius: var(--radius);
    box-shadow: inset 4px 0 0 var(--notice-ink);
}

.notice::before {
    content: var(--notice-mark);
    position: absolute;
    left: 0.85rem;
    top: 0.72rem;
    width: 1.15rem;
    height: 1.15rem;
    font: 700 0.72rem/1.15rem var(--font-mono);
    text-align: center;
    color: var(--ink-950);
    background: var(--notice-ink);
    border-radius: 50%;
}

.notice--error {
    --notice-ink: var(--coral);
    --notice-mark: "!";
    background: repeating-linear-gradient(-45deg, rgb(255 107 87 / 7%) 0 2px, transparent 2px 8px), var(--ink-700);
}

.notice--success {
    --notice-ink: var(--good);
    --notice-mark: "\2713";
}

.badge {
    display: inline-block;
    min-width: 1.45em;
    padding: 0 0.35em;
    font: 600 0.72rem/1.45 var(--font-mono);
    text-align: center;
    color: var(--ink-950);
    background: var(--coral);
    border-radius: 999px;
    box-shadow: 1px 1px 0 var(--keyline);
}

.tag {
    display: inline-block;
    padding: 0.02rem 0.4rem;
    font: 700 0.66rem/1.5 var(--font-body);
    font-stretch: 80%;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    white-space: nowrap;
    border: 1px solid currentcolor;
    border-radius: 1px;
}

/* ---------- Tabs and filter chips ---------- */

/* Index tabs standing on a rule; the current one is a paper tab with a coral plate behind it. */
.tabs {
    --tab-active: var(--paper);
    --tab-plate: var(--coral);
    display: flex;
    flex-wrap: wrap;
    align-items: flex-end;
    gap: 0.3rem;
    margin: 0 0 1.2rem;
    padding: 0 0.2rem;
    border-bottom: 2px solid var(--tab-plate);
}

.tabs__item {
    position: relative;
    display: inline-flex;
    align-items: center;
    gap: 0.4rem;
    margin-bottom: -2px;
    padding: 0.45rem 0.9rem 0.4rem;
    font-size: 0.9rem;
    font-weight: 600;
    color: var(--paper-dim);
    text-decoration: none;
    background: var(--ink-800);
    border: 1px solid var(--edge);
    border-bottom: 2px solid var(--tab-plate);
    border-radius: var(--radius) var(--radius) 0 0;
}

.tabs__item:hover {
    color: var(--paper);
    background: var(--ink-700);
}

.tabs__item.is-active {
    color: var(--ink-950);
    background: var(--tab-active);
    border-color: var(--tab-active);
    border-bottom-color: var(--tab-active);
    box-shadow: 3px -3px 0 var(--tab-plate);
}

.tabs--premium {
    --tab-active: var(--mustard);
    --tab-plate: var(--coral);
}

/* Filter chips: a row of small stamps, the chosen one inked in mustard. */
.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 0.35rem;
    margin: 0 0 1rem;
}

.chips__item {
    padding: 0.22rem 0.7rem;
    font-size: 0.83rem;
    white-space: nowrap;
    color: var(--paper-dim);
    text-decoration: none;
    border: 1px solid var(--ink-500);
    border-radius: var(--radius);
}

.chips__item:hover {
    color: var(--paper);
    border-color: var(--paper-faint);
}

.chips__item.is-active {
    color: var(--ink-950);
    background: var(--mustard);
    border-color: var(--keyline);
    box-shadow: 2px 2px 0 var(--keyline);
}

/* ---------- Queues (build queue, research queue, shipyard) ---------- */

.queue {
    margin: 0;
    padding: 0;
    list-style: none;
}

.queue__item {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.7rem;
    padding: 0.5rem 0.6rem;
    border-bottom: var(--dash);
}

.queue__item:last-child {
    border-bottom: 0;
}

.queue__item form {
    margin: 0;
}

/* The job that runs now: lit in mustard, its clock ticking. */
.queue__item.is-running {
    background: linear-gradient(90deg, rgb(232 180 67 / 13%), transparent 75%);
    box-shadow: inset 3px 0 0 var(--mustard);
}

.queue__time {
    margin-left: auto;
    font: 500 0.95rem var(--font-mono);
    font-variant-numeric: tabular-nums;
    color: var(--paper-faint);
}

.queue__item.is-running .queue__time {
    color: var(--mustard-light);
}

.queue__item.is-running .queue__time::before {
    content: "";
    display: inline-block;
    width: 0.45rem;
    height: 0.45rem;
    margin-right: 0.45rem;
    vertical-align: 0.1em;
    border-radius: 50%;
    background: var(--mustard);
    animation: ink-pulse 1.6s ease-in-out infinite;
}

@keyframes ink-pulse {
    50% {
        opacity: 0.25;
    }
}

/* ---------- Responsive shell ---------- */

/* One world only: it is named in every page title, so the worlds column gives its room to the page. */
@media (min-width: 1241px) {
    .shell:has(.colony-link:only-child) {
        grid-template-columns: 12.5rem minmax(0, 1fr);
        grid-template-areas: "nav content";
        max-width: 1320px;
    }

    .shell:has(.colony-link:only-child) .colonies {
        display: none;
    }
}

/* Narrower desktops: the worlds move into a strip above the page. */
@media (max-width: 1240px) {
    .shell {
        grid-template-columns: 11.5rem minmax(0, 1fr);
        grid-template-areas:
            "nav worlds"
            "nav content";
        row-gap: 1.1rem;
    }

    .colonies {
        position: static;
        display: flex;
        align-items: center;
        gap: 0.8rem;
    }

    .colonies__title {
        margin: 0;
        padding: 0;
        border: 0;
        flex: none;
    }

    .colonies__list {
        flex-direction: row;
        gap: 0.4rem;
        overflow-x: auto;
        scrollbar-width: thin;
        padding: 0 0.3rem 0.35rem 0;
    }

    .colony-link {
        flex: none;
        max-width: 13rem;
        grid-template-columns: 2rem minmax(0, 1fr);
        padding: 0.3rem 0.6rem 0.3rem 0.35rem;
        border-color: var(--edge);
    }

    .colony-link__image {
        width: 2rem;
        height: 2rem;
    }

    .colony-link--moon {
        margin-left: 0;
        grid-template-columns: 1.6rem minmax(0, 1fr);
    }

    .colony-link--moon::before {
        display: none;
    }

    .colony-link--moon .colony-link__image {
        width: 1.6rem;
        height: 1.6rem;
    }

    /* A single world is already named in every page title: no strip needed. */
    .colonies:has(.colony-link:only-child) {
        display: none;
    }
}

@media (max-width: 1100px) {
    .resource-bar__label {
        display: none;
    }

    .resource-bar__item {
        min-width: 0;
        grid-template-rows: 1fr;
        padding: 0.35rem 0.7rem 0.6rem;
    }

    .resource-bar__icon {
        grid-row: auto;
        width: 1.8rem;
        height: 1.8rem;
    }

    .resource-bar__value {
        align-self: center;
        font-size: 0.95rem;
    }

    .resource-bar__meter {
        left: 0.7rem;
        right: 0.7rem;
        bottom: 0.25rem;
    }

    .topbar__link-text {
        display: none;
    }
}

/* Tablets and phones: one column; the navigation becomes a scrolling strip of tabs. */
@media (max-width: 860px) {
    :root {
        --topbar-h: 3rem;
    }

    .topbar {
        flex-wrap: wrap;
        top: calc(-1 * var(--topbar-h));
        padding-top: 0.3rem;
        padding-bottom: 0.4rem;
        row-gap: 0.25rem;
    }

    .topbar__brand,
    .topbar__player {
        min-height: calc(var(--topbar-h) - 0.6rem);
    }

    .topbar__sigil {
        width: 1.6rem;
        height: 1.6rem;
    }

    .topbar__wordmark {
        font-size: 1.3rem;
    }

    .resource-bar {
        order: 3;
        flex: 1 0 100%;
        display: grid;
        grid-template-columns: repeat(5, minmax(0, 1fr));
        gap: 0.3rem;
    }

    .resource-bar__item {
        grid-template-columns: 1fr;
        justify-items: center;
        row-gap: 0.15rem;
        padding: 0.25rem 0.2rem 0.55rem;
        border: 1px solid var(--edge);
        border-radius: var(--radius);
        background: var(--ink-900);
    }

    .resource-bar__item--premium {
        margin-left: 0;
        background: var(--halftone-mustard), rgb(232 180 67 / 6%);
    }

    .resource-bar__icon {
        width: 1.5rem;
        height: 1.5rem;
    }

    .resource-bar__value {
        max-width: 100%;
        overflow: hidden;
        font-size: 0.78rem;
        text-overflow: clip;
    }

    /* Short names under the amounts, so the icons are learnt. */
    .resource-bar__label {
        display: block;
        order: 3;
        max-width: 100%;
        overflow: hidden;
        font-size: 0.56rem;
        letter-spacing: 0.05em;
        text-overflow: ellipsis;
    }

    .resource-bar__item.is-full .resource-bar__label::after,
    .resource-bar__item.is-short .resource-bar__label::after {
        content: none;
    }

    .resource-bar__meter {
        left: 0.35rem;
        right: 0.35rem;
        bottom: 0.2rem;
    }

    .shell {
        grid-template-columns: minmax(0, 1fr);
        grid-template-areas:
            "nav"
            "worlds"
            "content";
        gap: 0.9rem;
        padding-top: 1rem;
    }

    .sidenav {
        position: static;
        flex-direction: row;
        gap: 0.9rem;
        max-height: none;
        overflow-x: auto;
        overflow-y: hidden;
        margin: 0 calc(-1 * clamp(0.75rem, 2vw, 1.5rem));
        padding: 0.2rem clamp(0.75rem, 2vw, 1.5rem) 0.5rem;
        scroll-snap-type: x proximity;
        scrollbar-width: none;
    }

    .sidenav__group {
        flex-direction: row;
        flex: none;
        align-items: stretch;
        gap: 0.3rem;
        padding-left: 0.9rem;
        border-left: var(--dash);
    }

    .sidenav__group:first-child {
        padding-left: 0;
        border-left: 0;
    }

    .sidenav__group--misc {
        padding-top: 0;
        border-top: 0;
    }

    .sidenav__label {
        display: none;
    }

    /* The strip fades out at the right edge to show it scrolls. */
    .sidenav {
        mask-image: linear-gradient(to right, #000 calc(100% - 2.5rem), transparent);
    }

    .sidenav__item {
        flex-direction: column;
        gap: 0.2rem;
        min-width: 4.2rem;
        padding: 0.4rem 0.45rem 0.35rem;
        font-size: 0.72rem;
        text-align: center;
        white-space: nowrap;
        border: 1px solid var(--edge);
        scroll-snap-align: start;
    }

    .sidenav__item .badge {
        position: absolute;
        top: -0.35rem;
        right: -0.3rem;
        margin: 0;
    }

    .colonies__title {
        display: none;
    }
}

@media (max-width: 600px) {
    .panel {
        padding: 0.85rem 0.85rem 1rem;
    }

    .item-grid {
        grid-template-columns: repeat(auto-fill, minmax(min(100%, 15rem), 1fr));
    }

    /* On a phone the art becomes a banner so the name and button show with it. */
    .item-card__image {
        aspect-ratio: 2 / 1;
    }

    .topbar__name {
        max-width: 9rem;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
    }
}

@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 0.01ms !important;
        animation-iteration-count: 1 !important;
        transition-duration: 0.01ms !important;
        scroll-behavior: auto !important;
    }

    .btn:hover,
    .btn:active {
        transform: none;
    }
}
