/*
*************************************************************************
Art Fair SourceBook
/components/styles/directory-search.css

Styles for the merged directory + search browse page.

Card and list-row rules are lifted verbatim from directory.php so the card
view is pixel-identical to the public directory -- per Kenny, Sept 2026:
cards stay exactly as they are, the list view is where premium columns live.
That split is the whole reason both layouts exist.

Loaded via ds_css_url(), which cache-busts on filemtime() the same way
datasheet_css_url() does, so a CSS deploy can't sit invisible behind a
stale browser cache.
*************************************************************************
*/

/* ===========================================================
   LAYOUT
   =========================================================== */
.ds-wrap {
  padding: 20px 0 40px;
}

/* 1220.css zeroes the container gutter at exactly this breakpoint:
     @media (max-width: 830px) { .row, body, .container { padding-left: 0; padding-right: 0 } }
   so below 830px nothing provides a side margin and the content ran flush to
   the browser edge. Previously only restored at <=560px, which left 561-830px
   touching the left side. Per Kenny, Oct 2026. */
@media (max-width: 830px) {
  .ds-wrap {
    padding-left: 16px;
    padding-right: 16px;
  }
}

/* ---- checkbox reset (do not remove) ----
   Both pages render inside <div class="content">, and the global stylesheet
   styles EVERY input in there:

     .content input { padding: 0.7em; width: 80%; box-sizing: border-box; }
     input, select  { border: 1px solid #979797; padding: 0.5em; }

   A checkbox inheriting that becomes a bordered box ~9px padded and stretched
   to 80% of its container -- which is why the calendar legend boxes looked
   broken. The codebase's own workaround is class="box"
   (.content input.box { width: auto }), but that fixes only the width.
   Reset properly, once, for every checkbox this component emits: legend
   toggles, Save to MyAFSB, Limit-to, Upcoming-only. Per Kenny, Oct 2026. */
.ds-wrap input[type="checkbox"] {
  -webkit-appearance: checkbox;
  appearance: checkbox;
  width: 14px;
  height: 14px;
  min-width: 14px;
  padding: 0;
  margin: 0;
  border: 0;
  border-radius: 0;
  flex: 0 0 auto;
  vertical-align: middle;
  accent-color: #B23B48;
}

.ds-wrap h1 {
  font-family: 'Winsel-Variable', 'Work Sans', sans-serif;
  color: #252323;
  margin-bottom: 10px;
}

.ds-intro {
  color: #262323;
  margin-bottom: 24px;
  font-size: 15px;
  line-height: 1.6;
}

/* ===========================================================
   CARDS -- verbatim from directory.php, do not restyle
   =========================================================== */
.directory-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 18px;
}

/* Spacing is tighter than /directory's card on purpose. That card has three
   meta rows; this one has six (the three free fields plus the three paid
   metrics), so /directory's 20px padding and 4px row padding made the card
   noticeably airy and tall. Per-row spacing is trimmed to keep the overall
   height close to the original while the row rhythm stays readable.
   Per Kenny, Oct 2026. */
.directory-card {
  background: #fff;
  border: 1px solid #e8e0e0;
  border-radius: 6px;
  padding: 16px;
  width: calc(33.333% - 12px);
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  transition: box-shadow 0.15s ease, border-color 0.15s ease;
}

.directory-card:hover {
  box-shadow: 0 3px 12px rgba(178, 59, 72, 0.12);
  border-color: #B23B48;
}

/* .directory-card--featured / --paid / --free live together in the PLACEMENT
   TIERS block further down, after .card-link -- the free tier has to override
   .card-link at equal specificity, so it must come later in the file. */

.featured-badge {
  display: inline-block;
  background: #B23B48;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 3px;
  margin-bottom: 8px;
  margin-right: 6px;
}

.deadline-urgent-badge {
  display: inline-block;
  background: none;
  color: #B23B48;
  font-size: 10px;
  font-weight: 900;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  padding: 3px 8px;
  border-radius: 3px;
  margin-bottom: 8px;
  margin-right: 6px;
}

/* Show name as a headline, matching the page headings on /organizers and
   /promotional-listings. Per Wendy, Oct 2026.

   She called that treatment "the serif", but there is no serif anywhere on the
   site: .page-headline in styles.css sets no font-family at all, so it inherits
   `h1, h2 { font-family: 'Winsel-Variable-Light' }` -- a light sans. The stack
   below is therefore literally the same font those headings use, which is what
   she actually asked for.

   'Winsel-Variable-Light' maps to Winsel-Variable-Thin.otf, and a thin face set
   at body size reads washed out, so this runs a little larger than the 16px it
   replaced. Switch --ds-cardname-weight to 600 and the family to
   'Winsel-Variable' for the Bold alternative she approved as a fallback. */
.card-name {
  font-family: 'Winsel-Variable-Light', 'Work Sans', sans-serif;
  font-size: 18px;
  font-weight: normal;
  color: #252323;
  margin-bottom: 7px;
  line-height: 1.25;
}

.card-meta {
  list-style: none;
  padding: 0;
  margin: 0 0 8px;
  flex: 1;
}

.card-meta li {
  font-size: 13px;
  color: #262323;
  padding: 2px 0;
  line-height: 1.35;
  border-bottom: 1px solid #f2f2f2;
  display: flex;
  gap: 6px;
}

.card-meta li:last-child {
  border-bottom: none;
}

/* ---- star rating, directly under the title ----
   Set at the title's own 16px per Kenny, Oct 2026. Overlay technique: a grey
   five-star row with a clipped gold row on top, so fractional ratings render
   without half-star glyphs. */
/* Stars and the reviews button share one line under the title, button pushed
   to the right edge. Per Kenny, Oct 2026. */
.card-rating {
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
  margin: -2px 0 10px;
  font-size: 16px;
  line-height: 1;
}

