/*
 *  index.css
 *  Wayfare — the landing page
 *
 *  The Index, ported to the web. Every value here comes from the app:
 *  colours from `Palette.swift`, type from `Typeface.swift`, spacing,
 *  radius and motion from `DesignSystem.swift`, component geometry from the
 *  view that owns it. Nothing is approximated — when the app changes a
 *  token, this file changes with it.
 *
 *  The same house rules apply. Never a gradient, never a shadow, never a
 *  colour outside the palette, never a hardcoded size where a token exists.
 *  Structure comes from rules and margins.
 */

/* ── Faces ─────────────────────────────────────────────────────────────
 *
 *  The two variable faces the app registers at launch, served as the same
 *  TTFs the bundle carries. Both axis ranges are declared so the browser
 *  interpolates rather than synthesising a weight.
 *
 *  Fraunces' optical-size axis is the reason the family was chosen, so it
 *  is wired into every display token below at the size that token renders,
 *  exactly as `UIFont.display(size:weight:wonk:)` does.
 */

@font-face {
    font-family: "Fraunces";
    src: url("fonts/Fraunces-Variable.ttf") format("truetype-variations");
    font-weight: 100 900;
    font-display: swap;
}

@font-face {
    font-family: "Archivo";
    src: url("fonts/Archivo-Variable.ttf") format("truetype-variations");
    font-weight: 100 900;
    font-stretch: 62% 125%;
    font-display: swap;
}

/* ── Tokens ────────────────────────────────────────────────────────────── */

:root {
    /* Ground */
    --sheet: #F2F1EC;
    --plate: #FBFAF7;
    --well: #E7E5DE;

    /* Rules */
    --rule: #C9C7BC;
    --rule-strong: #A8A69A;

    /* Ink */
    --ink: #232320;
    --ink-secondary: #55544C;
    --ink-tertiary: #6E6D64;

    /* The three meaningful colours. `accession` is the mark of having been
       somewhere, `herbarium` is selection and filing state, `marginalia` is
       noted but not filed. Nothing else may use them, and a new section does
       not get a colour of its own. */
    --accession: #9C3A28;
    --herbarium: #4A5247;
    --marginalia: #3E5C76;

    /* Spacing */
    --space-xxxs: 2px;
    --space-xxs: 4px;
    --space-xs: 8px;
    --space-sm: 12px;
    --space-md: 16px;
    --space-lg: 28px;
    --space-xl: 40px;
    --space-xxl: 64px;
    --margin: 20px;
    --indent: 12px;

    /* Corner radius */
    --radius-xs: 3px;
    --radius-sm: 6px;
    --radius-md: 10px;
    --radius-lg: 14px;

    /* Tap targets */
    --tap-minimum: 44px;
    --tap-comfortable: 48px;

    /* Motion. `DSMotion.snappy` and `.sheet` are springs, which CSS cannot
       express without a keyframe library; these are the nearest honest
       curves at the same durations. `fade` is exact. */
    --fade: 180ms ease-out;
    --snappy: 240ms cubic-bezier(0.2, 0.9, 0.3, 1);
    --sheet-motion: 360ms cubic-bezier(0.2, 0.9, 0.3, 1);

    /* The page. Wider than a phone, but a register still wants a measure it
       can be read across rather than the full width of a monitor. */
    --measure: 680px;

    color-scheme: light dark;
}

/* Dark resolves per scheme the way the `UIColor` providers do. The manual
   choice below mirrors `AppearanceManager` — light, dark, or follow the
   system. */
@media (prefers-color-scheme: dark) {
    :root {
        --sheet: #191A17;
        --plate: #212320;
        --well: #131412;

        --rule: #35372F;
        --rule-strong: #4A4C43;

        --ink: #EDEBE1;
        --ink-secondary: #A5A497;
        --ink-tertiary: #85847A;

        --accession: #E0553A;
        --herbarium: #8FA189;
        --marginalia: #8AA9C4;
    }
}

:root[data-appearance="light"] {
    --sheet: #F2F1EC;
    --plate: #FBFAF7;
    --well: #E7E5DE;
    --rule: #C9C7BC;
    --rule-strong: #A8A69A;
    --ink: #232320;
    --ink-secondary: #55544C;
    --ink-tertiary: #6E6D64;
    --accession: #9C3A28;
    --herbarium: #4A5247;
    --marginalia: #3E5C76;
    color-scheme: light;
}

:root[data-appearance="dark"] {
    --sheet: #191A17;
    --plate: #212320;
    --well: #131412;
    --rule: #35372F;
    --rule-strong: #4A4C43;
    --ink: #EDEBE1;
    --ink-secondary: #A5A497;
    --ink-tertiary: #85847A;
    --accession: #E0553A;
    --herbarium: #8FA189;
    --marginalia: #8AA9C4;
    color-scheme: dark;
}

/* ── Type tokens ───────────────────────────────────────────────────────
 *
 *  One class per `ds_*` token, named the same. Display carries `opsz` set
 *  to its own rendered size and WONK on; `ds_serifBody` turns WONK off,
 *  because the splayed alternates are a signature at 34px and a
 *  distraction across a paragraph.
 */

.ds_plate_title {
    font-family: "Fraunces", Georgia, serif;
    font-size: 40px;
    font-variation-settings: "wght" 500, "opsz" 40, "SOFT" 0, "WONK" 1;
    line-height: 1.1;
}

.ds_display_large {
    font-family: "Fraunces", Georgia, serif;
    font-size: 34px;
    font-variation-settings: "wght" 500, "opsz" 34, "SOFT" 0, "WONK" 1;
    line-height: 1.15;
}

.ds_display_medium {
    font-family: "Fraunces", Georgia, serif;
    font-size: 28px;
    font-variation-settings: "wght" 500, "opsz" 28, "SOFT" 0, "WONK" 1;
    line-height: 1.2;
}

.ds_heading1 {
    font-family: "Fraunces", Georgia, serif;
    font-size: 24px;
    font-variation-settings: "wght" 500, "opsz" 24, "SOFT" 0, "WONK" 1;
    line-height: 1.25;
}

