/* =============================================================
   Artsopolis Octave Theme — Main Stylesheet
   Aesthetic: Modern, accessible, brand-kit-driven
   Google Fonts are loaded dynamically by functions.php based on
   Customizer → Brand Kit → Typography selections.
   ============================================================= */

/* ---------------------------------------------------------------
   1. CSS Custom Properties (Design Tokens)
   These are FALLBACKS. The actual values are injected at runtime by
   functions.php → artsopolis_octave_output_brand_kit_css() based on
   Customizer settings. Anything here is what unmodified installs see.
   --------------------------------------------------------------- */
:root {
  /* Brand colors — overridden by Customizer Brand Kit */
  /* WCAG 1.4.3. The previous default, #217dbf, measures 4.421:1 on white —
     just under the 4.5:1 AA minimum for normal-size text. That affected both
     of its jobs: link text at the default size, and white text/icons on a
     primary-filled button. #1f76b4 is 4.874:1 and visually near-identical.
     Kept in step with the ao_color_primary Customizer default in
     functions.php, which emits an inline :root override that wins over this
     value — changing only this one would have had no effect on a live site. */
  --color-primary:     #1f76b4;   /* Buttons, links, primary actions */
  --color-secondary:   #333459;   /* Footer background */
  --color-accent:      #3cb0e2;   /* Hover, accent details */

  /* Top Utility Bar — overridden by Customizer Top Utility Bar section.
     Background is independent of --color-secondary (footer) on purpose. */
  --topbar-bg-color:        #333459;
  --topbar-height:           44px;
  --topbar-btn-text-color:  #ffffff;   /* matches Pill mode's white text — safe against the default navy bg */
  --topbar-btn-radius:       999px;
  --topbar-icon-size:        32px;
  --topbar-icon-color:      #ffffff;

  /* Masthead — overridden by Customizer Masthead section. */
  --masthead-height:            80px;
  --nav-dropdown-hover-color:   #252525;
  --nav-dropdown-hover-radius:  0px;
  --nav-dropdown-bg-color:      #3cb0e2;

  /* Logo rendering size — overridden by Customizer Site Identity section
     (Logo Width (px) / Logo Height (px)). See .site-branding__logo below
     for how a value taller than 80px overlaps the Top Utility Bar. */
  --logo-width:   280px;
  --logo-height:   80px;

  --color-ink:         #252525;   /* Body text */
  --color-ink-muted:   #666666;   /* Secondary text */
  --color-paper:       #ffffff;   /* Page background */
  --color-bg-warm:     #f9f9f9;   /* Card / subtle bg */

  /* Derived colors — computed from primaries */
  --color-rule:        #e5e5e5;   /* Hairlines */
  --color-focus:       var(--color-primary);
  --color-success:     #1a6b3c;
  --color-error:       #c0392b;
  /* Fill of a saved (pressed) favorite heart/bookmark, on cards and detail
     pages alike (theme 2.103.0). One token so every template agrees. */
  --color-favorite-active: var(--color-success);

  /* Backwards-compatibility aliases — code from earlier versions
     references these names. */
  --color-bg:          var(--color-paper);
  --color-bg-card:     var(--color-paper);
  --color-link:        var(--color-primary);
  --color-link-hover:  var(--color-accent);
  --color-accent-dark: var(--color-secondary);
  --color-accent-pale: var(--color-bg-warm);
  --color-ink-light:   var(--color-ink-muted);

  /* Typography — overridden by Customizer Brand Kit */
  --font-body:        'Poppins', -apple-system, BlinkMacSystemFont, sans-serif;
  --font-display:     'Playfair Display', Georgia, serif;
  --font-mono:        'JetBrains Mono', 'Courier New', monospace;
  --font-base-size:   16px;

  /* Type Scale */
  --text-xs:   0.75rem;    /* 12px */
  --text-sm:   0.875rem;   /* 14px */
  --text-base: 1rem;       /* 16px */
  --text-md:   1.125rem;   /* 18px */
  --text-lg:   1.25rem;    /* 20px */
  --text-xl:   1.5rem;     /* 24px */
  --text-2xl:  1.875rem;   /* 30px */
  --text-3xl:  2.25rem;    /* 36px */
  --text-4xl:  3rem;       /* 48px */

  /* Spacing (8px grid) */
  --space-1:  0.25rem;
  --space-2:  0.5rem;
  --space-3:  0.75rem;
  --space-4:  1rem;
  --space-5:  1.25rem;
  --space-6:  1.5rem;
  --space-7:  1.75rem;
  --space-8:  2rem;
  --space-10: 2.5rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-20: 5rem;
  --space-24: 6rem;

  /* Layout */
  --max-width:        1040px;
  --content-width:    680px;
  --sidebar-width:    320px;
  --gutter:           clamp(1rem, 4vw, 2rem);

  /* Customizer-driven width overrides — default to --max-width */
  --header-width:     var(--max-width);
  --body-width:       var(--max-width);
  --footer-width:     var(--max-width);

  /* Borders — overridden by Customizer Brand Kit (Shape scale) */
  --radius-sm:   4px;
  --radius-md:   10px;
  --radius-lg:   20px;
  --radius-pill: 999px;
  --border-width: 1px;

  /* Shadows */
  --shadow-sm:  0 1px 3px rgba(0,0,0,0.08);
  --shadow-md:  0 4px 12px rgba(0,0,0,0.10);
  --shadow-lg:  0 8px 32px rgba(0,0,0,0.12);

  /* Transitions */
  --transition-fast: 120ms ease;
  --transition-base: 200ms ease;
  --transition-slow: 350ms ease;
}

/* ---------------------------------------------------------------
   2. Reset & Base
   --------------------------------------------------------------- */
*, *::before, *::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  font-size: var(--font-base-size, 16px);
  scroll-behavior: smooth;
  -webkit-text-size-adjust: 100%;
}

body {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 400;
  line-height: 1.6;
  color: var(--color-ink);
  background-color: var(--color-bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

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

/* WordPress swaps emoji glyphs for <img class="emoji"> pointing at s.w.org
   SVGs, and those SVGs carry a viewBox with no width/height attributes.
   Against the block reset above, a replaced element with no intrinsic size
   fills its container and the 1:1 ratio squares it off — the 2.5rem 📅 in
   .archive-empty__icon rendered 767x767 on oside2.artsopolis.com. Core used
   to guard this with an !important rule of its own, but wp-emoji-styles is
   not printed on every site (absent there while the detection script still
   runs), so size them here rather than depending on core. Class specificity
   beats the bare `img` type selector regardless of source order; no
   !important, so core's own rule still wins wherever it is present. */
img.emoji,
img.wp-smiley {
  display: inline;
  width: 1em;
  height: 1em;
  margin: 0 0.07em;
  padding: 0;
  border: none;
  background: none;
  box-shadow: none;
  vertical-align: -0.1em;
}

a {
  color: var(--color-link);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 1px;
  transition: color var(--transition-fast), text-decoration-color var(--transition-fast);
}

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

a:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
  border-radius: var(--radius-sm);
}

/* The shared image lightbox (assets/js/navigation.js, "Primary Image
   Lightbox") adds role="button" + tabindex="0" to
   .listing-detail__image-wrap[data-full] via JS on every template that uses
   it (event/venue/listing details, and the Billboard blog template). Every
   other :focus-visible rule in this file is scoped to a native interactive
   tag (a, button, select, …), so this JS-made button — a plain <div> —
   matched none of them and rendered with no visible focus ring at all
   (confirmed via computed style). This restores one, fixing it everywhere
   the lightbox is used, not just here. */
.listing-detail__image-wrap[tabindex]:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
}

ul, ol {
  padding-left: var(--space-6);
}

/* ---------------------------------------------------------------
   3. Skip Link (Accessibility)
   --------------------------------------------------------------- */
.skip-link {
  position: absolute;
  top: -100%;
  left: var(--space-4);
  z-index: 9999;
  padding: var(--space-3) var(--space-6);
  background: var(--color-ink);
  color: #ffffff;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  text-decoration: none;
  border-radius: var(--radius-md);
  transition: top var(--transition-fast);
}

.skip-link:focus {
  top: var(--space-4);
  outline: 2px solid var(--color-focus);
  outline-offset: 3px;
}

/* Visually hidden, but available to assistive technology. Standard
   WordPress utility — used for new-window notices, off-screen field
   labels, and live-region status text throughout the theme. */
.screen-reader-text {
  position: absolute !important;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  clip-path: inset(50%);
  white-space: nowrap;
  border: 0;
  word-wrap: normal !important;
}

/* When an SR-only element receives focus (e.g. a skip target), allow it
   to become visible rather than staying clipped. */
.screen-reader-text:focus {
  position: fixed !important;
  top: var(--space-4);
  left: var(--space-4);
  width: auto;
  height: auto;
  padding: var(--space-3) var(--space-6);
  clip: auto;
  clip-path: none;
  background: var(--color-ink);
  color: #ffffff;
  font-size: var(--text-sm);
  z-index: 100000;
  border-radius: var(--radius-md);
}

/* ---------------------------------------------------------------
   4. Layout Containers
   --------------------------------------------------------------- */
.site-wrapper {
  display: flex;
  flex-direction: column;
  min-height: 100vh;
}

.container {
  width: 100%;
  max-width: var(--body-width);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

/* Context-specific width overrides — only the inner container is constrained;
   the full-bleed site-header / site-footer background still extends edge-to-edge. */
.site-header .container {
  max-width: var(--header-width);
}

/* The utility bar sits directly above the masthead and shares its
   container width (not --body-width) so right-aligned content in both
   rows — e.g. the Login button here and a right-aligned nav menu below —
   lines up on the same right edge regardless of the configured widths. */
.site-topbar .container {
  max-width: var(--header-width);
}

.site-footer .container {
  max-width: var(--footer-width);
}

.container--narrow {
  max-width: var(--content-width);
}

.site-main {
  flex: 1;
  padding-block: var(--space-12) var(--space-20);
}

/* When the page leads with a breadcrumb (archive, taxonomy, and single
   listing templates), the breadcrumb supplies its own top spacing and the
   masthead sits directly above it. Collapse the site-main top padding in
   that case so there is no extra vertical gap between the header and the
   breadcrumb. Pages that do NOT lead with a breadcrumb (front page,
   dashboard, auth pages) keep the original top padding.

   Two DOM shapes need covering: CPT archive/detail templates print the
   breadcrumb as the first thing inside <main>, while the blog templates
   (home.php, single.php) print it via artsopolis_octave_render_breadcrumb()
   as a sibling immediately BEFORE <main> opens — so .site-main's own
   padding-top was never being collapsed for the blog, leaving a ~96px gap
   (48px site-main padding-top + the breadcrumb's own 48px of bottom
   spacing) instead of the ~48px every other listing/detail page gets.

   home.php/category.php/tag.php additionally print a third shape: the
   .blog-listing-toolbar (search + category filter) sits between the
   breadcrumb and <main>, so .breadcrumb + .site-main alone no longer
   matches there either — .blog-listing-toolbar's own margin-bottom is the
   sole intended source of that gap (currently 40px), so this needs
   covering too or .site-main's 48px padding-top stacks on top of it. */
.site-main:has(> .breadcrumb:first-child),
.breadcrumb + .site-main,
.breadcrumb + .blog-listing-toolbar + .site-main,
.site-main:has(> .auth-page--top) {
  padding-top: 0;
}

/* Billboard detail template: its featured image is meant to sit flush
   against the breadcrumb with no gap, so zero out the breadcrumb's own
   margin-bottom (normally var(--space-8), the ~48px gap before a page's
   title) specifically when the next .site-main contains a billboard post.
   Every other page keeps that spacing. */
.breadcrumb:has(+ .site-main .post-detail--billboard) {
  margin-bottom: 0;
}

/* Blog listing pages (home.php/category.php/tag.php): 20px less than the
   breadcrumb's usual 32px margin-bottom, specifically above
   .blog-listing-toolbar (the category filter + search row). Every other
   page keeps the full 32px. */
.breadcrumb:has(+ .blog-listing-toolbar) {
  margin-bottom: 12px;
}

/* ---------------------------------------------------------------
   5. Site Header
   --------------------------------------------------------------- */
.site-header {
  border-bottom: 1px solid var(--color-rule);
  /* Customizer → Masthead → Masthead Background Color, falling back to
     the paper/card color the masthead has always used. background-color
     rather than the shorthand so the graphic rules below can add an image
     without this resetting it. */
  background-color: var(--masthead-bg-color, var(--color-bg-card));
  position: sticky;
  top: 0;
  z-index: 100;
}

/* Semi-transparent masthead — Customizer → Masthead → "Semi-transparent
   masthead over the hero" (body class .ao-masthead-transparent).

   The masthead is tinted with --masthead-tint (the chosen color combined
   with the chosen transparency, built in functions.php) and lifted out of
   the flow by a negative bottom margin equal to its own rendered height, so
   the hero band below starts at the very top of the page and runs beneath
   it. That height cannot be read in CSS: --masthead-overlay-height is
   emitted server-side as an estimate and replaced with the measured value
   by masthead-transparency.js.

   Three gates, all deliberate:

     • :has(+ .ao-hero) — the overlay only applies where a hero band is the
       next thing after the masthead, i.e. the homepage. On an ordinary
       page there is nothing to see through to, and the body text would
       ghost through the bar instead.
     • min-width: 769px — below that the masthead is position: relative
       rather than sticky (see the ≤768px block in section 15) and the hero
       is only ~125px tall, so an ~113px masthead would cover almost all of
       it. Mobile keeps the solid bar.
     • .is-masthead-overlay — added by masthead-transparency.js, and only
       while the hero is at least 1.5x the masthead's height. A hero can
       also be a short ad banner from its shortcode source, and pulling a
       90px banner up under the masthead would bury it rather than reveal
       it. Keeping the class in the script's hands also means that without
       JavaScript the masthead is left exactly as it was, rather than tinted
       with nothing pulled up behind it.

   .is-masthead-solid is toggled by the same script once the hero has
   scrolled up past the masthead, which is what stops page content ghosting
   through the sticky bar for the rest of the page. The border stays in the
   box at 1px throughout — only its color changes — so nothing shifts by a
   pixel when the two states swap. */
@media (min-width: 769px) {
  .ao-masthead-transparent .site-header.is-masthead-overlay:has(+ .ao-hero) {
    background: var(--masthead-tint, rgba(255, 255, 255, 0.7));
    border-bottom-color: transparent;
    margin-bottom: calc(-1 * var(--masthead-overlay-height, 113px));
  }

  .ao-masthead-transparent .site-header.is-masthead-overlay.is-masthead-solid:has(+ .ao-hero) {
    background: var(--masthead-bg-color, var(--color-bg-card));
    border-bottom-color: var(--color-rule);
  }

  /* Added one frame after .is-masthead-overlay so the tint is simply there
     on arrival — the fade belongs to the scroll transition between the two
     states, not to page load. */
  .ao-masthead-transparent .site-header.is-masthead-animated {
    transition: background-color var(--transition-base), border-color var(--transition-base);
  }
}

/* Masthead background graphic — Customizer → Masthead → Masthead
   Background Graphic (body class .ao-masthead-graphic).

   The image, its fit, anchor point and repeat all arrive as custom
   properties from artsopolis_octave_output_masthead_css() in
   functions.php, printed only when a graphic is set — the fallbacks here
   are never what a real site sees. The graphic is painted on .site-header
   itself, so it spans the full viewport width behind the container, and
   the Masthead Height on .site-header__inner below is what gives it room.
   It is decorative, so it lives here as a background rather than as an
   <img>: nothing for a screen reader to announce, no alt text to keep in
   step with it. The ≤768px block in section 15 can switch it off again
   (Graphic on Phones → Hide). */
.ao-masthead-graphic .site-header {
  background-image: var(--masthead-bg-image, none);
  background-size: var(--masthead-bg-size, cover);
  background-position: var(--masthead-bg-position, center center);
  background-repeat: var(--masthead-bg-repeat, no-repeat);
}

/* Customizer → Masthead → "Keep the masthead visible while scrolling",
   switched off (body class .ao-masthead-static). The masthead has been
   sticky on tablet/desktop since the theme began; this returns it to the
   flow so it scrolls away with the page — the sensible choice once the row
   has been made tall for a graphic. Mobile (≤768px) is position: relative
   regardless; see section 15. */
.ao-masthead-static .site-header {
  position: relative;
}

.site-header__inner {
  display: grid;
  grid-template-columns: auto 1fr;
  /* Customizer → Masthead → Logo & Menu Vertical Alignment: start / center
     / end. Only visible once the row is taller than its content. */
  align-items: var(--masthead-valign, center);
  gap: var(--space-6);
  padding-block: var(--space-4);
  /* --masthead-height (Customizer → Masthead → Masthead Height) is a
     floor, not a fixed height: content taller than it (e.g. a full-height
     logo) still expands the row via normal grid sizing. align-items above
     places shorter content within it. */
  min-height: var(--masthead-height, 80px);
}

/* Nav alignment (Customizer → Masthead → Navigation Menu Alignment) is
   relative to the logo: the logo occupies the first (auto-width) grid
   column, and the nav is positioned within the remaining space of the
   second (1fr) column — so "center"/"right" never overlaps the logo. */
.site-header__inner .nav-primary {
  justify-self: start;
}

.site-header__inner--nav-center .nav-primary {
  justify-self: center;
}

.site-header__inner--nav-right .nav-primary {
  justify-self: end;
}

.site-branding {
  flex-shrink: 0;
}

/* .site-branding__logo's own box stays a fixed 80px tall regardless of
   --logo-height, so Site Title/Tagline below it (siblings in .site-branding)
   never move when the logo is resized. The <img> itself is positioned
   independently within that box, bottom-anchored — at the default 80px
   height it exactly fills the box (identical to the old in-flow render),
   but a taller value pushes its top edge above the box, up through the
   masthead row and, on tablet/desktop, into the Top Utility Bar above it
   (.site-header's z-index already stacks above .site-topbar — see below).
   Reverted to simple in-flow sizing on mobile; see the max-width:768px
   block. */
.site-branding__logo {
  position: relative;
  width: var(--logo-width, 280px);
  height: 80px;
}

.site-branding__logo img {
  display: block;
  position: absolute;
  left: 0;
  bottom: 0;
  width: var(--logo-width, 280px);
  height: var(--logo-height, 80px);
  object-fit: contain;
}

.site-title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

/* Customizer → Masthead → Site Title Color / Tagline Color. Both empty by
   default (the custom properties are only printed when set), which is Ink
   and Muted Ink as before. With a title color set, hover keeps that color
   rather than switching to Accent — Accent was chosen against a white
   masthead, not against whatever background or graphic the title now
   sits on. */
.site-title a {
  color: var(--masthead-title-color, var(--color-ink));
  text-decoration: none;
}

.site-title a:hover {
  color: var(--masthead-title-color, var(--color-accent));
}

.site-description {
  font-size: var(--text-xs);
  color: var(--masthead-tagline-color, var(--color-ink-muted));
  font-style: italic;
  margin-top: var(--space-1);
  font-family: var(--font-body);
  letter-spacing: 0.05em;
}

/* ---------------------------------------------------------------
   6. Primary Navigation (Tab-into-Panel Dropdowns)
   Replicates the ArtsLink North style:
   - Top-level items sit naked on white
   - On hover: light gray pill with top corners rounded (bottom edges
     flat so they appear to merge into the dropdown below)
   - Dropdown panel: cyan (--color-accent) background with white text,
     anchored to parent's left edge
   - Hover on a sub-menu item: dark (--color-ink) background
   --------------------------------------------------------------- */
.nav-primary {
  display: flex;
  align-items: center;
  gap: var(--space-2);
}

.nav-primary__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

/* Top-level item: relative positioning so the sub-menu can anchor to it.
   No bottom border-radius on the link so the pill "merges" into the panel. */
.nav-primary__item {
  position: relative;
}

.nav-primary__item > a {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 12px 18px;
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 400;
  /* Customizer → Masthead → Menu Item Text Color / Menu Item Background
     Color. Both empty by default, which is Ink text on nothing — the
     custom properties are only printed when a value is set. */
  color: var(--masthead-nav-text-color, var(--color-ink));
  text-decoration: none;
  border-radius: var(--radius-lg) var(--radius-lg) 0 0;
  background: var(--masthead-nav-bg-color, transparent);
  transition: color var(--transition-fast), background-color var(--transition-fast);
}

/* With a Menu Item Background Color set (body class .ao-masthead-nav-plate)
   each item is a free-standing plate rather than a tab that merges into
   its dropdown, so it is rounded on all four corners — and so is the
   dropdown panel beneath it, which no longer has a tab to merge with. */
.ao-masthead-nav-plate .nav-primary__item > a {
  border-radius: var(--radius-md);
}

/* Chevron for parent items with sub-menus.
   WP's default walker adds .menu-item-has-children on the <li> when sub-items
   exist; we ALSO handle .nav-primary__item--has-children for forward-compat
   with a future custom walker. */
.nav-primary__item.menu-item-has-children > a::after,
.nav-primary__item.nav-primary__item--has-children > a::after {
  content: "";
  display: inline-block;
  width: 8px;
  height: 8px;
  margin-left: 4px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg) translateY(-2px);
  transition: transform var(--transition-fast);
}

/* Hover, focus-within, touch-open, and current-page states */
.nav-primary__item:hover > a,
.nav-primary__item:focus-within > a,
.nav-primary__item.is-open > a,
.nav-primary__item.current-menu-item > a,
.nav-primary__item.current-menu-ancestor > a,
.nav-primary__item.current-menu-parent > a {
  /* Customizer → Masthead → Menu Item Hover Background Color; when empty
     with a plate set, functions.php derives a shade of the plate instead. */
  background-color: var(--masthead-nav-hover-bg-color, var(--color-bg-warm));
  color: var(--masthead-nav-text-color, var(--color-ink));
}

/* When the dropdown is open, rotate the chevron */
.nav-primary__item:hover > a::after,
.nav-primary__item:focus-within > a::after,
.nav-primary__item.is-open > a::after {
  transform: rotate(-135deg) translateY(2px) translateX(-2px);
}

/* ---------- Dropdown panel ---------- */
.nav-primary__item .sub-menu {
  position: absolute;
  top: 100%;                 /* flush against parent (no gap = no hover flicker) */
  left: 0;
  min-width: 220px;
  margin: 0;
  padding: 8px 0;
  list-style: none;
  /* Customizer → Masthead → Dropdown Background Color (independent of
     Brand Kit → Colors → Accent, which previously drove this directly). */
  background-color: var(--nav-dropdown-bg-color, var(--color-accent));
  /* sharp top-left to merge with parent pill's bottom-left corner */
  border-radius: 0 var(--radius-lg) var(--radius-lg) var(--radius-lg);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.08);
  opacity: 0;
  visibility: hidden;
  transform: translateY(-4px);
  transition: opacity var(--transition-fast), transform var(--transition-fast), visibility 0s linear var(--transition-fast);
  z-index: 100;
}

/* Show on hover / focus-within / touch-toggled */
.nav-primary__item:hover > .sub-menu,
.nav-primary__item:focus-within > .sub-menu,
.nav-primary__item.is-open > .sub-menu {
  opacity: 1;
  visibility: visible;
  transform: translateY(0);
  transition-delay: 0s;
}

/* If the parent item is near the right edge of the nav, flip the dropdown
   so its right edge aligns with parent's right edge instead of growing
   rightward (prevents overflow on rightmost menu items like "Join Us").
   We use :nth-last-child to detect "near right edge" — last 2 items. */
.nav-primary__item:nth-last-child(-n+2) .sub-menu {
  left: auto;
  right: 0;
  border-radius: var(--radius-lg) 0 var(--radius-lg) var(--radius-lg);
}

/* See .ao-masthead-nav-plate .nav-primary__item > a above. */
.ao-masthead-nav-plate .nav-primary__item .sub-menu {
  border-radius: var(--radius-lg);
}

.nav-primary__item .sub-menu li {
  padding: 0;
  list-style: none;
}

.nav-primary__item .sub-menu a {
  display: block;
  /* margin-inline insets the row's own box (and therefore its hover/focus
     background) 4px from the panel's left/right edges, so the highlight
     never runs edge-to-edge. */
  margin-inline: 4px;
  padding: 10px 18px;
  font-size: var(--text-sm);
  font-weight: 400;
  line-height: 1.35;
  color: #fff;
  text-decoration: none;
  background: transparent;
  transition: background-color var(--transition-fast), border-radius var(--transition-fast);
}

/* Hover/focus background — Customizer → Masthead → Dropdown Hover
   Background Color (independent of Brand Kit → Colors → Ink) and
   → Dropdown Hover Border Radius (default: 0, square corners). The panel
   itself has no overflow:hidden, so this never gets clipped into a
   rounded shape by its parent regardless of this setting. */
.nav-primary__item .sub-menu a:hover,
.nav-primary__item .sub-menu a:focus,
.nav-primary__item .sub-menu .current-menu-item > a {
  background-color: var(--nav-dropdown-hover-color, var(--color-ink));
  color: #fff;
  border-radius: var(--nav-dropdown-hover-radius, 0);
}

/* Mobile menu toggle */
.nav-toggle {
  display: none;
  /* Customizer → Brand Kit → Colors → Primary (mobile masthead only —
     desktop keeps this button hidden via display:none above). */
  background: var(--color-primary);
  border: 1px solid var(--color-primary);
  border-radius: var(--radius-md);
  /* Horizontal padding is 4px wider each side than --space-3 (12px), per
     request, to give the icon+label combo more breathing room. */
  padding: var(--space-2) calc(var(--space-3) + 4px);
  cursor: pointer;
  color: #fff;
  font-size: var(--text-sm);
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  transition: background-color var(--transition-fast), filter var(--transition-fast);
}

.nav-toggle:hover {
  filter: brightness(0.92);
}

.nav-toggle[aria-expanded="true"] .nav-toggle__icon--open { display: none; }
.nav-toggle[aria-expanded="false"] .nav-toggle__icon--close { display: none; }

/* Real root cause of the invisible hamburger/close icon: this theme's own
   responsive-media reset (`img, video, svg { max-width: 100%; height: auto; }`,
   further down this file) sets height:auto with no CSS width on every <svg>.
   For an INLINE svg sitting in a flex container (.nav-toggle) with only HTML
   width/height ATTRIBUTES (not CSS), that resolves to 0×0 instead of the
   intended 18×18 — confirmed via computed style on the live site. Explicit
   CSS size here overrides that reset (class specificity beats a bare `svg`
   type selector regardless of source order). */
.nav-toggle__icon {
  width: 18px;
  height: 18px;
  flex-shrink: 0;
}

/* Explicit stroke color, matching .nav-toggle__label's #fff, instead of
   relying solely on stroke="currentColor" inheritance. Kept as a defensive
   belt-and-suspenders measure alongside the sizing fix above. */
.nav-toggle .nav-toggle__icon path {
  stroke: #fff;
}

/* ---------------------------------------------------------------
   7. Breadcrumb Navigation
   --------------------------------------------------------------- */
.breadcrumb {
  /* 10px off each side = 20px shorter overall, applies theme-wide since
     every page shares this single .breadcrumb rule. */
  padding-block: calc(var(--space-4) - 10px);
  border-bottom: 1px solid var(--color-rule);
  margin-bottom: var(--space-8);
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: var(--space-4);
}

.breadcrumb__actions {
  flex-shrink: 0;
}

.breadcrumb__edit-btn {
  display: inline-block;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-error);
  background: #fff;
  border: 1.5px solid var(--color-error);
  border-radius: var(--radius-sm);
  padding: var(--space-2) var(--space-4);
  text-decoration: none;
  white-space: nowrap;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.breadcrumb__edit-btn:hover,
.breadcrumb__edit-btn:focus-visible {
  background: var(--color-error);
  color: #fff;
}

.breadcrumb__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

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

.breadcrumb__item + .breadcrumb__item::before {
  content: '›';
  color: var(--color-rule);
  font-size: var(--text-base);
  line-height: 1;
}

.breadcrumb__link {
  color: var(--color-ink-muted);
  text-decoration: none;
  font-size: var(--text-sm);
  transition: color var(--transition-fast);
}

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

.breadcrumb__current {
  color: var(--color-ink-light);
  font-size: var(--text-sm);
}

