/* Design tokens and the self-hosted fonts (ADR 0044). Courier Prime and Gelasio are SIL OFL fonts
   shipped in ./fonts/ with their licences; nothing is loaded from another host (strict CSP). A theme
   (themes/*.css) picks which tokens the page uses. */
@font-face {
  font-family: "Courier Prime";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/courier-prime-400.f85e0aa2239e.woff2") format("woff2");
}
@font-face {
  font-family: "Courier Prime";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("fonts/courier-prime-400-italic.0affa18094c7.woff2") format("woff2");
}
@font-face {
  font-family: "Courier Prime";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/courier-prime-700.bf94f71e7ba4.woff2") format("woff2");
}
@font-face {
  font-family: "Courier Prime";
  font-style: italic;
  font-weight: 700;
  font-display: swap;
  src: url("fonts/courier-prime-700-italic.bb8c3d824d2e.woff2") format("woff2");
}
@font-face {
  font-family: "Gelasio";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/gelasio-variable.4b665fc80b40.woff2") format("woff2");
}
@font-face {
  font-family: "Gelasio";
  font-style: italic;
  font-weight: 400 700;
  font-display: swap;
  src: url("fonts/gelasio-variable-italic.4d86a2363181.woff2") format("woff2");
}

:root {
  /* Palette */
  --burnt-red: #7a1219;
  --burnt-red-deep: #5e0e13;
  --tan: #f6f3e2;
  --cream: #f5f0e0;
  --white: #ffffff;
  --ink: #141414;
  --ink-soft: #4a4a4a;
  --featured: #ffd700;
  /* The "Open now" badge of a business card: dark green on a pale green pill (fixed, so it reads on any theme) */
  --open-now: #166534;
  --open-now-bg: #dcfce7;

  /* Type: the neutral stacks; the Raleighwood theme switches to Courier Prime and Georgia */
  --font-system: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "Courier Prime", ui-monospace, "Cascadia Mono", "Source Code Pro", Menlo, Consolas,
    "Courier New", monospace;
  --font-serif: Gelasio, Georgia, "Times New Roman", serif;
  --font-heading: var(--font-system);
  --font-body: var(--font-system);
  --font-ui: var(--font-system);

  /* Layout */
  --content-width: 82rem;
  --radius: 4px;

  /* The arrow in a call-to-action button (.btn-arrow): 1.5 times the 0.75rem button text (ADR 0108) */
  --btn-arrow-size: calc(var(--fs-btn) * 1.5);

  /* Type sizes: buttons (every .btn, the menu's Subscribe included), Home body copy and its secondary text */
  --fs-btn: 1.0625rem;
  --fs-body: 1.0625rem;
  --fs-small: 0.9375rem;
  --fs-nav: 0.9375rem;

  /* The one layer of the menu bar: above the page's own positioned content (the tape and pins at z-index 2, the
     carousel's buttons at 3), so the phone menu panel, which lives inside the header, drops over everything. */
  --z-header: 50;
}

/* ---- end of the design tokens: this block was tokens.css until ADR 0138, now the top of site.css so the page needs one request fewer. Its font URLs are relative to this folder, as before. ---- */

/* Public site styles. Brand colours come from /brand.css (--brand-primary, --brand-accent). */
:root {
    --section-heading-gap: 1.089rem;  /* what a section heading leaves under its rule (0.83em of its 1.3125rem), and above it in the similar events */
    --text: #1f2937;
    --muted: #4b5563;
    --line: #e5e7eb;
    --surface: #ffffff;
    --page: #f9fafb;
    --card-border: var(--ink, #000);
    --shadow-soft: 0 2px 6px rgba(0, 0, 0, 0.15);  /* the menu bar's shadow, also under the Home cream sections */
    --shadow-featured: 0 4px 6px -3px rgba(0, 0, 0, 0.25);  /* a Featured card at rest, and an editor's pick */
    --shadow-hover: 0 8px 16px rgba(0, 0, 0, 0.18);  /* an event card on hover; the taped Home cards use it too */    color-scheme: light;
}

@media (prefers-color-scheme: dark) {
    :root {
        --text: #e5e7eb;
        --muted: #9ca3af;
        --line: #374151;
        --surface: #111827;
        --page: #030712;
        --card-border: var(--line);
        color-scheme: dark;
    }
}

* {
    box-sizing: border-box;
}

body {
    margin: 0;
    font: 16px/1.5 var(--font-body);
    font-variant-numeric: lining-nums;
    color: var(--text);
    background: var(--page);
}

.skip-link {
    position: absolute;
    left: -999px;
}

.skip-link:focus {
    left: 8px;
    top: 8px;
    padding: 8px 12px;
    background: var(--surface);
}

.plain-main {
    max-width: var(--content-width);
    margin: 0 auto;
    padding: 12px 16px;
}

a {
    color: var(--link-color);
}

h1, h2, h3 {
    font-family: var(--font-heading);
}

h1 {
    margin: 16px 0 8px;
}

.filters {
    display: grid;
    gap: 6px 12px;
    grid-template-columns: repeat(auto-fit, minmax(11.5rem, 1fr));
    align-items: start;
    margin-bottom: 24px;
}

.filters .field {
    display: flex;
    flex-direction: column;
    justify-content: flex-start;
    gap: 4px;
}

.filters .field:last-child {
    align-self: end;
}

/* the button cell lines up with the controls */
.filters label {
    font-family: var(--font-ui);
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--muted);
    display: block;
}

.filters input, .filters select, .filters button {
    width: 100%;
    min-height: 44px;
    padding: 8px;
    font: inherit;
}

.filters input:not([type="checkbox"]), .filters select {
    height: 44px;
    border: 1px solid var(--card-border, var(--ink));
    border-radius: var(--radius);
    background-color: var(--surface);
    color: var(--text);
    font-family: var(--font-ui);
}

.filters select {
    appearance: none;
    padding-right: 36px;
    background: var(--surface) url("images/chevron-down.b74082ae9b52.svg") right 12px center / 12px no-repeat;
}

.filters button {
    background: var(--btn-bg);
    color: var(--btn-text);
    font: 700 0.9375rem var(--font-heading);
    letter-spacing: 0.04em;
    text-transform: var(--btn-transform);
    border: 1px solid var(--btn-bg);
    border-radius: var(--radius);
    cursor: pointer;
}

.filters .check {
    font-family: var(--font-ui);
    letter-spacing: normal;
    text-transform: none;
    display: flex;
    align-items: center;
    gap: 8px;
    min-height: 44px;
    font-size: 1rem;
    color: var(--text);
}

.filters input[type="checkbox"] {
    width: 1.25rem;
    height: 1.25rem;
    min-height: 0;
    margin: 0;
    accent-color: var(--accent);
}

.filters .search-row {
    grid-column: 1 / -1;
}

.filters .search-row input[type="search"] {
    height: 3rem;
    min-height: 3rem;
    font-size: 1.125rem;
    padding: 8px 14px;
}

.filters .action-row {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 6px 12px;
}

.filters .action-row select, .filters .action-row button {
    height: 3rem;
    min-height: 3rem;
    padding: 8px 14px;
    border-radius: var(--radius);
}

.filters .action-row select {
    padding-right: 36px;
    border: 1px solid var(--card-border, var(--ink));
    font: inherit;
    font-family: var(--font-ui);
}

.advanced {
    grid-column: 1 / -1;
}

/* wide screens: search bar, When select and button share one row */
@media (min-width: 64rem) {
    .filters {
        grid-template-columns: minmax(0, 1fr) 32rem;
        align-items: end;
    }

    .filters .search-row {
        grid-column: 1;
    }

    .filters .action-row {
        grid-column: 2;
    }

    .filters .advanced {
        grid-column: 1 / -1;
    }
}

.advanced summary {
    min-height: 44px;
    width: fit-content;
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    font-family: var(--font-ui);
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    color: var(--text);
}

.advanced summary:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

.advanced summary::marker {
    content: "";
}

.advanced summary::after {
    content: "\25BE";
    color: var(--accent);
}

.advanced[open] summary::after {
    content: "\25B4";
}

.advanced[open] {
    padding-bottom: 8px;
    margin-bottom: 16px;
    border-bottom: 1px solid var(--line);
}

.advanced-checks {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 2px;
    padding-bottom: 8px;
    margin-bottom: 4px;
    border-bottom: 1px solid var(--line);
}

/* .filters .field:last-child pushes the last cell to the end; keep both at the start */
.advanced-checks .field,
.advanced-checks .field:last-child {
    display: block;
    align-self: flex-start;
    width: auto;
}

.advanced-checks .check {
    justify-content: flex-start;
    min-height: 32px;
}

.advanced-heading {
    margin: 4px 0 0;
    color: var(--muted);
    font-family: var(--font-ui);
    font-size: 0.75rem;
    letter-spacing: 0.06em;
    text-transform: uppercase;
    font-weight: 400;
}

.advanced-fields {
    display: grid;
    gap: 6px 12px;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    align-items: start;
    margin-top: 8px;
}

.advanced-fields .field {
    min-width: 0;
}

.badge {
    display: inline-block;
    padding: 0 8px;
    border-radius: 999px;
    font-size: 0.8125rem;
    font-weight: 700;
    border: 1px solid var(--accent);
}

.badge.boosted {
    background: var(--surface);
    color: var(--text);
    border-width: 2px;
    border-color: var(--ink);
    padding: 4px 4px 4px;
    border-radius: 4px;
}

.pinned h2 {
    font-size: 1.3125rem;
    border-bottom: 2px solid var(--accent);
}

/* The underline moves from the h2 to the header row so it spans under the key; the h2's bottom margin moves to the row so the spacing is unchanged. */
.pinned-head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 0 12px;
    border-bottom: 2px solid var(--accent);
    margin-bottom: var(--section-heading-gap);
}

.pinned-head h2 {
    border-bottom: 0;
    margin-bottom: 0;
}

.day-heading {
    margin: 24px 0 8px;
    font-size: 1.3125rem;
    border-bottom: 2px solid var(--accent);
}

/* The day-jump strip above the day list: two weeks of single days in one row that scrolls sideways
   (carousel.js makes it loop; the separator marks where it starts over). */
.day-jump {
    display: flex;
    flex-wrap: nowrap;
    gap: 8px;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
    scroll-snap-type: x proximity;
    scroll-padding-inline: 8px;
    padding-block: 4px;
    margin-top: 24px;
    margin-bottom: 16px;
    scroll-margin-top: 16px;
}

/* Soft snap points: only Show all, Today, the first day of the second week and (through the loop's copy) the Show all after the separator. */
.day-jump .snap {
    scroll-snap-align: start;
}

.day-jump::-webkit-scrollbar {
    display: none;
}

.day-jump a, .day-jump span {
    flex: 0 0 auto;
    white-space: nowrap;
    display: inline-flex;
    align-items: center;
    min-height: 40px;
    padding: 6px 12px;
    border-radius: 4px;
    background: var(--cream);
    color: var(--ink);
    border: 1px solid var(--card-border, var(--ink));
    font-family: var(--font-ui);
    font-size: 0.875rem;
    text-decoration: none;
}

.day-jump a:hover, .day-jump a:focus-visible {
    border-color: var(--accent);
}

/* Where the row starts over: a vertical rule as tall as the row (a span, so the chip look is switched off). */
.day-jump .strip-reset {
    align-self: stretch;
    min-height: 0;
    padding: 0;
    margin: 0 6px;
    background: transparent;
    border: 0;
    border-left: 2px solid var(--burnt-red);
    border-radius: 0;
}

/* Desktop arrows beside the strip: hidden here (touch screens swipe); the desktop block below shows them. */
.strip-btn {
    display: none;
}

/* "Show all" resets the choice of days: an outline in place of the cream fill, never selected. */
.day-jump .show-all {
    background: transparent;
    color: var(--text);
    border-color: var(--burnt-red);
}

/* The day whose window is shown. */
.day-jump .is-active {
    background: var(--btn-bg);
    color: var(--btn-text);
    border-color: var(--btn-bg);
}

/* Desktop with a pointer (the Featured arrows' condition): arrows beside the strip, and the row snaps
   to every item so each scroll or arrow click lands exactly on one. Touch keeps the soft snap above. */
@media (hover: hover) and (min-width: 48rem) {
    .day-jump-bar {
        display: flex;
        align-items: stretch;
        gap: 8px;
        margin-top: 24px;
        margin-bottom: 16px;
    }

    .day-jump-bar .day-jump {
        flex: 1 1 auto;
        min-width: 0;
        margin: 0;
    }

    .day-jump {
        scroll-snap-type: x mandatory;
    }

    .day-jump a, .day-jump span {
        scroll-snap-align: start;
    }

    .strip-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        align-self: stretch;
        flex: 0 0 auto;
        width: 40px;
        padding: 0;
        font: inherit;
        font-size: 1.75rem;
        line-height: 1;
        color: var(--burnt-red);
        background: transparent;
        border: 1px solid var(--burnt-red);
        border-radius: var(--radius);
        cursor: pointer;
        transition: background-color 0.15s, color 0.15s;
    }

    .strip-btn[hidden] {
        display: none;
    }

    .strip-btn:hover,
    .strip-btn:focus-visible {
        background: var(--burnt-red);
        color: var(--white);
    }

    @media (prefers-reduced-motion: reduce) {
        .strip-btn {
            transition: none;
        }
    }
}

.ongoing h2 {
    font-size: 1.3125rem;
    border-bottom: 2px solid var(--accent);
}

/* Quick actions: the heading takes the same underline, size and default h2 margins as .ongoing h2. */
.actions {
    margin-top: 24px;
}

.actions-heading {
    font-size: 1.3125rem;
    border-bottom: 2px solid var(--accent);
}

.actions-row {
    display: flex;
    flex-wrap: wrap;
    gap: 10px;
}

.actions-row .btn {
    min-height: 44px;
}

/* .btn already has a 1px border (white on .btn-light), so only its colour changes and the size stays the same. */
.actions-row .btn-light {
    border-color: var(--burnt-red);
}

.pick-key {
    margin: 0;
    font-size: 0.75rem;
    color: var(--muted);
    white-space: nowrap;
}

.pick-key-star {
    margin-left: 1rem;
    color: var(--burnt-red);
}

.pick-key-megaphone {
    display: inline-block;
    width: 1em;
    height: 1em;
    background: url("images/megaphone.7b25fe88d257.svg") center / contain no-repeat;
    vertical-align: -0.15em;
}

/* Ongoing events past the fifth are hidden only once carousel.js has collapsed the section (class is-collapsed);
   without script everything shows and the "Show more" item stays hidden. */
.ongoing.is-collapsed .ongoing-extra {
    display: none;
}

.ongoing-more[hidden] {
    display: none;
}

.ongoing-more {
    display: flex;
}

.more-card {
    appearance: none;
    font: inherit;
    color: inherit;
    width: 100%;
    min-height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    gap: 6px;
    height: 100%;
    box-sizing: border-box;
    padding: 16px;
    text-align: center;
    cursor: pointer;
    background: var(--section-bg, var(--surface));
    border: 1px dashed var(--line);
    border-radius: var(--radius);
}

.more-card:hover {
    border-color: var(--accent);
}

/* The small "Show more dates" button of an event page: the same dashed button, as small as its words. */
.more-card[hidden] {
    display: none;  /* .more-card sets display, which would show a button that is still hidden */
}

.more-card-small {
    width: auto;
    min-height: 0;
    height: auto;
    margin-top: 6px;
    padding: 6px 12px;
    font-size: 0.8125rem;
}

.showing[hidden] {
    display: none;
}

.more-card-title {
    font-weight: 700;
}

.more-card-hint {
    color: var(--muted);
    font-size: 0.875rem;
}

.more-card:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

/* Phone: a collapsed list shows 2 events, then the button (with the count of the rest). */
@media (max-width: 36rem) {
    .ongoing.is-collapsed .ongoing-extra-m {
        display: none;
    }

    .more-count-desktop {
        display: none;
    }
}

/* Tablet and desktop: the button exists only when there are more than 6 events; the phone count is not shown. */
@media (min-width: 36.0625rem) {
    .ongoing-more:not(.more-desktop-ok) {
        display: none;
    }

    .more-count-mobile {
        display: none;
    }
}

.cards {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 12px;
    /* At most 3 columns (each at least a third of the width, minus the two 12px gaps), fewer when narrow */
    grid-template-columns: repeat(auto-fill, minmax(max(18rem, calc((100% - 24px) / 3)), 1fr));
}

/* The Boosted block is a row that scrolls sideways, 2 cards in view (soonest first, as the server
   sends them): swipe, drag the scrollbar or use the arrow keys / trackpad. Cards snap into place. */
.pinned .cards {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: calc((100% - 12px) / 2);
    overflow-x: auto;
    scroll-snap-type: x mandatory;
    scrollbar-width: none;  /* no scrollbar under the row; swipe, trackpad and the arrows still move it */
    /* room for the card shadow and the hover zoom, which the scrolling row would otherwise clip; the negative
       margins cancel the extra padding so the layout height does not change */
    padding-top: 10px;
    margin-top: -10px;
    padding-bottom: 16px;
    margin-bottom: -10px;
}

.pinned .cards::-webkit-scrollbar {
    display: none;
}

.pinned .cards > li {
    scroll-snap-align: start;
}

/* Last card of the Boosted row, promoting the submit form. The copy is placeholder wording for the owner to edit. */
.promo-card {
    position: relative;
    height: 100%;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    gap: 10px;
    padding: 16px;
    background: var(--section-bg, var(--surface));
    border: 1px dashed var(--line);
    border-radius: var(--radius);
}

.promo-title {
    margin: 0;
    font-size: 1.25rem;
}

.promo-text {
    margin: 0;
    color: var(--muted);
}

/* Shown in place of the day list when nothing is listed: one cell of the cards grid, as tall as a
   regular event card, followed by two dimmed placeholders. Placeholder wording for the owner to edit. */
.cards-empty {
    margin-bottom: 24px;
    container-type: inline-size;  /* the ghosts follow this grid's own width, as its columns do */
}

.empty-card {
    min-height: 10.25rem;
    box-sizing: border-box;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    padding: 10px 12px;
    text-align: center;
    background: var(--section-bg, var(--surface));
    border: 1px dashed var(--line);
    border-radius: var(--radius);
}

.empty-card-title {
    margin: 0;
    font-size: 1rem;
    line-height: 1.25;
}

.empty-card-text {
    margin: 0;
    font-size: 0.875rem;
    line-height: 1.3;
    color: var(--muted);
}

.empty-card-actions {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
}

.empty-card-actions .btn {
    padding: 6px 12px;
    font-size: 0.875rem;
}

/* "An event could go here": not links, nothing to hover or focus, and only where the grid has the column. */
.ghost-card {
    display: none;
    min-height: 10.25rem;
    box-sizing: border-box;
    border: 1px dashed var(--line);
    border-radius: var(--radius);
    background: color-mix(in srgb, var(--line) 22%, transparent);
    pointer-events: none;
}

@container (min-width: 36.75rem) {
    .ghost-card {
        display: block;
    }

    .ghost-third {
        display: none;
    }
}

@container (min-width: 55.5rem) {
    .ghost-third {
        display: block;
    }
}

.promo-link::after {
    content: "";
    position: absolute;
    inset: 0;
}

.pinned .cards {
    scroll-behavior: smooth;
}

@media (prefers-reduced-motion: reduce) {
    .pinned .cards {
        scroll-behavior: auto;
    }
}

/* Arrows sit in their own columns beside the row, so they never cover a card. They only show on
   desktop-sized screens with a pointer; touch screens swipe. carousel.js un-hides them. */
.carousel {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: center;
    column-gap: 10px;
}

.carousel-btn {
    display: none;
}

/* Position dots under the cards (not the arrow). Indicator only; carousel.js builds and updates them. */
.carousel-dots {
    grid-column: 1;
    display: flex;
    justify-content: center;
    gap: 6px;
    padding-top: 4px;
}

.carousel-dots[hidden] {
    display: none;
}

.carousel-dot {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: var(--line);
}

.carousel-dot.is-active {
    background: var(--burnt-red);
}