.ds_heading2 {
    font-family: "Fraunces", Georgia, serif;
    font-size: 20px;
    font-variation-settings: "wght" 500, "opsz" 20, "SOFT" 0, "WONK" 1;
    line-height: 1.3;
}

.ds_serif_body {
    font-family: "Fraunces", Georgia, serif;
    font-size: 17px;
    font-variation-settings: "wght" 400, "opsz" 17, "SOFT" 0, "WONK" 0;
    line-height: 1.5;
}

.ds_heading3 {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 17px;
    font-variation-settings: "wght" 600, "wdth" 100;
    line-height: 1.3;
}

.ds_body_large {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 17px;
    font-variation-settings: "wght" 400, "wdth" 100;
    line-height: 1.5;
}

.ds_body_regular {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 15px;
    font-variation-settings: "wght" 400, "wdth" 100;
    line-height: 1.5;
}

.ds_body_medium {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 14px;
    font-variation-settings: "wght" 400, "wdth" 100;
    line-height: 1.5;
}

.ds_body_small {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 13px;
    font-variation-settings: "wght" 400, "wdth" 100;
    line-height: 1.45;
}

.ds_label_large {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 15px;
    font-variation-settings: "wght" 600, "wdth" 100;
    line-height: 1.3;
}

.ds_label_medium {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 13px;
    font-variation-settings: "wght" 600, "wdth" 100;
    line-height: 1.3;
}

.ds_label_small {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 11px;
    font-variation-settings: "wght" 500, "wdth" 100;
    line-height: 1.3;
}

.ds_caption {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 11px;
    font-variation-settings: "wght" 400, "wdth" 100;
    line-height: 1.4;
}

/* The register: Archivo with tabular figures, so columns of numbers line up
   down a list. `.registerFigures()` and `.accessionTracking()` in the app. */

.ds_accession {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 11px;
    font-variation-settings: "wght" 600, "wdth" 100;
    font-variant-numeric: tabular-nums lining-nums;
    letter-spacing: 0.8px;
    text-transform: uppercase;
    line-height: 1.3;
}

.ds_stat {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 22px;
    font-variation-settings: "wght" 600, "wdth" 100;
    font-variant-numeric: tabular-nums lining-nums;
    line-height: 1.2;
}

.ds_stat_small {
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 16px;
    font-variation-settings: "wght" 600, "wdth" 100;
    font-variant-numeric: tabular-nums lining-nums;
    line-height: 1.2;
}

.figures {
    font-variant-numeric: tabular-nums lining-nums;
}

/* ── Ground ────────────────────────────────────────────────────────────── */

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

html {
    -webkit-text-size-adjust: 100%;
}

body {
    margin: 0;
    /* `SheetGround` — every screen sits on this and nothing paints over it. */
    background: var(--sheet);
    color: var(--ink);
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 15px;
    -webkit-font-smoothing: antialiased;
}

/* `TabRootScaffold`: the page margin, and a measure the register is read
   across. */
.scaffold {
    max-width: calc(var(--measure) + var(--margin) * 2);
    margin: 0 auto;
    padding: 0 var(--margin);
}

/* The atlas is a map, and a map is the one thing here that earns more width
   than a column of type. */
.scaffold--wide {
    max-width: 1040px;
}

button {
    font: inherit;
    color: inherit;
    background: none;
    border: 0;
    padding: 0;
    margin: 0;
    cursor: pointer;
    text-align: left;
}

/* ── Rules ─────────────────────────────────────────────────────────────
 *
 *  The hairline that does the structural work everywhere in this system.
 */

.rule {
    height: 1px;
    background: var(--rule);
    border: 0;
    margin: 0;
    flex: none;
}

.rule--strong {
    background: var(--rule-strong);
}

.rule--vertical {
    width: 1px;
    height: 44px;
    background: var(--rule);
}

/* ── Accession line ────────────────────────────────────────────────────
 *
 *  The catalogue mark. The app's one bold element, and the only place red
 *  appears — once per plate, or once per group, never once per row.
 */

.accession {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    color: var(--accession);
}

.accession__tick {
    width: 12px;
    height: 1px;
    background: var(--rule);
    flex: none;
}

.accession__detail {
    color: var(--ink-tertiary);
}

/* ── Visit mark ────────────────────────────────────────────────────────
 *
 *  10px square, 3px radius. Filled `accession` when you have been; an
 *  outline in the state's tint when you have not. The one place in a list
 *  where filling something in is visible progress.
 */

.mark {
    width: 10px;
    height: 10px;
    flex: none;
    border-radius: var(--radius-xs);
    border: 1px solid var(--rule-strong);
    background: transparent;
    align-self: center;
}

.mark--visited {
    background: var(--accession);
    border-color: transparent;
}

.mark--home {
    background: var(--marginalia);
    border-color: transparent;
}

.mark--planned {
    border: 2px solid var(--herbarium);
}

.mark--bucket {
    border-color: var(--marginalia);
}

/* ── Masthead ──────────────────────────────────────────────────────────
 *
 *  `TabTitleHeader` with the rule under it. The rule is load-bearing: it is
 *  what separates the masthead from the register below, which is why the
 *  header needs no background and no shadow.
 */

.masthead {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding-top: var(--space-md);
    padding-bottom: var(--space-sm);
}

.masthead__mark {
    width: 28px;
    height: 28px;
    flex: none;
}

.masthead__title {
    color: var(--ink);
    margin: 0;
}

.masthead__spacer {
    flex: 1;
}

/* `HeaderAction` — a ruled square, not a floating circle. */
.header_action {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    min-width: var(--tap-minimum);
    min-height: var(--tap-minimum);
    padding: 0 var(--space-sm);
    color: var(--ink);
    text-decoration: none;
    border: 1px solid var(--rule-strong);
    border-radius: var(--radius-sm);
    transition: opacity var(--fade);
}

.header_action:hover {
    opacity: 0.7;
}

/* The one header action that is a destination rather than a control. Filled
   in ink so the pair reads as "the way in" and "the other way in", which is
   what they are, without inventing a colour for it. */
.header_action--filled {
    background: var(--ink);
    color: var(--sheet);
    padding: 0 var(--space-sm);
    border-radius: var(--radius-sm);
}

