:root {
  --color-bg: #FDFBF9;
  --color-surface: #FFFFFF;
  --color-primary: #C0552B;
  --color-primary-dark: #9C4321;
  --color-accent: #D9A441;
  --color-emphasis: #6E2C3D;
  --color-text: #3A2E28;
  --color-text-muted: #8A7A70;
  --color-border: #EDE2D8;
  --radius: 10px;
  --shadow: 0 2px 10px rgba(60, 40, 20, 0.08);
  --font-heading: Georgia, 'Iowan Old Style', 'Palatino Linotype', serif;
  --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
}

* { box-sizing: border-box; }

/* Present to screen readers and search engines, invisible on screen — for
   a page's real <h1> where the visible branding already covers that role
   (see index.php: the header logo already shows the site name/brand, so a
   second big visible heading right below it would just be redundant). */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

body {
  margin: 0;
  background: var(--color-bg);
  color: var(--color-text);
  font-family: var(--font-body);
  line-height: 1.5;
}

h1, h2, h3 {
  font-family: var(--font-heading);
  color: var(--color-emphasis);
  margin: 0 0 0.5em;
}

a { color: var(--color-primary-dark); }

.container {
  max-width: 1120px;
  margin: 0 auto;
  padding: 0 20px;
}

/* Backoffice on desktop: tables and content span the same width as the
   header image (1740x608 scaled to the header's 500px height = ~1431px). */
@media (min-width: 1200px) {
  body.admin-area main.container { max-width: 1431px; }
  /* Header content (title, signed-in group) spans the same width, so the
     signed-in group sits at the header image's right edge. */
  body.admin-area .site-header-inner { max-width: 1431px; margin: 0 auto; }
}

/* Backoffice edit pages (event, source, venue, user): on desktop the form
   card fills the container and its fields flow in two columns instead of one
   narrow 720px strip. Long fields (textareas), field rows, sections and
   buttons span both columns. */
@media (min-width: 1000px) {
  body.admin-area .admin-form:not(.has-sticky-actions),
  body.admin-area .admin-form.has-sticky-actions .admin-form-fields {
    max-width: none;
    display: grid;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 16px 28px;
    align-items: start;
  }
  body.admin-area .admin-form.has-sticky-actions { max-width: none; }
  body.admin-area .admin-form.has-sticky-actions .admin-form-fields { flex: 1 1 auto; }
  body.admin-area .admin-form:not(.has-sticky-actions) > :not(.field),
  body.admin-area .admin-form-fields > :not(.field),
  body.admin-area .admin-form .field:has(textarea),
  body.admin-area .admin-form .field:has(.dropzone),
  body.admin-area .admin-form .field:has(input[type="url"]),
  body.admin-area .admin-form .field:has(.field-row) { grid-column: 1 / -1; }
}

/* Header — full-width background photo with a translucent cream wash on
   top so the logo/nav stay legible regardless of what part of the image
   shows through at header height. Region-specific photos (Madrid/
   Barcelona/Valencia — see templates/header.php's own $headerRegionClass)
   override just this one property; every other rule below still applies
   to all of them. No region (or any other one) keeps this plain default. */
.site-header {
  position: relative;
  background-image: url('/assets/img/header-bg.jpg');
  background-image: image-set(url('/assets/img/header-bg.avif') type('image/avif'), url('/assets/img/header-bg.webp') type('image/webp'), url('/assets/img/header-bg.jpg') type('image/jpeg'));
  background-position: center;
  background-repeat: no-repeat;
  /* Height locked to exactly fill the box (auto width, scaled to preserve
     the image's own aspect ratio) — the whole image is always visible top
     to bottom, never cropped vertically, regardless of this image's own
     aspect ratio or the viewport's width. Whatever that implies for width
     (usually wider than the box on a normal desktop viewport, sometimes
     narrower on an unusually tall/narrow one) is cropped or letterboxed
     left/right instead, centered either way — see background-position
     above. (cover — tried first — instead crops top/bottom on a viewport
     proportionally wider than the image, to guarantee full width instead.) */
  background-size: auto 100%;
  border-bottom: 1px solid var(--color-border);
  min-height: 500px;
}
.site-header--madrid { background-image: url('/assets/img/header-bg-madrid.jpg');
 background-image: image-set(url('/assets/img/header-bg-madrid.avif') type('image/avif'), url('/assets/img/header-bg-madrid.webp') type('image/webp'), url('/assets/img/header-bg-madrid.jpg') type('image/jpeg')); }
.site-header--barcelona { background-image: url('/assets/img/header-bg-barcelona.jpg');
 background-image: image-set(url('/assets/img/header-bg-barcelona.avif') type('image/avif'), url('/assets/img/header-bg-barcelona.webp') type('image/webp'), url('/assets/img/header-bg-barcelona.jpg') type('image/jpeg')); }
.site-header--valencia { background-image: url('/assets/img/header-bg-valencia.jpg');
 background-image: image-set(url('/assets/img/header-bg-valencia.avif') type('image/avif'), url('/assets/img/header-bg-valencia.webp') type('image/webp'), url('/assets/img/header-bg-valencia.jpg') type('image/jpeg')); }
.site-header--murcia { background-image: url('/assets/img/header-bg-murcia.jpg');
 background-image: image-set(url('/assets/img/header-bg-murcia.avif') type('image/avif'), url('/assets/img/header-bg-murcia.webp') type('image/webp'), url('/assets/img/header-bg-murcia.jpg') type('image/jpeg')); }

/* Three.js particle canvas (assets/js/header-particles.js) — sits behind
   the nav row but above the background photo; pointer-events stays off so
   clicks always reach the logo/hamburger/lang-switch above it. */
.header-particles {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
}
.header-particles canvas { display: block; }
.site-header-inner {
  position: relative;
  /* Was 2 — enough to clear .header-particles (z-index: 1) right behind
     it, but that also caps EVERY descendant's own stacking (the hamburger
     dropdown, z-index: 50) to compete at only "2" against the rest of the
     page, since position+z-index together make this its own stacking
     context. A later-in-DOM element elsewhere on the page with an equal or
     higher z-index (e.g. .event-card-badges' "Today" badge, z-index: 2)
     then wins that tie and renders on top of the whole open dropdown.
     60 clears every other local-popover-style z-index on the page (up to
     .hamburger-menu's own 50) while staying well under the 1000+ range
     reserved for true modals/lightboxes. */
  z-index: 60;
  display: grid;
  grid-template-columns: 1fr auto 1fr;
  align-items: center;
  gap: 12px;
  padding: 16px 28px;
}
.logo {
  grid-column: 2;
  justify-self: center;
  text-align: center;
  font-family: var(--font-heading);
  font-size: 1.5rem;
  color: var(--color-primary);
  text-decoration: none;
  font-weight: bold;
}
.main-nav {
  grid-column: 3;
  justify-self: end;
  display: flex;
  align-items: center;
  gap: 18px;
}
.main-nav a {
  text-decoration: none;
  color: var(--color-text);
  font-weight: 600;
}
/* SVG-flag #lang-select (templates/header.php, public pages only) — enhanced
   by custom-select.js into the same compact button+popup as the toolbar's
   own selects, but styled here as a plain borderless pill (no visible
   label — the flag/chevron are the only content, the language name itself
   is .visually-hidden, see that file's own comment) sized to match
   .search-toggle-btn's own height beside it in .main-nav, rather than the
   wider field-style look .status-filter-select/.field .custom-select-btn
   give other contexts. The dropdown chevron (base .custom-select-btn::after
   rule) stays visible here, unlike the rest of this button's own styling —
   without it, a single flag with no other affordance doesn't read as
   "click for more options". Targeted via the adjacent-sibling
   selector since custom-select.js doesn't copy the <select>'s own id onto
   the button it builds. */
#lang-select + .custom-select-btn {
  height: 32px;
  padding: 0 10px;
  border: none;
  background: none;
  border-radius: 16px;
  justify-content: center;
  gap: 4px;
}
#lang-select + .custom-select-btn:hover { background: var(--color-border); }
/* The flag icon itself (assets/img/flags/*.svg, from the free flag-icons
   set) — same fixed size in the pill button and in each dropdown row, with
   a hairline border since several of these flags have a white/pale edge
   that would otherwise blend into a light-mode background. */
.custom-select-flag {
  width: 20px;
  height: 15px;
  object-fit: cover;
  border-radius: 2px;
  box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.15);
  flex: 0 0 auto;
}
/* Magnifier button (assets/js/search-toggle.js) — opens/closes the
   #search-panel overlay below (see its own comment). Sits in the same
   .main-nav flex row as #lang-select, so its own 18px gap already spaces
   the two apart. */
.search-toggle-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-text);
  cursor: pointer;
}
.search-toggle-btn:hover, .search-toggle-btn[aria-expanded="true"] { background: var(--color-border); }

/* Hamburger menu (top-left) — assets/js/hamburger-menu.js */
.hamburger-wrap { grid-column: 1; justify-self: start; position: relative; }
.hamburger-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--color-border);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.85);
  color: var(--color-primary-dark);
  cursor: pointer;
}
.hamburger-btn:hover, .hamburger-btn[aria-expanded="true"] { background: var(--color-border); }
.hamburger-menu {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 8px;
  /* Wide enough that a region label like "Comunidad Valenciana" or
     "Región de Murcia" doesn't wrap onto 2-3 lines inside the indented
     submenu items (see .hamburger-submenu a's own left padding below). Was
     260px — still wrapped a longer "Country — Region" combo (e.g. "España
     — Comunidad Valenciana") onto 2 lines on a narrow phone. Widened
     further still (desktop: 800px below; mobile: full screen width minus
     an equal margin) on request, beyond what wrapping alone needed. */
  min-width: 320px;
  max-width: calc(100vw - 32px);
  z-index: 50;
  display: flex;
  flex-direction: column;
  gap: 2px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 6px;
}
/* Desktop: 150% wider than the 320px base above (i.e. 2.5×) on request —
   well past what any label actually needs to wrap, purely a sizing
   preference. Only above the 700px breakpoint mobile's own override (below)
   uses instead. */
@media (min-width: 701px) {
  .hamburger-menu { min-width: 800px; }
}
/* Without this, the menu stayed visible at all times regardless of the
   [hidden] attribute hamburger-menu.js toggles — an author-stylesheet
   display value always wins over the browser's own [hidden] default,
   whatever the specificity, so it has to be spelled out explicitly. */
.hamburger-menu[hidden] { display: none; }
/* Invisible hover bridge over the visual gap (margin-top above) between the
   button and the menu — without it, moving the mouse from the button down
   toward the menu crosses a strip of empty space with nothing rendered in
   it, the cursor loses :hover for an instant, and .hamburger-wrap:hover
   below stops applying before the mouse ever reaches the menu itself. */
.hamburger-menu::before {
  content: "";
  position: absolute;
  top: -8px;
  left: 0;
  right: 0;
  height: 8px;
}
.hamburger-menu a {
  display: block;
  padding: 10px 12px;
  border-radius: 6px;
  color: var(--color-text);
  text-decoration: none;
  font-weight: 600;
  font-size: 0.92rem;
}
.hamburger-menu a:hover { background: var(--color-bg); color: var(--color-primary-dark); }

/* Country/region submenus (see templates/header.php's $renderEventTypeMenu) —
   plain <details>/<summary>, no extra JS needed for the expand/collapse. */
