/**
 * @file
 * Event card.
 *
 * Old markup: .detail > .article_image + .info > .time / .title / .category,
 * positioned by Isotope with images of arbitrary aspect ratio. New card keeps
 * exactly the same fields (image, date/time, title, genre tags, booking status)
 * and adds the venue and price, which the old card dropped even though both are
 * on the node — visitors had to open every event to find out where it was and
 * whether it cost anything.
 *
 * The whole card is clickable via a stretched link on the title, so screen
 * readers get one meaningful link rather than three duplicates.
 */

/**
 * THE CARD
 *
 * Cards in a grid row stretch to the tallest one. With the footer pushed down
 * by `margin-block-start: auto`, a card whose title runs to one line ended up
 * with a large hole between the venue and the tags — the "stretched" look.
 *
 * The fix is not to stop stretching (ragged rows look accidental) but to make
 * the space read as structure: the body's content stays packed at the top, and
 * the footer sits against a hairline rule at the bottom. Equal heights, tidy
 * grid, no floating gap.
 */
.event-card {
  position: relative;
  display: flex;
  flex-direction: column;
  isolation: isolate;
  /* The whole card is one target (the title carries a stretched link), so it
     should say so on approach rather than only under the title itself. */
  cursor: pointer;

  /*
   * THE ARTWORK'S OWN COLOUR, AT THE FOOT OF THE CARD.
   *
   * `--card-c1` is set inline by the card template from the two colours GD read
   * out of the event's photograph — the same pair the event page's hero and
   * panel headings use. A listing of twenty events was twenty identical navy
   * rectangles under twenty different pictures; this lets the programme supply
   * the colour instead of the theme, so February looks different from October
   * without anybody editing a stylesheet.
   *
   * QUIET ON PURPOSE. `--card-wash` of a colour that has already been pulled
   * into a dark band, fading out by 45% of the card's height, lands within a
   * shade or two of --card-bg. It reads as the picture's light continuing past
   * its own edge rather than as a coloured card, and it stays under the body
   * text, the venue and the price — none of which sit on it strongly enough to
   * move their contrast ratios. Above that the card is --card-bg exactly, which
   * is where the title is. The strength is a token so it can be tuned, or set
   * to 0% to turn the treatment off site-wide; see css/base/tokens.css.
   *
   * WITHOUT A PALETTE IT IS NOTHING. `--card-tint` defaults to
   * `transparent`, and a colour-mix with transparent is transparent, so the
   * gradient paints nothing at all and the card is --card-bg — exactly what it
   * was before. Events with no artwork, unreadable files and cards beyond the
   * per-request palette budget all take that path.
   */
  background:
    linear-gradient(
      to top,
      color-mix(in oklab, var(--card-tint) var(--card-wash), transparent) 0%,
      transparent 45%
    ),
    var(--card-bg);
  border: 1px solid var(--card-border);
  border-radius: var(--card-radius);
  overflow: hidden;
  /* A card is an object before you touch it. Resting elevation, so the grid
     reads as a tray of cards rather than as flat colour blocks — and so the
     light palette, where card and canvas are a hair apart, still shows edges. */
  box-shadow: var(--lift-rest-shadow);
  transition:
    transform var(--duration-base) var(--ease-out),
    border-color var(--duration-base) var(--ease-out),
    box-shadow var(--duration-base) var(--ease-out);
}

/**
 * Hover.
 *
 * Four things move together, all cheap to composite: the card lifts, the
 * border warms to the brand magenta, a shadow tinted with the same magenta
 * appears beneath it, and the image drifts in slightly. Nothing reflows —
 * transform and opacity only — so a grid of thirty cards stays smooth.
 */
/* The lift only. The rim — border colour, ring and glow — is stated once in
   card-hover.css so this card and the hub card cannot drift apart. */
.event-card:hover {
  transform: translateY(var(--lift));
}

.event-card:focus-within {
  outline: var(--focus-ring);
  outline-offset: var(--focus-offset);
}

