/* GigGuide photos (design lane, 18 Oct 2026).
   Loaded on every page, after site-polish.css.

   The rules:
   1. A photo is never cut more than a little. When its shape is far from its
      box (a square poster in a wide card, a tall photo, a very wide banner),
      the whole photo shows on a soft blurred copy of itself.
   2. When a photo is cropped, the top is kept, where faces usually are.
      A photo can point somewhere else with the focus classes at the end.
   3. Tour and artist pages lead with a big photo, never cropped.

   Views add .photo-frame and one shape class to the box around the photo
   (partials/photo-shape.blade.php), and an img.photo-backdrop after the
   photo (partials/photo-backdrop.blade.php).

   Shape classes, from the photo's width divided by its height:
   .photo-portrait under 0.9, .photo-square 0.9 to 1.15, .photo-43 1.15 to
   1.45, .photo-169 1.45 to 1.95, .photo-wide 1.95 and over.
   ".photo-frame.photo-frame" repeats the class on purpose, to win over older
   rules such as "body #main .whats-on-pick-grid .card-art img". The featured
   strip sits outside #main on some pages, hence ":is(#main, .featured-strip)". */

/* 1. The box and the blurred copy */

.photo-frame {
  position: relative;
  isolation: isolate;
  overflow: hidden;
}

body :is(#main, .featured-strip) .photo-frame.photo-frame > img.photo-backdrop {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  margin: 0;
  padding: 0;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  aspect-ratio: auto;
  object-fit: cover;
  object-position: 50% 50%;
  filter: blur(24px) saturate(1.15) brightness(0.6);
  transform: scale(1.2);
  pointer-events: none;
}

/* 2. Whole photo when its shape is far from the box */

body :is(#main, .featured-strip) .photo-frame.photo-frame:is(.photo-portrait, .photo-square, .photo-wide) > img:not(.photo-backdrop) {
  object-fit: contain;
  object-position: 50% 50%;
}

/* A photo shown whole has see-through space around it, so the blurred copy
   must not be hidden behind the photo's own placeholder colour. */
body :is(#main, .featured-strip) .photo-frame.photo-frame > img:not(.photo-backdrop) {
  background: transparent;
}

/* Experience cards are 4:3, so a square photo only loses a little. */
body #main .experience-image.photo-frame.photo-square > img:not(.photo-backdrop) {
  object-fit: cover;
  object-position: var(--photo-x, 50%) var(--photo-y, 25%);
}

/* Wide boxes: a 4:3 photo would lose a third, so it shows whole. */
body #main :is(.news-photo, .experience-gallery-hero .photo-frame).photo-frame.photo-43 > img:not(.photo-backdrop) {
  object-fit: contain;
  object-position: 50% 50%;
}

/* The festival poster box is square, so wide photos show whole. */
body #main .festival-art.photo-frame:is(.photo-43, .photo-169) > img:not(.photo-backdrop) {
  object-fit: contain;
  object-position: 50% 50%;
}

/* Search result rows: small square photos are always cropped, no copy. */
body #main .gig-result .photo-frame.photo-frame > img:not(.photo-backdrop) {
  object-fit: cover;
  object-position: var(--photo-x, 50%) var(--photo-y, 25%);
}

body #main .gig-result .photo-frame.photo-frame > img.photo-backdrop {
  display: none;
}

/* 3. Cropped photos keep the top */

.featured-photo > img,
.card-art .gig-photo > img,
.gig-result > .gig-photo > img,
.page-home #main .festival-cards .card-art > img,
#main .experience-image > img,
#main .experience-gallery > .experience-gallery-item img,
#main .whats-on-experience-pick > .whats-on-pick-photo img,
.place-experience-grid figure > img,
.night-out-photo > img,
.news-item-media > img,
.suggestion-icon img.suggestion-photo {
  object-position: var(--photo-x, 50%) var(--photo-y, 25%);
}

/* Cards with no photo on the home page show the category name, like
   everywhere else (it was hidden there, leaving a faint icon only). */

.page-home #main .festival-cards .card-art .event-art:not([hidden]) {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 10px;
}

.page-home #main .festival-cards .card-art .event-art img {
  width: 28px;
  height: 28px;
  opacity: 0.9;
}

.page-home #main .festival-cards .card-art .event-art span {
  display: block;
  color: var(--gg-text);
  font: 700 13px/1 var(--gg-font-display);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}

