/* ===========================================================================
   Apollyon Data Engine - listing views (grid / map / calendar)

   Deliberately restrained: the cards themselves are styled by the App Designer
   (they are structurally the product card), so this file only dresses the bits
   that have no product equivalent - the view switcher, the map panel and the
   calendar. Brand colour comes from the App Designer's own token so a site's
   theme wins without anything being restated here.
   =========================================================================== */

.de-views { margin: 0 0 20px; width: 100%; }

/* NB there is deliberately no .de-view-bar / .de-view-label block any more.
   The switcher was a standalone strip above the filter bar; it is now one of
   the bar's own .input-icons controls, which means the App Designer's bar
   styling - control shape, icon weight and family - applies to it without a
   single property being restated here. Styling it separately again would be
   how the two drift apart. */

/* ---- in-bar controls: hide what the current view cannot use --------------
   The switcher and the distance tools now live INSIDE .apol-filter-controls,
   so the toolbar can no longer be hidden wholesale for map/calendar - that
   would take the way out of those views with it. The script tags the toolbar
   with the current view instead and these rules drop the controls that act on
   the card list: search, sort, card size, per-page, and the results count.

   :has() rather than a class on each wrapper, because the wrappers are the
   template's own .input-icons divs - untouched, so a template change to the
   bar needs no matching change here. Facets are deliberately NOT hidden: on
   the map they still decide which pins show. */
.apol-cat-toolbar.de-hide-listctl .apol-filter-controls > .input-icons:has([data-grid-control="text-filter"]),
.apol-cat-toolbar.de-hide-listctl .apol-filter-controls > .input-icons:has([data-grid-control="sort"]),
.apol-cat-toolbar.de-hide-listctl .apol-filter-controls > .input-icons:has([data-grid-control="page-size"]),
.apol-cat-toolbar.de-hide-listctl .apol-filter-controls > .input-icons:has(#gridSizeSelect) {
  display: none !important;
}
.apol-cat-toolbar.de-hide-listctl .pagination-label-holder { display: none !important; }

/* The calendar has no distance dimension - it is ordered by date. */
.apol-cat-toolbar.de-view-calendar .de-near,
.apol-cat-toolbar.de-view-calendar .de-near-status { display: none !important; }

/* Our two controls adopt the bar's own control shell, so they need almost
   nothing - only the bits .input-icons does not already cover. */
.de-view-pick .de-view-select { flex: 1 1 auto; min-width: 0; }

/* .input-icons is not a flex container of its own, so without this the field
   and buttons align on the TEXT BASELINE and the input sits visibly lower than
   the controls either side of it. */
.de-near { display: flex; align-items: center; gap: 6px; }

/* ⚠️ ".input-icons i { position: absolute }" in apol.base.css applies to EVERY
   <i> inside one of these wrappers, not just the leading control icon. Left
   alone, the icon inside each of our buttons is torn out of the button and
   positioned against the nearest positioned ancestor - which is what put the
   magnifying glass low and outside its box. Put them back in flow. */
.de-near i,
.de-view-pick i { position: static !important; }

/* Optical centring correction, verified by eye on the live bar rather than
   derived: these glyphs sit a shade right of the geometric centre of their
   box. translateX rather than position/left, because the rule above pins
   these icons to position:static and this must not undo that. */
.de-near-btn i,
.de-near-clear i,
.de-near-field .de-near-go i { transform: translateX(-1px); }

/* The postcode field, with its search button laid over the right-hand end so
   the pair occupies one control's width rather than two. */