@media (hover: hover) and (min-width: 48rem) {
    .carousel {
        grid-template-columns: minmax(0, 1fr) auto;
        grid-template-rows: 1fr 1fr auto;
    }

    .carousel > .cards {
        grid-column: 1;
        grid-row: 1 / span 2;
        /* room for the hover glow at both ends of the row: the scroll box is 10px wider on each side, the negative
           margins cancel it (cards stay put) and scroll-padding keeps snapped cards 10px inside the scrollport */
        padding-left: 10px;
        padding-right: 10px;
        margin-left: -10px;
        margin-right: -10px;
        scroll-padding-inline: 10px;
    }

    .carousel-dots {
        grid-column: 1;
        grid-row: 3;
    }

    .carousel-btn {
        display: flex;
        align-items: center;
        justify-content: center;
        align-self: stretch;
        height: auto;
        margin-bottom: 6px;
        width: 44px;
        padding: 0;
        font: inherit;
        font-size: 2.25rem;
        line-height: 1;
        color: var(--burnt-red);
        background: var(--cream);
        border: 1px solid var(--burnt-red);
        border-radius: var(--radius);
        cursor: pointer;
        transition: background-color 0.15s, color 0.15s;
        box-shadow: 0 4px 6px -3px rgba(0, 0, 0, 0.25);

    }

    @media (prefers-reduced-motion: reduce) {
        .carousel-btn {
            transition: none;
        }
    }

    /* Both arrows are always shown, the left one above the right one, each half the column height. */
    .carousel-btn[data-carousel-prev] {
        grid-column: 2;
        grid-row: 1;
        margin-bottom: 3px;
    }

    .carousel-btn[data-carousel-next] {
        grid-column: 2;
        grid-row: 2;
        margin-top: 3px;
    }

    /* Until the reader first moves the row, the left arrow is greyed out and does nothing. */
    .carousel:not(.is-started) .carousel-btn[data-carousel-prev] {
        color: var(--muted);
        border-color: var(--muted);
        background: var(--cream);
        box-shadow: none;
        opacity: 0.45;
        cursor: default;
        pointer-events: none;
    }

    .carousel-btn[hidden] {
        display: none;
    }

    .carousel-btn:hover:not(:disabled),
    .carousel-btn:focus-visible {
        background: var(--burnt-red);
        color: var(--white);
    }

    .carousel-btn:disabled {
        visibility: hidden;
    }
}

@media (max-width: 36rem) {
    .pinned .cards {
        grid-auto-columns: 85%;
    }
}

.event-card {
    padding: 12px 14px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 8px;
    height: 100%;
    position: relative;
}

/* Stretched link: the title link covers the whole card, so a click anywhere opens the event. */
.event-card .card-link::after {
    content: "";
    position: absolute;
    inset: 0;
}

.event-card a:not(.card-link) {
    position: relative;
    z-index: 1;
}

/* Placed before .is-boosted .event-card (same specificity, later wins) so the boosted border stays. */
.event-card:hover {
    border-color: var(--accent);
}

/* ---- Event card layout: a body wrapper (title row, meta, summary) and, on boosted cards only,
   an image slot on the left, a star beside the title and a --featured outline. */
.card-body {
    min-width: 0;
}

.card-head {
    display: flex;
    align-items: baseline;
}

.is-boosted .event-card {
    display: grid;
    grid-template-columns: 13.5rem 1fr;
    gap: 0;
    padding: 0;
    overflow: hidden;
    border: 2px solid var(--burnt-red);
    box-shadow: var(--shadow-featured);
}

/* Editor's pick (and a business's local favorite): a slightly thicker border, and the same resting shadow as a
   Featured card. Regular 1px -> 2px, boosted 2px -> 3px. */
.event-card.is-pick {
    border-width: 2px;
    border-color: var(--burnt-red);
    box-shadow: var(--shadow-featured);
}

.is-boosted .event-card.is-pick {
    border-width: 3px;
    border-color: var(--burnt-red);
}

/* A small decorative red star in the bottom-right corner, inside the border (the sr-only text names the pick). */
.event-card.is-pick::after {
    content: "\2605";
    position: absolute;
    right: 8px;
    bottom: 4px;
    font-size: 0.875rem;
    line-height: 1;
    color: var(--burnt-red);
    pointer-events: none;
}

/* Cards with the square picture: the star's ink bottom lines up with the picture's bottom (measured: the picture ends
   12px above the inner border edge on a card with no series line, less about 2px between the glyph's ink and its
   line box). Boosted cards keep bottom: 4px. */
.event-card-regular.is-pick::after {
    bottom: 10px;
}

/* Desktop boosted cards: keep the bottom-right extra line clear of the star. */
.is-pick .card-extra {
    padding-right: 1.25rem;
}

/* Boosted cards: a decorative megaphone in the bottom-right corner (the card already has an sr-only "Featured" label).
   On a boosted editor's pick the star moves left of it. */
.is-boosted .event-card::before {
    content: "";
    position: absolute;
    right: 8px;
    bottom: 12px;
    width: 1rem;
    height: 1rem;
    background: url("images/megaphone.7b25fe88d257.svg") center / contain no-repeat;
    pointer-events: none;
}

.is-boosted .event-card.is-pick::after {
    right: 30px;
    bottom: 12px;
}

.is-boosted .card-extra {
    padding-right: 1.5rem;
}

.is-boosted .is-pick .card-extra {
    padding-right: 2.75rem;
}

/* Desktop: the image fills the card's full height; at least 4:5 of the 13.5rem column (16.875rem), taller if the text needs it. */
.is-boosted .card-media {
    align-self: stretch;
    aspect-ratio: auto;
    min-height: 16.875rem;
}

.is-boosted .card-media .img-placeholder {
    width: 100%;
    height: 100%;
    min-height: 0;
    border-radius: 0;
}

/* Dev placeholders until real event images exist; the three variants cycle by the server-set class. */
.is-boosted .img-placeholder, .event-card-regular .img-placeholder {
    background-position: center;
    background-size: cover;
    background-repeat: no-repeat;
}

/* Regular (non-boosted) cards: the title row keeps the full width; under it a square picture on the left and
   the meta line, summary and series line to its right. .card-body becomes display: contents so its children are
   grid items of the card (the stretched link and the z-index on inner links are unaffected). */
.event-card-regular {
    display: grid;
    grid-template-columns: 5.5rem minmax(0, 1fr);
    column-gap: 12px;
    row-gap: 4px;
    align-content: start;
}

.event-card-regular .card-body {
    display: contents;
}

.event-card-regular .card-head {
    grid-column: 1 / -1;
}

.event-card-regular .card-media-square {
    grid-column: 1;
    grid-row: 2 / span 3;
    align-self: start;
    aspect-ratio: 1 / 1;
    min-width: 0;
}

.event-card-regular .card-media-square .img-placeholder {
    width: 100%;
    height: 100%;
    min-height: 0;
    border-radius: var(--radius);
}

/* An event photo (ADR 0122) fills the box the placeholder fills. Regular cards: a square, cropped by the image host
   to the card's rendition, so the width and height attributes reserve the same box before it loads. */
.card-photo {
    display: block;
    width: 100%;
    height: auto;
    object-fit: cover;
    border-radius: var(--radius);
}

/* Featured cards: the photo covers the whole media box (a 4:5 column on desktop, a square on phones) and takes no
   part in the card's height, so a late image never moves the text. */
.is-boosted .card-media picture {
    display: contents;
}

.is-boosted .card-media .card-photo {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    border-radius: 0;
}

/* A business logo (ADR 0123) is shown whole, never cropped: a square box, the picture contained and centred on a
   light ground. (The image host fits it inside the box, so a wide or tall logo has bands, not cut edges.) */
.card-photo.card-logo {
    aspect-ratio: 1 / 1;
    object-fit: contain;
    background: var(--surface);
    box-sizing: border-box;
    padding: 0.25rem;
}

.event-card-regular .meta,
.event-card-regular .summary,
.event-card-regular .series {
    grid-column: 2;
    min-width: 0;
}

.event-card-regular .series {
    margin-top: 0;
}

@media (max-width: 30rem) {
    .event-card-regular {
        grid-template-columns: 4.5rem minmax(0, 1fr);
    }
}

/* Ongoing and day-list cards (regular, non-boosted): title (max 2 lines), then one italic full-width line (runs through + place), then the square
   picture beside the summary (max 2 lines, top-aligned with the picture) and the series line below it. */
.event-card-listing .card-link {
    min-width: 0;
}

/* No row gap: the title sits close above the italic line, like the boosted cards; the rows below carry their own 4px. */
.event-card-listing {
    row-gap: 0;
}

.event-card-listing .event-title {
    margin-bottom: 0;
}

.event-card-listing .card-head {
    grid-row: 1;
}

.event-card-listing .meta {
    grid-column: 1 / -1;
    grid-row: 2;
    margin: 2px 0 0;
    font-size: 0.8125rem;
    line-height: 1.4;
    font-style: italic;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.event-card-listing .card-media-square {
    grid-row: 3 / span 2;
    margin-top: 4px;
}

.event-card-listing .summary {
    grid-column: 2;
    grid-row: 3;
    margin-top: 4px;
    align-self: start;
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
}

.event-card-listing .series {
    grid-row: 4;
    margin-top: 4px;
    align-self: start;
}

/* Footer row of a listing card (column 2, last row, at the bottom): the repeats text on the left and the small
   category / Online / price line on the right; it wraps when the row is too narrow. */
.event-card-listing .listing-foot {
    grid-column: 2;
    grid-row: 4;
    align-self: end;
    min-width: 0;
    margin-top: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-end;
    gap: 2px 8px;
}

.event-card-listing .listing-foot .series {
    grid-row: auto;
    margin-top: 0;
}

/* Shown on phones too (the global rule that hides .card-extra there is for the boosted cards' image badge). */
.event-card-listing .card-extra {
    display: block;
    margin: 0 0 0 auto;
    padding-top: 0;
}

.placeholder-1 .img-placeholder {
    background-image: url("images/event-placeholder-1.42befb9c7d5f.svg");
}

.placeholder-2 .img-placeholder {
    background-image: url("images/event-placeholder-2.52bebe064885.svg");
}

.placeholder-3 .img-placeholder {
    background-image: url("images/event-placeholder-3.035322d7d724.svg");
}

.is-boosted .card-body {
    display: flex;
    flex-direction: column;
    padding: 12px 14px 12px;
}

.is-boosted .card-media {
    position: relative;
}

/* Desktop: category, online marker and price as one small line at the bottom-right of the text area. */
.card-extra {
    margin: auto 0 0;
    padding-top: 6px;
    align-self: flex-end;
    text-align: right;
    font-family: var(--font-body);
    font-size: 0.75rem;
    line-height: 1.3;
    color: var(--muted);
}

.extra-badge {
    display: none;
}

/* The date and time badge sits in the top-left corner of the image (.when-badge). */
.when-badge {
    display: block;
    position: absolute;
    top: 8px;
    left: 8px;
    z-index: 1;
    padding: 1px 8px;
    font-family: var(--font-body);
    font-size: 0.8125rem;
    font-weight: 700;
    line-height: 1.5;
    color: var(--burnt-red);
    background: var(--white);
    border: 1px solid var(--burnt-red);
    border-radius: var(--radius);
}

/* The meta line drops the date/time (the badge on the image has it) and the separator right after it. */
.is-boosted .when, .is-boosted .when + .when-dot {
    display: none;
}

.card-head .badge.boosted {
    padding: 0;
    border: 0;
    background: transparent;
    color: var(--featured);
    font-size: 1.25rem;
    line-height: 1;
    -webkit-text-stroke: 0.75px var(--ink);
}

/* The star is hidden for now (screen readers still hear "Featured"); delete this rule to bring it back. */
.card-head .badge.boosted [aria-hidden="true"] {
    display: none;
    margin-right: 6px;
}

@media (max-width: 30rem) {
    /* phones: the date and time are a badge in the top-left corner of the image */
    .when-badge {
        display: block;
        position: absolute;
        top: 8px;
        left: 8px;
        z-index: 1;
        padding: 2px 8px;
        font-family: var(--font-body);
        font-size: 0.8125rem;
        font-weight: 700;
        line-height: 1.4;
        color: #000;
        background: var(--white);
        border: 1px solid #000;
        border-radius: var(--radius);
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    }

    /* phones: the text column starts 8px below the image, as before the desktop badge moved */
    .is-boosted .card-body {
        padding-top: 8px;
    }

    .card-extra {
        display: none;
    }

    /* phones: the same text as a small badge at the bottom-right of the image */
    .extra-badge {
        display: block;
        position: absolute;
        right: 8px;
        bottom: 8px;
        max-width: calc(100% - 16px);
        padding: 1px 6px;
        font-family: var(--font-body);
        font-size: 0.6875rem;
        font-weight: 600;
        line-height: 1.4;
        color: var(--text);
        background: var(--surface);
        border-radius: var(--radius);
        box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
    }

    .is-boosted .event-card {
        /* phones: image on top, square (1:1), text below. minmax(0, 1fr), not 1fr: a plain 1fr never goes narrower than
           its widest content, which stretched the card's one column (and its square picture) past the card. */
        grid-template-columns: minmax(0, 1fr);
    }

    .is-boosted .card-media {
        aspect-ratio: 1 / 1;
        min-height: 0;
        /* The picture is as wide as the card and square: not stretched to its grid row (the desktop rule), which
           made the row's height set the width and pushed the picture past the card's edge. */
        align-self: start;
        width: 100%;
        max-width: 100%;
    }

    /* phones: .card-extra is hidden, so the icons keep the corner position they had */
    .is-boosted .event-card::before,
    .is-boosted .event-card.is-pick::after {
        bottom: 4px;
    }
}

/* Desktop hover, like flipping a paper card: a very small zoom and a small tilt. The tilt is fixed per card by its
   position in the list (five values cycle). Not for phones, touch screens or reduced motion. */
@media (hover: hover) and (min-width: 48rem) and (prefers-reduced-motion: no-preference) {
    .event-card {
        transition: transform 0.16s ease-out, box-shadow 0.16s ease-out;
    }

    .event-card:hover {
        transform: scale(1.03) rotate(var(--tilt, 0deg));
        z-index: 2;
        box-shadow: var(--shadow-hover);
    }

    /* The large Featured cards do not zoom or tilt; a minor red glow around the border instead. */
    .is-boosted .event-card:hover {
        transform: none;
        box-shadow: 0 0 8px 1px var(--burnt-red);
    }

    .cards > li:nth-child(5n + 1) {
        --tilt: -1.2deg;
    }

    .cards > li:nth-child(5n + 2) {
        --tilt: 0.8deg;
    }

    .cards > li:nth-child(5n + 3) {
        --tilt: -0.5deg;
    }

    .cards > li:nth-child(5n + 4) {
        --tilt: 1.1deg;
    }

    .cards > li:nth-child(5n) {
        --tilt: -0.9deg;
    }
}

.event-title {
    margin: 0 0 4px;
    font-size: 1.0625rem;
}

.meta, .summary {
    margin: 0;
    color: var(--muted);
}

/* Boosted cards: the place line sits close under the title, in italics, with a thin divider above the description.
   With nothing visible in the line (online-only events) it takes no space. */
.is-boosted .event-title {
    margin-bottom: 0;
}

.is-boosted .meta.has-place {
    margin: 2px 0 6px;
    font-size: 0.8125rem;
    line-height: 1.4;
    font-style: italic;
    /* One line, whatever the venue name: a long one ends in an ellipsis (the text stays in the page), so the
       divider and the summary of neighbouring Featured cards start at the same height. */
    min-width: 0;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
}

.is-boosted .meta.has-place::after {
    content: "";
    display: block;
    width: 1.5rem;
    margin-top: 6px;
    border-bottom: 1px solid var(--muted);
}

.is-boosted .meta:not(.has-place) {
    margin: 0;
}

.empty, .more {
    margin: 24px 0;
}

/* Load previous events, the week dots, Load more events: one row under the day list. */
.pager {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 12px;
}

.pager .btn {
    display: inline-flex;
    align-items: center;
    gap: 8px;
    font-size: inherit;
    background: var(--cream);
    color: var(--burnt-red);
    border: 1px solid var(--burnt-red);
}

/* A button with nowhere to go (no earlier or later window): there, but greyed out and dead. */
.pager .is-disabled {
    background: var(--white);
    color: var(--muted);
    border-color: var(--line);
    opacity: 0.55;
    cursor: default;
    pointer-events: none;
}

/* On hover (pointer devices only) a live button fills red with white text, arrow included; a
   disabled one is a button, not a link, so it never matches. */
@media (hover: hover) {
    .pager a.btn:hover {
        background: var(--burnt-red);
        color: var(--white);
        border-color: var(--burnt-red);
        filter: none;
    }
}

/* One dot for each week with events, like the carousel's dots, but links: the circle is 6px, the target 24px. */
.pager-dots {
    display: flex;
    flex: 1 1 auto;
    justify-content: center;
    align-items: center;
}

.pager-dot {
    position: relative;
    display: block;
    width: 24px;
    height: 24px;
}

.pager-dot::before {
    content: "";
    position: absolute;
    top: 50%;
    left: 50%;
    width: 6px;
    height: 6px;
    margin: -3px 0 0 -3px;
    border-radius: 50%;
    background: var(--line);
}

.pager-dot.is-active::before {
    background: var(--burnt-red);
}

a.pager-dot:hover::before {
    background: var(--muted);
}

/* Phones: the dots on their own line above, the buttons sharing the width (their text may wrap). */
@media (max-width: 36rem) {
    .pager {
        flex-wrap: wrap;
    }

    .pager-dots {
        order: -1;
        flex: 0 0 100%;
    }

    .pager .btn {
        flex: 1 1 0;
        min-width: 0;
    }
}

.more {
    text-align: center;
}

a:focus-visible, button:focus-visible, input:focus-visible, select:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

.card-link {
    color: inherit;
    text-decoration: none;
}

/* A card title is one line, however long: cut with an ellipsis (the full title is in the page text and on the
   event's own page). min-width: 0 on every box above it lets the cut engage inside the flex and grid parents.
   Only the cards (.event-card): the page's own h1 may wrap. */
.event-card .event-title {
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}

.event-card .card-link, .event-card .card-head {
    min-width: 0;
}

.card-link:hover .event-title {
    text-decoration: underline;
}

.crumbs {
    margin: 8px 0;
    color: var(--muted);
    font-family: var(--font-mono);  /* the Courier face of the site's nav and labels (Courier Prime, self-hosted) */
    font-size: 0.875rem;
}

.event-page h1 {
    font-size: 1.75rem;
    line-height: 1.2;
    margin: 8px 0;
}

/* Section headings match the list page's (.pinned h2): 1.3125rem with an accent rule. */
.event-page h2, .related h2 {
    font-size: 1.3125rem;
    margin: 16px 0 6px;
    border-bottom: 2px solid var(--accent);
}

.event-page .description, .event-page .summary {
    max-width: 42rem;
}

.map-link, .ticket-link, .gcal-link, .ics-link, .online-link {
    display: inline-block;
    min-width: 44px;
    min-height: 44px;
    padding: 10px 0;
}

.event-image {
    display: block;
    max-width: 100%;
    height: auto;
    border-radius: 8px;
    margin: 12px 0;
}

.banner {
    margin: 12px 0;
    padding: 10px 14px;
    border-radius: 6px;
    border: 1px solid var(--line);
    background: var(--surface);
}

/* The cancelled alert: ALL CAPS (by CSS, the text itself is as written), bold, in the burnt red on a light red tint
   (burnt-red 10% over white: a contrast of about 9:1). The "ended" banner is not this. */
.banner.cancelled {
    border-color: var(--burnt-red);
    border-width: 1px 1px 1px 6px;
    background: color-mix(in srgb, var(--burnt-red) 10%, var(--white));
    color: var(--burnt-red);
    font-weight: 700;
    letter-spacing: 0.06em;
    text-transform: uppercase;
}

.chips {
    display: flex;
    flex-wrap: wrap;
    gap: 8px;
    margin: 8px 0;
}

.chip {
    padding: 2px 10px;
    border: 1px solid var(--line);
    border-radius: 999px;
    text-decoration: none;
    font-size: 0.875rem;
    background: var(--surface);
}

.pick, .featured-mark {
    margin: 4px 0;
    font-weight: 700;
    color: var(--accent);
}

.event-page .pick, .event-page .featured-mark {
    margin: 0;
}

/* An editor's pick: one inline line under the title: the pick marker (.pick), then, with a note, a colon and the italic
   note (.note), as the cards' italic lines. No box, no line. */
.pick-line {
    margin: 0 0 8px;
}

/* A short dash above the line (decorative, no element): 2rem wide, the red accent of the section rules. */
.pick-line::before {
    content: "";
    display: block;
    width: 2rem;
    margin: 8px 0;
    border-top: 2px solid var(--accent);
}

.pick-line .featured-mark {
    margin-right: 8px;
}

.note {
    font-style: italic;
}

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

.venue, .price {
    margin: 0 0 6px;
}

.calendar-links {
    display: flex;
    flex-wrap: wrap;
    gap: 16px;
    margin: 20px 0;
}

/* Under "Never miss an event" the button row ends the section, so whatever follows is spaced by its own gap: the
   similar events by their heading's (--section-heading-gap), the Featured block by the 16px the row used to leave. */
.actions .subscribe-link {
    margin-bottom: 0;
}

.actions + .pinned {
    margin-top: 16px;
}

.related {
    margin-top: 0;  /* the space above the heading is the heading's own (--section-heading-gap), as under its rule */
}

/* The related cards are the list's cards in a sideways row (ADR 0091): the Featured row's carousel arrows and
   script, three cards in view from 48rem, 85% wide on phones so the next card shows. Scroll-snap; padding above
   and below keeps the hover zoom and the Featured glow from being clipped (the negative margins cancel it). */
.related .cards {
    grid-template-columns: none;
    grid-auto-flow: column;
    grid-auto-columns: 85%;
    overflow-x: auto;
    scroll-snap-type: x proximity;
    scrollbar-width: none;
    padding-top: 10px;
    margin-top: -10px;
    padding-bottom: 16px;
    margin-bottom: -10px;
}

.related .cards::-webkit-scrollbar {
    display: none;
}

.related .cards > li {
    scroll-snap-align: start;
}

.related-item {
    padding: 0;
}

/* The heading row of the similar events is the list's Featured heading row (.pinned-head: heading left, key right,
   rule under both, the same space under the rule as under "Never miss an event"); the section's own h2 rule is
   dropped so the row carries it. */
.related .pinned-head h2 {
    margin: var(--section-heading-gap) 0 0;  /* as far below the section above as the cards are below the rule */
    border-bottom: 0;
}

/* The key, when it sits here, wraps under the heading on a narrow screen at the right edge. */
.related .pinned-head .pick-key {
    margin-left: auto;
}

/* The last slide: not an event, but the same shell as an event card (size, border, radius, hover). */
.related-more {
    padding: 0;
}

.related-more-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 4px;
    box-sizing: border-box;
    height: 100%;
    min-height: 10.25rem;
    padding: 12px 14px;
    background: var(--surface);
    border: 1px solid var(--line);
    border-radius: 8px;
    color: var(--burnt-red);
    font-family: var(--font-heading);
    font-weight: 700;
    text-decoration: none;
}