.card-stars {
  display: flex;
  align-items: center;
  gap: 6px;
}

.card-stars__outer {
  position: relative;
  display: inline-block;
  white-space: nowrap;
}

.card-stars__bg {
  color: #ded8d8;
  letter-spacing: 1px;
}

/* Brand red rather than gold, so the rating matches the standard palette used
   everywhere else on the page. Per Kenny, Oct 2026. */
.card-stars__fg {
  position: absolute;
  top: 0;
  left: 0;
  overflow: hidden;
  white-space: nowrap;
  color: #B23B48;
  letter-spacing: 1px;
}

.card-stars__val {
  font-size: 16px;
  font-weight: 600;
  color: #7a7474;
}

/* Deliberately smaller than the 16px stars beside it -- the stars are the
   headline, this is the action. margin-left:auto is what right-aligns it
   whether or not the show has a star to sit next to. */
.card-reviews {
  margin-left: auto;
  display: inline-flex;
  align-items: center;
  gap: 5px;
  flex-shrink: 0;
  padding: 4px 9px;
  border: 1px solid #B23B48;
  border-radius: 4px;
  font-size: 11.5px;
  font-weight: 600;
  line-height: 1.2;
  color: #B23B48;
  text-decoration: none;
  white-space: nowrap;
}

a.card-reviews:hover {
  background: #B23B48;
  color: #fff;
}

/* Locked: same treatment as the Map view toggle, so every locked affordance on
   the page reads the same way. */
.card-reviews--locked {
  border-color: #ddd8d8;
  background: #f7f5f5;
  color: #9a9393;
  cursor: not-allowed;
}

.card-reviews--locked .afsb-locked-cell {
  color: #9a9393;
  flex-shrink: 0;
}

/* ---- two-column card body ----
   Free fields left, paid metrics right. Each item is its own block with the
   label ABOVE a left-aligned value. Per Kenny, Oct 2026. */
.card-cols {
  display: flex;
  gap: 14px;
  margin-bottom: 12px;
  flex: 1;
}

.card-col {
  display: flex;
  flex-direction: column;
  gap: 8px;
  flex: 1 1 0;
  min-width: 0;
}

/* A hairline between the two halves, so the paid side reads as its own group
   without needing a tint. */
.card-col--paid {
  padding-left: 14px;
  border-left: 1px solid #e8e0e0;
}

.card-item {
  text-align: left;
}

.card-item__label {
  font-size: 10.5px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #9a9393;
  line-height: 1.3;
  margin-bottom: 1px;
}

.card-item__value {
  font-size: 13px;
  color: #262323;
  line-height: 1.3;
  word-break: break-word;
}

.card-col--paid .afsb-locked-cell {
  color: #b5aeae;
}

/* Plain red text link -- used for the "All Art Fairs" back link. */
.card-link {
  color: #B23B48;
  text-decoration: none;
  font-weight: 600;
  font-size: 13px;
}

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

/* Inside a card it becomes a full-width centred button: white on brand red.
   Scoped to .directory-card on purpose, so the back links elsewhere that reuse
   .card-link stay plain text. Per Kenny, Oct 2026. */
/* Outline is the resting style now -- it fills in on hover. The free tier
   replaces this with a plain text link; see the PLACEMENT TIERS block. */
.directory-card .card-link {
  display: block;
  margin-top: auto;
  padding: 9px 12px;
  background: #fff;
  color: #B23B48;
  border: 1px solid #B23B48;
  border-radius: 4px;
  text-align: center;
  font-weight: 600;
  font-size: 13px;
  text-decoration: none;
}

.directory-card .card-link:hover,
.directory-card .card-link:focus {
  background: #B23B48;
  color: #fff;
  text-decoration: none;
}

/* ===========================================================
   PLACEMENT TIERS -- three box styles, identical data on each

   Per Wendy, Oct 2026: the tier is expressed by the frame, never by removing
   fields. Only the border, the corners and the call-to-action change.

   Order matters here. `.directory-card--free .card-link` is (0,2,0), the same
   as `.directory-card .card-link` above it, so it wins on source order alone --
   moving this block earlier in the file would silently restore the button.
   =========================================================== */

/* PAID -- the baseline: hairline border, soft corners, outline button. */
.directory-card--paid {
  border-color: #EFEFEF;
  border-radius: 3px;
}

/* FEATURED -- paid box plus the bar. Border goes near-black so the bar is the
   only red on the frame; a red border around a red bar read as a smudge. */
.directory-card--featured {
  border-color: #262323;
  border-radius: 3px;
  position: relative;
}

/* Full-bleed bar: the negative margins cancel the card's 16px padding so it
   meets both edges, and the top corners match the card's own radius. */
.card-featured-bar {
  margin: -16px -16px 12px;
  padding: 5px 16px;
  background: #B23B48;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  border-radius: 2px 2px 0 0;
}

/* FREE -- square corners, and the button becomes a plain red text link. */
.directory-card--free {
  border-radius: 0;
}

.directory-card--free .card-link {
  padding: 9px 0;
  background: none;
  border: 0;
  border-radius: 0;
  color: #B23B48;
  text-align: left;
  text-decoration: underline;
}

.directory-card--free .card-link:hover,
.directory-card--free .card-link:focus {
  background: none;
  color: #8c2f38;
  text-decoration: underline;
}

/* Featured flag on a LIST row: dot plus the word, above the event name. The
   3px red stripe down the row is .ds-list-row--featured's inset box-shadow,
   and the row keeps its normal background -- no tint. Per Wendy, Oct 2026. */
.ds-feat-flag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  color: #B23B48;
  font-size: 10px;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  white-space: nowrap;
}

.ds-feat-dot {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: #B23B48;
  flex: 0 0 auto;
}

