/*
 * Global base styles.
 * ---------------------------------------------------------------------------
 * Bootstrap's reboot sets the page font, colour and background through its own
 * --bs-body-* custom properties. Rather than fighting it with overrides, the
 * brand tokens are assigned INTO those properties: Bootstrap then themes every
 * component it ships (navbar, dropdown, buttons, forms) from the ÁLFAR QUEST
 * palette, and the administrator's colour settings in MainLayout - which
 * override the --aq-* tokens on :root - keep flowing through automatically.
 */
:root {
    --bs-body-bg: var(--aq-bg-100);
    --bs-body-color: var(--aq-text-100);
    --bs-body-font-family: var(--aq-font-secondary);
    --bs-heading-color: var(--aq-text-100);
    --bs-link-color: var(--aq-primary);
    --bs-link-hover-color: var(--aq-text-100);
    --bs-border-color: var(--aq-border);
    --bs-emphasis-color: var(--aq-text-100);
}

/* Keeps the footer at the bottom on short pages instead of leaving a white
   gap below it, which is what the screenshot of an almost-empty page showed. */
html,
body {
    min-height: 100%;
}

body {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
}

/* Headings use the display font; body copy keeps the secondary font. */
h1, h2, h3, h4, h5, h6 {
    font-family: var(--aq-font-primary);
    letter-spacing: 0.01em;
}

/* The routed page content sits between the header and the footer and takes up
   whatever space is left. */
.site-main {
    flex: 1 0 auto;
}

/* Shared content wrapper for ordinary (non-homepage) pages. */
.page {
    max-width: var(--aq-content-width);
    padding: var(--aq-space-12) var(--aq-space-6);
    margin-inline: auto;
}

.page__heading {
    margin-block-end: var(--aq-space-4);
    font-size: var(--aq-text-3xl);
}

.page__intro {
    max-width: 60ch;
    color: var(--aq-text-300);
    font-size: var(--aq-text-lg);
}

/* Honest "nothing configured yet" state. The project never ships invented band
   copy, so an unconfigured page says so plainly. */
.empty-state {
    max-width: var(--aq-content-width);
    padding: var(--aq-space-16) var(--aq-space-6);
    margin-inline: auto;
    text-align: center;
}

.empty-state p {
    color: var(--aq-text-300);
}

/* Marks seeded sample copy and untranslated content so it can never be
   mistaken for the band's own words. */
.placeholder-note {
    display: inline-block;
    padding: var(--aq-space-1) var(--aq-space-3);
    border: 1px dashed var(--aq-border);
    border-radius: var(--aq-radius-sm);
    color: var(--aq-text-300);
    font-size: var(--aq-text-xs);
}

/* Secondary heading used by the catalogue pages to separate groups, such as
   the permanent line-up from guest artists, or history from fiction. */
.page__subheading {
    margin-block: var(--aq-space-8) var(--aq-space-4);
    font-size: var(--aq-text-2xl);
}

/* "Back to the listing" link at the foot of every detail page. */
.page__back {
    margin-block-start: var(--aq-space-8);
}

/* Shown only when a query has not resolved yet, which under static server
   rendering means the database is unreachable. */
.loading {
    padding: var(--aq-space-12) var(--aq-space-6);
    color: var(--aq-text-300);
    text-align: center;
}

/* ---- Catalogue listings --------------------------------------------------
   Releases, members, lore articles and merch all render as card grids. They
   share one auto-fitting grid so a listing never leaves a ragged last row,
   whatever the band publishes. Global, not component-scoped, because the
   cards are split across page and shared components. */
.release-list,
.member-list,
.lore-list,
.merch-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    gap: var(--aq-space-6);
    padding: 0;
    list-style: none;
}

.release-card,
.member-card,
.lore-card,
.merch-card {
    display: flex;
    flex-direction: column;
    gap: var(--aq-space-2);
    padding: var(--aq-space-4);
    background: var(--aq-bg-200);
    border: 1px solid var(--aq-border);
    border-radius: var(--aq-radius);
}

/* A featured merch item is highlighted with the brand colour rather than a
   larger cell, so the grid keeps its even rhythm. */
.merch-card--featured {
    border-color: var(--aq-primary);
}

/* Fiction and real history are visually distinct as well as labelled, but the
   label is what carries the meaning - the colour alone never does. */
.lore-card--fiction {
    border-inline-start: 3px solid var(--aq-primary);
}

.lore-card--history {
    border-inline-start: 3px solid var(--aq-border);
}

.release-card__link,
.member-card__link,
.lore-card__link {
    color: inherit;
    text-decoration: none;
}

.release-card__link:hover .release-card__title,
.release-card__link:focus-visible .release-card__title,
.member-card__link:hover .member-card__name,
.member-card__link:focus-visible .member-card__name,
.lore-card__link:hover .lore-card__title,
.lore-card__link:focus-visible .lore-card__title {
    color: var(--aq-primary);
}