.related-more-card:hover {
    border-color: var(--accent);
}

.related-more-arrow {
    font-size: 2.5rem;
    line-height: 1;
}

.related-more-label {
    font-size: 1.0625rem;
}

/* The dots here are buttons that scroll to their card: the 6px circle (as the Featured row's), a 24px target. */
.carousel-dots .carousel-dot {
    box-sizing: content-box;
    padding: 9px;
    border: 0;
    background-clip: content-box;
    cursor: pointer;
}

@media (hover: hover) and (min-width: 48rem) and (prefers-reduced-motion: no-preference) {
    .related-more-card {
        transition: transform 0.16s ease-out, box-shadow 0.16s ease-out;
    }

    .related-more-card:hover {
        transform: scale(1.03) rotate(var(--tilt, 0deg));
        box-shadow: 0 8px 16px rgba(0, 0, 0, 0.18);
    }
}

@media (min-width: 48rem) {
    .related .cards {
        grid-auto-columns: calc((100% - 24px) / 3);
    }
}

@media (hover: hover) and (min-width: 48rem) {
    .related .cards {
        scroll-snap-type: x mandatory;
    }
}

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

/* ---- Event page look (ADR 0091). Two looks: plain, and .featured while a paid boost runs. An editor's pick
   (.is-pick) takes the cards' red border. The image box is ALWAYS 4:5 (portrait, so a flyer stays readable)
   and the picture is never cropped: object-fit: contain on a tinted backdrop, so any other shape letterboxes.
   Phones: the box above the title, at most 28rem wide. From 48rem: the box in a left column (2/5; it scrolls
   with the page, nothing is sticky) and everything else stacked in the right column. */
/* The space under the breadcrumbs equals the space above them: the page's top padding (.plain-main, 12px) plus the
   breadcrumbs' own top margin (8px), at every width. */
.event-page {
    margin: 20px 0 0;
}

.event-side {
    width: 100%;
    max-width: 28rem;
    margin: 0 auto 1.5rem;  /* phones: room before the title block below (reset from 48rem) */
}

.event-hero {
    position: relative;
    box-sizing: border-box;
    width: 100%;
    aspect-ratio: 4 / 5;
    overflow: hidden;
    border-radius: 8px;
    background: var(--tan);
}

/* Under the image, each button as wide as it (the column is the image's width) and all alike. */
.event-actions {
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    margin-top: 0.75rem;
}

.event-actions .btn {
    width: 100%;
    min-height: 44px;
    text-align: center;
}

/* The share buttons: the cream of the pager's buttons and the red outline of the list's action buttons; their
   hover is the standard .btn hover. (The calendar buttons are the red ones, .btn-red.) */
.share-row .btn-light {
    background: var(--cream);
    border-color: var(--burnt-red);
}

.event-hero-img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: contain;
    object-position: center;
}

/* Category badges and, last and lowest, the neighbourhood: small, not links, stacked in the lower right corner inside the
   image box (at most 40% of its height: the top ones are cut first), on a solid
   cream badge with a hairline so they read on any picture. Type as the cards' category line (.card-extra). */
.event-cats {
    position: absolute;
    right: 0.5rem;
    bottom: 0.5rem;
    left: 0.5rem;
    z-index: 1;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    justify-content: flex-end;
    gap: 4px;
    max-height: 40%;
    overflow: hidden;
    margin: 0;
}

/* The time badge: the top-left corner of the image box (its look is the shared badge rule below). */
.event-hero .when-badge {
    top: 0.5rem;
    left: 0.5rem;
    box-shadow: none;
}

/* Share: a small heading and equal buttons in one row, wrapping on a narrow screen. The Calendar and Share headings
   are h2 elements (the page outline), set at the smaller size here; `.event-page h2` would otherwise win. */
.event-page .share-heading {
    margin: 0 0 6px;  /* the section headings' rhythm: a 2px accent rule under it, 6px before the content */
    font-size: 1rem;
    border-bottom: 2px solid var(--accent);
}

.share-row {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
}

.share-row .btn {
    flex: 1 1 6rem;
    min-height: 44px;
}

/* The share buttons are icons: equal 44px squares, left aligned. The picture is a background (as the megaphone
   is) so the button carries no visible text; "Copied" appears next to the row for a moment. */
.share-icons {
    align-items: center;
}

.share-icons .btn {
    flex: 0 0 44px;
    width: 44px;
    height: 44px;
    padding: 0;
}

.share-icon {
    display: block;
    width: 1.375rem;
    height: 1.375rem;
    background: center / contain no-repeat;
}

.share-icon-email {
    background-image: url("images/share-email.8d29d83710f2.svg");
}

.share-icon-text {
    background-image: url("images/share-text.9bc205a2b098.svg");
}

.share-icon-share {
    background-image: url("images/share-native.f64f8f26046d.svg");
}

.share-icon-link {
    background-image: url("images/share-link.cab8bd2dacba.svg");
}

.share-copy.is-copied .share-icon-link {
    background-image: url("images/share-check.dbba093a575d.svg");
}

.share-status {
    margin: 0 0 0 0.25rem;
}

.share-row.calendar-links {
    gap: 0.5rem;
    margin: 0;
}

/* A calendar control with nowhere to go yet (the .ics route): there, but a flat grey with white text at reduced
   strength, clearly not the live red button beside it. A disabled <button> is not focusable and takes no click. */
.share-row .btn.is-disabled {
    background: var(--muted);
    color: var(--white);
    border-color: var(--muted);
    opacity: 0.55;
    cursor: default;
    filter: none;
    pointer-events: none;
}

.share-copy[hidden], .share-native[hidden] {
    display: none;
}

.event-inner {
    min-width: 0;
    padding: 0;
}

/* Whatever comes first in the column (a banner or the title) starts at the top edge of the image box. */
.event-inner > :first-child {
    margin-top: 0;
}

/* A title at the top: the line box has empty space above the capitals (half-leading plus the font's ascent over its
   cap height), which put the glyphs below the image edge. Tighter leading and a pull up of 0.24em line the capital
   tops up with the top of the image box (measured in Chrome: within 1px with the heading font). */
.event-inner > .event-title:first-child {
    margin-top: -0.24em;
}

/* Featured and editor's pick: the red border on the image box (the cards' accent); Featured adds the soft
   shadow and a faint red glow. */
.event-page.featured .event-hero, .event-page.is-pick .event-hero {
    border: 2px solid var(--burnt-red);
}

.event-page.featured.is-pick .event-hero {
    border-width: 3px;
}

.event-page.featured .event-hero {
    box-shadow:
        0 4px 6px -3px rgba(0, 0, 0, 0.25),
        0 0 0 4px color-mix(in srgb, var(--burnt-red) 14%, transparent);
}

/* The Featured marker is plain text like the pick marker (one rule above), led by the card's red megaphone. */
.featured-mark .megaphone {
    display: inline-block;
    width: 1rem;
    height: 1rem;
    margin-right: 4px;
    vertical-align: -0.15em;
    background: url("images/megaphone.7b25fe88d257.svg") center / contain no-repeat;
}

.event-body {
    display: grid;
    gap: 1.25rem;
    margin-top: 1rem;
}

.event-facts {
    min-width: 0;
}

.event-facts section {
    margin-top: 1.25rem;
}

.event-main section {
    margin-top: 0;  /* the page's row gap spaces the About and Share sections */
}

.event-facts section:first-child {
    margin-top: 0;
}

/* The sections sit on the page: no box, no tint (Featured keeps its accent on the image, badge and title). */
.event-facts h2, .event-main h2 {
    margin: 0 0 6px;
}

.event-facts p, .event-main p {
    margin: 0 0 6px;
}

.event-main {
    min-width: 0;
}

.when-head, .about-head {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: baseline;
    gap: 0 12px;
    margin: 0 0 6px;
    border-bottom: 2px solid var(--accent);
}

.event-facts .when-head h2, .event-main .about-head h2 {
    margin: 0;
    border-bottom: 0;
}

.when-note, .price-pill {
    margin-left: auto;  /* right-aligned, also when it wraps under the heading on a very narrow screen */
}

/* A showing on two lines: the date, then the time. */
.showing {
    display: flex;
    flex-wrap: wrap;
    align-items: baseline;
    gap: 2px 8px;
    padding: 4px 0;
}

.showing time {
    display: block;
}

.showing-date, .showing-time {
    display: block;
}

.showing-time {
    color: var(--muted);
}

/* The red button (the newsletter and share buttons on an event page): solid red with white text; its hover is the
   standard .btn hover (a slightly brighter red). .btn.btn-red is more specific than the later .btn rules. */
.btn.btn-red {
    background: var(--burnt-red);
    color: var(--white);
    border-color: var(--burnt-red);
}

/* The address under the venue name is one inline text link, so the name and the address read as one block with plain
   line breaks (the shared .map-link rule above makes a link inline-block with 10px of padding: not here). Underlined,
   a thicker line on hover. */
.venue .map-link {
    display: inline;
    min-width: 0;
    min-height: 0;
    padding: 0;
    margin: 0;
}

.venue .map-link:hover {
    color: var(--burnt-red);
    text-decoration-thickness: 2px;
}

/* "Organized by ..." right under the title: italic like the cards' italic lines, a little smaller than the body text. */
.organizer-line {
    margin: 0 0 0.5rem;
    font-size: 0.9375rem;
    font-style: italic;
}

.online-link {
    font-weight: 700;
    color: var(--link-color);
    text-decoration: underline;
}

/* The join link sits in a line of text, so it must not make the line taller, yet its tap target is 44px like every
   other link: an inline-flex box 44px high whose vertical margins pull it back to one line of text (1lh is the
   line's height; -10px is the same for a 24px line, for a browser without the lh unit). The text is centred in the
   box, so the box extends the same distance above and below it and neither the text nor the line moves. */
.venue .online-link, .join-online .online-link {
    display: inline-flex;
    align-items: center;
    min-width: 44px;
    min-height: 44px;
    padding: 0;
    margin-block: -10px;
    margin-block: calc((1lh - 44px) / 2);
}

/* A hybrid event: the join link at the bottom right of the Where column, level with the last line of the address
   (the two share a line height; the bottoms are aligned). With no room it wraps under the address, right aligned. */
.venue-row {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    align-items: flex-end;
    gap: 0 12px;
}

.venue-row .venue {
    min-width: 0;
}

.venue-row .join-online {
    margin-left: auto;  /* (more specific than the column's paragraph margins) */
}

.chip:hover {
    border-color: var(--accent);
}

/* A chip that is not a link (the neighbourhood name): no hover change, no pointer. */
.chip-static,
.chip-static:hover {
    border-color: var(--line);
    cursor: default;
}

@media (min-width: 48rem) {
    .event-page {
        display: grid;
        grid-template-columns: minmax(0, 2fr) minmax(0, 3fr);
        gap: 32px;
        align-items: start;
    }

    .event-side {
        max-width: none;
        margin: 0;
    }

    /* When and Where side by side (both are short); About and Price stay below, full width. A long word wraps
       inside its half; the note on the When heading line wraps under the heading when the half is too narrow. */
    .event-facts {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 1.5rem;
        align-items: start;
        overflow-wrap: anywhere;
    }

    .event-facts section, .event-facts section:first-child {
        margin-top: 0;
    }
}

/* ---- Chrome: header, footer, buttons (themes set the --header-*, --footer-*, --btn-* variables) */
:root {
    --header-bg: var(--surface);
    --header-border: 3px solid var(--brand-primary);
    --footer-bg: var(--surface);
    --footer-text: var(--muted);
    --section-bg: var(--surface);
    --section-border: 1px solid var(--line);
    --btn-bg: var(--brand-primary);
    --btn-text: #ffffff;
    --btn-transform: none;
    --link-color: var(--brand-primary);
    --accent: var(--brand-accent);
    --btn-light-text: var(--brand-primary);
}

.sr-only {
    position: absolute;
    width: 1px;
    height: 1px;
    padding: 0;
    margin: -1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
    white-space: nowrap;
    border: 0;
}

.site-header {
    background: var(--header-bg);
    border-bottom: var(--header-border);
    box-shadow: var(--shadow-soft);
}

/* Desktop only: the menu bar stays at the top while scrolling; anchors land below it. */
@media (min-width: 48rem) {
    html {
        scroll-padding-top: 5rem;
    }

    .site-header {
        position: sticky;
        top: 0;
        z-index: var(--z-header);
    }
}

/* Same-page anchors (Join for free, skip link, day links) glide; only the page's own scroller, not the Featured row or the strip. */
@media (prefers-reduced-motion: no-preference) {
    html {
        scroll-behavior: smooth;
    }
}

/* Page loads fade (cross-document view transition; browsers without support ignore it). The header has its own name so it stays put while the rest fades. */
@media (prefers-reduced-motion: no-preference) {
    @view-transition {
        navigation: auto;
    }

    ::view-transition-old(root),
    ::view-transition-new(root) {
        animation-duration: 0.18s;
    }

    .site-header {
        view-transition-name: site-header;
    }
}

.header-inner, .footer-inner {
    max-width: var(--content-width);
    margin: 0 auto;
    padding: 10px 16px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 16px;
    flex-wrap: wrap;
}

.logo {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    color: var(--text);
    text-decoration: none;
}

.logo-img {
    display: block;
    height: 48px;
    width: auto;
    max-width: 100%;
}

.wordmark {
    font: 700 1.25rem var(--font-heading);
    line-height: 1.1;
}

.footer-logo {
    display: block;
    height: 40px;
    width: auto;
    max-width: 100%;
}

.main-nav {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 0;
    font-family: var(--font-ui);
    font-size: 0.8125rem;
}

/* The phone menu (below 48rem): logo, a compact Subscribe and a "Menu" toggle on one row of about 60px; the toggle is
   a details element (no script) whose panel drops over the page under the header as large full-width rows. From
   48rem the toggle is gone and .main-nav above is the menu. */
.mobile-nav {
    display: none;
}

@keyframes menu-scrim-in {
    from { opacity: 0; }
    to { opacity: 1; }
}

@media (max-width: 47.99rem) {
    .site-header {
        position: relative;
        z-index: var(--z-header);  /* without a z-index the later positioned page content (the tape, the carousel, the boxes) painted over the open panel */
    }

    /* logo left, the Menu toggle in the true centre, Subscribe right */
    .site-header .header-inner {
        display: grid;
        grid-template-columns: 1fr auto 1fr;
        align-items: center;
        gap: 8px;
        padding-top: 8px;
        padding-bottom: 8px;
    }

    .site-header .logo {
        grid-column: 1;
        grid-row: 1;
        justify-self: start;
    }

    .mobile-nav {
        grid-column: 2;
        grid-row: 1;
        justify-self: center;
    }

    .site-header .logo-img {
        height: 40px;
    }

    .site-header .main-nav {
        display: none;
    }

    .site-header .header-inner > .btn {
        grid-column: 3;
        grid-row: 1;
        justify-self: end;
        padding: 8px 12px;
        font-size: 0.9375rem;
        white-space: nowrap;
    }

    .mobile-nav {
        display: block;
    }

    @media (max-width: 22.5rem) {
        .site-header .header-inner > .btn {
            padding: 8px 8px;
            font-size: 0.8125rem;  /* so the side columns stay equal and the Menu toggle stays centred at 320px */
        }
    }

    .nav-menu summary {
        display: inline-flex;
        align-items: center;
        gap: 8px;
        min-height: 44px;
        padding: 0 10px;
        font: 400 1rem var(--font-ui);  /* the menu links' own font token */
        color: var(--text);
        cursor: pointer;
        list-style: none;
    }

    .nav-menu summary::-webkit-details-marker {
        display: none;
    }

    .nav-menu summary:focus-visible,
    .nav-list a:focus-visible {
        outline: 2px solid var(--burnt-red);
        outline-offset: -2px;
    }

    .nav-burger {
        width: 18px;
        height: 2px;
        background: currentColor;
        box-shadow: 0 -6px 0 currentColor, 0 6px 0 currentColor;
    }

    /* While the menu is open the page under the header is dimmed, so it is clear what was pressed. A fixed layer
       inside the header's own stacking context (the open details element is not positioned and makes no layer of its
       own, so this is the header's layer; no :has is used, ADR 0070; the panel, one step above it, stays crisp); it takes no taps (there
       is no script to close the menu with one, so the page stays usable) and fades in unless motion is reduced. */
    .nav-menu[open]::after {
        content: "";
        position: fixed;
        top: 60px;  /* the header's height: the header itself is not dimmed */
        left: 0;
        right: 0;
        bottom: 0;
        z-index: 0;
        background: rgba(0, 0, 0, 0.35);
        pointer-events: none;
    }

    @media (prefers-reduced-motion: no-preference) {
        .nav-menu[open]::after {
            animation: menu-scrim-in 0.15s ease-out;
        }
    }

    .nav-menu[open] .nav-burger {
        box-shadow: none;  /* one bar (a minus) while the panel is open */
    }

    .nav-list {
        position: absolute;
        top: 100%;
        left: 0;
        right: 0;
        z-index: 1;  /* inside the header's own layer */
        max-height: calc(100vh - 60px);
        overflow-y: auto;  /* a long menu scrolls inside the panel */
        background: var(--header-bg);
        box-shadow: var(--shadow-soft);
    }

    .nav-list a {
        position: relative;
        display: flex;
        align-items: center;
        justify-content: center;
        min-height: 52px;
        padding: 0 20px;
        font: 400 1.0625rem var(--font-ui);  /* the desktop menu links' font token (Courier on Raleigh, sans on Cary), same for every row */
        text-align: center;
        color: var(--text);
        text-decoration: none;
        border-top: 1px solid color-mix(in srgb, var(--muted) 30%, transparent);
    }

    /* The current page: the same type as the others, marked by a short burnt-red bar centred under the label. */
    .nav-list a[aria-current="page"]::after {
        content: "";
        position: absolute;
        left: 50%;
        bottom: 8px;
        width: 24px;
        height: 2px;
        margin-left: -12px;
        background: var(--burnt-red);
    }
}

/* The short menu labels ("Events", "Directory") are hidden visually (and from assistive technology, which reads the
   full label once) except from 48rem to 52rem, where the full ones are the ones hidden visually. */
.nav-short {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
}

@media (min-width: 48rem) and (max-width: 51.99rem) {
    .nav-short {
        position: static;
        width: auto;
        height: auto;
        overflow: visible;
        clip-path: none;
    }

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

/* 48rem to 60rem: one tight row (13px links with 3px of padding, a 36px logo, a smaller Subscribe button, 8px
   gaps; the separators only start at 60rem). */
@media (min-width: 48rem) and (max-width: 59.99rem) {
    .header-inner {
        gap: 8px;
        flex-wrap: nowrap;
    }

    .main-nav {
        flex-wrap: nowrap;
    }

    .logo {
        flex: 0 0 auto;
    }

    .logo-img {
        height: 36px;
    }

    .main-nav a {
        white-space: nowrap;
        padding: 0 3px;
    }

    .site-header .btn {
        font-size: 0.8125rem;
        padding: 8px 10px;
        white-space: nowrap;
    }
}

/* From 60rem the items stay on one line (the header keeps its height): 14px with 14px of padding each side of a
   link (so 14px of room each side of a separator), and from 70rem 15px (--fs-nav) with 18px. Narrower, the
   menu is the tight row above or wraps as it does on a phone. */
@media (min-width: 60rem) {
    .main-nav {
        flex-wrap: nowrap;
        font-size: 0.875rem;
    }

    .main-nav a {
        white-space: nowrap;
        padding: 0 14px;
    }
}

@media (min-width: 70rem) {
    .main-nav {
        font-size: var(--fs-nav);
    }

    .main-nav a {
        padding: 0 18px;
    }
}

.main-nav a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    color: var(--text);
    text-decoration: none;
    padding: 0 12px;
}

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

.main-nav a[aria-current="page"] {
    text-decoration: underline;
    text-underline-offset: 6px;
}