/* `.ds-wrap` prefix is LOAD-BEARING, do not drop it to "simplify" the selector.
   This page's wrapper is <div class="content ds-wrap">, and styles.css:925 has
   `.content label { display: block; margin: 0 0 0.2em }`. That is (0,1,1) and
   beats a bare `.myafsb-save-toggle` at (0,1,0), so without the prefix the
   label is laid out as a block -- which silently discards `display:inline-flex`
   and therefore `gap` and `align-items` as well. `.ds-wrap .myafsb-save-toggle`
   is (0,2,0) and wins.

   Spacing comes from the container's `gap`, NOT from a margin on the input: the
   checkbox reset (.ds-wrap input[type="checkbox"] { margin: 0 }) outranks
   `.myafsb-save-toggle input`, so a margin-right there is discarded too. */
.ds-wrap .myafsb-save-toggle {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-weight: 600;
  color: #252323;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  font-size: 13px;
}

.myafsb-save-toggle input[type="checkbox"] {
  cursor: pointer;
}

/* ---- card version ----
   Smaller text than the card body so it reads as a control rather than
   content, a slightly wider gap, and the box lifted onto the label's optical
   centre (a 14px box against 11.5px text sits visibly low otherwise).
   --ds-save-lift is the one number to tune. Per Kenny, Oct 2026. */
/* .ds-wrap prefix required here too -- see the note above. Without it
   `.content label`'s margin wins and margin-bottom is discarded. */
.ds-wrap .myafsb-save-toggle--card {
  --ds-save-lift: 3px;
  /* 10px, not 8 -- .card-rating below pulls itself up by -2px to hug the title,
     so this nets out to the same 8px of air the toggle had before the move. */
  margin-bottom: 10px;
  font-size: 11.5px;
  gap: 10px;
  line-height: 1;
}

.myafsb-save-toggle--card input[type="checkbox"] {
  position: relative;
  top: calc(-1 * var(--ds-save-lift));
}

/* ===========================================================
   LIST -- the signed-in layout; premium columns live here
   =========================================================== */
.ds-list {
  border: 1px solid #e8e0e0;
  border-radius: 6px;
  overflow: hidden;
  background: #fff;
}

/* Column widths come from a custom property set on the .ds-list wrapper, not
   from an inline style on every row. That is what lets the media queries below
   drop columns as the viewport narrows -- an inline grid-template-columns would
   beat any media query short of !important. */
.ds-list-head,
.ds-list-row {
  display: grid;
  grid-template-columns: var(--ds-cols);
  gap: 10px;
  align-items: center;
  padding: 10px 14px;
}

/*                        Event              Loc  Start Dead Sales FA   FC    Save */
.ds-list--public {
  --ds-cols: minmax(150px, 2.2fr) 1fr 1fr 1fr 96px 60px 60px;
}

.ds-list--member {
  --ds-cols: minmax(150px, 2.2fr) 1fr 1fr 1fr 96px 60px 60px 62px;
}

.ds-list-head {
  background: #262323;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.ds-list-head a {
  color: #fff;
  text-decoration: none;
}

.ds-list-head a:hover {
  text-decoration: underline;
}

.ds-list-head .ds-sorted {
  color: #f0b8bf;
}

/* White so it reads against the dark header -- it was inheriting and
   disappearing. Per Kenny, Oct 2026. */
.ds-sort-arrow {
  margin-left: 3px;
  font-size: 10px;
  line-height: 1;
  color: #fff;
}

/* Idle arrows are dim but present, so it is discoverable that a column sorts
   without four bright arrows competing with the active one. */
.ds-sort-arrow--idle {
  opacity: 0.55;
}

.ds-list-head a:hover .ds-sort-arrow--idle {
  opacity: 0.9;
}

/* The WHOLE row is a link to the show, not just the event name -- a far bigger
   tap target on mobile. Done with a stretched pseudo-element on the real <a>
   rather than wrapping the row in one: the row also contains the MyAFSB
   checkbox, and an interactive control inside an <a> is invalid HTML and
   breaks on touch. The <a> stays the accessible/keyboard target.
   Per Kenny, Oct 2026. */
.ds-list-row {
  border-top: 1px solid #f2f2f2;
  font-size: 13px;
  color: #262323;
  position: relative;
}

.ds-list-row .ds-list-name a::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
}

.ds-list-row:hover {
  cursor: pointer;
}

/* The save checkbox has to sit ABOVE the stretched link or it becomes
   unclickable -- the whole point of keeping it out of the <a>. */
.ds-list-row .ds-col-save {
  position: relative;
  z-index: 2;
}

/* Centre the checkbox in its column, header label included. In the list the
   label has no text -- it is just the box -- so centring the label centres the
   box. Per Kenny, Oct 2026. */
.ds-col-save {
  display: flex;
  align-items: center;
  justify-content: center;
}

.ds-list-head .ds-col-save {
  text-align: center;
}

/* No gap to honour here (no label text), so the card's spacing must not leak in. */
.ds-col-save .myafsb-save-toggle {
  gap: 0;
}

.ds-list-row:nth-child(even) {
  background: #fcfbfb;
}

.ds-list-row:hover {
  background: #fff5f6;
}

.ds-list-row--featured {
  box-shadow: inset 3px 0 0 #B23B48;
}

/* Badges stack on their own line above the event name. Their shared
   margin-bottom (8px, set for the card layout) is too much here, so it is
   trimmed to keep the row compact. */
.ds-list-badges {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  margin-bottom: 2px;
}

.ds-list-badges .ds-feat-flag,
.ds-list-badges .deadline-urgent-badge {
  margin-bottom: 0;
}

/* SCOPED TO BODY ROWS on purpose. This used to be a bare `.ds-list-name a`,
   which also matched the Event column's sort link in the dark header -- equal
   specificity to `.ds-list-head a` but declared later, so it won, painting the
   link #252323 on a #262323 background. The Event column looked unsortable
   because its header link was invisible. Per Kenny, Oct 2026. */