.hamburger-submenu summary {
  padding: 10px 12px;
  border-radius: 6px;
  font-weight: 600;
  font-size: 0.92rem;
  cursor: pointer;
  list-style: none;
}
.hamburger-submenu summary::-webkit-details-marker { display: none; }
.hamburger-submenu summary:hover { background: var(--color-bg); color: var(--color-primary-dark); }
.hamburger-submenu summary::after {
  content: "\25BE";
  float: right;
  color: var(--color-text-muted, currentColor);
}
.hamburger-submenu[open] summary::after { content: "\25B4"; }
.hamburger-submenu a { padding-left: 24px; font-weight: 500; }
/* Bullet only on the actual region links, not the "All regions"/unfiltered
   one above them (see $renderEventTypeMenu's own comment — that one's
   always the first entry) — display: list-item generates a native marker
   on any element, no <ul>/<li> restructuring needed. */
.hamburger-submenu-country { margin-left: 12px; }
.hamburger-submenu-country summary { font-weight: 500; }
a.hamburger-submenu-region { display: list-item; list-style-type: disc; list-style-position: inside; }

/* On devices with a real pointer (mouse/trackpad), hovering the button also
   peeks the menu open — a convenience on top of the click/tap-to-toggle
   that JS drives everywhere. Scoped to (hover: hover) so touchscreens (which
   report hover: none) rely purely on tap, avoiding the classic "stuck open
   after a tap" mobile hover bug.
   Suppressed while #search-panel is open: that overlay sits at a higher
   z-index (see its own comment), so a hover-revealed hamburger menu would
   render fully behind it — invisible, not just visually competing. The
   click-driven open/close in assets/js/hamburger-menu.js and
   search-toggle.js already close one when the other opens; this covers the
   one path those can't (a mouse hovering the button without ever clicking
   it — :has() support is assumed here, so this whole rule is simply
   skipped, and the peek convenience lost, on any browser without it,
   rather than misbehaving). */