.header_action--filled:hover {
    background: var(--ink-secondary);
    color: var(--sheet);
}

.header_action--selected {
    color: var(--herbarium);
    border-color: var(--herbarium);
}

.header_action__glyph {
    width: 16px;
    height: 16px;
}

/* ── Sections ──────────────────────────────────────────────────────────── */

.section {
    padding-top: var(--space-lg);
}

/* `SectionHeader`: a strong rule, then the title. Announces a new part of
   the page. */
.section_header {
    display: flex;
    align-items: baseline;
    gap: var(--space-xs);
    padding-top: var(--space-xs);
    padding-bottom: var(--space-xs);
    margin: 0;
    color: var(--ink);
}

.section_header__count {
    color: var(--ink-tertiary);
    font-variant-numeric: tabular-nums;
}

.section_header__spacer {
    flex: 1;
}

/* "See all" is the one link in a section head, and `herbarium` is the
   colour of a thing you are choosing to open. */
.section_header__action {
    color: var(--herbarium);
}

/* `GroupHeading` owns the space below itself and none above, so how far one
   group sits from the last stays a question about the page. */
.group_heading {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    padding-bottom: var(--space-xs);
}

.group_heading--following {
    padding-top: var(--space-lg);
}

.group_heading__spacer {
    flex: 1;
}

/* Rows under a group heading are indented. The heading marks the group, the
   indent shows what is in it, and neither reads without the other. */
.group_rows {
    padding-left: var(--indent);
}

/* ── Hero ──────────────────────────────────────────────────────────────
 *
 *  `WelcomeStep`, which is already the pitch: the name, the hook set in
 *  Fraunces, the sentence under it, then the four things the app does.
 */

.hero {
    padding-top: var(--space-lg);
    padding-bottom: var(--space-md);
}

.hero__hook {
    margin: 0 0 var(--space-sm);
    color: var(--ink);
    max-width: 30ch;
}

/*
 *  The map under the hook.
 *
 *  It runs wider than the type does, because the measure exists to keep a
 *  line of prose readable and a map is not prose — the atlas earns the width
 *  in the app for the same reason. `.map` brings its own hairlines top and
 *  bottom, so there is no rule here.
 */
.hero_map {
    padding-top: var(--space-lg);
    padding-bottom: var(--space-lg);
}

/*
 *  The landing page is a website: a masthead across the top, a column of
 *  type on the sheet, the map beside it. Not the welcome screen mounted
 *  on a plate over a background.
 */
body.landing {
    min-height: 100svh;
    display: flex;
    flex-direction: column;
}

.landing__chrome {
    flex: none;
    background: var(--sheet);
}

.landing__masthead {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
    padding: var(--space-md) var(--margin) var(--space-sm);
}

.landing__stage {
    flex: 1 1 auto;
    min-height: 24rem;
    display: grid;
    grid-template-columns: minmax(26rem, 30rem) minmax(0, 1fr);
}

.landing__pitch {
    min-width: 0;
    min-height: 0;
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: var(--space-md);
    padding: var(--space-xl) var(--margin);
    background: var(--sheet);
    border-right: 1px solid var(--rule-strong);
}

.landing__hook {
    margin: 0;
    color: var(--ink);
    max-width: 16ch;
}

.landing__lede {
    margin: 0;
    color: var(--ink-secondary);
    max-width: 32ch;
}

.landing__promises {
    list-style: none;
    margin: var(--space-sm) 0 0;
    padding: var(--space-md) 0 0;
    border-top: 1px solid var(--rule);
    display: grid;
    gap: var(--space-xs);
    color: var(--ink-secondary);
    max-width: 32ch;
}

.landing__map {
    position: relative;
    min-width: 0;
    min-height: 0;
    overflow: hidden;
}

.landing__map .map {
    height: 100%;
    aspect-ratio: auto;
    border: 0;
}

@media (max-width: 54rem) {
    .landing__stage {
        grid-template-columns: 1fr;
        grid-template-rows: auto minmax(18rem, 50svh);
    }

    .landing__pitch {
        border-right: 0;
        border-bottom: 1px solid var(--rule-strong);
        padding-top: var(--space-lg);
        padding-bottom: var(--space-lg);
    }

    .landing__hook {
        max-width: none;
    }

    .landing__map .pin__label {
        display: block;
    }
}

.hero__lede {
    margin: 0;
    color: var(--ink-secondary);
    max-width: 58ch;
}

/* ── Register rows ─────────────────────────────────────────────────────
 *
 *  `registerRow()`: flat on the sheet with a hairline beneath. Rows in this
 *  system are separated by rules, not by gaps between floating cards.
 */

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

.register_row {
    display: block;
    width: 100%;
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--rule);
}

.register_row--bare {
    border-bottom: 0;
}

.register_row--interactive {
    transition: opacity var(--fade);
}

.register_row--interactive:hover {
    opacity: 0.72;
}

.register_row__line {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
}

.register_row__body {
    flex: 1;
    min-width: 0;
}

.register_row__title {
    margin: 0;
    color: var(--ink);
}

/* 2pt, not a token — the app sets this stack at a literal 2 so the caption
   sits under the title as one block rather than as a second line. */
.register_row__detail {
    margin: 2px 0 0;
    color: var(--ink-tertiary);
}

.register_row__note {
    margin: var(--space-xxs) 0 0;
    color: var(--ink-secondary);
}

.register_row__chevron {
    width: 12px;
    height: 12px;
    flex: none;
    color: var(--ink-tertiary);
    align-self: center;
}

.register_row__count {
    color: var(--ink-tertiary);
    flex: none;
}

/* `DefinitionRow`: the field, then its value. A definition list, because
   naming the field is what lets a reader scan for the one they want. */
.definition {
    display: flex;
    align-items: baseline;
    gap: var(--space-xs);
    padding: var(--space-sm) 0;
    border-bottom: 1px solid var(--rule);
}

.definition__label {
    width: 108px;
    flex: none;
    color: var(--ink-tertiary);
}

.definition__value {
    margin: 0;
    color: var(--ink);
}

/* ── Plate ─────────────────────────────────────────────────────────────
 *
 *  The one surface treatment: flat fill, hairline edge, tight corners. A
 *  24px radius reads as a card in a feed; 6px reads as a trimmed sheet,
 *  which is the point. There is no second card style.
 */