/* Tour news stories with no photo: the act's name on the poster, so the big
   first story doesn't show an empty box with a faint icon. */

#main .news-poster {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 14px;
  padding: 16px;
  text-align: center;
}

#main .news-poster img {
  opacity: 0.8;
}

#main .news-poster .news-poster-name {
  display: block;
  max-width: 16ch;
  color: var(--gg-text-1);
  font: 700 clamp(26px, 3.4vw, 44px)/1.05 var(--gg-font-display);
  letter-spacing: -0.02em;
  overflow-wrap: anywhere;
  text-wrap: balance;
}

#main .news-item:not(.news-item-lead) .news-poster {
  gap: 8px;
  padding: 10px;
}

#main .news-item:not(.news-item-lead) .news-poster img {
  width: 24px;
  height: 24px;
}

#main .news-item:not(.news-item-lead) .news-poster .news-poster-name {
  display: -webkit-box;
  overflow: hidden;
  font-size: 15px;
  line-height: 1.15;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
}

@media (max-width: 999px) {
  #main .news-item:not(.news-item-lead) .news-poster {
    padding: 6px;
  }

  #main .news-item:not(.news-item-lead) .news-poster img {
    display: none;
  }

  #main .news-item:not(.news-item-lead) .news-poster .news-poster-name {
    font-size: 13px;
  }
}

/* 4. Gig page: the whole photo, up to 480px tall, on its blurred copy.
   Before, the box stopped at 480px but the photo could be 600px, so square
   posters lost their bottom. */

@media (min-width: 900px) {
  body.page-gig .event-story > .gig-photo > img:not(.photo-backdrop) {
    max-height: 480px;
  }
}

/* 5. City pages: things to do get a normal wide photo, not a thin strip */

body #main .place-experience-grid figure > img:not(.photo-backdrop) {
  height: auto;
  aspect-ratio: 16 / 9;
}

body #main .place-experience-grid .photo-frame.photo-frame > img.photo-backdrop {
  bottom: auto;
  height: auto;
  aspect-ratio: 16 / 9;
}

/* Boxes with a photo credit below the photo: the blurred copy only fills the
   photo's own box, with its rounded corners. */

body #main .news-photo.photo-frame.photo-frame > img.photo-backdrop {
  bottom: auto;
  height: auto;
  aspect-ratio: 16 / 9;
  border-radius: var(--gg-radius);
}

body #main .festival-art.photo-frame.photo-frame > img.photo-backdrop {
  bottom: auto;
  height: auto;
  aspect-ratio: 1 / 1;
  border-radius: var(--gg-radius);
}

body #main .night-out-photo.photo-frame.photo-frame > img.photo-backdrop {
  bottom: auto;
  height: 128px;
}

body #main :is(.news-photo, .festival-art).photo-frame {
  border-radius: var(--gg-radius);
}

body #main .night-out-photo.photo-frame {
  border-radius: var(--gg-radius-xs);
}

/* A credit under the photo sits on the card or page colour, so the blurred
   copy (slightly enlarged to hide its soft edges) never shows behind it. */

body #main .place-experience-grid .photo-frame > figcaption {
  position: relative;
  background: var(--gg-surface);
}

body #main .news-photo.photo-frame > figcaption,
body #main .festival-art.photo-frame > .festival-art-credit {
  position: relative;
  margin-top: 0;
  padding-top: 8px;
  background: var(--gg-bg);
}

body #main .night-out-photo.photo-frame > figcaption {
  position: relative;
  margin-top: 0;
  padding-top: 4px;
  background: var(--gg-surface);
}

/* Top 10 picks on experience pages */

.category-pick-photo {
  display: block;
}

body #main .category-pick-photo > img:not(.photo-backdrop) {
  display: block;
  height: auto;
  aspect-ratio: 16 / 9;
}

/* 6. Tour and artist pages: the big photo heading */

.photo-hero {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  border: 1px solid var(--gg-border);
  border-radius: var(--gg-radius-lg);
  background: var(--gg-surface);
}

.act-heading.photo-hero {
  min-height: 380px;
  margin-bottom: 8px;
  padding: 40px;
  gap: 48px;
}

.artist-heading.photo-hero {
  padding: 40px;
}