/* ---------------------------------------------------------------
   8. Detail Page Layout
   --------------------------------------------------------------- */
.listing-detail {
  max-width: var(--body-width);
  margin-inline: auto;
}

/* Eyebrow row: type label + bookmark/share buttons, above the image+heading+description grid */
.listing-detail__eyebrow {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: var(--space-4);
  flex-wrap: wrap;
}

.listing-detail__date {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: 500;
  letter-spacing: 0.08em;
  color: var(--color-ink-muted);
  text-transform: uppercase;
}

.listing-detail__bookmark {
  background: none;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-2);
  cursor: pointer;
  color: var(--color-ink-muted);
  font-size: var(--text-md);
  transition: color var(--transition-fast), border-color var(--transition-fast);
  line-height: 1;
  /* Glyph over caption (2.102.0) — see .listing-detail__action-label. */
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  min-width: 44px;
}

/* Explicit size: the theme's `img, video, svg { height: auto }` reset
   collapses an attribute-only inline SVG once its parent is a flex box
   (which the caption layout above made this button). 16px is what the
   width/height attributes always asked for. */
.listing-detail__bookmark svg {
  width: 16px;
  height: 16px;
  flex: none;
}

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

/* Saved: filled in green (theme 2.103.0 — was an accent-coloured outline). */
.listing-detail__bookmark[aria-pressed="true"] {
  color: var(--color-favorite-active, #1a6b3c);
  border-color: var(--color-favorite-active, #1a6b3c);
}

.listing-detail__bookmark[aria-pressed="true"] svg path {
  fill: currentColor;
}

/* ---------------------------------------------------------------
   Action captions + tooltips (2.102.0)

   Visitors did not recognise the eyebrow / card icons, so every one
   now carries a one-word caption under the glyph and repeats it in a
   small tooltip on hover and keyboard focus. The detail-page caption
   is styled here; the card caption (.listing-card__action-label) is
   in archive.css. The tooltip is generic: any element with a
   data-ao-tip attribute draws it, so it lives in this global sheet.
   --------------------------------------------------------------- */
.listing-detail__action-label {
  font-family: var(--font-body);
  font-size: 10px;
  font-weight: 600;
  line-height: 1;
  letter-spacing: 0.02em;
  text-transform: none;
  white-space: nowrap;
}

[data-ao-tip] {
  position: relative;
}

/* Drawn above the element by default; archive.css moves it below on the
   above-image card bar, where the top of the card would clip it. */
[data-ao-tip]::after {
  content: attr(data-ao-tip);
  position: absolute;
  left: 50%;
  bottom: calc(100% + 4px);
  z-index: 5;
  padding: 4px 8px;
  border-radius: var(--radius-sm);
  background: var(--color-ink);
  color: #fff;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 500;
  line-height: 1.2;
  letter-spacing: 0;
  text-transform: none;
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  visibility: hidden;
  transform: translate(-50%, 2px);
  transition: opacity var(--transition-fast), transform var(--transition-fast),
              visibility 0s linear var(--transition-fast);
}

[data-ao-tip]:focus-visible::after {
  opacity: 1;
  visibility: visible;
  transform: translate(-50%, 0);
  transition-delay: 0s;
}

/* Hover only where hover exists: on a touch screen the tooltip would stick
   after a tap, and the caption is already on screen. */
@media (hover: hover) {
  [data-ao-tip]:hover::after {
    opacity: 1;
    visibility: visible;
    transform: translate(-50%, 0);
    transition-delay: 0s;
  }
}

@media (prefers-reduced-motion: reduce) {
  [data-ao-tip]::after {
    transition: none;
    transform: translate(-50%, 0);
  }
}

.listing-detail__title {
  font-family: var(--font-display);
  font-size: clamp(var(--text-2xl), 5vw, var(--text-4xl));
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--color-ink);
  margin-bottom: var(--space-4);
}

/* Expired-event notice, sitting directly under the title on a single event
   whose last date has passed. Deliberately quieter than the legacy theme's
   solid red banner — a light red plate rather than a full-bleed block —
   because it lives inside the page's own heading block, above the presenter
   line, rather than floating above the title.

   The colours are literal, not brand tokens: this is a status colour that has
   to stay recognisably red whatever palette a site picks, and it must not
   move when the Brand Kit changes (see the inline ao-brand-kit block, which
   overrides token values defined here). Dark red on the light red plate
   measures 8.7:1, comfortably past WCAG AA for this text size. */
.listing-detail__expired {
  display: flex;
  align-items: flex-start;
  gap: var(--space-2);
  margin-bottom: var(--space-4);
  padding: var(--space-3) var(--space-4);
  border: 1px solid #f3b7b2;
  border-left: 4px solid #c0392b;
  border-radius: var(--radius-sm);
  background: #fdecea;
  color: #7f1d1d;
  font-size: var(--text-sm);
  font-weight: 600;
}

/* Sized explicitly: the icon is the only thing giving the row its colour
   accent, and it must not inherit the flex row's stretch. */
.listing-detail__expired svg {
  flex: none;
  width: 1rem;
  height: 1rem;
  margin-top: 0.1em;
  color: #c0392b;
}


/* Second line: the recovery path out of an expired event. The notice used to
   be a single centred row; it is now icon + a text column, so the icon aligns
   to the first line rather than to the middle of a two-line block. */
.listing-detail__expired-text {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  min-width: 0;
}

.listing-detail__expired-more {
  font-weight: 400;
  line-height: 1.5;
}

/* Links sit on the notice's own red ink, so they need to read as links
   without fighting it — underlined, inheriting colour, weight for the
   primary action only. */
.listing-detail__expired-more a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.listing-detail__expired-cta {
  font-weight: 700;
  white-space: nowrap;
}

.listing-detail__expired-more a:hover,
.listing-detail__expired-more a:focus-visible {
  text-decoration-thickness: 2px;
}

.listing-detail__expired-sep {
  margin: 0 var(--space-1);
  opacity: 0.5;
}

/* Capped-list footer under an associated-events grid. */
.ao-assoc-events__more {
  margin-top: var(--space-4);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

/* Count line + "View more" button (venue page, theme 2.93.0). */
.ao-assoc-events__footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  flex-wrap: wrap;
  margin-top: var(--space-4);
}
.ao-assoc-events__footer .ao-assoc-events__more {
  margin-top: 0;
}
.ao-assoc-events__view-more[disabled] {
  opacity: 0.6;
  cursor: progress;
}
.listing-detail__meta {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.listing-detail__location,
.listing-detail__organizer,
.listing-detail__presenter {
  font-size: var(--text-sm);
  color: var(--color-ink-light);
}

.listing-detail__location a,
.listing-detail__organizer a,
.listing-detail__presenter a {
  color: var(--color-link);
}

/* Body layout: heading + image + description, in that DOM order (matching
   reading/tab order — see the comment on the template markup order below).
   grid-template-areas is set by the --stacked / --side_by_side modifier
   below, per the module's "Detail page layout" setting; named grid areas
   place items independently of source order, so this DOM order renders
   identically to before in both layouts. */
.listing-detail__body {
  display: grid;
  grid-template-columns: 400px 1fr;
  column-gap: var(--space-10);
  row-gap: var(--space-6);
  margin-bottom: var(--space-10);
  align-items: start;
}

.listing-detail__body .listing-detail__figure      { grid-area: image; }
.listing-detail__body .listing-detail__heading      { grid-area: heading; }
.listing-detail__body .listing-detail__description  { grid-area: description; }

/* Stacked (default): title/categories/divider span full width above the image. */
.listing-detail__body--stacked {
  grid-template-areas:
    "heading heading"
    "image   description";
}

/* Side-by-side: title/categories/divider sit beside the image, above the
   description.
   grid-template-rows: auto 1fr (rather than the default two `auto` rows)
   is required here: the image is a named area spanning both rows, and when
   an item spanning multiple `auto` tracks is taller than what those tracks
   would otherwise total, CSS Grid distributes the deficit across *all* the
   tracks it spans — inflating the heading's row by a variable amount instead
   of leaving it sized to its own content. Making the second row `1fr`
   excludes it from that intrinsic-sizing redistribution (per spec, flexible
   tracks absorb the slack instead), so the heading row always matches its
   own content height and the row-gap below is exact regardless of image or
   description height (verified with both a long and a one-line description
   against a 400px image). */
.listing-detail__body--side_by_side {
  grid-template-areas:
    "image heading"
    "image description";
  grid-template-rows: auto 1fr;
  /* Fixed 24px between the divider (the heading's own border-bottom) and the
     top of the description text. Paired with the first-child reset below,
     which removes the description's leading element's own default top
     margin (a <p>, <ul>, etc. have different defaults per module — that
     variability is what made this gap inconsistent before). */
  row-gap: 24px;
}

.listing-detail__body--side_by_side .listing-detail__description > :first-child {
  margin-top: 0;
}

/* Heading block: title, optional meta, categories/tags, and the divider beneath
   them. Carries the divider so it renders at whatever width the heading block
   occupies — full width when stacked, column width when side-by-side. */
.listing-detail__heading {
  border-bottom: 2px solid var(--color-ink);
  padding-bottom: var(--space-6);
}

/* The <figure> around the featured image + its <figcaption> (theme 2.95.0)
   is the grid item and the sticky element, so the caption travels with the
   image. Before it, .listing-detail__image-wrap (now the figure's first
   child, still the lightbox trigger) held both roles; the two billboard
   templates' position:static overrides of that class stay harmless. The
   margin reset undoes the UA's 1em/40px figure margins. */
.listing-detail__figure {
  position: sticky;
  top: calc(var(--space-4) + 60px);
  margin: 0;
}

/* Caption under the featured image: the attachment's Media Library caption,
   printed by the 7 single-ao_*.php templates. Same width rule as the image
   so it never runs wider than the picture. */
.listing-detail__image-caption {
  width: 400px;
  max-width: 100%;
  margin: var(--space-2) 0 0;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--color-ink-muted);
  text-align: center;
}

.listing-detail__image {
  width: 400px;
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
  display: block;
}

.listing-detail__description {
  font-size: var(--text-md);
  line-height: 1.75;
  color: var(--color-ink);
}

.listing-detail__description p + p {
  margin-top: var(--space-5);
}

/* Info grid below body */
.listing-detail__info-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  border-top: 1px solid var(--color-rule);
}

.listing-detail__info-section {
  padding: var(--space-6) 0;
  border-bottom: 1px solid var(--color-rule);
}

/* The band of space under a section was never just this padding — whatever
   element happened to end the section brought its own bottom margin along
   (.info-section__posted-by carries 12px, .info-section__value 8px, a
   .contact-block none), so the gap above a rule ran anywhere from ~29px to
   ~46px depending on which section it was. The margin has nothing to do
   below the last element in a section; dropping it is what makes the space
   above and below a rule read as the same measurement everywhere. */
.listing-detail__info-section > :last-child {
  margin-bottom: 0;
}

.listing-detail__info-section:nth-child(odd) {
  padding-right: var(--space-8);
  border-right: 1px solid var(--color-rule);
}

.listing-detail__info-section:nth-child(even) {
  padding-left: var(--space-8);
}

.listing-detail__info-section--full {
  grid-column: 1 / -1;
  padding-right: 0;
  border-right: none;
  padding-left: 0;
}

/* Location + Map paired row: Location (3) on the left, Map (2) on the right. */
.listing-detail__locmap-grid {
  display: grid;
  grid-template-columns: 3fr 2fr;
  gap: 0;
}

.listing-detail__locmap-grid .listing-detail__info-section {
  border-bottom: 1px solid var(--color-rule);
}

.listing-detail__locmap-address {
  padding-right: var(--space-8);
  border-right: 1px solid var(--color-rule);
}

.listing-detail__locmap-map {
  padding-left: var(--space-8);
}

/* Constrain the map to a 3:2 ratio within the right column. */
.listing-detail__map-ratio {
  width: 100%;
  aspect-ratio: 3 / 2;
}

.listing-detail__map-ratio .listing-map {
  width: 100%;
  height: 100%;
  aspect-ratio: auto; /* fill the 3:2 wrapper instead of the default 16/9 */
}

.info-section__title {
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--color-ink);
  margin-bottom: var(--space-4);
  letter-spacing: 0.01em;
}

.info-section__value {
  font-size: var(--text-base);
  color: var(--color-ink-light);
  line-height: 1.6;
}

.info-section__label {
  font-weight: 600;
  color: var(--color-ink);
  margin-right: var(--space-2);
}

.info-section__posted-by {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  line-height: 1.5;
  margin-bottom: var(--space-3);
}

.info-section__posted-org {
  font-weight: 600;
  color: var(--color-ink);
}

.info-section__posted-date {
  color: var(--color-ink-light);
}

.info-section__posted-line {
  display: block;
}

.info-section__value--large {
  font-size: var(--text-md);
  color: var(--color-ink);
  font-weight: 300;
}

/* ---------------------------------------------------------------
   Detail quadrant layout (left column / right column)

   Which sections land in which column is decided per module by its own
   single-*.php, not here. Classifieds, for example, reads
   Details · Dates · Contact · Documents on the left and
   Custom Fields · Location · Map on the right, while organizations and
   venues put Contact on the right. These rules only describe the two
   columns.
   --------------------------------------------------------------- */
.listing-detail__quadrants {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 0;
  border-top: 1px solid var(--color-rule);
  border-bottom: 1px solid var(--color-rule);
}

.listing-detail__col {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.listing-detail__col--left {
  padding-right: var(--space-8);
  border-right: 1px solid var(--color-rule);
}

.listing-detail__col--right {
  padding-left: var(--space-8);
}

/* One module can end up with nothing at all in its left column — an
   organization with no contact details and no custom fields, for instance.
   The column is then dropped rather than rendered empty, and the grid
   collapses to the one remaining column so no divider is ruled down the
   middle of a half-empty row. */
.listing-detail__quadrants--single {
  grid-template-columns: 1fr;
}

.listing-detail__quadrants--single .listing-detail__col--right {
  padding-left: 0;
}

/* Sections stack vertically within each column, each divided by a rule.
   Reset the old two-column odd/even borders that no longer apply here. */
.listing-detail__quadrants .listing-detail__info-section {
  padding: var(--space-6) 0;
  border-bottom: 1px solid var(--color-rule);
  border-right: none;
  padding-left: 0;
  padding-right: 0;
}

.listing-detail__quadrants .listing-detail__col > .listing-detail__info-section:last-child {
  border-bottom: none;
}

/* Plain (non-bold) inline labels — used for Deadline / Expiration. */
.info-section__label--plain {
  font-weight: 400;
  color: var(--color-ink-light);
}

/* ---------------------------------------------------------------
   Venue detail — sub-blocks, rich text, and the accessibility list
   (single-ao_venue.php quadrants)
   --------------------------------------------------------------- */

/* A labelled sub-block within a section (Hours / Admission Fees / Parking). */
.info-section__block + .info-section__block {
  margin-top: var(--space-5);
}

.info-section__subtitle {
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-ink);
  margin: 0 0 var(--space-2);
}

/* Limited rich text (bold / italic / link) stored by the venue forms. */
.info-section__richtext p {
  margin: 0 0 var(--space-2);
}

.info-section__richtext p:last-child {
  margin-bottom: 0;
}

.info-section__richtext a {
  color: var(--color-link, var(--color-primary));
  text-decoration: underline;
}

/* Accessibility types — icon + label, with optional detail beneath. */
.ao-access-list {
  list-style: none;
  margin: 0 0 var(--space-4);
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
}

/* Thin double horizontal rule separating the event's own accessibility info
   from the associated venue's accessibility block on the event detail page. */
.ao-access-divider {
  border: 0;
  border-top: 3px double var(--color-border, #e5e5e5);
  margin: var(--space-5) 0;
  height: 0;
}

/* ---------------------------------------------------------------
   Accessibility accordions (event detail page)
   Collapsible <details> panels so long accessibility content doesn't
   consume vertical space. Collapsed by default.
   --------------------------------------------------------------- */
.ao-access-accordion {
  border: 1px solid var(--color-border, #e5e5e5);
  border-radius: var(--radius-sm, 4px);
  background: #fff;
}

.ao-access-accordion__summary {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  cursor: pointer;
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--color-ink);
  list-style: none;
  user-select: none;
}

/* Hide the native disclosure triangle (we supply our own chevron). */
.ao-access-accordion__summary::-webkit-details-marker { display: none; }
.ao-access-accordion__summary::marker { content: ''; }

.ao-access-accordion__summary:hover {
  background: var(--color-surface, #faf9f7);
}

.ao-access-accordion__summary:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: -2px;
}

.ao-access-accordion__icon {
  flex: 0 0 auto;
  width: 24px;
  height: 24px;
  display: block;
}

.ao-access-accordion__label {
  flex: 1 1 auto;
  min-width: 0;
}

.ao-access-accordion__chevron {
  flex: 0 0 auto;
  display: inline-flex;
  color: var(--color-ink-muted);
  transition: transform var(--transition-fast, 150ms) ease;
}

.ao-access-accordion[open] .ao-access-accordion__chevron {
  transform: rotate(180deg);
}

.ao-access-accordion__panel {
  padding: 0 var(--space-4) var(--space-4);
  border-top: 1px solid var(--color-border, #e5e5e5);
  padding-top: var(--space-4);
}

/* The list already carries a bottom margin; drop it on the last child so the
   panel's own padding controls the spacing. */
.ao-access-accordion__panel > *:last-child {
  margin-bottom: 0;
}

@media (prefers-reduced-motion: reduce) {
  .ao-access-accordion__chevron {
    transition: none;
  }
}

.ao-access-list__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
}

.ao-access-list__icon {
  flex: 0 0 auto;
  display: inline-flex;
  width: 34px;
  height: 34px;
}

/* The ADA PNGs are self-contained dark tiles with a white glyph. Two of them
   (accessible parking, wheelchair) have a knocked-out transparent glyph, so
   they rely on a light backdrop — which the page background provides. */
.ao-access-list__icon .ao-accessibility-icon {
  width: 34px;
  height: 34px;
  display: block;
}

.ao-access-list__text {
  min-width: 0;
}

.ao-access-list__label {
  display: block;
  font-size: var(--text-base);
  color: var(--color-ink);
  line-height: 1.4;
}

.ao-access-list__detail {
  display: block;
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  line-height: 1.6;
  margin-top: 2px;
}

/* Each accessibility occurrence (date + time) on its own row, matching the
   printer-friendly view's layout — .ao-access-list__date-row is a <span>
   nested inside .ao-access-list__dates (also a <span>), so without this it
   stays inline and every date runs together on one line. */
.ao-access-list__date-row {
  display: block;
}

.ao-access-list__date-row + .ao-access-list__date-row {
  margin-top: 2px;
}

/* Location address forced onto a single line, wrapping only if it must. */
.listing-detail__address-line .info-section__value {
  white-space: normal;
}

.listing-detail__address-line .info-section__value > span {
  white-space: nowrap;
}

/* Map sits directly beneath the Location section in the right column. */
.listing-detail__map-section .info-section__title.screen-reader-text {
  margin-bottom: 0;
}

.listing-detail__map-section .listing-detail__map-ratio {
  width: 100%;
  aspect-ratio: 3 / 2;
}

/* Custom-fields display rows. */
.listing-detail__custom-fields .cf-display__row {
  margin-bottom: var(--space-2);
}

.cf-display__label {
  font-weight: 400;
  color: var(--color-ink-light);
  margin-right: var(--space-2);
}

.cf-display__value {
  color: var(--color-ink-light);
}


.info-section__note {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  font-style: italic;
  margin-top: var(--space-3);
}

/* No-image variant: heading and description stack full width, regardless of
   the stacked/side_by_side layout setting (there's no image to sit beside). */
.listing-detail__body--no-image {
  grid-template-columns: 1fr;
  grid-template-areas:
    "heading"
    "description";
}

/* ---------------------------------------------------------------
   9. Address & Contact Blocks
   --------------------------------------------------------------- */
.contact-block {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

/* Event detail: Email | Phone side by side on one row (wraps on narrow
   screens). Overrides .contact-block's default vertical stacking. */
.contact-block.ao-event-contact-row {
  flex-direction: row;
  flex-wrap: wrap;
  gap: var(--space-3) var(--space-6);
}

/* Event detail: Age and Attendance Type share one row, Attendance sitting to
   the right of the Age text. Row gap keeps them readable once the pair wraps
   onto two lines on a narrow column; the wider column gap is what separates
   the two fields from each other, so neither reads as part of the other. */
.ao-event-age-attendance {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin-top: var(--space-2);
}

/* Each half is itself an icon+text run (Attendance pairs a pictogram with
   "In-Person" / "Virtual"), so it needs its own inline flex context rather
   than inheriting the row's wide column gap between icon and word. */
.ao-event-age-attendance__item {
  display: inline-flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Event detail: Price Range stacked above the ticket buttons. The block is
   inline-flex so it shrink-wraps to the button row rather than to the full
   width of the section — that is what makes `align-items: center` centre the
   price over the BUTTONS instead of over the whole column. */
.ao-event-ticket-block {
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  margin-top: var(--space-4);
}

/* Four points smaller than the surrounding rows (--text-base is 1rem/12pt, so
   this resolves to 8pt) — expressed as a subtraction rather than a literal so
   it keeps that relationship if the base type size is ever retuned.
   text-align matters only in the stretched mobile layout below; on desktop the
   centring comes from the flex parent. */
.ao-event-price-range {
  font-size: calc(var(--text-base) - 4pt);
  text-align: center;
  margin: 0;
}

/* Event detail: "More Information" — heads the Email / Phone / Website group
   that sits below the ticket buttons. Shares .info-section__title, so only the
   spacing differs: it needs room above it to separate from the buttons, which
   a section-opening heading never does. */
.ao-event-more-info-title {
  margin-top: var(--space-6);
}

/* Event detail: Website / Buy Tickets / Discount Tickets buttons on one row. */
.ao-event-detail-buttons {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
}

/* Event detail Location section: address column beside the map on desktop,
   stacked on small screens so the map keeps a usable width. */
.ao-location-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-8);
  align-items: start;
}

/* Location + Accessibility share a left column beside the map on the right, so
   the space next to the (tall) map stays filled. Left column holds the two
   stacked sibling <section>s; right column is the map. */
.ao-locaccess {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-8);
  align-items: start;
}

/* No address → no map → single full-width column. */
.ao-locaccess--no-map {
  grid-template-columns: 1fr;
}

/* Stack Location above Accessibility in the left column. */
.ao-locaccess__col {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
  min-width: 0;
}

@media (max-width: 768px) {
  .ao-location-grid {
    grid-template-columns: 1fr;
    gap: var(--space-6);
  }

  /* Collapse to one column; the map drops below the stacked sections. */
  .ao-locaccess {
    grid-template-columns: 1fr;
    gap: var(--space-6);
  }

  /* Stack email/phone rather than squeezing them side by side. */
  .contact-block.ao-event-contact-row {
    flex-direction: column;
    gap: var(--space-3);
  }

  /* Full-width action buttons are easier to hit on touch screens. */
  .ao-event-detail-buttons .btn {
    width: 100%;
    justify-content: center;
  }

  /* ...which only works if their wrapper is full width too. Left shrink-wrapped,
     the block would size to the button's own text and "100%" would resolve to
     that, undoing the rule above. Stretching it also hands the Price Range the
     full width, so its own text-align is what centres it here. */
  .ao-event-ticket-block {
    display: flex;
    width: 100%;
    align-items: stretch;
  }
}

.contact-block__item {
  display: flex;
  align-items: flex-start;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-ink-light);
}

.contact-block__icon {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  margin-top: 2px;
  color: var(--color-ink-muted);
}

/* Non-linked contact content — e.g. the Contact Name on a classified,
   which is a person to ask for rather than something to click. Kept at the
   item colour so it reads as one row with the icon beside it, and visibly
   apart from the link-coloured rows below it. */
.contact-block__text {
  color: var(--color-ink-light);
}

.contact-block__link {
  color: var(--color-link);
  text-decoration: none;
  transition: color var(--transition-fast);
}

.contact-block__link:hover {
  color: var(--color-accent);
  text-decoration: underline;
}

/* Social links — single inline row of icon + channel name, directly under
   the website URL in the Contact section. */
.contact-social {
  list-style: none;
  margin: var(--space-1) 0 0;
  padding: 0;
  display: flex;
  flex-flow: row wrap;
  align-items: center;
  gap: var(--space-2) var(--space-5);
}

.contact-social__item {
  margin: 0;
}

.contact-social__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-link);
  text-decoration: none;
  transition: color var(--transition-fast);
  white-space: nowrap;
}

.contact-social__link:hover {
  color: var(--color-accent);
  text-decoration: underline;
}

.contact-social__icon {
  display: inline-flex;
  flex-shrink: 0;
  color: var(--color-ink-muted);
  transition: color var(--transition-fast);
}

.contact-social__link:hover .contact-social__icon {
  color: var(--color-accent);
}

.contact-social__icon svg {
  width: 18px;
  height: 18px;
  display: block;
}

/* ---------------------------------------------------------------
   10. Map Section
   --------------------------------------------------------------- */
.listing-map {
  width: 100%;
  aspect-ratio: 16 / 9;
  border-radius: var(--radius-md);
  overflow: hidden;
  background: var(--color-bg-warm);
  border: 1px solid var(--color-rule);
  position: relative; /* needed for Mapbox GL JS absolute positioning */
}

/* Legacy Google Maps iframe (kept for any remaining embeds) */
.listing-map iframe {
  width: 100%;
  height: 100%;
  border: 0;
}

/* Mapbox GL JS fills the container completely */
.listing-map--mapbox {
  /* Mapbox GL JS sets its own canvas dimensions — ensure it fills the container */
}

.listing-map--mapbox .mapboxgl-canvas {
  left: 0;
  top: 0;
}

/* Custom map marker */
.ao-map-marker {
  cursor: pointer;
}

/* Mapbox popup styling */
.mapboxgl-popup-content {
  padding: 12px 14px;
  border-radius: 6px;
  box-shadow: 0 4px 16px rgba(0,0,0,.15);
  font-family: inherit;
}

/* Mapbox link — replaces Google Maps link */
.maps-link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-sm);
  color: var(--color-link);
  text-decoration: none;
  margin-top: var(--space-3);
  transition: color var(--transition-fast);
}

.maps-link:hover {
  color: var(--color-accent);
  text-decoration: underline;
}

.maps-link__icon {
  width: 16px;
  height: 16px;
  color: #ea4335; /* Google red */
}

/* ---------------------------------------------------------------
   Documents (PDF) — detail page list
   --------------------------------------------------------------- */
/* Always carried alongside .listing-detail__info-section on the same element
   (single-ao_classified.php, single-ao_artist.php), and both of those sit in
   a quadrant column, whose rule out-specifies this one — so this padding is
   only ever reached if a documents band is placed outside the quadrants.
   Kept in step with the sections anyway, so that day doesn't reintroduce a
   band 8px taller than everything around it. */
.listing-detail__documents {
  padding: var(--space-6) 0;
  border-bottom: 1px solid var(--color-rule);
}

.document-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.document-list__item {
  margin: 0;
}

.document-list__link {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  font-size: var(--text-base);
  color: var(--color-link);
  text-decoration: none;
  transition: color var(--transition-fast);
}

.document-list__link:hover {
  color: var(--color-accent);
  text-decoration: underline;
}

.document-list__icon {
  flex: 0 0 auto;
  color: var(--color-ink-muted);
}

.document-list__size {
  color: var(--color-ink-muted);
  font-size: var(--text-sm);
}

/* ---------------------------------------------------------------
   Document Upload — form uploader rows
   --------------------------------------------------------------- */
.ao-pdf-uploader__items,
.ao-pdf-uploader__new {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.ao-pdf-uploader__new:not(:empty) {
  margin-top: var(--space-3);
}

.ao-pdf-item {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  flex-wrap: wrap;
  padding: var(--space-3);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-bg-warm);
}

.ao-pdf-item__info {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  min-width: 180px;
  flex: 1 1 220px;
}

.ao-pdf-item__icon {
  flex: 0 0 auto;
  color: var(--color-ink-muted);
}

.ao-pdf-item__filename {
  color: var(--color-link);
  text-decoration: none;
  word-break: break-word;
}