.plate {
    background: var(--plate);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    padding: var(--space-md);
}

.plate--outline {
    background: transparent;
}

.plate--flush {
    padding: 0;
    overflow: hidden;
}

/* ── Empty state ───────────────────────────────────────────────────────
 *
 *  An empty screen is an invitation to act, so it is written as one: what
 *  this will hold, and the one action that starts filling it. Drawn as an
 *  empty plate outline — the shape of the thing that is missing.
 */

.empty {
    display: grid;
    justify-items: center;
    gap: var(--space-md);
    text-align: center;
    padding: var(--space-xl) var(--space-lg);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
}

.empty__symbol {
    width: 22px;
    height: 22px;
    color: var(--ink-tertiary);
}

.empty__title {
    margin: 0;
    color: var(--ink);
}

.empty__subtitle {
    margin: var(--space-xs) 0 0;
    color: var(--ink-secondary);
    max-width: 42ch;
}

/* ── Buttons ───────────────────────────────────────────────────────────── */

/* `DSPrimaryButton`: solid ink, square-ish, no gradient and no glow. */
.button_primary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    min-height: var(--tap-comfortable);
    padding: var(--space-sm) var(--space-lg);
    background: var(--ink);
    color: var(--sheet);
    border: 1px solid var(--ink);
    border-radius: var(--radius-sm);
    text-decoration: none;
    /* `.scaleButtonStyle()` — the press, ported. */
    transition: transform 120ms ease-out, opacity var(--fade);
}

.button_primary:active {
    transform: scale(0.97);
}

.button_primary--wide {
    width: 100%;
}

/* The button before there is anything to link to. Ruled and quiet rather
   than a lit control that does nothing — a full-strength button that
   refuses the press reads as broken instead of as not yet. */
.button_primary[aria-disabled="true"] {
    background: transparent;
    color: var(--ink-tertiary);
    border-color: var(--rule-strong);
    cursor: default;
}

.button_primary[aria-disabled="true"]:active {
    transform: none;
}

.button_primary__mark {
    width: 18px;
    height: 18px;
    flex: none;
}

/* `DSSecondaryButton`: a ruled outline, which is how this system says
   "button" without spending colour on it. */
.button_secondary {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-xs);
    min-height: var(--tap-minimum);
    padding: var(--space-xs) var(--space-md);
    color: var(--ink);
    border: 1px solid var(--rule-strong);
    border-radius: var(--radius-sm);
    text-decoration: none;
    transition: transform 120ms ease-out, opacity var(--fade);
}

.button_secondary:active {
    transform: scale(0.97);
}

.button_secondary--filed {
    color: var(--marginalia);
    border-color: var(--marginalia);
}

.button_plain {
    color: var(--ink-secondary);
    min-height: var(--tap-minimum);
}

/* `DSChip`: selected fills with `herbarium`, which is this system's only
   meaning for "currently chosen". */
.chip {
    display: inline-flex;
    align-items: center;
    min-height: var(--tap-minimum);
    padding: var(--space-xs) var(--space-sm);
    color: var(--ink-secondary);
    border: 1px solid var(--rule);
    border-radius: var(--radius-xs);
    transition: background var(--snappy), color var(--snappy);
}

.chip--selected {
    background: var(--herbarium);
    border-color: transparent;
    color: var(--sheet);
}

/* ── SegmentedRule ─────────────────────────────────────────────────────
 *
 *  A ruled tab strip. The 2px selection mark sits directly on the hairline,
 *  which is why the strip is a column with no gap: the mark meets the rule.
 *  Not `Picker(.segmented)`, which brings a filled capsule this system has
 *  no other use for.
 */

.segmented {
    display: flex;
    flex-direction: column;
}

.segmented__row {
    display: flex;
}

.segmented__segment {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    align-items: center;
}

.segmented__label {
    display: flex;
    align-items: center;
    justify-content: center;
    min-height: 36px;
    width: 100%;
    text-align: center;
    color: var(--ink-tertiary);
    transition: color var(--snappy);
}

.segmented__mark {
    height: 2px;
    width: 100%;
    background: transparent;
    transition: background var(--snappy);
}

.segmented__segment--selected .segmented__label {
    color: var(--ink);
}

.segmented__segment--selected .segmented__mark {
    background: var(--ink);
}

/* ── RegisterSearchField ───────────────────────────────────────────────
 *
 *  A recessed well, 48px tall, no border. The only sunken surface in the
 *  system, which is what makes it read as somewhere to type.
 */

.search {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    height: var(--tap-comfortable);
    padding: 0 var(--space-sm);
    background: var(--well);
    border-radius: var(--radius-sm);
}

.search__glyph {
    width: 16px;
    height: 16px;
    flex: none;
    color: var(--ink-tertiary);
}

.search__input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: none;
    color: var(--ink);
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 15px;
}

.search__input:focus {
    outline: none;
}

.search__input::placeholder {
    color: var(--ink-tertiary);
}

/* ── The worked example ────────────────────────────────────────────────
 *
 *  The app, running on the page. It is the same register, the same marks
 *  and the same rules — a screenshot would say less and could not be
 *  pressed.
 */

.demo {
    margin-top: var(--space-md);
    border: 1px solid var(--rule-strong);
    border-radius: var(--radius-sm);
    background: var(--sheet);
    overflow: hidden;
}

.demo__header {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    padding: var(--space-md) var(--margin) var(--space-sm);
}

.demo__title {
    margin: 0;
    color: var(--ink);
}

.demo__subtitle {
    margin: var(--space-xxs) 0 0;
    color: var(--ink-tertiary);
}

.demo__spacer {
    flex: 1;
}

/* The tab strip stands in for the tab bar. Three tabs across the top of a
   page is a thing the web already knows how to read; a floating bar at the
   bottom of a browser window is not. */
.demo__tabs {
    padding: 0 var(--margin);
}

.demo__pane {
    padding: var(--space-md) var(--margin) var(--space-lg);
    min-height: 420px;
}

.demo__pane--flush {
    padding-left: 0;
    padding-right: 0;
}