.site-footer {
    background: var(--footer-bg);
    color: var(--footer-text);
    margin-top: 32px;
}

.site-footer a {
    color: inherit;
}

.footer-inner {
    padding: 36px 16px;
    align-items: flex-end;
}

.footer-name {
    margin: 0;
    font: 700 1.25rem var(--font-heading);
}

.footer-tagline {
    margin: 4px 0 0;
    font-size: 0.875rem;
}

.footer-links {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 12px;
}

.socials a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
}

.socials {
    display: flex;
    gap: 12px;
    list-style: none;
    margin: 0;
    padding: 0;
    font-size: 0.875rem;
}

.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-height: 44px;
    padding: 8px 14px;
    background: var(--btn-bg);
    color: var(--btn-text);
    border: 1px solid var(--btn-bg);
    border-radius: 3px;
    font: 700 var(--fs-btn)/1.2 var(--font-heading);
    letter-spacing: 0.04em;
    text-transform: var(--btn-transform);
    text-decoration: none;
    cursor: pointer;
}

.btn:hover {
    filter: brightness(1.12);
}

/* The arrow after a button label: a text glyph in a span of its own (ADR 0108), sized from a token so it is in
   proportion to the 0.75rem label. A fixed system font draws it the same everywhere; line-height 1 keeps it from
   making the button taller than its 44px minimum. */
.btn-arrow {
    margin-inline-start: 0.5em;
    font-family: var(--font-system);
    font-size: var(--btn-arrow-size);
    font-weight: 400;
    line-height: 1;
}

.btn-small {
    padding: 10px 14px;
}

.btn-wide {
    display: flex;
    text-align: center;
}

.btn-light, .site-footer .btn-light {
    background: var(--white);
    color: var(--btn-light-text);
    border-color: var(--white);
}

/* The quieter of two buttons side by side (the thanks page's "Return home"): the primary colour as an outline on
   the page. Brand-neutral, made from the button tokens; the theme files restyle it. */
.btn-secondary {
    background: transparent;
    color: var(--btn-bg);
    border-color: var(--btn-bg);
}

.btn-secondary:hover {
    background: var(--btn-bg);
    color: var(--btn-text);
    filter: none;
}

/* The next-step links of the submission return and manage pages: buttons side by side, wrapping onto the next line
   on a narrow screen, with clear space between them and above. Each target is at least 44px high (.btn) and shows a
   focus ring in the button colour. Brand look comes from .btn / .btn-secondary and the theme files. */
.page-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 12px;
    margin: 1rem 0;
}

.page-actions .btn {
    box-sizing: border-box;
    max-width: 100%;
    text-align: center;
}

.page-actions .btn:focus-visible {
    outline: 3px solid var(--btn-bg);
    outline-offset: 3px;
}

/* Small UX animations: short, opacity/colour only, off for reduced motion */
@media (prefers-reduced-motion: no-preference) {
    .btn, .btn-light, .btn-small, .btn-wide {
        transition:
            color 0.15s ease-out,
            background-color 0.15s ease-out,
            border-color 0.15s ease-out,
            box-shadow 0.15s ease-out,
            filter 0.15s ease-out,
            transform 0.15s ease-out;
    }

    .btn:active, .btn-light:active, .btn-small:active {
        transform: translateY(1px);
    }

    .filters input, .filters select, .filters button,
    .filters .action-row select, .filters .action-row button,
    .advanced summary,
    .day-jump a,
    .more-card {
        transition:
            color 0.15s ease-out,
            background-color 0.15s ease-out,
            border-color 0.15s ease-out,
            box-shadow 0.15s ease-out;
    }

    /* Links in the header and footer: colour only (a footer button keeps the button transition above). */
    .main-nav a,
    .site-footer a:not(.btn),
    .socials a:not(.btn) {
        transition: color 0.15s ease-out;
    }
}

/* Dark mode, after the chrome defaults above (the same specificity, so the later rule wins): the
   brand colour is too dark for links on a near-black page, so links use a tint of it that is at
   least 4.5:1 whatever the brand colour is (a mix with 55% white is never darker than mid grey).
   The fixed colour is for browsers without color-mix. The Raleighwood theme is light only and sets
   its own values after this file. */
@media (prefers-color-scheme: dark) {
    :root {
        --link-color: #93b4ff;
    }

    @supports (color: color-mix(in srgb, red, blue)) {
        :root {
            --link-color: color-mix(in srgb, var(--brand-primary) 45%, #ffffff);
        }
    }
}

/* ---- CMS pages: sections, boxes and the page blocks */
.cms-main {
    padding-bottom: 8px;
}

.pg-inner {
    max-width: var(--content-width);
    margin: 0 auto;
    padding: 16px;
    position: relative;
}

.pg-box {
    background: var(--section-bg);
    border: var(--section-border);
    border-radius: 3px;
    padding: 16px;
    position: relative;
    overflow: hidden;
}

.box-heading {
    margin: 4px 0;
    text-align: center;
    font-size: 1.5rem;
}

.box-sub {
    margin: 0 0 16px;
    text-align: center;
    font-style: italic;
}

.box-cta {
    text-align: center;
    margin: 20px 0 4px;
}

/* The button of the Home Stories and Events Calendar blocks: centred at the bottom, split from the content
   above by a row of small round grey dots (80% of the width, decorative: a pseudo-element, no markup) with
   room on both sides. `space` spreads whole dots evenly, the first and last touching the ends. */
.box-cta-split {
    margin: 14px 0 8px;
}

/* Exactly three dots: a 36px strip of three 12px tiles, each with one 5px dot in its middle. */
.box-cta-split::before {
    content: "";
    display: block;
    width: 36px;
    height: 6px;
    margin: 0 auto 14px;
    background-image: radial-gradient(circle, var(--muted) 2.5px, transparent 3px);
    background-size: 12px 6px;
    background-repeat: repeat-x;
    opacity: 0.7;
}

.pg-bg {
    position: absolute;
    inset: 0;
    width: 100%;
    height: 100%;
    object-fit: cover;
    opacity: 0.18;
    pointer-events: none;
    z-index: 0;
}

.pg-hero {
    position: relative;
    overflow: hidden;
}

.pg-hero .pg-inner {
    z-index: 1;
    padding-top: 40px;
    padding-bottom: 56px;
}

.hero-headline {
    max-width: 36rem;
    font-size: clamp(1.75rem, 5vw, 2.75rem);
    line-height: 1.2;
    margin: 8px 0 20px;
}

.hero-headline em {
    text-decoration: underline;
}

.pg-typewriter {
    padding-bottom: 0;
}

/* Typewriter + hero share one band: the rotating text sits as far above the headline as the
   button sits below it (20px each). The hero keeps its own bottom padding. */
.hero-band .pg-typewriter .live-indicator {
    vertical-align: top;
}

.hero-band .pg-hero .pg-inner {
    padding-top: 0;
}

.hero-band .hero-headline {
    margin: 20px 0;
}

/* On a phone the hero text sits centred between the header and the Latest Newsletter box: 28px above the chip and
   28px (12px here plus the newsletter section's 16px) below the button. */
@media (max-width: 47.99rem) {
    .hero-band .pg-typewriter {
        padding-top: 28px;
    }

    .hero-band .pg-hero .pg-inner {
        padding-bottom: 12px;
    }

    /* and centred across the column: the chip (its width unchanged), the headline and the button */
    .hero-band .pg-typewriter,
    .hero-band .pg-hero .pg-inner {
        text-align: center;
    }
}

/* The band is a centred grid: rotating text and hero in column 1, the newsletter card on the
   right (desktop); a single column in reading order below 48rem. Each block keeps its own
   .pg-inner padding, so edges line up with the rest of the page content. */
.hero-band-inner {
    max-width: var(--content-width);
    margin: 0 auto;
}

.hero-band .news-card {
    max-width: none;
    width: 100%;
    margin: 0;
}

/* Same picture proportions as a story card. */
.hero-band .news-image, .hero-band .news-card .img-placeholder {
    aspect-ratio: 3 / 2;
}

@media (min-width: 48rem) {
    /* The right column is one story card wide: the story grid sits inside .pg-inner (16px padding
       each side) and a .pg-box (1px border + 16px padding each side) and splits into three
       columns with 14px gaps; the news section drops its left padding so the card itself, not
       the card plus padding, takes that width. The box is one card plus the 17px (border and padding)
       its right side already reaches beyond the third card, so its left edge is flush with the third
       story card's and its right edge is where it was. */
    .hero-band-inner {
        display: grid;
        grid-template-columns: minmax(0, 1fr) calc((100% - 94px) / 3 + 33px);
        column-gap: 24px;
        align-items: center;
    }

    /* .pg-inner centres itself with auto margins, which in a grid cell shrinks it to its content
       and centres it; zero margins let it fill the cell and start at the cell's left edge. */
    .hero-band-inner > .pg-typewriter,
    .hero-band-inner > .news-section {
        margin: 0;
    }

    .hero-band-inner > .pg-typewriter {
        grid-column: 1;
        grid-row: 1;
        align-self: end;
    }

    .hero-band-inner > .pg-hero {
        grid-column: 1;
        grid-row: 2;
        align-self: start;
    }

    .hero-band-inner > .news-section {
        grid-column: 2;
        grid-row: 1 / span 2;
        align-self: center;
        padding-left: 0;
    }
}

.news-card {
    max-width: 22rem;
    margin-left: auto;
    text-align: center;
}

.card-heading {
    margin: 4px 0 10px;
    font-style: italic;
    font-size: 1.125rem;
}

.news-image, .news-card .img-placeholder {
    aspect-ratio: 4 / 3;
}

.news-title {
    margin: 8px 0;
    font: italic 700 1rem var(--font-heading);
}

/* The Home post cards (ADR 0099): the picture and the text panel are one card, one rounded shape
   clipped at its edge. The picture runs edge to edge on top (no padding, margin or border of its
   own), and the panel below it carries the surface colour, so the text sits on white with the
   picture above it. The same shell is used by the newsletter card and every story card. */
.post-card {
    background: var(--surface);
    border: 1px solid var(--card-border);
    border-radius: 3px;
    /* not clipped: the washi tape straddles the top edge; the picture and the text panel carry the rounded
       corners themselves (the card's 3px radius less its 1px border) */
}

.post-image {
    display: block;
    width: 100%;
    margin: 0;
    border: 0;
    border-radius: 2px 2px 0 0;
    object-fit: cover;
}

.post-text {
    background: var(--surface);
    padding: 12px 14px 14px;
    overflow-wrap: anywhere;
    border-radius: 0 0 2px 2px;
}

.post-text .news-title {
    margin: 0;
}

.story-image, .story-card .img-placeholder {
    aspect-ratio: 3 / 2;
}

.news-title a {
    color: inherit;
    text-decoration: none;
}

/* A stored post picture (ADR 0099) has width and height attributes so the box is reserved before it
   loads; the aspect ratio of .news-image or .story-image sets the shape, so the height attribute
   must not apply. Long unbroken text wraps instead of widening the card. */
img.post-image {
    height: auto;
}

.news-title {
    overflow-wrap: anywhere;
}

.news-title a:hover, .news-title a:focus-visible {
    text-decoration: underline;
}

.news-note {
    margin: 10px 0 0;
    font-style: italic;
    font-size: 0.875rem;
}

.img-placeholder {
    background: var(--line);
    min-height: 8rem;
}

.story-grid, .quote-grid {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    gap: 14px;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}

.story-card {
    background: var(--surface);
    border: 1px solid var(--card-border);
    border-radius: 3px;
    position: relative;  /* the box the send date badge and the tape are placed in */
}

/* The send date of a Home story: a small badge at the top left of the picture, the look of the
   events cards' time badge. It never takes a click, so the picture and title links stay whole. */
.sent-badge {
    position: absolute;
    top: 8px;
    left: 8px;
    z-index: 1;
    padding: 1px 8px;
    font-family: var(--font-body);
    font-size: 0.8125rem;
    font-weight: 700;
    line-height: 1.5;
    color: var(--burnt-red);
    background: var(--white);
    border: 1px solid var(--burnt-red);
    border-radius: var(--radius);
    pointer-events: none;
}

.story-media {
    position: relative;
}

.story-media img, .story-media .img-placeholder {
    width: 100%;
    aspect-ratio: 3 / 2;
    object-fit: cover;
    display: block;
}

.story-tag {
    position: absolute;
    top: 8px;
    left: 8px;
    background: var(--btn-bg);
    color: var(--btn-text);
    font: 700 0.625rem var(--font-heading);
    text-transform: uppercase;
    padding: 3px 7px;
    border-radius: 2px;
}

.story-text {
    padding: 10px 12px 14px;
}

.story-text h3 {
    margin: 0 0 6px;
    font-size: 1rem;
}

.story-text a {
    color: inherit;
    text-decoration: none;
}

.story-text p {
    margin: 0;
    font-size: 0.875rem;
}

/* The latest-stories block (ADR 0099): the text panel of a story card is a title and at most two
   lines of subtitle (the rest is cut by the clamp, no script and no inline style). It carries both
   .story-text and .post-text; the more specific rule below sets its padding, so the older
   .story-text padding above cannot win the cascade. */
.story-card .post-text {
    padding: 14px 14px 16px;
}

.story-card .post-text a:hover, .story-card .post-text a:focus-visible {
    text-decoration: underline;
}

.story-sub {
    display: -webkit-box;
    -webkit-box-orient: vertical;
    -webkit-line-clamp: 2;
    line-clamp: 2;
    overflow: hidden;
    overflow-wrap: anywhere;
}

.quote-card {
    background: var(--surface);
    border: 1px solid var(--card-border);
    border-radius: 3px;
    padding: 12px 14px;
    display: flex;
    gap: 10px;
    justify-content: space-between;
    align-items: center;
    font-style: italic;
    font-size: 0.875rem;
}

.quote-card blockquote {
    margin: 0;
}

.quote-card p {
    margin: 0;
}

.quote-by {
    text-align: center;
    font-size: 0.75rem;
}

.quote-by span {
    display: block;
}

.avatar {
    border-radius: 50%;
    display: block;
    margin: 0 auto 4px;
    width: 48px;
    height: 48px;
    overflow: hidden;
    /* The picture fills the circle undistorted; a non-square one is cropped around its centre. */
    object-fit: cover;
    object-position: center;
}

.promo {
    display: grid;
    gap: 20px;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    align-items: center;
}

.promo-media img, .promo-media .img-placeholder {
    width: 100%;
    display: block;
}

/* Without Featured events: the picture, then the button centred below it (the same order as with them). */
.promo:not(.promo-featured) {
    grid-template-columns: minmax(0, 36rem);
    justify-content: center;
}

.promo:not(.promo-featured) > .promo-cta {
    margin: 0;
    text-align: center;
}

.promo-text h2 {
    font-size: 1.5rem;
    margin: 0 0 12px;
}

/* The Events Calendar block with Featured events (ADR 0109): under the centred heading and subheading comes
   the carousel, then the button centred below it. */
.promo.promo-featured {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas: "media";
    align-items: start;
}

.promo-featured > .home-featured {
    grid-area: media;
    min-width: 0;
}

.promo-featured > .promo-cta {
    grid-area: cta;
    margin: 0;
    text-align: center;
}

/* The carousel is the events page's own (two cards in view, arrows in their own column beside the row, one
   card on a phone) at the full width of the box. A single Featured event stays centred in the row. */
.home-featured .cards {
    justify-content: safe center;
}

/* The slide group (role group) between a card's list item and the card: it fills the item like the card did. */
.home-featured .slide-group {
    height: 100%;
}

/* The Home carousel has no arrow column: the cards fill the box, centred, and move by themselves on a desktop
   (carousel.js, data-autoplay) or by swipe. The buttons stay in the markup for the script but are never shown. */
.home-featured .carousel {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto auto;
    position: relative;
}

/* The dots row (with the play/pause button) sits above the cards: 8px under the subheading's own space, and the
   row of cards starts about 14px below it (the cards' 10px shadow room is part of that). */
.home-featured .carousel > .carousel-controls {
    grid-column: 1;
    grid-row: 1;
    padding: 0 0 10px;
    margin-top: -8px;  /* the subheading's 16px bottom margin is too much here: 12px above the row */
}

.home-featured .carousel > .cards {
    grid-column: 1;
    grid-row: 2;
}

/* The arrows are out of sight for a mouse but stay in the page: a keyboard or screen reader user reaches them,
   and while one has focus it shows over the edge of the row. */
.home-featured .carousel .carousel-btn {
    display: flex;
    align-items: center;
    justify-content: center;
    position: absolute;
    top: 50%;
    width: 1px;
    height: 1px;
    margin: 0;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    z-index: 2;
}

.home-featured .carousel .carousel-btn[hidden] {
    display: none;
}

.home-featured .carousel .carousel-btn:focus-visible {
    width: 44px;
    height: 44px;
    margin-top: -22px;
    overflow: visible;
    clip-path: none;
    visibility: visible;
}

.home-featured .carousel .carousel-btn[data-carousel-prev] {
    left: 4px;
}

.home-featured .carousel .carousel-btn[data-carousel-next] {
    right: 4px;
}

/* With a mouse or trackpad the arrows are small plain chevrons (just a muted line shape, burnt red on hover or
   focus) in the controls row itself: [play/pause] [<] dots [>], one centred group. Each is a 24x40 target (the
   dots' own targets are 24px, so none overlap) that adds nothing to the row's height. Touch screens keep the
   swipe and no arrows (the group is then just the dots, centred). */
@media (hover: hover) {
    .home-featured .carousel .carousel-btn {
        position: relative;
        top: 0;
        flex: 0 0 auto;
        width: 24px;
        height: 40px;
        margin: -7px 0;  /* the 40px target adds nothing to the row's height */
        padding: 0;
        overflow: visible;
        clip-path: none;
        font-size: 0;  /* the chevron is drawn below; the aria-label names the button */
        color: var(--muted);
        background: none;
        border: 0;
        box-shadow: none;
        cursor: pointer;
        z-index: 3;
    }

    .home-featured .carousel .carousel-btn[hidden] {
        display: none;
    }

    .home-featured .carousel .carousel-btn[data-carousel-prev] {
        margin-right: 18px;  /* between the left chevron and the play/pause button */
    }

    .home-featured .carousel .carousel-btn[data-carousel-next] {
        margin-left: 18px;  /* between the last dot and the right chevron (the targets never overlap) */
    }

    .home-featured .carousel .carousel-btn::before {
        content: "";
        position: absolute;
        top: 50%;
        width: 10px;
        height: 10px;
        border-style: solid;
        border-color: currentColor;
        border-width: 0 0 2px 2px;
    }

    .home-featured .carousel .carousel-btn[data-carousel-prev]::before {
        left: 50%;
        margin: -3px 0 0 -3px;  /* 2px lower than the middle, to sit on the dots' line */
        transform: rotate(45deg);
    }

    .home-featured .carousel .carousel-btn[data-carousel-next]::before {
        right: 50%;
        margin: -3px -3px 0 0;
        transform: rotate(-135deg);
    }

    .home-featured .carousel .carousel-btn:hover,
    .home-featured .carousel .carousel-btn:focus-visible {
        color: var(--burnt-red);
        background: none;
    }

    .home-featured .carousel .carousel-btn:focus-visible {
        outline: 2px solid var(--burnt-red);
        outline-offset: -4px;
        border-radius: 50%;
    }
}

/* Play/pause button at the start of the dots row: a 32px target, muted, with a visible focus ring. */
.carousel-controls {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    padding-top: 4px;
}

.home-featured .carousel-controls {
    gap: 0;  /* [play/pause] [<] dots [>]: the targets touch, the play/pause has its own 8px */
}

.home-featured .carousel-play {
    margin-right: 8px;
}

.carousel-controls .carousel-dots {
    padding-top: 0;
}

.carousel-play {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 32px;
    height: 32px;
    padding: 0;
    color: var(--muted);
    background: transparent;
    border: 1px solid var(--line);
    border-radius: 50%;
    cursor: pointer;
}

.carousel-play[hidden] {
    display: none;
}

.carousel-play svg {
    fill: currentColor;
}

.carousel-play .glyph-play,
.carousel-play.is-playing .glyph-pause {
    display: block;
}

.carousel-play .glyph-pause,
.carousel-play.is-playing .glyph-play {
    display: none;
}

.carousel-play:hover {
    color: var(--text);
    border-color: var(--muted);
}

.carousel-play:focus-visible,
.home-featured .carousel-dot:focus-visible,
.home-featured .carousel .carousel-btn:focus-visible {
    outline: 2px solid var(--burnt-red);
    outline-offset: 2px;
}


.pg-band {
    text-align: center;
    padding: 28px 16px;
}

.band-text {
    position: relative;
    z-index: 1;
}

.band-text h2 {
    margin: 0;
    font-size: 1.75rem;
}

.band-text p {
    margin: 4px 0 14px;
    font-style: italic;
}

.accordion-layout {
    display: grid;
    gap: 16px;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
    align-items: end;
}

.accordion details {
    background: var(--surface);
    border: 1px solid var(--card-border);
    border-radius: 3px;
    margin-bottom: 8px;
}

.accordion summary {
    cursor: pointer;
    min-height: 44px;
    padding: 12px;
    font: 700 1rem/1.25 var(--font-heading);
    text-align: center;
    list-style: none;
}

.accordion summary::-webkit-details-marker {
    display: none;
}

.accordion summary::after {
    content: "\25BE";
    float: right;
}

.accordion details[open] summary::after {
    content: "\25B4";
}

.accordion details p {
    margin: 0;
    padding: 0 12px 12px;
}

/* Side by side, the button (bottom aligned to the list by .accordion-layout) ends exactly where the last item
   ends: the item's 8px bottom margin would otherwise leave the button 8px lower. Stacked, nothing changes. */
@media (min-width: 38rem) {
    .accordion details:last-child {
        margin-bottom: 0;
    }

    /* The left column holds the brand logo, centred against the block of the first three closed items (3 x the
       46px closed row and two 8px gaps), and the button at the bottom. Opening an item does not move the logo. */
    .accordion-cta {
        align-self: stretch;
        display: flex;
        flex-direction: column;
        justify-content: space-between;
    }

    .accordion-logo {
        display: flex;
        align-items: center;
        justify-content: center;
        height: calc(3 * 46px + 2 * 8px);
        padding: 8px 0;
        box-sizing: border-box;
    }

    .accordion-logo img {
        display: block;
        max-width: 60%;
        max-height: 100%;
        width: auto;
        height: auto;
    }
}

/* Stacked, the logo sits centred between the subheading and the button: at most 60% of the width and 90px high. */
@media (max-width: 37.99rem) {
    .accordion-logo {
        display: flex;
        justify-content: center;
        margin: 4px 0 20px;  /* 20px above (with the grid's 16px gap) and below */
    }

    .accordion-logo img {
        display: block;
        width: auto;
        height: auto;
        max-width: 60%;
        max-height: 90px;
    }
}

.sponsor-title {
    text-align: center;
    font-size: 1.5rem;
    margin: 20px 0;
}

.points {
    list-style: none;
    padding: 0;
    margin: 12px auto;
    max-width: 36rem;
    font-size: 0.9375rem;
}

.points li {
    margin-bottom: 10px;
}

.pg-offers .offer-row {
    display: grid;
    gap: 20px;
    grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
    align-items: center;
    padding: 18px 0;
    border-top: 1px solid var(--line);
}

.offer-media img, .offer-media .img-placeholder {
    width: 100%;
    max-height: 18rem;
    object-fit: contain;
    display: block;
}

.offer-text h3 {
    font-size: 1.25rem;
    margin: 0 0 8px;
}

.offer-quote {
    font-style: italic;
}

.inquiry-layout {
    display: grid;
    gap: 20px;
    grid-template-columns: repeat(auto-fit, minmax(16rem, 1fr));
}

.inquiry-map img, .inquiry-map .img-placeholder {
    width: 100%;
    min-height: 12rem;
    object-fit: cover;
    display: block;
}

@media (max-width: 40rem) {
    .header-inner {
        justify-content: center;
    }

    .news-card {
        margin: 0 auto;
    }

    .footer-inner, .footer-links {
        align-items: flex-start;
    }
}

/* ---- Public event submission form (ADR 0070, 0128): complete without script (every field is shown unless the browser supports :has(), see the end of this file); the one script, submit_form.js, only adds the progressive sections, counters and the venue box */
.submit-form fieldset {
    margin: 0 0 20px;
    padding: 12px 14px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--surface);
}