.release-card__meta,
.member-card__role,
.merch-card__price,
.lore-card__badge {
    display: flex;
    flex-wrap: wrap;
    gap: var(--aq-space-3);
    margin: 0;
    color: var(--aq-text-300);
    font-size: var(--aq-text-sm);
}

.release-card__description,
.member-card__bio,
.lore-card__summary,
.merch-card__description {
    margin: 0;
    color: var(--aq-text-200);
    font-size: var(--aq-text-sm);
}

/* ---- Release detail ------------------------------------------------------ */
.release__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--aq-space-4);
    color: var(--aq-text-300);
}

.release__streaming,
.member__links {
    display: flex;
    flex-wrap: wrap;
    gap: var(--aq-space-4);
    padding: 0;
    list-style: none;
}

.tracklist {
    display: flex;
    flex-direction: column;
    gap: var(--aq-space-4);
    padding-inline-start: var(--aq-space-6);
}

.tracklist__item {
    padding-block: var(--aq-space-2);
    border-block-end: 1px solid var(--aq-border);
}

.tracklist__duration {
    margin-inline-start: var(--aq-space-3);
    color: var(--aq-text-300);
    font-variant-numeric: tabular-nums;
}

.tracklist__item audio {
    display: block;
    width: 100%;
    margin-block-start: var(--aq-space-2);
}

/* Lyrics and press copy are plain text from the admin area, so the band's own
   line breaks are preserved here rather than by injecting <br> markup. */
.tracklist__lyrics p,
.release__press,
.release__credits,
.member__bio,
.member__background,
.member__contributions,
.lore__body {
    max-width: 70ch;
    white-space: pre-wrap;
}

/* ---- Timeline -----------------------------------------------------------
   A single vertical rule with each event hanging off it. */
.timeline {
    display: flex;
    flex-direction: column;
    gap: var(--aq-space-6);
    padding-inline-start: var(--aq-space-6);
    border-inline-start: 2px solid var(--aq-border);
    list-style: none;
}

.timeline__event--fiction {
    border-inline-start: 3px solid var(--aq-primary);
    padding-inline-start: var(--aq-space-4);
}

.timeline__event--history {
    border-inline-start: 3px solid var(--aq-text-300);
    padding-inline-start: var(--aq-space-4);
}

.timeline__date {
    margin: 0;
    color: var(--aq-text-300);
    font-size: var(--aq-text-sm);
    font-variant-numeric: tabular-nums;
}

.timeline__badges {
    display: flex;
    flex-wrap: wrap;
    gap: var(--aq-space-3);
    margin: 0;
    font-size: var(--aq-text-xs);
    text-transform: uppercase;
    letter-spacing: 0.08em;
}

.timeline__kind,
.lore__badge {
    color: var(--aq-primary);
}

/* Shared admin content panel. Global rather than component-scoped because
   several /admin screens use it and CSS isolation would confine it to one. */
.admin-panel {
    max-width: 70ch;
    padding: var(--aq-space-6);
    background: var(--aq-bg-200);
    border: 1px solid var(--aq-border);
    border-radius: var(--aq-radius);
}

.admin-panel__heading {
    margin-block-end: var(--aq-space-4);
    font-size: var(--aq-text-lg);
}

.admin-panel p:last-child {
    margin-block-end: 0;
}

.admin-panel p {
    color: var(--aq-text-300);
}

/* The 70ch measure above is for prose. A panel wrapping a listing table needs
   the full width, or the reorder column wraps onto its own line. */
.admin-panel:has(.admin-table) {
    max-width: none;
}

/* Listing tables for the homepage and navigation editors. Bootstrap's .table
   handles the layout; these rules only supply the dark-theme colours, which
   Bootstrap's defaults get wrong against --aq-bg-200. */
.admin-table {
    --bs-table-color: var(--aq-text-100);
    --bs-table-bg: transparent;
    --bs-table-border-color: var(--aq-border);

    margin-block-end: 0;
    vertical-align: middle;
}

.admin-table th {
    font-size: var(--aq-text-sm);
    color: var(--aq-text-300);
    text-transform: uppercase;
    letter-spacing: 0.04em;
}

.admin-table code {
    color: var(--aq-text-300);
    word-break: break-all;
}

/* Edit link and the two reorder forms sit on one line. The forms are
   block-level by default, which would stack them vertically. */
.admin-table__actions {
    display: flex;
    gap: var(--aq-space-2);
    align-items: center;
    white-space: nowrap;
}

.admin-table__actions form {
    margin: 0;
}

/* The re-parent control: a select and its Apply button on one line. A plain
   form is block-level, which would stack the two and double the row height. */