@media (hover: hover) {
  .site-header-inner:not(:has(#search-panel:not([hidden]))) .hamburger-wrap:hover .hamburger-menu[hidden] { display: flex; }
}

/* Buttons */
.btn {
  display: inline-block;
  padding: 10px 18px;
  border-radius: var(--radius);
  border: 1px solid transparent;
  font-weight: 600;
  cursor: pointer;
  text-decoration: none;
  font-size: 0.95rem;
}
.btn-primary { background: var(--color-primary); color: #fff; }
.btn-primary:hover { background: var(--color-primary-dark); }
.btn-outline { background: transparent; border-color: var(--color-primary); color: var(--color-primary-dark); }
.btn-outline:hover { background: #fbeee6; }
.btn-outline.btn-danger { border-color: #A83232; color: #A83232; }
.btn-outline.btn-danger:hover { background: #F3E1E1; }
.btn-toggle { background: var(--color-surface); border-color: var(--color-border); color: var(--color-text-muted); }
.btn-toggle.is-active { background: var(--color-accent); border-color: var(--color-accent); color: #fff; }
/* iOS-style on/off switch (track + sliding thumb), driven by a real
   checkbox's own :checked state (via an adjacent-sibling selector) — e.g.
   admin/sources.php's "Enabled" column, where the checkbox itself still
   needs to behave like a normal form field (checked/unchecked submits with
   the rest of the form) rather than a JS-only control. */
.switch-track {
  position: relative;
  flex-shrink: 0;
  width: 40px;
  height: 22px;
  border-radius: 999px;
  background: var(--color-border);
  transition: background-color 0.15s ease;
}
.switch-thumb {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  background: #fff;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.3);
  transition: transform 0.15s ease;
}
.switch-toggle { position: relative; display: inline-flex; cursor: pointer; }
.switch-toggle input[type="checkbox"] { position: absolute; width: 1px; height: 1px; opacity: 0; }
.switch-toggle input[type="checkbox"]:checked + .switch-track { background: var(--color-accent); }
.switch-toggle input[type="checkbox"]:checked + .switch-track .switch-thumb { transform: translateX(18px); }
.switch-toggle input[type="checkbox"]:focus-visible + .switch-track { outline: 2px solid var(--color-accent); outline-offset: 2px; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }
.btn:disabled:hover { background: transparent; }
.btn-inline { align-self: flex-start; padding: 6px 12px; font-size: 0.85rem; }
.btn-inline[hidden] { display: none; }

.link-btn {
  background: none;
  border: none;
  padding: 0;
  color: var(--color-primary-dark);
  font-weight: 600;
  cursor: pointer;
  text-decoration: underline;
}
.link-btn-danger { color: #a83232; }
.link-btn:disabled { color: var(--color-text-muted); cursor: not-allowed; text-decoration: none; }
.link-btn-icon {
  display: inline-flex;
  align-items: center;
  text-decoration: none;
  opacity: 0.7;
  background: none;
  border: none;
  padding: 0;
  margin: 0;
  color: inherit;
  font: inherit;
  cursor: pointer;
}
.link-btn-icon:hover { opacity: 1; }

/* Search panel — a click-to-open overlay (assets/js/search-toggle.js)
   anchored to .site-header-inner (position:relative, z-index:60 — see its
   own comment), so top:100% drops it right below the nav row and lets it
   expand OVER the rest of the header's own background image, rather than
   push page content down the way it did before this was an overlay.
   right:0 alone (no left/width) both sizes it to its own content — the
   panel is just a transparent wrapper around .search-form's own opaque,
   self-padded card now that the form itself is compact (Country/Keyword/
   Search all on one row) — and keeps it flush with the SAME padding-box
   edge .main-nav's own magnifier button sits against, so the panel opens
   right under/near it instead of a full-bleed bar spanning the whole
   header. Mobile keeps the old edge-to-edge width instead (see the
   @media (max-width: 600px) override below) — there's no "near the
   magnifier" room to spare on a narrow phone screen anyway. */
.search-panel {
  position: absolute;
  top: 100%;
  right: 0;
  z-index: 55;
  padding: 10px 0 24px;
}
@media (max-width: 600px) {
  .search-panel { left: 0; }
}
.search-panel[hidden] { display: none; }
.search-form {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 14px;
  align-items: flex-end;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow);
}
.field[hidden] { display: none; }
.field { display: flex; flex-direction: column; gap: 4px; }
.field-grow { flex: 1 1 220px; }
.field-narrow { max-width: 100px; }
/* justify-content: flex-end keeps the action buttons (wrapped together in
   .field-actions-buttons so they move as one group) pinned to the row's
   own right edge. */
.field-actions { flex-direction: row; align-items: center; justify-content: flex-end; gap: 10px; flex-wrap: wrap; }
.field-actions-buttons { display: flex; gap: 10px; }
.field label { font-size: 0.8rem; color: var(--color-text-muted); font-weight: 600; }
.field input, .field select, .field textarea, .field .custom-select-btn {
  padding: 9px 10px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  font-size: 0.95rem;
  font-family: inherit;
  background: #fff;
  color: var(--color-text);
}
/* Keyword's own "x" (templates/header.php) — sits INSIDE the input itself,
   right-aligned and vertically centered, rather than as a separate element
   beside it — .field-clearable becomes the positioning context, and the
   input's own right padding leaves room so its own text never runs under
   the button. Hidden via the `hidden` attribute (toggled in JS) whenever
   the field is already empty, not shown as a permanent fixture. */
.field-clearable { position: relative; }
.field-clearable > input { width: 100%; padding-right: 34px; }
.field-clear-btn {
  position: absolute;
  top: 50%;
  right: 4px;
  transform: translateY(-50%);
  width: 24px;
  height: 24px;
  padding: 0;
  font-size: 1rem;
  line-height: 1;
  border-radius: 50%;
  border: none;
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
}
.field-clear-btn:hover { color: var(--color-text); background: var(--color-border); }
.field-row { display: flex; gap: 14px; flex-wrap: wrap; }
.field-row .field { flex: 1 1 160px; }
.field-row .venue-alias-input { flex: 1 1 160px; }
/* Scoped to the search panel specifically (unlike admin/api-keys.php's own
   use of the shared .field-grow, which should keep growing to fill its
   row) — capped so the keyword field doesn't expand to fill all remaining
   width on its own row. */
.search-form .field-grow { flex: 1 1 200px; max-width: 320px; }
/* Moved out of its own .field-actions row and into #search-filters-row
   directly, right after Keyword, now that Search is the only button left
   there (Clear filters/Near me/past-events all moved out or were removed —
   see this row's own comment). flex-shrink: 0 keeps it at its natural
   width even as .field-grow's own keyword input shrinks first on a
   narrower row. */
.search-form-submit { flex-shrink: 0; }
/* #search-filters-row is .search-form's only direct child now (Search
   used to sit in its own separate .field-actions row below it — see
   .search-form-submit's own comment for why it moved into this row
   instead) — flex-basis: 100% just keeps it spanning the form's own full
   width rather than sizing to its content. */
.search-form > .field-row { flex-basis: 100%; }
/* Country/Keyword are each a label-on-top .field (see .field's own
   flex-direction: column above), so without this the label-less Search
   button — .search-form's own align-items: flex-end only positions
   #search-filters-row AS A WHOLE, not each item inside its own nested flex
   row — would stretch to match their full label+input height instead of
   sitting flush with just the input boxes at the bottom. */
#search-filters-row { align-items: flex-end; }
.field-hint { font-size: 0.8rem; color: var(--color-text-muted); margin: 4px 0 0; }
.field-warning { font-size: 0.85rem; margin: 6px 0 0; padding: 8px 12px; border-radius: var(--radius); background: #FFF3D6; color: #8A6D1D; }
.field-warning[hidden] { display: none; }
.field-warning a { color: inherit; font-weight: 600; margin-left: 6px; }

.permalink-field { display: flex; align-items: center; flex-wrap: wrap; gap: 0; }
.permalink-prefix { font-size: 0.85rem; color: var(--color-text-muted); white-space: nowrap; }
.permalink-field input { flex: 1 1 160px; min-width: 0; }
.permalink-clear {
  flex-shrink: 0;
  width: 28px;
  height: 28px;
  margin-left: 6px;
  padding: 0;
  font-size: 1rem;
  line-height: 1;
  border-radius: 50%;
  border: 1px solid var(--color-border);
  background: transparent;
  color: var(--color-text-muted);
  cursor: pointer;
}
.permalink-clear:hover { color: var(--color-text); border-color: var(--color-text-muted); }

/* White pill, not plain text — the search bar sits over the header's own
   background image/photo, where the previous muted-on-transparent text
   was hard to read. */
.geo-status {
  display: inline-block;
  margin-top: 10px;
  padding: 6px 14px;
  background: var(--color-surface);
  color: var(--color-text);
  border-radius: 999px;
  font-size: 0.9rem;
  box-shadow: 0 1px 4px rgba(0, 0, 0, 0.2);
}
/* The unconditional display:inline-block above overrides [hidden]'s own
   default display:none — same gotcha as .field-row[hidden] elsewhere in
   this file. Without this, turning "near me" off (search.js sets
   geoStatus.hidden = true) left this pill visibly stuck on screen. */
.geo-status[hidden] { display: none; }

/* Results */
.results-panel { padding: 10px 0 40px; }
.view-toggle { display: flex; align-items: center; gap: 8px; margin-bottom: 16px; flex-wrap: wrap; }
/* Sits inline inside .view-toggle now, right after the home button — no
   margin of its own (used to be a standalone row above it). */
/* flex-wrap here too (not just on .view-toggle around it) — .type-filter
   itself wrapping onto its own line inside .view-toggle doesn't help if
   its own two <select>s then can't wrap relative to EACH OTHER: real
   Android/Chrome native <select> chrome can render wider than desktop
   testing shows, and with no wrap here that combined width just overflows
   the page horizontally instead of dropping to a second line. */
.type-filter { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; max-width: 100%; }
/* Narrow screens: Region and Type share one row (each shrunk to half width,
   own text ellipsis-truncating if it doesn't fit — see .status-filter-select's
   own overflow/text-overflow rule below), with List/Map/Calendar/Refresh
   pushed onto their own row underneath — flex-basis: 100% on .type-filter
   makes it always claim the FULL row width inside .view-toggle, so whatever
   comes after it in DOM order (the view buttons) has no room left and wraps.
   Applies whether these are custom-select.js's own compact buttons or (JS
   off) the plain native <select>s underneath — this rule's own sibling
   comment's per-<select> flex-wrap safety net above still applies on top of
   this if a really long option label ever can't fit even at half width. */
@media (max-width: 600px) {
  .type-filter { flex: 1 1 100%; }
  .type-filter .status-filter-select { flex: 1 1 0; max-width: none; min-width: 0; }
}
.btn-icon { display: inline-flex; align-items: center; justify-content: center; padding: 9px; }
.icon-home { flex-shrink: 0; }
.btn-share { position: relative; display: inline-flex; align-items: center; gap: 6px; }
.icon-share { flex-shrink: 0; }
.btn-calendar { display: inline-flex; align-items: center; gap: 6px; }
.icon-calendar { flex-shrink: 0; }

/* Generic "(i)" info icon + custom popover (assets/js/info-popover.js). */
.info-icon-wrap { position: relative; display: inline-flex; align-items: center; }
.info-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  padding: 0;
  border: none;
  border-radius: 50%;
  background: none;
  color: var(--color-text-muted);
  cursor: pointer;
}
.info-icon:hover, .info-icon[aria-expanded="true"] { color: var(--color-primary-dark); background: var(--color-border); }
.info-popover {
  position: absolute;
  top: 100%;
  left: 0;
  margin-top: 10px;
  width: 240px;
  z-index: 40;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 10px 12px;
  font-size: 0.82rem;
  font-weight: 400;
  line-height: 1.45;
  color: var(--color-text);
  text-align: left;
}
.info-popover::before {
  content: "";
  position: absolute;
  bottom: 100%;
  left: 10px;
  border: 6px solid transparent;
  border-bottom-color: var(--color-border);
}
.info-popover::after {
  content: "";
  position: absolute;
  bottom: 100%;
  left: 11px;
  border: 5px solid transparent;
  border-bottom-color: var(--color-surface);
}
/* margin-left: auto pushes this button (and everything after it —
   currently just Share) to the row's own right edge, leaving
   List/Map/Calendar at the left — same technique the button it replaces
   (the old #btn-refresh) used. .is-active mirrors .btn-toggle's own
   accent-fill convention (see that rule above) for "near me" being on. */
.view-toggle #btn-near-me-toolbar { margin-left: auto; }
.view-toggle #btn-near-me-toolbar.is-active { background: var(--color-accent); border-color: var(--color-accent); color: #fff; }
.share-status {
  display: block;
  margin-top: 6px;
  font-size: 0.8rem;
  color: var(--color-text-muted);
}
.view-toggle .share-status {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 4px;
  white-space: nowrap;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 4px 8px;
  box-shadow: var(--shadow);
}
.event-detail-actions { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.event-related-region { margin-top: 40px; padding-top: 24px; border-top: 1px solid var(--color-border); }
.event-related-region h2 { margin: 0 0 16px; }

.event-grid[hidden], .event-map-wrap[hidden], .event-calendar-wrap[hidden] {
  display: none;
}

.event-grid {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
  gap: 20px;
}
/* grid-column: 1 / -1 spans every column regardless of how many auto-fill
   creates at the current width, so the heading always sits on its own
   full-width row rather than sharing a row with a card. */
.week-title {
  grid-column: 1 / -1;
  margin: 6px 0 -6px;
  font-size: 1.05rem;
  font-weight: 700;
  color: var(--color-emphasis);
  border-bottom: 2px solid var(--color-border);
  padding-bottom: 8px;
}
.week-title:first-child { margin-top: 0; }
.week-title a { color: inherit; text-decoration: none; }
.week-title a:hover { text-decoration: underline; }
.event-card {
  position: relative;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow);
  transition: transform 0.15s ease;
}
.event-card:hover { transform: translateY(-2px); }
.event-card-today {
  border-color: var(--color-accent);
  box-shadow: 0 0 0 2px var(--color-accent), var(--shadow);
}
/* "Other tango events" (event_type=other) get a light golden tint so they
   read as visually distinct from regular milongas at a glance in the list
   and map popups, without being as loud as the solid-gold "Today" ring. */
.event-card-other { background: #FFF6E0; border-color: #E9CE8E; }
.event-card-badges {
  position: absolute;
  top: 10px;
  left: 10px;
  z-index: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 4px;
}
.event-card-badge {
  background: var(--color-accent);
  color: #fff;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  padding: 3px 9px;
  border-radius: 999px;
  box-shadow: var(--shadow);
}
.event-card-badge-unconfirmed { background: #A83232; }
.event-card-badge-cancelled { background: #5A5A5A; }
.event-card-badge-new {
  background: var(--color-primary);
  animation: badge-new-flash 1.6s ease-in-out infinite;
}
@keyframes badge-new-flash {
  0%, 100% { opacity: 1; }
  50% { opacity: 0.5; }
}
@media (prefers-reduced-motion: reduce) {
  .event-card-badge-new { animation: none; }
}
.event-card-badge-date-changed { background: #5B4A8A; }
.event-card-badge-sold-out { background: #B45309; }
.event-card-meta.is-cancelled { text-decoration: line-through; }
.event-card-edit {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 50%;
  background: var(--color-surface);
  color: var(--color-primary-dark);
  box-shadow: var(--shadow);
}
.event-card-edit:hover { background: var(--color-accent); color: #fff; }
.event-card-link { text-decoration: none; color: inherit; display: flex; flex-direction: column; height: 100%; }
.event-card-img { width: 100%; height: 160px; object-fit: cover; display: block; background: var(--color-border); flex-shrink: 0; }
.event-card-body { padding: 14px; display: flex; flex-direction: column; flex: 1; }
.event-card-title { margin: 0 0 6px; font-size: 1.1rem; color: var(--color-emphasis); }
.event-card-meta { margin: 0 0 4px; color: var(--color-primary-dark); font-weight: 600; font-size: 0.9rem; }
.event-card-location { margin: 0; color: var(--color-text-muted); font-size: 0.85rem; }

/* CTA inside the card's own <a> (not a separate link — nesting an <a>
   inside .event-card-link would be invalid HTML) — visual affordance for
   the same click-anywhere-on-the-card navigation. */
.event-card-cta {
  display: flex;
  align-items: center;
  gap: 6px;
  width: fit-content;
  margin: auto 0 0 auto;
  padding: 6px 12px;
  border: 1px solid var(--color-primary);
  border-radius: var(--radius);
  color: var(--color-primary-dark);
  font-size: 0.85rem;
  font-weight: 600;
}
.icon-arrow { flex-shrink: 0; }
@media (max-width: 600px) {
  .event-card-cta { padding: 7px; border-radius: 50%; }
  .event-card-cta-label { display: none; }
}

/* z-index: 1 (not just position:relative) is load-bearing — without an
   EXPLICIT value here this stays z-index:auto, which does NOT create a new
   stacking context, so Leaflet's own internal controls (.leaflet-top/
   .leaflet-bottom, z-index: 1000 in leaflet.css) escape this wrapper
   entirely and compete directly against .site-header-inner's z-index: 60
   at the page level — and win, rendering the map's zoom/fullscreen controls
   ABOVE the search panel whenever the two visually overlap (a tall open
   panel on a short mobile viewport, map view underneath it). Any low value
   works; the point is just to trap Leaflet's own 1000-ish internal range
   inside its own contained stacking context instead of leaking it out. */
.event-map-wrap { position: relative; z-index: 1; }
.event-map, .event-map-single { position: relative; height: 480px; border-radius: var(--radius); overflow: hidden; border: 1px solid var(--color-border); }
.event-map-single { height: 220px; margin: 10px 0 8px; }
.btn-directions { display: flex; align-items: center; justify-content: center; gap: 6px; width: 100%; margin-bottom: 20px; box-sizing: border-box; }

/* Fullscreen toggle (assets/js/map-fullscreen.js) — styled like Leaflet's
   own zoom control (plain white box) rather than the site's branded
   buttons, since it sits directly on top of map tiles. */
.map-fullscreen-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 1000;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 34px;
  height: 34px;
  padding: 0;
  border: none;
  border-radius: 4px;
  background: #fff;
  color: #333;
  cursor: pointer;
  box-shadow: 0 1px 5px rgba(0, 0, 0, 0.4);
}
.map-fullscreen-btn:hover { background: #f4f4f4; }

.event-map:fullscreen, .event-map-single:fullscreen,
.event-map:-webkit-full-screen, .event-map-single:-webkit-full-screen {
  width: 100vw;
  height: 100vh;
  border-radius: 0;
  border: none;
  margin: 0;
}

.map-legend {
  position: absolute;
  z-index: 1000;
  bottom: 12px;
  left: 12px;
  max-width: 220px;
  display: flex;
  flex-direction: column;
  gap: 3px;
  background: rgba(255, 255, 255, 0.92);
  border: 1px solid var(--color-border);
  border-radius: 6px;
  padding: 6px 10px;
  font-size: 0.8rem;
  color: var(--color-text);
  box-shadow: var(--shadow);
}
.map-legend-row { display: flex; align-items: center; gap: 6px; margin: 0; }
.map-legend-note { margin: 0; font-size: 0.7rem; line-height: 1.3; color: var(--color-text-muted); }
.map-legend-marker {
  width: 12px;
  height: 12px;
  border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg);
  flex-shrink: 0;
}
.map-legend-marker-today {
  background: #D9A441;
  border: 1.5px solid #6E2C3D;
}

.event-calendar-wrap {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 16px;
}

/* Admin calendar (admin/events.php): this month + next month side by side
   on desktop, one page on mobile — see admin_render_calendar_grid(). */
.admin-calendar-pages { display: flex; flex-direction: column; gap: 20px; }
.calendar-page-second { display: none; }
@media (min-width: 900px) {
  .admin-calendar-pages { flex-direction: row; align-items: flex-start; }
  .admin-calendar-pages > .calendar-page { flex: 1 1 0; min-width: 0; }
  .calendar-page-second { display: block; }
  .calendar-nav-next-mobile { display: none; }
}
.calendar-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 12px;
  font-size: 1.1rem;
  font-weight: 700;
  color: var(--color-emphasis);
}
.calendar-nav {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.3rem;
  line-height: 1;
  padding: 4px 12px;
  border-radius: 6px;
  color: var(--color-primary-dark);
}
.calendar-nav:hover:not(:disabled) { background: var(--color-border); }
.calendar-nav:disabled { opacity: 0.35; cursor: default; }
.calendar-grid {
  display: grid;
  /* minmax(0, 1fr), not plain 1fr — a plain 1fr track's minimum width is
     still its content's natural size, so a long unbroken event title could
     force that one column wider than the rest. Clamping the minimum to 0
     forces all 7 columns to stay truly equal, letting overflow/ellipsis on
     the chip itself handle anything that doesn't fit. */
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 1px;
  background: var(--color-border);
  border: 1px solid var(--color-border);
  border-radius: 8px;
  overflow: hidden;
}
.calendar-weekday {
  background: var(--color-bg);
  text-align: center;
  font-size: 0.72rem;
  font-weight: 700;
  text-transform: uppercase;
  color: var(--color-text-muted);
  padding: 6px 0;
}
.calendar-day {
  background: var(--color-surface);
  min-height: 92px;
  min-width: 0;
  padding: 4px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}
.calendar-day.is-outside { background: var(--color-bg); }
.calendar-day.is-today { background: #FFF7EA; }
.calendar-day-number { font-size: 0.78rem; font-weight: 700; color: var(--color-text-muted); }
.calendar-day.is-today .calendar-day-number { color: var(--color-primary-dark); }
.calendar-event-chip {
  display: block;
  background: var(--color-accent);
  color: #fff;
  font-size: 0.68rem;
  font-weight: 600;
  padding: 2px 5px;
  border-radius: 4px;
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.calendar-event-chip:hover { opacity: 0.85; }
.calendar-more { font-size: 0.68rem; color: var(--color-text-muted); padding: 1px 5px; }

/* Past days, shown only to a logged-in admin (see search.js) — dimmed
   rather than hidden, so history stays visibly distinct from what's next. */
.calendar-day.is-past .calendar-event-chip { opacity: 0.4; }
.calendar-day.is-past .calendar-event-chip:hover { opacity: 0.65; }
.calendar-day.is-past .calendar-more { opacity: 0.6; }
@media (max-width: 700px) {
  .calendar-day { min-height: 60px; }
  .calendar-weekday { font-size: 0.62rem; padding: 4px 0; }
  .calendar-day-number { font-size: 0.68rem; }
  .calendar-event-chip, .calendar-more { font-size: 0.58rem; padding: 1px 3px; }
}

/* Event-card popups on the map: the Leaflet chrome already supplies the
   rounded wrapper/shadow, so the card inside drops its own to avoid doubling up. */
.map-popup .leaflet-popup-content-wrapper { padding: 0; border-radius: var(--radius); overflow: hidden; }
.map-popup .leaflet-popup-content { margin: 0; }
.map-popup .leaflet-popup-tip-container { margin-top: -1px; }
.map-popup-card { border: none; box-shadow: none; border-radius: 0; }
.map-popup-card .event-card-img { height: 120px; }
.map-popup-card .event-card-body { padding: 10px 12px; }
.map-popup-card .event-card-title { font-size: 1rem; }
.btn-directions-popup {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 5px;
  width: calc(100% - 24px);
  margin: 0 12px 10px;
  padding: 6px 10px;
  font-size: 0.78rem;
  box-sizing: border-box;
}
.map-popup .leaflet-popup-close-button {
  top: 6px; right: 6px; width: 22px; height: 22px; line-height: 20px;
  background: rgba(255,255,255,0.9); border-radius: 50%; text-align: center;
}

.empty-state { color: var(--color-text-muted); padding: 30px 0; }
.empty-state-nearest { grid-column: 1 / -1; padding: 8px 0 0; margin: 0; text-align: center; }

.not-found {
  max-width: 420px;
  margin: 40px auto 60px;
  padding: 0 20px;
  text-align: center;
}
.not-found-img { width: 220px; max-width: 100%; margin: 0 auto 20px; display: block; }
.not-found h1 { color: var(--color-emphasis); margin-bottom: 10px; }
.not-found p { color: var(--color-text-muted); line-height: 1.6; margin-bottom: 22px; }

/* Event detail */
.back-link { display: inline-block; margin: 20px 0 16px; text-decoration: none; }
.event-detail-top { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 8px; }
.event-nav { display: flex; gap: 8px; margin: 20px 0 16px; }
.event-detail-layout { display: grid; grid-template-columns: 2fr 1fr; gap: 30px; }
.event-detail-img { width: 100%; border-radius: var(--radius); margin-bottom: 16px; box-shadow: var(--shadow); }
.event-detail-img[data-lightbox] { cursor: zoom-in; }

/* Full-size image overlay (assets/js/lightbox.js). */
.lightbox-overlay {
  position: fixed;
  inset: 0;
  z-index: 3000;
  background: rgba(20, 12, 8, 0.88);
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 50px 20px;
}
.lightbox-img {
  max-width: 100%;
  max-height: 100%;
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.lightbox-close {
  position: fixed;
  top: 14px;
  right: 20px;
  background: none;
  border: none;
  color: #fff;
  font-size: 2.2rem;
  line-height: 1;
  cursor: pointer;
  padding: 6px 10px;
}
.lightbox-close:hover { opacity: 0.8; }
.lightbox-nav {
  position: fixed;
  top: 50%;
  transform: translateY(-50%);
  background: rgba(0, 0, 0, 0.35);
  border: none;
  color: #fff;
  font-size: 2.6rem;
  line-height: 1;
  cursor: pointer;
  padding: 10px 16px;
  border-radius: var(--radius);
}
.lightbox-nav:hover { background: rgba(0, 0, 0, 0.55); }
.lightbox-prev { left: 10px; }
.lightbox-next { right: 10px; }
.lightbox-caption {
  position: fixed;
  bottom: 48px;
  left: 50%;
  transform: translateX(-50%);
  max-width: min(90vw, 600px);
  color: #fff;
  background: rgba(0, 0, 0, 0.35);
  padding: 4px 14px;
  border-radius: var(--radius);
  font-size: 0.9rem;
  text-align: center;
}
.lightbox-counter {
  position: fixed;
  bottom: 16px;
  left: 50%;
  transform: translateX(-50%);
  color: #fff;
  background: rgba(0, 0, 0, 0.35);
  padding: 4px 12px;
  border-radius: var(--radius);
  font-size: 0.85rem;
}
@media (max-width: 600px) {
  .lightbox-nav { font-size: 2rem; padding: 8px 12px; }
}
.event-detail-meta { color: var(--color-primary-dark); font-weight: 600; }
.event-detail-description { white-space: pre-line; margin: 16px 0; }
.event-detail-sidebar { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 18px; align-self: start; }
@media (max-width: 800px) {
  .event-detail-layout { grid-template-columns: 1fr; }
}

/* Admin */
.admin-bar { display: flex; align-items: center; justify-content: space-between; padding: 24px 0 10px; flex-wrap: wrap; gap: 10px; }
/* Every admin page's button row (nav, back, history, ...) sits on its own row
   below the page title: flex-basis: 100% forces the wrap unconditionally,
   relying on .admin-bar's own flex-wrap: wrap above. */
.admin-bar-actions { display: flex; align-items: center; justify-content: flex-start; gap: 12px; flex-wrap: wrap; flex-basis: 100%; }
/* "Signed in as X" + logout, in the site header's .main-nav
   (templates/header.php), top right of every back-office page. */
.admin-settings-link { margin-left: auto; }
.admin-bar-signed-in { display: flex; align-items: center; gap: 12px; }
.admin-toolbar { display: flex; align-items: center; justify-content: space-between; margin-bottom: 16px; flex-wrap: wrap; gap: 10px; }
/* Admin toolbar "More" dropdown (templates/admin-nav-more.php) — reuses
   .hamburger-menu's exact panel styling (position/shadow/border/link
   treatment) below for a consistent look; only this wrapper's positioning
   context is new. Click-to-toggle only (admin-nav-dropdown.js), no
   hover-peek — a toolbar button, unlike the public header's hamburger, so
   the hover convenience there doesn't apply here.
   order: -1 pins it as the first (leftmost) item of its row regardless of
   DOM position — every admin page already places it first by hand, but
   .admin-bar-actions/.admin-toolbar have no flex-wrap safety net of their
   own, so on a narrow screen (or if a future edit adds a button before it)
   it stays the anchor of the row instead of drifting wherever the other
   buttons wrap to. */
.admin-nav-dropdown { position: relative; display: inline-block; order: -1; }
.status-filter a { margin-right: 10px; text-decoration: none; color: var(--color-text-muted); font-weight: 600; padding: 6px 10px; border-radius: 6px; }
.status-filter a.is-active { background: var(--color-accent); color: #fff; }
/* admin/events.php's All/Draft/Published/Unpublished filter — a <select>
   rather than the tab-style .status-filter above, styled to sit alongside
   the toolbar's .btn-outline buttons instead of a plain form-field look. */
.status-filter-select {
  padding: 9px 10px;
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  font-size: 0.95rem;
  font-weight: 600;
  font-family: inherit;
  background: #fff;
  color: var(--color-text);
  cursor: pointer;
  /* A long selected option's own text (e.g. "Todas las comunidades")
     truncates with an ellipsis instead of forcing the <select> wider than
     the screen on a narrow phone — max-width caps it well under a typical
     mobile viewport even before .type-filter's own flex-wrap kicks in. */
  max-width: min(100%, 220px);
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
/* admin/events.php's own status filter specifically (same id reused by its
   two mutually-exclusive copies — the list view's own "Status" column
   header and the calendar view's toolbar equivalent, only one ever
   rendered at once — see either one's own comment) — its own option text
   is short ("All statuses"/"Draft"/"Published"/"Unpublished", no repeated
   "Status: " prefix), so the shared 220px cap above left this column far
   wider than it needs to be. */
#admin-events-status-select { max-width: 140px; }

/* Compact custom dropdown (assets/js/custom-select.js) replacing a plain
   <select>'s native option list — used for the toolbar's own Region/Type
   selects above (reusing .status-filter-select's own box styling as-is,
   see that file's own comment) and the search panel's Country/Region
   fields (via .field .custom-select-btn, see that rule above). The
   <select> itself stays in the DOM, just hidden — real form field/source
   of truth, this is a purely visual layer on top of it.
   display: contents removes the wrapper from layout entirely so the
   button inherits whatever box/flex sizing the <select> itself used to
   get from ITS real parent, without needing separate width rules per
   context. */
.custom-select { display: contents; }
.custom-select-btn {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  text-align: left;
  cursor: pointer;
  /* font-family only (not the `font` shorthand) — a <button> doesn't
     inherit the page's font-family by default the way a <select> does,
     but the shorthand would also reset font-weight/size, clobbering
     .status-filter-select's own font-weight: 600 further up. */
  font-family: inherit;
}
.custom-select-btn span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
/* Plain CSS arrow (no glyph/icon font needed) — flips to point up while the
   list is open, same idea as a native <select>'s own indicator. */
.custom-select-btn::after {
  content: '';
  flex: 0 0 auto;
  width: 7px;
  height: 7px;
  border-right: 2px solid currentColor;
  border-bottom: 2px solid currentColor;
  opacity: 0.6;
  transform: translateY(-2px) rotate(45deg);
}
.custom-select-btn[aria-expanded="true"]::after { transform: translateY(1px) rotate(-135deg); }
.custom-select-btn:disabled { cursor: default; opacity: 0.6; }
.custom-select-pop {
  position: absolute;
  z-index: 1500;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 4px;
  overflow-y: auto;
}
/* Deliberately more compact than a native <select>'s own per-row spacing
   (Android Chrome in particular renders those much taller) — the actual
   complaint this whole component exists to fix. */
.custom-select-option {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 7px 10px;
  border-radius: 6px;
  font-size: 0.9rem;
  cursor: pointer;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.custom-select-option:hover, .custom-select-option.is-active { background: var(--color-bg); }
.custom-select-option.is-selected { font-weight: 600; color: var(--color-primary-dark); }

.admin-search-form { display: flex; align-items: center; gap: 8px; margin-left: auto; }
/* Search sits right-aligned, directly left of the settings cog. */
.admin-search-form + .admin-settings-link { margin-left: 0; }
/* Wraps the <input> so the "x" clear link (below) can sit absolutely
   positioned inside its right edge instead of as a separate "Limpiar"/
   "Borrar" text link after the search button. */
.admin-search-input-wrap { position: relative; display: inline-flex; align-items: center; }
.admin-search-form input[type="search"] {
  padding: 8px 26px 8px 10px;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  font-size: 0.9rem;
  /* Narrower than before (was 220px) — a wide toolbar (Events list: new/
     from-url/type-filter/view-toggle/search/settings) was wrapping the
     settings gear icon onto its own second line to make room for this
     field. Still wide enough for a normal search phrase; it's a text
     input, not fixed-width content, so it doesn't need to be this big to
     stay usable. */
  width: 140px;
}
/* The browser's own built-in search-cancel-button would otherwise sit right
   on top of .admin-search-clear below — this app's "clear" needs to be a
   real link (reloads the page with q= removed, same as every other filter
   here), not the native JS-only clear, so the native one is hidden rather
   than shown alongside a second, redundant "x". */
.admin-search-form input[type="search"]::-webkit-search-cancel-button { display: none; }
.admin-search-clear {
  position: absolute;
  right: 6px;
  top: 50%;
  transform: translateY(-50%);
  display: flex;
  align-items: center;
  justify-content: center;
  width: 18px;
  height: 18px;
  border-radius: 50%;
  line-height: 1;
  font-size: 1.1rem;
  color: var(--color-text-muted);
  text-decoration: none;
}
.admin-search-clear:hover { color: var(--color-text); background: var(--color-border); }

.admin-table { width: 100%; border-collapse: collapse; background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius); overflow: hidden; }
.admin-table th, .admin-table td { padding: 12px 14px; border-bottom: 1px solid var(--color-border); text-align: left; font-size: 0.92rem; }
.admin-table th { background: #FBF3EC; color: var(--color-emphasis); }
.admin-table-sort { color: inherit; text-decoration: none; font-weight: inherit; white-space: nowrap; }
.admin-table-sort:hover { text-decoration: underline; }
.admin-table-sort.is-active { color: var(--color-primary-dark); }
.admin-table tr.is-past { opacity: 0.55; }
.admin-pagination { display: flex; align-items: center; justify-content: center; gap: 14px; margin-top: 16px; }
.admin-pagination-label { color: var(--color-text-muted); font-size: 0.9rem; }
.admin-row-actions { display: flex; gap: 10px; align-items: center; flex-wrap: nowrap; }
.inline-form { display: inline; }

.col-drag-handle { width: 32px; padding-left: 10px; padding-right: 0; }
.drag-handle { display: inline-flex; color: var(--color-text-muted); cursor: grab; }
.admin-table tr[draggable="true"] { cursor: grab; }
.admin-table tr.is-dragging { opacity: 0.4; }
.source-url-cell a { word-break: break-all; }

/* admin/sources.php only — every other .admin-table (events, venues, ...)
   keeps its default left alignment; this one's columns are short, fixed-
   shape values (dates, a country name, a status dot, a count) where
   centering reads better, unlike events.php's long free-text titles. */
.admin-table-sources th, .admin-table-sources td { text-align: center; }
.admin-table-sources .source-url-cell { min-width: 280px; }
.admin-table-sources .admin-row-actions { justify-content: center; }

/* Status dot (admin/sources.php's "Estado" column) — a color-only signal
   with the actual label/detail only on hover (title attribute), replacing
   the old text badge so the column reads as a quick visual scan across
   many rows instead of a wall of uppercase pills. */
.status-dot { display: inline-block; width: 11px; height: 11px; border-radius: 50%; vertical-align: middle; }
.status-dot-ok { background: #2C6E31; }
.status-dot-error { background: #A83232; }
.status-dot-neutral { background: #B0B0B0; }

.col-id { width: 1%; white-space: nowrap; color: var(--color-text-muted); }
.col-thumb { width: 52px; padding-right: 0; }
.admin-thumb { width: 44px; height: 44px; object-fit: cover; border-radius: 4px; display: block; background: var(--color-bg); }
.admin-thumb[data-lightbox] { cursor: zoom-in; }
.admin-thumb-placeholder { object-fit: contain; padding: 4px; opacity: 0.5; }

/* Superadmin-only bulk selection, shared by admin/events.php and
   admin/sources.php (admin-bulk-select.js) */
.col-select { width: 36px; padding-right: 0; text-align: center; }

/* admin/events.php's (also venues/sources) own "Columns" multi-select (assets/js/admin-column-
   toggle.js) — one .hide-col-X per data column, each paired with a
   matching .col-X on that column's own <th>/<td>s. col-select and the
   Actions column aren't part of this (no .col-actions exists at all):
   both are structural, not data, and always stay visible. */
.admin-table.hide-col-id .col-id,
.admin-table.hide-col-thumb .col-thumb,
.admin-table.hide-col-title .col-title,
.admin-table.hide-col-type .col-type,
.admin-table.hide-col-date .col-date,
.admin-table.hide-col-country .col-country,
.admin-table.hide-col-region .col-region,
.admin-table.hide-col-city .col-city,
.admin-table.hide-col-languages .col-languages,
.admin-table.hide-col-status .col-status,
.admin-table.hide-col-confidence .col-confidence,
.admin-table.hide-col-url .col-url,
.admin-table.hide-col-organizer .col-organizer,
.admin-table.hide-col-email .col-email,
.admin-table.hide-col-phone .col-phone,
.admin-table.hide-col-updated_by .col-updated_by,
.admin-table.hide-col-updated_on .col-updated_on,
.admin-table.hide-col-name .col-name,
.admin-table.hide-col-coords .col-coords,
.admin-table.hide-col-events .col-events,
.admin-table.hide-col-enabled .col-enabled,
.admin-table.hide-col-last_scanned .col-last_scanned,
.admin-table.hide-col-scan_frequency .col-scan_frequency,
.admin-table.hide-col-last_event .col-last_event,
.admin-table.hide-col-events_count .col-events_count {
  display: none;
}
.col-url a, .col-email a, .col-phone a { word-break: break-all; }
/* admin/events.php's own Status filter (assets/js/admin-status-filter.js)
   — a checkbox popup reusing .custom-select-btn/.status-filter-select for
   the closed button and .custom-select-pop/.admin-column-toggle-item for
   the popup itself, same as the "Columns" picker just below reuses the
   same pieces for its own checkboxes. inline-flex so the wrapper <div>
   (block-level by default) doesn't stretch full width inside its <th>/
   toolbar row the way a plain <select> never did. */
.admin-status-filter-multi { display: inline-flex; }
/* The Country column header's filter: just a small chevron button next to the sort link (admin_country_filter_html()); highlighted while a country filter is active. */
.admin-country-filter { vertical-align: middle; margin-left: 2px; }
.admin-country-filter-btn { border: 0; background: transparent; color: inherit; cursor: pointer; font-size: 0.85rem; line-height: 1; padding: 3px 5px; border-radius: 4px; }
.admin-country-filter-btn:hover, .admin-country-filter-btn:focus-visible { background: rgba(0, 0, 0, 0.07); }
.admin-country-filter.is-filtered .admin-country-filter-btn { background: #F3ECD9; color: #8A6D1D; font-weight: 700; }
.admin-column-toggle { position: relative; display: inline-flex; }
.admin-column-toggle-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 6px 10px;
  border-radius: 6px;
  font-size: 0.9rem;
  cursor: pointer;
  white-space: nowrap;
}
.admin-column-toggle-item:hover { background: var(--color-bg); }

/* admin/events.php's own toolbar switch (Columns button's neighbor) —
   .switch-toggle itself is already display:inline-flex (see its own rule
   above); this just adds a visible text label + spacing, unlike the
   Users/Sources screens' own switch-toggle usage, which sits inside a
   table cell with no room or need for one. */
.admin-toolbar-switch { align-items: center; gap: 8px; font-size: 0.9rem; color: var(--color-text); }
.admin-toolbar-switch-label { white-space: nowrap; }

/* Inline-edit mode (assets/js/admin-inline-edit.js) — every .inline-
   editable <td> always carries both its plain .inline-display and an
   .inline-input; only one shows at a time, same class-on-<table> switch
   mechanism as the "Columns" picker's own .hide-col-X above. Hidden by
   default (base state) regardless of JS load order/failure, so a page
   with this script broken/blocked still just shows the normal read-only
   table. */
.admin-table .inline-input {
  display: none;
  width: 100%;
  min-width: 90px;
  padding: 4px 6px;
  font-size: 0.85rem;
  font-family: inherit;
  border: 1px solid var(--color-border);
  border-radius: 4px;
  background: var(--color-surface);
  color: var(--color-text);
}
.admin-table .inline-input:disabled { opacity: 0.5; cursor: not-allowed; }
.admin-table.inline-edit-on .inline-editable .inline-display { display: none; }
.admin-table.inline-edit-on .inline-editable .inline-input { display: inline-block; }
/* Brief feedback right after a successful/failed inline save — cleared on
   the next edit, not a persistent state of its own. */
.admin-table .inline-input.is-saving { opacity: 0.6; }
.admin-table .inline-input.is-error { border-color: #A83232; }
/* Floats above the page content, pinned to the viewport bottom, instead of
   sitting inline above the table — so it stays reachable without scrolling
   back up after selecting rows further down a long list. `hidden` (set in
   the PHP markup, toggled by admin-bulk-select.js) still fully removes it
   from layout regardless of this positioning. Width mirrors .container's
   own content box (max-width 1120px minus its 20px+20px padding) so the
   floating bar lines up with the page above it instead of spanning edge
   to edge. */
.admin-bulk-actions {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  background: #FBF3EC; border: 1px solid var(--color-border); border-radius: var(--radius);
  position: fixed; left: 20px; right: 20px; bottom: 16px; max-width: 1080px; margin: 0 auto;
  box-shadow: 0 4px 16px rgba(0, 0, 0, 0.18);
  z-index: 40;
}
.admin-bulk-actions #admin-bulk-count { font-weight: 600; color: var(--color-emphasis); margin-right: auto; }

.proposal-list { display: flex; flex-direction: column; gap: 14px; }
.proposal-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 16px 18px; }
.proposal-card h3 { margin: 8px 0 4px; font-size: 1.05rem; }
.proposal-card-header { display: flex; align-items: center; justify-content: space-between; gap: 12px; flex-wrap: wrap; }
.proposal-card-header-right { display: flex; align-items: center; gap: 12px; }
.proposal-source { font-size: 0.8rem; color: var(--color-text-muted); }
.proposal-source a { word-break: break-all; }

/* Before/after comparison for an update proposal's proposed_*_text fields
   (see admin/proposals.php) — reuses the site's existing red/green pair
   (badge-unpublished / badge-published) so "removed" vs "added" reads the
   same way it already does everywhere else. */
.proposal-diff { margin-top: 10px; display: flex; flex-direction: column; gap: 4px; }
.proposal-diff-row { display: flex; flex-wrap: wrap; align-items: baseline; gap: 6px; font-size: 0.9rem; }
.proposal-diff-label { font-weight: 700; color: var(--color-text-muted); }
.proposal-diff-before { color: #A83232; text-decoration: line-through; }
.proposal-diff-arrow { color: var(--color-text-muted); }
.proposal-diff-after { color: #2C6E31; font-weight: 600; }
.proposal-diff-description { margin-top: 10px; padding: 10px 12px; background: var(--color-bg); border-radius: var(--radius); font-size: 0.9rem; }
.proposal-diff-description p { margin: 4px 0; }
.proposal-diff-description .proposal-diff-before { text-decoration: none; }
.proposal-diff-poster { margin-top: 10px; display: flex; gap: 16px; flex-wrap: wrap; }
.proposal-diff-poster figure { margin: 0; text-align: center; }
.proposal-diff-poster img { border-radius: var(--radius); border: 1px solid var(--color-border); cursor: pointer; }
.proposal-diff-poster figcaption { margin-top: 4px; }

/* admin/proposal-review.php's side-by-side before/after comparison. */
.proposal-review-columns { display: flex; gap: 20px; flex-wrap: wrap; align-items: flex-start; margin-top: 16px; }
.proposal-review-column { flex: 1 1 320px; min-width: 280px; }
.proposal-review-column h2 { font-size: 1rem; margin: 0 0 10px; color: var(--color-text-muted); }
.proposal-review-actions { margin-top: 20px; }
.proposal-preview-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 16px 18px; }
.proposal-preview-empty { display: flex; align-items: center; justify-content: center; min-height: 160px; text-align: center; }
.proposal-preview-img { max-width: 100%; max-height: 220px; border-radius: var(--radius); cursor: pointer; display: block; margin: 0 auto; }
.proposal-preview-block { margin: 10px 0; border-radius: 6px; }
.proposal-preview-description { font-size: 0.9rem; white-space: pre-line; }
/* The change highlight — same amber/gold as the site's other "pay attention
   here" accents (--color-accent), shown on BOTH sides so it's easy to spot
   which piece of the before card to compare against which piece of after. */
.proposal-preview-highlight { background: #FBF1DC; box-shadow: 0 0 0 2px var(--color-accent); padding: 6px 8px; margin-left: -8px; margin-right: -8px; }

/* Shown for the duration of a "Scan with AI" / "Scan all with AI" submit
   (see assets/js/admin-scan-modal.js) — a plain synchronous form POST that
   can take a while, with no other progress indicator otherwise. Covers the
   whole page so nothing underneath is clickable while it's up. */
.scan-modal-overlay {
  position: fixed;
  inset: 0;
  background: rgba(43, 26, 20, 0.55);
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 1000;
}
/* An author-stylesheet display value always wins over the browser's own
   [hidden] default, whatever the specificity, so it has to be spelled out
   explicitly (see the same note by .hamburger-menu[hidden] above). */
.scan-modal-overlay[hidden] { display: none; }
.scan-modal {
  background: var(--color-surface);
  border-radius: var(--radius);
  padding: 32px 40px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  box-shadow: 0 8px 32px rgba(0, 0, 0, 0.25);
  text-align: center;
  max-width: 320px;
}
.scan-modal-spinner {
  width: 36px;
  height: 36px;
  border: 4px solid var(--color-border);
  border-top-color: var(--color-primary);
  border-radius: 50%;
  animation: scan-modal-spin 0.8s linear infinite;
}
@keyframes scan-modal-spin {
  to { transform: rotate(360deg); }
}
.scan-modal p { margin: 0; font-weight: 600; color: var(--color-emphasis); }

/* Status color-coding for admin/events.php's calendar chips — .calendar-*
   itself is shared with the public homepage's calendar view (search.js). */
.calendar-event-chip.status-draft { background: #C99A2E; }
.calendar-event-chip.status-unpublished { background: #A83232; }
.calendar-event-chip.is-unconfirmed { border: 1px dashed #fff; }
.calendar-event-chip.is-cancelled { background: #5A5A5A; text-decoration: line-through; }

.badge { display: inline-block; padding: 3px 10px; border-radius: 999px; font-size: 0.78rem; font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em; }
.badge-published { background: #E4F3E4; color: #2C6E31; }
.badge-draft { background: #F3ECD9; color: #8A6D1D; }
.badge-unpublished { background: #F3E1E1; color: #A83232; }
.badge-neutral { background: #ECECEC; color: #6B6B6B; }
.badge-ciclo { background: #E6E1F0; color: #5B4A8A; font-size: 0.68rem; padding: 2px 8px; vertical-align: middle; }
.badge-date-changed { background: #E6E1F0; color: #5B4A8A; font-size: 0.68rem; padding: 2px 8px; vertical-align: middle; }
.badge-sold-out { background: #FBE9D0; color: #B45309; font-size: 0.68rem; padding: 2px 8px; vertical-align: middle; }
.sold-out-label { display: inline-block; margin-left: 8px; padding: 2px 10px; border-radius: 999px; background: #B45309; color: #fff; font-size: 0.75rem; font-weight: 700; letter-spacing: 0.03em; text-transform: uppercase; vertical-align: middle; }
.badge-unconfirmed { background: #F3E1E1; color: #A83232; font-size: 0.68rem; padding: 2px 8px; vertical-align: middle; }
.badge-cancelled { background: #E8E8E8; color: #5A5A5A; font-size: 0.68rem; padding: 2px 8px; vertical-align: middle; }
.badge-draft-pending { background: #FFF3D6; color: #8A6D1D; font-size: 0.68rem; padding: 2px 8px; vertical-align: middle; }
/* admin/events.php's list-view Confidence column — same green/yellow/red bands as the Status badges above, by score instead of status. */
.badge-confidence { font-size: 0.75rem; }
.badge-confidence-high { background: #E4F3E4; color: #2C6E31; }
.badge-confidence-medium { background: #F3ECD9; color: #8A6D1D; }
.badge-confidence-low { background: #F3E1E1; color: #A83232; }
/* admin/events.php's list-view Status column (status_emoji()) — the label (Draft/Published/Unpublished) only shows on hover/focus via the title attribute. */
.status-emoji { font-size: 1.1rem; cursor: default; vertical-align: middle; }
.admin-table th.col-status, .admin-table td.col-status { text-align: center; }
.status-change-btn { background: none; border: 0; padding: 2px 4px; border-radius: var(--radius); cursor: pointer; font: inherit; }
.status-change-btn:hover { background: rgba(0, 0, 0, 0.06); }
.status-change-btn .status-emoji { cursor: pointer; }
.status-change-item { width: 100%; background: none; border: 0; font: inherit; text-align: left; cursor: pointer; }
.status-change-item.is-current { font-weight: 700; }
.admin-bar h1 { display: flex; align-items: center; gap: 12px; }
.admin-bar h1 .badge { font-size: 0.65rem; }

.admin-form { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 24px; box-shadow: var(--shadow); max-width: 720px; display: flex; flex-direction: column; gap: 16px; }

/* admin/settings.php's tabbed layout — .settings-tab-nav and each
   .settings-tab-panel are direct children of .admin-form, so its own
   flex-column gap already spaces them; admin-settings-tabs.js toggles
   [hidden] on the panels and .is-active here. */
.settings-tab-nav { display: flex; gap: 4px; flex-wrap: wrap; border-bottom: 1px solid var(--color-border); }
.settings-tab-btn {
  background: none;
  border: none;
  border-bottom: 2px solid transparent;
  padding: 10px 14px;
  font-weight: 600;
  font-size: 0.92rem;
  color: var(--color-text-muted);
  cursor: pointer;
}
.settings-tab-btn:hover { color: var(--color-primary-dark); }
.settings-tab-btn.is-active { color: var(--color-primary-dark); border-bottom-color: var(--color-primary); }
.settings-tab-panel { display: flex; flex-direction: column; gap: 16px; }
.settings-country-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 10px 20px; }
/* Same gotcha as .hamburger-menu[hidden] above — author display always
   wins over the browser's own [hidden] default, so it has to be spelled
   out explicitly here too. */
.settings-tab-panel[hidden] { display: none; }
/* Panels that are also .admin-form (the Backup and maintenance tab, outside the settings form) would
   otherwise get display: grid from `body.admin-area .admin-form`, which out-ranks the rule above. */
body.admin-area .settings-tab-panel[hidden] { display: none; }
/* admin/settings.php's About tab — plain read-only key/value rows, reusing
   .admin-table's own look rather than inventing a new one; :first-child
   narrows just the label column since these two-column rows would
   otherwise split evenly like a normal data table. */
/* Plain key/value list: no gridlines or outer frame, tighter cells. */
.about-info-table { max-width: 480px; border: 0; background: none; }
.about-info-table td { border: 0; padding: 3px 10px 3px 0; font-size: 0.88rem; }
.about-info-table td:first-child { width: 45%; color: var(--color-text-muted); font-weight: 600; }

/* admin/settings.php's AI provider drag-reorder list (admin-ai-provider-order.js) — same drag mechanics as .drag-handle/tr[draggable] in admin/sources.php, just <li> instead of table rows. */
.ai-provider-order-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; max-width: 420px; }
.ai-provider-order-list li {
  display: flex;
  align-items: center;
  gap: 10px;
  background: var(--color-bg);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 8px 12px;
  cursor: grab;
}
.ai-provider-order-list li.is-dragging { opacity: 0.4; }
.ai-provider-order-list li.is-provider-disabled { opacity: 0.6; }
.ai-provider-order-toggle { display: flex; align-items: center; gap: 8px; flex: 1 1 auto; cursor: pointer; }
.ai-provider-order-name { font-weight: 600; }

.key-create-form {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
  align-items: flex-end;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 18px;
  box-shadow: var(--shadow);
  margin-bottom: 20px;
}
.key-reveal {
  background: #FBF3EC;
  border: 1px solid var(--color-accent);
  border-radius: var(--radius);
  padding: 18px;
  margin-bottom: 20px;
}
.key-reveal p { margin: 0 0 8px; }
.key-reveal-token {
  display: block;
  margin-top: 8px;
  padding: 10px 12px;
  background: #fff;
  border: 1px solid var(--color-border);
  border-radius: 6px;
  font-size: 0.95rem;
  word-break: break-all;
  user-select: all;
}

/* Login page: no site header (removed via $hideHeader), so center the
   form both ways in the full viewport instead of just the content column. */
.admin-login-page main {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.admin-login {
  width: 100%;
  max-width: 380px;
  text-align: center;
}
.admin-login .admin-form { max-width: none; text-align: left; margin-top: 16px; }
.admin-login-logo {
  display: block;
  font-family: var(--font-heading);
  font-size: 1.6rem;
  color: var(--color-primary);
  text-decoration: none;
  margin-bottom: 16px;
}
.form-actions { display: flex; gap: 12px; margin-top: 8px; }

/* admin/event-form.php's "always visible" Save/Clone/Delete actions.
   .has-sticky-actions here is a plain wrapper <div> (NOT itself a <form> —
   Clone/Delete are each their own separate <form>, which can't nest inside
   the main one, so the main field-editing <form> lives at
   .admin-form-fields instead and carries id="event-form"; the Save/Publish
   buttons sit outside it in .form-actions and target it via form="event-form").
   The "card" look (background/border/padding/shadow) that plain .admin-form
   has elsewhere moves to .admin-form-fields here, so .form-actions sits on
   the page's own background rather than appearing embedded inside the
   card — a fixed floating bar on mobile (where there's no room for a side
   column), a sticky side panel on desktop that stays visible while
   scrolling. Scoped specifically to .has-sticky-actions: every other admin
   form (login, venue, source, user) is untouched. Matches this codebase's
   existing 900px admin desktop breakpoint (see .admin-calendar-pages). */
.admin-form.has-sticky-actions {
  background: none; border: none; box-shadow: none; padding: 0; max-width: 940px;
  display: flex; flex-direction: column; gap: 16px;
}
.admin-form.has-sticky-actions .admin-form-fields {
  background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius);
  padding: 24px; box-shadow: var(--shadow);
  display: flex; flex-direction: column; gap: 16px; max-width: 720px;
}
.admin-form.has-sticky-actions .form-actions { flex-wrap: wrap; }
@media (min-width: 900px) {
  .admin-form.has-sticky-actions { flex-direction: row; align-items: flex-start; gap: 24px; }
  .admin-form.has-sticky-actions .admin-form-fields { flex: 1 1 auto; min-width: 0; }
  .admin-form.has-sticky-actions .form-actions { position: sticky; top: 24px; flex-direction: column; flex-wrap: nowrap; width: 170px; flex-shrink: 0; margin-top: 0; }
  .admin-form.has-sticky-actions .form-actions .btn { width: 100%; text-align: center; }
}
@media (max-width: 899.98px) {
  .admin-form.has-sticky-actions .admin-form-fields { padding-bottom: 76px; }
  .admin-form.has-sticky-actions .form-actions {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    z-index: 50;
    margin: 0;
    padding: 12px 20px;
    background: var(--color-surface);
    border-top: 1px solid var(--color-border);
    box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.08);
  }
}
.current-locandina { display: flex; align-items: center; gap: 12px; margin-bottom: 8px; }
.current-locandina img { border-radius: 6px; border: 1px solid var(--color-border); }
.current-locandina img[data-lightbox] { cursor: zoom-in; }

.dropzone {
  border: 2px dashed var(--color-border);
  border-radius: var(--radius);
  padding: 20px;
  text-align: center;
  background: #FBF3EC;
  transition: border-color 0.15s ease, background 0.15s ease;
}
.dropzone.is-dragover {
  border-color: var(--color-primary);
  background: #FBEEE6;
}
.dropzone-text {
  margin: 0 0 10px;
  color: var(--color-text-muted);
  font-size: 0.9rem;
  pointer-events: none;
}
.dropzone input[type="file"] {
  display: block;
  margin: 0 auto;
}
.dropzone-preview {
  max-width: 200px;
  border-radius: 6px;
  margin-top: 12px;
  border: 1px solid var(--color-border);
}
.dropzone-preview[data-lightbox] { cursor: zoom-in; }

.autocomplete { position: relative; }
.autocomplete-list {
  position: absolute;
  z-index: 20;
  top: 100%;
  left: 0;
  right: 0;
  margin: 4px 0 0;
  padding: 4px;
  list-style: none;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  max-height: 220px;
  overflow-y: auto;
}
.autocomplete-item {
  padding: 8px 10px;
  border-radius: 6px;
  cursor: pointer;
}
.autocomplete-item:hover, .autocomplete-item.is-active {
  background: #FBEEE6;
}
.autocomplete-item-name { font-weight: 600; color: var(--color-emphasis); }
.autocomplete-item-meta { font-size: 0.8rem; color: var(--color-text-muted); }

.alert { padding: 12px 16px; border-radius: var(--radius); margin-bottom: 16px; }
.alert-success { background: #E4F3E4; color: #2C6E31; }
.alert-error { background: #F8E3E3; color: #A83232; }
.alert-info { background: #FFF3D6; color: #8A6D1D; }
.alert ul { margin: 0; padding-left: 18px; }
.pending-draft-banner p { margin: 0 0 10px; }
.pending-draft-banner-actions { display: flex; gap: 10px; align-items: center; }
.pending-draft-banner-actions .btn { font-family: inherit; line-height: 1.2; }
.event-history-list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.event-history-item {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 16px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  flex-wrap: wrap;
}
.event-history-meta { display: flex; align-items: center; gap: 10px; flex-wrap: wrap; }
.event-history-by { color: var(--color-text-muted); font-size: 0.85rem; }
.event-from-url-confirm {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 20px;
  max-width: 640px;
}
.event-from-url-confirm-details { display: grid; grid-template-columns: max-content 1fr; gap: 6px 16px; margin: 16px 0; }
.event-from-url-confirm-details dt { font-weight: 600; color: var(--color-text-muted); }
.event-from-url-confirm-details dd { margin: 0; }
.key-label-form { display: flex; align-items: center; gap: 8px; }
.key-label-input { width: auto; min-width: 140px; }

/* Shown on an event's public page only to the admin previewing a
   draft/unpublished event (see event.php) — makes it unmistakable that
   what they're looking at isn't actually live for visitors. */
.preview-banner {
  background: #F3ECD9;
  color: #8A6D1D;
  border: 1px solid #E3D3A0;
  border-radius: var(--radius);
  padding: 10px 16px;
  margin: 16px auto 0;
  max-width: 900px;
  font-weight: 600;
  font-size: 0.9rem;
  text-align: center;
}
.preview-banner p { margin: 0; }
/* Publish/Duplicate/Delete — only rendered for the logged-in admin who's
   allowed to see this draft/unpublished event's page at all (see event.php's
   own $previewingAdmin check), so an admin reviewing a preview can act on it
   immediately instead of switching over to the admin edit form first. */
.preview-banner-actions { display: flex; gap: 10px; justify-content: center; margin-top: 10px; }
/* Same Clone/Delete (plus Unpublish in place of Publish) as .preview-banner
   above, but for a LIVE published page — no "not visible to the public"
   warning applies here, so this skips that banner's background/border
   entirely and is just the button row on its own. */
.admin-page-actions { margin: 16px auto 0; max-width: 900px; }

/* Shown on an event's public page to every visitor when the organizer/admin
   has flagged the date as not yet confirmed (see event.php, admin/event-form.php). */
.unconfirmed-banner {
  background: #F3E1E1;
  color: #A83232;
  border: 1px solid #E3B3B3;
  border-radius: var(--radius);
  padding: 10px 16px;
  margin: 16px auto 0;
  max-width: 900px;
  font-weight: 600;
  font-size: 0.9rem;
  text-align: center;
}

/* Shown on an event's public page to every visitor when the organizer/admin
   has cancelled the event (see event.php, admin/event-form.php). Takes
   priority over .unconfirmed-banner if somehow both are set. */
.cancelled-banner {
  background: #E8E8E8;
  color: #5A5A5A;
  border: 1px solid #D2D2D2;
  border-radius: var(--radius);
  padding: 10px 16px;
  margin: 16px auto 0;
  max-width: 900px;
  font-weight: 600;
  font-size: 0.9rem;
  text-align: center;
}

/* Inline "Cancelled" label next to a struck-through date (event.php's own
   meta line, and each cancelled entry in its "other dates" ciclo list). */
.cancelled-label {
  display: inline-block;
  background: #5A5A5A;
  color: #fff;
  font-size: 0.68rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.02em;
  padding: 2px 8px;
  border-radius: 999px;
  text-decoration: none;
  vertical-align: middle;
}
.event-detail-meta.is-cancelled { text-decoration: line-through; }
.event-other-dates li.is-cancelled { text-decoration: line-through; }

/* Closing visual band — full-bleed, static (no parallax), bottom-anchored so
   the illustration's floor lines up with the edge just above the footer.
   Uses the dedicated full-resolution asset, not the compressed og-image. */


/* Footer */
.site-footer { padding: 30px 0; color: var(--color-text-muted); font-size: 0.85rem; border-top: 1px solid var(--color-border); margin-top: 40px; text-align:center;}
.site-footer p { margin: 0 0 4px;}
.site-footer p:last-child { margin-bottom: 0; }
.footer-legal-links { font-size: 0.8rem; }
.footer-legal-links a { color: var(--color-text-muted); text-decoration: underline; }
.footer-legal-links span { margin: 0 6px; color: var(--color-border); }

/* Privacy / Cookie policy pages */
.legal-page { max-width: 760px; margin: 0 auto; padding: 20px 0 50px; line-height: 1.65; }
.legal-page h2 { margin-top: 1.6em; font-size: 1.3rem; }
.legal-page ul { padding-left: 22px; }
.legal-page li { margin-bottom: 8px; }
.legal-table { width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem; }
.legal-table th, .legal-table td { border: 1px solid var(--color-border); padding: 10px 12px; text-align: left; vertical-align: top; }
.legal-table th { background: #FBF3EC; color: var(--color-emphasis); }
.legal-table code { background: var(--color-bg); border: 1px solid var(--color-border); border-radius: 4px; padding: 1px 5px; font-size: 0.85em; }

/* Contact form (contact.php) */
.contact-form { max-width: 600px; margin: 24px auto; }
.contact-form .form-actions { justify-content: flex-end; }
.hp-field { position: absolute; left: -9999px; top: -9999px; }
.checkbox-field { display: flex; align-items: flex-start; gap: 8px; }
.checkbox-field input[type="checkbox"] { margin-top: 4px; flex-shrink: 0; }
.checkbox-field label { font-size: 0.95rem; color: var(--color-text); font-weight: 400; cursor: pointer; }
.checkbox-field a { color: var(--color-accent); }

.radio-group { display: flex; gap: 18px; flex-wrap: wrap; margin-top: 2px; }
.field .radio-option {
  display: flex;
  align-items: center;
  gap: 6px;
  font-size: 0.95rem;
  font-weight: 400;
  color: var(--color-text);
  cursor: pointer;
}
.radio-option input[type="radio"] { margin: 0; }

/* Ciclo — additional dates rows (admin/event-form.php) */
.occurrence-rows { display: flex; flex-direction: column; gap: 8px; margin-bottom: 8px; }
.occurrence-row { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.occurrence-row input[type="date"] { flex: 1 1 150px; }
.occurrence-row .time-input { flex: 1 1 110px; }
.occurrence-row-sep { color: var(--color-text-muted); }
.occurrence-cancelled { flex-shrink: 0; white-space: nowrap; font-size: 0.85rem; }
.occurrence-remove { flex-shrink: 0; width: 34px; height: 34px; padding: 0; font-size: 1.1rem; line-height: 1; border-radius: 50%; }

/* Ciclo — other dates list (event.php detail page) */
.event-other-dates { margin: -2px 0 14px; }
.event-other-dates-label { margin: 0 0 4px; font-weight: 600; color: var(--color-primary-dark); font-size: 0.9rem; }
.event-other-dates ul { margin: 0; padding-left: 20px; color: var(--color-text-muted); font-size: 0.9rem; }

/* "Organizing a milonga?" prompt near the event list, linking to /contact */
.organizer-prompt {
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  padding: 14px 18px;
  margin: 16px 0;
  font-size: 0.95rem;
  text-align: center;
}
.organizer-prompt a { color: var(--color-accent); font-weight: 700; text-decoration: underline; }

/* Floating "jump to admin panel" button, shown only to a logged-in admin
   browsing the public site (see templates/footer.php). */
.admin-fab {
  position: fixed;
  bottom: 20px;
  right: 20px;
  /* Above .map-fullscreen-btn/.map-legend (both 1000) — a fixed,
     viewport-persistent button must always render above an in-page map
     control it happens to scroll behind, not the other way around. Still
     below the datepicker popup/cookie banner/lightbox, which are meant to
     cover everything while open. */
  z-index: 1010;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px 18px;
  background: var(--color-accent);
  color: #fff;
  border-radius: 999px;
  box-shadow: var(--shadow);
  text-decoration: none;
  font-weight: 700;
  font-size: 0.9rem;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.admin-fab:hover { transform: translateY(-2px); box-shadow: 0 6px 16px rgba(0,0,0,0.2); }
.admin-fab svg { flex-shrink: 0; }
@media (max-width: 899.98px) {
  /* admin/event-form.php's own sticky bottom Save/Clone/Delete bar
     (.has-sticky-actions .form-actions, same breakpoint) would otherwise
     sit directly under this fixed, higher-z-index button. --sticky-actions-height
     is set by assets/js/admin-sticky-fab.js from that bar's own actual
     rendered height (it can wrap to two rows on a narrow phone, so a fixed
     guess here isn't reliable) — the 70px fallback only matters before
     that JS runs or if it isn't present at all. */
  body.has-sticky-actions-page .admin-fab { bottom: calc(var(--sticky-actions-height, 70px) + 16px); }
}
@media (max-width: 600px) {
  .admin-fab { bottom: 14px; right: 14px; padding: 10px 14px; font-size: 0.85rem; }

  /* Icon-only floating Share button — positioned above .admin-fab (when a
     logged-in admin also sees that button) so the two never overlap.
     Same z-index reasoning as .admin-fab just above: must outrank the map
     controls (1000) it can otherwise scroll behind. */
  .btn-share {
    position: fixed;
    bottom: 70px;
    right: 14px;
    z-index: 1010;
    width: 46px;
    height: 46px;
    padding: 0;
    justify-content: center;
    border-radius: 50%;
    background: var(--color-accent);
    border-color: var(--color-accent);
    color: #fff;
    box-shadow: var(--shadow);
  }
  .btn-share:hover { background: var(--color-accent); }
  .btn-share-label { display: none; }
  .share-status,
  .view-toggle .share-status {
    position: fixed;
    top: auto;
    bottom: 122px;
    right: 14px;
    margin: 0;
  }
}

/* Cookie consent banner */
.cookie-consent {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 2000;
  background: var(--color-surface);
  border-top: 1px solid var(--color-border);
  box-shadow: 0 -2px 10px rgba(60, 40, 20, 0.12);
}
.cookie-consent-inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  flex-wrap: wrap;
  padding: 16px 20px;
}
.cookie-consent p {
  margin: 0;
  color: var(--color-text);
  font-size: 0.9rem;
  flex: 1 1 320px;
}
.cookie-consent-actions {
  display: flex;
  gap: 10px;
  flex-shrink: 0;
}
.pwa-install-banner {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: 12px;
  z-index: 1900;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 14px;
  max-width: 440px;
  margin: 0 auto;
  padding: 14px 16px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
}
.pwa-install-text { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.pwa-install-text strong { color: var(--color-emphasis); font-size: 0.95rem; }
.pwa-install-text span { color: var(--color-text-muted); font-size: 0.82rem; }
.pwa-install-actions { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.pwa-install-close { font-size: 1.3rem; line-height: 1; color: var(--color-text-muted); padding: 4px 6px; }
@media (max-width: 480px) {
  .pwa-install-banner { flex-direction: column; align-items: stretch; }
  .pwa-install-actions { justify-content: flex-end; }
}

@media (max-width: 500px) {
  .cookie-consent-actions { width: 100%; }
  .cookie-consent-actions .btn { flex: 1 1 auto; }
}


@media (max-width: 700px) {
  .site-header {
	  min-height: 300px;
	  background-size: auto 100%;
	  background-position: center;
	}
  /* As wide as the screen allows while keeping an equal margin (16px) from
     both edges, regardless of where the hamburger button itself sits — not
     just relative to the button/.hamburger-wrap (this menu's own
     positioning context), which sits 28px in from the left edge (see
     .hamburger-wrap inside .site-header-inner's own padding). left: -12px
     shifts the menu 16px from the viewport's own left edge (16 - 28 =
     -12); width matches with 16px taken off both sides. */
  .hamburger-menu {
    left: -12px;
    width: calc(100vw - 32px);
    min-width: 0;
    max-width: none;
  }
}

/* Custom calendar popup (assets/js/datepicker.js) — always Monday-first,
   overriding whatever week order the visitor's browser locale would use
   for a native <input type="date"> picker. */
.datepicker-pop {
  position: absolute;
  z-index: 1500;
  width: 260px;
  background: var(--color-surface);
  border: 1px solid var(--color-border);
  border-radius: var(--radius);
  box-shadow: var(--shadow);
  padding: 10px;
}
.datepicker-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 8px;
  font-weight: 600;
  text-transform: capitalize;
}
.datepicker-nav {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  padding: 4px 10px;
  border-radius: 6px;
  color: var(--color-primary-dark);
}
.datepicker-nav:hover { background: var(--color-border); }
.datepicker-grid {
  display: grid;
  grid-template-columns: repeat(7, 1fr);
  gap: 2px;
  text-align: center;
}
.datepicker-weekday {
  font-size: 0.72rem;
  font-weight: 600;
  color: var(--color-text-muted);
  padding: 4px 0 6px;
}
.datepicker-day {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 0.85rem;
  padding: 7px 0;
  border-radius: 6px;
  color: var(--color-text);
}
.datepicker-day:hover:not(:disabled) { background: var(--color-border); }
.datepicker-day.is-outside { visibility: hidden; }
.datepicker-day.is-today { font-weight: 700; color: var(--color-primary-dark); }
.datepicker-day.is-selected { background: var(--color-primary-dark); color: #fff; }
.datepicker-footer { margin-top: 6px; text-align: right; }
.datepicker-clear {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 0.78rem;
  color: var(--color-primary-dark);
  text-decoration: underline;
}

/* Region/country summary sentence, shown just below the header image. */
.header-summary {
  margin: 0;
  padding: 10px 16px 0;
  text-align: center;
  font-size: .9rem;
  font-weight: 600;
  color: #3b2a22;
}

.venue-index h2 { margin: 28px 0 4px; }
.venue-index h3 { margin: 16px 0 4px; font-size: 1rem; color: var(--muted, #666); }
.venue-index-list { list-style: none; margin: 0; padding: 0; }
.venue-index-list li { padding: 4px 0; }
.venue-index-count { margin-left: 8px; font-size: .8rem; color: var(--muted, #666); }
.past-banner a { color: inherit; text-decoration: underline; }

/* "Happening now": replaces the plain "Today" badge while an event is running. */
.event-card-badge-live {
  background: #C62828;
  display: inline-flex;
  align-items: center;
  gap: 6px;
}
.event-card-badge-live::before {
  content: "";
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: #fff;
  animation: badge-live-pulse 1.4s ease-in-out infinite;
}
@keyframes badge-live-pulse {
  0%, 100% { opacity: 1; transform: scale(1); }
  50% { opacity: 0.35; transform: scale(0.7); }
}
@media (prefers-reduced-motion: reduce) {
  .event-card-badge-live::before { animation: none; }
}
.event-card-live { border-color: #C62828; box-shadow: 0 0 0 2px #C62828, var(--shadow); }

/* Date-window and city links under the header (today / this week / ...). */
.chip-nav {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 8px;
  margin: 12px auto 4px;
  padding: 0 16px;
  max-width: 900px;
}
.chip-nav-link {
  padding: 5px 14px;
  border: 1px solid var(--color-accent);
  border-radius: 999px;
  font-size: .85rem;
  font-weight: 600;
  color: inherit;
  text-decoration: none;
  background: transparent;
}
.chip-nav-link:hover { background: rgba(0, 0, 0, .05); }
.chip-nav-link.is-active { background: var(--color-accent); color: #fff; }
.chip-nav-city { border-style: dashed; }

/* <picture> wrappers around poster images must not affect layout. */
picture { display: contents; }

/* Place FAQ (region and city pages), venue facts, and guide pages. */
.faq { max-width: 900px; margin: 32px auto 0; }
.faq-item { border-bottom: 1px solid var(--color-border); padding: 10px 0; }
.faq-item summary { cursor: pointer; font-weight: 600; }
.faq-item p { margin: 8px 0 0; }
.faq-guides { margin-top: 14px; font-size: .9rem; }
.venue-schedule { margin: 6px 0; font-weight: 600; }
.venue-intro { margin: 8px 0; }
.guide { max-width: 760px; }
.guide p { line-height: 1.65; }
.guide-list { list-style: none; margin: 0; padding: 0; }
.guide-list li { margin: 18px 0; }
.guide-list h2 { margin: 0 0 4px; font-size: 1.15rem; }
.guide-cta { margin-top: 24px; font-weight: 600; }
.guide-figure { margin: 22px 0; }
.guide-figure img { display: block; width: 100%; height: auto; max-height: 360px; object-fit: cover; border-radius: 10px; }
.guide-figure figcaption { margin-top: 6px; font-size: .78rem; color: var(--color-text-muted); }

/* Event version history: compare picker and side-by-side compare page. */
.history-compare-bar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 0 0 14px; }
.history-section-title { font-size: 1.05rem; margin: 18px 0 8px; }
.event-history-item { align-items: center; }
.history-compare-check { width: 18px; height: 18px; }
.compare-toggle-label { display: inline-block; margin: 6px 0 10px; cursor: pointer; }
.compare-table { width: 100%; border-collapse: collapse; table-layout: fixed; }
.compare-table th, .compare-table td { border: 1px solid var(--color-border); padding: 8px 10px; vertical-align: top; text-align: left; overflow-wrap: anywhere; white-space: pre-wrap; }
.compare-table thead th { white-space: normal; }
.compare-table tbody th { width: 140px; font-weight: 600; white-space: normal; }
.compare-diff td { background: rgba(255, 193, 7, .08); }
.compare-table del { background: rgba(220, 53, 69, .18); text-decoration: line-through; }
.compare-table ins { background: rgba(40, 167, 69, .2); text-decoration: none; }
.compare-empty { color: var(--color-text-muted); font-style: italic; }
.compare-poster { max-width: 160px; max-height: 160px; margin-top: 6px; border-radius: 4px; cursor: zoom-in; }
.compare-toggle:checked ~ .compare-table .compare-same { display: none; }
@media (max-width: 700px) { .compare-table tbody th { width: 90px; } .compare-table th, .compare-table td { padding: 6px; font-size: .85rem; } }

/* Event form: description language switcher (assets/js/admin-description-langs.js). */
.description-lang-head { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 12px; margin-bottom: 6px; }
.description-lang-head label { margin: 0; }
.description-lang-head .custom-select-btn { width: auto; min-width: 180px; gap: 8px; }
.description-lang-head .btn { margin-left: auto; }
.description-lang-head .btn + .btn { margin-left: 0; }
.description-original-switch { align-items: center; gap: 6px; }
.custom-select-flag-text { margin-left: 8px; }
.custom-select-option .custom-select-flag { vertical-align: -2px; }

.compare-poster-info { font-size: 0.85rem; color: var(--color-text-muted); }

/* Admin stats page (admin/stats.php) */
.stats-filters { display: flex; flex-wrap: wrap; gap: 6px; margin-left: auto; }
.stats-filters .btn.is-active { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.stats-tiles { display: grid; grid-template-columns: repeat(auto-fill, minmax(140px, 1fr)); gap: 12px; margin-bottom: 20px; }
.stats-tile { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 12px 14px; display: flex; flex-direction: column; gap: 2px; box-shadow: var(--shadow); }
.stats-tile-value { font-family: var(--font-heading); font-size: 1.7rem; color: var(--color-emphasis); line-height: 1.1; }
.stats-tile-label { font-size: 0.8rem; color: var(--color-text-muted); }
.stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 16px; margin-bottom: 32px; }
.stats-card { background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius); padding: 14px 16px; box-shadow: var(--shadow); min-width: 0; }
.stats-card-wide { grid-column: 1 / -1; }
.stats-card h2 { font-size: 1rem; margin: 0 0 12px; }
.stats-note { font-size: 0.85rem; color: var(--color-text-muted); margin: 0 0 8px; }
.stats-empty { color: var(--color-text-muted); margin: 0; }
.stats-bars { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.stats-bars li { display: grid; grid-template-columns: minmax(70px, 38%) 1fr 36px; gap: 8px; align-items: center; font-size: 0.88rem; }
.stats-bar-label { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.stats-bar-track { background: var(--color-border); border-radius: 4px; height: 10px; overflow: hidden; }
.stats-bar-fill { display: block; height: 100%; background: var(--color-primary); border-radius: 4px; }
.stats-bar-n { text-align: right; color: var(--color-text-muted); font-variant-numeric: tabular-nums; }
.stats-cols { display: flex; align-items: flex-end; gap: 4px; height: 190px; overflow-x: auto; padding-top: 4px; }
.stats-col { flex: 1 0 28px; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; align-items: center; gap: 3px; font-size: 0.7rem; }
.stats-col-n { color: var(--color-text-muted); }
.stats-col-bar { display: block; width: 100%; background: var(--color-primary); border-radius: 3px 3px 0 0; min-height: 2px; }
.stats-col.is-current .stats-col-bar { background: var(--color-accent); }
.stats-col.is-current .stats-col-label { font-weight: 700; color: var(--color-text); }
.stats-col-label { color: var(--color-text-muted); white-space: nowrap; }
.stats-col-stack { display: flex; flex-direction: column; width: 100%; min-height: 2px; }
.stats-col-stack .stats-col-bar { border-radius: 0; min-height: 0; }
.stats-col-bar-manual { background: var(--color-primary); }
.stats-col-bar-api { background: var(--color-emphasis); }
.stats-legend { font-size: 0.8rem; color: var(--color-text-muted); margin: 10px 0 0; }
.stats-swatch { display: inline-block; width: 10px; height: 10px; border-radius: 2px; margin: 0 4px 0 8px; vertical-align: baseline; }

.repeat-clone-form { display: inline-flex; align-items: center; gap: 6px; }
.repeat-clone-form input[type="date"] { padding: 9px 10px; border: 1px solid var(--color-border); border-radius: var(--radius); font: inherit; }