.submit-form legend {
    padding: 0 6px;
    font: 700 1rem var(--font-heading);
}

.submit-form .field {
    margin: 0 0 12px;
    border: 0;
    padding: 0;
}

.submit-form label {
    display: block;
    font-size: 0.9375rem;
    margin-bottom: 4px;
}

.submit-form input[type="text"], .submit-form input[type="email"], .submit-form input[type="url"],
.submit-form input[type="date"], .submit-form input[type="time"], .submit-form select, .submit-form textarea {
    width: 100%;
    max-width: 40rem;
    padding: 8px;
    font: inherit;
    color: var(--text);
    background: var(--page);
    border: 1px solid var(--line);
    border-radius: 4px;
}

.submit-form .choice-list {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
}

.submit-form label.choice {
    display: inline-flex;
    gap: 6px;
    align-items: center;
    margin: 0;
}

.submit-form .hint {
    margin: 4px 0;
    color: var(--muted);
    font-size: 0.875rem;
}

.submit-form .error, .error {
    margin: 4px 0;
    color: #b91c1c;
    font-weight: 700;
}

@media (prefers-color-scheme: dark) {
    .submit-form .error, .error {
        color: #fca5a5;
    }
}

.submit-form .has-error input, .submit-form .has-error select, .submit-form .has-error textarea {
    border-color: #b91c1c;
    border-width: 2px;
}

.banner.problem {
    border-color: #b91c1c;
}

.page-title {
    text-align: center;
}

.page-subtitle {
    display: block;
    font-size: 1.125rem;
    font-weight: 400;
    color: var(--muted);
}

.page-intro {
    max-width: 42rem;
    margin: 0 auto 16px;
    text-align: center;
    color: var(--muted);
}

.subscribe-link {
    margin: 16px 0;
}

/* ---- Recurring series (ADR 0069): list tag, Also line, detail summary and next showing */
.series {
    margin: 4px 0 0;
    display: flex;
    flex-wrap: wrap;
    gap: 4px 8px;
    align-items: baseline;
    font-size: 0.875rem;
    color: var(--muted);
}

/* One look for the small pills: the Repeats tag of the cards, and on an event page the price pill and the badges on the
   image (categories, neighbourhood, time). */
.badge.repeats, .badge.price-pill, .badge.cat-badge, .badge.loc-badge, .badge.when-badge {
    padding: 0 8px;
    font-family: var(--font-body);
    font-size: 0.8125rem;
    font-weight: 600;
    line-height: 1.5;
    color: inherit;
    border-color: var(--line);
    background: var(--cream);
    border-radius: 4px;
}

/* The time badge is a bit larger than the others: one px of type and of padding, nothing else. */
.badge.when-badge {
    padding: 3px 13px;
    font-size: 0.875rem;
}

/* TRIAL (founder may remove): the recurrence line under the showings, in the key's small muted type. */
.recurrence-details {
    margin: 0;
    font-size: 0.75rem;
    color: var(--muted);
}

/* "Happening now", small, inline after the time on the second line. */
.badge.happening-now {
    border-color: var(--accent);
    margin-left: 6px;
    font-size: 0.75rem;
}

/* The next date of a series: the date and time on the left, the Repeats tag at the right of the row. */
.showing .badge.repeats {
    align-self: flex-start;
    margin-left: auto;
}

/* ---- Directory and neighborhoods (ADR 0077): listing grid and cards, listing page, hours, contact links */
/* The listing grid is the events cards' grid (.cards: at most three columns, fewer when narrow); .biz-grid adds nothing. */
.badge.featured {
    background: var(--surface);
    color: var(--text);
    border-width: 2px;
}

.badge.favorite {
    background: var(--surface);
    color: var(--text);
    font-weight: 600;
    border-color: var(--muted);
}

.biz-page h1 {
    font-size: 1.75rem;
}

/* The listing page's cover photo (1200:630, cropped by the image host) above the name, and the logo beside the
   name (ADR 0123). The attributes reserve both boxes before the pictures load. */
.biz-cover {
    display: block;
    width: 100%;
    height: auto;
    aspect-ratio: 1200 / 630;
    object-fit: cover;
    border-radius: var(--radius);
    margin: 0 0 1rem;
}

.biz-title {
    display: flex;
    align-items: center;
    gap: 0.75rem;
}

.biz-title h1 {
    margin: 0;
}

.biz-logo {
    flex: none;
    display: block;
    width: 4rem;
    height: 4rem;
    object-fit: contain;
    border-radius: var(--radius);
}

.biz-page h2 {
    font-size: 1.125rem;
    margin: 20px 0 6px;
    border-bottom: 1px solid var(--line);
}

.biz-page .description, .biz-page .summary {
    max-width: 42rem;
}

.biz-page .favorite-note {
    color: var(--muted);
    font-size: 0.875rem;
}

.biz-page .address {
    margin: 0 0 6px;
}

.contact-links {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 16px;
    margin: 0;
}

.contact-links a {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    min-width: 44px;
}

.hours-table {
    border-collapse: collapse;
    width: 100%;
    max-width: 28rem;
}

.hours-table th, .hours-table td {
    padding: 6px 8px;
    text-align: left;
    border-bottom: 1px solid var(--line);
    font-weight: inherit;
}

.hours-table tr.today {
    font-weight: 700;
    background: var(--surface);
}

.hours-table .today-mark {
    color: var(--muted);
    font-weight: 400;
}

/* ---- Business cards (ADR 0077): the events card shell (.event-card, .event-card-listing: border, picture, one-line
   title, italic line, a badge at the bottom right, hover), with the events cards' own rows. A Featured listing
   (li.is-featured) gets the events cards' red border, glow on hover and megaphone; a local favorite (.is-pick) the
   star and red border the events cards give an editor's pick. */

/* The business placeholder pictures (the li's biz-ph-N class, as the events cards' placeholder-N): square flat badges,
   one icon each, until the image flow gives a listing its own photo. */
.biz-ph-1 .img-placeholder {
    background-image: url("images/business-placeholder-1.af05f27effb6.svg");
}

.biz-ph-2 .img-placeholder {
    background-image: url("images/business-placeholder-2.b23ff0f73035.svg");
}

.biz-ph-3 .img-placeholder {
    background-image: url("images/business-placeholder-3.77062b2aa4aa.svg");
}

.biz-ph-4 .img-placeholder {
    background-image: url("images/business-placeholder-4.1282282bed94.svg");
}

.biz-ph-5 .img-placeholder {
    background-image: url("images/business-placeholder-5.ad3032586afe.svg");
}

.biz-ph-6 .img-placeholder {
    background-image: url("images/business-placeholder-6.f83392bee3f6.svg");
}

.biz-ph-7 .img-placeholder {
    background-image: url("images/business-placeholder-7.190055829d50.svg");
}

.biz-ph-8 .img-placeholder {
    background-image: url("images/business-placeholder-8.3eecd40aa59f.svg");
}

.biz-ph-9 .img-placeholder {
    background-image: url("images/business-placeholder-9.8cba08ddcb71.svg");
}

.biz-ph-10 .img-placeholder {
    background-image: url("images/business-placeholder-10.d44f6677d8e5.svg");
}

/* The list is shown by category: each group is an Ongoing-style section (its h2 is .ongoing h2) whose heading links to
   the category's page. */
.biz-section h2 a {
    color: inherit;
    text-decoration: none;
}

.biz-section h2 a:hover {
    text-decoration: underline;
}

/* Group headings take the events day headings' spacing (.day-heading: 24px above, 8px below). */
.biz-section h2 {
    margin: 24px 0 8px;
}

/* The results' own heading row (it carries the key when there is no Featured row) and the Newest Listings heading (a
   .related section, which is sized by .event-page on an event page and has no such wrapper here) are as large as the
   section headings. */
#results-heading,
#newest-heading {
    font-size: 1.3125rem;
}

/* Phones: the directory's Advanced filters stack in one column, so "Featured first" is never clipped. */
@media (max-width: 30rem) {
    #directory-search .advanced-fields {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* The badge in the card's bottom-right corner (the events cards' .card-extra place): a small pill, green for "Open now"
   and the Featured gold for "Opening soon"; both with their own background, so they read on any theme. */
.open-badge {
    display: inline-block;
    padding: 0 8px;
    border-radius: 999px;
    font-size: 0.75rem;
    font-weight: 700;
    line-height: 1.5;
    white-space: nowrap;
}

.open-badge.is-open {
    color: var(--open-now);
    background: var(--open-now-bg);
}

.open-badge.is-soon {
    color: var(--ink);
    background: var(--featured);
}

/* One centre line for the bottom marks: the badge, the Featured megaphone and the Local favorite star are all centred
   18px above the card's padding edge (the card leaves 12px under its last row: the badge's -3px bottom margin and its
   18px height put its centre there; the megaphone, 16px, sits at 10px and the star, 14px, at 11px). The events cards
   hide .card-extra on a phone, so a business card shows its badge there too, and its marks keep the same place at
   every width (these rules come after the events cards' own, phone ones included). */
.biz-card .card-extra {
    display: flex;
    align-items: center;
    margin-top: auto;
    margin-right: 0;
    margin-bottom: -3px;
    margin-left: auto;
    padding-top: 0;
}

.biz-card.event-card::before {
    bottom: 10px;
}

.biz-card.event-card.is-pick::after {
    bottom: 11px;
}

/* A taller card (its neighbour in the row is taller) keeps the badge at its bottom: the last row takes the extra
   height, and the badge sits at the end of it. */
.biz-card.event-card-listing {
    grid-template-rows: auto auto auto 1fr;
}

.is-featured .biz-card {
    border: 2px solid var(--burnt-red);
    box-shadow: 0 4px 6px -3px rgba(0, 0, 0, 0.25);
}

.is-featured .biz-card::before {
    content: "";
    position: absolute;
    right: 8px;
    width: 1rem;
    height: 1rem;
    background: url("images/megaphone.7b25fe88d257.svg") center / contain no-repeat;
    pointer-events: none;
}

.is-featured .biz-card .card-extra {
    padding-right: 1.5rem;
}

.is-featured .biz-card.is-pick {
    border-width: 3px;
}

.is-featured .biz-card.is-pick::after {
    right: 30px;
}

.is-featured .biz-card.is-pick .card-extra {
    padding-right: 2.75rem;
}

@media (hover: hover) and (min-width: 48rem) and (prefers-reduced-motion: no-preference) {
    .is-featured .biz-card:hover {
        transform: none;
        box-shadow: 0 0 8px 1px var(--burnt-red);
    }
}

/* ---- Neighborhood pages (ADR 0087): index groups, counts, event teasers, the page's sections */
.hood-group h2 {
    font-size: 1.125rem;
    margin: 20px 0 8px;
    border-bottom: 1px solid var(--line);
}

.hood-index {
    list-style: none;
    margin: 0;
    padding: 0;
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(16rem, 1fr));
    gap: 0 16px;
}

.hood-item {
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    padding-bottom: 8px;
    border-bottom: 1px solid var(--line);
}

.hood-link {
    display: inline-flex;
    align-items: center;
    min-height: 44px;
    min-width: 44px;
    font-weight: 600;
}

.hood-counts {
    color: var(--muted);
    font-size: 0.875rem;
}

.hood-page h2 {
    font-size: 1.125rem;
    margin: 20px 0 8px;
    border-bottom: 1px solid var(--line);
}

.teaser .event-title {
    margin: 0 0 4px;
    font-size: 1.0625rem;
}

/* ---- Public event submission form, clarity pass (ADR 0070 note, 2026-10-27) ----
   CSS only, no script. Browsers without :has() skip the whole @supports block and show every field,
   as before. A group is hidden only when its fields do not apply to what is chosen (the server
   ignores them anyway, SubmitEventForm._ignored; the new-venue fields are the one exception and
   the form refuses them with an error on the venue field, which keeps the group shown), and never
   while it holds an error. */
.submit-jump {
    margin: 0 0 16px;
    font-size: 0.9375rem;
}

.submit-form input[type="checkbox"], .submit-form input[type="radio"] {
    width: 1.25rem;
    height: 1.25rem;
    flex: none;
}

.submit-form label.choice {
    min-height: 44px;
}

.error-summary {
    margin: 0 0 20px;
    padding: 12px 14px;
    border: 2px solid #b91c1c;
    border-radius: 6px;
    background: var(--surface);
}

.error-summary h2 {
    margin: 0 0 4px;
    font-size: 1.125rem;
}

.error-summary p {
    margin: 0 0 8px;
}

.error-summary ul {
    margin: 0;
    padding-left: 1.25rem;
}

.error-summary a {
    font-weight: 700;
}

@supports selector(:has(*)) {
    .submit-form:not(:has(input[name="format"][value="multi_day"]:checked)) .only-multi-day:not(:has(.has-error)) {
        display: none;
    }

    .submit-form:not(:has(input[name="format"][value="recurring"]:checked)) .only-recurring:not(:has(.has-error)) {
        display: none;
    }

    /* the link to join online is always shown (greyed by submit_form.js until "This event is online only" is ticked; a normal
       field without script) and takes a star while that box is ticked */
    .submit-form:has(#venue_online_only:checked) .req-when-online,
    .submit-form:has(#venue_also_online:checked) .req-when-online {
        display: inline;
    }

    /* inside the repeat block: the days show once a pattern is chosen, the week of the month only for "Every month" */
    .submit-form:not(:has(select[name="pattern"] option:not([value=""]):checked)) .only-pattern:not(:has(.has-error)) {
        display: none;
    }

    .submit-form:not(:has(select[name="pattern"] option[value="monthly"]:checked)) .only-monthly:not(:has(.has-error)) {
        display: none;
    }

    .venue-group:not(:has(select[name="venue"] option[value="new"]:checked)):not(:has(.has-error)) .only-new-venue {
        display: none;
    }
}

/* --- Event photo on the submission form (ADR 0111). One isolated block: the design branch
   restyles the form, so keep this to the file input only. --- */
.submit-form input[type="file"] {
    display: block;
    max-width: 100%;
    font: inherit;
}

/* A fieldset defaults to min-width: min-content, and the file input's intrinsic width made this one 377px wide in a
   358px column (the page scrolled sideways at 390px, by 33px at 360px). Let it shrink to the column. */
.submit-form fieldset#photo {
    min-width: 0;
}

/* ---- Home cream sections (Latest newsletter, Latest stories, Events Calendar, Testimonials, the accordion, the
   subscribe band): .deco-card on the box (red top band and the menu bar's soft shadow). Remove the class in the
   block templates (cms/templates/cms/blocks/) to drop it. ---- */
.deco-card {
    border-top-left-radius: 0;
    border-top-right-radius: 0;
    box-shadow: var(--shadow-soft);
}

.deco-card::before {
    content: "";
    z-index: 1;
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    height: 4px;
    background: var(--burnt-red);
    pointer-events: none;
}

/* Washi tape on the Latest newsletter card and on each Latest stories card (on the cards, not the cream boxes): a
   small tilted translucent strip straddling the card's top edge, centred, each card at its own angle. Decorative
   only: no content, no clicks. */
.news-section .post-card {
    position: relative;
    --tape-angle: -3deg;
}

.stories-section .story-card:nth-child(1) { --tape-angle: 2.5deg; }
.stories-section .story-card:nth-child(2) { --tape-angle: -1.5deg; }
.stories-section .story-card:nth-child(3) { --tape-angle: 4deg; }

/* Hover and keyboard focus inside the card: the same small in-plane tilt and shadow as an event card (its own tilt
   values and --shadow-hover, 0.16s ease-out), but the card swings from its top centre, where the tape is, so the top
   barely moves and the bottom corners shift sideways. Transform and shadow only: no layout shift. Not with reduced
   motion. */
.news-section .post-card { --tilt: 0.8deg; }
.stories-section .story-card:nth-child(1) { --tilt: -0.5deg; }
.stories-section .story-card:nth-child(2) { --tilt: 0.8deg; }
.stories-section .story-card:nth-child(3) { --tilt: -0.9deg; }

@media (prefers-reduced-motion: no-preference) {
    .news-section .post-card,
    .stories-section .story-card {
        transform-origin: 50% 0;
        transition: transform 0.16s ease-out, box-shadow 0.16s ease-out;
    }

    .news-section .post-card:focus-within,
    .stories-section .story-card:focus-within {
        transform: rotate(var(--tilt, 0deg));
        box-shadow: var(--shadow-hover);
    }
}

@media (hover: hover) and (prefers-reduced-motion: no-preference) {
    .news-section .post-card:hover,
    .stories-section .story-card:hover {
        transform: rotate(var(--tilt, 0deg));
        box-shadow: var(--shadow-hover);
    }
}

/* A nod to print media at the foot of the Home page. In the white space above the footer: a six-step grey wedge and
   the brand name, on a desktop centred on the accordion's dropdown column (the right column of its two-column
   grid: 75% of the band less 4.5px, from the 17px border and padding and the 16px gap), on a phone centred on the
   page. At the very end of the page (inside the footer): the two bottom crop marks. All decoration (aria-hidden). */
.home-page .print-marks {
    --m: color-mix(in srgb, var(--text) 60%, transparent);
    position: relative;
    height: 0;
}

/* The strip is small: the last section's 16px bottom padding and the footer's 32px margin (the band itself takes no
   height; the wedge and its caption sit in the white, clear of the section's shadow). */
.home-page .pm-wrap {
    padding-top: 0;
    padding-bottom: 0;
}

.home-page .pm-wedge {
    position: absolute;
    top: -5px;
    left: 50%;
    width: 240px;
    margin-left: -120px;
    text-align: center;
}

@media (min-width: 38rem) {
    .home-page .pm-wedge {
        left: calc(75% - 4.5px);
    }
}

