/* Typeface */

@font-face {
    font-family: "Courier Prime";
    font-style: normal;
    font-weight: 400;
    font-display: swap;
    src: url("../fonts/courier-prime-regular.woff2") format("woff2");
}

@font-face {
    font-family: "Courier Prime";
    font-style: normal;
    font-weight: 700;
    font-display: swap;
    src: url("../fonts/courier-prime-bold.woff2") format("woff2");
}

/* Tokens */

:root {
    --bg: hsl(30 10 93);
    --primary: black;
    --accent: hsl(30 50 40);
    --action: hsl(0 50 50);
    --light: hsl(30 30 97);
    /* The accent's tint, owned by selection alone: the mark of
       the reader's touch, never a control's dress. */
    --selection: hsl(30 50 83);
    --tool: hsl(30 10 90);
    /* One carriage return: the body line pitch (1rem × 1.3) as a
       length. All vertical rhythm is a multiple or fraction of it;
       horizontal micro-spacing uses ch, the monospace grid's own
       unit. Keep in step with body line-height. */
    --line: 1.2rem;
    /* Native controls (checkboxes) tick in ink, not OS blue. */
    accent-color: var(--primary);
}

/* Base */

body {
    font-family: courier prime, courier, monospace;
    background: var(--bg);
    color: var(--primary);
    max-width: 540px;
    margin: calc(4 * var(--line)) auto;
    padding: 0 var(--line);
    line-height: 1.2;
}

@media (max-width: 600px) {
    body {
        margin: var(--line) auto;
    }
}

h1, h2 {
    font-weight: bold;
}

h1 {
    font-size: 1.5rem;
    margin: 0;
    text-transform: uppercase;
    letter-spacing: 0.5ch;
    border-bottom: 2px solid var(--primary);
    padding: calc(var(--line) / 4) 0;
}

/* A half-step over body size — enough presence to anchor a
   section without competing with the masthead's display scale. */
h2 {
    font-size: 1.25rem;
    margin-top: calc(2 * var(--line));
    margin-bottom: var(--line);
}

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

p {
    hyphens: auto;
}

/* The hidden attribute always wins. Its UA default loses to any
   authored display value, which has now bitten three times (event
   grids, month rows, city-key spans) — so make it unconditional. */
[hidden] {
    display: none !important;
}

::selection {
    background: var(--selection);
}

/* Header */

header {
    margin-bottom: var(--line);
}

header a {
    text-decoration: none;
}

/* The nav's public destinations wear the content orange; the
   operator links behind the login carry a.action's red. */
header nav a {
    color: var(--accent);
}

header .masthead {
    margin-bottom: calc(var(--line) / 2);
}

/* Log out rides at the end of the operator row, dressed as its
   neighbors: bare red text, no box. Specificity outranks the
   form-button dress. */
header nav form {
    display: inline;
}

header nav button {
    background: none;
    border: none;
    border-radius: 0;
    padding: 0;
    color: var(--action);
}

/* Event list */

article {
    margin-bottom: calc(1.5 * var(--line));
}

article:target {
    /* Landing back from an edit round-trip marks your place. */
    background: var(--light);
}

article.event {
    /* Whitespace alone separates events — the time gutter and bold
       titles carry the structure. Margin only below, so :target
       highlights hug the event text. */
    margin: 0 0 var(--line);
    /* Gig-guide columns: the gutter holds the time range, so
       wrapped detail lines align under details, not the time.
       8ch fits "12:30PM–"; longer ranges wrap after the dash. */
    display: grid;
    grid-template-columns: 8ch 1fr;
    column-gap: 2ch;
}

/* On the venues page the gutter holds the date instead, and the
   line leads with the time — the heading already names the place. */
article.event.dated .on {
    text-transform: uppercase;
}

article.event .buttons {
    grid-column: 2;
}

/* Cross-links between the two views — the venue in a date line,
   the date in a venue line — jump to their section on the other
   page. Set in ink with the standard underline: the underline
   carries the link-ness, the ink keeps the lines calm. */
a.venue-link,
article.event .on a {
    color: var(--primary);
}

form.search {
    display: flex;
    gap: 1ch;
    margin-bottom: var(--line);
}