.admin-table__nest {
  display: flex;
  gap: var(--aq-space-2);
  align-items: center;
  margin: 0;
}

/* Keeps the parent dropdown from stretching the Nesting column to the width of
   its longest option, which would squeeze the Actions column off narrow
   screens. */
.admin-table__nest select {
  min-width: 8rem;
  max-width: 12rem;
}

/* Colour preview beside a hex token on the appearance screen. Fixed width
   because it has no text content, so it would otherwise collapse. The colour
   itself is set inline from the stored value - it is data, not styling. */
.settings-swatch {
  width: 2.75rem;
  border-color: var(--aq-border);
}

/* Marks a nested menu entry. Purely decorative - the indent is a visual cue,
   so the glyph itself is aria-hidden in the markup. */
.admin-table__indent {
    display: inline-block;
    margin-inline-end: var(--aq-space-2);
    color: var(--aq-text-300);
}

/* Save/Cancel row beneath an editor form. */
.admin-form__actions {
    display: flex;
    gap: var(--aq-space-3);
    margin-block-start: var(--aq-space-6);
}

/* Media library thumbnail grid. auto-fill rather than a fixed column count,
   so the library reflows from a phone to a wide desktop without media
   queries. */
.media-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
    gap: var(--aq-space-4);

    /* It is a <ul>: drop the list affordances, keep the semantics. */
    padding: 0;
    margin: 0;
    list-style: none;
}

.media-grid__item {
    padding: var(--aq-space-3);
    background: var(--aq-bg-100);
    border: 1px solid var(--aq-border);
    border-radius: var(--aq-radius);
}

.media-grid__link {
    display: block;
    color: var(--aq-text-100);
    text-decoration: none;
}

.media-grid__link:hover .media-grid__name,
.media-grid__link:focus-visible .media-grid__name {
    text-decoration: underline;
}

/* Fixed-height box with a checkerboard behind it, so a transparent PNG is
   distinguishable from a white one - which matters when picking a logo. */
.media-grid__thumb {
    display: flex;
    align-items: center;
    justify-content: center;
    block-size: 140px;
    margin-block-end: var(--aq-space-2);
    overflow: hidden;
    background-color: var(--aq-bg-200);
    background-image:
        linear-gradient(45deg, var(--aq-overlay) 25%, transparent 25%),
        linear-gradient(-45deg, var(--aq-overlay) 25%, transparent 25%),
        linear-gradient(45deg, transparent 75%, var(--aq-overlay) 75%),
        linear-gradient(-45deg, transparent 75%, var(--aq-overlay) 75%);
    background-position: 0 0, 0 8px, 8px -8px, -8px 0;
    background-size: 16px 16px;
    border-radius: var(--aq-radius-sm);
}

/* contain, not cover: the grid is for IDENTIFYING a file, so seeing the whole
   image matters more than filling the tile neatly. */
.media-grid__thumb img {
    max-inline-size: 100%;
    max-block-size: 100%;
    object-fit: contain;
}

.media-grid__icon {
    font-size: var(--aq-text-3xl);
    color: var(--aq-text-300);
}

/* Long upload names must not stretch the grid column, so they wrap. */
.media-grid__name {
    display: block;
    font-size: var(--aq-text-sm);
    word-break: break-word;
}

.media-grid__meta {
    margin: var(--aq-space-1) 0 0;
    font-size: var(--aq-text-xs);
    color: var(--aq-text-300);
}

/* Missing alt text is an accessibility defect, so it is coloured as a warning
   rather than as muted metadata. */
.media-grid__warning {
    margin: var(--aq-space-1) 0 0;
    font-size: var(--aq-text-xs);
    font-weight: 600;
    color: var(--aq-accent);
}

/* Focal point editor: preview beside the two number fields, stacking on
   narrow screens. */
.media-focal {
    display: flex;
    flex-wrap: wrap;
    gap: var(--aq-space-6);
    align-items: flex-start;
}

.media-focal__frame {
    position: relative;
    flex: 1 1 280px;
    max-inline-size: 420px;
    line-height: 0;
}

.media-focal__image {
    inline-size: 100%;
    block-size: auto;
    border-radius: var(--aq-radius-sm);
}

/* Crosshair marking the saved focal point. Centred on its coordinates via the
   translate, so the ring's middle - not its corner - sits on the point. */
.media-focal__marker {
    position: absolute;
    inline-size: 24px;
    block-size: 24px;
    border: 2px solid var(--aq-primary);
    border-radius: var(--aq-radius-pill);
    box-shadow: 0 0 0 2px var(--aq-overlay);
    transform: translate(-50%, -50%);
}

.media-focal__controls {
    flex: 1 1 220px;
}