.home-page .pm-steps {
    display: block;
    position: relative;
    width: 146px;
    height: 16px;
    margin: 0 auto;
    background:
        radial-gradient(circle, var(--text) 0 7.5px, transparent 8px) 0 0 / 16px 16px no-repeat,
        radial-gradient(circle, color-mix(in srgb, var(--text) 80%, var(--page)) 0 7.5px, transparent 8px) 26px 0 / 16px 16px no-repeat,
        radial-gradient(circle, color-mix(in srgb, var(--text) 60%, var(--page)) 0 7.5px, transparent 8px) 52px 0 / 16px 16px no-repeat,
        radial-gradient(circle, color-mix(in srgb, var(--text) 40%, var(--page)) 0 7.5px, transparent 8px) 78px 0 / 16px 16px no-repeat,
        radial-gradient(circle, color-mix(in srgb, var(--text) 20%, var(--page)) 0 7.5px, transparent 8px) 104px 0 / 16px 16px no-repeat,
        radial-gradient(circle, var(--page) 0 6.7px, var(--m) 7px 8px, transparent 8.5px) 130px 0 / 16px 16px no-repeat;
}

.home-page .pm-caption {
    display: block;
    margin-top: 10px;
    font: 400 10.5px var(--font-mono);
    letter-spacing: 0.14em;
    text-transform: uppercase;
    color: var(--muted);
}

/* Vertical 18px dashes on the cream boxes' left and right outer edges and one at the page centre (not on a phone,
   where the wedge is there), all on the midline of the wedge and caption block (14px below the band's top).
   Decoration only. */
.home-page .pm-trim {
    position: absolute;
    left: 0;
    right: 0;
    top: 14px;
    height: 0;
    pointer-events: none;
}

.home-page .pm-trim::before {
    content: "";
    position: absolute;
    inset: -9px 0;
    background:
        linear-gradient(var(--m), var(--m)) left 0 top 0 / 1px 100% no-repeat,
        linear-gradient(var(--m), var(--m)) right 0 top 0 / 1px 100% no-repeat;
}

.home-page .pm-trim::after {
    content: "";
    position: absolute;
    left: 50%;
    top: -9px;
    width: 1px;
    height: 18px;
    margin-left: -0.5px;
    background: var(--m);
}

@media (max-width: 37.99rem) {
    .home-page .pm-trim::after {
        display: none;
    }
}

/* Home body copy a bit larger (the Home page only: .home-page is the main element's class from home_page.html):
   running text at --fs-body, secondary text at --fs-small, the smallest (the byline under a quote, the date
   badge) not below 13px. Headings, the event cards and every other page keep their sizes. */
.home-page .box-sub,
.home-page .post-text,
.home-page .accordion details p,
.home-page .band-text p {
    font-size: var(--fs-body);
    line-height: 1.55;
}

.home-page .news-note,
.home-page .story-sub {
    font-size: var(--fs-small);
    line-height: 1.5;
}

.home-page .quote-card {
    font-size: var(--fs-small);
    line-height: 1.5;
}

.home-page .quote-by {
    font-size: 0.8125rem;
    white-space: nowrap;  /* "Emily K." stays on one line */
}

.news-section .post-card::after,
.stories-section .story-card::after {
    content: "";
    position: absolute;
    top: -8px;
    left: 50%;
    width: 60px;
    height: 16px;
    transform: translateX(-50%) rotate(var(--tape-angle, -2deg));
    background: linear-gradient(180deg,
        color-mix(in srgb, var(--cream) 85%, transparent),
        color-mix(in srgb, var(--ink) 12%, var(--cream)));
    border: 1px solid color-mix(in srgb, var(--ink) 20%, transparent);
    clip-path: polygon(0 0, 100% 0, 98% 25%, 100% 50%, 98% 75%, 100% 100%, 0 100%, 2% 75%, 0 50%, 2% 25%);
    pointer-events: none;
    z-index: 2;
}

/* ---- Subscribe landing pages (newsletter/subscribe.html, subscribe_thanks.html, subscribe_unavailable.html) ----
   Brand-neutral structure only; every theme gives these classes its own look. The site header stays and the footer is
   not rendered (ADR 0118): the page is a flex column (a class on the body) so the main area fills the space under the
   header and its content is centred in that space.
   The logo, heading and copy are centred; the address field and the button are one joined box (a row from 36rem,
   stacked on a phone); the Turnstile widget (never restyled, only given room) is centred under the box. */
body.subscribe-page {
    display: flex;
    flex-direction: column;
    min-height: 100vh;
    min-height: 100dvh;
}

.subscribe-main {
    flex: 1 0 auto;
    box-sizing: border-box;
    width: 100%;
    max-width: none;
    margin: 0;
    padding: 2.5rem 16px;
    display: flex;
    align-items: center;
    justify-content: center;
}

.subscribe-landing {
    width: 100%;
    max-width: 34rem;
    text-align: center;
}

.subscribe-landing .landing-logo {
    display: block;
    max-width: 100%;
    height: auto;
    margin: 0 auto 1.25rem;
}

.subscribe-landing .landing-title {
    margin: 0 0 0.75rem;
    line-height: 1.15;
    text-wrap: balance;
}

.subscribe-landing .landing-tagline,
.subscribe-landing .landing-reassure {
    margin: 0 auto 0.75rem;
    max-width: 28rem;
    font-size: 1.125rem;
    line-height: 1.35;
    text-wrap: balance;
}

.subscribe-landing .landing-reassure {
    margin-bottom: 1.5rem;
}

.subscribe-landing .banner {
    margin: 0 0 1rem;
    text-align: left;
}

.subscribe-landing .landing-actions,
.subscribe-landing .landing-link {
    margin: 1rem 0 0;
}

/* The action buttons of the thanks and unavailable pages: stacked full width on a phone, side by side and centred
   from 36rem. Every target is at least 44px high and has a visible focus ring in the button colour. */
.subscribe-landing .landing-actions {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 12px;
}

@media (min-width: 36rem) {
    .subscribe-landing .landing-actions {
        flex-direction: row;
        justify-content: center;
        align-items: center;
    }
}

.subscribe-landing .landing-actions .btn {
    min-height: 44px;
    box-sizing: border-box;
    text-align: center;
}

.subscribe-landing .landing-actions .btn:focus-visible {
    outline: 3px solid var(--btn-bg);
    outline-offset: 3px;
}

.subscribe-form .join-box {
    display: flex;
    flex-direction: column;
    gap: 6px;
    padding: 6px;
    text-align: left;
}

.subscribe-form .join-box .field {
    flex: 1 1 auto;
    margin: 0;
}

.subscribe-form .join-box input[type="email"] {
    display: block;
    box-sizing: border-box;
    width: 100%;
    max-width: none;
    min-height: 44px;
}

.subscribe-form .join-box .btn {
    flex: 0 0 auto;
    white-space: nowrap;
}

@media (min-width: 36rem) {
    .subscribe-form .join-box {
        flex-direction: row;
        align-items: stretch;
    }
}

.subscribe-form input[type="email"]::placeholder {
    text-transform: uppercase;
    letter-spacing: 0.03em;
}

.subscribe-form .error {
    margin: 0.5rem 0 0;
    text-align: center;
}

.subscribe-form .cf-turnstile {
    display: flex;
    justify-content: center;
    min-height: 65px;
    margin: 1rem 0 0;
}

.subscribe-form .hint {
    max-width: 30rem;
    margin: 1rem auto 0;
    text-align: center;
}

/* ---- The public event form: one box (Event Submission) with five sub-headings, and a hint under each header ----
   Brand-neutral structure; the colours come from the theme's section variables and the themes restyle the box.
   Fields that sit well side by side (dates, name and email, organizer) are in a `.field-row`. A field's order
   on the page is its reading order: label, hint, control, error. */
.form-heading {
    margin: 24px 0 12px;
    font-size: 1.375rem;
}

.form-boxes {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 20px;
    align-items: start;
    margin: 0 0 20px;
}

/* From 64rem each box is full width and its fields are laid out in two equal columns (a grid, row by row, so the
   reading and tab order stay the page order): related fields pair up, and the wide ones (the categories, the
   one-time / several days / repeats choice and its extra fields) span both columns. `.field-row` wrappers dissolve
   so their fields become grid cells. A cell's control sits at the bottom of the cell, so the two controls of a pair
   line up even when their hints are different lengths. */
@media (min-width: 64rem) {
    .form-box-body {
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 32px;
    }

    .form-box-body > .field-row {
        display: contents;
    }

    /* the top block spans both columns and is laid out in three rows (see change 76 below): the second row starts at one height
       for both sides, so the venue's header sits on the summary's baseline. The open categories panel and the venue
       suggestions float without changing a row. */
    .form-box-body > .form-top {
        grid-column: 1 / -1;
        display: grid;
        grid-template-columns: repeat(2, minmax(0, 1fr));
        column-gap: 32px;
        align-items: start;
    }

    /* Changes 76, 77: the block is one flat list in column order (name, summary, categories, then event website, venue with its
       ticks and the typed-venue note, link to join online) and the grid has three rows and fills them column by column, so no
       cell is placed by hand and the rows line up: name | event website, summary | venue, categories | link to join online.
       Below 64rem the same order stacks (the whole left column, then the whole right column). The tab order follows. */
    .form-top {
        grid-template-rows: repeat(3, auto);
        grid-auto-flow: column;
    }

    .form-box-body > .form-divider {
        grid-column: 1 / -1;
    }

    /* the two fields of a pair (first day | starts at, your name | your email, ends at | highest price) keep their controls
       level when one hint is longer than the other */
    .form-box-body > .field-row > .field:not(.choices) {
        display: flex;
        flex-direction: column;
    }

    .form-box-body > .field-row > .field > input:not([type="checkbox"]):not([type="radio"]),
    .form-box-body > .field-row > .field > select,
    .form-box-body > .field-row > .field > textarea {
        margin-top: auto;
    }

    /* Contact Info: your name has a character counter under its box and your email has not, so their boxes are lined up from the
       top (label, then box, in both) instead of from the bottom of the cell, which put the email box one counter lower */
    .form-box-body > .field-row.contact-row > .field > input:not([type="checkbox"]):not([type="radio"]) {
        margin-top: 0;
    }

    /* the free tick sits level with the price field beside it */
    .form-box-body > .field:has(> label.choice) {
        align-self: end;
    }
}

.form-box {
    min-width: 0;
    background: var(--section-bg);
    border: var(--section-border);
    border-radius: 6px;
}

.form-box-wide {
    margin: 0 0 20px;
}

.form-box-title {
    margin: 0;
    padding: 10px 16px;
    font: 700 1.0625rem/1.3 var(--font-heading);
    border-bottom: var(--section-border);
    border-radius: 5px 5px 0 0;
    background: color-mix(in srgb, var(--section-bg) 90%, var(--text));
}

.form-box-body {
    padding: 16px 16px 6px;
}

.field-row {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(min(100%, 12rem), 1fr));
    gap: 0 16px;
}

.field-row > .field {
    min-width: 0;
}

.form-box fieldset {
    min-width: 0;
}

/* a group of choices inside a box is flat: no outline, and its legend reads like a field's label */
.form-box .field {
    background: none;
}

.form-box .field.choices legend {
    padding: 0;
    margin-bottom: 2px;
    font: 400 0.9375rem var(--font-body);
}

.form-box fieldset#photo {
    margin: 0 0 12px;
    padding: 0;
    border: 0;
    background: none;
    box-shadow: none;
}

/* the flyer block's legend reads exactly like a field's label (the Ticket price label beside it): the body font, the label's size,
   weight (inherited) and line height, and the label's 4px gap below */
.form-box fieldset#photo legend {
    padding: 0;
    margin-bottom: 4px;
    font: inherit;
    font-size: 0.9375rem;
}

.submit-form .req {
    color: var(--burnt-red);
    font-weight: 700;
}

/* label, then the hint a little closer, then the control a little further */
.submit-form .field > label + .hint {
    margin-top: -2px;
}

.submit-form .field > .hint {
    margin-bottom: 8px;
}

.submit-form .field > .hint + .hint {
    margin-top: -4px;
}

.form-consent {
    margin: 0 0 12px;
}

/* Change 80: the contact notice and the two tick boxes under it (the agreement and the optional marketing box). The wording is the
   same at every width; on a narrow screen a longer line wraps in balanced halves instead of leaving a short last line, and the
   notice sits close above the boxes. */
.form-consent > .hint {
    margin: 0 0 4px;
    text-wrap: balance;
}

/* Change 82: in the stacked layout (below 64rem, where the form's columns stack) the contact notice is centred; the two tick boxes
   under it keep their left alignment, and desktop is unchanged. */
@media (max-width: 63.99rem) {
    .form-consent > .hint {
        text-align: center;
    }
}

.form-consent .field {
    margin-top: 0;
    margin-bottom: 0;
}

.form-consent label.choice > span {
    text-wrap: balance;
}

@media (max-width: 47.99rem) {
    .form-box-body {
        padding: 14px 12px 4px;
    }
}

/* The first lines of the event form sit close together: the heading, the introduction and the "* required" legend, then
   the first box (its title bar carries the "About the event" heading). */
p.submit-intro {
    margin-bottom: 4px;
}

p.submit-legend {
    margin: 0 0 14px;
}

p.submit-brand {
    margin: 0 0 8px;
}

.form-box-sub {
    font-weight: 400;
    opacity: 0.8;
}

/* The live character counter under a free-text field of the event form (submit_form.js creates it; without script it is
   not there). Right-aligned, small, muted; the warning colour when the field is under its minimum (after the visitor has
   typed or left it) or has reached its maximum. The line is reserved so the form does not jump as the count changes. */
.char-count {
    min-height: 1.25em;
    margin: 2px 0 0;
    text-align: right;
    font-size: 0.8125rem;
    color: var(--muted);
}

.char-count.is-low,
.char-count.is-over {
    color: var(--burnt-red);
    font-weight: 700;
}

/* The divider under the top block of the Required box: a plain decorative rule (an empty element hidden from assistive
   technology, the border is all there is to it) across both columns. */
/* Event Pricing (change 41): on the left the ticket price, a short box, with the free tick right beside it on the same row;
   on the right (from 64rem; below the fields on a narrower screen) the preview of the level visitors will see. The price
   field's own wrapper dissolves so its label, hints, box and error are cells of one grid: the box in the first column, the
   tick in the second, on the box's row. */
.price-block {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 4px 32px;
    margin: 0 0 12px;
}

@media (min-width: 64rem) {
    .price-block {
        grid-template-columns: repeat(2, minmax(0, 1fr));
    }
}

.price-fields {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    column-gap: 16px;
    align-content: start;
}

.price-fields > .field:first-child {
    display: contents;
}

.price-fields > .field:first-child > label,
.price-fields > .field:first-child > .hint,
.price-fields > .field:first-child > .error {
    grid-column: 1 / -1;
}

.price-fields > .field:first-child > input {
    grid-column: 1;
    grid-row: 4;
    width: calc(10ch + 24px);
    max-width: 100%;
    margin-bottom: 12px;
}

.price-fields > .field:first-child > .error {
    grid-row: 5;
}

.price-fields > .field:has(> label.choice) {
    grid-column: 2;
    grid-row: 4;
    align-self: start;
    margin: 0;
}

/* the preview box: heading, one sentence of explanation, the level (made by submit_form.js) */
.price-preview {
    align-self: start;
    padding: 12px 16px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--page);
}

.price-preview-title {
    margin: 0 0 4px;
    font: 700 1rem/1.3 var(--font-heading);
}

.price-preview .hint {
    margin: 0 0 8px;
}

.price-preview-value {
    margin: 0;
    min-height: 1.8rem;
    font: 700 1.5rem/1.2 var(--font-heading);
}

.price-preview-value.is-empty {
    color: var(--muted);
}

/* Event Flyer & Pricing (only when the image store is on: .price-block.has-flyer). The flyer / photo block
   (events/_submit_photo.html, one self-contained block: move it by moving its include) is the FIRST child, so on a phone it
   comes first, then the price fields, then the preview. From 64rem it is the LEFT column, spanning both rows; the ticket price
   and the tick are on the right, with the preview under them. */
.price-block.has-flyer > .flyer-block {
    margin-bottom: 16px;
}

@media (min-width: 64rem) {
    .price-block.has-flyer {
        grid-template-rows: auto 1fr;
    }

    .price-block.has-flyer > .flyer-block {
        grid-column: 1;
        grid-row: 1 / span 2;
        margin-bottom: 0;
    }

    .price-block.has-flyer > .price-fields {
        grid-column: 2;
        grid-row: 1;
    }

    .price-block.has-flyer > .price-preview {
        grid-column: 2;
        grid-row: 2;
    }
}

/* The picker (made by submit_form.js: .js-flyer on the block; without script the plain native file input shows, with its
   label above it). The real input stays in the page, focusable, only visually hidden; its label is the large button (the
   site's .btn / .btn-secondary look, at least 48px high, full width) and shows the focus ring when the input has focus
   from the keyboard. The thumbnail is a small data: image (the page's CSP allows no other source). */
.flyer-pick {
    position: relative;
}

/* the line under the legend sits as close as a field's hint sits under its label */
.flyer-block > legend + .hint {
    margin-top: -2px;
    margin-bottom: 8px;
}

.flyer-block.js-flyer .flyer-input {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    opacity: 0;
}

.submit-form .flyer-block .flyer-button {
    display: flex;
    box-sizing: border-box;
    width: 100%;
    min-height: 48px;
    margin: 4px 0 8px;
    text-align: center;
}

.flyer-button.is-focus {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

.flyer-preview {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 8px 12px;
    margin: 8px 0;
    padding: 10px 12px;
    border: 1px solid var(--line);
    border-radius: 6px;
    background: var(--page);
}

.flyer-preview[hidden],
.flyer-thumb[hidden],
.flyer-message[hidden],
.flyer-details[hidden] {
    display: none;
}

.flyer-thumb {
    display: block;
    width: auto;
    height: auto;
    max-width: 120px;
    max-height: 120px;
    border: 1px solid var(--line);
    border-radius: 4px;
    background: #fff;
    object-fit: contain;
}

.flyer-file {
    flex: 1 1 8rem;
    min-width: 0;
    margin: 0;
    font-size: 0.9375rem;
    overflow-wrap: anywhere;
}

.flyer-name {
    font-weight: 700;
    unicode-bidi: isolate;   /* with dir="auto": a right-to-left file name cannot reorder the extension next to it */
}

.flyer-size {
    color: var(--muted);
}

.flyer-remove {
    flex: 0 0 auto;
}

.form-divider {
    grid-column: 1 / -1;
    height: 0;
    margin: 6px 0 18px;
    border-top: 1px solid var(--line);
}

/* Natural dates (change 63; made by submit_form.js, so none of this exists without script): a text box that reads typed dates
   next to the calendar button, the real date input kept out of sight in the same place (it is where the calendar opens),
   and one reserved line under them that echoes the reading in full. The box and the button together are as wide as the date
   input they stand in for, and the echo adds nothing to the width of its column (zero width, stretched to the column;
   an error line wraps instead). */
.date-entry {
    position: relative;
    display: flex;
    align-items: center;
    gap: 4px;
}

.submit-form .date-entry .date-text {
    width: calc(9ch + 22px);
    min-width: 0;
    max-width: 100%;
}

.date-cal {
    flex: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    padding: 0;
    color: var(--text);
    background: var(--page);
    border: 1px solid var(--line);
    border-radius: 4px;
    cursor: pointer;
}

.date-cal:hover {
    border-color: var(--text);
}

.date-cal:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 1px;
}

.date-cal[hidden] {
    display: none;
}

/* Change 66: the date fields are the browser's own inputs again, with the Open calendar button beside them (made by
   submit_form.js). The browser's built-in calendar icon would double that button, so it is hidden here, and only here: a date
   input with no button (no script, or a browser with no showPicker) keeps its icon. The box is as wide as its text needs. */
@supports selector(::-webkit-calendar-picker-indicator) {   /* Chrome, Edge, Safari: the icon can be hidden; Firefox keeps its own icon and width */
    .submit-form .date-entry input[type="date"] {
        width: calc(10ch + 24px);
        min-width: 0;
        max-width: 100%;
    }

    .submit-form .date-entry input[type="date"]::-webkit-calendar-picker-indicator {
        display: none;
    }
}

/* The real time input stays in the page as the posted field and as the anchor of the browser's own picker. It is one invisible pixel
   (no border, nothing painted), at the left edge under the text box, so the picker the clock button opens hangs under the text box
   rather than at the far corner of the button, where it looked like a second bubble beside the clock. */
.submit-form .date-entry .date-native {
    position: absolute;
    left: 0;
    bottom: 0;
    width: 1px;
    height: 1px;
    min-width: 0;
    margin: 0;
    padding: 0;
    border: 0;
    overflow: hidden;
    clip-path: inset(50%);
    opacity: 0;
    pointer-events: none;
}

.date-echo {
    width: 0;
    min-width: 100%;
    min-height: 1.4em;
    margin: 2px 0 0;
    color: var(--muted);
    font-size: 0.8125rem;
    line-height: 1.4;   /* the same as the reserved min-height, so a line of text does not change the height */
    white-space: nowrap;
}