.ao-pdf-item__size {
  color: var(--color-ink-muted);
  font-size: var(--text-sm);
}

.ao-pdf-item__label {
  flex: 1 1 200px;
  min-width: 160px;
}

.ao-pdf-item__remove {
  flex: 0 0 auto;
  background: none;
  border: none;
  font-size: 20px;
  line-height: 1;
  color: var(--color-ink-muted);
  cursor: pointer;
  padding: 0 var(--space-2);
}

.ao-pdf-item__remove:hover {
  color: #b32d2e;
}

.ao-pdf-uploader__add {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-3);
}

.ao-pdf-uploader__count {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

/* ---------------------------------------------------------------
   11. Accessibility Button (e.g. Accessibility Info)
   --------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-3) var(--space-5);
  border-radius: var(--radius-md);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 400;
  cursor: pointer;
  text-decoration: none;
  transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
  border: 1px solid transparent;
  line-height: 1;
}

.btn--outline {
  background: transparent;
  border-color: var(--color-rule);
  color: var(--color-ink-light);
}

.btn--outline:hover {
  border-color: var(--color-ink-light);
  color: var(--color-ink);
  background: var(--color-bg-warm);
}

.btn--primary {
  background: var(--color-accent);
  color: #ffffff;
  border-color: var(--color-accent);
}

.btn--primary:hover {
  background: var(--color-accent-dark);
  border-color: var(--color-accent-dark);
  color: #ffffff;
}


/* ---------------------------------------------------------------
   11b. 404 — nothing matched the requested URL
   --------------------------------------------------------------- */

/* Centred, generously spaced block. Before 404.php existed, a miss fell
   through to index.php's empty-loop branch and printed "Nothing found" in
   `listing-detail__title` — the same class a real listing's <h1> uses — which
   read as a broken listing page rather than a missing one. This is its own
   component so it can never be mistaken for detail-page furniture. */
.error-404 {
  max-width: 34rem;
  margin: 0 auto;
  padding-block: var(--space-10);
  text-align: center;
}

/* Customizer graphic (Appearance → Customize → 404 Page → Graphic), stacked
   above the "404" numeral, which stays on the page either way. The theme's
   global `img { display: block }` means text-align on the parent will not
   centre this, hence the auto margins. Capped at 320px so an oversized upload
   cannot dominate the page, and `height: auto` (inherited from that same
   global rule) keeps whatever aspect ratio the file has. The bottom margin is
   deliberately tighter than the block's other gaps: the graphic and the
   numeral below it read as one unit, not two stacked elements. */
.error-404__image {
  max-width: min(320px, 100%);
  margin: 0 auto var(--space-4);
}

/* Decorative — the code is aria-hidden in the markup, since the status is
   already carried by the 404 response header and the heading below says the
   same thing in words. */
.error-404__code {
  font-family: var(--font-display);
  font-size: var(--text-4xl);
  font-weight: 700;
  line-height: 1;
  color: var(--color-rule);
  margin-bottom: var(--space-4);
}

.error-404__title {
  font-family: var(--font-display);
  font-size: clamp(var(--text-xl), 4vw, var(--text-4xl));
  font-weight: 700;
  line-height: 1.1;
  letter-spacing: -0.02em;
  color: var(--color-ink);
  margin-bottom: var(--space-4);
}

.error-404__text {
  font-size: var(--text-lg);
  color: var(--color-ink-light);
  margin-bottom: var(--space-8);
}

/* Wraps to one button per line on a narrow screen rather than letting the
   two shrink into each other. */
.error-404__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
  margin-bottom: var(--space-10);
}

.error-404__search {
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-rule);
}

.error-404__search-label {
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  margin-bottom: var(--space-3);
}

/* Field + button row. Sized and centred as a unit, capped so the pair stays
   visually tied to the copy above rather than running the width of the block. */
.error-404__search-form {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-2);
  max-width: 24rem;
  margin: 0 auto;
}

/* Matches .ao-blog-search__input (the theme's other search box) so the two
   read as the same control. */
.error-404__search-input {
  flex: 1;
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
}

/* The theme's global :focus-visible rules cover links and buttons only, so a
   text field would otherwise fall back to the browser's default ring. Uses
   --color-focus rather than .ao-blog-search__input's hardcoded blue, so the
   ring follows the site's Brand Kit. */
.error-404__search-input:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
  border-color: var(--color-focus);
}

/* The label wraps at narrow widths otherwise, since the row is a flex
   container that will happily squeeze the button. */
.error-404__search-submit {
  white-space: nowrap;
}

/* ── Tier 2: a Page authored in the block editor takes over ───────────────
   The 34rem cap and centred text above are right for a heading and one line
   of copy, and wrong for a page someone has laid out themselves — a Columns
   or Cover block would be squeezed into a narrow centred strip. The modifier
   releases the wrapper to the container's own width and lets the page's
   blocks control their own alignment, including full-width ones. */
.error-404--custom {
  max-width: none;
}

.error-404__custom {
  text-align: initial;
  margin-bottom: var(--space-10);
}

/* The buttons and search box keep the built-in layout's measure and centring
   even when the content above them does not, so they still read as the page's
   footer rather than as part of whatever was authored. */
.error-404--custom .error-404__actions,
.error-404--custom .error-404__search {
  max-width: 34rem;
  margin-inline: auto;
}

/* ---------------------------------------------------------------
   12. Taxonomy Tags
   --------------------------------------------------------------- */
.tag-list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  padding: 0;
  margin: 0;
}

.tag {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  background: var(--color-bg-warm);
  border: 1px solid var(--color-rule);
  border-radius: 100px;
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-light);
  text-decoration: none;
  transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}

.tag:hover {
  background: var(--color-accent-pale);
  border-color: var(--color-accent);
  color: var(--color-accent-dark);
}

/* Badges rendered "On category type row" (Badges admin tool) — a plain
   flex item inside .tag-list, right after the last pill. The row grows to
   fit a badge taller than the pills on its own: a flex line's height is
   always at least its tallest item's height.

   Vertical centring has to happen on the LIST, not on the badge. Under the
   default `align-items: stretch` every <li> stretched to the full line
   height; the badge's own `align-items: center` (below) then centred it
   inside that stretched box, but each pill is an inline-block sitting at
   the TOP of its own stretched <li>, so pills and badge ended up centred on
   different axes and read as misaligned. Measured on sandbox2's Owl Theatre
   Company page: an 80px row with pill centres at 344.6px and the badge
   centre at 370px. Centring the list puts all three at 370px and leaves the
   row height untouched.

   Scoped to .listing-detail__tags — the detail-page category row is the
   only place this placement renders (all 7 single-ao_*.php templates) — so
   other .tag-list users, e.g. .ao-artist-card__body, are unaffected. */
.listing-detail__tags .tag-list {
  align-items: center;
}

/* Detail-page category row: each top-level category leads its own selected
   sub-categories, and the groups are divided by a vertical rule.

   A group is one <li> holding the parent pill and a nested <ul> of its
   sub-categories (template-parts/listing-tag-row.php) — the relationship the
   rules draw, expressed in the markup as well. Both levels repeat .tag-list's
   own flex + wrap + gap, so a row of pills wraps and spaces exactly as it did
   when every pill was a sibling: the gap between a parent and its first child
   is the same value as the gap between two groups.

   All seven detail templates render this row through
   template-parts/listing-tag-row.php, so all seven group the same way. Other
   .tag-list users outside .listing-detail__tags — e.g. .ao-artist-card__body —
   never emit these classes and are unaffected either way. */
.listing-detail__tags .tag-list__group,
.listing-detail__tags .tag-list__subgroup {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

/* The rule between groups is DRAWN, not typed — do not put a character back
   in `content`. It used to be `content: "|"`, and CSS generated content with a
   non-empty string is exposed to assistive tech in Chrome, Safari and Firefox:
   every group boundary was announced as a stray "vertical bar" in the middle
   of the category list. An empty string is not exposed, so the rule stays
   decoration in fact and not just in intent.

   1px × 12px matches the footprint of the pipe glyph it replaces (measured:
   ~3.5px × 12px at --text-xs), and a drawn rule keeps that height instead of
   inheriting whatever the body font's pipe happens to be. It sits inside the
   group's own flex row, so .tag-list's gap puts it the same distance from the
   pill before it as from the pill after it. */
.listing-detail__tags .tag-list__group--divided::after {
  content: "";
  width: 1px;
  height: var(--text-xs);
  background: var(--color-ink-muted);
}

.listing-detail__category-badge {
  display: flex;
  align-items: center;
}

.listing-detail__category-badge-image {
  display: block;
  max-width: 100%;
  height: auto;
}

/* Badge hover/focus/tap popup (Badges admin tool) — shows the badge's
   Description field content. Shared by both the "On category type row"
   and "On image" placements.

   .ao-badge-hover__trigger carries aria-describedby pointing at the
   popup's id (see artsopolis_octave_wrap_badge_with_hover() in
   functions.php), so the popup is deliberately NEVER display:none — a
   display:none element is pulled out of the accessibility tree, which
   would break that relationship for screen readers regardless of what a
   sighted user's mouse/keyboard is doing. Instead it defaults to the
   standard "visually hidden" clip technique (in the DOM and readable by
   assistive tech, invisible on screen) and only its position/sizing
   flips to the visible floating-bubble treatment on :hover/:focus-within/
   .is-open (.is-open is toggled by assets/js/badge-popup.js for touch
   devices, which have no real :hover state — see that file). */
.ao-badge-hover {
  position: relative;
  display: inline-flex;
}

.ao-badge-hover__trigger {
  display: inline-flex;
  border: 0;
  margin: 0;
  padding: 0;
  background: none;
  cursor: pointer;
}

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

.ao-badge-hover:hover .ao-badge-hover__popup,
.ao-badge-hover:focus-within .ao-badge-hover__popup,
.ao-badge-hover.is-open .ao-badge-hover__popup {
  bottom: 100%;
  left: 50%;
  transform: translateX(-50%);
  margin: 0 0 4px;
  width: max-content;
  height: auto;
  min-width: 160px;
  max-width: 280px;
  padding: var(--space-2) var(--space-3);
  overflow: visible;
  clip: auto;
  background: #ffffff;
  color: #000000;
  font-size: var(--text-xs);
  line-height: 1.5;
  text-align: left;
  white-space: normal;
  border-radius: 3px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.2);
  z-index: 30;
}

/* WCAG 1.4.13 (Content on Hover or Focus) — "Hoverable".
   The popup carries links (badge Descriptions routinely name the program the
   badge belongs to), so the pointer has to be able to reach it — and it could
   not. Two gaps stood between the badge and the bubble: the margin above, and
   the bubble being wider than the badge (measured on the CultureWorks staging
   detail page: a 280px popup centred over a 120px badge, with its link sitting
   80px to the LEFT of the badge's own box). :hover is on the wrapper, which
   shrink-wraps the badge alone, so the natural diagonal move towards that link
   left the wrapper and closed the popup before the pointer ever arrived.

   This transparent strip spans the popup's full width and reaches down onto
   the badge's top edge, making the two boxes one contiguous hover target in
   every direction the link can be approached from. It is a child of the popup,
   so the visually-hidden default state clips it away with everything else
   (and .is-dismissed re-clips it) — it only exists while the popup is shown.
   6px against a 4px gap, so subpixel rounding cannot reopen a dead line. */
.ao-badge-hover:hover .ao-badge-hover__popup::after,
.ao-badge-hover:focus-within .ao-badge-hover__popup::after,
.ao-badge-hover.is-open .ao-badge-hover__popup::after {
  content: "";
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  height: 6px;
}

/* WCAG 1.4.13 (Content on Hover or Focus) — "Dismissible".
   The reveal above is pure CSS, so pressing Escape could not take it back:
   assets/js/badge-popup.js could only clear .is-open (its own touch-tap
   state), which does nothing about :hover / :focus-within. A mouse or
   keyboard user therefore had no way to dismiss the popup at all, and the
   SC's "does not obscure other content" exemption does not apply — measured
   on sandbox2, the bubble sits directly over the <h1> page title.

   badge-popup.js now adds .is-dismissed on Escape and removes it once the
   pointer or focus actually leaves the badge, so the popup hides in place
   (without moving hover or focus, as the SC requires) and still works on the
   next hover. Same specificity as the reveal rule (0,3,0) and placed after
   it, so it wins on source order. */
.ao-badge-hover.is-dismissed .ao-badge-hover__popup {
  position: absolute;
  bottom: auto;
  left: auto;
  transform: none;
  width: 1px;
  height: 1px;
  min-width: 0;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  background: none;
  box-shadow: none;
}

/* Badges rendered "On image" (Badges admin tool) — absolutely positioned
   at one of the image's 4 corners. .ao-badge-image-anchor is a dedicated
   wrapper immediately around the_post_thumbnail() (NOT
   .listing-detail__figure, which toggles position: sticky/static
   responsively) so the badge's containing block never moves
   independently of the image. inline-block so the anchor's own box
   shrink-wraps to the image's actual rendered size, keeping "corner"
   accurate at any width. */
.ao-badge-image-anchor {
  position: relative;
  display: inline-block;
  max-width: 100%;
}

.ao-badge-on-image {
  position: absolute;
  z-index: 20;
}

.ao-badge-on-image__image {
  display: block;
  max-width: none;
}

/* Each corner's badge is flush with that corner, then shifted outward by
   10% of its OWN box (translate() percentages are relative to the
   element's own size) — so roughly 10% of the badge bleeds past the
   image's edge, matching every corner consistently regardless of the
   badge's chosen display size. */
.ao-badge-on-image--top-left {
  top: 0;
  left: 0;
  transform: translate(-10%, -10%);
}

.ao-badge-on-image--top-right {
  top: 0;
  right: 0;
  transform: translate(10%, -10%);
}

.ao-badge-on-image--bottom-left {
  bottom: 0;
  left: 0;
  transform: translate(-10%, 10%);
}

.ao-badge-on-image--bottom-right {
  bottom: 0;
  right: 0;
  transform: translate(10%, 10%);
}

/* ---------------------------------------------------------------
   13. Related Listings Section
   --------------------------------------------------------------- */
.related-listings {
  margin-top: var(--space-16);
  padding-top: var(--space-8);
  border-top: 1px solid var(--color-rule);
}

.related-listings__title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 600;
  margin-bottom: var(--space-6);
  letter-spacing: -0.01em;
}

.related-listings__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-6);
}

.listing-card {
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-bg-card);
  overflow: hidden;
  transition: box-shadow var(--transition-base), transform var(--transition-base);
  text-decoration: none;
  color: inherit;
  display: block;
}

.listing-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.listing-card__image {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
}

.listing-card__body {
  padding: var(--space-4);
}

.listing-card__type {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  margin-bottom: var(--space-2);
}

.listing-card__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 600;
  line-height: 1.2;
  color: var(--color-ink);
  margin-bottom: var(--space-2);
}

.listing-card__date {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

/* Blog "Classic" card only (template-parts/blog-card.php) — the generic
   module card (template-parts/listing-card.php) has its own footer/eyebrow
   layout and doesn't use this wrapper. */
.listing-card__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

.listing-card__author {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

.listing-card__date + .listing-card__author::before {
  content: "\2022";
  margin-right: var(--space-2);
  color: var(--color-ink-muted);
}

/* Shared by template-parts/blog-card.php (Blog "Classic" card),
   template-parts/listing-card.php (generic module card), and
   template-parts/event-listing-card.php — none of them had this rule until
   now, so all three were rendering it with unstyled default <p> margins. */
.listing-card__excerpt {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  line-height: 1.5;
  margin: var(--space-2) 0 0;
}

/* ---------------------------------------------------------------
   14. Site Footer
   --------------------------------------------------------------- */
.site-footer {
  background: var(--color-ink);
  color: #c8c5bf;
  padding-block: var(--space-12);
  margin-top: auto;
}

.site-footer__inner {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  gap: var(--space-8);
}

.footer-col__title {
  font-family: var(--font-display);
  font-size: var(--text-base);
  font-weight: 600;
  color: #ffffff;
  margin-bottom: var(--space-4);
  letter-spacing: 0.01em;
}

.footer-nav {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.footer-nav a {
  color: #c8c5bf;
  font-size: var(--text-sm);
  text-decoration: none;
  transition: color var(--transition-fast);
}

.footer-nav a:hover {
  color: #ffffff;
}

.site-footer__bottom {
  margin-top: var(--space-8);
  padding-top: var(--space-6);
  border-top: 1px solid rgba(255,255,255,0.1);
  display: flex;
  justify-content: space-between;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--space-4);
  font-size: var(--text-xs);
  color: rgba(255,255,255,0.4);
}

/* ---------------------------------------------------------------
   15. Responsive — Tablet (≤768px)
   --------------------------------------------------------------- */
@media (max-width: 768px) {
  /* Side-by-side is a desktop-only enhancement — always collapse to the same
     heading → image → description order on narrow screens, regardless of the
     module's layout setting, and reset the side-by-side-only spacing tweaks
     to the classic stacked values. */
  .listing-detail__body {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    grid-template-areas:
      "heading"
      "image"
      "description";
    row-gap: var(--space-6);
  }

  .listing-detail__figure {
    position: static;
  }

  .listing-detail__image,
  .listing-detail__image-caption {
    width: 100%;
    max-width: 400px;
  }

  .listing-detail__info-grid {
    grid-template-columns: 1fr;
  }

  .listing-detail__quadrants {
    grid-template-columns: 1fr;
  }

  .listing-detail__col--left {
    padding-right: 0;
    border-right: none;
    border-bottom: 1px solid var(--color-rule);
  }

  .listing-detail__col--right {
    padding-left: 0;
  }

  .listing-detail__info-section:nth-child(odd) {
    padding-right: 0;
    border-right: none;
  }

  .listing-detail__info-section:nth-child(even) {
    padding-left: 0;
  }

  .listing-detail__locmap-grid {
    grid-template-columns: 1fr;
  }

  .listing-detail__locmap-address {
    padding-right: 0;
    border-right: none;
  }

  .listing-detail__locmap-map {
    padding-left: 0;
  }

  .site-footer__inner {
    grid-template-columns: 1fr;
  }

  .nav-toggle {
    display: flex;
  }

  .nav-primary__list {
    display: none;
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    /* Customizer → Brand Kit → Colors → Primary */
    background: var(--color-primary);
    border-bottom: 1px solid var(--color-rule);
    flex-direction: column;
    /* Overrides the desktop .nav-primary base rule's align-items: center —
       in that rule it vertically-centers a horizontal row, but here the
       list is flex-direction: column, so the inherited value centers each
       item horizontally instead (shrink-wrapping every pill to its own
       text width, so left position varied per item's text length). */
    align-items: stretch;
    padding: var(--space-4);
    gap: var(--space-1);
    box-shadow: var(--shadow-md);
  }

  .nav-primary[data-open="true"] .nav-primary__list {
    display: flex;
  }

  .nav-primary__item > a {
    /* 20% left inset, scales with device width instead of a fixed px value
       (percentage padding resolves against the containing block's width). */
    padding: 7px var(--space-4) 7px 20%;
    width: 100%;
    border-radius: var(--radius-md);
    color: #fff;
    /* The desktop Menu Item Background Color plate (see the base rule)
       has no place inside this Primary-colored panel. */
    background: transparent;
    text-align: left;
    justify-content: flex-start;
  }

  .nav-primary__item:hover > a,
  .nav-primary__item:focus-within > a,
  .nav-primary__item.is-open > a,
  .nav-primary__item.current-menu-item > a,
  .nav-primary__item.current-menu-ancestor > a,
  .nav-primary__item.current-menu-parent > a {
    background-color: rgba(255, 255, 255, 0.15);
    color: #fff;
  }

  /* Mobile disclosure chevron: points right while collapsed, rotates to
     point down once the sub-menu is open (desktop keeps its own
     down → up hover chevron, unchanged, from the base rule above). */
  .nav-primary__item.menu-item-has-children > a::after,
  .nav-primary__item.nav-primary__item--has-children > a::after {
    transform: rotate(-45deg) translateX(-1px);
  }

  .nav-primary__item:hover > a::after,
  .nav-primary__item:focus-within > a::after,
  .nav-primary__item.is-open > a::after {
    transform: rotate(45deg) translateY(-2px);
  }

  /* Mobile: sub-menus stack inline (no floating panel) and stay collapsed
     until the parent item is tapped — navigation.js sets aria-expanded on
     the parent link on first tap (touch) or on keyboard focus; a second tap
     follows the link normally. */
  .nav-primary__item .sub-menu {
    display: none;
    position: static;
    opacity: 1;
    visibility: visible;
    transform: none;
    transition: none;
    /* Customizer → Brand Kit → Colors → Secondary */
    background: var(--color-secondary);
    border-radius: var(--radius-md);
    margin: 4px 0 8px 0;
    padding: 4px 0;
    box-shadow: none;
    min-width: 0;
  }

  .nav-primary__item > a[aria-expanded="true"] + .sub-menu {
    display: block;
  }

  .nav-primary__item .sub-menu a {
    color: #fff;
    /* Nested 20px deeper than the parent's 20% so sub-items stay visually
       subordinate instead of sitting left of their own parent's text. */
    padding: 8px var(--space-5) 8px calc(20% + 20px);
    text-align: left;
  }

  .nav-primary__item .sub-menu a:hover,
  .nav-primary__item .sub-menu a:focus,
  .nav-primary__item .sub-menu .current-menu-item > a {
    background-color: rgba(255, 255, 255, 0.15);
    color: #fff;
  }

  /* Mobile: anchored-right fix not needed */
  .nav-primary__item:nth-last-child(-n+2) .sub-menu {
    left: auto;
    right: auto;
  }

  .site-header {
    position: relative;
  }

  /* Customizer → Masthead → Graphic on Phones → Hide (body class
     .ao-masthead-graphic--hide-mobile). The graphic goes — background-image
     none here means the phone never fetches it — and the row returns to
     its default 80px floor, since the Masthead Height was raised to give
     the graphic room, not the logo and menu button. */
  .ao-masthead-graphic--hide-mobile .site-header {
    background-image: none;
  }

  .ao-masthead-graphic--hide-mobile .site-header__inner {
    min-height: 80px;
  }

  /* Mobile nav collapses to just the hamburger toggle (the full menu list
     becomes an absolutely-positioned dropdown panel below), so pin it to
     the right edge regardless of the desktop Nav Alignment setting. */
  .site-header__inner .nav-primary {
    justify-self: end;
  }

  /* The desktop/tablet logo overlap effect (.site-branding__logo above)
     isn't a priority on mobile — revert to simple in-flow sizing so a
     Logo Height configured large for the desktop overlap just renders at
     its normal size here (growing the masthead row if needed) instead of
     overlapping the Top Utility Bar on a cramped mobile layout. */
  .site-branding__logo {
    position: static;
    display: flex;
    align-items: center;
    width: auto;
    height: auto;
  }

  .site-branding__logo img {
    position: static;
    width: var(--logo-width, 280px);
    height: var(--logo-height, 80px);
  }
}

/* ---------------------------------------------------------------
   16. Responsive — Mobile (≤480px)
   --------------------------------------------------------------- */
@media (max-width: 480px) {
  .listing-detail__title {
    font-size: var(--text-2xl);
  }

  .listing-detail__info-section {
    padding-block: var(--space-6);
  }

  .site-footer__bottom {
    flex-direction: column;
    text-align: center;
  }
}

/* ---------------------------------------------------------------
   17. Print Styles
   --------------------------------------------------------------- */
@media print {
  .site-header,
  .site-footer,
  .breadcrumb,
  .nav-toggle,
  .listing-detail__bookmark,
  .topbar-icon--favorites,
  .btn,
  .related-listings {
    display: none !important;
  }

  .listing-detail__body {
    grid-template-columns: 200px 1fr;
    grid-template-rows: auto;
    grid-template-areas:
      "heading heading"
      "image   description";
    row-gap: var(--space-6);
  }

  a[href]::after {
    content: ' (' attr(href) ')';
    font-size: 0.75em;
    color: var(--color-ink-muted);
  }
}

/* ---------------------------------------------------------------
   18. Reduced Motion
   --------------------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}

/* ========================================================================
   Gallery Lightbox (detail page)
   ======================================================================== */
.ao-gallery-display {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(180px, 1fr));
  gap: var(--space-3);
  margin: var(--space-6) 0;
}

.ao-gallery-display__item {
  aspect-ratio: 1;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--color-bg-warm);
  cursor: zoom-in;
  transition: transform var(--transition-fast), box-shadow var(--transition-fast);
  padding: 0;
}

.ao-gallery-display__item:hover,
.ao-gallery-display__item:focus {
  transform: scale(1.02);
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  outline: none;
}

.ao-gallery-display__item img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.ao-lightbox {
  position: fixed;
  inset: 0;
  background: rgba(0, 0, 0, 0.92);
  z-index: 9999;
  display: none;
  align-items: center;
  justify-content: center;
  padding: 5vh 5vw;
}

.ao-lightbox.is-open {
  display: flex;
}

.ao-lightbox__inner {
  position: relative;
  max-width: 100%;
  max-height: 100%;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.ao-lightbox__img {
  max-width: 100%;
  max-height: 80vh;
  object-fit: contain;
  border-radius: var(--radius-sm);
}

.ao-lightbox__caption {
  color: #fff;
  font-size: var(--text-sm);
  text-align: center;
  max-width: 600px;
  margin: 0;
  line-height: 1.5;
}

.ao-lightbox__close,
.ao-lightbox__prev,
.ao-lightbox__next {
  position: absolute;
  background: rgba(255, 255, 255, 0.1);
  border: 1px solid rgba(255, 255, 255, 0.3);
  color: #fff;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  font-size: 20px;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color var(--transition-fast);
}

.ao-lightbox__close:hover,
.ao-lightbox__prev:hover,
.ao-lightbox__next:hover {
  background: rgba(255, 255, 255, 0.25);
}

.ao-lightbox__close {
  top: -56px;
  right: 0;
}

.ao-lightbox__prev {
  left: -56px;
  top: 50%;
  transform: translateY(-50%);
}

.ao-lightbox__next {
  right: -56px;
  top: 50%;
  transform: translateY(-50%);
}

@media (max-width: 800px) {
  .ao-lightbox__close {
    top: -52px;
    right: 0;
  }
  .ao-lightbox__prev {
    left: var(--space-2);
    top: auto;
    bottom: var(--space-2);
    transform: none;
  }
  .ao-lightbox__next {
    right: var(--space-2);
    top: auto;
    bottom: var(--space-2);
    transform: none;
  }
}

/* Section divider in submission forms */
.ao-form__section {
  margin-top: var(--space-8);
  padding-top: var(--space-6);
  border-top: 1px solid var(--color-rule);
}

.ao-form__section-title {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  margin-bottom: var(--space-5);
}

/* ---------------------------------------------------------------
   Dashboard layout
   --------------------------------------------------------------- */
.dashboard-layout {
  display: grid;
  grid-template-columns: 210px 1fr; /* was 240px — reduced 30px to give the form more room */
  gap: calc(var(--space-10) - 10px); /* was var(--space-10) (40px) — reduced 10px */
  max-width: var(--body-width);
  margin-inline: auto;
  align-items: start;
}

/* Sidebar nav */
.dashboard-sidebar {
  position: sticky;
  top: calc(60px + var(--space-8));
}

.dashboard-sidebar__user {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-4);
  background: var(--color-bg-warm);
  border-radius: var(--radius-md);
  margin-bottom: var(--space-6);
}

.dashboard-sidebar__avatar {
  width: 40px;
  height: 40px;
  border-radius: 50%;
  background: var(--color-accent-pale);
  border: 2px solid var(--color-accent);
  display: flex;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 700;
  color: var(--color-accent-dark);
  flex-shrink: 0;
}

.dashboard-sidebar__name {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-ink);
  line-height: 1.2;
}

.dashboard-sidebar__role {
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  font-family: var(--font-mono);
  letter-spacing: 0.05em;
}

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

.dashboard-nav__section {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  padding: var(--space-3) var(--space-3) var(--space-2);
  margin-top: var(--space-4);
}

.dashboard-nav__section:first-child {
  margin-top: 0;
}

.dashboard-nav__item a {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-3);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  text-decoration: none;
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.dashboard-nav__item a:hover {
  background: var(--color-bg-warm);
  color: var(--color-ink);
}