.ds-list-row .ds-list-name a {
  color: #252323;
  font-weight: 600;
  text-decoration: none;
}

.ds-list-row .ds-list-name a:hover {
  color: #B23B48;
  text-decoration: underline;
}

/* Belt and braces: every header link, including Event, stays white. */
.ds-list-head .ds-list-name a,
.ds-list-head a {
  color: #fff;
}

.ds-list-num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

/* Paywalled cell -- same lock treatment results.php uses */
.afsb-locked-cell {
  color: #9a9393;
  vertical-align: -2px;
}

.ds-list-empty {
  color: #b5aeae;
}

/* ===========================================================
   CALENDAR -- month-paginated, Sunday start
   =========================================================== */
/* The month nav is the first thing the calendar renders, so it carries the
   divider that separates the page-level view toggle above from the calendar's
   own controls (month/year jump, then the legend toggles) below. Without it
   the two rows of controls read as one undifferentiated block. Adjacent
   sibling margins collapse, so the 20px here wins over .ds-meta's 14px and
   the spacing stays symmetric either side of the rule. */
.ds-cal-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 14px;
  flex-wrap: wrap;
  margin-top: 20px;
  padding-top: 20px;
  border-top: 1px solid #e8e0e0;
  margin-bottom: 14px;
}

.ds-cal-nav h3 {
  margin: 0;
  min-width: 170px;
  text-align: center;
  font-family: 'Winsel-Variable', 'Work Sans', sans-serif;
  color: #252323;
}

.ds-cal-nav a {
  color: #B23B48;
  text-decoration: none;
  font-weight: 600;
  padding: 6px 12px;
  border: 1px solid #B23B48;
  border-radius: 4px;
}

.ds-cal-nav a:hover {
  background: #B23B48;
  color: #fff;
}

/* Sits BELOW the month label rather than beside it, per Kenny, Oct 2026. */
.ds-cal-jump {
  display: flex;
  gap: 8px;
  align-items: center;
  justify-content: center;
  flex-wrap: nowrap;
  margin: 0 0 14px;
}

/* width:auto is load-bearing. These selects are NOT inside .ds-field, so the
   earlier width fix never reached them and they inherited the global
   `.content select { width: 80% }` -- each one 80% of the row, which is why
   they looked enormous AND wrapped onto separate lines (two 80% items cannot
   sit side by side). Sized to their content instead, and the selected text is
   centred in the closed box via text-align-last. Per Kenny, Oct 2026. */
.ds-cal-jump select.ds-cal-goto {
  width: auto;
  min-width: 0;
  flex: 0 0 auto;
  padding: 6px 24px;
  font-size: 14px;
  text-align: center;
  text-align-last: center;
  -moz-text-align-last: center;
  text-align: -webkit-center;
}

.ds-cal-jump select.ds-cal-goto option {
  text-align: center;
}

/* Brief dim while a month is fetched, so a slow request does not look like a
   dead click. Pointer events stay off to prevent double-firing. */
#ds-cal-wrap.is-loading {
  opacity: 0.55;
  pointer-events: none;
  transition: opacity 0.1s ease;
}

.ds-cal-jump select {
  border: 1px solid #979797;
  border-radius: 4px;
  padding: 6px 10px;
  font-size: 14px;
  background: #fff;
  color: #252323;
  cursor: pointer;
}

.ds-cal {
  width: 100%;
  border-collapse: collapse;
  table-layout: fixed;
}

.ds-cal th {
  background: #262323;
  color: #fff;
  font-size: 12px;
  font-weight: 600;
  padding: 8px 4px;
  letter-spacing: 0.04em;
}

.ds-cal td {
  border: 1px solid #e8e0e0;
  vertical-align: top;
  height: 104px;
  padding: 5px;
  font-size: 11px;
}

.ds-cal .ds-cal-empty {
  background: #fafafa;
}

.ds-cal .ds-cal-today {
  background: #fff5f6;
}

.ds-cal-daynum {
  font-weight: 700;
  color: #7a7474;
  margin-bottom: 4px;
}

.ds-cal-today .ds-cal-daynum {
  color: #B23B48;
}

.ds-cal-item {
  display: flex;
  align-items: flex-start;
  gap: 4px;
  margin-bottom: 3px;
  line-height: 1.3;
}

.ds-cal-item img {
  flex-shrink: 0;
  margin-top: 1px;
}

.ds-cal-item a {
  text-decoration: none;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  display: block;
}

.ds-cal-item--start a {
  color: #000;
  font-weight: 600;
}

.ds-cal-item--deadline a,
.ds-cal-item--notification a,
.ds-cal-item--refund a,
.ds-cal-item--balance a {
  color: #08088a;
  font-weight: 400;
}

.ds-cal-tag {
  color: #7a7474;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.04em;
}

.ds-cal-more {
  color: #7a7474;
  font-size: 10px;
  margin-top: 2px;
}

/* Hover callout on a calendar entry -- the rich detail results.php shows */
.ds-cal-hover {
  position: relative;
}

.ds-cal-hover .ds-cal-callout {
  display: none;
  position: absolute;
  z-index: 40;
  left: 0;
  top: 100%;
  width: 230px;
  background: #fff;
  border: 1px solid #262323;
  border-radius: 5px;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
  padding: 10px 12px;
  font-size: 11.5px;
  line-height: 1.5;
  color: #262323;
  white-space: normal;
}

.ds-cal-hover:hover .ds-cal-callout,
.ds-cal-hover:focus-within .ds-cal-callout {
  display: block;
}

.ds-cal-callout strong {
  display: block;
  margin-bottom: 4px;
  color: #252323;
}

/* Legend */
.ds-cal-legend {
  margin: 14px 0 18px;
  padding: 12px 16px;
  border: 1px solid #e8e0e0;
  border-radius: 6px;
  background: #fff;
  font-size: 12px;
  color: #262323;
}