.date-echo.is-error {
    color: #b91c1c;
    font-weight: 700;
    white-space: normal;
}

/* Date and time controls are only as wide as their format needs (the field itself keeps its label and hint). The width
   is the text (mm/dd/yyyy, --:-- --) plus the control's padding and the native picker icon. */
.submit-form input[type="date"] {
    width: calc(10ch + 56px);
    max-width: 100%;
}

.submit-form input[type="time"] {
    width: calc(8ch + 66px);   /* a few pixels more than the date box needs: "07:00 PM" no longer touches the clock icon (Cary) */
    max-width: 100%;
}

/* ---- The categories picker on the event form: a native <details> around the real checkboxes ----
   The summary looks like a select box (the chosen labels as chips, "2 of 3", a chevron); the panel is a floating list
   under it that overlays the fields below while open. Without script it still opens and closes and the boxes work as
   plain checkboxes; submit_form.js adds the chips, the limit, the Escape / outside-click / Done closing. */
.multi-select {
    position: relative;
}

.multi-select > summary {
    display: flex;
    align-items: center;
    gap: 10px;
    min-height: 44px;
    padding: 4px 10px;
    color: var(--text);
    background: var(--page);
    border: 1px solid var(--line);
    border-radius: 4px;
    cursor: pointer;
    list-style: none;
}

.multi-select > summary::-webkit-details-marker {
    display: none;
}

.multi-select > summary::after {
    content: "";
    flex: none;
    width: 0.5rem;
    height: 0.5rem;
    margin: -4px 4px 0 0;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
}

.multi-select[open] > summary::after {
    margin-top: 4px;
    transform: rotate(-135deg);
}

.multi-select > summary:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 2px;
}

.multi-select-value {
    flex: 1 1 auto;
    min-width: 0;
    color: var(--muted);
}

.multi-select-count {
    flex: none;
    font-size: 0.8125rem;
    color: var(--muted);
}

.multi-select .chip {
    display: inline-block;
    margin: 2px 4px 2px 0;
    padding: 0 8px;
    font-size: 0.8125rem;
    line-height: 1.7;
    color: var(--text);
    background: var(--tan, var(--surface));
    border: 1px solid var(--line);
    border-radius: 3px;
}

.multi-select-panel {
    position: absolute;
    z-index: 30;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    box-sizing: border-box;
    max-height: min(70vh, 24rem);
    overflow-y: auto;
    padding: 8px 12px 12px;
    background: var(--surface);
    border: 1px solid var(--text);
    border-radius: 6px;
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.18);
}

/* ---- The venue type-ahead (submit_form.js): a text box that drives the real <select name="venue"> ----
   Without script none of this exists and the select shows. With it the select is hidden (it stays in the page and is
   what is posted), the box shows the venue's name, and a list of at most ten matches floats under the box over the
   fields below it (it takes no room, as the categories panel does). A venue that is not listed needs only its name,
   which the box already holds, so the typed-name field and its sentence are hidden unless the name has an error. */
.venue-select-hidden {
    display: none;
}

/* Change 73: the two ticks under the venue box ("ONLY online" and "hybrid") sit on one row when they fit, else stack */
.venue-ticks {
    display: flex;
    flex-wrap: wrap;
    gap: 4px 24px;
}

.venue-group.is-typeahead .only-new-venue > .hint,
.venue-group.is-typeahead .only-new-venue > .field:has(input[name="new_venue_name"]):not(.has-error) {
    display: none;
}

/* Change 70: with script the website field of a venue that is not listed is shown only once the script has decided the typed
   venue is really not listed (class link-shown on the group, set by submit_form.js), or when it holds an error; the script's own
   sentence above it ("Venue is not on our list (yet), please confirm details below.", in the counter's red) shows with it. It fades in as the date fields do, only when it appears because of
   what the visitor typed (class link-just-shown), never on page load. */
.venue-group.is-typeahead:not(.link-shown) .only-new-venue:not(:has(.has-error)) {
    display: none;
}

.venue-group.is-typeahead.link-shown .only-new-venue > .hint {
    display: block;
    color: var(--burnt-red);   /* change 72: the same red as the character counter's warning (the Cary theme sets its own) */
}

@media (prefers-reduced-motion: no-preference) {
    .venue-group .only-new-venue.link-just-shown {
        animation: date-reveal 200ms ease-out;
    }
}

.venue-combo {
    position: relative;
}

/* the star the online link takes on while that box is ticked (shown by the :has() block above) */
.req-when-online {
    display: none;
}

.venue-combo-list {
    position: absolute;
    z-index: 30;
    top: calc(100% + 4px);
    left: 0;
    right: 0;
    box-sizing: border-box;
    max-height: min(70vh, 24rem);
    margin: 0;
    padding: 4px 0;
    overflow-y: auto;
    list-style: none;
    background: var(--surface);
    border: 1px solid var(--text);
    border-radius: 6px;
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.18);
}

.venue-combo-list[hidden] {
    display: none;
}

.venue-combo-option {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    column-gap: 8px;
    min-height: 44px;
    box-sizing: border-box;
    padding: 4px 12px;
    cursor: pointer;
}

.venue-combo-option.is-active {
    background: color-mix(in srgb, var(--accent) 14%, var(--surface));
    outline: 3px solid var(--accent);
    outline-offset: -3px;
}

.venue-combo-city {
    color: var(--muted);
    font-size: 0.875rem;
}

.multi-select-panel .choice-list {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));
    gap: 0 12px;
}

.multi-select-panel .choice:has(input:disabled) {
    opacity: 0.5;
    cursor: not-allowed;
}

.multi-select-note {
    min-height: 1.25em;
    margin: 6px 0 0;
    font-size: 0.875rem;
    color: var(--muted);
}

.multi-select-done {
    min-height: 44px;
    margin-top: 8px;
    padding: 0 20px;
    font: 700 var(--fs-btn)/1.2 var(--font-heading);
    letter-spacing: 0.04em;
    text-transform: var(--btn-transform);
    color: var(--btn-text);
    background: var(--btn-bg);
    border: 1px solid var(--btn-bg);
    border-radius: 3px;
    cursor: pointer;
}

/* the picker's removable chips (made by submit_form.js) */

button.chip {
    font-family: inherit;
    cursor: pointer;
}

button.chip:hover {
    border-color: var(--text);
}

button.chip:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: 1px;
}

/* The first day's label reads for the answer to "How often does it happen?": "Date" (once), "First day" (several days in
   a row and repeats, also what a browser without :has() shows). Same CSS-keyed-on-the-ticked-radio
   mechanism as the show/hide of the extra fields above; no script. */
.submit-form .label-once,
.submit-form .label-repeat {
    display: none;
}

@supports selector(:has(*)) {
    .submit-form:has(input[name="format"][value="one_time"]:checked) .label-once,
    .submit-form:has(input[name="format"][value="recurring"]:checked) .label-repeat {
        display: inline;
    }

    .submit-form:has(input[name="format"][value="one_time"]:checked) .label-multi,
    .submit-form:has(input[name="format"][value="recurring"]:checked) .label-multi {
        display: none;
    }
}

/* ---- The date section of the Required box: a heading and ONE row of every date question ----
   "How often does it happen?" is a column of three stacked radios on the left; every other item sits in a wrapping area
   to its right. Each item has its header and hint above its control. Headers share the top of the row and the controls
   the bottom of their line (an item is a column that pushes its control down), so headers and inputs both line up
   whatever the hints' lengths, and the first radio is level with the controls. The area wraps where it does not fit,
   and below 40rem everything stacks in the same order. "Several days in a row" adds the last day between the first day
   and the start time, "Repeats" adds its fields at the end of the area. */
.form-section-title {
    grid-column: 1 / -1;
    margin: 0 0 12px;
    font: 700 1.0625rem/1.3 var(--font-heading);
}

/* Centred sub-headings (About the Event, Date & Time, Contact Info): the title sits in the middle of a rule that runs out on
   both sides of it, and that rule takes the place of the plain divider that used to sit above it (the divider is hidden
   when a heading follows it; the heading carries the same space above). Without :has() support both show. */
.form-section-title {
    display: flex;
    align-items: center;
    gap: 14px;
    margin-top: 25px;
    text-align: center;
}

.form-box-body > .form-section-title:first-child {
    margin-top: 0;
}

.form-section-title::before,
.form-section-title::after {
    content: "";
    flex: 1 1 0;
    border-top: 1px solid var(--line);
}

.form-divider:has(+ .form-section-title) {
    display: none;
}

/* Progressive sections (change 49; submit_form.js adds .js-sections to the form and the classes below, so without script none of
   this applies and every section is open). A section that is not open yet shows only its heading, muted, with a short note;
   its content is hidden and inert. When it opens the content fades in like the other changing fields, unless the visitor asks
   for less motion. */
.js-sections .section-locked-item,
.js-sections .section-collapsed-item {
    display: none !important;
}

.form-section-title.is-locked {
    color: var(--muted);
}

/* the chevron button on the heading line of a section that is not open yet: a 44px target that adds no height to the line
   (negative margins), a small chevron pointing down (shown but locked: up) */
/* Change 54: the chevron button sits at the far right end of the heading line, over the rule (its box fill cuts the rule there, so
   it reads as an icon at the end of the line), vertically centred and out of the flow, so the heading text stays exactly
   centred between the two rules. */
.form-section-title {
    position: relative;
}

.section-toggle {
    position: absolute;
    top: 50%;
    right: 0;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin: 0;
    padding: 0;
    color: inherit;
    background: var(--section-bg);
    border: 0;
    border-radius: 50%;
    cursor: pointer;
}

.section-toggle:focus-visible {
    outline: 3px solid var(--accent);
    outline-offset: -2px;
}

.section-chevron {
    width: 9px;
    height: 9px;
    margin-top: -4px;
    border-right: 2px solid currentColor;
    border-bottom: 2px solid currentColor;
    transform: rotate(45deg);
}

.section-toggle[aria-expanded="true"] .section-chevron {
    margin-top: 4px;
    transform: rotate(-135deg);
}

/* ONE disabled look for every inactive box of the event form (change 55, after the venue box when "online only" is ticked: the
   box keeps its own fill, border and text and simply goes light, with the not-allowed cursor where the pointer can reach it).
   It serves the venue box, every box in a locked section the visitor has opened to look at (inert: nothing in it can be
   focused, typed in, ticked or pressed), and the link to join online while "online only" is not ticked. Only the controls
   and previews are lightened, never the labels and hints, which stay readable (muted). The strength is one token. */
.submit-form {
    --inactive-opacity: 0.55;
}

.venue-combo > input:disabled,
.js-sections .online-greyed :is(input, .req-when-online),
.js-sections .section-peek :is(input, select, textarea, .multi-select > summary, .chip, .price-preview, .venue-combo-list, .date-cal, .flyer-button, .flyer-preview) {
    opacity: var(--inactive-opacity);
    cursor: not-allowed;
}

.js-sections .section-peek,
.js-sections .online-greyed {
    user-select: none;
}

.js-sections .section-peek :is(label, legend, .hint, .req, .section-chevron),
.js-sections .online-greyed :is(label, .hint) {
    color: var(--muted);
}

.section-lock-hint {
    grid-column: 1 / -1;
    margin: -8px 0 12px;
    color: var(--burnt-red);   /* the form's error red (the character counter's warning colour); the Cary theme sets its own */
    font-size: 0.875rem;
    text-align: center;
}

@media (prefers-reduced-motion: no-preference) {
    .section-just-opened {
        animation: date-reveal 200ms ease-out;
    }
}

/* the page header and the box headings of the event form are centred; fields, labels and hints are not */
.submit-title,
p.submit-intro,
p.submit-legend,
.form-box-title {
    text-align: center;
}

.form-date-row {
    grid-column: 1 / -1;
    display: flex;
    flex-wrap: wrap;
    align-items: flex-start;
    gap: 12px 24px;
    margin: 0 0 12px;
}

/* the rest of the row (every item after the radios) is its own wrapping area to the right of them. Its items are as wide as
   their one-line subtitle, sit at the top of their line, and (from 40rem) keep that subtitle on one line, so every header
   has the same height and the controls of a line are level; the repeat fields wrap inside it without ever dropping
   below the stacked radios. */
/* Change 59: the fields are a small grid of three rows. Row 1: the first day and the end field ("Last day" / "Repeats until"; nothing
   for Once). Row 2: the start time under the first day and the end time under the end field. Row 3 (Repeats only): how it
   repeats, the days and the week of the month. Below 40rem it is one column in that same order. */
.form-date-rest {
    flex: 1 1 20rem;
    min-width: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    align-items: start;
    gap: 12px 46px;
}

@media (min-width: 40rem) {
    .form-date-rest {
        grid-template-columns: max-content max-content minmax(0, 1fr);   /* the third, flexible track takes the width of the third row so it does not stretch the two columns */
        justify-content: start;
    }

    .form-date-rest > .repeat-row {
        grid-column: 1 / -1;
    }
}

/* Below 64rem (no room for the wide grid below) the date columns sit a little closer, so the area stays inside its box at 768px. */
@media (min-width: 40rem) and (max-width: 63.99rem) {
    .form-date-rest {
        column-gap: 20px;
    }
}

.form-date-rest > .field,
.form-date-rest > .only-multi-day > .field,
.form-date-rest > .repeat-end > .field,
.form-date-rest > .repeat-row > .field,
.form-date-rest > .repeat-row > .only-pattern > .field,
.form-date-rest > .repeat-row > .only-monthly > .field {
    min-width: 0;
    margin: 0;
    max-width: 100%;
}

@media (min-width: 40rem) {
    .form-date-rest > .field > .hint,
    .form-date-rest > .only-multi-day > .field > .hint,
    .form-date-rest > .repeat-end > .field > .hint,
    .form-date-rest > .repeat-row > .field > .hint {
        white-space: nowrap;
    }
}

/* "How often does it happen?": its three answers are stacked, one under the other, in a column only as wide as the longest
   answer. Its subtitle (a hint line, like the neighbours' hints) sits above the first answer, so the first answer's row
   is level with the date and time boxes beside it; the other two hang below it. */
.form-date-row > #id_format {
    flex: 0 0 auto;
    margin: 0;
}

.form-date-row > #id_format .choice-list {
    flex-direction: column;
    flex-wrap: nowrap;
    gap: 0;
}

/* The ticked answer reads as active: its words are bold. The width of the bold words is reserved by a hidden copy of the
   text (the span's data-text, drawn bold and invisible under the words), so ticking another answer moves nothing. */
.form-date-row > #id_format label.choice > span {
    display: inline-flex;
    flex-direction: column;
}

.form-date-row > #id_format label.choice > span::after {
    content: attr(data-text);
    height: 0;
    overflow: hidden;
    visibility: hidden;
    font-weight: 700;
}

.form-date-row > #id_format label.choice:has(input:checked) > span {
    font-weight: 700;
}


/* A cue that the fields changed with the answer: what appears (or is swapped in) fades in and settles up from 3px below
   in 200 ms. CSS only. The rules apply only while the focus is in the radios (or, for the fields that depend on how it
   repeats, in that list), so nothing animates when the page loads, even with an answer already ticked (an error page);
   the limit is that tabbing into the group, or clicking the answer already ticked, plays the same short cue once on what
   is shown. Nothing animates for visitors who ask for less motion. */