.artist-heading.photo-hero > div {
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: 48px;
  min-height: 300px;
}

.photo-hero-backdrop {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: block;
  overflow: hidden;
  pointer-events: none;
}

.photo-hero-backdrop > img {
  display: block;
  width: 100%;
  height: 100%;
  max-width: none;
  max-height: none;
  object-fit: cover;
  filter: blur(40px) saturate(1.2);
  transform: scale(1.25);
  opacity: 0.6;
}

.photo-hero-backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  background: linear-gradient(90deg,
    color-mix(in srgb, var(--gg-bg) 94%, transparent) 0%,
    color-mix(in srgb, var(--gg-bg) 78%, transparent) 45%,
    color-mix(in srgb, var(--gg-bg) 30%, transparent) 100%);
}

.photo-hero .photo-hero-media {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: flex-end;
  order: 2;
  width: min(48%, 580px);
  margin: 0;
  container-type: inline-size;
}

.photo-hero .photo-hero-media > img {
  display: block;
  width: 100%;
  max-width: 100%;
  height: auto;
  max-height: 420px;
  object-fit: contain;
  border-radius: var(--gg-radius);
  background: none;
  box-shadow: 0 24px 60px rgba(0, 0, 0, 0.45);
}

/* Square and tall photos are sized by height, so they don't fill the width
   with empty space. The width and height on the img keep the space while it
   loads, so nothing moves. The cqw caps keep the photo inside the box when
   the box is narrow (tablets), so it never gets empty bands. */
.photo-hero .photo-hero-media:is(.photo-square, .photo-portrait) > img {
  width: auto;
  height: 420px;
}

.photo-hero .photo-hero-media.photo-square > img {
  height: min(420px, 87cqw);
}

.photo-hero .photo-hero-media.photo-portrait > img {
  height: min(420px, 111cqw);
}

.photo-hero .photo-hero-media > figcaption {
  max-width: 100%;
  margin-top: 8px;
  padding: 3px 8px;
  border-radius: var(--gg-radius-xs);
  background: color-mix(in srgb, var(--gg-bg) 85%, transparent);
  color: var(--gg-text-2);
  text-align: right;
}

.photo-hero .photo-hero-media > figcaption a {
  color: var(--gg-text-1);
}

.artist-heading.photo-hero .artist-intro {
  flex: 1 1 auto;
}

/* 7. Tour pages with no photo: the next show, as a ticket */

.act-heading.photo-hero-plain {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  min-height: 300px;
  margin-bottom: 8px;
  padding: 40px;
  gap: 48px;
  border: 1px solid var(--gg-border);
  border-radius: var(--gg-radius-lg);
  background:
    radial-gradient(circle at 88% 15%, color-mix(in srgb, var(--gg-cat-concerts) 22%, transparent), transparent 55%),
    var(--gg-surface);
}

.artist-heading.photo-hero-plain {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  padding: 40px;
  border: 1px solid var(--gg-border);
  border-radius: var(--gg-radius-lg);
  background:
    radial-gradient(circle at 88% 15%, color-mix(in srgb, var(--gg-cat-concerts) 22%, transparent), transparent 55%),
    var(--gg-surface);
}

.artist-heading.photo-hero-plain > div {
  flex-wrap: nowrap;
  align-items: center;
  justify-content: space-between;
  gap: 48px;
}

.act-next {
  display: flex;
  flex: none;
  order: 2;
  width: min(42%, 420px);
  min-height: 132px;
  overflow: hidden;
  border: 1px solid var(--gg-border-strong);
  border-radius: var(--gg-radius-lg);
  background: color-mix(in srgb, var(--gg-bg) 60%, transparent);
  color: var(--gg-text-1);
  text-decoration: none;
}

.act-next-date {
  display: flex;
  flex: none;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 2px;
  width: 96px;
  padding: 16px 8px;
  border-right: 1px dashed var(--gg-border-strong);
  color: var(--gg-text-2);
  font-size: 13px;
  font-weight: 600;
}

.act-next-date strong {
  color: var(--gg-text-1);
  font: 700 40px/1 var(--gg-font-display);
}

.act-next-copy {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  justify-content: center;
  gap: 4px;
  min-width: 0;
  padding: 16px 20px;
}

.act-next-label {
  color: var(--gg-text-3);
  font-size: 13px;
}