/* float: none is load-bearing. The site's global stylesheet sets
   `h4 { float: left; margin-right: 0.83333em; }` (styles.css ~704), so this
   heading floated and the legend items flowed up alongside it -- the first
   icon collided with the word "Legend". styles.css already does the same
   un-float for .info_content h4, so this follows existing precedent.
   Per Kenny, Oct 2026. */
.ds-cal-legend h4 {
  float: none;
  display: block;
  width: 100%;
  margin: 0 0 8px;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #7a7474;
}

/* Each legend item is a label carrying its own show/hide checkbox, so the
   checkbox, icon and text are one click target. Replaces the old split of an
   icon row plus a separate toggle row. Per Kenny, Oct 2026. */
.ds-cal-legend-items {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
}

/* gap:0 on the row; each child sets its own left margin instead, so the
   checkbox sits tight to its icon and the icon tight to its text, rather than
   one uniform gap spreading all three apart. */
.ds-cal-legend-item {
  display: inline-flex;
  align-items: center;
  gap: 0;
  cursor: pointer;
  user-select: none;
  white-space: nowrap;
  line-height: 1;
}

/* The 20px icon reads as sitting higher than the 14px checkbox and 12px label
   even though flex centres all three, so the checkbox and label are nudged up
   to meet it optically. Per Kenny, Oct 2026 -- he's eyeballing the rendered
   page, which is the only way to judge this.
   --ds-legend-lift is the single number to tune. position/top rather than
   transform, so the text stays on the pixel grid and doesn't blur. */
.ds-cal-legend-items {
  --ds-legend-lift: 5px;
}

.ds-cal-legend-item input[type="checkbox"] {
  cursor: pointer;
  position: relative;
  top: calc(-1 * var(--ds-legend-lift));
}

.ds-cal-legend-item img,
.ds-cal-legend-item .ds-cal-legend-tag {
  margin-left: 5px;
}

.ds-cal-legend-item .ds-cal-legend-text {
  margin-left: 5px;
  font-size: 12px;
  line-height: 1;
  position: relative;
  top: calc(-1 * var(--ds-legend-lift));
}

/* Unchecked reads as "hidden from the grid" without needing a second cue. */
.ds-cal-legend-item:has(input:not(:checked)) .ds-cal-legend-text {
  color: #9a9393;
  text-decoration: line-through;
}

/* Stands in for the icon on the three date types that render as text-tagged
   entries in the grid rather than icons. */
.ds-cal-legend-tag {
  flex-shrink: 0;
  padding: 1px 5px;
  border-radius: 3px;
  background: #eef0f8;
  color: #08088a;
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: 0.03em;
}

/* Non-interactive key for the MyAFSB status icons -- these explain the icons,
   they are not filters, so they get no checkbox. */
.ds-cal-legend-key {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 6px 16px;
  margin-top: 10px;
  padding-top: 10px;
  border-top: 1px solid #f2f2f2;
}

.ds-cal-legend-key__label {
  font-weight: 700;
  color: #7a7474;
}

.ds-cal-legend-key span {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  white-space: nowrap;
}

/* Icons are 20x20. Pinned explicitly so the row does not reflow as they load,
   and so the global `img { max-width: 100% }` cannot squash them. */
.ds-cal-legend-items img,
.ds-cal-legend-key img {
  width: 20px;
  height: 20px;
  flex-shrink: 0;
}

/* JS-driven per-type visibility, same pattern directory.php uses */
.ds-cal-grid.hide-start .ds-cal-item--start,
.ds-cal-grid.hide-deadline .ds-cal-item--deadline,
.ds-cal-grid.hide-notification .ds-cal-item--notification,
.ds-cal-grid.hide-refund .ds-cal-item--refund,
.ds-cal-grid.hide-balance .ds-cal-item--balance {
  display: none;
}

/* ===========================================================
   MAP
   =========================================================== */
.ds-map {
  width: 100%;
  height: 520px;
  border: 1px solid #e8e0e0;
  border-radius: 6px;
}

/* ===========================================================
   FILTER BAR
   Sections are rendered or withheld by tier, so the bar is one
   section tall for a public visitor and four for a subscriber.
   =========================================================== */
.ds-filters {
  border: 1px solid #262323;
  border-radius: 6px;
  margin-bottom: 24px;
  background: #fff;
}

.ds-fsec {
  border-bottom: 1px solid #e8e0e0;
  padding: 14px 18px;
}

.ds-fsec:last-child {
  border-bottom: 0;
}

.ds-fsec h3 {
  margin: 0 0 10px;
  font-size: 13px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  color: #262323;
}

.ds-frow {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
}

/* flex-shrink is disabled on purpose. A <select> sizes itself to its widest
   <option> when left alone, but as a shrinkable flex item the field was being
   squeezed and the select stretched to that squeezed width, clipping the
   selected option text ("Featured & upcoming", "Indoors or outdoors"). With
   shrink off, each field keeps its natural width and the row wraps instead --
   which is what flex-wrap above is already there for. The search input opts
   back into shrinking via its own inline flex basis, since it should absorb
   the leftover space. Per Kenny, Oct 2026. */
.ds-field {
  display: flex;
  flex-direction: column;
  gap: 4px;
  flex: 0 0 auto;
}

/* Search on its own row, dropdowns beneath. The search input is the one field
   that SHOULD stretch and shrink -- it opts back into flexing, unlike the
   fixed-width selects below it. */
.ds-frow--search {
  margin-bottom: 14px;
}

/* Fixed width rather than fill-the-row: the bar used to stretch the whole
   container with the button pushed far to the right. `flex: 0 1` so it still
   SHRINKS on a narrow phone but never grows past --ds-search-w, which is the
   one number to tune. Per Kenny, Oct 2026. */