@keyframes date-reveal {
    from {
        opacity: 0.45;
        transform: translateY(3px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@media (prefers-reduced-motion: no-preference) {
    .submit-form:has(input[name="format"]:focus) .only-multi-day,
    .submit-form:has(input[name="format"]:focus) .only-recurring,
    .submit-form:has(input[name="format"]:focus) .label-once,
    .submit-form:has(input[name="format"]:focus) .label-multi,
    .submit-form:has(input[name="format"]:focus) .label-repeat,
    .submit-form:has(select[name="pattern"]:focus) .only-pattern,
    .submit-form:has(select[name="pattern"]:focus) .only-monthly,
    .submit-form:has(select[name="pattern"]:focus) .hint-default,
    .submit-form:has(select[name="pattern"]:focus) .hint-monthly {
        animation: date-reveal 200ms ease-out;
    }
}

/* "Several days in a row": the last day is one more item of the row; the wrapper keeps the show/hide rule above (hidden
   unless that answer is ticked, or it holds an error) */
.form-date-rest > .only-multi-day {
    max-width: 100%;
}

/* "Repeats": "Repeats until" is one more item of the first line, where "Last day" sits for several days in a row (the
   wrapper keeps the show/hide rule above). The rest is a second line of its own, only for Repeats: how it repeats, the days
   (a picker like the categories one) and the week of the month side by side, then the live sentence under them. The three
   stretch to the height of the line, so their headers share the top and their controls the bottom, whatever the hints' length. */
.form-date-rest > .repeat-end,
.form-date-rest > .only-multi-day {
    max-width: 100%;
}

/* The end field takes the second column of the first row (change 59: it used to sit between the first day and the start time,
   with margins that made two equal gaps; now there is one gap, the column gap, 46px as before), and the start and end time
   take the two columns of the second row. */
@media (min-width: 40rem) {
    .form-date-rest > .field:nth-child(1) {
        grid-column: 1;
        grid-row: 1;
    }

    .form-date-rest > .repeat-end,
    .form-date-rest > .only-multi-day {
        grid-column: 2;
        grid-row: 1;
    }

    .form-date-rest > .field:has(#id_start_time) {
        grid-column: 1;
        grid-row: 2;
    }

    .form-date-rest > .field:has(#id_end_time) {
        grid-column: 2;
        grid-row: 2;
    }

    .form-date-rest > .repeat-row {
        grid-row: 3;
    }
}

.form-date-rest > .repeat-row {
    min-width: 0;
    display: flex;
    flex-wrap: wrap;
    align-items: stretch;
    gap: 12px 24px;
}

.form-date-rest > .repeat-row > .field:not(.choices),
.form-date-rest > .repeat-row > .only-monthly > .field {
    display: flex;
    flex-direction: column;
}

.form-date-rest > .repeat-row > .field:not(.choices) {
    flex: 0 1 14rem;
}

.form-date-rest > .repeat-row > .only-pattern {
    display: flex;
    flex: 0 1 17rem;
    min-width: 0;
}

.form-date-rest > .repeat-row > .only-monthly {
    display: flex;
    flex: 0 1 14rem;
    min-width: 0;
}

.form-date-rest > .repeat-row > .only-pattern > .field {
    display: flex;
    flex: 1;
    flex-direction: column;
}

.form-date-rest > .repeat-row > .only-monthly > .field {
    flex: 1;
}

.form-date-rest > .repeat-row > .field > select,
.form-date-rest > .repeat-row > .only-monthly > .field > select,
.form-date-rest > .repeat-row > .only-pattern > .field > .multi-select {
    margin-top: auto;
}

.form-date-rest .multi-select > summary {
    min-width: 0;
}

/* repeats idea 1: the live sentence under the repeat fields (made by submit_form.js; remove with that block). One muted line
   that wraps on a narrow screen; in the over-limit state it reads like the character counters'. */
.repeat-sentence {
    flex: 1 0 100%;
    margin: 0;
    color: var(--muted);
    font-size: 0.875rem;
}

.repeat-sentence.is-over {
    color: var(--burnt-red);
    font-weight: 700;
}
/* end of repeats idea 1 */

/* Change 67: from 64rem the Date & Time section is one grid across the whole width of the box: the radios, then three equal
   columns (up to 17rem each) with the free space shared evenly between the four, so the first and the last sit on the edges of
   the box and the gaps are the same. Row 1: first day | last day / repeats until. Row 2: start time | end time. Row 3 (Repeats
   only): how it repeats | on these days | which one in the month, on the same three columns (a subgrid of the section's own
   columns), the live sentence under them. The wrapper `.form-date-rest` takes no box of its own, so its fields are cells of
   the section. A browser without subgrid, or a narrower window, keeps the wrapping rows above. */
@media (min-width: 64rem) {
    @supports (grid-template-columns: subgrid) {
        .form-date-row {
            display: grid;
            grid-template-columns: auto repeat(3, minmax(0, 17rem));
            justify-content: space-between;
            align-items: start;
            gap: 0 24px;
        }

        .form-date-row > #id_format {
            grid-column: 1;
            grid-row: 1 / span 3;
        }

        .form-date-rest {
            display: contents;
        }

        .form-date-rest > .field:nth-child(1) {
            grid-column: 2;
            grid-row: 1;
        }

        .form-date-rest > .repeat-end,
        .form-date-rest > .only-multi-day {
            grid-column: 3;
            grid-row: 1;
        }

        .form-date-rest > .field:has(#id_start_time) {
            grid-column: 2;
            grid-row: 2;
            margin-top: 12px;
        }

        .form-date-rest > .field:has(#id_end_time) {
            grid-column: 3;
            grid-row: 2;
            margin-top: 12px;
        }

        .form-date-rest > .repeat-row {
            grid-column: 2 / -1;
            grid-row: 3;
            display: grid;
            grid-template-columns: subgrid;
            column-gap: normal;   /* the section's own gap */
            align-items: stretch;
            margin-top: 12px;
        }

        .form-date-rest > .repeat-row > .field {
            grid-column: 1;
        }

        .form-date-rest > .repeat-row > .only-pattern {
            grid-column: 2;
        }

        .form-date-rest > .repeat-row > .only-monthly {
            grid-column: 3;
        }

        .form-date-rest > .repeat-row > .repeat-sentence {
            grid-column: 1 / -1;
        }

        .form-date-rest > .repeat-row > .field > select,
        .form-date-rest > .repeat-row > .only-monthly > .field > select {
            max-width: 14rem;   /* the dropdowns keep their old width inside the wider columns */
        }
    }
}

/* Change 68 (breakpoint 75rem since change 71, which added 24px before the start time): from 75rem the date and time fields are ONE row, in this order and with no gap left for a hidden one: Once = event
   date | start time | end time (three columns); Several days = first day | last day | start time | end time; Repeats = first day |
   repeats until | start time | end time (four columns). The tracks are the same four columns for every answer, so the first
   columns never move; Once simply leaves the fourth empty. Repeats has a second row: how it repeats | on these days | which one in
   the month on the first three of the same columns, the live sentence under them. The fields are placed in row 1 with no column
   of their own, so the grid fills the columns in order and skips the hidden end field. The second row is the flexible one: the
   radios (rows 1 and 2) take their extra height there, so the date row never grows taller than its fields. The radios keep
   their own full width; the four columns are up to 11rem each with one fixed 32px gap between every two columns (change 69:
   they are packed to the left, the free width stays at the right edge of the section). Between 64rem and 75rem the two-by-two grid above applies (Once
   stays one row of three): four columns stop fitting under 75rem (at 1184px Cary's end time would end 9px past the section's edge). */
@media (min-width: 64rem) and (max-width: 74.99rem) {
    @supports (grid-template-columns: subgrid) {
        /* Once is still one row of three here: event date | start time | end time on the three columns */
        .form-date-row:has(input[name="format"][value="one_time"]:checked) .form-date-rest > .field:has(#id_start_time) {
            grid-column: 3;
            grid-row: 1;
            margin-top: 0;
        }

        .form-date-row:has(input[name="format"][value="one_time"]:checked) .form-date-rest > .field:has(#id_end_time) {
            grid-column: 4;
            grid-row: 1;
            margin-top: 0;
        }
    }
}

@media (min-width: 75rem) {
    @supports (grid-template-columns: subgrid) {
        .form-date-row {
            grid-template-columns: max-content repeat(4, minmax(0, 11rem));
            grid-template-rows: auto 1fr;
            justify-content: start;   /* change 69: the columns sit side by side with one fixed gap; the unused width stays at the right */
            column-gap: 32px;
        }

        .form-date-row > #id_format {
            grid-row: 1 / span 2;
        }

        .form-date-rest > .field:nth-child(1),
        .form-date-rest > .repeat-end,
        .form-date-rest > .only-multi-day,
        .form-date-rest > .field:has(#id_start_time),
        .form-date-rest > .field:has(#id_end_time) {
            grid-column: auto;
            grid-row: 1;
            margin-top: 0;
        }

        /* Change 71: the start and end time sit 24px further right than their columns (the extra space before the start time is
           24px more than the 32px between the other columns; the start-to-end gap stays 32px). A negative right margin of the
           same size keeps each field as wide as its column. The week of the month (row 2, under the end time) moves with them. */
        .form-date-rest > .field:has(#id_start_time),
        .form-date-rest > .field:has(#id_end_time),
        .form-date-rest > .repeat-row > .only-monthly {
            margin-left: 24px;
            margin-right: -24px;
        }

        .form-date-rest > .repeat-row {
            grid-row: 2;
        }

        /* the second row: how it repeats under the first day, the days picker over two columns (it needs about 17rem for its chips),
           the week of the month under the end time; the hint of how it repeats may wrap in its narrow column */
        .form-date-rest > .repeat-row > .only-pattern {
            grid-column: 2 / span 2;
        }

        .form-date-rest > .repeat-row > .only-pattern > .field {
            max-width: 17rem;
        }

        .form-date-rest > .repeat-row > .only-monthly {
            grid-column: 4;
        }

        .form-date-rest > .repeat-row > .field > .hint {
            white-space: normal;
        }
    }
}

/* the days hint reads one way for weekly and every other week and another for monthly: the stylesheet shows one of the two
   (without :has() support both are shown, one after the other) */
@supports selector(:has(*)) {
    .submit-form .hint-monthly {
        display: none;
    }

    .submit-form:has(select[name="pattern"] option[value="monthly"]:checked) .hint-monthly {
        display: inline;
    }

    .submit-form:has(select[name="pattern"] option[value="monthly"]:checked) .hint-default {
        display: none;
    }
}

/* From 64rem the legends of the Categories and of "How often does it happen?" sit level with the labels beside them
   (Event name; First day...): a legend's text rides 1px above a label's, so it is nudged down by that much (a position
   offset, so no box moves; the Cary theme adds its own extra pixel). */
@media (min-width: 64rem) {
    .form-top > #id_categories > legend,
    .form-date-row > #id_format > legend {
        position: relative;
        top: 1px;
    }
}

/* ===== FEATURED INTEREST CARDS (ADR 0129) - design block, safe to tweak or remove as a whole =====
   Inside Final Notes of the Event Submission box, only when no payment provider is set and the brands have a Featured slot
   (events/templates/events/_submit_interest.html). Three radio cards in one fieldset: the label is the whole card, the radio
   stays visible and keeps its own focus ring. The checked card is marked three ways: the "Selected" tick and the bold title (a
   sibling rule, so it works without :has() and with script off) and, where :has() is supported, a thicker accent border.
   One card per row (the left column of Final Notes from 64rem, the single column below). No JavaScript. */
.interest-block {
    margin: 4px 0 12px;
    padding-top: 14px;
    border-top: 1px solid var(--line);
}

.interest-block > .field.choices {
    margin: 0 0 4px;
}

.form-box .interest-block .field.choices legend {
    margin-bottom: 8px;
    font: 700 1.0625rem/1.3 var(--font-heading);
}

.interest-grid {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: 12px;
}

.interest-card {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 4px;
    box-sizing: border-box;
    min-height: 44px;
    padding: 14px 16px;
    background: var(--page);
    border: 2px solid var(--line);
    border-radius: 6px;
    cursor: pointer;
}

.submit-form .interest-card {
    margin: 0;
    font-weight: 400;
}

.interest-card > input[type="radio"] {
    margin: 0 0 4px;
    flex: none;
}

.interest-card > span {
    display: block;
}

.interest-title {
    font-size: 1.0625rem;
    line-height: 1.3;
}

.interest-price {
    font: 700 1.5rem/1.2 var(--font-heading);
}

.interest-text,
.interest-bullet {
    font-size: 0.9375rem;
    line-height: 1.4;
}

.interest-bullets {
    margin-top: 4px;
}

.interest-bullet {
    display: block;
    position: relative;
    padding-left: 1.1em;
}

.interest-bullet::before {
    content: "\2022";
    position: absolute;
    left: 0.2em;
}

/* the "Selected" tick: top right of the card, only on the checked one (no :has() needed) */
.interest-card > .interest-selected {
    display: none;
    position: absolute;
    top: 12px;
    right: 14px;
    font-size: 0.875rem;
    font-weight: 700;
    color: var(--burnt-red);
}

.interest-card > input:checked ~ .interest-selected {
    display: block;
}

.interest-card > input:checked ~ .interest-title {
    font-weight: 700;
}

@supports selector(:has(*)) {
    .interest-card:has(> input:checked) {
        border-color: var(--burnt-red);
        box-shadow: 0 0 0 1px var(--burnt-red);   /* with the 2px border: 3px of accent */
    }

    .interest-card:has(> input:focus-visible) {
        outline: 3px solid var(--text);
        outline-offset: 2px;
    }
}

/* locked (the sections script greys the controls): the cards follow the shared inactive look */
.js-sections .section-peek .interest-card {
    opacity: var(--inactive-opacity);
    cursor: not-allowed;
}

.interest-block .interest-lead {
    margin: 0 0 8px;
}

@media (min-width: 64rem) {
    /* the cards stack in the LEFT column of the box body (under "Extended Event Details"; the box body is a two-column grid
       from here), one per row, at that column's width; the right column beside them stays empty */
    .form-box-body > .interest-block {
        grid-column: 1;
    }
}
/* ===== end FEATURED INTEREST CARDS ===== */

/* ===== FEATURED INTEREST EXAMPLE PANEL (ADR 0129) - design block, safe to tweak or remove as a whole =====
   The example of the CHOSEN option, one at a time (events/_submit_interest_examples.html), made of the REAL card classes of the
   /events/ list so each brand's own card CSS styles it. The three slides share one grid cell, so the panel keeps the height of
   the tallest (Video feature) and nothing jumps; the others are visibility:hidden. Free shows by default. Where :has() is
   supported the checked radio picks the slide with no script; submit_form.js also sets data-example on the panel on change (its
   only job is browsers without :has()). Decorative and not clickable (inert, no links). The right column from 64rem, under the
   cards below that. */
.interest-examples {
    min-width: 0;
    margin: 4px 0 12px;
    padding-top: 14px;
    border-top: 1px solid var(--line);
}

.interest-examples-label {
    margin: 0 0 2px;
    font: 700 1.0625rem/1.3 var(--font-heading);
}

.interest-examples .interest-examples-note {
    margin: 2px 0 8px;
}

.example-stack {
    display: grid;
}

.example-slide {
    grid-area: 1 / 1;
    min-width: 0;
    box-sizing: border-box;
    padding: 6px 6px 4px;
    visibility: hidden;
}

.example-slide.example-free {
    visibility: visible;
}

.example-frame {
    pointer-events: none;
    user-select: none;
}

.example-frame .event-card {
    height: auto;
    cursor: default;
}

.example-caption {
    margin: 8px 0 0;
    font-size: 0.875rem;
    font-weight: 700;
    text-align: center;
}

.example-caption::before {
    content: "Example: ";
    font-weight: 400;
}

/* the Video feature's extra line, as a bar under its boosted card: the brand's red (--burnt-red, the primary button and the
   selected card's colour) with white words and the boosted card's own shadow (--shadow-featured). The Cary theme sets its own
   colour, border and shadow; the size and spacing are shared, so the two bars match. */
.example-video-bar {
    margin: 0;
    padding: 14px 18px;
    font-size: 0.9375rem;
    text-align: center;
    text-wrap: balance;
    line-height: 1.4;
    color: #fff;
    background: var(--burnt-red);
    border: 2px solid var(--burnt-red);
    border-radius: 6px;
    box-shadow: var(--shadow-featured);
}

/* the connector between the Video bar and the boosted card: PLUS, bold and small, between two thin rules */
.example-plus {
    display: flex;
    align-items: center;
    gap: 12px;
    margin: 14px 0;
    font-size: 0.8125rem;
    font-weight: 700;
    letter-spacing: 0.12em;
    color: var(--burnt-red);
}

.example-plus::before,
.example-plus::after {
    content: "";
    flex: 1 1 0;
    border-top: 1px solid currentColor;
}

/* which slide shows: the script's data-example (all browsers with script) ... */
.interest-examples[data-example="boosted"] .example-free,
.interest-examples[data-example="video"] .example-free {
    visibility: hidden;
}

.interest-examples[data-example="boosted"] .example-boosted,
.interest-examples[data-example="video"] .example-video {
    visibility: visible;
}

/* ... and, with no script, the checked radio itself where :has() is supported */
@supports selector(:has(*)) {
    .form-box-body:has(input[name="featured_interest"][value="boosted"]:checked) .example-free,
    .form-box-body:has(input[name="featured_interest"][value="video"]:checked) .example-free {
        visibility: hidden;
    }

    .form-box-body:has(input[name="featured_interest"][value="boosted"]:checked) .example-boosted,
    .form-box-body:has(input[name="featured_interest"][value="video"]:checked) .example-video {
        visibility: visible;
    }
}

/* Below 64rem (the example panel sits under the option cards) only the chosen slide takes space, so the panel and everything
   under it follow the chosen example's height (Free shortest, Video tallest); from 64rem the constant-height rules above stay.
   The same two ways of choosing: the script's data-example, and the checked radio with :has(). Free when neither works. */
@media (max-width: 63.99rem) {
    .example-slide {
        display: none;
    }

    .example-slide.example-free {
        display: block;
    }

    .interest-examples[data-example="boosted"] .example-free,
    .interest-examples[data-example="video"] .example-free {
        display: none;
    }

    .interest-examples[data-example="boosted"] .example-boosted,
    .interest-examples[data-example="video"] .example-video {
        display: block;
    }

    @supports selector(:has(*)) {
        .form-box-body:has(input[name="featured_interest"][value="boosted"]:checked) .example-free,
        .form-box-body:has(input[name="featured_interest"][value="video"]:checked) .example-free {
            display: none;
        }

        .form-box-body:has(input[name="featured_interest"][value="boosted"]:checked) .example-boosted,
        .form-box-body:has(input[name="featured_interest"][value="video"]:checked) .example-video {
            display: block;
        }
    }
}

/* The newly chosen example fades in and settles up from 6px in 220 ms (opacity and transform only: no layout shift). It plays
   only after the visitor changes the choice: the :has() rules need the CHECKED radio to be the FOCUSED one too (a click, a tap
   or an arrow key puts the focus there; a page load does not), and the script's rules need the class it adds on the first
   change. Nothing animates for visitors who ask for less motion. */
@keyframes example-reveal {
    from {
        opacity: 0;
        transform: translateY(6px);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

/* the Video feature's three parts arrive in turn instead of the whole slide fading: the text bar (a tiny pop from 96% and 4px
   below), then PLUS, then the event card (the same fade as the other examples); 200 ms each, 100 ms apart, 400 ms in all.
   Backwards fill keeps each invisible during its delay, so nothing flashes before it starts. */
@keyframes example-pop {
    from {
        opacity: 0;
        transform: translateY(4px) scale(0.96);
    }

    to {
        opacity: 1;
        transform: none;
    }
}

@media (prefers-reduced-motion: no-preference) {
    .interest-examples.is-changed[data-example=""] .example-free,
    .interest-examples.is-changed[data-example="boosted"] .example-boosted {
        animation: example-reveal 220ms ease-out;
    }

    .interest-examples.is-changed[data-example="video"] .example-video-bar {
        animation: example-pop 200ms ease-out both;
    }

    .interest-examples.is-changed[data-example="video"] .example-plus {
        animation: example-pop 200ms ease-out 100ms both;
    }

    .interest-examples.is-changed[data-example="video"] .example-video .event-card {
        animation: example-reveal 200ms ease-out 200ms both;
    }

    @supports selector(:has(*)) {
        .form-box-body:has(input[name="featured_interest"][value=""]:checked:focus) .example-free,
        .form-box-body:has(input[name="featured_interest"][value="boosted"]:checked:focus) .example-boosted {
            animation: example-reveal 220ms ease-out;
        }

        .form-box-body:has(input[name="featured_interest"][value="video"]:checked:focus) .example-video-bar {
            animation: example-pop 200ms ease-out both;
        }

        .form-box-body:has(input[name="featured_interest"][value="video"]:checked:focus) .example-plus {
            animation: example-pop 200ms ease-out 100ms both;
        }

        .form-box-body:has(input[name="featured_interest"][value="video"]:checked:focus) .example-video .event-card {
            animation: example-reveal 200ms ease-out 200ms both;
        }
    }
}

/* locked (peek): greyed with the section. The panel IS the section item (the script puts section-peek on it), so the class is on
   the panel itself; the cards are inside the interest block item and use the descendant rule above. */
.js-sections .interest-examples.section-peek {
    opacity: var(--inactive-opacity);
}
/* ===== end FEATURED INTEREST EXAMPLE PANEL ===== */


/* ===== FORM PROGRESS AIDS (submit_form.js adds all of these; without script none exists) - design block, safe to tweak or remove as a whole =====
   Under the "Event Submission" heading and its legend line, a slim bar row with "Step N of 5". The fill is
   completed / 5 as a class (is-done-0 .. is-done-4: no inline style). The bar is STICKY inside the box: when its place scrolls
   out of view it stays at the top of the screen (below the site menu where the menu is sticky: from 48rem; the phone menu is
   not sticky) in a compact form, "N/5" and a thin line on a solid background, and it lets go when the box ends. Its height is
   the same stuck or not, so nothing moves when it sticks (the script only adds is-stuck, watching a marker above the bar).
   A check mark sits at the left end of each finished section heading, out of the flow (so the heading text stays exactly
   centred) and opposite the chevron; "Almost there" is a line under Final Notes once it is open. */
.form-box {
    /* the bar's top: 0 on a phone; below the sticky site menu from 48rem. KEEP IN STEP WITH THE MENU'S HEIGHT (measured: 64px
       from 48rem and 68px from 60rem on the Raleigh theme, 66px on Cary): 2px less, so the bar tucks under the menu's edge
       (the bar's layer is below the menu's) and never leaves a gap. */
    --submit-bar-top: 0px;
}

@media (min-width: 48rem) {
    .form-box {
        --submit-bar-top: 62px;
    }
}

@media (min-width: 60rem) {
    .form-box {
        --submit-bar-top: 66px;
    }
}

.submit-progress-sentinel {
    height: 0;
}

.submit-progress {
    position: sticky;
    top: var(--submit-bar-top);
    z-index: 20;   /* above the form, below the menu (50) and below the pickers' lists (30), which open over it */
    box-sizing: border-box;
    display: flex;
    align-items: center;
    gap: 12px;
    height: 40px;
    padding: 0 16px;
    background: var(--section-bg);
    border-bottom: 1px solid transparent;
}

/* the section rule (.form-divider) between the bar and the legend, inset like the box content; without script there is no bar and
   the rule would sit right under the heading's own border, so it is left out there */
.form-box > .form-divider {
    margin: 8px 16px 0;
}

.form-box-title + .form-divider {
    display: none;
}

/* desktop (64rem, the form's two-column breakpoint): no rule above the legend, and only a small breathing gap under the bar */
@media (min-width: 64rem) {
    .form-box > .form-divider {
        display: none;
    }

    .submit-form .form-box > .submit-box-legend {
        margin-top: 0;
        padding-top: 8px;
    }
}

/* the legend line under the box heading (server-rendered): small, italic, in the form's red, centred; it comes after the bar and scrolls away with the page (only the bar sticks) */
.submit-form .submit-box-legend {
    margin: 0;
    padding: 10px 16px 0;
    font-style: italic;
    font-weight: 400;
    text-align: center;
    color: var(--burnt-red);
}

.submit-progress-label {
    flex: none;
    font-size: 0.875rem;
    font-weight: 700;
    color: var(--text);
}

.submit-progress-label .label-brief {
    display: none;
}

.submit-progress.is-stuck .submit-progress-label .label-full {
    display: none;
}

.submit-progress.is-stuck .submit-progress-label .label-brief {
    display: inline;
}

.submit-progress.is-stuck {
    border-bottom-color: var(--line);
}

.submit-progress-track {
    flex: 1 1 auto;
    min-width: 0;
    height: 10px;
    overflow: hidden;
    background: var(--line);
    border: 1px solid var(--line);
    border-radius: 999px;
}

.submit-progress.is-stuck .submit-progress-track {
    height: 6px;
}

.submit-progress-fill {
    width: 0;
    height: 100%;
    background: var(--burnt-red);
    border-radius: 999px;
}

.submit-progress-fill.is-done-1 { width: 20%; }
.submit-progress-fill.is-done-2 { width: 40%; }
.submit-progress-fill.is-done-3 { width: 60%; }
.submit-progress-fill.is-done-4 { width: 80%; }

@media (prefers-reduced-motion: no-preference) {
    .submit-progress-fill {
        transition: width 300ms ease-out;
    }
}

/* focusing a field or following an error link must not leave it under the stuck bar (and, from 48rem, the menu: the page's own
   scroll-padding-top of 5rem is already added there) */
.submit-form :is(input, select, textarea, fieldset, .form-section-title, details) {
    scroll-margin-top: 3.5rem;
}

@media (min-width: 48rem) {
    .submit-form :is(input, select, textarea, fieldset, .form-section-title, details) {
        scroll-margin-top: 2.75rem;
    }
}

.section-check {
    position: absolute;
    top: 50%;
    left: 0;
    transform: translateY(-50%);
    display: inline-flex;
    align-items: center;
    justify-content: center;
    min-width: 28px;
    height: 28px;
    padding-right: 6px;
    font-size: 1.125rem;
    font-weight: 700;
    line-height: 1;
    color: var(--burnt-red);
    background: var(--section-bg);   /* cuts the rule at the left end, as the chevron's fill does at the right */
}

.section-check[hidden],
.section-almost[hidden] {
    display: none;
}

.form-box-body > .section-almost {
    grid-column: 1 / -1;
    margin: -6px 0 12px;
    text-align: center;
}
/* ===== end FORM PROGRESS AIDS ===== */
