/*
 * The shell only — masthead, footer, type scale, the handful of elements every page
 * has. Everything a single page needs lives in that page's own {% block styles %}.
 *
 * That split is this site's `css` axis: a stylesheet per page rather than one for the
 * site. The profile page carries a gallery, a viewer dialog and a review list; the
 * terms page carries prose. Serving one file that answers for both means every reader
 * of the terms page downloads and parses rules for a photo viewer they will never see,
 * and the file only ever grows, because nothing is ever safe to delete from it.
 *
 * Selectors here are ids and element names. There is almost no class vocabulary on this
 * site by design: a class list is the most mechanical thing a script can compare across
 * two domains, and an id is scoped to one page's one element, so there is nothing to
 * diff. Styling reaches elements through structure — `#listing > article` — rather than
 * through names attached to them.
 */

:root {
    /* Two ends and very little between them. Mountain light is either on or off, and the
       palette is read that way: near-black ground, near-white text, one signal colour. */
    --ground: #0a0c10;
    --raised: #14171e;
    --ink: #f4f6f8;
    --quiet: #9aa4b2;
    --edge: #2a3038;
    --signal: #d8ff3e;
    /* The full-bleed measure. Content runs to the window edges with only this gutter, so
       there is no centred column anywhere on the site — no wrapper element exists to
       apply one to. */
    --gutter: clamp(16px, 4vw, 40px);
}

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

html {
    /* Never a horizontal scrollbar, whatever a long unbroken word in donor copy does. */
    overflow-x: hidden;
}

body {
    margin: 0;
    background: var(--ground);
    color: var(--ink);
    /* Condensed faces first, and only ones that ship with an operating system. No webfont
       is fetched anywhere on this site: a font pulled from a third party is a request every
       page here makes to one outside host, which is a dependency and a giveaway as much
       as a dependency. Where nothing condensed exists the stack falls to the system sans
       and the page is merely wider, not broken. */
    font-family: "Roboto Condensed", "Liberation Sans Narrow", "Arial Narrow", "Helvetica Neue Condensed", system-ui, sans-serif;
    font-size: 17px;
    line-height: 1.55;
    -webkit-text-size-adjust: 100%;
}

/* Nothing on this site is rounded except things you press. Roundness is the signal for
   "pressable" rather than decoration, so panels, photographs and inputs stay square and
   a capsule always means a control. */
a[data-action] {
    display: inline-block;
    padding: 11px 22px;
    border-radius: 999px;
    background: var(--signal);
    color: #0a0c10;
    font-weight: 700;
    letter-spacing: 0.02em;
    text-decoration: none;
}

/* Die Kontaktzeile ist eine Reihe, kein Fliesstext. Als `inline-block` in einem Absatz
   brachen die Kapseln wie Wörter um: auf einem 390px-Telefon rutschte „Weitere Fotos"
   eine Zeile tiefer und an den linken Rand, während „Nummer anzeigen" eingerückt neben
   der Nummer stehen blieb — gemessen: top 1712 gegen 1760, left 104 gegen 16.

   Die Nummer bekommt eine eigene Zeile, die Kapseln teilen sich die nächste. Nur zu
   umbrechen genügte nicht: Nummer plus beide Kapseln sind zusammen breiter als ein
   Telefon, also blieb eine Kapsel neben der Nummer hängen und die andere sprang allein
   nach unten — derselbe schiefe Eindruck, nur eine Zeile später. */
[data-role="contact"] {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 10px 12px;
}

[data-role="contact"] strong { flex-basis: 100%; }

a[data-action="quiet"] {
    background: transparent;
    color: var(--ink);
    border: 1px solid var(--edge);
}

a[data-action]:hover {
    filter: brightness(1.08);
}

a {
    color: var(--ink);
    text-decoration-color: var(--edge);
    text-underline-offset: 3px;
}

a:hover {
    text-decoration-color: var(--signal);
}

img {
    max-width: 100%;
    height: auto;
    display: block;
}

h1, h2, h3 {
    line-height: 1.12;
    letter-spacing: -0.01em;
    margin: 0 0 12px;
    font-weight: 700;
}

h1 {
    font-size: clamp(30px, 6vw, 52px);
    text-transform: uppercase;
}