.ds-wrap .ds-frow--search {
  --ds-search-w: 320px;
}

.ds-field--grow {
  flex: 0 1 var(--ds-search-w, 320px);
  max-width: 100%;
  min-width: 0;
}

.ds-field--grow input {
  width: 100%;
}

/* ===========================================================
   MOBILE FILTER ACCORDION

   On a phone the four refinement dropdowns collapse behind a toggle so only
   the search field and its button are visible -- per Kenny, Oct 2026.

   The collapsing is gated on .js-collapsible, which JS adds to the form at
   load. Without JS the class never appears and the dropdowns stay visible,
   so a no-script phone is not left with filters it can never open.
   =========================================================== */
/* A chevron, not a button that looks like another dropdown. The earlier
   full-width bordered control labelled "Filters" read as a fourth select,
   which is exactly the wrong signal. Now: brand red, icon only, centred.
   Per Kenny, Oct 2026. */
.ds-filter-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  gap: 5px;
  margin: 0 auto;
  background: none;
  border: 0;
  padding: 6px 10px;
  font-family: inherit;
  font-size: 12px;
  font-weight: 700;
  color: #B23B48;
  cursor: pointer;
  line-height: 1;
}

.ds-filter-toggle:hover .ds-filter-toggle__chev,
.ds-filter-toggle:focus-visible .ds-filter-toggle__chev {
  background: #B23B48;
  color: #fff;
}

/* Active-filter count is the only text that earns its place here -- without it
   a collapsed panel gives no hint that filters are applied. Rendered as a small
   filled badge rather than words, to keep the control icon-only. */
.ds-filter-toggle__count {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 18px;
  height: 18px;
  padding: 0 5px;
  border-radius: 9px;
  background: #B23B48;
  color: #fff;
  font-size: 11px;
  font-weight: 700;
  line-height: 1;
}

.ds-filter-toggle__chev {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: 1px solid #B23B48;
  border-radius: 50%;
  color: #B23B48;
  font-size: 10px;
  transition: transform 0.18s ease, background 0.15s ease, color 0.15s ease;
}

.ds-filter-toggle[aria-expanded="true"] .ds-filter-toggle__chev {
  transform: rotate(180deg);
}

/* #ds-filter-more is a BLOCK container wrapping whole .ds-fsec sections, not a
   flex row of fields. It wraps everything except the search row, so the
   chevron collapses the entire filter set -- including a subscriber's
   Location / Dates / Event rules / Limit-to sections, which previously sat
   outside it and stayed on screen. The inner .ds-frow still does the flexing. */
.ds-filter-more > .ds-fsec:last-child {
  border-bottom: 0;
}

@media (max-width: 700px) {
  .ds-filter-toggle {
    display: flex;
  }

  .ds-filters.js-collapsible .ds-filter-more {
    display: none;
  }

  .ds-filters.js-collapsible .ds-filter-more.is-open {
    display: block;
  }

  /* Stacked full-width controls read better than a wrapped two-up grid once
     the panel is open on a phone. */
  .ds-filter-more .ds-field,
  .ds-filter-more .ds-field select:not([multiple]) {
    width: 100%;
    flex: 1 1 100%;
    min-width: 0;
  }
}

.ds-field label {
  font-size: 12px;
  font-weight: 600;
  color: #262323;
}

.ds-field input,
.ds-field select {
  border: 1px solid #979797;
  border-radius: 4px;
  padding: 6px 10px;
  font-size: 14px;
  color: #252323;
  background: #fff;
  box-sizing: border-box;
}

/* `width: auto` is LOAD-BEARING -- without it these selects do not size to
   their widest option.

   The previous version of this rule omitted width and the comment claimed it
   "stays auto". It does not: styles.css has `.content select { width: 80% }`
   at (0,1,1), and nothing here declared width, so every single select was 80%
   of its flex item and the selected text clipped -- "Featured & upcomin".
   Wendy reported it, Oct 2026. Resolved with the cascade checker, not by eye.
   `.ds-field select:not([multiple])` is (0,2,1) and wins.

   The floor is 12rem (192px) because the longest option, "Featured &
   upcoming", needs ~163px at 14px plus the 30px arrow gutter. Right padding
   keeps the native arrow off the text. Same fix already applied to the
   calendar jump selects for the same global rule. */
.ds-field select:not([multiple]) {
  width: auto;
  min-width: 12rem;
  padding-right: 30px;
  max-width: 100%;
}

.ds-field input:focus,
.ds-field select:focus {
  outline: none;
  border-color: #B23B48;
}

.ds-field select[multiple] {
  min-width: 210px;
}

.ds-hint {
  font-weight: 400;
  color: #7a7474;
}

.ds-inline {
  font-weight: 400 !important;
  display: inline-flex;
  align-items: center;
  gap: 5px;
}

.ds-btn {
  background: #B23B48;
  color: #fff;
  border: 0;
  border-radius: 4px;
  padding: 8px 18px;
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  font-family: inherit;
}

.ds-btn:hover {
  background: #8c2f38;
}

.ds-btn.secondary {
  background: #fff;
  color: #B23B48;
  border: 1px solid #B23B48;
  text-decoration: none;
  display: inline-block;
}

.ds-btn.secondary:hover {
  background: #fff5f6;
}

.ds-factions {
  gap: 12px;
}

.ds-checks {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 16px;
}

.ds-checks label {
  font-size: 13px;
  font-weight: 400;
  display: flex;
  align-items: center;
  gap: 5px;
  cursor: pointer;
}

/* ===========================================================
   SHARED CHROME
   =========================================================== */
/* Three tracks so the view toggle sits in the true centre of the row rather
   than being pushed right by space-between -- the count occupies the left
   track and the right track stays empty, which keeps the toggle centred on
   the page regardless of how long the count text is. Per Kenny, Oct 2026. */