.de-near-field { position: relative; display: inline-flex; flex: 0 1 148px; min-width: 0; }
.de-near-field .de-near-input {
  width: 100% !important;   /* beats the bar's fixed 220px on text inputs */
  min-width: 0;
  padding-right: 34px;      /* room for the button that sits on top */
}
.de-near-field .de-near-go {
  position: absolute;
  top: 50%;
  right: 2px;
  transform: translateY(-50%);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border: 0;                /* it is inside the field's own border */
  background: transparent;
  /* sits over the WHITE input, so it follows the input's text colour - not
     the bar's, which is the light-on-dark one used outside the field */
  color: var(--apol-color-muted, #666);
  opacity: .8;
}
.de-near-field .de-near-go:hover { opacity: 1; }

/* Icon buttons, sized to sit level with the controls either side rather than
   as word-wide buttons - which is what pushed the bar onto a second row.
   40px matches the height the bar gives its inputs and selects.

   COLOUR comes from the App Designer's own filter-bar text token. Inheriting
   instead would pick up ".input-icons { color: var(--apol-color-heading) }",
   which is a DARK heading colour - invisible against the dark bar, which is
   why the location button could not be seen at all. */
.de-near-go,
.de-near-btn,
.de-near-clear {
  flex: 0 0 auto;
  font: inherit;
  line-height: 1;
  width: 38px;
  height: 40px;
  padding: 0;
  cursor: pointer;
  /* Centre the glyph geometrically. The icons were sitting a touch right of
     centre because, once put back in flow, an inline <i> is positioned by
     text layout - which carries the font's own side bearing. Flex centring
     removes that rather than compensating for it with a nudge that would be
     wrong at another icon or font size. */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border-radius: var(--apol-input-radius, var(--apol-button-radius, 4px));
  color: var(--apol-listing-filterbar-text, #fff);
  border: 1px solid var(--apol-listing-filterbar-rule, rgba(255, 255, 255, .28));
  background: transparent;
}
/* Icon-only on the desktop bar; the label is shown only on the mobile sheet. */
.de-near-btn-label { display: none; }

.de-near-go:hover,
.de-near-btn:hover,
.de-near-clear:hover { filter: brightness(1.08); }
.de-near-go:focus-visible,
.de-near-btn:focus-visible,
.de-near-clear:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* A sentence, not a control - so it sits on its own line BELOW the control
   row (the script places it after .apol-filter-controls, not inside it) and
   never reflows the controls. :empty so it takes no space until it speaks. */
/* ---- busy state ----------------------------------------------------------
   Browser geolocation can take several seconds, and the permission prompt may
   appear over the page - with no feedback the button reads as broken, which
   is exactly how it looked. The glyph is hidden rather than removed so the
   button cannot change size mid-spin. */
.de-near-btn,
.de-near-go { position: relative; }

.de-near .is-busy i { visibility: hidden; }
.de-near .is-busy::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 14px;
  height: 14px;
  margin: -7px 0 0 -7px;
  border: 2px solid currentColor;
  border-top-color: transparent;   /* the gap that makes the rotation legible */
  border-radius: 50%;
  animation: de-spin .7s linear infinite;
}
.de-near .is-busy { cursor: progress; }

@keyframes de-spin { to { transform: rotate(360deg); } }

/* Respect a stated preference for less motion: keep the indicator, drop the
   spin - a static ring still marks the control as busy. */
@media (prefers-reduced-motion: reduce) {
  .de-near .is-busy::after { animation: none; opacity: .6; }
}

/* Same App Designer token as the buttons - it sits on the bar, not in a field. */
.de-near-status {
  display: block;
  margin: 6px 0 0;
  font-size: 13px;
  opacity: .8;
  color: var(--apol-listing-filterbar-text, #fff);
}
.de-near-status:empty { display: none; }

/* ---- mobile + tablet filter panel: reorder + separate the DE controls ------
   Below 980px the filter is a stacked LIGHT panel in BOTH of its modes:
     - SHEET  (App Designer --apol-listing-filter-mobile:sheet) - full-screen,
               a .apol-filter-sheet-head bar and a pinned footer button;
     - DRAWER (the default)  - a slide-out with an X close as the panel's first
               child and an in-flow "View results" button as its last.
   These rules deliberately do NOT scope to body.apol-filter-sheet, so they
   cover both: below 980 the panel is always this stacked light drawer, never
   the desktop bar (which is >980). apol.de.listing.css only loads on DE
   listings, so a products filter is untouched regardless.
   Verified on the live sheet at 375px; the drawer shares the same structure. */
@media (max-width: 980px) {
  /* Header stays at the top. The sheet has .apol-filter-sheet-head; the drawer
     inserts .apol-filter-drawer-close (X) as the body's first child. Both must
     outrank the relocated DE controls (negative order) below. */
  details.apol-filter-panel > .apol-filter-body > .apol-filter-sheet-head,
  details.apol-filter-panel > .apol-filter-body > .apol-filter-drawer-close { order: -10; }

  /* The drawer's in-flow "View results" button stays pinned to the bottom.
     (The sheet moves its own copy into a fixed foot, outside this flow.) */
  details.apol-filter-panel > .apol-filter-body > .apol-filter-drawer-apply { order: 100; }

  /* Postcode, search, View options - all before the order-0 native rows. */
  .apol-filter-body .de-near { order: -4; }
  .apol-filter-body .input-icons:has([data-grid-control="text-filter"]) { order: -2; }
  .apol-filter-body .de-view-pick { order: -1; }

  /* UNIFORM ROW RHYTHM + FULL WIDTH. .input-icons carries a 14px margin but the
     select pills carry 0, so DE rows and native rows spaced differently. Kill
     the margin, pad each DE row the same, and let a 1px border - the one the
     native filter groups use - do the separating.
     ⚠️ ZERO SIDE PADDING (16px 0, not 16px 20px). The native Sort / View pills
     span the full row width; a side pad here inset the postcode / search /
     Options boxes by 20px so they came out narrower than the selects. Verified
     on the live drawer: with 0 side pad every control is the same 294px. */
  .apol-filter-body .de-near,
  .apol-filter-body .input-icons:has([data-grid-control="text-filter"]),
  .apol-filter-body .de-view-pick {
    margin: 0 !important;
    padding: 16px 0 !important;
    border-bottom: 1px solid var(--apol-color-border, #e9e9e9);
  }

  /* Postcode: field full width to match the search input; the location button
     drops to the line below and fills it - with its label shown so a lone icon
     does not read as empty space. */
  .apol-filter-body .de-near { flex-wrap: wrap; row-gap: 10px; }
  .apol-filter-body .de-near-field { flex: 1 1 100% !important; }
  .apol-filter-body .de-near .de-near-btn { flex: 1 1 auto; width: auto; gap: 8px; }
  .apol-filter-body .de-near-btn-label { display: inline; }

  /* ⚠️ COLOUR REVERSE FOR THE LIGHT PANEL. The distance controls are coloured
     for the DARK desktop bar - white text and border via the App Designer's
     --apol-listing-filterbar-* tokens. On the white sheet/drawer that is
     invisible: the "Use my location" button vanished. Flip to the panel's own
     text/border tokens (still App Designer values, just not the filterbar-white
     ones). Both mobile modes are always light, so a fixed reverse is correct. */
  .apol-filter-body .de-near-btn,
  .apol-filter-body .de-near-clear {
    color: var(--apol-color-text, #222) !important;
    border-color: var(--apol-color-border, #d5d5d5) !important;
  }

  /* The "Showing N nearest first" status is REDUNDANT in the panel and only
     broke up the layout - the Sort row already reads "Nearest first" and the
     footer / apply button already implies the result set. Hidden in both
     modes; it still shows inline on the desktop bar, which has room for it. */
  .apol-filter-body .de-near-status { display: none !important; }
}

/* The card holder, hidden for the views that replace it. A class rather than
   an inline style because apol-grid-size-switcher.js overwrites
   holder.style.display on every re-render; !important to beat the stylesheet's
   own "display: grid !important" on the holder. */
.de-hide-cards { display: none !important; }

/* The distance label on a card. :empty rather than a hidden attribute, so the
   slot takes no space at all until it actually has a value - otherwise every
   card carries the gap whether or not a location was ever shared. */
.de-card-distance {
  display: block;
  font-size: 13px;
  font-weight: 600;
  margin: 2px 0 0;
  color: var(--apol-color-primary, #0099cc);
}
.de-card-distance:empty { display: none; }

/* The numeric sort key. Never shown - it exists only for apolgrid's numeric
   sort to read via textContent, which display:none does not affect. */
.de-dist-key { display: none; }

/* ---- list layout ---------------------------------------------------------
   The SAME cards as the grid, reflowed to full-width rows - so filtering,
   sorting and paging all keep working untouched, and the App Designer's card
   styling still applies. Only the axis changes.
   Scoped to the .de-layout-list class the script puts on the card holder, so
   an ecom category using the same holder is never affected.
   !important on the columns matches the holder's own grid rule, which is
   itself !important - without it the grid template wins and nothing moves.

   ⚠️ SELECTORS ARE DELIBERATELY CLASS-NAME-AGNOSTIC. apol-grid-size-switcher.js
   RENAMES these elements as the visitor changes card size: with "View - Small"
   the holder becomes .data_grid_card_holder_small, the cards become
   .data_grid_card_small, and the image/content divs gain _small too - the base
   class is REMOVED, not added to. Keying on .data_grid_card_holder therefore
   matched nothing at the default size, which is exactly why List first shipped
   looking identical to Grid. .de-layout-list and .de-card survive the rename
   (the switcher only swaps its own four names), so everything hangs off those,
   and the inner boxes are matched on a class SUBSTRING. */
/* gap:0 matters as much as the single column. The holder is a card grid with
   "gap: 32px <x>" - that 32px row gap is the space that made every row look
   over-padded, and no amount of trimming the row's own padding could reach it. */
.de-layout-list {
  grid-template-columns: 1fr !important;
  gap: 0 !important;
}

/* List is a TABLE, not a card. No image, one line per item, columns that line
   up down the page - for scanning twenty events by date and distance, which a
   picture per row actively gets in the way of.

   It is still the same card elements underneath, so filtering, sorting, paging
   and the App Designer's own colours all keep working; only the layout of the
   card's insides changes. */
.de-layout-list .de-card {
  display: block;
  width: 100%;
  /* the card chrome would draw a box round every row */
  padding: 0 !important;
  margin: 0 !important;
  background: transparent !important;
  border: 0 !important;
  border-radius: 0 !important;
}

/* No picture in a table. */
.de-layout-list .de-card > a > [class*="data_grid_card_image"] { display: none !important; }

/* Quick View is an overlay pinned to the corner of a picture. With no picture
   it would hover over the text of every row. */
.de-layout-list .apol-qv-btn { display: none !important; }

/* The anchor is forced to flex/column !important by apol.base.css (so a card
   can pass its height down to the button). Rather than fight that, leave it
   as the row container and put the COLUMNS on the content box inside it. */
/* Vertical padding is deliberately minimal: the row should be as tall as the
   button it contains and no taller, so a long list stays scannable. The
   button's own padding sets the height. */
.de-layout-list .de-card > a {
  width: 100%;
  padding: 2px var(--de-list-pad-x) !important;
  border-bottom: 1px solid var(--apol-color-border, rgba(0, 0, 0, .12));
}
.de-layout-list .de-card > a:hover { background: rgba(0, 0, 0, .025); }

/* THE COLUMNS, DECLARED ONCE. The header row is a sibling of the card holder,
   not a child of it, so it cannot inherit from .de-layout-list - and two
   copies of this track list would drift apart the first time either is
   touched. Hence a custom property both read.
   minmax(0,…) on every flexible track, or a long unbroken title refuses to
   shrink and pushes the later columns off the end. */
:root {
  /* ⚠️ The CTA track is a FIXED width, deliberately not "auto". Auto sizes to
     content - which in the rows is the button, but in the header is an empty
     cell that collapses to zero. The header then had that width to share out
     among its fr tracks, so every header label sat further right than the
     column beneath it. A fixed track is identical in both grids. */
  --de-list-cta: 132px;
  --de-list-cols:
      minmax(0, 2.2fr)      /* title            */
      minmax(0, 1.1fr)      /* date / when      */
      minmax(0, .7fr)       /* distance         */
      minmax(0, 2fr)        /* where + summary  */
      var(--de-list-cta);   /* the CTA          */
  --de-list-gap: 16px;
  --de-list-pad-x: 4px;
  /* Every row is at least this tall, whatever cells it happens to contain.
     Without it a row's height is set by its tallest PRESENT cell, so an item
     with no distance and no location came out a couple of pixels shorter than
     one with both - visible as uneven spacing the moment a location search
     fills some rows and not others. Sized to clear the CTA button. */
  --de-list-row-h: 36px;
}

/* THE ROW. */
.de-layout-list .de-card > a > [class*="data_grid_card_content"] {
  display: grid !important;
  grid-template-columns: var(--de-list-cols);
  align-items: center;
  align-content: center;
  gap: 4px var(--de-list-gap);
  width: 100%;
  /* The card's content box carries its OWN padding and min-height, and both
     differ per size variant - ".data_grid_card_content_small" is padded 10px
     top and bottom with a 160px min-height, the base one with none. Left in
     place they inflate every row and change it whenever the visitor switches
     card size. Cleared, so the height below is the only thing setting it. */
  padding: 0 !important;
  min-height: var(--de-list-row-h);
  height: var(--de-list-row-h);
}

/* EVERY CELL IS PLACED EXPLICITLY. Auto-placement was the original bug and it
   produced three separate-looking faults from one cause: the distance cell
   hides itself when empty, so with no location shared every later cell shifted
   one column left (the address appeared under DISTANCE), and any extra cell
   pushed the button onto a second row - which also made that row taller than
   its neighbours. Named columns mean a missing value leaves its column EMPTY
   instead of moving everything after it.
   grid-row: 1 is the belt to that braces: nothing can ever start a second row,
   whatever future markup the card gains. */
/* ⚠️ A WHITELIST, and it has to be. The five cells below are placed by hand,
   so ANY other direct child of the content box is auto-placed - and with
   columns 1-5 already taken it lands in an implicit SIXTH column. That column
   is 0px wide and invisible, but it still takes a column-gap, and those 16px
   come off the fr tracks: every row column ends up fractionally narrower than
   the header's, which reads as the whole row drifting left, by more with each
   column across. Cards carry extra spans depending on the listing type and the
   item's own data, so "which element is it" is the wrong question - nothing
   unlisted may be a grid item at all.
   grid-auto-columns: 0 is the second line of defence if one ever slips past. */
.de-layout-list .de-card > a > [class*="data_grid_card_content"] { grid-auto-columns: 0; }

.de-layout-list [class*="data_grid_card_content"] > * { display: none; grid-row: 1; }

.de-layout-list .data_grid_card_product_name          { display: block; grid-column: 1; }
.de-layout-list [class*="data_grid_card_price"]       { display: block; grid-column: 2; }
.de-layout-list .de-card-distance                     { display: block; grid-column: 3; }
.de-layout-list [class*="data_grid_card_description"] { display: block; grid-column: 4; }
.de-layout-list .viewproduct_button_link              { display: block; grid-column: 5; }

/* Re-stated AFTER the whitelist turns it back on, and more specific, so an
   empty distance still takes no cell. */
.de-layout-list .de-card-distance:empty { display: none; }

/* An item can carry BOTH a price and a date - they are two spans sharing the
   class, and they would then occupy the same cell and overlap. In a table of
   events the date is what the column is scanned by, so the price gives way;
   where there is no date, the price keeps the column (and the header names
   itself accordingly - see showListHead). */
.de-layout-list [class*="data_grid_card_price"]:not(.de-card-when):has(~ .de-card-when) {
  display: none !important;
}

/* The header row. Same tracks, same gap, same horizontal padding as the rows
   below it - that is what makes the columns line up. */
.de-list-head {
  display: grid;
  grid-template-columns: var(--de-list-cols);
  gap: var(--de-list-gap);
  align-items: center;
  padding: 0 var(--de-list-pad-x) 6px;
  border-bottom: 2px solid var(--apol-color-border, rgba(0, 0, 0, .18));
  font-size: 12px;
  font-weight: 700;
  letter-spacing: .04em;
  text-transform: uppercase;
  opacity: .65;
}
.de-list-head span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* One line per cell: a table stops being scannable the moment rows differ in
   height. */
.de-layout-list [class*="data_grid_card_content"] > * {
  min-width: 0;
  margin: 0 !important;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  /* one stated line-height for every cell: the card's own type styles differ
     per element, and inheriting them made a row's height depend on which
     cells it happened to have */
  line-height: 1.35 !important;
}

.de-layout-list .data_grid_card_product_name { font-size: 15px !important; font-weight: 600 !important; }
/* the price/date slot is an <h5> inside a <span> in the card markup */
.de-layout-list [class*="data_grid_card_price"],
.de-layout-list [class*="data_grid_card_price"] h5 {
  font-size: 14px !important;
  font-weight: 500 !important;
  display: inline !important;
}
.de-layout-list [class*="data_grid_card_description"] { font-size: 13px; opacity: .8; }
.de-layout-list [class*="data_grid_card_description"] p { margin: 0 !important; display: inline !important; }
.de-layout-list .de-card-distance { font-size: 13px; }

/* The CTA is a full-width block on a card; in a table it is a cell.
   Selector is deliberately over-specific: the App Designer sets width, margin
   and display on .data_grid_card .viewproduct_button_link with !important, and
   at equal specificity that becomes a source-order race this must not lose -
   losing it is what made the button full-width and pushed it onto its own
   line. */
.de-layout-list .de-card .viewproduct_button_link {
  display: inline-block !important;
  width: auto !important;
  margin: 0 !important;
  padding: 7px 14px !important;
  font-size: 13px !important;
  white-space: nowrap;
  justify-self: end;
}

/* Below the point where five columns stop fitting, fall back to a stacked
   block per item - still no image, still compact, just no longer aligned. */
@media (max-width: 860px) {
  /* the columns no longer line up, so a header over them would be a lie */
  .de-list-head { display: none !important; }
  .de-layout-list .de-card > a { padding: 8px var(--de-list-pad-x) !important; }
  .de-layout-list .de-card > a > [class*="data_grid_card_content"] {
    grid-template-columns: 1fr auto;
    gap: 2px 12px;
  }
  /* Release the desktop placement - the explicit columns and the single-row
     rule above would otherwise keep every cell jammed onto one line here. */
  /* rows grow to their content here, so the fixed height must go */
  .de-layout-list .de-card > a > [class*="data_grid_card_content"] {
    min-height: 0;
    height: auto;
    padding: 4px 0 !important;
  }
  .de-layout-list [class*="data_grid_card_content"] > * {
    grid-row: auto;
    grid-column: auto;
    white-space: normal;
  }
  .de-layout-list .data_grid_card_product_name { grid-column: 1 / -1; }
  .de-layout-list [class*="data_grid_card_description"] { grid-column: 1 / -1; }
}

/* ---- hybrid split view: map/calendar beside the list ---------------------
   .de-views (holding the active panel) and the card holder are already
   siblings inside .data_grid_items_all_right; the script adds .de-split there
   and this makes them two columns, with pagination spanning underneath.
   The panel is the wider column - it is the thing you came to the map/calendar
   for; the list is the index beside it. */
.data_grid_items_all_right.de-split {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr);
  gap: 0 24px;
  align-items: start;
}
/* the panel wrapper - override its inline grid-column:1/-1 (set for when it
   sat inside the card grid) so it takes the left column only */
.data_grid_items_all_right.de-split > .de-views { grid-column: 1 !important; grid-row: 1; }
.data_grid_items_all_right.de-split > [class*="data_grid_card_holder"] { grid-column: 2; grid-row: 1; }
.data_grid_items_all_right.de-split > .pagination_holder { grid-column: 1 / -1; grid-row: 2; }

/* The list column is tall content beside a fixed-height panel: cap it to the
   panel and scroll, so the map does not float above a mile of rows. */
.data_grid_items_all_right.de-split > [class*="data_grid_card_holder"] {
  max-height: 560px;
  overflow-y: auto;
}

/* THE NARROW LIST. A half-width column at desktop viewport would still get the
   5-column table (the collapse below keys on VIEWPORT width, not column width)
   and overflow. .de-list-narrow forces the stacked form regardless - the same
   rules as the 860px breakpoint above, triggered by the class instead. */
.de-list-narrow.de-layout-list .de-card > a { padding: 8px var(--de-list-pad-x) !important; }
.de-list-narrow.de-layout-list .de-card > a > [class*="data_grid_card_content"] {
  grid-template-columns: 1fr auto;
  gap: 2px 12px;
  min-height: 0;
  height: auto;
  padding: 4px 0 !important;
}
.de-list-narrow.de-layout-list [class*="data_grid_card_content"] > * {
  grid-row: auto;
  grid-column: auto;
  white-space: normal;
}
.de-list-narrow.de-layout-list .data_grid_card_product_name { grid-column: 1 / -1; }
.de-list-narrow.de-layout-list [class*="data_grid_card_description"] { grid-column: 1 / -1; }

/* The row picked from the map or the calendar. A left brand-colour bar plus a
   tint, so it reads as "this one" without recolouring the whole row. Scoped to
   the list layout: in a grid it would be an odd stripe across a card. */
.de-layout-list .de-card.de-selected > a {
  background: var(--apol-color-primary-tint, rgba(0, 153, 204, .1));
  box-shadow: inset 3px 0 0 0 var(--apol-color-primary, #0099cc);
}

/* On a phone the split cannot hold two columns - stack the panel over the
   list, and let the list find its own height again. */
@media (max-width: 760px) {
  .data_grid_items_all_right.de-split { grid-template-columns: 1fr; }
  .data_grid_items_all_right.de-split > .de-views,
  .data_grid_items_all_right.de-split > [class*="data_grid_card_holder"] { grid-column: 1; }
  .data_grid_items_all_right.de-split > [class*="data_grid_card_holder"] {
    grid-row: auto;
    max-height: none;
    overflow: visible;
  }
}

/* ---- map -----------------------------------------------------------------
   ONE fixed height at every width, deliberately NOT a viewport unit. dvh was
   tried and reverted: the "d" is dynamic, so it tracks the mobile address bar
   collapsing and the map visibly jumps taller mid-scroll. svh would hold still
   but then wastes the space the address bar frees up. A plain px height is
   stable everywhere and tall enough to be worth showing. */
.de-map { width: 100%; height: 560px; }

.de-map-info { font-size: 14px; line-height: 1.4; }
.de-map-info strong { display: block; margin-bottom: 2px; }
.de-map-info a { display: inline-block; margin-top: 6px; }

/* ---- calendar ------------------------------------------------------------ */
.de-cal { display: block; }

.de-cal-nav {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 18px;
  margin: 0 0 14px;
}
.de-cal-label { font-size: 17px; font-weight: 600; min-width: 11em; text-align: center; }

.de-cal-arrow {
  font: inherit;
  font-size: 16px;
  line-height: 1;
  width: 38px;
  height: 38px;
  /* fixed basis: in a flex row these otherwise get squashed out of round on
     narrow screens */
  flex: 0 0 38px;
  padding: 0;
  cursor: pointer;
  border-radius: 50%;
  color: var(--apol-color-primary-contrast, #fff);
  background: var(--apol-color-primary, #0099cc);
  border: 0;
}
.de-cal-arrow:hover { filter: brightness(1.08); }
.de-cal-arrow[disabled] { opacity: .32; cursor: default; filter: none; }
.de-cal-arrow:focus-visible { outline: 2px solid currentColor; outline-offset: 2px; }

/* The month area is drag/swipe-able, so suppress the browser's own horizontal
   pan and text selection while dragging across it. pan-y keeps VERTICAL
   scrolling with the page - only the horizontal axis is claimed. */
.de-cal-month { touch-action: pan-y; }

/* ---- month carousel ------------------------------------------------------
   The track is what Flickity is built on (its viewport/slider wrappers come
   from the shared rules in apol.base.css). Each month is one full-width cell,
   so a drag follows the finger and settles on a month boundary.
   The width MUST be stated here: Flickity absolutely positions its cells, and
   an unstated width would collapse each month to its content. */
.de-cal-track { width: 100%; }
.de-cal-month { width: 100%; }

/* NB deliberately NO ".de-cal-track:not(.flickity-enabled) .de-cal-month
   { display:none }" rule here. It looks like a sensible guard against the
   months flashing stacked, but it would hide the cells WHILE the carousel is
   being constructed - reintroducing the zero-width measurement bug from the
   other direction, and only when Flickity happens to add its class late.
   No guard is needed: the script clears the inline display and constructs the
   carousel in one synchronous turn, so the browser never paints between them.

   Flickity puts the grab cursor on the viewport; on a calendar the pointer is
   mostly over event links, where a text cursor reads as "not draggable". */
.de-cal-track.flickity-enabled .de-cal-day { cursor: inherit; }

.de-cal-grid { display: grid; grid-template-columns: repeat(7, 1fr); gap: 4px; }

.de-cal-wd {
  font-size: 11px;
  letter-spacing: .06em;
  text-transform: uppercase;
  opacity: .6;
  padding: 4px 2px;
  text-align: center;
}

.de-cal-day {
  min-height: 88px;
  padding: 5px 6px;
  border: 1px solid rgba(0, 0, 0, .1);
  border-radius: 3px;
}
.de-cal-day.has-events { background: rgba(0, 0, 0, .03); }

/* Days belonging to the neighbouring months. Shown so the grid is always a
   complete rectangle, but greyed back so they read as context, not content. */
.de-cal-day.is-outside { background: rgba(0, 0, 0, .015); border-color: rgba(0, 0, 0, .05); }
.de-cal-day.is-outside .de-cal-num { opacity: .3; }
.de-cal-day.is-today { border-color: var(--apol-color-primary, #0099cc); border-width: 2px; }

.de-cal-num { display: block; font-size: 12px; opacity: .55; }

/* Stated per-cell so a narrow screen can drop the 7-column header and still
   say which day each cell is. Hidden on desktop, where the header does that. */
.de-cal-dow { display: none; }

.de-cal-ev {
  display: block;
  margin-top: 4px;
  font-size: 12px;
  line-height: 1.3;
  text-decoration: none;
  overflow-wrap: anywhere;
  color: var(--apol-color-primary, #0099cc);
  font-weight: 600;
}
.de-cal-ev:hover { text-decoration: underline; }

/* On a phone the month becomes one column - but EVERY day is still listed, with
   its weekday named in the cell, so nothing is lost compared with the desktop
   grid; it is just laid out differently. */
@media (max-width: 640px) {
  .de-cal-grid { grid-template-columns: 1fr; gap: 0; }
  .de-cal-wd { display: none; }

  /* The padding days exist to square off the desktop grid. In a one-per-row
     list they would just be confusing duplicates of the next month. */
  .de-cal-day.is-outside { display: none; }

  .de-cal-day {
    min-height: 0;
    display: flex;
    flex-wrap: nowrap;
    align-items: baseline;
    gap: 0 10px;
    border: 0;
    border-bottom: 1px solid rgba(0, 0, 0, .1);
    border-radius: 0;
    padding: 9px 4px;
  }
  .de-cal-day.is-today { background: rgba(0, 0, 0, .04); }

  .de-cal-dow { display: inline; flex: 0 0 auto; min-width: 5.5em; font-size: 12px; opacity: .55; }
  .de-cal-num { display: inline; flex: 0 0 auto; min-width: 1.5em; font-size: 15px; font-weight: 600; opacity: 1; }

  /* Events run on from the date number on the SAME line. Because they sit in
     their own block, a long title wraps inside that block - so the second line
     starts under the first event, not back at the left margin. */
  .de-cal-evs { flex: 1 1 auto; min-width: 0; }
  .de-cal-ev { margin-top: 0; font-size: 13px; }
  .de-cal-ev + .de-cal-ev { margin-top: 3px; }
}

/* ---- the shared OVERVIEW -------------------------------------------------
   One appearance for both hosts: inside the map's info window, and inside the
   .de-ov-pop panel the calendar anchors to a clicked entry. Everything here
   styles .de-ov itself, so the two hosts cannot drift apart. */
.de-ov { font-size: 14px; line-height: 1.45; max-width: 300px; }

.de-ov-img {
  margin: 0 0 8px;
  /* fixed ratio: item images vary wildly and an unconstrained one makes the
     panel jump about as different pins are opened */
  aspect-ratio: 16 / 9;
  overflow: hidden;
  border-radius: 4px;
}
.de-ov-img img { width: 100%; height: 100%; object-fit: cover; display: block; }

.de-ov-title { font-weight: 700; font-size: 15px; margin: 0 0 3px; }
.de-ov-when,
.de-ov-where { opacity: .8; font-size: 13px; }
.de-ov-dist { font-weight: 600; font-size: 13px; color: var(--apol-color-primary, #0099cc); }

.de-ov-desc {
  margin: 6px 0 0;
  font-size: 13px;
  opacity: .85;
  /* it is a preview, not the page - keep it to a glance */
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.de-ov-cta {
  display: inline-block;
  margin: 10px 0 0;
  padding: 8px 14px;
  border-radius: 4px;
  font-size: 13px;
  font-weight: 600;
  text-decoration: none;
  color: var(--apol-color-primary-contrast, #fff);
  background: var(--apol-color-primary, #0099cc);
}
.de-ov-cta:hover { filter: brightness(1.08); }

/* the calendar's host panel */
.de-ov-pop {
  display: none;
  position: absolute;
  z-index: 10000;
  padding: 14px;
  border-radius: 6px;
  background: #fff;
  color: #222;
  box-shadow: 0 6px 24px rgba(0, 0, 0, .26);
}
.de-ov-close {
  position: absolute;
  top: 4px;
  right: 6px;
  font: inherit;
  font-size: 20px;
  line-height: 1;
  padding: 2px 6px;
  cursor: pointer;
  border: 0;
  background: transparent;
  color: inherit;
  opacity: .55;
}
.de-ov-close:hover { opacity: 1; }

/* ---- map view: cards under the map ---------------------------------------
   The map panel and the card holder are siblings, the panel first, so the
   cards already fall underneath. This only stops the map running the full
   height of a tall screen and pushing every card below the fold. */
.de-view-panel[data-de-panel="map"] { margin: 0 0 24px; }

/* ---- calendar tooltip ---------------------------------------------------- */
.de-tip {
  display: none;
  position: absolute;
  z-index: 9999;
  max-width: 280px;
  padding: 9px 12px;
  border-radius: 5px;
  background: #222;
  color: #fff;
  font-size: 13px;
  line-height: 1.45;
  box-shadow: 0 4px 14px rgba(0, 0, 0, .22);
  pointer-events: none;   /* never let it swallow the click on the event */
}
.de-tip strong { display: block; margin-bottom: 3px; }
.de-tip span { display: block; opacity: .85; }