.dashboard-nav__item a.is-active {
  background: var(--color-accent-pale);
  color: var(--color-accent-dark);
  font-weight: 600;
}

.dashboard-nav__item a svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

.dashboard-nav__divider {
  border: none;
  border-top: 1px solid var(--color-rule);
  margin: var(--space-4) 0;
}

/* Dashboard main content */
.dashboard-main__header {
  padding-bottom: var(--space-6);
  border-bottom: 2px solid var(--color-ink);
  margin-bottom: var(--space-8);
}

.dashboard-main__eyebrow {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  margin-bottom: var(--space-3);
}

.dashboard-main__title {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: var(--color-ink);
}

/* Welcome / choose listing type cards */
.dashboard-cards {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-5);
  margin-top: var(--space-2);
}

.dashboard-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  text-align: center;
  padding: var(--space-8) var(--space-6);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-lg);
  background: var(--color-bg-card);
  text-decoration: none;
  color: inherit;
  transition: box-shadow var(--transition-base), transform var(--transition-base), border-color var(--transition-base);
}

.dashboard-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-3px);
  border-color: var(--color-accent);
}

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

.dashboard-card__icon {
  width: 48px;
  height: 48px;
  background: var(--color-accent-pale);
  border-radius: 50%;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: var(--space-4);
  color: var(--color-accent-dark);
}

.dashboard-card__icon svg {
  width: 24px;
  height: 24px;
}

.dashboard-card__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 600;
  color: var(--color-ink);
  margin-bottom: var(--space-2);
}

.dashboard-card__description {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  line-height: 1.5;
}

/* Submissions table */
.submissions-table {
  width: 100%;
  border-collapse: collapse;
  font-size: var(--text-sm);
}

.submissions-table th {
  text-align: left;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  padding: var(--space-3) var(--space-4);
  border-bottom: 2px solid var(--color-ink);
}

.submissions-table td {
  padding: var(--space-4) var(--space-4);
  border-bottom: 1px solid var(--color-rule);
  vertical-align: middle;
  color: var(--color-ink-light);
}

.submissions-table tr:last-child td {
  border-bottom: none;
}

.submissions-table tr:hover td {
  background: var(--color-bg-warm);
}

.submissions-table__title {
  font-weight: 600;
  color: var(--color-ink);
}

.submission-status {
  display: inline-block;
  padding: 2px var(--space-3);
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.05em;
  text-transform: uppercase;
}

.submission-status--pending {
  background: #fef3cd;
  color: #856404;
}

.submission-status--publish {
  background: #d1e7dd;
  color: #0a5c36;
}

.submission-status--draft {
  background: var(--color-bg-warm);
  color: var(--color-ink-muted);
}

.submissions-table__actions {
  display: flex;
  gap: var(--space-2);
}

.submissions-table__actions a {
  font-size: var(--text-xs);
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--color-ink-light);
  transition: background-color var(--transition-fast), color var(--transition-fast);
}

.submissions-table__actions a:hover {
  background: var(--color-bg-warm);
  color: var(--color-ink);
}

/* Empty submissions state */
.submissions-empty {
  padding: var(--space-12) var(--space-8);
  text-align: center;
  border: 1px dashed var(--color-rule);
  border-radius: var(--radius-md);
}

.submissions-empty__title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 600;
  color: var(--color-ink);
  margin-bottom: var(--space-3);
}

.submissions-empty__message {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  margin-bottom: var(--space-6);
}

/* ---------------------------------------------------------------
   Responsive
   --------------------------------------------------------------- */
@media (max-width: 768px) {
  .auth-card {
    padding: var(--space-8) var(--space-6);
  }

  .dashboard-layout {
    grid-template-columns: 1fr;
  }

  .dashboard-sidebar {
    position: static;
  }

  .dashboard-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2);
  }

  .dashboard-nav__section {
    display: none;
  }

  .dashboard-nav__item a {
    padding: var(--space-2) var(--space-3);
    border: 1px solid var(--color-rule);
    border-radius: var(--radius-md);
  }

  .dashboard-cards {
    grid-template-columns: 1fr;
  }

  .ao-form__row {
    flex-direction: column;
  }

  .submissions-table {
    display: block;
    overflow-x: auto;
  }
}

/* ---------------------------------------------------------------
   Tags in header (below title)
   --------------------------------------------------------------- */
.listing-detail__tags {
  margin-top: var(--space-4);
  margin-bottom: 0;
}

/* ---------------------------------------------------------------
   Media Gallery — Split Layout
   Thumbnail strip (left) + large preview (right)
   --------------------------------------------------------------- */
.ao-gallery-split {
  margin-top: var(--space-6);
}

.ao-gallery-split__layout {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-8);
  align-items: start;
  margin-top: var(--space-6);
}

/* Thumbnail grid — auto-fill, 3-per-row feel at desktop */
.ao-gallery-split__thumbs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-3);
  align-content: start;
}

.ao-gallery-split__thumb {
  aspect-ratio: 1;
  border: 2px solid var(--color-rule);
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--color-bg-warm);
  cursor: pointer;
  padding: 0;
  transition: border-color var(--transition-fast), transform var(--transition-fast);
}

.ao-gallery-split__thumb:hover {
  border-color: var(--color-ink-light);
  transform: scale(1.03);
}

.ao-gallery-split__thumb.is-active {
  border-color: var(--color-ink);
  box-shadow: 0 0 0 1px var(--color-ink);
}

.ao-gallery-split__thumb img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

/* Large preview panel */
.ao-gallery-split__preview {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.ao-gallery-split__preview-btn {
  display: block;
  width: 100%;
  padding: 0;
  border: none;
  background: none;
  cursor: zoom-in;
  border-radius: var(--radius-sm);
  overflow: hidden;
}

.ao-gallery-split__preview-btn:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

.ao-gallery-split__preview-img {
  width: 100%;
  height: auto;
  display: block;
  border-radius: var(--radius-sm);
  transition: opacity var(--transition-fast);
}

.ao-gallery-split__preview-img.is-loading {
  opacity: 0.5;
}

.ao-gallery-split__caption {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  font-style: italic;
  line-height: 1.5;
  margin: 0;
  min-height: 1.5em; /* prevent layout jump when caption is empty */
}

/* Responsive — tablet: stack columns */
@media (max-width: 768px) {
  .ao-gallery-split__layout {
    grid-template-columns: 1fr;
  }

  /* On mobile show thumbs after preview so preview leads */
  .ao-gallery-split__preview {
    order: -1;
  }

  .ao-gallery-split__thumbs {
    grid-template-columns: repeat(auto-fill, minmax(80px, 1fr));
  }
}

/* ---------------------------------------------------------------
   Media Gallery — Video support additions
   --------------------------------------------------------------- */

/* Thumbnail: video items with play badge overlay */
.ao-gallery-split__thumb {
  position: relative; /* needed for play badge positioning */
}

.ao-gallery-split__play-badge {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-xl);
  color: #fff;
  background: rgba(0, 0, 0, 0.25);
  text-shadow: 0 1px 4px rgba(0,0,0,0.6);
  pointer-events: none;
}

/* Responsive video embed (16:9) */
.ao-gallery-split__video-wrap {
  position: relative;
  width: 100%;
  padding-top: 56.25%; /* 16:9 */
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: #000;
}

.ao-gallery-split__video-frame {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: none;
  display: block;
}

/* ---------------------------------------------------------------
   Associated Events — card grid on org + venue detail pages
   --------------------------------------------------------------- */
.ao-assoc-events {
  margin-top: var(--space-10);
  padding-top: var(--space-8);
  border-top: 1px solid var(--color-rule);
}

.ao-assoc-events__heading {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--color-ink);
  letter-spacing: -0.01em;
  margin-bottom: var(--space-6);
}

.ao-assoc-events__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--space-5);
  list-style: none;
  padding: 0;
  margin: 0;
}

/* ── Event card ── */
.ao-event-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-bg-card);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: box-shadow var(--transition-base), transform var(--transition-base);
}

.ao-event-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.ao-event-card__image-wrap {
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--color-bg-warm);
  flex-shrink: 0;
}

.ao-event-card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--transition-base);
}

.ao-event-card:hover .ao-event-card__image {
  transform: scale(1.03);
}

.ao-event-card__image-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-ink-muted);
  opacity: 0.4;
}

.ao-event-card__image-placeholder svg {
  width: 40px;
  height: 40px;
}

.ao-event-card__body {
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  flex: 1;
}

.ao-event-card__title {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.25;
  color: var(--color-ink);
  margin: 0;
}

.ao-event-card:hover .ao-event-card__title {
  color: var(--color-link);
}

.ao-event-card__date {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
}

/* Responsive — collapse to 2 columns on tablet, 1 on mobile */
@media (max-width: 768px) {
  .ao-assoc-events__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 480px) {
  .ao-assoc-events__grid {
    grid-template-columns: 1fr;
  }
}

/* ---------------------------------------------------------------
   Associated Artists — card grid on the event detail page, below the
   "Upcoming Events from {organization}" section. Same shape as the
   .ao-assoc-events/.ao-event-card pair above, plus a .tag-list/.tag pill
   row for each artist's categories.
   --------------------------------------------------------------- */
.ao-assoc-artists {
  margin-top: var(--space-10);
  padding-top: var(--space-8);
  border-top: 1px solid var(--color-rule);
}

.ao-assoc-artists__heading {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--color-ink);
  letter-spacing: -0.01em;
  margin-bottom: var(--space-6);
}

.ao-assoc-artists__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--space-5);
  list-style: none;
  padding: 0;
  margin: 0;
}

/* ── Artist card ── */
.ao-artist-card {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-bg-card);
  overflow: hidden;
  text-decoration: none;
  color: inherit;
  transition: box-shadow var(--transition-base), transform var(--transition-base);
}

.ao-artist-card:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.ao-artist-card__image-wrap {
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--color-bg-warm);
  flex-shrink: 0;
}

.ao-artist-card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--transition-base);
}

.ao-artist-card:hover .ao-artist-card__image {
  transform: scale(1.03);
}

.ao-artist-card__image-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-ink-muted);
  opacity: 0.4;
}

.ao-artist-card__image-placeholder svg {
  width: 40px;
  height: 40px;
}

.ao-artist-card__body {
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  flex: 1;
}

.ao-artist-card__body .tag-list {
  gap: var(--space-1);
}

.ao-artist-card__title {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.25;
  color: var(--color-ink);
  margin: 0;
}

.ao-artist-card:hover .ao-artist-card__title {
  color: var(--color-link);
}

/* Responsive — collapse to 2 columns on tablet, 1 on mobile */
@media (max-width: 768px) {
  .ao-assoc-artists__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 480px) {
  .ao-assoc-artists__grid {
    grid-template-columns: 1fr;
  }
}

/* ========================================================================
   Favorites — header badge icon/count sizing
   (positioning + count-bubble styling lives with .topbar-icon--favorites
   in the Top Utility Bar section)
   ======================================================================== */
.ao-favorites-badge__icon {
  flex: 0 0 auto;
}

/* ========================================================================
   Favorites — /favorites/ page
   ======================================================================== */
.ao-favorites-page {
  padding-top: var(--space-6);
  padding-bottom: var(--space-8);
}

.ao-favorites-page__header {
  margin-bottom: var(--space-6);
}

.ao-favorites-page__title {
  font-family: var(--font-display);
  font-size: clamp(var(--text-2xl), 4vw, var(--text-3xl));
  font-weight: 700;
  margin: 0 0 var(--space-3);
  line-height: 1.1;
}

.ao-favorites-page__intro {
  color: var(--color-ink-muted);
  margin: 0;
  max-width: 60ch;
}

.ao-favorites-page__loading,
.ao-favorites-page__error {
  color: var(--color-ink-muted);
  font-style: italic;
  padding: var(--space-5) 0;
}

.ao-favorites-page__error {
  color: var(--color-accent);
}

.ao-favorites-page__empty {
  background: var(--color-bg-warm);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  padding: var(--space-6);
  text-align: center;
  color: var(--color-ink-muted);
}

.ao-favorites-page__empty p {
  margin: 0 0 var(--space-2);
}

.ao-favorites-page__empty p:last-child {
  margin-bottom: 0;
}

.ao-favorites-page__empty a {
  color: var(--color-accent);
  text-decoration: underline;
}

.ao-favorites-page__empty svg {
  vertical-align: -0.15em;
  color: var(--color-accent);
}

.ao-favorites-section {
  margin-bottom: var(--space-7);
}

.ao-favorites-section:last-child {
  margin-bottom: 0;
}

.ao-favorites-section__header {
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  padding-bottom: var(--space-2);
  margin-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-rule);
}

.ao-favorites-section__title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 600;
  margin: 0;
}

.ao-favorites-section__count {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  font-variant-numeric: tabular-nums;
}

.ao-favorites-section__empty {
  color: var(--color-ink-muted);
  font-style: italic;
  margin: 0;
}

.ao-favorites-list {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.ao-favorites-item {
  position: relative;
  display: grid;
  grid-template-columns: 100px 1fr auto;
  align-items: center;
  gap: var(--space-4);
  padding: var(--space-3) var(--space-4);
  background: #fff;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.ao-favorites-item:hover {
  border-color: var(--color-accent);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}

.ao-favorites-item__thumb {
  display: block;
  width: 100px;
  height: 100px;
  border-radius: var(--radius-sm);
  overflow: hidden;
  background: var(--color-bg-warm);
  border: 1px solid var(--color-rule);
  flex: 0 0 auto;
}

.ao-favorites-item__thumb-img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.ao-favorites-item__thumb--empty {
  display: flex;
  align-items: center;
  justify-content: center;
}

.ao-favorites-item__thumb-placeholder {
  font-size: 28px;
  opacity: 0.4;
}

.ao-favorites-item__body {
  min-width: 0; /* allow text truncation within grid */
}

.ao-favorites-item__title-wrap {
  margin: 0;
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.3;
}

.ao-favorites-item__title {
  color: var(--color-ink);
  text-decoration: none;
}

.ao-favorites-item__title:hover,
.ao-favorites-item__title:focus {
  color: var(--color-accent);
  text-decoration: underline;
}

.ao-favorites-item__date {
  margin: 4px 0 0;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  font-variant-numeric: tabular-nums;
}

.ao-favorites-item__remove {
  background: transparent;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  width: 32px;
  height: 32px;
  cursor: pointer;
  color: var(--color-ink-muted);
  font-size: 18px;
  line-height: 1;
  padding: 0;
  transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}

.ao-favorites-item__remove:hover,
.ao-favorites-item__remove:focus {
  background: var(--color-accent-pale);
  color: var(--color-accent);
  border-color: var(--color-accent);
}

.ao-favorites-item__remove:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

@media (max-width: 480px) {
  .ao-favorites-item {
    grid-template-columns: 72px 1fr auto;
    gap: var(--space-3);
  }
  .ao-favorites-item__thumb {
    width: 72px;
    height: 72px;
  }
}

/* ==========================================================================
   Share Button + Dialog
   ========================================================================== */

/* Share trigger button — mirrors .listing-detail__bookmark styling */
.listing-detail__share {
  background: none;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  padding: var(--space-1) var(--space-2);
  cursor: pointer;
  color: var(--color-ink-muted);
  font-size: var(--text-md);
  transition: color var(--transition-fast), border-color var(--transition-fast);
  line-height: 1;
  /* Glyph over caption (2.102.0) — see .listing-detail__action-label. */
  display: inline-flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  min-width: 44px;
}

/* Blog detail templates only (template-parts/share-button.php) — 10%
   smaller than the shared 18px (var(--text-md)) base, without touching the
   event detail page's copy, which reuses .listing-detail__share alone. */
.post-detail__share-btn {
  font-size: 16.2px;
}

/* Sized in em, not by the attributes: this theme's `img, video, svg
   { height: auto }` reset collapses an attribute-only inline SVG inside a
   flex parent. 1em keeps the icon tied to the font-size above, so the
   .post-detail__share-btn modifier below still shrinks it. */
.listing-detail__share svg {
  width: 1em;
  height: 1em;
  flex: none;
}

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

.listing-detail__share:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* Dialog backdrop */
.ao-share-dialog {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: flex;
  align-items: center;
  justify-content: center;
}

.ao-share-dialog[hidden] {
  display: none;
}

.ao-share-dialog__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.45);
  cursor: pointer;
}

/* Dialog panel */
.ao-share-dialog__panel {
  position: relative;
  background: var(--color-surface, #fff);
  border-radius: var(--radius-md, 8px);
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.18);
  padding: var(--space-7) var(--space-8);
  width: min(400px, calc(100vw - var(--space-8)));
  /* With the QR panel expanded the popup is ~560px tall; on a phone held
     sideways it must scroll rather than run off both ends of the screen. */
  max-height: min(90vh, 800px);
  overflow-y: auto;
  overscroll-behavior: contain;
  z-index: 1;
}

.ao-share-dialog__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  margin-bottom: var(--space-5);
  padding-bottom: var(--space-4);
  border-bottom: 1px solid var(--color-rule);
}

.ao-share-dialog__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: 1.2;
  color: var(--color-ink);
  margin: 0;
}

.ao-share-dialog__close {
  background: none;
  border: none;
  cursor: pointer;
  color: var(--color-ink-muted);
  font-size: var(--text-lg);
  padding: var(--space-1);
  border-radius: var(--radius-sm);
  line-height: 1;
  transition: color var(--transition-fast);
  display: flex;
  align-items: center;
  justify-content: center;
}

.ao-share-dialog__close svg {
  width: 1em;
  height: 1em;
}

.ao-share-dialog__close:hover {
  color: var(--color-ink);
}

.ao-share-dialog__close:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* Share options: a single row of brand icons, no background colours. */
.ao-share-dialog__options {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: row;
  align-items: center;
  justify-content: center;
  gap: var(--space-5);
}

.ao-share-dialog__option {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 50%;
  background: transparent;
  text-decoration: none;
  color: var(--color-ink);
  transition: color var(--transition-fast), background var(--transition-fast), transform var(--transition-fast);
}

.ao-share-dialog__option:hover {
  color: var(--color-primary);
  background: var(--color-bg-warm);
  transform: translateY(-1px);
}

.ao-share-dialog__option:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 3px;
}

.ao-share-dialog__option svg {
  /* 32px — doubled from the 16px (1rem) these shipped at, which read as too
     small inside the 48px circles. The button box is unchanged, so the tap
     target is still the same and stays above the WCAG 2.5.8 minimum. */
  width: 2rem;
  height: 2rem;
}

/* X, LinkedIn, Threads and Print sit 5% smaller (30.4px) than Facebook. Their
   glyphs fill more of the 24-unit viewBox than the Facebook circle does, so at
   an equal box they read heavier; trimming them evens the row out visually. */
.ao-share-dialog__option--x svg,
.ao-share-dialog__option--linkedin svg,
.ao-share-dialog__option--threads svg,
.ao-share-dialog__option--print svg {
  width: 1.9rem;
  height: 1.9rem;
}

@media (prefers-reduced-motion: reduce) {
  .ao-share-dialog__option:hover {
    transform: none;
  }
}

/* ==========================================================================
   Add to Calendar Dialog (template-parts/add-to-calendar-dialog.php)

   Reuses .ao-share-dialog for the backdrop, panel, header and close button so
   the two popups on an event page are visibly the same object. Only the body
   differs: a date picker and two full-width labelled rows, rather than the
   share dialog's single row of icon-only circles.

   The trigger needs no rules of its own — it carries .listing-detail__share,
   which already sizes and colours it, and .listing-detail__calendar exists as
   a hook for per-site overrides.
   ========================================================================== */

/* A little wider than the share dialog: these rows carry a title and a line
   of explanatory text, not a bare icon.

   Capped and scrollable, which the share dialog never needed: this panel grows
   with the content — four destinations, a date picker, the "all dates" note and
   the subscribe block — and on a short viewport (a phone in landscape, a small
   laptop) it would otherwise run off both ends of the screen with no way to
   reach the lower half. */
.ao-calendar-dialog .ao-share-dialog__panel {
  width: min(460px, calc(100vw - var(--space-8)));
  max-height: min(90vh, 800px);
  overflow-y: auto;
  overscroll-behavior: contain;
}

.ao-calendar-dialog__picker {
  margin-bottom: var(--space-5);
}

.ao-calendar-dialog__label {
  display: block;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-ink);
  margin-bottom: var(--space-2);
}

.ao-calendar-dialog__select {
  width: 100%;
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  background: var(--color-surface, #fff);
  color: var(--color-ink);
  font-family: inherit;
  font-size: var(--text-sm);
  line-height: 1.4;
}

.ao-calendar-dialog__select:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.ao-calendar-dialog__options {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.ao-calendar-dialog__option {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  padding: var(--space-3) var(--space-4);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--color-ink);
  transition: color var(--transition-fast), border-color var(--transition-fast), background var(--transition-fast);
}

.ao-calendar-dialog__option:hover {
  color: var(--color-primary);
  border-color: var(--color-accent);
  background: var(--color-bg-warm);
}

.ao-calendar-dialog__option:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

.ao-calendar-dialog__option-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: none;
  color: var(--color-ink-muted);
}

/* Sized explicitly. The theme's `img, video, svg { height: auto }` reset
   collapses an attribute-only inline SVG to zero height inside a flex row. */
.ao-calendar-dialog__option-icon svg {
  width: 1.25rem;
  height: 1.25rem;
  flex: none;
}

.ao-calendar-dialog__option:hover .ao-calendar-dialog__option-icon {
  color: inherit;
}

.ao-calendar-dialog__option-text {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 0;
}

.ao-calendar-dialog__option-title {
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.3;
}

.ao-calendar-dialog__option-hint {
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  line-height: 1.3;
}

/* "All dates" selected: Google's create-event URL takes one date range, so the
   option is genuinely unavailable. Kept visible and focusable — see the note
   below it — rather than removed mid-interaction. */
.ao-calendar-dialog__option.is-disabled {
  cursor: not-allowed;
  opacity: 0.55;
}

.ao-calendar-dialog__option.is-disabled:hover {
  color: var(--color-ink);
  border-color: var(--color-rule);
  background: transparent;
}

.ao-calendar-dialog__note {
  margin: var(--space-4) 0 0;
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--color-ink);
  background: var(--color-bg-warm);
  border-radius: var(--radius-sm);
  padding: var(--space-3);
}

.ao-calendar-dialog__note[hidden] {
  display: none;
}

.ao-calendar-dialog__tz {
  margin: var(--space-4) 0 0;
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  text-align: center;
}

/* Names the event when the dialog was opened from a listing card, where the
   page holds many. Hidden on a detail page, whose <h1> already says it. */
.ao-calendar-dialog__event {
  margin: 0 0 var(--space-4);
  font-size: var(--text-sm);
  font-weight: 600;
  line-height: 1.35;
  color: var(--color-ink);
}

.ao-calendar-dialog__event[hidden] {
  display: none;
}

/* Loading / error line, shown in place of the body while a card's payload is
   being fetched. Given the body's rough height so the panel does not visibly
   jump when the dates arrive. */
.ao-calendar-dialog__status {
  margin: 0;
  padding: var(--space-6) var(--space-3);
  min-height: 8rem;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-size: var(--text-sm);
  line-height: 1.5;
  color: var(--color-ink-muted);
}

.ao-calendar-dialog__status[hidden],
.ao-calendar-dialog__body[hidden],
.ao-calendar-dialog__picker[hidden] {
  display: none;
}

/* The .ics option is the universal fallback rather than a fourth service, so
   it is set slightly apart from the three that open a website. The card's own
   calendar button needs no rules: .listing-card__action (archive.css) already
   sizes and colours all four icons in that row. */
.ao-calendar-dialog__option--file {
  margin-top: var(--space-2);
}

/* ==========================================================================
   Subscribe to the presenting organization's calendar

   Set apart from the four options above by a rule and a lighter treatment,
   because it is a different proposition: those add one event, this starts a
   standing subscription that keeps updating itself. Deliberately quieter — the
   dialog was opened to save an event, and this is an offer alongside that, not
   a competing call to action.
   ========================================================================== */
.ao-calendar-subscribe {
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-rule);
}

.ao-calendar-subscribe[hidden] {
  display: none;
}

.ao-calendar-subscribe__title {
  margin: 0 0 var(--space-1);
  font-family: var(--font-display);
  font-size: var(--text-sm);
  font-weight: 700;
  line-height: 1.3;
  color: var(--color-ink);
  /* A long organization name must wrap rather than widen the panel. */
  overflow-wrap: anywhere;
}

.ao-calendar-subscribe__blurb {
  margin: 0 0 var(--space-3);
  font-size: var(--text-xs);
  line-height: 1.5;
  color: var(--color-ink-muted);
}

.ao-calendar-subscribe__options {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
}

/* Compact chips, not full-width rows: these are secondary to the four
   destinations above, and three of them stacked would out-weigh the thing the
   dialog is actually for. */
.ao-calendar-subscribe__option {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: var(--space-2) var(--space-3);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  background: none;
  font-family: inherit;
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: 1.2;
  color: var(--color-ink);
  text-decoration: none;
  cursor: pointer;
  transition: color var(--transition-fast), border-color var(--transition-fast), background var(--transition-fast);
}

.ao-calendar-subscribe__option:hover {
  color: var(--color-primary);
  border-color: var(--color-accent);
  background: var(--color-bg-warm);
}

.ao-calendar-subscribe__option:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
}

/* Sized explicitly — the theme's `svg { height: auto }` reset collapses an
   attribute-only inline SVG inside a flex row. */
.ao-calendar-subscribe__icon {
  display: inline-flex;
  align-items: center;
  flex: none;
  color: var(--color-ink-muted);
}

.ao-calendar-subscribe__icon svg {
  width: 0.9375rem;
  height: 0.9375rem;
  flex: none;
}

.ao-calendar-subscribe__option:hover .ao-calendar-subscribe__icon {
  color: inherit;
}

.ao-calendar-subscribe__option.is-copied {
  color: var(--color-primary);
  border-color: var(--color-accent);
}

/* Revealed only when the clipboard is unavailable, so the visitor can copy the
   URL by hand instead of pressing a button that does nothing. */
.ao-calendar-subscribe__url {
  width: 100%;
  margin-top: var(--space-2);
  padding: var(--space-2);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  color: var(--color-ink);
  background: var(--color-bg-warm);
}

.ao-calendar-subscribe__url[hidden] {
  display: none;
}

/* ========================================================================
   Standard Pages (page.php)
   ======================================================================== */
.page-detail {
  padding-top: var(--space-7);
  padding-bottom: var(--space-8);
  /* Width is governed by the `.container` class also applied to this element,
     which respects the Layout Widths Customizer setting (--body-width). */
}

.page-detail__header {
  margin-bottom: var(--space-6);
  padding-bottom: var(--space-5);
  border-bottom: 1px solid var(--color-rule);
}

.page-detail__title {
  font-family: var(--font-display);
  font-size: clamp(var(--text-2xl), 4vw, var(--text-4xl));
  font-weight: 700;
  line-height: 1.1;
  margin: 0;
  color: var(--color-ink);
}

.page-detail__image-wrap {
  margin: 0 0 var(--space-6);
}

.page-detail__image {
  width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
  display: block;
}

/* Content area — applies "prose" styling to whatever the editor outputs */
.page-detail__content,
.post-detail__content {
  font-size: var(--text-md);
  line-height: 1.75;
  color: var(--color-ink);
}

.page-detail__content > * + *,
.post-detail__content > * + * {
  margin-top: var(--space-5);
}

.page-detail__content h2,
.post-detail__content h2 {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: 1.2;
  margin-top: var(--space-7);
}

.page-detail__content h3,
.post-detail__content h3 {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 600;
  line-height: 1.3;
  margin-top: var(--space-6);
}

.page-detail__content h4,
.post-detail__content h4 {
  font-size: var(--text-lg);
  font-weight: 600;
  margin-top: var(--space-5);
}