/* A pushed screen. The app slides these in from the right; here they
   replace the pane, with a back control where the navigation bar was. */
.pushed {
    animation: push var(--sheet-motion);
}

@keyframes push {
    from { opacity: 0; transform: translateX(12px); }
    to   { opacity: 1; transform: none; }
}

.back {
    display: inline-flex;
    align-items: center;
    gap: var(--space-xs);
    min-height: var(--tap-minimum);
    color: var(--ink-secondary);
}

.back__glyph {
    width: 12px;
    height: 12px;
}

/* ── The scan ──────────────────────────────────────────────────────────
 *
 *  `AutoScanView` — a bar, two figures, and one line saying where the
 *  photographs are going. The numbers are what earn the hook, so they are
 *  set as figures and not as prose.
 */

.scan__lead {
    margin: 0 0 var(--space-md);
    color: var(--ink-secondary);
}

.scan__progress {
    height: 4px;
    background: var(--well);
    border-radius: var(--radius-xs);
    overflow: hidden;
    margin: var(--space-md) 0 var(--space-xs);
}

.scan__progress_fill {
    height: 100%;
    width: 0;
    background: var(--ink);
    transition: width 200ms linear;
}

.scan__figures {
    display: flex;
    align-items: baseline;
    gap: var(--space-sm);
    color: var(--ink-tertiary);
}

.scan__figures_spacer {
    flex: 1;
}

.privacy_line {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    color: var(--ink-tertiary);
    margin: var(--space-sm) 0 0;
}

.privacy_line__lock {
    width: 12px;
    height: 12px;
    flex: none;
}

/* ── The reveal ────────────────────────────────────────────────────────
 *
 *  `ScanRevealView`. It shows the trip page rather than a summary of it,
 *  because a prettier mock-up would be a promise the app then breaks.
 */

.reveal__found {
    margin: 0 0 var(--space-sm);
    color: var(--ink-tertiary);
}

.reveal__title {
    margin: 0;
    color: var(--ink);
}

.reveal__facts {
    margin: var(--space-xs) 0 0;
    color: var(--ink-secondary);
}

.reveal__more {
    margin: 0;
    color: var(--ink-tertiary);
}

.reveal__footer {
    display: grid;
    justify-items: center;
    gap: var(--space-xs);
    padding-top: var(--space-sm);
}

.reveal__note {
    margin: 0;
    color: var(--ink-tertiary);
}

/* ── Day rows ──────────────────────────────────────────────────────────
 *
 *  The day number in accession red in a 24px margin, a hairline running the
 *  height of the day, the photographs to the right. This column is what the
 *  trip page looks like, which is why the reveal looks like it too.
 */

.day {
    display: flex;
    align-items: stretch;
    gap: var(--space-sm);
}

.day--empty {
    opacity: 0.55;
}

.day__margin {
    width: 24px;
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: var(--space-xxs);
}

.day__number {
    color: var(--accession);
}

.day--empty .day__number {
    color: var(--ink-tertiary);
}

.day__hairline {
    width: 1px;
    flex: 1;
    background: var(--rule);
}

.day__body {
    flex: 1;
    min-width: 0;
    padding-bottom: var(--space-lg);
    display: grid;
    gap: var(--space-xs);
    justify-items: start;
}

.day__date {
    color: var(--ink-tertiary);
}

.day__place {
    margin: var(--space-xxs) 0 0;
    color: var(--ink);
}

.day__highlights {
    margin: var(--space-xxs) 0 0;
    color: var(--ink-secondary);
}

/* ── Photographs ───────────────────────────────────────────────────────
 *
 *  A mounted plate with nothing in it yet. This page has no camera roll to
 *  read, and inventing one — stock photographs of somebody else's holiday —
 *  would be the one dishonest thing on the page. So the strip shows what
 *  the app shows before a photograph decodes: the frame, at the size it
 *  will be, in the order it will be in.
 */

.strip {
    display: flex;
    gap: var(--space-xxs);
    overflow-x: auto;
    scrollbar-width: none;
    width: 100%;
    padding-bottom: var(--space-xxs);
}

.strip::-webkit-scrollbar {
    display: none;
}

.frame {
    flex: none;
    background: var(--well);
    border: 1px solid var(--rule);
    border-radius: var(--radius-xs);
    display: flex;
    align-items: flex-end;
    justify-content: flex-end;
    padding: var(--space-xxs);
    color: var(--ink-tertiary);
}

.frame--day {
    width: 92px;
    height: 92px;
}

.frame--album {
    width: 104px;
    height: 104px;
}

.frame--reveal {
    width: 84px;
    height: 84px;
}

.frame--city {
    width: 76px;
    height: 76px;
}

/* The cover is a plate the width of the page: 200px on the reveal, 260 on
   the trip itself. */
.cover {
    width: 100%;
    height: 200px;
    background: var(--well);
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    display: flex;
    align-items: flex-end;
    padding: var(--space-sm);
    color: var(--ink-tertiary);
}

.cover--trip {
    height: 260px;
}

/* ── Trip page ─────────────────────────────────────────────────────────── */

.trip {
    display: grid;
    gap: var(--space-lg);
}

.trip__heading {
    display: grid;
    gap: var(--space-xxs);
    justify-items: start;
}

.trip__title {
    margin: 0;
    color: var(--ink);
}

.trip__counts {
    margin: var(--space-xxs) 0 0;
    color: var(--ink-tertiary);
}

/* The route map on a trip is 220px in the app and keeps its hairline
   frame here. Pins sit on it the same way they do on the atlas. */
.trip__map {
    position: relative;
    height: 220px;
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    background: var(--plate);
    overflow: hidden;
}

.trip__section {
    display: grid;
    gap: var(--space-sm);
}

/* ── Atlas ─────────────────────────────────────────────────────────────
 *
 *  A chart rather than a basemap: land mounted on the sheet, hairline
 *  borders, and the pins doing all the talking. The projection is
 *  equirectangular, so a pin's position is its coordinates and nothing
 *  else.
 */

.atlas {
    display: grid;
    gap: var(--space-xs);
}

.atlas__controls {
    display: grid;
    gap: var(--space-xs);
    padding: 0 var(--margin);
}