/* Media */
.event-card__media {
  position: relative;
  background: var(--surface-2);
  overflow: hidden;
}

/**
 * Drupal renders an image field as any of <img>, <a><img>, <picture><img>, or
 * a field wrapper around one of those. The wrappers are neutralised so the
 * <img> itself is what carries the ratio, whatever the field settings are.
 */
.event-card__media a,
.event-card__media picture,
.event-card__media .field,
.event-card__media .field__item {
  display: block;
  inline-size: 100%;
  block-size: 100%;
}

.event-card__media img {
  display: block;
  inline-size: 100%;
  block-size: auto;
  aspect-ratio: var(--card-media-ratio);
  /*
   * `cover` by default — see --card-media-fit in tokens.css. The ratio above
   * matches what the image style serves, so there is nothing to crop; cover is
   * what guarantees the picture reaches the card's top, left and right edges
   * whatever arrives.
   */
  object-fit: var(--card-media-fit, cover);
  object-position: center;
  transition: scale var(--duration-slow) var(--ease-out);
}

.event-card:hover .event-card__media img {
  scale: 1.05;
}

/* A soft scrim under the medallion so a pale photograph never swallows it. */
.event-card__media::after {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  block-size: 45%;
  background: linear-gradient(to bottom, rgb(0 0 0 / 42%), transparent);
  pointer-events: none;
}

/**
 * "View event" cue.
 *
 * The lift and the glow say *something* is interactive; this says what will
 * happen. It rides in from the right on hover and on keyboard focus, and is
 * hidden from assistive technology, which already has the title's real link.
 */