.ds-meta {
  display: grid;
  /* minmax(0, 1fr), not plain 1fr: a bare 1fr is minmax(auto, 1fr), so a long
     count string ("695 events (showing 1-24) - 3 of 25 saved shows used")
     could grow the left track past its share and shift the toggle off-centre.
     Pinning the minimum to 0 keeps the two outer tracks equal and lets the
     count wrap inside its own track instead. */
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  align-items: center;
  gap: 10px;
  margin-bottom: 14px;
  font-size: 13px;
  color: #262323;
}

.ds-meta > :first-child {
  justify-self: start;
}

.ds-views {
  display: flex;
  gap: 6px;
  flex-wrap: wrap;
  justify-content: center;
  justify-self: center;
}

/* One style wherever the toggle appears: outline at rest, solid when active.
   Per Wendy, Oct 2026 -- was near-black, now brand red. */
.ds-views a,
.ds-views .ds-views__locked {
  padding: 6px 14px;
  background: #fff;
  border: 1px solid #B23B48;
  border-radius: 4px;
  color: #B23B48;
  text-decoration: none;
  font-size: 13px;
  white-space: nowrap;
}

.ds-views a.active {
  background: #B23B48;
  border-color: #B23B48;
  color: #fff;
}

/* A view this tier cannot use: visible, clearly inert, and carrying the same
   lock glyph as the paywalled table cells so the two read as one idea. */
.ds-views .ds-views__locked {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  border-color: #ddd8d8;
  background: #f7f5f5;
  color: #9a9393;
  cursor: not-allowed;
  user-select: none;
}

.ds-views .ds-views__locked .afsb-locked-cell {
  color: #9a9393;
  flex-shrink: 0;
}

.ds-pager {
  display: flex;
  gap: 6px;
  justify-content: center;
  margin: 22px 0;
  flex-wrap: wrap;
}

/* The top copy sits between the view toggle and the results, so it needs less
   room above it than the bottom copy. Per Kenny, Oct 2026. */
.ds-pager--top {
  margin: 0 0 14px;
}

.ds-pager--bottom {
  margin: 18px 0 0;
}

.ds-pager__gap {
  border-color: transparent;
}

.ds-pager a,
.ds-pager span {
  padding: 6px 11px;
  border: 1px solid #e8e0e0;
  border-radius: 4px;
  color: #262323;
  text-decoration: none;
  font-size: 13px;
}

.ds-pager a.active {
  background: #B23B48;
  color: #fff;
  border-color: #B23B48;
}

.ds-empty {
  padding: 36px;
  text-align: center;
  color: #7a7474;
  border: 1px dashed #e8e0e0;
  border-radius: 6px;
}

.ds-note {
  font-size: 12px;
  color: #7a7474;
  margin-top: 6px;
  line-height: 1.5;
}

.ds-upsell {
  background: #fff5f6;
  border: 1px solid #e3b7bd;
  border-radius: 6px;
  padding: 12px 16px;
  margin-bottom: 16px;
  font-size: 13px;
  color: #6b4a4f;
}

.ds-upsell a {
  color: #B23B48;
  font-weight: 600;
}

/* ===========================================================
   RESPONSIVE
   =========================================================== */
/* Narrow screens scroll the list sideways rather than losing columns -- per
   Kenny, Oct 2026: every column should stay reachable. The min-width on the
   grid is what forces the overflow; without it the fr columns would just
   collapse to nothing and no scrollbar would appear. */
.ds-list-scroll {
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;
}

.ds-list--public {
  min-width: 860px;
}

.ds-list--member {
  min-width: 920px;
}

/* Narrow screens: the three-track row cannot hold a count and four view
   buttons side by side, so stack them and centre both -- the toggle stays
   centred on mobile as well as desktop. */
@media (max-width: 760px) {
  .ds-meta {
    grid-template-columns: 1fr;
    justify-items: center;
  }

  .ds-meta > :first-child {
    justify-self: center;
    text-align: center;
  }
}

@media (max-width: 900px) {
  .directory-card {
    width: calc(50% - 9px);
  }

  /* The list header deliberately stays visible at every width. It used to be
     hidden here, with rows collapsing to two unlabelled columns -- which left
     a bare "$4,200" and "12" with nothing to say what they were. Shedding
     columns (see the breakpoints above) keeps every remaining value labelled.

     NOTE: this block used to also shrink .ds-cal td to height:auto/min-height:62px.
     That was removed -- see the mobile calendar block below. Squeezing seven
     columns into a phone width gave ~52px per day, which no event name fits in. */
}

@media (max-width: 560px) {

  .ds-list-head,
  .ds-list-row {
    gap: 8px;
    padding: 9px 10px;
    font-size: 12.5px;
  }
}

@media (max-width: 560px) {
  .ds-wrap {
    padding: 20px 16px 40px;
  }

  .directory-card {
    width: 100%;
  }

  .ds-cal-nav h3 {
    min-width: 0;
  }
}

/* ===========================================================
   COLLAPSIBLE FILTER SECTIONS
   Each category header (Location, Dates, Event rules, Limit to) is a chevron
   toggle. Default is collapsed -- on desktop the four paid sections stacked
   open pushed the results below the fold. Per Kenny, Oct 2026.

   Collapsing is gated on `.js-fsec`, which the page script adds. With JS off
   `.ds-fsec__body` is never hidden, so the filters cannot end up locked behind
   a chevron that does nothing.
   =========================================================== */
.ds-fsec__head {
  margin: 0;
}

/* Full button reset. styles.css:88 styles every bare `button` as a solid red
   CTA (red fill, white text, border, 16px); a section header must not look like
   a submit button. `.ds-fsec__toggle` is (0,1,0) and beats `button` at (0,0,1). */