.page-detail__content a,
.post-detail__content a {
  color: var(--color-accent);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.page-detail__content a:hover,
.post-detail__content a:hover {
  color: var(--color-accent-dark);
}

.page-detail__content img,
.post-detail__content img {
  max-width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
}

.page-detail__content ul,
.post-detail__content ul,
.page-detail__content ol,
.post-detail__content ol {
  padding-left: var(--space-6);
}

.page-detail__content li + li,
.post-detail__content li + li {
  margin-top: var(--space-2);
}

.page-detail__content blockquote,
.post-detail__content blockquote {
  border-left: 3px solid var(--color-accent);
  padding-left: var(--space-5);
  font-style: italic;
  color: var(--color-ink-muted);
  margin-left: 0;
  margin-right: 0;
}

.page-detail__content code,
.post-detail__content code {
  background: var(--color-bg-warm);
  padding: 2px 6px;
  border-radius: var(--radius-sm);
  font-size: 0.9em;
}

.page-detail__content pre,
.post-detail__content pre {
  background: var(--color-bg-warm);
  padding: var(--space-4);
  border-radius: var(--radius-sm);
  overflow-x: auto;
  font-size: var(--text-sm);
  line-height: 1.5;
}

.page-detail__content pre code,
.post-detail__content pre code {
  background: transparent;
  padding: 0;
}

.page-detail__content hr,
.post-detail__content hr {
  border: 0;
  border-top: 1px solid var(--color-rule);
  margin: var(--space-7) 0;
}

.page-detail__content table,
.post-detail__content table {
  width: 100%;
  border-collapse: collapse;
  margin: var(--space-5) 0;
}

.page-detail__content th,
.page-detail__content td,
.post-detail__content th,
.post-detail__content td {
  border: 1px solid var(--color-rule);
  padding: var(--space-2) var(--space-3);
  text-align: left;
}

.page-detail__content th,
.post-detail__content th {
  background: var(--color-bg-warm);
  font-weight: 600;
}

/* WP block-editor alignment helpers */
.page-detail__content .alignleft,
.post-detail__content .alignleft {
  float: left;
  margin: 0 var(--space-5) var(--space-3) 0;
}

.page-detail__content .alignright,
.post-detail__content .alignright {
  float: right;
  margin: 0 0 var(--space-3) var(--space-5);
}

.page-detail__content .aligncenter,
.post-detail__content .aligncenter {
  display: block;
  margin-left: auto;
  margin-right: auto;
}

/* …but not on an image block's <figure>. Core's image-block CSS draws a
   captioned, aligned figure as display: table with its <figcaption> as
   display: table-caption, so the caption is exactly as wide as the image.
   The block rule above beat that (same specificity, later in source), and a
   table-caption with no table around it gets an anonymous table of its own
   that shrinks to the longest word — the caption rendered one letter per
   line under the image (2.100.0). Restoring display: table keeps the
   centring: auto margins centre a table just as they centre a block. */
.page-detail__content .wp-block-image .aligncenter,
.post-detail__content .wp-block-image .aligncenter,
.page-detail__content .wp-block-image.aligncenter,
.post-detail__content .wp-block-image.aligncenter {
  display: table;
}

.page-detail__content .wp-caption,
.post-detail__content .wp-caption {
  max-width: 100%;
}

/* Grid layout Group blocks (2.116.3). Written when the theme had no
   blockGap support, so WordPress dropped a block's own "Block spacing"
   value and core's fallback :where(.is-layout-grid) { gap: 0.5em } was all
   that applied — cards ended up ~10px apart. 2em matches core's Columns
   block gap, so a Grid of cards spaces like the Columns rows it replaces.
   Since 2.118.0 (appearance-tools on in functions.php) a Grid that sets
   its own Block spacing prints a per-block .wp-container-* gap later at
   equal specificity and wins; this stays the default for Grids that set
   none. Plain class selector beats the zero-specificity :where().
   Mirrored in editor.css. */
.is-layout-grid {
  gap: 2em;
}

/* Image captions — the classic-editor .wp-caption-text and the block
   editor's figcaption.wp-element-caption alike (2.100.0: the block caption
   used to inherit body copy at full size). */
.page-detail__content .wp-caption-text,
.post-detail__content .wp-caption-text,
.page-detail__content .wp-element-caption,
.post-detail__content .wp-element-caption {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  text-align: center;
  margin-top: var(--space-2);
}

/* Page/post pagination (wp_link_pages) */
.page-detail__pagination,
.post-detail__pagination {
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-rule);
  display: flex;
  align-items: baseline;
  gap: var(--space-3);
  flex-wrap: wrap;
}

.page-detail__pagination-label,
.post-detail__pagination-label {
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

.page-detail__pagination-link,
.post-detail__pagination-link {
  padding: var(--space-1) var(--space-3);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  font-variant-numeric: tabular-nums;
}

/* ========================================================================
   Full Width Pages (page-full-width.php, and any page.php page built with
   a page builder — see artsopolis_octave_is_builder_page())
   ======================================================================== */

/* Deliberately the inverse of .page-detail: no `.container`, so no
   --body-width ceiling and no --gutter, and no vertical padding either, so a
   builder's first section meets the site header with nothing between them.
   The site header and footer are untouched and keep their own
   --header-width / --footer-width settings. */
.page-full {
  padding-top: 0;
  padding-bottom: 0;
}

/* .site-main's own padding-block (48px / 80px) has to go too, or a builder's
   first section floats below the masthead instead of meeting it, and its last
   section leaves a band of page background above the footer. Same technique as
   the breadcrumb collapse further up this file.

   Keyed on __canvas rather than .page-full so it applies only to builder
   output — the __prose variant is ordinary running text and still wants the
   breathing room. */
.site-main:has(.page-full__canvas) {
  padding-block: 0;
}

/* Builder output is left completely bare — sections carry their own
   backgrounds edge to edge and their own typography. Nothing is styled here
   on purpose; anything added would be competing with the builder. */
.page-full__canvas {
  width: 100%;
}

/* Editor content on this template still gets .page-detail__content prose
   styling (applied together in the template), but needs the measure back —
   without .container it would otherwise run the full width of the viewport.
   A block marked full or wide alignment opts back out, which is what makes
   a full-bleed block layout possible alongside ordinary paragraphs. */
.page-full__prose > * {
  max-width: var(--body-width);
  margin-inline: auto;
  padding-inline: var(--gutter);
}

.page-full__prose > .alignfull,
.page-full__prose > .alignwide {
  max-width: none;
  padding-inline: 0;
}

/* ========================================================================
   Standard Blog Posts (single.php)
   ======================================================================== */
.post-detail {
  padding-top: var(--space-7);
  padding-bottom: var(--space-8);
  /* Width is governed by the `.container` class also applied to this element,
     which respects the Layout Widths Customizer setting (--body-width). */
}

.post-detail__header {
  margin-bottom: var(--space-6);
}

/* Wraps .post-detail__categories + the share button (template-parts/share-button.php)
   in all 4 detail templates (Billboard reuses this exact class too, inside
   its shaded band — see its own dark-bg override for .post-detail__category
   further down), so the share trigger sits 30px to the right of the
   category badges instead of at the bottom of the page. Always rendered —
   even with no categories — so the share button has a consistent home
   either way. */
.post-detail__header-top {
  display: flex;
  align-items: center;
  gap: 30px;
  margin-bottom: var(--space-3);
}

.post-detail__header-top .post-detail__categories {
  margin-bottom: 0;
}

.post-detail__categories {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-3);
}

.post-detail__category {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  font-weight: 600;
  color: var(--color-accent);
  text-decoration: none;
}

.post-detail__category:hover {
  text-decoration: underline;
}

.post-detail__title {
  font-family: var(--font-display);
  font-size: clamp(var(--text-2xl), 4.5vw, var(--text-4xl));
  font-weight: 700;
  line-height: 1.1;
  margin: 0 0 var(--space-3);
  color: var(--color-ink);
}

.post-detail__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

.post-detail__date {
  font-variant-numeric: tabular-nums;
}

.post-detail__image-wrap {
  margin: 0 0 var(--space-6);
}

.post-detail__image {
  width: 100%;
  height: auto;
  border-radius: var(--radius-sm);
  display: block;
}

.post-detail__tags {
  margin-top: var(--space-6);
  padding-top: var(--space-4);
  border-top: 1px solid var(--color-rule);
}

.post-detail__nav {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
  margin-top: var(--space-7);
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-rule);
}

.post-detail__nav-link {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: var(--space-4);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  text-decoration: none;
  color: var(--color-ink);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.post-detail__nav-link:hover,
.post-detail__nav-link:focus {
  border-color: var(--color-accent);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
}

.post-detail__nav-link--next {
  text-align: right;
  grid-column: 2;
}

.post-detail__nav-link--prev:only-child {
  grid-column: 1 / 2;
}

.post-detail__nav-label {
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-ink-muted);
  font-weight: 600;
}

.post-detail__nav-title {
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.3;
}

@media (max-width: 600px) {
  .post-detail__nav {
    grid-template-columns: 1fr;
  }
  .post-detail__nav-link--next {
    text-align: left;
    grid-column: 1;
  }
}

/* ========================================================================
   Page with Right Sidebar Template
   ======================================================================== */
.page-with-sidebar {
  display: grid;
  grid-template-columns: minmax(0, 1fr) var(--sidebar-width);
  gap: var(--space-8);
  padding-top: var(--space-7);
  padding-bottom: var(--space-8);
}

.page-with-sidebar__main {
  /* Override the centered max-width from .page-detail since the grid handles layout here */
  max-width: none;
  margin: 0;
  padding-top: 0;
  padding-bottom: 0;
}

.page-with-sidebar__sidebar {
  /* Allow sidebar to sit slightly higher than the centered narrow page */
  padding-top: var(--space-1);
}

.page-with-sidebar__sidebar .widget {
  margin-bottom: var(--space-6);
}

.page-with-sidebar__sidebar .widget__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: 1.2;
  margin: 0 0 var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 2px solid var(--color-ink);
}

.page-with-sidebar__sidebar ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.page-with-sidebar__sidebar li {
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-rule);
  font-size: var(--text-sm);
}

.page-with-sidebar__sidebar li:last-child {
  border-bottom: 0;
}

.page-with-sidebar__sidebar a {
  color: var(--color-ink);
  text-decoration: none;
}

.page-with-sidebar__sidebar a:hover,
.page-with-sidebar__sidebar a:focus {
  color: var(--color-accent);
  text-decoration: underline;
}

.page-with-sidebar__sidebar-empty {
  padding: var(--space-4);
  background: var(--color-bg-warm);
  border: 1px dashed var(--color-rule);
  border-radius: var(--radius-sm);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

/* Stack on tablet and smaller */
@media (max-width: 900px) {
  .page-with-sidebar {
    grid-template-columns: 1fr;
    gap: var(--space-6);
  }
}

/* -----------------------------------------------------------------------
   Module Right Column (Classifieds + other directory modules)
   Detail pages: two columns (content + right widgets).
   Listing pages handle their own three-column grid in archive.css.
   The .ao-right-column aside and .ao-right-widget styles below are shared
   by both layouts.
   ----------------------------------------------------------------------- */
.ao-with-right {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 300px;
  gap: var(--space-10);
  align-items: start;
  padding-top: var(--space-8);
  padding-bottom: var(--space-8);
}

.ao-with-right__main {
  min-width: 0;
}

/* The article inside the two-column wrapper no longer needs its own
   container width — the grid governs it. */
.ao-with-right__main > .listing-detail {
  max-width: none;
  margin: 0;
  padding-left: 0;
  padding-right: 0;
}

.ao-with-right .ao-right-column {
  position: sticky;
  top: calc(60px + var(--space-8));
  min-width: 0;
}

/* Shared right-column widget styling. */
.ao-right-column {
  min-width: 0;
}

.ao-right-widget {
  margin-bottom: var(--space-8);
}

.ao-right-widget:last-child {
  margin-bottom: 0;
}

.ao-right-widget__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 700;
  line-height: 1.2;
  margin: 0 0 var(--space-3);
  padding-bottom: var(--space-2);
  border-bottom: 2px solid var(--color-ink);
}

.ao-right-widget ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.ao-right-widget li {
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-rule);
  font-size: var(--text-sm);
}

.ao-right-widget li:last-child {
  border-bottom: 0;
}

.ao-right-widget a {
  color: var(--color-ink);
  text-decoration: none;
}

.ao-right-widget a:hover,
.ao-right-widget a:focus {
  color: var(--color-accent);
  text-decoration: underline;
}

@media (max-width: 900px) {
  .ao-with-right {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }

  .ao-with-right .ao-right-column {
    position: static;
  }
}


/* ========================================================================
   ARTSOPOLIS OCTAVE — HOMEPAGE / BRAND-KIT COMPONENTS
   Everything below consumes the Brand Kit CSS variables that
   functions.php → artsopolis_octave_output_brand_kit_css() emits.
   ======================================================================== */

/* -----------------------------------------------------------------------
   Top Utility Bar
   ----------------------------------------------------------------------- */
.site-topbar {
  background: var(--topbar-bg-color, var(--color-secondary));
  color: #fff;
  font-size: var(--text-sm);
}

.site-topbar__inner {
  display: flex;
  justify-content: flex-end;
  align-items: center;
  gap: var(--space-3);
  /* --topbar-height is the TOTAL bar height (Customizer → Top Utility Bar
     → Bar Height), not a floor with extra padding stacked on top — there is
     intentionally no padding-block here. Content (buttons/icons) is
     vertically centered within it by align-items. Buttons need ~38px
     (padding + line-height) to avoid clipping, so min-height acts as a
     graceful floor if a smaller value is entered. */
  min-height: var(--topbar-height, 44px);
}

.site-topbar__actions {
  display: flex;
  align-items: center;
  gap: var(--space-3);
}

.topbar-btn {
  display: inline-block;
  background: var(--color-primary);
  color: #fff;
  font-size: var(--text-sm);
  font-weight: 500;
  padding: 8px 18px;
  border-radius: var(--topbar-btn-radius, var(--radius-pill));
  text-decoration: none;
  transition: background var(--transition-fast), color var(--transition-fast), border-radius var(--transition-fast);
}

.topbar-btn:hover,
.topbar-btn:focus {
  background: var(--color-accent);
  color: #fff;
  text-decoration: none;
}

/* Flat button style (Top Utility Bar → Subscribe / Login Button Style =
   "Flat text"). Applies to Subscribe, Member Login, and the My Account
   toggle alike since they all share .topbar-btn. Drops the pill background
   and shape entirely, leaving just colored text. */
.site-topbar__actions--flat-buttons .topbar-btn {
  background: transparent;
  color: var(--topbar-btn-text-color, #fff);
  padding: 8px 10px;
  border-radius: 0;
}

.site-topbar__actions--flat-buttons .topbar-btn:hover,
.site-topbar__actions--flat-buttons .topbar-btn:focus {
  background: transparent;
  color: var(--topbar-btn-text-color, #fff);
  text-decoration: underline;
}

/* Account dropdown (logged-in "My Account" button + menu) */
.topbar-account {
  position: relative;
  display: inline-block;
}

.topbar-account__toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border: 0;
  cursor: pointer;
  font: inherit;
  font-weight: 500;
}

.topbar-account__toggle:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

.topbar-account__caret {
  transition: transform var(--transition-fast);
}

.topbar-account__toggle[aria-expanded="true"] .topbar-account__caret {
  transform: rotate(180deg);
}

.topbar-account__menu {
  position: absolute;
  top: calc(100% + 6px);
  right: 0;
  z-index: 200;
  min-width: 180px;
  margin: 0;
  padding: 6px 0;
  list-style: none;
  background: #fff;
  border-radius: var(--radius-md, 8px);
  box-shadow: 0 6px 24px rgba(0,0,0,0.18);
}

.topbar-account__menu[hidden] {
  display: none;
}

.topbar-account__menu li {
  margin: 0;
}

.topbar-account__menu a {
  display: block;
  padding: 9px 18px;
  color: var(--color-ink, #1a1a1a);
  font-size: var(--text-sm);
  text-decoration: none;
  white-space: nowrap;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.topbar-account__menu a:hover,
.topbar-account__menu a:focus {
  background: var(--color-secondary);
  color: #fff;
  text-decoration: none;
}

.topbar-account__menu a:focus-visible {
  outline: 2px solid #fff;
  outline-offset: -2px;
}

.topbar-account__logout {
  border-top: 1px solid rgba(0,0,0,0.08);
  margin-top: 4px;
}

.topbar-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--topbar-icon-size, 32px);
  height: var(--topbar-icon-size, 32px);
  background: transparent;
  border: 0;
  border-radius: var(--radius-pill);
  color: var(--topbar-icon-color, #fff);
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast), width var(--transition-fast), height var(--transition-fast);
}

.topbar-icon:hover,
.topbar-icon:focus {
  background: rgba(255,255,255,0.1);
  background: color-mix(in srgb, currentColor 14%, transparent);
}

/* The hover/focus tint above is subtle (14% opacity) and, on its own, is
   a weak keyboard-focus indicator — unlike the adjacent My Account toggle,
   which already gets a solid outline. Add one here too (WCAG 2.4.7).
   currentColor tracks --topbar-icon-color, which is contrast-checked
   against --topbar-bg-color in the Customizer (see
   customizer-a11y-warnings.js), so the outline stays visible together
   with the icon itself. */
.topbar-icon:focus-visible {
  outline: 2px solid currentColor;
  outline-offset: 2px;
}

/* Icon glyph scales with the button (Customizer → Top Utility Bar →
   Favorites & Search Icon Size), keeping the original 16px-in-a-32px-box
   ratio. Overrides the SVGs' inline width/height attributes in header.php. */
.topbar-icon svg {
  width: calc(var(--topbar-icon-size, 32px) * 0.5);
  height: calc(var(--topbar-icon-size, 32px) * 0.5);
}

/* Favorites icon — count badge overlaid on the icon (hydrated by favorites.js) */
.topbar-icon--favorites {
  position: relative;
}

.topbar-icon--favorites .ao-favorites-badge__count {
  position: absolute;
  top: 2px;
  right: 2px;
  min-width: clamp(14px, calc(var(--topbar-icon-size, 32px) * 0.4), 24px);
  height: clamp(14px, calc(var(--topbar-icon-size, 32px) * 0.4), 24px);
  padding: 0 3px;
  border-radius: var(--radius-pill);
  /* --color-primary's default now clears 4.5:1 on its own (see the token),
     so this no longer has to rescue the default. It is kept because the
     count sits in small (10-14px) bold text that doesn't reach the "large
     text" exemption, and --color-primary is Customizer-settable: the extra
     10% darkening buys margin for a site that picks a borderline colour.
     Falls back to the plain colour where color-mix is unsupported. */
  background: var(--color-primary);
  background: color-mix(in srgb, var(--color-primary) 90%, black 10%);
  color: #fff;
  font-size: clamp(10px, calc(var(--topbar-icon-size, 32px) * 0.28), 14px);
  font-weight: 700;
  line-height: clamp(14px, calc(var(--topbar-icon-size, 32px) * 0.4), 24px);
  text-align: center;
  font-variant-numeric: tabular-nums;
}

.topbar-icon--favorites[data-count="0"] .ao-favorites-badge__count {
  opacity: 0.6;
}

@media (max-width: 600px) {
  .site-topbar__inner {
    flex-wrap: wrap;
    justify-content: center;
  }
}

/* -----------------------------------------------------------------------
   Header Tagline
   ----------------------------------------------------------------------- */
.site-tagline {
  margin: 4px 0 0 0;
  font-size: var(--text-xs);
  /* Customizer → Masthead → Tagline Color; see .site-title a above. */
  color: var(--masthead-tagline-color, var(--color-ink-muted));
  letter-spacing: 0.05em;
  text-transform: uppercase;
  font-weight: 500;
}

/* -----------------------------------------------------------------------
   Hero Band
   ----------------------------------------------------------------------- */
.ao-hero {
  width: 100%;
  overflow: hidden;
  line-height: 0;
}

.ao-hero__image {
  width: 100%;
  height: auto;
  display: block;
}

.ao-hero__link {
  display: block;
  line-height: 0;
}

/* Shortcode-rendered hero (e.g., Artsopolis Advertising plugin output).
   Center the banner since ad creatives may not span 1920px wide; the
   plugin emits inline-block wrappers which would otherwise float left. */
.ao-hero--shortcode {
  text-align: center;
  background: var(--color-bg-warm);
}

.ao-hero--shortcode .aa-banner-wrap,
.ao-hero--shortcode .aa-zone-wrap {
  display: inline-block;
  max-width: 100%;
}

.ao-hero--shortcode .aa-banner-img {
  max-width: 100%;
  height: auto;
  display: block;
  margin: 0 auto;
}

/* -----------------------------------------------------------------------
   Homepage main layout (events left, sidebar right)
   ----------------------------------------------------------------------- */
.hp-main {
  padding-top: var(--space-8);
  padding-bottom: var(--space-12);
}

/* Homepage editor content wrapper. The assigned Front Page's content
   renders inside the left column of .hp-layout; the events grid (placed
   by editors via [ao_events_grid]) and any other shortcodes/blocks live
   here. Inherits prose typography from the global type scale. */
.hp-content {
  font-size: var(--text-base);
  line-height: 1.6;
}

.hp-content > * + * {
  margin-top: var(--space-5);
}

/* Events grid placed in homepage content shouldn't have prose spacing
   above/below — its own internal spacing handles it. */
.hp-content > .hp-events {
  margin-top: 0;
}

.hp-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 320px;
  gap: var(--space-10);
  align-items: start;
}

/* When no sidebar widgets are configured (and the aside element is
   not rendered), collapse the grid to a single column so the events
   grid uses the full width instead of leaving a 320px empty gap. */
.hp-layout--no-sidebar {
  grid-template-columns: 1fr;
}

@media (max-width: 1024px) {
  .hp-layout {
    grid-template-columns: 1fr;
    gap: var(--space-8);
  }
}

/* -----------------------------------------------------------------------
   Homepage Events Grid
   ----------------------------------------------------------------------- */
.hp-events__header {
  margin-bottom: var(--space-5);
}

.hp-events__title {
  font-family: var(--font-display);
  font-size: var(--text-3xl);
  font-weight: 400;
  /* Brand Kit -> Colors -> Primary (was Secondary until 2.87.3), so the
     grid heading matches the site's primary brand colour wherever the
     [ao_featured_events_grid] shortcode is placed. */
  color: var(--color-primary);
  margin: 0;
}

.hp-events__tabs {
  display: flex;
  flex-wrap: wrap;
  gap: 2px;
  margin-bottom: var(--space-6);
  border-bottom: 1px solid var(--color-rule);
}

.hp-events__tab {
  background: transparent;
  border: 1px solid transparent;
  border-bottom: 0;
  padding: 10px 18px;
  font-family: var(--font-body);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--color-ink-muted);
  cursor: pointer;
  border-radius: var(--radius-md) var(--radius-md) 0 0;
  transition: background var(--transition-fast), color var(--transition-fast);
}

.hp-events__tab:hover {
  background: var(--color-bg-warm);
  color: var(--color-ink);
}

.hp-events__tab--active {
  background: var(--color-primary);
  color: #fff;
}

.hp-events__tab--active:hover {
  background: var(--color-primary);
  color: #fff;
}

.hp-events__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
}

@media (max-width: 800px) {
  .hp-events__grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 500px) {
  .hp-events__grid { grid-template-columns: 1fr; }
}

.hp-events__footer {
  margin-top: var(--space-6);
  text-align: right;
}

.hp-events__view-all {
  display: inline-block;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: none;
}

.hp-events__view-all:hover { text-decoration: underline; }

.hp-events__empty,
.hp-events__no-results {
  padding: var(--space-8);
  background: var(--color-bg-warm);
  border-radius: var(--radius-md);
  text-align: center;
  color: var(--color-ink-muted);
}

/* Toggled by the category tabs. .hp-events sets a grid/flow context, so
   re-assert hiding for the attribute the script uses. */
.hp-events__no-results[hidden] {
  display: none;
}

/* -----------------------------------------------------------------------
   Event Card
   ----------------------------------------------------------------------- */
.ao-event-card {
  position: relative;
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  overflow: hidden;
  display: flex;
  flex-direction: column;
  transition: transform var(--transition-base), box-shadow var(--transition-base);
}

.ao-event-card:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

.ao-event-card__date-badge {
  position: absolute;
  top: 12px;
  left: 12px;
  z-index: 2;
  background: var(--color-secondary);
  color: #fff;
  width: 56px;
  height: 56px;
  border-radius: var(--radius-pill);
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  font-family: var(--font-body);
  line-height: 1;
  box-shadow: var(--shadow-sm);
}

.ao-event-card__month {
  font-size: 10px;
  font-weight: 600;
  letter-spacing: 0.08em;
  margin-top: 2px;
}

.ao-event-card__day {
  font-size: 20px;
  font-weight: 700;
  margin: 1px 0;
}

.ao-event-card__year {
  font-size: 9px;
  opacity: 0.85;
  margin-bottom: 2px;
}

.ao-event-card__media {
  display: block;
  background: var(--color-bg-warm);
  aspect-ratio: 4 / 3;
  overflow: hidden;
}

.ao-event-card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.ao-event-card__image--placeholder {
  background: linear-gradient(135deg, var(--color-bg-warm), var(--color-rule));
}

.ao-event-card__body {
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  flex: 1;
}

.ao-event-card__title {
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.3;
  margin: 0;
}

.ao-event-card__title a {
  color: var(--color-ink);
  text-decoration: none;
}

.ao-event-card__title a:hover { color: var(--color-primary); }

.ao-event-card__venue {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  margin: 0;
  line-height: 1.4;
}

.ao-event-card__cta {
  display: inline-block;
  align-self: flex-start;
  margin-top: auto;
  padding: 6px 14px;
  background: var(--color-primary);
  color: #fff;
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  border-radius: var(--radius-pill);
  text-decoration: none;
  transition: background var(--transition-fast);
}

.ao-event-card__cta:hover {
  background: var(--color-accent);
  color: #fff;
  text-decoration: none;
}

/* -----------------------------------------------------------------------
   Homepage Sidebar Widgets
   ----------------------------------------------------------------------- */
.hp-layout__sidebar {
  display: flex;
  flex-direction: column;
  gap: var(--space-6);
}

.hp-widget {
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  padding: var(--space-5);
}

.hp-widget__title {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 400;
  color: var(--color-secondary);
  margin: 0 0 var(--space-3) 0;
}

.hp-widget a {
  color: var(--color-primary);
}

.hp-widget ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.hp-widget li {
  padding: var(--space-2) 0;
  border-bottom: 1px solid var(--color-rule);
}

.hp-widget li:last-child { border-bottom: 0; }

/* -----------------------------------------------------------------------
   Sponsors Band
   ----------------------------------------------------------------------- */
.hp-sponsors {
  background: var(--color-paper);
  padding-block: var(--space-12);
  border-top: 1px solid var(--color-rule);
}

.hp-sponsors__title {
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.15em;
  text-transform: uppercase;
  color: var(--color-primary);
  text-align: center;
  margin: 0 0 var(--space-8) 0;
}

.hp-sponsors__logos {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: var(--space-10);
}

.sponsor-logo img {
  max-height: 80px;
  width: auto;
  height: auto;
  filter: none;
  opacity: 0.9;
  transition: opacity var(--transition-fast);
}

.sponsor-logo:hover img {
  opacity: 1;
}

/* -----------------------------------------------------------------------
   Partners Directory
   ----------------------------------------------------------------------- */
.hp-partners {
  background: var(--color-paper);
  padding-block: var(--space-10);
  border-top: 1px solid var(--color-rule);
}

.hp-partners__title {
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: 600;
  color: var(--color-secondary);
  text-align: center;
  margin: 0 0 var(--space-5) 0;
}

.hp-partners__list {
  font-size: var(--text-sm);
  line-height: 1.9;
  color: var(--color-ink-muted);
  text-align: center;
  margin: 0;
  max-width: 980px;
  margin-inline: auto;
}

.hp-partners__name {
  display: inline;
  white-space: nowrap;
}

.hp-partners__sep {
  color: var(--color-rule);
  margin: 0 6px;
}

/* -----------------------------------------------------------------------
   Footer (redesigned 4-column + dark indigo)
   ----------------------------------------------------------------------- */
.site-footer {
  background: var(--color-secondary);
  color: #fff;
  padding-block: var(--space-12) var(--space-6);
}

.site-footer__inner {
  display: grid;
  grid-template-columns: 2fr 1fr 1fr 1fr;
  gap: var(--space-8);
  margin-bottom: var(--space-8);
}