.act-next-place {
  font: 700 21px/1.2 var(--gg-font-display);
  overflow-wrap: anywhere;
}

.act-next-venue,
.act-next-when {
  color: var(--gg-text-2);
  font-size: 14px;
  line-height: 1.4;
  overflow-wrap: anywhere;
}

.act-next-more {
  margin-top: 6px;
  color: var(--gg-link);
  font-size: 14px;
  font-weight: 600;
}

@media (hover: hover) and (pointer: fine) {
  .act-next:hover {
    border-color: var(--gg-text-3);
  }

  .act-next:hover .act-next-more {
    text-decoration: underline;
  }
}

.act-next:focus-visible {
  outline: 2px solid var(--gg-link);
  outline-offset: 3px;
}

/* Tablets */

@media (max-width: 999px) {
  .act-heading.photo-hero,
  .act-heading.photo-hero-plain,
  .artist-heading.photo-hero,
  .artist-heading.photo-hero-plain {
    padding: 28px;
    gap: 28px;
  }

  .artist-heading.photo-hero > div,
  .artist-heading.photo-hero-plain > div {
    gap: 28px;
  }

  /* Beside the photo the facts can wrap, so drop the dividers that would
     start the second line. */
  :is(.act-heading.photo-hero, .act-heading.photo-hero-plain) .act-facts {
    gap: 8px 20px;
  }

  :is(.act-heading.photo-hero, .act-heading.photo-hero-plain) .act-facts p + p {
    padding-left: 0;
    border-left: 0;
  }
}

/* Phones: the photo comes first, as wide as the screen. */

@media (max-width: 759px) {
  .act-heading.photo-hero,
  .act-heading.photo-hero-plain {
    min-height: 0;
    margin-inline: calc(50% - 50vw);
    padding: 20px calc(50vw - 50%) 22px;
    border: 0;
    border-radius: 0;
  }

  body #main > .artist-heading:is(.photo-hero, .photo-hero-plain) {
    margin-inline: calc(50% - 50vw);
    padding: 20px calc(50vw - 50%) 22px;
    border: 0;
    border-radius: 0;
  }

  .artist-heading.photo-hero > div,
  .artist-heading.photo-hero-plain > div {
    flex-direction: column;
    flex-wrap: nowrap;
    align-items: stretch;
    gap: 16px;
    min-height: 0;
  }

  .photo-hero-backdrop::after {
    background: linear-gradient(180deg,
      color-mix(in srgb, var(--gg-bg) 25%, transparent) 0%,
      color-mix(in srgb, var(--gg-bg) 80%, transparent) 50%,
      var(--gg-bg) 100%);
  }

  .photo-hero .photo-hero-media {
    order: -1;
    align-items: center;
    width: 100%;
  }

  .photo-hero .photo-hero-media > img {
    max-height: 56vh;
  }

  /* A square photo fills the phone's width. A tall one is sized by height. */
  .photo-hero .photo-hero-media.photo-square > img {
    width: 100%;
    height: auto;
    max-height: min(56vh, 420px);
  }

  .photo-hero .photo-hero-media.photo-portrait > img {
    height: min(56vh, 420px);
    height: min(56vh, 420px, 111cqw);
  }

  .photo-hero .photo-hero-media > figcaption {
    text-align: center;
  }

  .act-next {
    order: 6;
    width: 100%;
    min-height: 112px;
  }

  .act-next-date {
    width: 84px;
  }

  .act-next-date strong {
    font-size: 34px;
  }
}

/* 8. Focus classes. Add one x and one y class to a photo's img when its
   subject isn't near the top middle, for example
   class="photo-x-0 photo-y-25" for a face near the left edge. */

.photo-x-0 { --photo-x: 0%; }
.photo-x-25 { --photo-x: 25%; }
.photo-x-50 { --photo-x: 50%; }
.photo-x-75 { --photo-x: 75%; }
.photo-x-100 { --photo-x: 100%; }
.photo-y-0 { --photo-y: 0%; }
.photo-y-25 { --photo-y: 25%; }
.photo-y-50 { --photo-y: 50%; }
.photo-y-75 { --photo-y: 75%; }
.photo-y-100 { --photo-y: 100%; }

@media (forced-colors: active) {
  .photo-hero,
  .act-heading.photo-hero-plain,
  .act-next {
    border: 1px solid CanvasText;
  }
}