h2 {
    font-size: clamp(20px, 3vw, 27px);
    margin-top: 34px;
}

h3 {
    font-size: 19px;
}

p {
    margin: 0 0 14px;
    /* Prose does not run the full width of a wide window even on a full-bleed site: a
       line of seventy characters is read, a line of two hundred is scanned and lost. The
       layout is edge-to-edge; the sentence inside it still has a measure. */
    max-width: 68ch;
}

#masthead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
    padding: 16px var(--gutter);
    border-bottom: 1px solid var(--edge);
    background: var(--ground);
}

#masthead > a {
    display: flex;
    align-items: center;
    gap: 11px;
    text-decoration: none;
    /* The wordmark is set heavy, all caps and tight — the way lettering is cut into a
       trail sign, where it has to read at a distance and in bad light. */
    font-weight: 800;
    font-size: clamp(19px, 3.4vw, 25px);
    letter-spacing: 0.06em;
    text-transform: uppercase;
    /* Without this the mark and the name refuse to shrink below their content and push
       the navigation off a narrow screen. */
    min-width: 0;
}

#masthead svg {
    flex: none;
}

#masthead nav {
    display: flex;
    gap: 20px;
    font-size: 15px;
    text-transform: uppercase;
    letter-spacing: 0.07em;
}

#masthead nav a {
    text-decoration: none;
    color: var(--quiet);
    padding: 4px 0;
}

#masthead nav a[aria-current] {
    color: var(--signal);
    box-shadow: inset 0 -2px 0 var(--signal);
}

main {
    padding: 0 var(--gutter) 56px;
}

#colophon {
    border-top: 1px solid var(--edge);
    padding: 26px var(--gutter) 40px;
    color: var(--quiet);
    font-size: 14px;
    display: flex;
    justify-content: space-between;
    gap: 14px;
    flex-wrap: wrap;
}

#colophon a {
    color: var(--quiet);
}

/*
 * The listing, shared because three pages build one: a run of bare <article> elements
 * with no wrapping element and no card around each. A stack of entries, the way a
 * register is read down a page, not a grid of tiles.
 *
 * The stack lays itself out in columns on a wide screen, which is not the same thing as
 * becoming a grid: an entry is still a row — thumbnail left, name right, a rule above it
 * — and it is still read downwards. What changes is that the register runs in two or
 * three columns instead of one, the way a printed index does, rather than leaving
 * two-thirds of a desktop empty beside a 74px picture.
 */
#listing {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(min(330px, 100%), 1fr));
    column-gap: 34px;
}

/* The profile page puts its heading INSIDE the listing, so the grid made it a cell: the
   heading took the first column and pushed the first entry into the second, leaving a
   hole under it. Anything that is not an entry spans the whole row. */
#listing > :not(article) {
    grid-column: 1 / -1;
}

#listing > article {
    border-top: 1px solid var(--edge);
}

#listing > article > a {
    display: flex;
    align-items: center;
    gap: 16px;
    padding: 13px 0;
    text-decoration: none;
}

#listing > article img {
    /* 96 rather than 74: the row got wider when the register went into columns, and at
       74 the picture read as an icon beside the name instead of as a face. The donor's
       thumbnails arrive at 320, 150 and 87 wide, so no single drawn size is true for all
       of them; 3:4 is the ratio every one of them shares. */
    width: 96px;
    aspect-ratio: 3 / 4;
    object-fit: cover;
    flex: none;
}

#listing > article h3 {
    margin: 0;
    font-weight: 700;
    letter-spacing: 0.01em;
    /* A name is data and can be long. Without this the flex item refuses to shrink below
       its text and pushes the age off the row. */
    min-width: 0;
    overflow-wrap: anywhere;
}

#listing > article p {
    margin: 0;
    color: var(--quiet);
    font-size: 15px;
}

@media (prefers-reduced-motion: no-preference) {
    html {
        scroll-behavior: smooth;
    }
}

/* The picture in hand while the next one travels: the file comes through PHP from
   object storage and takes a second or more, and the old photograph stays on screen
   the whole time. Fading it is what tells the reader the click was heard. */
img[aria-busy] { opacity: 0.4; filter: saturate(0.5); transition: opacity 0.12s linear; }