@media (max-width: 900px) {
  .site-footer__inner {
    grid-template-columns: 1fr 1fr;
  }
  .footer-col--about { grid-column: 1 / -1; }
}

@media (max-width: 540px) {
  .site-footer__inner {
    grid-template-columns: 1fr;
  }
}

.footer-col__title {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 400;
  color: #fff;
  margin: 0 0 var(--space-4) 0;
  letter-spacing: 0.02em;
}

.footer-col--about .footer-col__title {
  font-size: var(--text-xl);
}

/* Customizer → Footer Settings → About Column → About Image: centered in
   the column, above the About Text and beneath the column title. Sized by
   its own Width field (an inline width on the <img>), else at its natural
   size within the column. */
.footer-about-image {
  margin: 0 0 var(--space-4) 0;
  text-align: center;
}

.footer-about-image__img {
  display: inline-block;
  max-width: 100%;
  height: auto;
}

.footer-about-text {
  font-size: var(--text-sm);
  line-height: 1.6;
  color: rgba(255,255,255,0.85);
  margin: 0 0 var(--space-4) 0;
  max-width: 28em;
}

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

.footer-nav li {
  padding: 4px 0;
}

.footer-nav a {
  color: rgba(255,255,255,0.85);
  text-decoration: none;
  font-size: var(--text-sm);
  transition: color var(--transition-fast);
}

.footer-nav a:hover {
  color: #fff;
  text-decoration: underline;
}

.footer-nav--inline {
  display: flex;
  flex-direction: row;
  gap: var(--space-4);
}

.site-footer__bottom {
  border-top: 1px solid rgba(255,255,255,0.15);
  /* Customizer → Footer → Copyright → "Copyright bar height": the bar
     element carries --footer-copyright-height (min-height) and zeroes
     --footer-copyright-pad, so the number is the bar's full height with
     its content centred. Blank: 16px padding above the text. */
  padding-top: var(--footer-copyright-pad, var(--space-4));
  min-height: var(--footer-copyright-height, auto);
  box-sizing: border-box;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-3);
  font-size: var(--text-xs);
  color: rgba(255,255,255,0.7);
}

.site-footer__bottom p {
  margin: 0;
}

/* Social links inside footer */
.site-footer .footer-social {
  display: flex;
  flex-direction: row;
  list-style: none;
  padding: 0;
  margin: var(--space-3) 0 0 0;
  gap: var(--space-3);
}

.site-footer .footer-social li {
  padding: 0;
}

.site-footer .footer-social__link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  opacity: 0.85;
  transition: opacity var(--transition-fast);
}

.site-footer .footer-social__link:hover {
  opacity: 1;
}

/* -----------------------------------------------------------------------
   Footer — Custom Blocks
   Enabled via Appearance → Customize → Footer Settings → Custom Blocks
   (ao_footer_block_count > 0). Renders template-parts/footer-custom-blocks.php
   instead of the default 4-column footer above. Each .footer-block-custom-N
   wrapper holds the rendered block content of a Page chosen in the
   Customizer — background, logo, columns, and headings all come from
   whatever blocks were used on that page, not from theme CSS. Intentionally
   minimal: no max-width here, so a full-width Group block background on the
   page spans edge-to-edge with no extra alignfull plumbing needed.
   ----------------------------------------------------------------------- */
.site-footer--custom-blocks {
  padding: 0;
}

/* Per-block padding override (Footer Settings → Custom Blocks → Block N —
   Padding) comes in as a --footer-block-padding custom property on the
   .footer-block-custom-N wrapper; 0 here is what's used when an admin
   leaves it blank, preserving the original edge-to-edge default. */
.footer-block-custom {
  padding: var(--footer-block-padding, 0);
  /* Customizer "Block N — Background Color"; transparent when unset so the
     Page's own blocks keep supplying the background. */
  background-color: var(--footer-block-bg-color, transparent);
}

.footer-block-custom > .wp-block-group,
.footer-block-custom > .wp-block-columns {
  margin-block: 0;
}

/* The Copyright/Social bar always gets its own dark band — unlike the
   blocks above it (which supply their own background via the block
   editor), this bar has no page content of its own to draw a background
   from. */
.footer-bottom-band {
  background-color: var(--color-secondary);
  color: #fff;
  /* Customizer → Footer → Copyright → "Copyright bar height" — see
     .site-footer__bottom above. The band is a flex column so its inner
     row sits vertically centred inside whatever height is set. */
  padding-block: var(--footer-copyright-pad, var(--space-4));
  min-height: var(--footer-copyright-height, auto);
  box-sizing: border-box;
  display: flex;
  align-items: center;
}

.footer-bottom-band > .container {
  width: 100%;
}

/* Page-authored links (List/Paragraph/etc. from the block editor) inherit
   the theme's global `a { color: var(--color-link) }`, which is tuned for
   light page backgrounds and has too little contrast against a typical
   dark footer block background. Default to a light, footer-appropriate
   color instead of touching the global link color. Per-block overrides
   (Footer Settings → Custom Blocks → Block N — Link Color / Link Hover
   Color) come in as --footer-block-link-color / --footer-block-link-hover-color
   custom properties on the .footer-block-custom-N wrapper; these var()
   fallbacks are what's used when an admin leaves them blank. */
.footer-block-custom a {
  color: var(--footer-block-link-color, rgba(255, 255, 255, 0.85));
  text-decoration-color: var(--footer-block-link-color, rgba(255, 255, 255, 0.5));
}

.footer-block-custom a:hover,
.footer-block-custom a:focus-visible {
  color: var(--footer-block-link-hover-color, #fff);
  text-decoration-color: var(--footer-block-link-hover-color, #fff);
}

/* Logo/sponsor grids built as a Cover block (for a background image or
   color) wrapping a Kadence Table block of images are common in footer
   Custom Blocks (e.g. funder logos). Two things break on narrow screens:
   1. Core's Cover block defaults to a flat 430px min-height with no
      responsive variant — fine once the table below is full width, but a
      big empty gap once that table shrinks. Let it hug its content instead.
   2. A Kadence Table is a literal <table> and doesn't reflow — the browser
      keeps every column and just squeezes each cell, shrinking images to
      near nothing. table/tbody/tr get the classic responsive-table
      treatment (display: block, so each row stays a self-contained block
      and cell order can't shuffle across rows) and td becomes an
      inline-block so its images wrap to ~2 per row instead of 4.
   Scoped to .footer-block-custom so this doesn't touch Cover or Table
   blocks used elsewhere on the site. */
@media (max-width: 768px) {
  .footer-block-custom .wp-block-cover {
    min-height: 0;
  }

  .footer-block-custom .kb-table-container {
    max-width: 100%;
  }

  .footer-block-custom table.kb-table,
  .footer-block-custom table.kb-table tbody,
  .footer-block-custom table.kb-table tr {
    display: block;
  }

  .footer-block-custom table.kb-table td {
    display: inline-block;
    width: calc(50% - 1rem);
    vertical-align: middle;
  }
}

.footer-bottom-band .site-footer__bottom {
  /* The inner row inherits .site-footer__bottom's margin-top (the gap the
     Simple layout keeps between its columns and the bar). Inside the band
     that margin only inflated the band's height above the text, beyond
     anything the height setting could reach — zero it here. */
  margin-top: 0;
  border-top: 0;
  padding-top: 0;
}

.footer-bottom-band .footer-social {
  margin-top: 0;
}

/* Customizer → Footer → Copyright → "Copyright Background Color". The bar
   element carries --footer-copyright-bg and --footer-copyright-ink (white or
   dark ink, whichever reads better on that background — decided in PHP by
   artsopolis_octave_prefers_light_text()) plus a --tinted modifier class.
   Simple layout: the bar is normally a hairline-topped row over the footer's
   own background, so a tint needs its own inner padding and loses the
   hairline. Custom Blocks: the band already has padding; only the colors
   change. Links in a tinted bar take the ink color too, so a light tint
   does not leave the footer menu's light links unreadable. */
.site-footer__bottom--tinted {
  background-color: var(--footer-copyright-bg);
  color: var(--footer-copyright-ink);
  border-top: 0;
  padding: var(--footer-copyright-pad, var(--space-4)) var(--space-4);
}

.footer-bottom-band--tinted {
  background-color: var(--footer-copyright-bg);
  color: var(--footer-copyright-ink);
}

.site-footer__bottom--tinted a,
.site-footer__bottom--tinted .footer-nav a,
.footer-bottom-band--tinted a,
.footer-bottom-band--tinted .footer-nav a {
  color: var(--footer-copyright-ink);
}


/* ========================================================================
   EVENT SEARCH WIDGET — [ao_event_search]
   ======================================================================== */
.ao-event-search {
  background: var(--color-paper);
  padding: var(--space-6);
  border-radius: var(--radius-md);
  border: 1px solid var(--color-rule);
  /* Size container for the stacked (narrow) layout — see the
     @container ao-ev-search block further down. The classified widget
     (.ao-event-search.ao-classified-search) overrides the name with its
     own, later in the file, so its query keeps working. */
  container-type: inline-size;
  container-name: ao-ev-search;
}

.ao-event-search__heading {
  display: flex;
  align-items: center;
  gap: var(--space-3);
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  color: var(--color-ink);
  margin: 0 0 var(--space-5) 0;
}

/* Search glyph before the heading: the archive sidebar's keyword-submit
   button look (dark plate, white magnifier — .sidebar-search__btn in
   archive.css), sized to the heading's cap height. The SVG is sized
   explicitly because the theme's global svg { height: auto } reset would
   otherwise collapse it. */
.ao-event-search__heading-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 1.15em;
  height: 1.15em;
  border-radius: var(--radius-sm);
  background: var(--color-ink);
  color: #ffffff;
}

.ao-event-search__heading-icon svg {
  width: 16px;
  height: 16px;
}

/* Mobile "Advanced Search" disclosure — inert by default. The wrapper is
   display:contents so the fields inside it stay direct grid items and every
   placement rule in this file still reaches them; the toggle, the Close
   control and the keyword field's own submit glyph are hidden. archive.css's
   ≤600px block is the ONLY place that turns the wrapper into a collapsible
   unit and reveals the three controls — on phones, for every instance of the
   widget (theme 2.94.0); at wider viewports a widget in a right column is
   untouched. */
.ao-event-search__advanced {
  display: contents;
}

.ao-event-search__advanced-toggle,
.ao-event-search__advanced-close,
.ao-event-search__keyword-submit {
  display: none;
}


/* Inside a sidebar / right-column widget wrapper — the Homepage Sidebar's
   .hp-widget, a module right column's .ao-right-widget, the Primary
   Sidebar's .widget (page-with-sidebar.php) or the archive sidebar's
   widget-area block — the column already frames each widget (border,
   radius, padding). The form drawing its own frame inside that doubled the
   inset, so its fields ended up narrower than a plain text widget's content
   in the same column. Drop the inner frame there so the form's fields and
   heading sit flush with the neighbouring widgets' content. The container
   query still keys off the form's width, now the widget's content width. */
.hp-widget .ao-event-search,
.ao-right-widget .ao-event-search,
.page-with-sidebar__sidebar .widget .ao-event-search,
.sidebar-widget--widget-area .ao-event-search {
  background: transparent;
  border: 0;
  border-radius: 0;
  padding: 0;
}

/* Grid layout — four equal columns, filled in source order (theme 2.113.0):
     Row 1: keyword  | dates (start, end, presets — three columns)
     Row 2: category | Official Tags | organization | venue
     Row 3: city     | accessibility |              | Search + Reset
   Auto-placement rather than fixed cells, so a field an admin has switched
   off closes its gap instead of leaving a hole. The date block only spans
   three columns — no start line, so it takes the cells beside the keyword
   rather than dropping to a row of its own — and the buttons are pinned to
   column 4, which auto-placement puts after the last field (on that field's
   row when column 4 is free, else the next). Until 2.113.0 the dates were
   pinned to column 1 and shared the last row with the buttons. Replaced
   the old 2 + actions grid whose cell collisions needed per-combination
   modifier classes. The classified widget keeps that older grid — scoped
   rules for it follow. */
.ao-event-search__grid {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: var(--space-3);
  align-items: stretch;
}

/* Field wrappers (each contains a label + input) */
.ao-event-search__field {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.ao-event-search__dates {
  grid-column: span 3;
}

.ao-event-search__actions {
  grid-column: 4 / span 1;
  display: flex;
  flex-direction: row;
  gap: var(--space-2);
  /* Centred, not stretched: in a narrower container the date block wraps
     to two lines and the buttons would otherwise grow to that height. */
  align-items: center;
  min-width: 0;
}

/* Classified search widget ([ao_classified_search]):
     keyword | category | [Search]
     state   | city     | [Reset]
   One class deeper than the event rules above; the ≤900px and ≤560px blocks
   below match that depth so they still win here. */
.ao-classified-search .ao-event-search__grid {
  grid-template-columns: 1fr 1fr auto;
}
.ao-classified-search .ao-event-search__field--keyword  { grid-column: 1; grid-row: 1; }
.ao-classified-search .ao-event-search__field--category { grid-column: 2; grid-row: 1; }
.ao-classified-search .ao-event-search__field--state    { grid-column: 1; grid-row: 2; }
.ao-classified-search .ao-event-search__field--city     { grid-column: 2; grid-row: 2; }
/* Single-state service area: no State field, so City takes the whole row. */
.ao-classified-search--no-state .ao-event-search__field--city { grid-column: 1 / span 2; }
.ao-classified-search .ao-event-search__actions         { grid-column: 3; grid-row: 1 / span 2; flex-direction: column; }

/* The category and accessibility fields use the archive sidebar's
   .ao-multiselect control (defined in archive.css, which loads site-wide).
   That control is sized for a narrow sidebar; here it sits in a row beside
   native <select>s, so its trigger is matched to them — same height, padding,
   type size and ground — instead of reading as a different kind of control.
   Everything inside the panel keeps its own sizing. */
.ao-event-search .ao-multiselect__toggle {
  min-height: 44px;
  padding: 12px 14px;
  font-size: var(--text-base);
  background: var(--color-paper);
  box-sizing: border-box;
}

/* The panel overlays the fields below it, so it has to clear the date row and
   the preset chips rather than sliding under them. */
.ao-event-search .ao-multiselect__panel {
  z-index: 30;
}

/* Form controls — shared styling for inputs and selects */
.ao-event-search input[type="search"],
.ao-event-search input[type="date"],
.ao-event-search select {
  display: block;
  width: 100%;
  padding: 12px 14px;
  font-family: var(--font-body);
  font-size: var(--text-base);
  color: var(--color-ink);
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
  min-height: 44px;
  box-sizing: border-box;
}

.ao-event-search input:focus,
.ao-event-search select:focus {
  outline: 0;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 2px rgba(33, 125, 191, 0.15);
}

/* Same ink as the dropdowns' resting text ("Select Category" etc. — the
   <select>s above and the .ao-multiselect toggles), so the keyword and date
   placeholders read as one row of controls with them (theme 2.115.0; was
   #737373, the front-end form placeholder grey). */
.ao-event-search input::placeholder {
  color: var(--color-ink);
  opacity: 1;
}

/* iOS Safari only — -webkit-touch-callout exists in no other engine. Two
   WebKit-on-iOS quirks with native date inputs: an EMPTY one renders no
   text at all (placeholder is ignored, there is no calendar glyph), and
   the control's intrinsic sizing wins over width:100% inside a flex row,
   so the two pickers overflowed the widget and grew to ~110px tall.
   Flatten the control (-webkit-appearance:none), pin the box, and draw the
   placeholder ourselves from the placeholder attribute until the input
   holds a value (.has-value, kept in step by archive-sidebar.js). */
@supports (-webkit-touch-callout: none) {
  .ao-event-search input[type="date"] {
    -webkit-appearance: none;
    appearance: none;
    display: flex;
    align-items: center;
    width: 100%;
    min-width: 0;
    height: 44px;
    min-height: 44px;
    padding-top: 0;
    padding-bottom: 0;
    text-align: left;
  }

  .ao-event-search input[type="date"]::-webkit-date-and-time-value {
    text-align: left;
    min-height: 1.3em;
  }

  .ao-event-search input[type="date"]:not(.has-value)::before {
    content: attr(placeholder);
    color: var(--color-ink); /* matches ::placeholder above */
  }

  .ao-event-search input[type="date"]:focus::before {
    content: none;
  }
}

/* Select arrow: hide native, add our own (consistent across browsers) */
.ao-event-search select {
  appearance: none;
  -webkit-appearance: none;
  background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 12 12'><path d='M3 4.5l3 3 3-3' stroke='%23666' stroke-width='1.5' fill='none' stroke-linecap='round' stroke-linejoin='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 12px;
  padding-right: 36px;
}

/* Category dropdown — replaces a native <select> so subcategories can nest
   under their parent (an arrow toggle reveals them), matching the archive
   sidebar's .sidebar-category-group pattern (see archive.css). See
   template-parts/ao-event-search.php. */
.ao-category-dropdown {
  position: relative;
}

.ao-category-dropdown__trigger {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  width: 100%;
  padding: 12px 14px;
  font-family: var(--font-body);
  font-size: var(--text-base);
  color: var(--color-ink);
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  min-height: 44px;
  box-sizing: border-box;
  cursor: pointer;
  transition: border-color var(--transition-fast), box-shadow var(--transition-fast);
}

.ao-category-dropdown__trigger:focus,
.ao-category-dropdown__trigger[aria-expanded="true"] {
  outline: 0;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 2px rgba(33, 125, 191, 0.15);
}

.ao-category-dropdown__trigger span {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.ao-category-dropdown__chevron {
  flex-shrink: 0;
  color: #666;
  transition: transform var(--transition-fast);
}

.ao-category-dropdown__trigger[aria-expanded="true"] .ao-category-dropdown__chevron {
  transform: rotate(180deg);
}

.ao-category-dropdown__panel {
  position: absolute;
  top: calc(100% + 4px);
  left: 0;
  right: 0;
  z-index: 20;
  max-height: 320px;
  overflow-y: auto;
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  padding: var(--space-2);
}

.ao-category-dropdown__option {
  display: block;
  width: 100%;
  text-align: left;
  padding: var(--space-2);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
  background: transparent;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
}

.ao-category-dropdown__option:hover,
.ao-category-dropdown__option:focus {
  background: var(--color-bg-warm);
  outline: 0;
}

.ao-category-dropdown__option[aria-selected="true"] {
  background: var(--color-accent-pale);
  color: var(--color-accent-dark);
  font-weight: 600;
}

.ao-category-dropdown__group-row {
  display: flex;
  align-items: center;
  gap: var(--space-1);
}

.ao-category-dropdown__group-row .ao-category-dropdown__option {
  flex: 1;
  min-width: 0;
}

.ao-category-dropdown__toggle {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  height: 24px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--color-ink-muted);
  cursor: pointer;
  border-radius: var(--radius-sm);
  flex-shrink: 0;
  transition: background-color var(--transition-fast);
}

.ao-category-dropdown__toggle:hover,
.ao-category-dropdown__toggle:focus {
  background: var(--color-bg-warm);
  color: var(--color-ink);
  outline: 0;
}

.ao-category-dropdown__arrow {
  transition: transform var(--transition-fast);
}

.ao-category-dropdown__toggle[aria-expanded="true"] .ao-category-dropdown__arrow {
  transform: rotate(90deg);
}

.ao-category-dropdown__children {
  display: flex;
  flex-direction: column;
  gap: 1px;
  padding-left: calc(24px + var(--space-1));
}

/* [hidden] and .ao-category-dropdown__children are equal specificity, and
   author styles beat the UA stylesheet's [hidden] { display: none } on a
   tie — so display:flex above would otherwise always win and the JS's
   hidden-attribute toggle would have no visual effect. This raises the
   collapsed state's specificity so it actually hides the children. */
.ao-category-dropdown__children[hidden] {
  display: none;
}

.ao-category-dropdown__children .ao-category-dropdown__option {
  font-size: var(--text-xs);
}

@media (prefers-reduced-motion: reduce) {
  .ao-category-dropdown__chevron,
  .ao-category-dropdown__arrow {
    transition: none;
  }
}

/* Submit + reset buttons. In the wide event layout they share the last
   row's fourth column, 25% smaller than the 44px controls above them
   (33px, 9/21px padding, 12px type); the stacked container query and the
   ≤560px block put the full 44px size back, so phones and narrow
   placements are unchanged. flex: 1 splits the column between the two. */
.ao-event-search__submit,
.ao-event-search__reset {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 1 1 0;
  min-width: 0;
  padding: 9px 21px;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  text-decoration: none;
  border: 0;
  border-radius: var(--radius-sm);
  cursor: pointer;
  min-height: 33px;
  transition: background var(--transition-fast), color var(--transition-fast);
  white-space: nowrap;
}

/* The classified widget's buttons still stack in their own column at the
   original size. */
.ao-classified-search .ao-event-search__submit,
.ao-classified-search .ao-event-search__reset {
  flex: 0 0 auto;
  padding: 12px 28px;
  font-size: var(--text-base);
  min-height: 44px;
}

.ao-event-search__submit {
  background: var(--color-ink);
  color: #fff;
}

.ao-event-search__submit:hover,
.ao-event-search__submit:focus {
  background: var(--color-primary);
  color: #fff;
}

.ao-event-search__reset {
  background: var(--color-ink-muted);
  color: #fff;
}

.ao-event-search__reset:hover,
.ao-event-search__reset:focus {
  background: var(--color-ink);
  color: #fff;
  text-decoration: none;
}

/* Date row: 2 date inputs + 6 preset chips, all in a flex row */
.ao-event-search__dates {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: stretch;
}

.ao-event-search__date-input {
  position: relative;
  flex: 1 1 140px;
  min-width: 0;
}

/* "Start Date (mm/dd/yyyy)" / "End Date (mm/dd/yyyy)" (theme 2.114.0) — the
   archive sidebar's overlay (see .sidebar-date__placeholder in archive.css).
   An opaque span covering the empty field's own "mm/dd/yyyy" from the left
   edge to just short of the calendar icon, inset 1px inside the border, its
   text lined up with the input's 14px side padding. Click-through, hidden
   while the field has focus so the native segments are there to type into,
   and shown only while archive-sidebar.js marks the wrapper --empty (no JS =
   the plain native field). It starts at the input's own type size and
   fitDatePlaceholders() shrinks it until the whole text fits, Start and End
   kept at the same size; the stacked container query below re-aligns it to
   that layout's smaller padding and type. */
.ao-event-search__date-placeholder {
  display: none;
  position: absolute;
  top: 1px;
  bottom: 1px;
  left: 1px;
  right: 34px;
  align-items: center;
  padding-left: 13px;
  border-radius: var(--radius-sm) 0 0 var(--radius-sm);
  background: var(--color-paper);
  color: var(--color-ink); /* matches ::placeholder above */
  font-family: var(--font-body);
  font-size: var(--text-base);
  line-height: 1;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  pointer-events: none;
}

.ao-event-search__date-input--empty .ao-event-search__date-placeholder {
  display: flex;
}

.ao-event-search__date-input--empty:focus-within .ao-event-search__date-placeholder {
  display: none;
}

.ao-event-search__presets {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-1);
}

.ao-event-search__preset {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: 0 14px;
  min-height: 44px;
  min-width: 44px;
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.ao-event-search__preset:hover,
.ao-event-search__preset:focus {
  background: var(--color-bg-warm);
  border-color: var(--color-primary);
  color: var(--color-primary);
  outline: 0;
}

/* Tablet (≤900px): the event widget keeps its three rows — only the buttons
   give up side padding so Search + Reset still fit the fourth column at
   768px. The classified widget collapses to two columns with its buttons in
   a row beneath, as it always has. */
@media (max-width: 900px) {
  .ao-event-search .ao-event-search__submit,
  .ao-event-search .ao-event-search__reset {
    padding-left: 12px;
    padding-right: 12px;
  }
  .ao-classified-search .ao-event-search__grid {
    grid-template-columns: 1fr 1fr;
  }
  .ao-classified-search .ao-event-search__actions {
    grid-column: 1 / -1;
    grid-row: auto;
    flex-direction: row;
  }
  .ao-classified-search .ao-event-search__submit,
  .ao-classified-search .ao-event-search__reset {
    flex: 1;
  }
}

/* Phones (≤560px): one column in source order for both widgets, and the
   buttons back at full size. Two classes deep to outrank the classified
   widget's pinned cells above. */
@media (max-width: 560px) {
  .ao-event-search .ao-event-search__grid {
    grid-template-columns: 1fr;
  }
  .ao-event-search .ao-event-search__field,
  .ao-event-search .ao-event-search__dates,
  .ao-event-search .ao-event-search__actions {
    grid-column: 1;
    grid-row: auto;
  }
  .ao-event-search .ao-event-search__actions {
    flex-direction: row;
  }
  .ao-event-search .ao-event-search__submit,
  .ao-event-search .ao-event-search__reset {
    flex: 1;
    min-height: 44px;
    padding: 12px 28px;
    font-size: var(--text-base);
  }
}

/* ==========================================================================
   Event Search Widget — stacked layout for narrow containers
   In a right column the viewport is wide but the widget is not, so the
   collapse keys off the widget's OWN width (same technique as the classified
   widget below). The stacked order follows the legacy sidebar search:
   keyword → date block (inline month calendar, date pickers, preset chips)
   → category → organization → venue → city → accessibility → Official Tags
   → Search/Reset. Selectors are three classes deep so they outrank the
   pinned date/actions cells above at the same specificity but later in the
   file.
   Descendant, not child, combinators: below the keyword field the items sit
   inside the display:contents .ao-event-search__advanced wrapper (the mobile
   disclosure), so a child combinator would miss them and Search/Reset would
   keep their desktop column-3 placement and overflow the widget. The
   classified widget sets its own container-name, so this query never matches
   it.
   ========================================================================== */
@container ao-ev-search (max-width: 480px) {
  .ao-event-search .ao-event-search__grid {
    grid-template-columns: 1fr;
  }
  .ao-event-search .ao-event-search__grid .ao-event-search__field,
  .ao-event-search .ao-event-search__grid .ao-event-search__dates,
  .ao-event-search .ao-event-search__grid .ao-event-search__actions {
    grid-column: 1;
    grid-row: auto;
  }
  .ao-event-search .ao-event-search__grid .ao-event-search__field--keyword       { order: 1; }
  .ao-event-search .ao-event-search__grid .ao-event-search__dates                { order: 2; }
  .ao-event-search .ao-event-search__grid .ao-event-search__field--category      { order: 3; }
  .ao-event-search .ao-event-search__grid .ao-event-search__field--organization  { order: 4; }
  .ao-event-search .ao-event-search__grid .ao-event-search__field--venue         { order: 5; }
  .ao-event-search .ao-event-search__grid .ao-event-search__field--city          { order: 6; }
  .ao-event-search .ao-event-search__grid .ao-event-search__field--district      { order: 7; }
  .ao-event-search .ao-event-search__grid .ao-event-search__field--accessibility { order: 8; }
  .ao-event-search .ao-event-search__grid .ao-event-search__field--official-tags { order: 9; }
  .ao-event-search .ao-event-search__grid .ao-event-search__actions              { order: 10; flex-direction: row; }
  .ao-event-search .ao-event-search__actions .ao-event-search__submit,
  .ao-event-search .ao-event-search__actions .ao-event-search__reset {
    flex: 1;
    /* Full 44px size here: the 25%-smaller buttons are a wide-layout
       economy only. */
    min-height: 44px;
    padding: 12px 28px;
    font-size: var(--text-base);
  }

  /* Date block: calendar on top (full width), then the two pickers side by
     side, then the six chips on ONE row. The calendar exists only here. */
  .ao-event-search .ao-event-search__calendar {
    display: block;
    flex: 1 1 100%;
  }
  .ao-event-search .ao-event-search__date-input {
    flex: 1 1 40%;
  }
  /* The native date input's "mm/dd/yyyy" + calendar icon needs ~120px at
     the base size; at half a narrow column it was being clipped, so the
     text steps down a size and the side padding tightens. */
  .ao-event-search .ao-event-search__date-input input[type="date"] {
    font-size: var(--text-sm);
    padding-left: 8px;
    padding-right: 8px;
  }
  /* The overlaid placeholder follows the input: 8px padding, smaller type
     as its starting size, a smaller icon reserve. */
  .ao-event-search .ao-event-search__date-input .ao-event-search__date-placeholder {
    right: 26px;
    padding-left: 7px;
    font-size: var(--text-sm);
  }
  /* Chips never wrap: each shrinks to its label at the small size, and the
     numeric ones give up width first (min-width: 0 undoes the 44px floor). */
  .ao-event-search .ao-event-search__presets {
    flex: 1 1 100%;
    flex-wrap: nowrap;
    gap: 3px;
  }
  .ao-event-search .ao-event-search__preset {
    flex: 1 1 auto;
    min-width: 0;
    min-height: 36px;
    padding: 0 5px;
    font-size: var(--text-xs);
  }
  /* Tighter heading: 14px less above and below. Above is taken off the
     widget wrapper's own padding with a negative margin, since inside a
     sidebar widget the form has no padding of its own (see the
     .hp-widget/.ao-right-widget rule above). */
  .ao-event-search .ao-event-search__heading {
    margin-top: -14px;
    margin-bottom: calc(var(--space-5) - 14px);
  }
}

/* Very narrow widget (a ~300px right column): half the column is ~130px, and
   "Start Date (mm/dd/yyyy)" did not fit there even at the script's 8px floor
   (theme 2.114.0). Below 390px the two pickers take a row each instead, where
   the placeholder fits at the stacked layout's normal small type. Between 390
   and 480px they stay side by side, fitted to 10px or more. Same selector
   as the 40% rule in the block above, later in the file, so it wins. */
@container ao-ev-search (max-width: 390px) {
  .ao-event-search .ao-event-search__date-input {
    flex: 1 1 100%;
  }
}

/* Inline month calendar (see template-parts/ao-event-search.php and
   initDateCalendars() in archive-sidebar.js). display:none at rest and only
   switched on by the container query above; [hidden] (set until the script
   has built the grid) must still win over that display:block. */
.ao-event-search__calendar {
  display: none;
  min-width: 0;
}

.ao-event-search__calendar[hidden] {
  display: none;
}

.ao-event-search__calendar-label {
  margin: 0 0 var(--space-2);
  font-family: var(--font-body);
  font-size: var(--text-base);
  color: var(--color-ink);
}

.ao-event-search__calendar-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2);
  padding: var(--space-1) var(--space-2);
  background: var(--color-bg-warm);
  border: 1px solid var(--color-rule);
  border-bottom: 0;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}