.map {
    position: relative;
    width: 100%;
    aspect-ratio: 1000 / 394.44;
    background: var(--sheet);
    border-top: 1px solid var(--rule);
    border-bottom: 1px solid var(--rule);
    overflow: hidden;
    touch-action: pan-y;
}

/* The Maps JavaScript API draws into this. It gets the frame and the
   hairlines; everything inside it is the app's own style document. */
.map__canvas {
    position: absolute;
    inset: 0;
}

/* Google's own attribution and terms have to stay legible, so they are left
   alone. They are the one piece of type on this page that is not ours. */
.map--google .map__pins {
    pointer-events: none;
}

.map--google .pin {
    pointer-events: auto;
}

.map__world {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
}

/*
 *  The landing page's map, drifting.
 *
 *  One keyframe for both backends. Google's canvas already holds the pins,
 *  so it moves alone; the chart is an outline and a pin layer, and those
 *  two have to travel together. Linear, not ease-in-out: a curve that
 *  slows to a stop at each end is what read as chop. Alternate rather
 *  than a jump-cut loop, so the motion never hiccups. Scaled past the
 *  frame so the travel never uncovers an edge.
 */
.map--drift .map__canvas,
.map--drift .map__world,
.map--drift:not(.map--google) .map__pins {
    animation: map_flow 90s linear infinite alternate;
    will-change: transform;
}

@keyframes map_flow {
    from { transform: translate3d(4%, 0, 0) scale(1.12); }
    to   { transform: translate3d(-4%, 0, 0) scale(1.12); }
}

.map__world #land {
    fill: var(--plate);
    stroke: var(--rule);
    stroke-width: 0.6;
    vector-effect: non-scaling-stroke;
}

.map__world #borders {
    fill: none;
    stroke: var(--rule);
    stroke-width: 0.5;
    vector-effect: non-scaling-stroke;
}

.map__pins {
    position: absolute;
    inset: 0;
}

/*
 *  `AtlasMarkIcon`: a head, a 15px shaft in ink, and a 2px sheet-coloured
 *  halo so a pin over a border is still one shape. Anchored at the tip of
 *  the shaft, which is the coordinate — not the centre of the head.
 */
.pin {
    position: absolute;
    transform: translate(-50%, -100%);
    display: grid;
    justify-items: center;
    padding: 0;
    transition: opacity var(--snappy);
}

.pin__head {
    width: 11px;
    height: 11px;
    border-radius: var(--radius-xs);
    background: var(--accession);
    outline: 2px solid var(--sheet);
}

.pin--home .pin__head {
    background: var(--marginalia);
}

.pin--planned .pin__head {
    background: var(--sheet);
    border: 3px solid var(--herbarium);
}

.pin__shaft {
    width: 1.5px;
    height: 15px;
    background: var(--ink);
    outline: 1.5px solid var(--sheet);
}

.pin__label {
    position: absolute;
    bottom: 100%;
    margin-bottom: 3px;
    white-space: nowrap;
    color: var(--ink);
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 10.5px;
    font-variation-settings: "wght" 600;
    letter-spacing: 0.4px;
    paint-order: stroke;
    -webkit-text-stroke: 3px var(--sheet);
}

.pin--dim {
    opacity: 0.25;
}

.pin--selected .pin__head {
    outline-color: var(--ink);
}

/* The year scrubber under the map: the same 2px mark as `SegmentedRule`,
   scrolled rather than divided, because there is no fixed number of years. */
.years {
    display: flex;
    gap: 0;
    overflow-x: auto;
    scrollbar-width: none;
    padding: 0 var(--margin);
    border-bottom: 1px solid var(--rule);
}

.years::-webkit-scrollbar {
    display: none;
}

.year {
    display: flex;
    flex-direction: column;
    gap: var(--space-xs);
    align-items: center;
    flex: none;
}

.year__label {
    padding: 0 var(--space-sm);
    min-height: 36px;
    display: flex;
    align-items: center;
    color: var(--ink-tertiary);
}

.year__mark {
    height: 2px;
    width: 100%;
    background: transparent;
}

.year--selected .year__label {
    color: var(--ink);
}

.year--selected .year__mark {
    background: var(--ink);
}

/* The sheet that comes up when a pin is pressed. In the app it is a real
   sheet fitted to its content; here it takes the place below the map, which
   is the same relationship without covering the map that raised it. */
.place_sheet {
    margin: 0 var(--margin);
    animation: sheet var(--sheet-motion);
}

@keyframes sheet {
    from { opacity: 0; transform: translateY(8px); }
    to   { opacity: 1; transform: none; }
}

.place_sheet__heading {
    display: grid;
    gap: var(--space-xxs);
    justify-items: start;
}

.place_sheet__name {
    margin: 0;
    color: var(--ink);
}

.place_sheet__where {
    margin: 0;
    color: var(--ink-tertiary);
}

.place_sheet__summary {
    margin: var(--space-xxs) 0 0;
    color: var(--ink-secondary);
}

.place_sheet__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-xs);
    padding-top: var(--space-md);
}

/* ── You ───────────────────────────────────────────────────────────────── */

.identity {
    display: flex;
    align-items: flex-start;
    gap: var(--space-md);
}

/* `SelfAvatar` — a monogram on a well, because a person without a
   photograph should not get a grey silhouette. */
.avatar {
    width: 64px;
    height: 64px;
    flex: none;
    border-radius: var(--radius-sm);
    background: var(--well);
    border: 1px solid var(--rule);
    display: flex;
    align-items: center;
    justify-content: center;
    color: var(--ink-secondary);
}

.identity__body {
    flex: 1;
    min-width: 0;
}

.identity__name {
    margin: 0;
    color: var(--ink);
}

.identity__handle {
    margin: var(--space-xxxs) 0 var(--space-xs);
    color: var(--ink-tertiary);
}

/*
 *  `TotalsFigures`: three ruled columns, left-aligned, with a 44px vertical
 *  hairline between them. The one place in the app where a figure is the
 *  subject rather than a caption.
 */
.totals {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    padding: var(--space-sm) 0;
}

.totals--register {
    border-top: 1px solid var(--rule-strong);
    border-bottom: 1px solid var(--rule-strong);
}