/* The clear ✕ sits inside the field like a typed correction mark —
   bare glyph, no key dress (fields are the paper). search.js
   reveals it when there's something to clear; Firefox draws no
   native mark, and WebKit's is hidden below so every browser
   shows this one. */
.searchbox {
    position: relative;
    flex: 1;
}

.searchbox input {
    padding-right: 3ch;
}

/* Suppress WebKit's native mark only while ours is showing — with
   JS off the .clear button stays [hidden] forever, and the native
   ✕ survives as the no-JS path Chrome/Safari always had. */
.searchbox:has(.clear:not([hidden])) input::-webkit-search-cancel-button {
    -webkit-appearance: none;
}

button.clear {
    position: absolute;
    top: 50%;
    translate: 0 -50%;
    right: 0.5ch;
    padding: calc(var(--line) / 4) 0.5ch;
    background: none;
    border: none;
    cursor: pointer;
}

/* Jump block: a typewritten calendar index — one row per month,
   one linked day number per date with events, so the block is also
   a density map of the season. Plain fragment links. */
nav.date-jump {
    margin-bottom: calc(1.5 * var(--line));
}

nav.date-jump .month-row {
    display: grid;
    grid-template-columns: 4ch 1fr;
    column-gap: 1ch;
}

nav.date-jump .month {
    font-weight: bold;
}

nav.date-jump .days {
    display: flex;
    flex-wrap: wrap;
    column-gap: 1ch;
}

nav.date-jump .days a {
    width: 2ch;
    text-align: right;
    text-decoration: none;
}

nav.date-jump .days a:hover {
    text-decoration: underline;
}

/* Venue index: one wrapped run of every venue name, A–Z — the same
   order as the sections below. The event line's own ink bullet
   seams the names; each rides its link's ::after only when a
   visible neighbor follows, so the live filter never strands one,
   and the inline-block atom keeps it out of the hover underline.
   Browsers without :has() fall back to plain spacing. */
nav.venue-jump {
    margin-bottom: calc(1.5 * var(--line));
}

nav.venue-jump a {
    text-decoration: none;
}

nav.venue-jump a:hover {
    text-decoration: underline;
}

nav.venue-jump a:not([hidden]):has(~ a:not([hidden]))::after {
    content: "•";
    display: inline-block;
    margin-left: 1ch;
    color: var(--primary);
}

section.date-group,
section.venue-group {
    scroll-margin-top: var(--line);
}

/* Section headings speak in their index's voice. */
section.date-group h2,
section.venue-group h2 {
    text-transform: uppercase;
}

/* Forms and controls */

label {
    display: block;
}

/* Controls get a gentle 3px round-over — enough to read as
   touchable without going app-y. */
input,
textarea,
button {
    font-family: inherit;
    font-size: inherit;
    padding: calc(var(--line) / 4) 1ch;
    border-radius: 3px;
}

input,
textarea {
    background: var(--light);
    color: inherit;
    border: 1px solid;
    width: 100%;
    box-sizing: border-box;
    line-height: inherit;
}

input[type="checkbox"] {
    width: auto;
}

/* A lone checkbox sits on its label's line instead of orphaned
   below it (labels are otherwise block). */
form p:has(> input[type="checkbox"]) label {
    display: inline;
}

input[type="file"] {
    padding: calc(var(--line) / 4);
}

/* The file picker's pseudo-button wears the same quiet dress as
   every real button (it can't inherit the form-button rule). */
input[type="file"]::file-selector-button {
    font: inherit;
    background: var(--bg);
    color: var(--primary);
    border: 1px solid;
    border-radius: 3px;
    padding: calc(var(--line) / 4) 1ch;
    cursor: pointer;
    margin-right: 1ch;
    /* The UA's wording, in the machine's voice — CSS can't rename
       "Choose Files", but it can stop it shouting. */
    text-transform: lowercase;
}

/* Start and end time are one thought — the two rows split the
   line evenly (the checkbox rule's :has() idiom). Each shaves
   0.5ch for the collapsed whitespace between the inline-blocks:
   exactly one space, exactly 1ch on the monospace grid. */
form p:has(> input[type="time"]) {
    display: inline-block;
    vertical-align: top;
    width: calc(50% - 0.5ch);
}