.ds-fsec__toggle {
  display: flex;
  align-items: center;
  gap: 8px;
  width: 100%;
  margin: 0;
  padding: 0;
  background: none;
  border: 0;
  color: inherit;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.ds-fsec__toggle:hover .ds-fsec__title,
.ds-fsec__toggle:focus-visible .ds-fsec__title {
  color: #B23B48;
}

.ds-fsec__title {
  font: inherit;
  color: inherit;
}

/* Pushes the chevron to the far right whatever the title length. */
.ds-fsec__chev {
  margin-left: auto;
  font-size: 10px;
  line-height: 1;
  color: #8C8880;
  transition: transform 0.15s ease;
}

.ds-fsec--toggles.is-open .ds-fsec__chev {
  transform: rotate(180deg);
}

/* Count badge: the one hint a collapsed section is doing something. Same shape
   as .ds-filter-toggle__count on the whole-panel toggle. */
.ds-fsec__count {
  display: inline-block;
  min-width: 16px;
  padding: 1px 5px;
  border-radius: 9px;
  background: #B23B48;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 1.4;
  text-align: center;
}

.js-fsec .ds-fsec__body {
  display: none;
}

.js-fsec .ds-fsec--toggles.is-open .ds-fsec__body {
  display: block;
}

/* Collapsed sections only need the header, so the generous section padding just
   makes a column of fat empty bars. */
.js-fsec .ds-fsec--toggles {
  padding-top: 10px;
  padding-bottom: 10px;
}

.js-fsec .ds-fsec--toggles.is-open {
  padding-top: 14px;
  padding-bottom: 14px;
}

.js-fsec .ds-fsec--toggles.is-open .ds-fsec__head {
  margin-bottom: 10px;
}

/* ===========================================================
   SUBSCRIPTIONS LINE (under the search bar)
   Mirrors the "Subscriptions:" row in the results.php summary block: the label
   bold near-black, the value in the site grey. Those .summary-* classes live in
   results.php's inline <style> and so are unavailable here -- these are local
   equivalents, not a rename of them.

   `.ds-wrap` prefixes because this page's wrapper is <div class="content
   ds-wrap">, and bare single-class selectors here lose to styles.css's
   `.content <element>` rules at (0,1,1).
   =========================================================== */
.ds-wrap .ds-subs {
  margin: -4px 0 14px;
  font-family: 'Work Sans', sans-serif;
  line-height: 1.4;
}

.ds-wrap .ds-subs__label {
  color: #252323;
  font-weight: 600;
  font-size: 16px;
}

.ds-wrap .ds-subs__value {
  margin-left: 10px;
  color: #8C8880;
  font-size: 14px;
}

/* ===========================================================
   LAUNCH NOTICE -- temporary, delete with the PHP when it expires

   Sits directly under the page heading rule. Informational, so it is kept
   quieter than an error box: tinted brand background, no heavy border.
   =========================================================== */
.ds-wrap .ds-banner {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  margin: 0 0 18px;
  padding: 11px 14px;
  background: #fdf4f5;
  border-left: 3px solid #B23B48;
  border-radius: 3px;
}

/* The retired-page notice is an explanation rather than an announcement, so it
   carries a touch more weight than the launch banner and no dismiss button. */
.ds-wrap .ds-banner--moved {
  background: #f7f5f5;
  border-left-color: #262323;
}

.ds-wrap .ds-banner__text {
  margin: 0;
  flex: 1 1 auto;
  font-size: 14px;
  line-height: 1.4;
  color: #252323;
}

/* The global `.content button` styling would make this a full-size button, so
   everything is reset explicitly. 32px box keeps it a comfortable tap target
   on a phone without making the bar taller than its text. */
.ds-wrap .ds-banner__x {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  margin: -5px -5px -5px 0;
  padding: 0;
  background: none;
  border: 0;
  border-radius: 3px;
  color: #8C8880;
  font-size: 22px;
  line-height: 1;
  cursor: pointer;
}

.ds-wrap .ds-banner__x:hover,
.ds-wrap .ds-banner__x:focus {
  background: rgba(178, 59, 72, 0.1);
  color: #B23B48;
}

/* ===========================================================
   MOBILE CALENDAR -- must stay LAST in this file.
   Media queries add no specificity, so this block only wins over the base
   .ds-cal rules by source order. It previously sat near the top and was
   silently overridden -- the scroll worked but the cell sizing did not.
   =========================================================== */
/* ---- mobile calendar: bigger, and scrolled sideways ----
   `table-layout: fixed; width: 100%` on seven columns gives ~52px per day at
   phone width, which no event name fits into -- the month was technically on
   screen but unreadable. So on narrow screens the grid keeps full-size cells
   and legible type, and the wrapper scrolls horizontally instead of the table
   compressing. Same trade already made for the list view.
   Per Kenny, Oct 2026. */
@media (max-width: 830px) {
  .ds-cal-grid {
    overflow-x: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior-x: contain;
  }

  /* ~111px per column -- enough for a truncated event name to be readable. */
  .ds-cal {
    min-width: 780px;
  }

  .ds-cal td {
    height: 110px;
    padding: 6px;
    font-size: 12.5px;
  }

  .ds-cal th {
    font-size: 12.5px;
    padding: 9px 4px;
  }

  .ds-cal-daynum {
    font-size: 12.5px;
    margin-bottom: 5px;
  }

  .ds-cal-item {
    margin-bottom: 4px;
  }

  .ds-cal-item a {
    font-size: 12px;
  }

  .ds-cal-more {
    font-size: 11px;
  }

  /* The hover callout is absolutely positioned, so inside a scrolling wrapper
     it would be clipped. There is no hover on touch anyway, and :focus-within
     would otherwise fire it on tap -- so it is off at these widths. */
  .ds-cal-hover .ds-cal-callout,
  .ds-cal-hover:hover .ds-cal-callout,
  .ds-cal-hover:focus-within .ds-cal-callout {
    display: none;
  }
}