.ao-event-search__calendar-month {
  flex: 1;
  text-align: center;
  font-family: var(--font-body);
  font-size: var(--text-base);
  font-weight: 600;
  color: var(--color-ink);
}

.ao-event-search__calendar-nav {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  min-height: 36px;
  padding: 0;
  border: 0;
  border-radius: var(--radius-sm);
  background: transparent;
  font-size: var(--text-lg);
  line-height: 1;
  color: var(--color-ink);
  cursor: pointer;
}

.ao-event-search__calendar-nav:hover,
.ao-event-search__calendar-nav:focus-visible {
  background: var(--color-paper);
  color: var(--color-primary);
  outline: 0;
}

.ao-event-search__calendar-grid {
  width: 100%;
  table-layout: fixed;
  border-collapse: separate;
  border-spacing: 3px;
  margin: 0;
  padding: var(--space-1);
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: 0 0 var(--radius-sm) var(--radius-sm);
  box-sizing: border-box;
}

.ao-event-search__calendar-grid th {
  padding: var(--space-1) 0;
  font-family: var(--font-body);
  font-size: var(--text-xs);
  font-weight: 600;
  text-align: center;
  color: var(--color-ink-muted);
}

.ao-event-search__calendar-grid td {
  padding: 0;
  text-align: center;
}

.ao-event-search__calendar-day {
  display: block;
  width: 100%;
  min-height: 34px;
  padding: 0;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--color-bg-warm);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
  cursor: pointer;
  transition: background var(--transition-fast), border-color var(--transition-fast), color var(--transition-fast);
}

.ao-event-search__calendar-day.is-past {
  color: var(--color-ink-muted);
}

.ao-event-search__calendar-day:hover,
.ao-event-search__calendar-day:focus-visible {
  background: var(--color-paper);
  border-color: var(--color-primary);
  color: var(--color-primary);
  outline: 0;
}

.ao-event-search__calendar-day[aria-current="date"] {
  border-color: var(--color-ink);
  font-weight: 700;
}

.ao-event-search__calendar-day[aria-pressed="true"] {
  background: var(--color-ink);
  border-color: var(--color-ink);
  color: #fff;
}


/* ==========================================================================
   Classified Search Widget — right-column + narrow-container behavior
   The classified widget reuses the .ao-event-search grid, but because it can
   live in a narrow right-column (where the viewport is still wide), it stacks
   based on its OWN width via a container query rather than the viewport. The
   source order is keyword → category → state → city → actions, so when it
   stacks, State and City sit above the Search/Reset buttons.
   ========================================================================== */
.ao-classified-search {
  container-type: inline-size;
  container-name: ao-cls-search;
}

/* When the widget's own width is narrow (right column or small screens),
   collapse to a single column. Everything flows in source order, which puts
   the action buttons last (below State and City). */
@container ao-cls-search (max-width: 480px) {
  .ao-classified-search .ao-event-search__grid {
    grid-template-columns: 1fr;
  }
  .ao-classified-search .ao-event-search__field--keyword,
  .ao-classified-search .ao-event-search__field--category,
  .ao-classified-search .ao-event-search__field--state,
  .ao-classified-search .ao-event-search__field--city,
  .ao-classified-search .ao-event-search__actions {
    grid-column: 1;
    grid-row: auto;
  }
  .ao-classified-search .ao-event-search__actions {
    flex-direction: row;
  }
  .ao-classified-search .ao-event-search__submit,
  .ao-classified-search .ao-event-search__reset {
    flex: 1;
  }
}

/* Fallback for browsers without container query support: the existing
   viewport media queries below still collapse the widget on small screens.
   For those browsers in a desktop right column the widget keeps the 2-col
   grid, which remains usable. */

   ========================================================================== */
.archive-view-toggle {
  display: flex;
  gap: 4px;
  margin-bottom: 16px;
}

.archive-view-toggle__btn {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 7px 14px;
  border: 1px solid var(--color-rule);
  background: #fff;
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-weight: 500;
  color: var(--color-ink-muted);
  cursor: pointer;
  transition: background 0.15s, border-color 0.15s, color 0.15s;
}

.archive-view-toggle__btn.is-active,
.archive-view-toggle__btn[aria-pressed="true"] {
  background: var(--color-ink);
  border-color: var(--color-ink);
  color: #fff;
}

.archive-view-toggle__btn:hover:not(.is-active) {
  background: var(--color-bg-warm);
  border-color: var(--color-ink-muted);
}

/* Archive map container */
.archive-map {
  width: 100%;
  height: 520px;
  aspect-ratio: unset; /* override the 16/9 from .listing-map */
  border-radius: var(--radius-md);
  overflow: hidden;
  margin-bottom: 24px;
  position: relative;
}

.archive-map__loading {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  background: var(--color-bg-warm);
}

/* ===============================================================
   Cultural Assets map — [ao_cultural_assets_map]
   The map container reuses .archive-map for its frame and height;
   only the module filter above it is new.
   =============================================================== */
.ao-assets-map-wrap {
  margin-bottom: 24px;
}

.ao-assets-map__filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 8px 20px;
  margin: 0 0 12px;
  padding: 0;
  border: 0;
}

.ao-assets-map__legend {
  padding: 0;
  margin-right: 4px;
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-ink);
}

.ao-assets-map__filter {
  display: flex;
  align-items: center;
  gap: 8px;
}

/* 18px box in a 24px row: the label is part of the same target, and
   together they clear the 24px minimum (WCAG 2.5.8) comfortably. */
.ao-assets-map__checkbox {
  width: 18px;
  height: 18px;
  margin: 0;
  accent-color: var(--color-ink);
  cursor: pointer;
}

.ao-assets-map__label {
  display: flex;
  align-items: center;
  gap: 7px;
  min-height: 24px;
  font-size: var(--text-sm);
  color: var(--color-ink);
  cursor: pointer;
}

/* Colour key for the module, matching its markers. Not the only way the
   module is identified — the label names it too — so colour is never
   carrying the meaning on its own (WCAG 1.4.1). */
.ao-assets-map__swatch {
  width: 14px;
  height: 14px;
  border: 1px solid rgba(0, 0, 0, 0.25);
  border-radius: 50%;
  flex: 0 0 auto;
}

/* A module the visitor has switched off reads as off, without relying on
   the checkbox alone being noticed. */
.ao-assets-map__checkbox:not(:checked) + .ao-assets-map__label {
  color: var(--color-ink-muted);
}

.ao-assets-map__checkbox:not(:checked) + .ao-assets-map__label .ao-assets-map__swatch {
  background: transparent !important;
  border-color: var(--color-ink-muted);
}

@media (max-width: 560px) {
  .ao-assets-map__filters {
    gap: 10px 16px;
  }
}

/* ---------------------------------------------------------------
   Map marker popups (detail-page maps and the archive map alike).
   Built by makePopup() in assets/js/listing-map.js — the markup is
   a place name, its address, and on the events archive the list of
   events happening there.
   --------------------------------------------------------------- */
.ao-map-popup__title {
  margin: 0;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.4;
}

/* Links keep the site's link colour and underline. Bold alone did not
   distinguish them from the text around them — in the event list the only
   difference between a title and its date was the weight. */
.ao-map-popup__title a {
  color: var(--color-link);
}

/* Mapbox ships a close button 8px wide; the popup needs one big enough to
   hit (WCAG 2.5.8 asks for 24x24), and the title needs room to clear it. */
.ao-map-popup--with-events .mapboxgl-popup-close-button {
  width: 28px;
  height: 28px;
  padding: 0;
  font-size: 20px;
  line-height: 1;
  color: var(--color-ink-muted);
  border-radius: var(--radius-sm, 4px);
}

.ao-map-popup--with-events .mapboxgl-popup-close-button:hover {
  background: var(--color-bg-warm);
  color: var(--color-ink);
}

.ao-map-popup--with-events .ao-map-popup__title {
  padding-right: 30px;
}

.ao-map-popup__address {
  margin: 4px 0 0;
  font-size: 12px;
  line-height: 1.3;
  color: #555;
}

.ao-map-popup__rule {
  height: 0;
  margin: 8px 0;
  border: 0;
  border-top: 1px solid #dcdcde;
}

/* A busy venue can host a long run of events — keep the popup a sane
   size and let the list scroll rather than growing off the map. */
.ao-map-popup__events {
  max-height: 190px;
  overflow-y: auto;
  margin: 0;
  padding: 0;
  list-style: none;
}

.ao-map-popup__event {
  margin: 0 0 6px;
  font-size: 12px;
  line-height: 1.35;
}

.ao-map-popup__event:last-child {
  margin-bottom: 0;
}

.ao-map-popup__event a {
  color: var(--color-link);
  font-weight: 600;
}

.ao-map-popup__dates {
  display: block;
  color: #555;
}

/* Message drawn over the map canvas — empty result, load failure, or a
   "result set was capped" notice. Removed with the map's loading overlay,
   so it is only ever visible once the canvas is behind it. */
.archive-map__message {
  position: absolute;
  top: 50%;
  left: 50%;
  z-index: 2;
  transform: translate(-50%, -50%);
  max-width: min(90%, 420px);
  margin: 0;
  padding: 12px 20px;
  border-radius: var(--radius-sm, 4px);
  /* Opaque, not translucent: at 94% the map tiles bleed through enough to
     pull the error text under 4.5:1 on the Dark and Satellite styles. */
  background: #fff;
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);
  font-size: var(--text-sm);
  color: var(--color-ink);
  text-align: center;
}

.archive-map__message--error {
  color: var(--color-error);
}

/* The truncation notice is advisory, not a dead end — keep the map itself
   clear and sit it along the bottom edge. */
.archive-map__message--notice {
  top: auto;
  bottom: 12px;
  transform: translateX(-50%);
  font-size: var(--text-xs, 12px);
}

/* ===============================================================
   Customizer-driven heading typography (H1–H6)
   ---------------------------------------------------------------
   These rules let the Appearance → Customize → Brand Kit → Typography
   per-heading controls (font / size / weight / letter-spacing) drive
   the theme's visible headings. Each major heading component is mapped
   to its semantic level via the --h{N}-* variables emitted in the
   <style id="ao-brand-kit"> block. Targeted by tag.class so a class
   used at two levels (e.g. footer-col__title as h2 and h4) resolves
   correctly. Eyebrow/accent labels (.ao-form__section-title and the
   mono kicker labels) are intentionally excluded — they are not
   display headings and keep their own styling.
   =============================================================== */

/* H1 — page & detail titles */
h1.archive-header__title,
h1.listing-detail__title,
h1.page-detail__title,
h1.post-detail__title,
h1.dashboard-main__title,
h1.ao-favorites-page__title,
h1.auth-card__title {
  font-family: var(--h1-font);
  font-size: var(--h1-size);
  font-weight: var(--h1-weight);
  letter-spacing: var(--h1-spacing);
}

/* H2 — section, card & block display titles.
   Only genuine display-style headings are mapped here. A few small,
   label-style h2s in the theme (.info-section__title, .hp-sponsors__title,
   .hp-partners__title, .footer-col__title, .sidebar-widget__title,
   .post-comments__title) are deliberately left on their own styling so the
   H2 control doesn't unexpectedly enlarge small UI labels. */
h2.listing-card__title,
h2.archive-empty__title,
h2.dashboard-card__title,
h2.submissions-empty__title,
h2.ao-assoc-events__heading,
h2.ao-event-search__heading,
h2.ao-favorites-section__title,
h2.ao-share-dialog__title,
h2.hp-events__title {
  font-family: var(--h2-font);
  font-size: var(--h2-size);
  font-weight: var(--h2-weight);
  letter-spacing: var(--h2-spacing);
}

/* H3 — sub-section, widget & event-card titles */
h3.ao-event-card__title,
h3.ao-right-widget__title,
h3.hp-widget__title,
h3.widget__title,
h3.related-listings__title,
h3.post-detail__nav-title {
  font-family: var(--h3-font);
  font-size: var(--h3-size);
  font-weight: var(--h3-weight);
  letter-spacing: var(--h3-spacing);
}

/* H4–H6 have no dedicated display-heading components in the theme chrome;
   their controls apply to bare h4–h6 inside rich text content (below). The
   small footer-col__title label keeps its own existing styling. */

/* Bare heading tags inside rich text content follow their level too. */
.page-detail__content h1,
.post-detail__content h1 {
  font-family: var(--h1-font);
  font-size: var(--h1-size);
  font-weight: var(--h1-weight);
  letter-spacing: var(--h1-spacing);
}
.page-detail__content h2,
.post-detail__content h2 {
  font-family: var(--h2-font);
  font-size: var(--h2-size);
  font-weight: var(--h2-weight);
  letter-spacing: var(--h2-spacing);
}
.page-detail__content h3,
.post-detail__content h3 {
  font-family: var(--h3-font);
  font-size: var(--h3-size);
  font-weight: var(--h3-weight);
  letter-spacing: var(--h3-spacing);
}
.page-detail__content h4,
.post-detail__content h4 {
  font-family: var(--h4-font);
  font-size: var(--h4-size);
  font-weight: var(--h4-weight);
  letter-spacing: var(--h4-spacing);
}
.page-detail__content h5,
.post-detail__content h5 {
  font-family: var(--h5-font);
  font-size: var(--h5-size);
  font-weight: var(--h5-weight);
  letter-spacing: var(--h5-spacing);
}
.page-detail__content h6,
.post-detail__content h6 {
  font-family: var(--h6-font);
  font-size: var(--h6-size);
  font-weight: var(--h6-weight);
  letter-spacing: var(--h6-spacing);
}

/* ============================================================
   Submissions table: sortable column headers
   ============================================================ */
.submissions-table__sortable {
  padding: 0;
}

.submissions-table__sort-btn {
  display: flex;
  align-items: center;
  gap: var(--space-2);
  width: 100%;
  padding: var(--space-3) var(--space-4);
  background: none;
  border: none;
  cursor: pointer;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  text-align: left;
  white-space: nowrap;
  transition: color var(--transition-fast);
}

.submissions-table__sort-btn:hover {
  color: var(--color-ink);
}

.submissions-table__sortable[aria-sort="ascending"] .submissions-table__sort-btn,
.submissions-table__sortable[aria-sort="descending"] .submissions-table__sort-btn {
  color: var(--color-ink);
}

/* Sort direction indicator — Unicode arrows */
.submissions-table__sort-icon::after {
  content: '\2195'; /* ↕ unsorted */
  font-size: 0.75em;
  opacity: 0.4;
}

.submissions-table__sortable[aria-sort="ascending"] .submissions-table__sort-icon::after {
  content: '\2191'; /* ↑ */
  opacity: 1;
}

.submissions-table__sortable[aria-sort="descending"] .submissions-table__sort-icon::after {
  content: '\2193'; /* ↓ */
  opacity: 1;
}

/* ============================================================
   Submissions table: image thumbnail column
   ============================================================ */
.submissions-table__image-col {
  width: 72px;
  padding: var(--space-3) var(--space-4);
}

.submissions-table__image {
  width: 72px;
  padding: var(--space-2) var(--space-4);
  vertical-align: middle;
}

.submissions-table__image img {
  display: block;
  width: 56px;
  height: 56px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  background: var(--color-bg-warm);
}

/* Placeholder shown when a post has no featured image */
.submissions-table__no-image {
  display: block;
  width: 56px;
  height: 56px;
  border-radius: var(--radius-sm);
  background: var(--color-bg-warm);
  border: 1px dashed var(--color-rule);
}

/* ============================================================
   Dashboard card: Submission Guidelines link
   ============================================================ */
.dashboard-card__guidelines {
  display: flex;
  align-items: center;
  gap: 5px;
  margin-top: var(--space-4);
  padding-top: var(--space-3);
  border-top: 1px solid var(--color-rule);
  font-size: var(--text-xs);
  font-family: var(--font-mono);
  letter-spacing: 0.04em;
  color: var(--color-ink-muted);
  text-decoration: none;
  cursor: pointer;
  transition: color var(--transition-fast);
  /* Prevent the card's own <a> click from following its href */
  pointer-events: auto;
  position: relative;
  z-index: 1;
}

.dashboard-card:hover .dashboard-card__guidelines {
  color: var(--color-ink);
}

.dashboard-card__guidelines svg {
  flex-shrink: 0;
  /* Sized explicitly — the theme's `img, video, svg { height: auto }` reset
     collapses an inline SVG that relies only on its width/height attributes. */
  width: 13px;
  height: 13px;
}

/* Bulk Import Events — a second trigger stacked under Submission Guidelines
   on the Event tile. Same span-not-anchor construction (it sits inside the
   card's own <a>), so it inherits the rules above; it only drops the second
   top rule, which would read as a double divider between the two lines. */
.dashboard-card__bulk-import {
  margin-top: var(--space-2);
  padding-top: 0;
  border-top: none;
}

.dashboard-card__bulk-import:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

/* ============================================================
   Submission Guidelines modal
   ============================================================ */
#ao-guidelines-modal {
  position: fixed;
  inset: 0;
  z-index: 9999;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 20px;
}

#ao-guidelines-modal[hidden] {
  display: none;
}

.ao-guidelines-modal__backdrop {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.55);
}

.ao-guidelines-modal__panel {
  position: relative;
  background: #fff;
  border-radius: var(--radius-md);
  box-shadow: 0 8px 40px rgba(0, 0, 0, 0.22);
  width: 100%;
  max-width: 640px;
  max-height: 85vh;
  display: flex;
  flex-direction: column;
  overflow: hidden;
}

.ao-guidelines-modal__header {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-4);
  padding: var(--space-6) var(--space-8) var(--space-4);
  border-bottom: 1px solid var(--color-rule);
}

.ao-guidelines-modal__title {
  margin: 0;
  font-size: var(--text-lg);
}

.ao-guidelines-modal__copy {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  flex-shrink: 0;
  padding: 6px 12px;
  background: transparent;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
  color: var(--color-ink-muted);
  font-size: var(--text-xs);
  font-weight: 600;
  line-height: 1;
  cursor: pointer;
  transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}

.ao-guidelines-modal__copy:hover {
  background: var(--color-bg-warm);
  color: var(--color-ink);
  border-color: var(--color-ink-muted);
}

.ao-guidelines-modal__copy:focus-visible {
  outline: 2px solid var(--color-focus);
  outline-offset: 2px;
}

.ao-guidelines-modal__copy svg {
  flex-shrink: 0;
}

.ao-guidelines-modal__copy.is-copied {
  background: var(--color-success);
  border-color: var(--color-success);
  color: #fff;
}

.ao-guidelines-modal__body {
  flex: 1 1 auto;
  overflow-y: auto;
  padding: var(--space-6) var(--space-8);
  font-size: var(--text-sm);
  line-height: 1.7;
  color: var(--color-ink);
  /* Prose content styles */
}

.ao-guidelines-modal__body p  { margin: 0 0 var(--space-4); }
.ao-guidelines-modal__body ul,
.ao-guidelines-modal__body ol { margin: 0 0 var(--space-4); padding-left: var(--space-6); }
.ao-guidelines-modal__body li { margin-bottom: var(--space-2); }
.ao-guidelines-modal__body h2,
.ao-guidelines-modal__body h3 { margin: var(--space-5) 0 var(--space-2); }
.ao-guidelines-modal__body a  { color: var(--color-primary); }

.ao-guidelines-modal__footer {
  flex-shrink: 0;
  display: flex;
  justify-content: center;
  padding: var(--space-4) var(--space-8) var(--space-6);
  border-top: 1px solid var(--color-rule);
}

.ao-guidelines-modal__close {
  padding: 10px 48px;
  background: var(--color-ink);
  color: #fff;
  border: none;
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  font-weight: 600;
  cursor: pointer;
  transition: opacity var(--transition-fast);
}

.ao-guidelines-modal__close:hover {
  opacity: 0.8;
}

.ao-guidelines-modal__close:focus-visible {
  outline: 2px solid var(--color-ink);
  outline-offset: 3px;
}

.ao-guidelines-modal__body--loading {
  color: var(--color-ink-muted);
  font-style: italic;
}

/* ============================================================
   My Submissions — module filter pill tabs
   ============================================================ */
.submissions-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
}

.submissions-tabs__pill {
  display: inline-flex;
  align-items: center;
  padding: 6px 16px;
  border: 1px solid var(--color-rule);
  border-radius: 999px;
  background: transparent;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  font-weight: 500;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  text-decoration: none;
  cursor: pointer;
  transition: background var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
  white-space: nowrap;
}

.submissions-tabs__pill:hover {
  background: var(--color-bg-warm);
  border-color: var(--color-ink-muted);
  color: var(--color-ink);
}

.submissions-tabs__pill--active,
.submissions-tabs__pill--active:hover {
  background: var(--color-ink);
  border-color: var(--color-ink);
  color: #fff;
}

@media (max-width: 480px) {
  .submissions-tabs {
    gap: var(--space-1);
  }
  .submissions-tabs__pill {
    padding: 5px 12px;
    font-size: 10px;
  }
}

/* Organization sub-tabs (Event tab only) — a smaller, second-row pill
   set that filters the Event tab's own tabs down to one organization.
   Distinguished from the main tabs' black active state with the site's
   link/primary color so the two rows read as different filter levels. */
.submissions-tabs--has-sub {
  margin-bottom: var(--space-2);
}

.submissions-tabs--sub {
  gap: var(--space-1);
}

.submissions-tabs__pill--sub {
  padding: 4px 14px;
  font-size: 11px;
}

.submissions-tabs__pill--sub.submissions-tabs__pill--active,
.submissions-tabs__pill--sub.submissions-tabs__pill--active:hover {
  background: var(--color-primary);
  border-color: var(--color-primary);
}

@media (max-width: 480px) {
  .submissions-tabs__pill--sub {
    padding: 4px 10px;
    font-size: 10px;
  }
}

/* ---------------------------------------------------------------
   "More Dates" progressive disclosure (event detail page)
   Days past the first batch are hidden until revealed. The [hidden]
   attribute does the work; this rule guards against the utility being
   overridden by the flex container's display.
   --------------------------------------------------------------- */
.event-performance-day.is-hidden {
  display: none;
}

/* "More Dates" / "Collapse" controls sit on one row beneath the date list. */
.ao-dates-controls {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-top: var(--space-4);
}

.ao-more-dates,
.ao-collapse-dates {
  align-self: flex-start;
}

/* Both controls are toggled via the [hidden] attribute. .btn sets an explicit
   display, which would otherwise beat the browser's default [hidden] styling,
   so re-assert it here. */
.ao-more-dates[hidden],
.ao-collapse-dates[hidden] {
  display: none;
}

/* Without JS the button can't reveal anything, so show every date and hide
   the inert control. */
.no-js .event-performance-day.is-hidden,
.no-js .event-performance-day[hidden] {
  display: flex;
}

.no-js .ao-dates-controls,
.no-js .ao-more-dates,
.no-js .ao-collapse-dates {
  display: none;
}

/* Venue accessibility "More Info" button — separated from the Additional
   Accessibility Info text above it by the same gap the icon list uses. */
.ao-access-more {
  margin-top: var(--space-4);
  margin-bottom: 0;
}

/* ---------------------------------------------------------------
   Event performance dates — date on the left, times to its right on
   the same row. A day can hold several performances, so the times
   column stacks them beside a single date label.
   --------------------------------------------------------------- */
.event-performance-day {
  display: flex;
  align-items: baseline;
  gap: 0;
}

/* The date column is a fixed width so every row's start time begins at the
   same x-position regardless of how long the date reads ("Fri, May 1, 2026"
   vs "Thu, September 10, 2026"). Sized in ch so it tracks the font rather
   than a hardcoded pixel guess; 23ch covers the longest "D, F j, Y" string.
   nowrap keeps a long date on one line rather than wrapping inside the
   reserved column. */
.event-performance-day__date {
  flex: 0 0 23ch;
  font-weight: 600;
  font-size: var(--text-sm);
  color: var(--color-ink);
  margin: 0;
  white-space: nowrap;
}

/* The flex rule above sets `display` on the same element the "More Dates"
   toggle hides, and an author `display` declaration overrides the browser's
   default [hidden] styling. Re-assert hiding for both the attribute and the
   class so collapsed days stay collapsed. */
.event-performance-day[hidden],
.event-performance-day.is-hidden {
  display: none;
}

/* Times sit 50px left of where the 35px gap previously placed them: 35px comes
   from removing that gap, the remaining 15px from this pull. The date column
   keeps its full 23ch reserve, so shortening the gap moves the times without
   squeezing the dates. */
.event-performance-day__times {
  display: flex;
  flex-direction: column;
  gap: var(--space-1, 4px);
  min-width: 0;
  margin-left: -15px;
}

.event-performance-time {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  font-size: var(--text-sm);
  color: var(--color-ink-light);
}

/* Pull the start→end arrow 2px closer on each side. The row gap is uniform,
   so trimming the arrow's own margins is what tightens just this pairing. */
.event-performance-time__arrow {
  margin-left: -2px;
  margin-right: -2px;
  color: var(--color-rule);
}

/* Narrow screens: keep the date and its times on one row. The 23ch reserve
   that aligns start times on desktop is too wide here — at ~179px it forces
   the times onto a second line on a 360–390px phone — so the date sizes to
   its content instead and the times follow inline. Alignment across rows is
   sacrificed, but each entry stays on a single line. */
@media (max-width: 600px) {
  .event-performance-day {
    gap: var(--space-3);
    flex-wrap: nowrap;
  }

  .event-performance-day__date {
    flex: 0 1 auto;
    min-width: 0;
  }

  .event-performance-day__times {
    padding-left: 0;
    margin-left: 0;
    flex: 1 1 auto;
  }

  /* Reclaim horizontal space: tighten the gaps inside the time row and drop
     the fixed 23ch alignment so "7:00 PM → 10:00 PM 3h" fits beside the date. */
  .event-performance-time {
    gap: var(--space-2);
    flex-wrap: nowrap;
    white-space: nowrap;
  }
}