button {
    background: none;
    color: inherit;
    border: none;
    cursor: pointer;
}

/* Every button wears the same quiet dress — the machine's keys
   are all one size. Hue still speaks: red = destructive. The
   commit keys (save, extract, scrape all) fill with ink instead
   — see button.primary below. */
form button {
    background: none;
    color: var(--primary);
    border: 1px solid;
    cursor: pointer;
}

/* Commit register: the button that does the form's real work
   rests filled — ink paper, paper legend. */
button.primary {
    background: var(--primary);
    color: var(--bg);
    border-color: var(--primary);
}

/* Destructive variant: the same key with a red legend. Unqualified
   so the focus inversion still outranks it. */
button.danger {
    color: var(--action);
}

button:disabled {
    opacity: 0.5;
    cursor: default;
}

form p {
    margin: 0 0 var(--line);
}

ul.messages,
ul.errorlist {
    list-style: square;
    padding-left: 2ch;
}

.helptext {
    display: block;
    font-size: 0.875rem;
    margin-top: calc(var(--line) / 4);
}

/* Staff surfaces */

.buttons a {
    color: var(--action);
}

.draft {
    background: var(--primary);
    color: var(--bg);
    padding: 0 0.25rem;
}

.duplicate-hint {
    color: var(--action);
    margin: 0;
}

/* Utility links on staff surfaces (select all, cancel, …). */
a.action {
    color: var(--action);
}

/* Flyers */

.flyer-thumb {
    max-width: 120px;
    margin-top: calc(var(--line) / 4);
    border: 1px solid;
}

button.flyer-link {
    background: none;
    color: var(--accent);
    padding: 0;
    text-decoration: underline;
}

.flyer-popover {
    border: 1px solid;
    padding: 0;
    max-width: min(90vw, 480px);
    max-height: 90vh;
}

.flyer-popover img {
    display: block;
    width: 100%;
    max-height: 90vh;
    object-fit: contain;
}

.flyer-popover::backdrop {
    background: rgba(0, 0, 0, 0.5);
}

/* Scrape console */

form.run-all {
    margin-bottom: calc(1.5 * var(--line));
}

article.source form {
    margin-top: calc(var(--line) / 4);
}

.run-error {
    color: var(--action);
}

/* Back to top */

/* Floating "top↑", shown by to-top.js after a screenful of scroll
   (ships hidden — without JS it never appears, and scrolling back
   is the fallback). An ink tab docked flush to the page's bottom
   edge, rounded only where it leaves the paper. */
a.to-top {
    position: fixed;
    bottom: 0;
    right: var(--line);
    background: var(--primary);
    border-radius: 3px 3px 0 0;
    padding: calc(var(--line) / 4) 1ch;
    text-decoration: none;
    color: var(--bg);
}

/* The stylesheet's one motion: the tab slides up out of the edge
   it's docked to. @starting-style supplies the from-state for the
   un-hide frame; without support it simply appears. Hiding snaps —
   display:none is immediate, unnoticed mid-scroll. */
@media (prefers-reduced-motion: no-preference) {
    a.to-top {
        transition: translate 0.2s ease-out;
    }

    @starting-style {
        a.to-top {
            translate: 0 100%;
        }
    }
}

/* Focus */

/* Focus is the cursor, and the cursor inverts: whatever a press-
   thing's resting scheme, swap its ink and paper. Fields you type
   in thicken their edge instead. Last in the file on purpose: the
   inversion must outrank earlier equal-specificity color rules
   (.buttons a, a.action, header nav a). */
a:focus-visible,
button:focus-visible {
    background: var(--primary);
    color: var(--bg);
    outline: none;
}

/* The ink-resting controls (the top tab, primary buttons) flip
   the other way; for the buttons the border keeps the flipped
   key a key. */
a.to-top:focus-visible,
button.primary:focus-visible {
    background: var(--bg);
    color: var(--primary);
}

input:focus-visible,
textarea:focus-visible {
    outline: 1px solid var(--primary);
    outline-offset: 0;
}

/* The seam bullet keeps legible ink when its link inverts. */
nav.venue-jump a:focus-visible::after {
    color: inherit;
}