.event-card__cue {
  position: absolute;
  z-index: 2;
  inset-block-end: var(--space-2xs);
  inset-inline-end: var(--space-2xs);
  display: inline-flex;
  align-items: center;
  gap: var(--space-3xs);
  padding: 0.35rem var(--space-2xs);
  border-radius: var(--radius-pill);
  background: var(--accent-solid);
  color: var(--me-white);
  font-size: var(--step--2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0;
  translate: 0.5rem 0;
  transition:
    opacity var(--duration-base) var(--ease-out),
    translate var(--duration-base) var(--ease-out);
  pointer-events: none;
}

.event-card:hover .event-card__cue,
.event-card:focus-within .event-card__cue {
  opacity: 1;
  translate: 0 0;
}

@media (prefers-reduced-motion: reduce) {
  .event-card__cue {
    translate: 0 0;
  }
}

/**
 * Cards with no image.
 *
 * Several live events have no article image. The media block always renders so
 * those cards keep their date medallion; without a picture it becomes a short
 * accent panel rather than a missing block.
 */
.event-card__media-placeholder {
  aspect-ratio: 5 / 2;
  min-block-size: 4.5rem;
  background:
    linear-gradient(
      135deg,
      color-mix(in srgb, var(--me-magenta) 26%, transparent) 0%,
      var(--surface-2) 70%
    );
}

.event-card--row .event-card__media-placeholder {
  block-size: 100%;
  aspect-ratio: auto;
  min-block-size: 100%;
}

/* Date medallion — the date is what people scan a listing for. */
.event-card__date {
  position: absolute;
  z-index: 2;
  inset-block-start: var(--space-2xs);
  inset-inline-start: var(--space-2xs);
  display: grid;
  place-items: center;
  gap: 0;
  min-inline-size: 3.1rem;
  padding: var(--space-3xs) var(--space-2xs) 0.35rem;
  border-radius: var(--radius-s);
  /*
   * NO backdrop-filter.
   *
   * This was `blur(8px)`, and it is the single most repeated element on the
   * site: one per card, so a full listing carried fifty-odd blur layers. Each
   * one is its own compositing layer that the browser re-samples as the page
   * moves, and scrolling a grid of them under a header that is ALSO
   * backdrop-filtered is what made the top of the page flicker.
   *
   * The medallion sits on a photograph and was already 74% black. At 82% it
   * reads the same and costs nothing to scroll.
   */
  background: color-mix(in srgb, var(--me-black) 82%, transparent);
  color: var(--me-white);
  text-align: center;
  line-height: 1.05;
}

.event-card__date-dow {
  font-size: var(--step--2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--me-magenta-300);
}

.event-card__date-day {
  font-size: var(--step-2);
  font-weight: var(--weight-black);
  font-variant-numeric: tabular-nums;
}

.event-card__date-month {
  font-size: var(--step--2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

/* Multi-day / recurring events show a range instead of a single day. */
.event-card__date--range .event-card__date-day {
  font-size: var(--step-0);
}

/* A date the view printed as text, when no parsed date was available. */
.event-card__date--text {
  min-inline-size: 0;
  padding: var(--space-3xs) var(--space-2xs);
  font-size: var(--step--2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  color: var(--me-magenta-300);
}

/* Booking status flag — carried over from .booking-status. */
.event-card__status {
  position: absolute;
  z-index: 2;
  inset-block-start: var(--space-2xs);
  inset-inline-end: var(--space-2xs);
  padding: 0.3rem var(--space-2xs);
  border-radius: var(--radius-xs);
  background: var(--accent-solid);
  color: var(--me-white);
  font-size: var(--step--2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
}

/* Status flags carry white or near-black labels only — a flag is small, bold
   and load-bearing, so it gets the highest contrast the palette allows. */
.event-card__status--waitlist { background: var(--me-warning); color: var(--me-navy-deep); }
.event-card__status--soldout,
.event-card__status--fully-booked { background: var(--surface-well); color: var(--me-white); }
.event-card__status--cancelled { background: var(--me-error); color: var(--me-navy-deep); }

/* Body — content packed at the top, footer against the bottom rule. */
.event-card__body {
  display: flex;
  flex-direction: column;
  gap: var(--space-3xs);
  flex: 1;
  padding: var(--space-s) var(--space-s) 0;
}

.event-card__time {
  color: var(--text-secondary);
  font-size: var(--step--2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  font-variant-numeric: tabular-nums;
}

.event-card__title {
  font-size: var(--step-1);
  line-height: var(--leading-snug);
  letter-spacing: -0.015em;
  margin-block: 0.15rem var(--space-xs);
}

.event-card__title a {
  color: var(--text-primary);
  text-decoration: none;
  background-image: linear-gradient(var(--me-magenta-300), var(--me-magenta-300));
  background-repeat: no-repeat;
  background-position: 0 100%;
  background-size: 0 1.5px;
  transition:
    background-size var(--duration-base) var(--ease-out),
    color var(--duration-fast) var(--ease-out);
}

/* Stretched link: the anchor covers the card without nesting interactive
   elements. Real links inside the card (genre tags) are lifted above it. */
.event-card__title a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 1;
}

/* The underline sweeps in from the left on hover — a small, precise signal
   that the whole card is one target. */
.event-card:hover .event-card__title a {
  color: var(--me-magenta-300);
  background-size: 100% 1.5px;
}

/**
 * Footer.
 *
 * `margin-block-start: auto` pins it to the bottom of a stretched card, and the
 * hairline above it turns the leftover space into a deliberate gap between the
 * event's details and its tags rather than an accidental hole.
 */
.event-card__footer {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-2xs);
  margin-block-start: auto;
  padding: var(--space-xs) var(--space-s);
  margin-inline: calc(var(--space-s) * -1);
  border-block-start: 1px solid var(--border-subtle);
}

/**
 * Genre labels.
 *
 * Soft, the way the outgoing site had them: small, uppercase, letter-spaced and
 * muted, so they read as a quiet classification under the title rather than
 * competing with it. They were rendering as full-strength magenta underlined
 * links, which made every card look like it had three headlines.
 *
 * `font-size: 0` on the container is deliberate. Views separates the terms with
 * runs of `&nbsp;` that the theme cannot remove; zeroing the container collapses
 * those to nothing, and each link restores its own size. It also means the same
 * rule works for the <ul><li> markup the node teaser emits and the bare <a> list
 * the views field emits.
 */
.event-card__tags {
  position: relative;
  z-index: 2;
  font-size: 0;
  list-style: none;
  margin: 0;
  padding: 0;
  /* Give way to the price rather than push it out of the card. The labels wrap
     at their own spaces, which is fine — a second line of genre labels is
     tidy, a price hanging over the edge is not. */
  min-inline-size: 0;
  flex: 0 1 auto;
}

.event-card__tags li {
  display: inline;
}

.event-card__tags a {
  display: inline-block;
  border: 0;
  padding: 0;
  background: none;
  color: var(--text-muted);
  font-size: var(--step--2);
  font-weight: var(--weight-bold);
  letter-spacing: var(--tracking-wide);
  text-transform: uppercase;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--duration-fast) var(--ease-out);
}

.event-card__tags a:hover {
  color: var(--me-magenta-300);
}

/**
 * Spacing goes on the direct children, not on the links.
 *
 * `a:last-child` matched EVERY link when the markup is <li><a>, because each
 * link is the only child of its own <li> — so every gap collapsed and the
 * labels ran together as "MARKETS & FAIRSFOOD & DRINK". Targeting the row's own
 * children works for both shapes: <li> from the node teaser, bare <a> from the
 * views field.
 */
.event-card__tags > * {
  margin-inline-end: var(--space-s);
}

.event-card__tags > *:last-child {
  margin-inline-end: 0;
}

/**
 * The price, and the belt-and-braces that stop it leaving the card.
 *
 * `white-space: nowrap` is what a price wants — "$20 - $25" broken over two
 * lines reads as two prices — and it is also what broke the card. A nowrap flex
 * item has a min-content width as wide as its whole string, and a flex item
 * will not shrink below that, so an editor's full fee schedule pushed itself
 * out through the side of the card and was chopped mid-word.
 *
 * `min-inline-size: 0` is the line that actually fixes it: it lets the item
 * shrink past its min-content width, at which point `overflow: hidden` and
 * `text-overflow: ellipsis` have something to do. The label is shortened in PHP
 * first (see _mosman_events_2026_cost_short()), so in practice the ellipsis
 * only ever catches a long label with no dollar amount in it to summarise.
 */
.event-card__price {
  font-size: var(--step--1);
  font-weight: var(--weight-bold);
  color: var(--text-primary);
  white-space: nowrap;
  margin-inline-start: auto;
  min-inline-size: 0;
  max-inline-size: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.event-card__price--free {
  color: var(--me-success);
}

/* Feature variant — the first card on the landing grid. */
@media (min-width: 64rem) {
  .event-card--feature {
    display: grid;
    grid-template-rows: 1fr auto;
  }

  .event-card--feature .event-card__media img {
    aspect-ratio: auto;
    block-size: 100%;
    min-block-size: 18rem;
  }

  .event-card--feature .event-card__title {
    font-size: var(--step-3);
  }

  .event-card--feature .event-card__body {
    gap: var(--space-xs);
    padding: var(--space-m);
  }
}

/* Row variant — search results and taxonomy listings. */
.event-card--row {
  flex-direction: row;
  align-items: stretch;
}

.event-card--row .event-card__media {
  flex: none;
  inline-size: clamp(6.5rem, 26vw, 13rem);
}

.event-card--row .event-card__media img {
  block-size: 100%;
  aspect-ratio: auto;
  min-block-size: 100%;
}

.event-card--row .event-card__date {
  inset-block-start: var(--space-3xs);
  inset-inline-start: var(--space-3xs);
  min-inline-size: 2.75rem;
  padding: 2px var(--space-3xs) var(--space-3xs);
}

.event-card--row .event-card__date-day {
  font-size: var(--step-1);
}

/* Compact variant — sidebar "related events" rail. */
.event-card--compact .event-card__body {
  padding: var(--space-xs);
  gap: var(--space-3xs);
}

.event-card--compact .event-card__title {
  font-size: var(--step-0);
}

.event-card--compact .event-card__tags {
  display: none;
}