/* Very narrow screens only. At ~360px and below the row can't hold a long
   date plus its times, so fall back to stacking. Phones at 390px and up keep
   the single-line layout above. */
@media (max-width: 360px) {
  .event-performance-day {
    flex-direction: column;
    gap: var(--space-1);
  }

  .event-performance-day__times {
    padding-left: var(--space-3);
  }
}

/* Print option in the share dialog. Grouped with the social platforms but set
   apart by a divider, since it opens a printer-friendly page rather than
   sharing to a third-party service. */
.ao-share-dialog__option--print {
  position: relative;
}

.ao-share-dialog__option--print::before {
  content: "";
  position: absolute;
  left: calc(var(--space-5) / -2);
  top: 50%;
  transform: translateY(-50%);
  width: 1px;
  height: 32px; /* matches the 2rem icon height */
  background: var(--color-rule);
}

/* QR code panel in the share dialog (artsopolis_octave_share_qr_panel() in
   functions.php). Sits below the icon row, always visible, with the code for
   the shared URL, a hint and a download link. Present only when the plugin
   provides AO_QR. */
.ao-share-dialog__qr {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
  margin-top: var(--space-5);
  padding-top: var(--space-5);
  border-top: 1px solid var(--color-rule);
  text-align: center;
}

/* Sized explicitly: the theme's `img, video, svg { height: auto }` reset
   would leave this at zero height until the SVG arrives, and the panel would
   jump when it did. Always on white, whatever the dialog surface colour —
   a code on a tinted background scans less reliably. */
.ao-share-dialog__qr-image {
  display: block;
  width: 200px;
  height: 200px;
  padding: var(--space-2);
  background: #fff;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
}

.ao-share-dialog__qr-hint {
  margin: 0;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

.ao-share-dialog__qr-download {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: underline;
  text-underline-offset: 2px;
}

.ao-share-dialog__qr-download:hover {
  color: var(--color-accent);
}

.ao-share-dialog__qr-download:focus-visible {
  outline: 2px solid var(--color-accent);
  outline-offset: 2px;
  border-radius: 2px;
}

/* ========================================================================
   Blog Listing — Grid (template-parts/blog-listing-grid.php)
   ======================================================================== */
.blog-grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-8);
}

.blog-grid__item {
  display: flex;
  flex-direction: column;
}

.blog-grid__image-link {
  display: block;
}

.blog-grid__image {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  border-radius: var(--radius-md);
}

.blog-grid__image--placeholder {
  background: var(--color-bg-warm);
}

.blog-grid__body {
  padding-top: var(--space-4);
}

.blog-grid__meta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  align-items: center;
  font-size: var(--text-xs);
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: var(--color-ink-muted);
  margin-bottom: var(--space-2);
}

.blog-grid__category {
  /* var(--color-accent) computes to ~2.47:1 against a white card background
     — well under the 4.5:1 WCAG AA minimum for normal text. This darker
     shade computes to ~6:1. */
  color: #186a8c;
  font-weight: 600;
  text-decoration: none;
}

.blog-grid__category:hover {
  text-decoration: underline;
}

/* Only show the separating bullet when a date span actually precedes the
   category — i.e. hide it automatically when the "Show publish date"
   setting is off and the category is the meta line's only content. */
.blog-grid__date + .blog-grid__category::before {
  content: "\2022";
  margin-right: var(--space-2);
  color: var(--color-ink-muted);
}

/* Bullet before the author: fires whichever of date/category actually
   precedes it, so it still shows up correctly if either is hidden/absent. */
.blog-grid__category + .blog-grid__author::before,
.blog-grid__date + .blog-grid__author::before {
  content: "\2022";
  margin-right: var(--space-2);
  color: var(--color-ink-muted);
}

.blog-grid__title {
  font-family: var(--font-display);
  font-size: var(--text-lg);
  font-weight: 600;
  line-height: 1.25;
  margin: 0 0 var(--space-2);
}

.blog-grid__title a {
  color: var(--color-ink);
  text-decoration: none;
}

.blog-grid__title a:hover {
  text-decoration: underline;
}

.blog-grid__excerpt {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  line-height: 1.5;
  margin: 0 0 var(--space-3);
}

.blog-grid__link {
  font-size: var(--text-sm);
  font-weight: 600;
  color: var(--color-primary);
  text-decoration: none;
}

.blog-grid__link:hover {
  text-decoration: underline;
}

@media (max-width: 900px) {
  .blog-grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 600px) {
  .blog-grid {
    grid-template-columns: 1fr;
  }
}

/* ========================================================================
   Blog Listing — Compact list (template-parts/blog-listing-compact.php)
   ======================================================================== */
.blog-compact-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.blog-compact-item {
  display: flex;
  gap: var(--space-5);
  padding-block: var(--space-5);
  border-bottom: 1px solid var(--color-rule);
}

.blog-compact-item:first-child {
  padding-top: 0;
}

.blog-compact-item__thumb-link {
  flex: 0 0 auto;
  display: block;
}

.blog-compact-item__thumb {
  width: 96px;
  height: 96px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  display: block;
}

.blog-compact-item__thumb--placeholder {
  background: var(--color-bg-warm);
}

.blog-compact-item__body {
  flex: 1 1 auto;
  min-width: 0;
}

.blog-compact-item__title {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.3;
  margin: 0 0 var(--space-1);
}

.blog-compact-item__title a {
  color: var(--color-ink);
  text-decoration: none;
}

.blog-compact-item__title a:hover {
  text-decoration: underline;
}

.blog-compact-item__meta {
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
  margin: 0 0 var(--space-2);
}

.blog-compact-item__excerpt {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  line-height: 1.5;
  margin: 0;
}

.blog-compact-item__author {
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
}

.blog-compact-item__meta time + .blog-compact-item__author::before {
  content: "\2022";
  margin: 0 var(--space-2);
  color: var(--color-ink-muted);
}

@media (max-width: 480px) {
  .blog-compact-item__thumb {
    width: 64px;
    height: 64px;
  }
}

/* ========================================================================
   Blog Detail — Featured (template-parts/blog-detail-featured.php)
   ======================================================================== */
.post-detail--featured .post-detail__hero {
  display: grid;
  grid-template-columns: 1fr 1fr;
  grid-template-rows: auto 1fr;
  gap: var(--space-8);
  align-items: start;
  margin-bottom: var(--space-6);
}

.post-detail--featured .post-detail__hero--no-media {
  grid-template-columns: 1fr;
}

.post-detail--featured .post-detail__hero-content {
  grid-column: 1;
  grid-row: 1 / span 2;
  align-self: center;
}

.post-detail--featured .post-detail__hero-media {
  grid-column: 2;
  grid-row: 1 / span 2;
}

.post-detail--featured .post-detail__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  border-radius: var(--radius-sm);
  display: block;
}

@media (max-width: 768px) {
  .post-detail--featured .post-detail__hero {
    grid-template-columns: 1fr;
  }

  .post-detail--featured .post-detail__hero-content,
  .post-detail--featured .post-detail__hero-media {
    grid-column: 1;
    grid-row: auto;
  }
}

/* ========================================================================
   Blog Detail — Minimal (template-parts/blog-detail-minimal.php)
   ======================================================================== */
.post-detail--minimal .post-detail__minimal-inner {
  max-width: 680px;
  margin-inline: auto;
}

.post-detail--minimal .post-detail__header {
  text-align: center;
  margin-bottom: var(--space-8);
}

.post-detail--minimal .post-detail__categories {
  justify-content: center;
}

/* Minimal's whole header is centered — a space-between row would shove the
   share button out to the column's far edge, clashing with that. Centering
   the row instead keeps categories + share button together as one centered
   group (still reading as "share button to the right of the category
   badges" — just not edge-to-edge). */
.post-detail--minimal .post-detail__header-top {
  justify-content: center;
}

.post-detail--minimal .post-detail__title {
  font-size: clamp(var(--text-2xl), 5vw, var(--text-4xl));
}

.post-detail--minimal .post-detail__meta {
  justify-content: center;
}

.post-detail--minimal .post-detail__content--minimal {
  font-family: var(--font-display);
  font-size: var(--text-md);
  line-height: 1.7;
}

/* ========================================================================
   Blog Detail — Billboard (template-parts/blog-detail-billboard.php)
   ======================================================================== */
/* overflow-x: hidden clips the ~8-15px the full-bleed image (100vw, below)
   overshoots the actual visible viewport by — 100vw includes the vertical
   scrollbar's width, but the scrollbar itself doesn't reserve that space
   from the layout viewport, so width:100vw is reliably a few pixels wider
   than the page actually is. Confirmed live (both desktop and mobile):
   without this, the page gains a horizontal scrollbar. Scoped to this
   template rather than applied globally to minimize blast radius. */
.post-detail--billboard {
  padding-top: 0;
  overflow-x: hidden;
}

/* Full-bleed featured image: .post-detail__billboard-image-outer breaks out
   of any ancestor's max-width to span the full viewport width regardless of
   where in the page it sits, and is the positioning context for the
   title-overlay box below (so the overlay can sit visually on top of the
   image while living outside the lightbox trigger in the DOM — see
   blog-detail-billboard.php). .listing-detail__image-wrap (the lightbox
   trigger itself, unchanged by the breakout) just fills it edge to edge;
   its position/top are still reset here to override that shared class's
   CPT-oriented sticky positioning. */
.post-detail--billboard .post-detail__billboard-image-outer {
  position: relative;
  width: 100vw;
  max-width: 100vw;
  left: 50%;
  right: 50%;
  margin-left: -50vw;
  margin-right: -50vw;
}

.post-detail--billboard .listing-detail__image-wrap {
  position: static;
  width: 100%;
  cursor: zoom-in;
}

/* Hero height — admin-configurable (Posts → Blog Settings, default 600px),
   applied as a CSS custom property inline on
   .post-detail__billboard-image-wrap so it also bounds the wrap's own
   height (the wrap has no explicit height of its own; it sizes to its
   image child), which in turn gives the title-overlay box (now a sibling —
   see .post-detail__billboard-image-outer above) a definite containing
   block to anchor against. Since theme 2.116.2 it is a MAXIMUM, matching the
   category Billboard in archive.css (2.116.1): a fixed height made
   object-fit: cover cut the sides off any image wider than the height
   allowed at the current viewport width. height: auto takes the ratio from
   the img's width/height attributes (the_post_thumbnail() prints them), so
   the full width always shows and cover only crops top/bottom past the cap. */
.post-detail--billboard .post-detail__billboard-image {
  width: 100%;
  height: auto;
  max-height: var(--ao-billboard-image-height, 600px);
  object-fit: cover;
  display: block;
}

@media (max-width: 600px) {
  .post-detail--billboard .post-detail__billboard-image {
    max-height: min(var(--ao-billboard-image-height, 600px), 360px);
  }
}

/* margin-bottom is the "50px of white space" before the description —
   background-color is set inline per-post from the Billboard shaded-area
   color setting (Posts → Blog Settings), default #f0f0f0. */
.post-detail__billboard-shade {
  margin-bottom: 50px;
  padding-block: var(--space-8);
}

/* The shade band's padding-top is var(--space-8) (32px), so a -2px
   margin-top here nets a 30px gap between the image and the caption. */
.post-detail__billboard-caption {
  text-align: right;
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  margin: -2px 0 var(--space-6);
}

/* The .post-detail__header-top row (category + share button, see
   blog-detail-billboard.php — same shared class the other 3 detail
   templates use) is always rendered — even on posts with no category — so
   the share button has a consistent home, and always carries this
   modifier, pulling it 40px closer to the image/caption above than the
   shade band's own padding-top would otherwise place it. */
.post-detail__billboard-lead {
  margin-top: -40px !important;
}

/* Category badges inside Billboard's shaded band need the same light/dark
   auto-contrast treatment as its other text (see
   artsopolis_octave_prefers_light_text()) — .post-detail__category's
   default color is a fixed accent shade with no such safeguard, since the
   other 3 detail templates that use it always sit on a plain page
   background, never an admin-configurable color. */
.post-detail__billboard-shade--dark-bg .post-detail__category {
  color: #ffffff;
}

.post-detail__billboard-title {
  font-family: var(--font-display);
  font-size: clamp(var(--text-2xl), 4.5vw, var(--text-4xl));
  font-weight: 700;
  line-height: 1.1;
  margin: 0 0 var(--space-4);
  color: var(--color-ink);
}

/* Date + author, side by side — same pairing as .post-detail__meta on the
   other 3 detail templates, just under Billboard's own class prefix so it
   can share the light/dark-bg color logic below with the rest of the band. */
.post-detail__billboard-meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3);
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
}

.post-detail__billboard-date {
  font-variant-numeric: tabular-nums;
}

.post-detail__billboard-author {
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.04em;
  font-size: var(--text-xs);
  color: var(--color-ink-muted);
}

.post-detail__billboard-excerpt {
  font-family: var(--font-display);
  font-size: var(--text-md);
  line-height: 1.5;
  color: var(--color-ink);
  margin: var(--space-2) 0 0;
}

.post-detail__billboard-shade--dark-bg .post-detail__billboard-excerpt {
  color: rgba(255, 255, 255, 0.85);
}

/* Title-overlay mode ("Display title over image", Posts → Blog Settings):
   the title renders inside .post-detail__billboard-image-wrap (which is
   position: relative, see above) instead of the shade band below. The
   --bg modifier (on by default, toggled off via "Overlay title background")
   adds a dark scrim behind the text — rather than relying on the theme's
   light/dark text-color logic used for the shade band — which guarantees
   legibility regardless of what's in the admin-uploaded photo underneath.
   The text-shadow on -text is a lighter-touch fallback for when that
   background is turned off. */
.post-detail__billboard-title-overlay {
  position: absolute;
  z-index: 2;
  max-width: min(90%, 900px);
  padding: var(--space-3) var(--space-4);
  border-radius: 4px;
}

.post-detail__billboard-title-overlay--bg {
  background: rgba(0, 0, 0, 0.55);
}

.post-detail__billboard-title-overlay-text {
  margin: 0;
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.15;
  color: #ffffff;
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.85), 0 2px 10px rgba(0, 0, 0, 0.5);
}

.post-detail__billboard-title-overlay--v-top {
  top: var(--space-6);
}

.post-detail__billboard-title-overlay--v-middle {
  top: 50%;
  transform: translateY(-50%);
}

.post-detail__billboard-title-overlay--v-bottom {
  bottom: var(--space-6);
}

.post-detail__billboard-title-overlay--h-left {
  left: var(--space-6);
  text-align: left;
}

.post-detail__billboard-title-overlay--h-center {
  left: 50%;
  text-align: center;
}

.post-detail__billboard-title-overlay--h-center.post-detail__billboard-title-overlay--v-middle {
  transform: translate(-50%, -50%);
}

.post-detail__billboard-title-overlay--h-center:not(.post-detail__billboard-title-overlay--v-middle) {
  transform: translateX(-50%);
}

.post-detail__billboard-title-overlay--h-right {
  right: var(--space-6);
  text-align: right;
}

/* Applied server-side (see artsopolis_octave_prefers_light_text()) when the
   admin-configured shaded-area background color is dark enough that the
   default dark ink text would fail WCAG 1.4.3 contrast against it. */
.post-detail__billboard-shade--dark-bg .post-detail__billboard-title {
  color: #ffffff;
}

.post-detail__billboard-shade--dark-bg .post-detail__billboard-caption,
.post-detail__billboard-shade--dark-bg .post-detail__billboard-date,
.post-detail__billboard-shade--dark-bg .post-detail__billboard-author {
  color: rgba(255, 255, 255, 0.85);
}

@media (max-width: 600px) {
  .post-detail__billboard-title-overlay {
    padding: var(--space-2) var(--space-3);
  }

  .post-detail__billboard-title-overlay-text {
    font-size: clamp(var(--text-lg), 6vw, var(--text-2xl)) !important;
  }
}

/* ========================================================================
   Blog Related Posts (template-parts/blog-related-posts.php)
   Shared by all 4 blog-detail-*.php templates.
   ======================================================================== */
.blog-related-posts {
  margin-top: var(--space-10);
  padding-top: var(--space-8);
  border-top: 1px solid var(--color-rule);
}

.blog-related-posts__heading {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 700;
  margin: 0 0 var(--space-6);
}

.blog-related-posts__grid {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
}

@media (max-width: 900px) {
  .blog-related-posts__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 600px) {
  .blog-related-posts__grid {
    grid-template-columns: 1fr;
  }
}

/* ========================================================================
   Blog Listing Toolbar — search box + category filter, one row
   (home.php/category.php/tag.php wrap both in a single
   .container.blog-listing-toolbar; see each partial's own rules below).
   ======================================================================== */
.blog-listing-toolbar {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-4);
  margin-bottom: 40px;
}

/* Pushes the search box to the row's right edge regardless of whether the
   category filter renders (it skips itself entirely with under 2
   categories — see blog-category-filter.php) — margin-left: auto works
   whether it's the second flex item or the only one, unlike
   justify-content: space-between, which would left-align a lone item. */
.blog-listing-toolbar .ao-blog-search {
  margin-left: auto;
}

/* ========================================================================
   Blog Search Box (template-parts/blog-search-form.php)
   Shown on the blog listing page and its category/tag archives.
   ======================================================================== */
.ao-blog-search {
  display: flex;
  gap: var(--space-2);
  max-width: 480px;
}

.ao-blog-search__input {
  flex: 1;
  min-width: 0;
  padding: var(--space-2) var(--space-3);
  font-family: var(--font-body);
  font-size: var(--text-sm);
  color: var(--color-ink);
  background: var(--color-paper);
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-sm);
}

.ao-blog-search__input:focus {
  outline: 0;
  border-color: var(--color-primary);
  box-shadow: 0 0 0 2px rgba(33, 125, 191, 0.15);
}

.ao-blog-search__submit {
  white-space: nowrap;
}

/* ========================================================================
   Blog Category Filter (template-parts/blog-category-filter.php)
   Shown on the blog listing page and its category/tag archives, alongside
   the search box above. Pill styling mirrors the existing .tag-list/.tag
   pattern (see "Taxonomy Tags" above) for visual consistency.
   ======================================================================== */
.blog-category-filter {
  /* Spacing after the whole row is owned by .blog-listing-toolbar's own
     margin-bottom (70px) — this partial no longer sets its own. */
}

.blog-category-filter__list {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  padding: 0;
  margin: 0;
}

.blog-category-filter__link {
  display: inline-block;
  padding: var(--space-1) var(--space-3);
  background: var(--color-bg-warm);
  border: 1px solid var(--color-rule);
  border-radius: 100px;
  font-size: var(--text-sm);
  color: var(--color-ink-light);
  text-decoration: none;
  transition: background-color var(--transition-fast), color var(--transition-fast), border-color var(--transition-fast);
}

.blog-category-filter__link:hover {
  background: var(--color-accent-pale);
  border-color: var(--color-accent);
  color: var(--color-accent-dark);
}

.blog-category-filter__link.is-active {
  background: var(--color-ink);
  border-color: var(--color-ink);
  color: #ffffff;
  font-weight: 600;
}

.blog-category-filter__count {
  opacity: 0.7;
  font-size: 0.9em;
  margin-left: 2px;
}

/* ========================================================================
   Blog Listing — Grid: featured/sticky post
   (template-parts/blog-listing-grid.php)
   ======================================================================== */
.blog-grid__item--featured {
  grid-column: 1 / -1;
}

.blog-grid__item--featured .blog-grid__image {
  aspect-ratio: 21 / 9;
}

.blog-grid__item--featured .blog-grid__title {
  font-size: var(--text-2xl);
}

.blog-grid__item--featured .blog-grid__excerpt {
  font-size: var(--text-md);
}

.blog-grid__featured-badge {
  display: inline-block;
  padding: 2px var(--space-2);
  background: var(--color-accent);
  color: #ffffff;
  font-weight: 700;
  font-size: var(--text-xs);
  letter-spacing: 0.05em;
  text-transform: uppercase;
  border-radius: var(--radius-sm);
}

/* ========================================================================
   Featured Blog Posts widget — [ao_featured_blog_posts] shortcode
   (template-parts/blog-featured-posts.php,
    template-parts/blog-featured-card-{hero,small}.php)
   ======================================================================== */
.blog-featured-posts__heading {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 600;
  margin-bottom: var(--space-6);
  letter-spacing: -0.01em;
}

/* Shared "eyebrow" category label — same darkened accent used by
   .blog-grid__category (var(--color-accent) alone computes to ~2.47:1
   against a white card, under the 4.5:1 WCAG AA minimum; this shade
   computes to ~6:1). */
.blog-featured-posts__eyebrow {
  display: inline-block;
  font-size: var(--text-xs);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #186a8c;
  text-decoration: none;
  margin-bottom: var(--space-2);
}

.blog-featured-posts__eyebrow:hover {
  text-decoration: underline;
}

.blog-featured-posts__byline {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  margin: 0;
}

/* -- Hero row: up to 2 large cards -- */
.blog-featured-posts__hero-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-8);
  margin-bottom: var(--space-10);
}

.blog-featured-posts__hero-card {
  display: flex;
  flex-direction: column;
}

.blog-featured-posts__hero-image-link {
  display: block;
}

.blog-featured-posts__hero-image {
  width: 100%;
  aspect-ratio: 4 / 3;
  object-fit: cover;
  display: block;
  border-radius: var(--radius-md);
}

.blog-featured-posts__hero-image--placeholder {
  background: var(--color-bg-warm);
}

.blog-featured-posts__hero-body {
  padding-top: var(--space-4);
}

.blog-featured-posts__hero-title {
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: 700;
  line-height: 1.2;
  margin: 0 0 var(--space-2);
}

.blog-featured-posts__hero-title a {
  color: var(--color-ink);
  text-decoration: none;
}

.blog-featured-posts__hero-title a:hover {
  text-decoration: underline;
}

.blog-featured-posts__hero-card .blog-featured-posts__byline {
  margin-bottom: var(--space-3);
}

.blog-featured-posts__excerpt {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  line-height: 1.5;
  margin: 0;
}

/* -- Small row: remaining cards, thumbnail + text -- */
.blog-featured-posts__small-row {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-6);
  margin-bottom: var(--space-8);
}

.blog-featured-posts__small-card {
  display: flex;
  gap: var(--space-4);
}

.blog-featured-posts__small-image-link {
  flex: 0 0 auto;
  display: block;
}

.blog-featured-posts__small-image {
  width: 88px;
  height: 88px;
  object-fit: cover;
  border-radius: var(--radius-sm);
  display: block;
}

.blog-featured-posts__small-image--placeholder {
  background: var(--color-bg-warm);
}

.blog-featured-posts__small-body {
  flex: 1 1 auto;
  min-width: 0;
}

.blog-featured-posts__small-title {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.3;
  margin: 0 0 var(--space-1);
}

.blog-featured-posts__small-title a {
  color: var(--color-ink);
  text-decoration: none;
}

.blog-featured-posts__small-title a:hover {
  text-decoration: underline;
}

/* -- View All CTA, right-aligned per the widget's mockup -- */
.blog-featured-posts__cta {
  display: flex;
  justify-content: flex-end;
}

@media (max-width: 900px) {
  .blog-featured-posts__hero-row {
    grid-template-columns: 1fr;
  }

  .blog-featured-posts__small-row {
    grid-template-columns: 1fr 1fr;
  }
}

@media (max-width: 600px) {
  .blog-featured-posts__small-row {
    grid-template-columns: 1fr;
  }
}

/* ---------------------------------------------------------------
   Recommended Dining & Drinks — card grid on the event detail page
   (below "Upcoming Events from {organization}") and the venue detail
   page. template-parts/dining-recommendations.php. Same section shape
   as .ao-assoc-events / .ao-assoc-artists above; the card adds a
   distance line ("At the venue" / "0.3 mi away"), a dining-type pill
   row, a short blurb and a Reserve button / phone link.
   --------------------------------------------------------------- */
.ao-dining {
  margin-top: var(--space-10);
  padding-top: var(--space-8);
  border-top: 1px solid var(--color-rule);
}

.ao-dining__heading {
  font-family: var(--font-display);
  font-size: var(--text-xl);
  font-weight: 700;
  color: var(--color-ink);
  letter-spacing: -0.01em;
  margin-bottom: var(--space-6);
}

.ao-dining__grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: var(--space-5);
  list-style: none;
  padding: 0;
  margin: 0;
}

.ao-dining-card {
  display: flex;
  flex-direction: column;
  height: 100%;
  border: 1px solid var(--color-rule);
  border-radius: var(--radius-md);
  background: var(--color-bg-card);
  overflow: hidden;
  transition: box-shadow var(--transition-base), transform var(--transition-base);
}

.ao-dining-card:hover,
.ao-dining-card:focus-within {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.ao-dining-card__image-wrap {
  display: block;
  width: 100%;
  aspect-ratio: 4 / 3;
  overflow: hidden;
  background: var(--color-bg-warm);
  flex-shrink: 0;
}

.ao-dining-card .ao-dining-card__image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform var(--transition-base);
}

.ao-dining-card:hover .ao-dining-card__image {
  transform: scale(1.03);
}

.ao-dining-card__image-wrap--placeholder .ao-dining-card__image {
  object-fit: contain;
}

.ao-dining-card__image-placeholder {
  width: 100%;
  height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--color-ink-muted);
  opacity: 0.4;
}

.ao-dining-card .ao-dining-card__image-placeholder svg {
  width: 40px;
  height: 40px;
}

.ao-dining-card__body {
  padding: var(--space-4);
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  flex: 1;
}

.ao-dining-card__distance {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--color-ink-muted);
  margin: 0;
}

/* "At the venue" is emphasised by weight, not by the brand colour: the
   primary token is whatever a site's Brand Kit sets, and a light brand
   blue at this 12px size would not reach the 4.5:1 text contrast AA asks
   for. Ink on the card background always does. */
.ao-dining-card--venue .ao-dining-card__distance {
  color: var(--color-ink);
  font-weight: 700;
}

@media (prefers-reduced-motion: reduce) {
  .ao-dining-card,
  .ao-dining-card__image {
    transition: none;
  }
  .ao-dining-card:hover,
  .ao-dining-card:focus-within {
    transform: none;
  }
  .ao-dining-card:hover .ao-dining-card__image {
    transform: none;
  }
}

.ao-dining-card__title {
  font-family: var(--font-display);
  font-size: var(--text-md);
  font-weight: 600;
  line-height: 1.25;
  margin: 0;
}

.ao-dining-card__title a {
  color: var(--color-ink);
  text-decoration: none;
}

.ao-dining-card__title a:hover,
.ao-dining-card__title a:focus-visible {
  color: var(--color-link);
  text-decoration: underline;
}

.ao-dining-card__types {
  gap: var(--space-1);
  margin: 0;
}

.ao-dining-card__blurb {
  font-size: var(--text-sm);
  color: var(--color-ink-muted);
  line-height: 1.5;
}

.ao-dining-card__blurb p {
  margin: 0;
}

.ao-dining-card__actions {
  margin-top: auto;
  padding-top: var(--space-2);
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-4);
}

.ao-dining-card__reserve {
  font-size: var(--text-sm);
}

.ao-dining-card__phone {
  display: inline-flex;
  align-items: center;
  gap: var(--space-1);
  font-size: var(--text-sm);
  color: var(--color-link);
  text-decoration: none;
}

.ao-dining-card__phone:hover,
.ao-dining-card__phone:focus-visible {
  text-decoration: underline;
}

.ao-dining-card .ao-dining-card__phone svg {
  width: 16px;
  height: 16px;
  flex-shrink: 0;
}

@media (max-width: 768px) {
  .ao-dining__grid {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 480px) {
  .ao-dining__grid {
    grid-template-columns: 1fr;
  }
}

/* ── Venue detail page: the venue's own Dining & Drinks quadrant ── */
.ao-venue-dining__image-wrap {
  margin-bottom: var(--space-4);
  border-radius: var(--radius-md);
  overflow: hidden;
}

.ao-venue-dining .ao-venue-dining__image {
  display: block;
  width: 100%;
  height: auto;
}

.ao-venue-dining__types {
  margin-bottom: var(--space-3);
}

.ao-venue-dining__actions {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--space-3);
  margin-top: var(--space-3);
}

.ao-venue-dining__phone .info-section__subtitle {
  display: block;
}