/* Read-only file facts. Two columns on anything wider than a phone. */
.media-detail {
    display: grid;
    grid-template-columns: max-content 1fr;
    gap: var(--aq-space-2) var(--aq-space-4);
    margin: 0;
}

.media-detail dt {
    font-size: var(--aq-text-sm);
    color: var(--aq-text-300);
}

.media-detail dd {
    margin: 0;
    word-break: break-word;
}

h1:focus {
    outline: none;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid #e50000;
}

.validation-message {
    color: #e50000;
}

.blazor-error-boundary {
    background: url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iNTYiIGhlaWdodD0iNDkiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiIG92ZXJmbG93PSJoaWRkZW4iPjxkZWZzPjxjbGlwUGF0aCBpZD0iY2xpcDAiPjxyZWN0IHg9IjIzNSIgeT0iNTEiIHdpZHRoPSI1NiIgaGVpZ2h0PSI0OSIvPjwvY2xpcFBhdGg+PC9kZWZzPjxnIGNsaXAtcGF0aD0idXJsKCNjbGlwMCkiIHRyYW5zZm9ybT0idHJhbnNsYXRlKC0yMzUgLTUxKSI+PHBhdGggZD0iTTI2My41MDYgNTFDMjY0LjcxNyA1MSAyNjUuODEzIDUxLjQ4MzcgMjY2LjYwNiA1Mi4yNjU4TDI2Ny4wNTIgNTIuNzk4NyAyNjcuNTM5IDUzLjYyODMgMjkwLjE4NSA5Mi4xODMxIDI5MC41NDUgOTIuNzk1IDI5MC42NTYgOTIuOTk2QzI5MC44NzcgOTMuNTEzIDI5MSA5NC4wODE1IDI5MSA5NC42NzgyIDI5MSA5Ny4wNjUxIDI4OS4wMzggOTkgMjg2LjYxNyA5OUwyNDAuMzgzIDk5QzIzNy45NjMgOTkgMjM2IDk3LjA2NTEgMjM2IDk0LjY3ODIgMjM2IDk0LjM3OTkgMjM2LjAzMSA5NC4wODg2IDIzNi4wODkgOTMuODA3MkwyMzYuMzM4IDkzLjAxNjIgMjM2Ljg1OCA5Mi4xMzE0IDI1OS40NzMgNTMuNjI5NCAyNTkuOTYxIDUyLjc5ODUgMjYwLjQwNyA1Mi4yNjU4QzI2MS4yIDUxLjQ4MzcgMjYyLjI5NiA1MSAyNjMuNTA2IDUxWk0yNjMuNTg2IDY2LjAxODNDMjYwLjczNyA2Ni4wMTgzIDI1OS4zMTMgNjcuMTI0NSAyNTkuMzEzIDY5LjMzNyAyNTkuMzEzIDY5LjYxMDIgMjU5LjMzMiA2OS44NjA4IDI1OS4zNzEgNzAuMDg4N0wyNjEuNzk1IDg0LjAxNjEgMjY1LjM4IDg0LjAxNjEgMjY3LjgyMSA2OS43NDc1QzI2Ny44NiA2OS43MzA5IDI2Ny44NzkgNjkuNTg3NyAyNjcuODc5IDY5LjMxNzkgMjY3Ljg3OSA2Ny4xMTgyIDI2Ni40NDggNjYuMDE4MyAyNjMuNTg2IDY2LjAxODNaTTI2My41NzYgODYuMDU0N0MyNjEuMDQ5IDg2LjA1NDcgMjU5Ljc4NiA4Ny4zMDA1IDI1OS43ODYgODkuNzkyMSAyNTkuNzg2IDkyLjI4MzcgMjYxLjA0OSA5My41Mjk1IDI2My41NzYgOTMuNTI5NSAyNjYuMTE2IDkzLjUyOTUgMjY3LjM4NyA5Mi4yODM3IDI2Ny4zODcgODkuNzkyMSAyNjcuMzg3IDg3LjMwMDUgMjY2LjExNiA4Ni4wNTQ3IDI2My41NzYgODYuMDU0N1oiIGZpbGw9IiNGRkU1MDAiIGZpbGwtcnVsZT0iZXZlbm9kZCIvPjwvZz48L3N2Zz4=) no-repeat 1rem/1.8rem, #b32121;
    padding: 1rem 1rem 1rem 3.7rem;
    color: white;
}

    .blazor-error-boundary::after {
        content: "An error has occurred."
    }

.darker-border-checkbox.form-check-input {
    border-color: #929292;
}

.form-floating > .form-control-plaintext::placeholder, .form-floating > .form-control::placeholder {
    color: var(--bs-secondary-color);
    text-align: end;
}

.form-floating > .form-control-plaintext:focus::placeholder, .form-floating > .form-control:focus::placeholder {
    text-align: start;
}