.total {
    flex: 1;
    display: grid;
    gap: var(--space-xxxs);
    justify-items: start;
}

.total__value {
    color: var(--ink);
}

.total__value--zero {
    color: var(--ink-tertiary);
}

.total__label {
    color: var(--ink-tertiary);
}

.hero__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-md);
    padding-top: var(--space-lg);
}

/* ── Onboarding ────────────────────────────────────────────────────────
 *
 *  The sign-up flow: one question a screen, a progress bar over it, one
 *  button under it. `OnboardingQuestionHeader` is left-aligned, because a
 *  question is read rather than admired.
 */

.auth {
    max-width: calc(var(--measure) + var(--margin) * 2);
    margin: 0 auto;
    padding: 0 var(--margin) var(--space-xxl);
}

/* A link that is a way back rather than a reference: it reads as a control,
   so it is not underlined like one of the links in a sentence. */
a.back {
    text-decoration: none;
}

/* `OnboardingProgressBar` — one 2px segment a step, filled in ink. */
.progress {
    display: flex;
    gap: var(--space-xxs);
    padding: var(--space-md) 0;
}

.progress__segment {
    flex: 1;
    height: 2px;
    background: var(--rule);
    transition: background var(--snappy);
}

.progress__segment--done {
    background: var(--ink);
}

.question {
    margin: var(--space-lg) 0 0;
    color: var(--ink);
}

.question__subtitle {
    margin: var(--space-xs) 0 0;
    color: var(--ink-secondary);
    max-width: 52ch;
}

.step {
    padding-top: var(--space-lg);
    display: grid;
    align-content: start;
    gap: var(--space-md);
}

/* A field is a label above a well. The well is the only sunken surface in
   the system, which is what makes it read as somewhere to type. */
.field {
    display: grid;
    gap: var(--space-xxs);
}

.field__label {
    color: var(--ink-tertiary);
}

.field__well {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
    height: var(--tap-comfortable);
    padding: 0 var(--space-sm);
    background: var(--well);
    border-radius: var(--radius-sm);
}

.field__prefix {
    color: var(--ink-tertiary);
}

.field__input {
    flex: 1;
    min-width: 0;
    border: 0;
    background: none;
    color: var(--ink);
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 15px;
}

.field__input:focus {
    outline: none;
}

.field__input::placeholder {
    color: var(--ink-tertiary);
}

/* A failure leads with the consequence. `accession` is not used here — it
   means "you have been there" and a form error is not that — so the weight
   does the work. */
.field__error {
    color: var(--ink);
}

.auth__footer {
    display: grid;
    gap: var(--space-xs);
    /* The button is as wide as its label, not as wide as the page. */
    justify-items: start;
    padding-top: var(--space-lg);
}

/* The rule under the last question is the one thing here that runs the full
   measure — it is what the button is standing on. */
.auth__footer .rule {
    justify-self: stretch;
    margin-bottom: var(--space-sm);
}

/* Same shape as the welcome screen: two 48pt ruled squares, Apple first. */
.providers {
    display: grid;
    gap: var(--space-sm);
    padding-top: var(--space-md);
}

.providers__label {
    color: var(--ink-tertiary);
    margin: 0;
}

.providers__row {
    display: flex;
    gap: var(--space-sm);
}

.providers__mark {
    width: 48px;
    height: 48px;
    padding: 0;
    display: grid;
    place-items: center;
    border: 1px solid var(--rule-strong);
    border-radius: var(--radius-sm);
    background: var(--plate);
    color: var(--ink);
    cursor: pointer;
}

.providers__mark:hover {
    border-color: var(--ink);
}

.providers__glyph {
    width: 20px;
    height: 20px;
}

.providers__glyph--google {
    width: 18px;
    height: 18px;
}

.auth__alternate {
    color: var(--ink-secondary);
    min-height: var(--tap-minimum);
    display: inline-flex;
    align-items: center;
    border: 0;
    background: none;
    padding: 0;
    font: inherit;
    cursor: pointer;
    text-decoration: none;
    text-align: left;
}

/* The one place a preview says it is a preview: where somebody is about to
   trust it with an account. */
.note {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    padding: var(--space-sm) 0 0;
    color: var(--ink-secondary);
}

.note__lock {
    width: 16px;
    height: 16px;
    /* Optically on the first line of type rather than above it. */
    margin-top: 2px;
    flex: none;
    color: var(--ink);
}

/* A chosen row: `herbarium`, which is this system's only meaning for
   "currently chosen". */
.choice--chosen .register_row__title {
    color: var(--herbarium);
}

.choice__check {
    width: 14px;
    height: 14px;
    color: var(--herbarium);
    flex: none;
    align-self: center;
}

/* ── The signed-in bar ─────────────────────────────────────────────────── */

.account_bar {
    display: flex;
    align-items: center;
    gap: var(--space-sm);
}

.account_bar__name {
    color: var(--ink);
}

/* ── Privacy note ──────────────────────────────────────────────────────
 *
 *  `PrivacyNote`. Set heavier than body copy on purpose: reading someone's
 *  entire photo library is the largest thing this app asks for, and the
 *  answer to "what happens to my photos" has to land before the button
 *  does. Said once, prominently, and never repeated as filler.
 */

.privacy {
    margin-top: var(--space-lg);
}

.privacy__body {
    display: flex;
    align-items: flex-start;
    gap: var(--space-sm);
    padding-top: var(--space-xs);
}

.privacy__lock {
    width: 20px;
    flex: none;
    color: var(--ink);
}

.privacy__promise {
    margin: 0;
    color: var(--ink);
}

.privacy__detail {
    margin: var(--space-xxs) 0 0;
    color: var(--ink-secondary);
}

/* ── Download ──────────────────────────────────────────────────────────── */

.download {
    padding: var(--space-lg) 0 var(--space-xs);
}

.download__note {
    margin: var(--space-sm) 0 0;
    color: var(--ink-tertiary);
}

/* ── Footer ────────────────────────────────────────────────────────────── */

.footer {
    margin-top: var(--space-xl);
    padding: var(--space-md) 0 var(--space-xxl);
    border-top: 1px solid var(--rule-strong);
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-md);
    color: var(--ink-tertiary);
}

.footer__spacer {
    flex: 1;
}

/* The appearance control is `AppearanceManager` — light, dark, or follow
   the system — and it belongs where a setting belongs, not in the masthead. */
.appearance {
    display: flex;
    align-items: center;
    gap: var(--space-xs);
}

.appearance__options {
    display: flex;
    border: 1px solid var(--rule);
    border-radius: var(--radius-sm);
    overflow: hidden;
}

.appearance__option {
    min-height: 32px;
    padding: 0 var(--space-sm);
    color: var(--ink-tertiary);
    border-right: 1px solid var(--rule);
    display: flex;
    align-items: center;
}

.appearance__option:last-child {
    border-right: 0;
}

.appearance__option--selected {
    background: var(--herbarium);
    color: var(--sheet);
}

/* ── Focus ─────────────────────────────────────────────────────────────
 *
 *  Ink, not the browser's blue. The palette's three colours mean something
 *  else and a focus ring is not one of them.
 */

:focus-visible {
    outline: 2px solid var(--ink);
    outline-offset: 2px;
    border-radius: var(--radius-xs);
}

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

/* ── Narrow ────────────────────────────────────────────────────────────
 *
 *  A phone is the width this system was designed at, so little changes.
 *  The display sizes step down, because 40px of Fraunces across a 320px
 *  screen breaks the hook over four lines.
 */

@media (max-width: 480px) {
    .landing__masthead {
        flex-wrap: wrap;
    }

    .ds_plate_title {
        font-size: 32px;
        font-variation-settings: "wght" 500, "opsz" 32, "SOFT" 0, "WONK" 1;
    }

    .ds_display_large {
        font-size: 28px;
        font-variation-settings: "wght" 500, "opsz" 28, "SOFT" 0, "WONK" 1;
    }

    .ds_display_medium {
        font-size: 24px;
        font-variation-settings: "wght" 500, "opsz" 24, "SOFT" 0, "WONK" 1;
    }

    .definition {
        display: block;
    }

    .definition__label {
        width: auto;
        display: block;
        margin-bottom: var(--space-xxs);
    }

    .button_primary {
        width: 100%;
    }

    .identity {
        display: block;
    }

    .identity__body {
        margin-top: var(--space-sm);
    }

    /* Three columns cannot hold the totals on a narrow screen, and the
       vertical rules between them are a fixed 44px against a row that
       grows. They fall to ruled rows, as they do at accessibility sizes. */
    .totals {
        display: grid;
        gap: 0;
    }

    .totals .rule--vertical {
        display: none;
    }

    .total {
        display: flex;
        align-items: baseline;
        gap: var(--space-sm);
        padding: var(--space-xs) 0;
        border-bottom: 1px solid var(--rule);
    }

    /* A world map 320px wide is a decoration. Given room to be a map, it
       scrolls sideways instead. */
    .map {
        aspect-ratio: 620 / 394.44;
    }

    .pin__label {
        display: none;
    }
}

/* ── Back office ───────────────────────────────────────────────────────── */

.admin_nav {
    display: flex;
    gap: var(--space-md);
    padding: var(--space-sm) 0;
}

.admin_nav a,
.admin_nav button {
    color: var(--ink-secondary);
    min-height: var(--tap-minimum);
    display: inline-flex;
    align-items: center;
    border: 0;
    background: none;
    padding: 0;
    font: inherit;
    cursor: pointer;
    text-decoration: none;
}

.admin_nav a[aria-current="page"] {
    color: var(--ink);
    font-weight: 600;
}

.admin {
    padding-bottom: var(--space-xxl);
}

.admin__grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(10rem, 1fr));
    gap: var(--space-md);
    padding: var(--space-lg) 0;
}

.admin__stat {
    display: grid;
    gap: var(--space-xxs);
}

.admin__stat dt {
    color: var(--ink-tertiary);
}

.admin__stat dd {
    margin: 0;
    color: var(--ink);
}

.admin_table {
    width: 100%;
    border-collapse: collapse;
}

.admin_table th,
.admin_table td {
    text-align: left;
    padding: var(--space-xs) var(--space-sm) var(--space-xs) 0;
    border-bottom: 1px solid var(--rule);
    vertical-align: top;
}

.admin_table th {
    color: var(--ink-tertiary);
    font-weight: 500;
}

.admin_table button,
.admin_table a.admin_row {
    color: inherit;
    text-decoration: none;
    background: none;
    border: 0;
    padding: 0;
    font: inherit;
    cursor: pointer;
    text-align: left;
}

.admin__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    padding-top: var(--space-md);
}

.admin__pre {
    white-space: pre-wrap;
    word-break: break-word;
    font-family: "Archivo", system-ui, sans-serif;
    font-size: 13px;
    color: var(--ink-secondary);
    max-height: 24rem;
    overflow: auto;
    padding: var(--space-sm) 0;
}

/*  Trend markers.
 *
 *  `accession` is the app's "been there" red and nothing else may borrow it —
 *  except that a bug coming back after it was closed is the one thing in this
 *  table worth an eye going straight to it. Everything else is weight and
 *  words, so the red keeps meaning something.
 */
.admin_trend {
    color: var(--ink-tertiary);
    white-space: nowrap;
}

.admin_trend--new {
    color: var(--ink);
    font-weight: 500;
}

.admin_trend--back {
    color: var(--accession);
    font-weight: 600;
}

.admin_since {
    color: var(--ink-secondary);
    margin: 0 0 var(--space-sm);
}

.admin_hold {
    color: var(--ink);
    font-weight: 500;
    margin: var(--space-sm) 0 0;
}

.admin_block {
    margin: var(--space-xl) 0 0;
}

.admin_photo {
    display: block;
    width: 100%;
    max-width: 28rem;
    height: auto;
    margin: var(--space-md) 0;
    border: 1px solid var(--rule);
}

/* Functional motion only, and there is little of it. Honour the preference
   anyway — the app gates its decorative animation on the same thing. */
@media (prefers-reduced-motion: reduce) {
    *,
    *::before,
    *::after {
        animation-duration: 1ms !important;
        transition-duration: 1ms !important;
    }
}
