@charset "UTF-8";
/* ==========================================================================
   THE SKAGIT CASINO RESORT — PROMOTIONS
   "Midnight Brass", layer 7 of 7.
   --------------------------------------------------------------------------
   Load order (see inc/enqueue.php):
     1. style.css                    <- legacy child theme
     2. skagit-design-system.css     <- tokens, base, focus, reduced motion
     3. skagit-components.css        <- component skins
     4. skagit-responsive.css        <- breakpoint layer
     5. skagit-rooms-amenities.css
     6. skagit-buttons.css           <- the .sk-btn system
     7. skagit-header.css
     8. skagit-promotions.css        <- THIS FILE (must be last)

   SCOPE
   Three fixes, all owner-reported:
     (1) archive cards were different heights;
     (2) the single promotion buried its own copy under a huge square image;
     (3) "Offer Rules" navigated off-site instead of opening in place.

   WHAT THIS FILE DOES **NOT** DO
   It does not restate the promo card skin. skagit-components.css §7 already
   owns the card surface, the media crop, the badge, the type ramp and the
   meta colours, and skagit-responsive.css owns the grid breakpoints. This
   file only adds the geometry those two layers were missing, plus the two
   genuinely new components (the single-promotion offer sheet, and the rules
   dialog). Every override below is escalated by one real class that exists
   in the markup, so nothing here depends on source order alone.

   !important LEDGER FOR THIS FILE:  ZERO.
   Every override wins on specificity. If you add one, document it here.

   CONTRAST (measured, sRGB, WCAG 2.x formula — see AGENT-PROMOTIONS-REPORT.md
   for the full table). Nothing in this file paints text below 5.3:1.
   ========================================================================== */


/* ==========================================================================
   1. LOCAL TOKENS
   Scoped to the two promotion roots so nothing leaks into other templates.
   ========================================================================== */

.sno-promo-archive,
.skagit-promo-single,
.skagit-promo-dialog {
  /* Card media crop. The source assets are 1080x1080 social graphics whose
     text runs to the edges, so ANY non-square crop guillotines the offer.
     1/1 is the only ratio that shows the whole asset with object-fit:cover
     and zero letterboxing — and a single fixed ratio is half of what makes
     every card the same height. */
  --skagit-promo-media-ratio: 1 / 1;

  /* Reserved line boxes. These are the other half of equal heights: title,
     meta and excerpt each occupy a FIXED number of line boxes whether or not
     the content fills them, so a promo with no time and a two-word title is
     exactly as tall as one with both. */
  --skagit-promo-title-lines: 2;
  --skagit-promo-title-lh: 1.22;      /* == --sk-lh-snug                     */
  --skagit-promo-meta-lh: 1.35;
  --skagit-promo-meta-gap: 0.25rem;
  --skagit-promo-excerpt-lines: 3;
  --skagit-promo-excerpt-lh: 1.6;

  --skagit-promo-dialog-w: min(60rem, 94vw);
}


/* ==========================================================================
   2. ARCHIVE — TOOLBAR
   Markup: archive-promotion.php .promo-toolbar
   skagit-components.css §8 owns the toolbar frame and the pill skin. Added
   here: the group semantics wrapper, and the result counter.
   ========================================================================== */

.sno-promo-archive .promo-filters {
  /* The pills are now aria-pressed toggles inside a labelled group; the
     group element is a new box in the flex row and must not stretch. */
  align-items: center;
}

.sno-promo-archive .promo-sorter {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

/* The visible "Sort" label. The control previously had only a
   screen-reader-text label, which left sighted users guessing what the
   unlabelled select did. */
.sno-promo-archive .promo-sorter-label {
  font-family: var(--sk-font-body);
  font-size: var(--sk-fs-xs);
  font-weight: var(--sk-weight-bold);
  letter-spacing: var(--sk-tracking-wide);
  text-transform: uppercase;
  color: var(--sk-text-faint);          /* 5.54:1 on --sk-mist               */
  white-space: nowrap;
}

/* Empty state for a filter that matches nothing. It is a SIBLING of the grid,
   not a child: the sort routine re-appends every card to the grid, and a
   child would end up shuffled in among them. Hidden until JS reveals it. */
.sno-promo-archive .skagit-promo-empty {
  margin: var(--sk-space-md) 0 0;
  padding: var(--sk-space-2xl) var(--sk-gutter);
  border: 1px dashed var(--sk-border-strong);
  border-radius: var(--sk-radius-lg);
  background: var(--sk-white);
  text-align: center;
  font-family: var(--sk-font-display);
  font-size: var(--sk-fs-lg);
  color: var(--sk-text-faint);          /* 5.54:1 on --sk-mist, 6.01 on white */
}

.sno-promo-archive .skagit-promo-empty[hidden] { display: none; }


/* ==========================================================================
   3. ARCHIVE — EQUAL-HEIGHT CARDS
   --------------------------------------------------------------------------
   THE BUG, precisely.
   A CSS grid row is as tall as its tallest item, and `align-items: stretch`
   then stretches every sibling in THAT ROW to match. So cards were already
   equal *within* a row — what the owner saw is that row 1 was 40px taller
   than row 2, because one card in row 1 had a three-line title and a
   two-line date. Stretching cannot fix that; only pinning the intrinsic
   content height can.

   The fix is four fixed boxes:
     media   -> aspect-ratio, so it never depends on the image
     title   -> exactly 2 line boxes, reserved and clamped
     meta    -> exactly 2 line boxes, reserved whether or not a time exists
     excerpt -> exactly 3 line boxes, reserved and clamped
   …plus the action row pinned with margin-top:auto so it is flush at the
   bottom even if a future field is added above it.

   Second cause, in the JS: the old filter used jQuery .fadeIn(), which
   writes `style="display:block"` onto the <article>. That inline declaration
   beats `display:flex` from skagit-components.css §7.1, so after the very
   first filter click every card silently lost its flex column and the button
   floated up under the excerpt. skagit-promotions.js now toggles the native
   `hidden` attribute instead and never touches `display`.
   ========================================================================== */

/* All four escalate through .skagit-promo-card, a class that exists only on
   this markup, so each is one class more specific than the components rule
   it refines. No source-order dependency. */

.promotions-grid .skagit-promo-card {
  /* Belt and braces: components.css §7.1 already sets height:100%, but the
     card must also refuse to be squeezed below its content. */
  min-height: 100%;
}

/* --- 3.1 The filtered-out state ----------------------------------------
   (0,2,1) beats `.promotions-grid .sno-card { display: flex }` at (0,2,0).
   The native attribute also removes the card from the accessibility tree,
   which .fadeOut()'s inline display:none did not do reliably. */
.promotions-grid .skagit-promo-card[hidden] { display: none; }

/* --- 3.2 Media: one ratio for every card ------------------------------- */
.promotions-grid .skagit-promo-card .sno-card-image {
  flex: 0 0 auto;
  aspect-ratio: var(--skagit-promo-media-ratio);
  height: auto;
}

/* --- 3.3 Body: a column that ends flush --------------------------------- */
.promotions-grid .skagit-promo-card .sno-card-body {
  gap: var(--sk-space-2xs);
  min-height: 0;
}

/* --- 3.4 Title: 2 reserved line boxes ----------------------------------- */
.promotions-grid .skagit-promo-card .skagit-promo-card__title {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--skagit-promo-title-lines);
  line-clamp: var(--skagit-promo-title-lines);
  overflow: hidden;
  line-height: var(--skagit-promo-title-lh);
  /* Reserve the full two lines so a one-line title does not shorten the card. */
  min-height: calc(var(--skagit-promo-title-lines) * var(--skagit-promo-title-lh) * 1em);
}

/* --- 3.5 Meta: 2 reserved line boxes, always ----------------------------
   Owner requirement: "cards with no date must not collapse differently".
   The date line always renders (it falls back to the publish date in PHP);
   the time line is optional. The block reserves BOTH regardless, so the
   presence or absence of a time never changes the card's height. */
.promotions-grid .skagit-promo-card .skagit-promo-card__meta {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--skagit-promo-meta-gap);
  min-height: calc(2 * var(--skagit-promo-meta-lh) * 1em + var(--skagit-promo-meta-gap));
}

.promotions-grid .skagit-promo-card .skagit-promo-card__meta-line {
  display: flex;
  align-items: center;
  gap: 0.45em;
  max-width: 100%;
  min-width: 0;
  line-height: var(--skagit-promo-meta-lh);
}

.promotions-grid .skagit-promo-card .skagit-promo-card__meta-line i {
  flex: 0 0 auto;
  width: 1em;
  text-align: center;
  color: var(--sk-accent-ink);          /* 5.81:1 on white                   */
}

/* One line, hard. An unusually long free-text date ellipsises rather than
   wrapping and unbalancing the grid. CSS ellipsis does not remove the text
   from the accessibility tree, so screen readers still get the full string,
   and the untruncated value is on the single promotion page. */
.promotions-grid .skagit-promo-card .skagit-promo-card__meta-text {
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* --- 3.6 Excerpt: 3 reserved line boxes ---------------------------------
   Body copy on these posts runs 245-1042 bytes and PHP trims the card
   excerpt to 18 words, which is ~2.5 lines in a 320-380px column. Clamping
   at 3 therefore truncates essentially nothing in practice while still
   pinning the height. `flex` is deliberately NOT 1 1 auto here — an absorbing
   excerpt would make each row's slack land in a different place. */
.promotions-grid .skagit-promo-card .skagit-promo-card__excerpt {
  flex: 0 0 auto;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: var(--skagit-promo-excerpt-lines);
  line-clamp: var(--skagit-promo-excerpt-lines);
  overflow: hidden;
  margin: 0;
  line-height: var(--skagit-promo-excerpt-lh);
  min-height: calc(var(--skagit-promo-excerpt-lines) * var(--skagit-promo-excerpt-lh) * 1em);
}

/* --- 3.7 Action row: flush at the bottom, every card -------------------- */
.promotions-grid .skagit-promo-card .skagit-promo-card__action {
  display: block;
  margin-top: auto;
  padding-top: var(--sk-space-2xs);
}

/* The "View Details" affordance is a <span>, not a nested <a>: the whole card
   is already one link, and a link inside a link is invalid HTML and an extra
   tab stop for no gain. It borrows the .sk-btn secondary skin and only ever
   reassigns the system's four paint properties — no new button CSS. */
.promotions-grid .skagit-promo-card .skagit-promo-card__btn {
  width: 100%;
  cursor: inherit;
}

/* Card-level hover lights the button, because the pointer is never actually
   over the <span>. Reassigns the same custom properties skagit-buttons.css
   §3 uses for .sk-btn--secondary:hover — identical paint, no duplication. */
.promotions-grid .skagit-promo-card:hover .skagit-promo-card__btn,
.promotions-grid .skagit-promo-card:focus-within .skagit-promo-card__btn {
  --sk-btn-fg: var(--sk-white);         /* 11.16:1 on --sk-navy-700          */
  --sk-btn-bg: var(--sk-navy-700);
  --sk-btn-border: var(--sk-navy-700);
  --sk-btn-shadow: 0 8px 20px rgba(11, 61, 104, 0.26);
}

/* The card link is the single focusable control; give the focus ring the
   whole card to draw around rather than an inner sliver. */
.promotions-grid .skagit-promo-card .sno-card-link:focus-visible {
  outline-offset: -4px;
  border-radius: var(--sk-radius-lg);
}


/* ==========================================================================
   4. SINGLE PROMOTION — THE OFFER SHEET
   Markup: single-promotion.php .skagit-promo-single
   --------------------------------------------------------------------------
   THE BUG: the old template printed the title, then a full-width featured
   image, then the date, then the copy, then the CTA — a single centred
   column. With a 1080x1080 asset at 640px wide that is ~800px of masthead
   before the first word of the actual offer, so on a 1440x900 desktop the
   copy and the CTA both started below the fold.

   THE LAYOUT: a two-column offer sheet at >=64em. Copy occupies the left
   column top-to-bottom; the image is a contained, framed plate in the right
   column, aligned to the top and capped so it can never outgrow the copy it
   is supporting. Below 64em it collapses to one column in DOM order —
   eyebrow, title, image, facts, copy, actions — which puts a capped image
   between the headline and the copy so the offer is one short scroll away.

   Grid areas (not source order) do the reordering, so the DOM order is the
   reading order on every screen and nothing depends on flexbox `order`.
   ========================================================================== */

.skagit-promo-single {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background:
    radial-gradient(120% 80% at 82% 0%, rgba(212, 175, 55, 0.09) 0%, rgba(212, 175, 55, 0) 58%),
    linear-gradient(180deg, var(--sk-white) 0%, var(--sk-white) 62%, var(--sk-mist) 100%);
  padding-block: var(--sk-space-xl) var(--sk-space-2xl);
}

/* One faint deco arc, the same device the shared page header uses, so the
   single page reads as the same family as the archive. */
.skagit-promo-single::before {
  content: "";
  position: absolute;
  z-index: -1;
  top: -42%;
  right: -14%;
  width: min(96vw, 900px);
  aspect-ratio: 1;
  border: 1px solid rgba(11, 61, 104, 0.07);
  border-radius: 50%;
  pointer-events: none;
}

.skagit-promo-single__back {
  margin-bottom: var(--sk-space-md);
}

.skagit-promo-single__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--sk-space-md);
  align-items: start;
  grid-template-areas:
    "eyebrow"
    "title"
    "media"
    "facts"
    "body"
    "actions";
}

/* No featured image: drop the media row entirely rather than leave an empty
   grid track, and narrow the measure so the copy does not run to 1400px.
   Written AFTER the base rule so it wins at equal specificity; the desktop
   counterpart is at the end of §6.2 for the same reason. */
.skagit-promo-single__grid--no-media {
  grid-template-areas:
    "eyebrow"
    "title"
    "facts"
    "body"
    "actions";
  max-width: var(--sk-container-narrow);
}

.skagit-promo-single__eyebrow  { grid-area: eyebrow; }
.skagit-promo-single__title    { grid-area: title; }
.skagit-promo-single__media    { grid-area: media; }
.skagit-promo-single__facts    { grid-area: facts; }
.skagit-promo-single__body     { grid-area: body; }
.skagit-promo-single__actions  { grid-area: actions; }

/* --- 4.1 Eyebrow -------------------------------------------------------- */
.skagit-promo-single__eyebrow {
  margin: 0;
  font-family: var(--sk-font-body);
  font-size: var(--sk-fs-xs);
  font-weight: var(--sk-weight-black);
  letter-spacing: var(--sk-tracking-eyebrow);
  text-transform: uppercase;
  color: var(--sk-accent-ink);          /* 5.81:1 on white                   */
}

/* --- 4.2 Title ---------------------------------------------------------- */
.skagit-promo-single .skagit-promo-single__title {
  margin: 0;
  font-family: var(--sk-font-display);
  font-size: var(--sk-fs-4xl);
  font-weight: var(--sk-weight-bold);
  line-height: var(--sk-lh-tight);
  letter-spacing: var(--sk-tracking-display);
  text-transform: none;
  color: var(--sk-navy-900);            /* 17.76:1 on white                  */
  text-wrap: balance;
}

/* A short brass rule under the headline — the system's signature mark. */
.skagit-promo-single__title::after {
  content: "";
  display: block;
  width: clamp(56px, 7vw, 92px);
  height: 2px;
  margin-top: var(--sk-space-sm);
  border-radius: 2px;
  background: var(--sk-grad-brass);
  box-shadow: 0 1px 8px rgba(212, 175, 55, 0.4);
}

/* --- 4.3 Facts: the date/time chips ------------------------------------
   These are the two things a guest actually needs, so they sit directly
   under the headline instead of being buried under the artwork. */
.skagit-promo-single__facts {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sk-space-2xs);
  margin: 0;
  padding: 0;
  list-style: none;
}

.skagit-promo-single__fact {
  display: inline-flex;
  align-items: center;
  gap: 0.55em;
  margin: 0;
  padding: 0.55rem 1rem;
  border: 1px solid transparent;
  border-radius: var(--sk-radius-pill);
  font-family: var(--sk-font-body);
  font-size: var(--sk-fs-sm);
  font-weight: var(--sk-weight-bold);
  letter-spacing: 0.04em;
  line-height: 1.3;
}

/* Primary fact — the dates. Solid brass-tint plate. */
.skagit-promo-single__fact--date {
  background: var(--sk-gold-200);
  border-color: rgba(176, 141, 40, 0.45);
  color: var(--sk-navy-900);            /* 15.05:1 on --sk-gold-200          */
}

/* Secondary fact — the hours. */
.skagit-promo-single__fact--time {
  background: var(--sk-mist);
  border-color: var(--sk-border);
  color: var(--sk-text);                /* 12.25:1 on --sk-mist              */
}

.skagit-promo-single__fact i {
  flex: 0 0 auto;
  font-size: 0.9em;
  color: var(--sk-bronze-700);          /* 5.98:1 on --sk-gold-200           */
}

.skagit-promo-single__fact--time i { color: var(--sk-accent-ink); } /* 5.36:1 on --sk-mist */

/* --- 4.4 Body copy ------------------------------------------------------
   `.sno-content-body` is kept as a second class purely to inherit the
   design system's prose-link underlines (§2.3) — the only bare
   `.sno-content-body` rules in the system are those link rules; every other
   one is scoped under `.sno-single-wrapper`, which this template no longer
   uses. */
.skagit-promo-single .skagit-promo-single__body {
  max-width: var(--sk-measure);
  margin: 0;
  font-size: var(--sk-fs-md);
  line-height: var(--sk-lh-loose);
  color: var(--sk-text);                /* 13.27:1 on white                  */
}

.skagit-promo-single .skagit-promo-single__body > :first-child { margin-top: 0; }
.skagit-promo-single .skagit-promo-single__body > :last-child { margin-bottom: 0; }
.skagit-promo-single .skagit-promo-single__body p { color: inherit; font-size: inherit; }

.skagit-promo-single .skagit-promo-single__body h2,
.skagit-promo-single .skagit-promo-single__body h3 {
  margin-top: var(--sk-space-md);
  font-size: var(--sk-fs-lg);
}

.skagit-promo-single .skagit-promo-single__body ul,
.skagit-promo-single .skagit-promo-single__body ol { margin: 0 0 var(--sk-space-sm); }

/* --- 4.5 Actions -------------------------------------------------------- */
.skagit-promo-single__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sk-space-sm);
  margin: 0;
  padding-top: var(--sk-space-2xs);
}

/* --- 4.6 Media plate ----------------------------------------------------
   Contained, never full-bleed. The frame is a 1px brass hairline over a
   mist mat, so a square social graphic reads as a deliberate plate rather
   than a hero that failed to crop. */
.skagit-promo-single__media {
  position: relative;
  margin: 0;
  padding: 0;
}

.skagit-promo-single__media-frame {
  position: relative;
  overflow: hidden;
  aspect-ratio: var(--skagit-promo-media-ratio);
  width: min(100%, 340px);
  margin-inline: auto;
  border: 1px solid rgba(176, 141, 40, 0.38);
  border-radius: var(--sk-radius-lg);
  background: var(--sk-mist);
  box-shadow: var(--sk-shadow-lg);
}

.skagit-promo-single__media-frame img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.skagit-promo-single__media-caption {
  margin: var(--sk-space-2xs) 0 0;
  text-align: center;
  font-family: var(--sk-font-body);
  font-size: var(--sk-fs-xs);
  letter-spacing: var(--sk-tracking-wide);
  text-transform: uppercase;
  color: var(--sk-text-faint);          /* 6.01:1 on white                   */
}


/* ==========================================================================
   5. THE OFFER RULES DIALOG
   Markup: single-promotion.php <dialog class="skagit-promo-dialog">
   Behaviour: assets/js/skagit-promotions.js
   --------------------------------------------------------------------------
   Two rendering modes share one stylesheet:

     NATIVE  — showModal() puts the element in the top layer. The <dialog>
               box is transparent and only sizes the panel; ::backdrop paints
               the scrim; the UA supplies `position:fixed; inset:0;
               margin:auto`, which centres it whatever `display` we set.

     FALLBACK— .is-fallback. The <dialog> itself becomes the full-screen
               scrim at --sk-z-overlay and centres the same panel. Identical
               markup, identical panel rules, only the outer box differs.

   The explicit `display:none` on the bare class matters: a browser with no
   <dialog> support renders the element as an ordinary visible block, so the
   rules image would print inline halfway down the page.
   ========================================================================== */

.skagit-promo-dialog {
  display: none;
  width: var(--skagit-promo-dialog-w);
  max-width: var(--skagit-promo-dialog-w);
  max-height: 92vh;
  max-height: 92dvh;
  padding: 0;
  border: 0;
  background: transparent;
  overflow: visible;
  color: var(--sk-text);
}

.skagit-promo-dialog[open] {
  display: flex;
  flex-direction: column;
}

.skagit-promo-dialog::backdrop {
  background: rgba(4, 16, 28, 0.78);
  -webkit-backdrop-filter: blur(3px) saturate(0.9);
  backdrop-filter: blur(3px) saturate(0.9);
}

/* --- 5.1 Fallback outer box -------------------------------------------- */
.skagit-promo-dialog.is-fallback[open] {
  position: fixed;
  inset: 0;
  z-index: var(--sk-z-overlay);
  width: auto;
  max-width: none;
  max-height: none;
  padding: var(--sk-gutter);
  align-items: center;
  justify-content: center;
  background: rgba(4, 16, 28, 0.78);
  -webkit-backdrop-filter: blur(3px) saturate(0.9);
  backdrop-filter: blur(3px) saturate(0.9);
}

.skagit-promo-dialog.is-fallback .skagit-promo-dialog__panel {
  flex: 0 1 auto;
  width: min(60rem, 100%);
  max-height: 92vh;
  max-height: 92dvh;
}

/* --- 5.2 Panel ---------------------------------------------------------- */
.skagit-promo-dialog__panel {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  min-height: 0;
  overflow: hidden;
  border-radius: var(--sk-radius-lg);
  background: var(--sk-white);
  box-shadow: var(--sk-shadow-xl);
  /* Start state for the open transition. `.is-open` is added on the next
     frame by the JS; if the JS never runs, neither does the dialog. */
  opacity: 0;
  transform: translateY(14px) scale(0.985);
}

.skagit-promo-dialog.is-open .skagit-promo-dialog__panel {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: no-preference) {
  .skagit-promo-dialog__panel {
    transition: opacity var(--sk-dur-base) var(--sk-ease-out),
                transform var(--sk-dur-base) var(--sk-ease-out);
  }
}

/* No motion preference honoured: the panel simply appears. Because the start
   state is a paint state (not display), removing the transition is enough —
   there is no half-animated frame to see. */
@media (prefers-reduced-motion: reduce) {
  .skagit-promo-dialog__panel { transition: none; }
}

/* --- 5.3 Head ----------------------------------------------------------- */
.skagit-promo-dialog__head {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: space-between;
  gap: var(--sk-space-sm);
  padding: var(--sk-space-sm) var(--sk-space-md);
  background: var(--sk-grad-night);
  box-shadow: var(--sk-rim-light), 0 1px 0 rgba(212, 175, 55, 0.55);
}

.skagit-promo-dialog .skagit-promo-dialog__title {
  margin: 0;
  font-family: var(--sk-font-display);
  font-size: var(--sk-fs-lg);
  font-weight: var(--sk-weight-bold);
  letter-spacing: var(--sk-tracking-tight);
  line-height: var(--sk-lh-snug);
  text-transform: none;
  color: var(--sk-gold-200);            /* 15.05:1 on --sk-navy-900          */
}

.skagit-promo-dialog__subtitle {
  display: block;
  margin: 0.15rem 0 0;
  font-family: var(--sk-font-body);
  font-size: var(--sk-fs-xs);
  font-weight: var(--sk-weight-semi);
  letter-spacing: var(--sk-tracking-wide);
  text-transform: uppercase;
  color: var(--sk-text-on-dark-muted);  /* 10.0:1 on --sk-navy-900           */
}

/* Close control. Borrows the ghost-on-dark paint from skagit-buttons.css §4;
   only the geometry is set here, so it stays a square icon target. */
.skagit-promo-dialog .skagit-promo-dialog__close {
  --sk-btn-pad-x: 0;
  --sk-btn-pad-y: 0;
  --sk-btn-min-h: 44px;
  flex: 0 0 auto;
  width: 44px;
  font-size: 1rem;
}

/* --- 5.4 Viewport: the zoomable, scrollable document -------------------- */
.skagit-promo-dialog__viewport {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  overscroll-behavior: contain;
  -webkit-overflow-scrolling: touch;
  padding: var(--sk-space-sm);
  background:
    repeating-linear-gradient(45deg,
      rgba(11, 61, 104, 0.035) 0 10px,
      rgba(11, 61, 104, 0) 10px 20px),
    var(--sk-mist);
  /* tabindex="0" makes this a keyboard-scrollable region; it therefore needs
     a focus ring, which the design system's global :focus-visible supplies. */
}

.skagit-promo-dialog__img {
  display: block;
  width: 100%;
  height: auto;
  margin-inline: auto;
  border-radius: var(--sk-radius-sm);
  background: var(--sk-white);
  box-shadow: var(--sk-shadow-sm);
  cursor: zoom-in;
}

/* Zoomed. `max-width: none` is required — the design system sets a global
   `img { max-width: 100% }`, and (0,2,0) here beats (0,0,1) there. */
.skagit-promo-dialog__viewport.is-zoomed .skagit-promo-dialog__img {
  width: 210%;
  max-width: none;
  cursor: zoom-out;
}

@media (prefers-reduced-motion: no-preference) {
  .skagit-promo-dialog__img { transition: width var(--sk-dur-base) var(--sk-ease-out); }
}

/* PDFs and anything else that is not an image get an embedded frame rather
   than a navigation. The new-tab link in the footer remains the escape hatch. */
.skagit-promo-dialog__frame {
  display: block;
  width: 100%;
  height: min(70vh, 720px);
  border: 0;
  border-radius: var(--sk-radius-sm);
  background: var(--sk-white);
}

/* --- 5.5 Foot ----------------------------------------------------------- */
.skagit-promo-dialog__foot {
  display: flex;
  flex: 0 0 auto;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sk-space-xs) var(--sk-space-sm);
  padding: var(--sk-space-xs) var(--sk-space-md);
  border-top: 1px solid var(--sk-border);
  background: var(--sk-white);
}

.skagit-promo-dialog__note {
  flex: 1 1 14rem;
  margin: 0;
  font-size: var(--sk-fs-xs);
  line-height: 1.45;
  color: var(--sk-text-faint);          /* 6.01:1 on white                   */
}

.skagit-promo-dialog__foot-actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--sk-space-sm);
}

/* Label swap driven purely by aria-pressed, so the DOM state and the visible
   state cannot drift apart. Not pressed = not zoomed = offer "Zoom in". */
.skagit-promo-dialog__zoom[aria-pressed="false"] .skagit-promo-dialog__zoom-label-out,
.skagit-promo-dialog__zoom[aria-pressed="true"]  .skagit-promo-dialog__zoom-label-in { display: none; }

/* --- 5.6 Page scroll lock ----------------------------------------------
   (0,1,1) on `html.…` and on `html.… body` beats the design system's
   `html { overflow-x: clip }` and `body { overflow-x: clip }` at (0,0,1),
   so no !important is needed. The class is removed on close. */
html.skagit-promo-modal-open,
html.skagit-promo-modal-open body {
  overflow: hidden;
}


/* ==========================================================================
   6. RESPONSIVE
   Mobile-first: everything above is the small-screen layout.
   ========================================================================== */

/* ---- 6.1 >= 40em (640px): two facts side by side, roomier plate -------- */
@media (min-width: 40em) {
  .skagit-promo-single__media-frame { width: min(100%, 420px); }
}

/* ---- 6.2 >= 64em (1024px): the two-column offer sheet ------------------
   This is the breakpoint that fixes the owner's complaint. At 1440x900 the
   eyebrow, headline, both fact chips, the opening copy and the CTA row all
   sit inside the first ~620px of the document, i.e. above the fold with the
   sticky header allowed for. */
@media (min-width: 64em) {
  /* Measured: with --sk-space-2xl (88px at 1440) the CTA row bottomed out at
     721px, which leaves only ~30px once the ~150px sticky header is added on
     the real page. --sk-space-xl (60px) restores the margin without making
     the section feel cramped. */
  .skagit-promo-single {
    padding-block: var(--sk-space-xl) var(--sk-space-3xl);
  }

  .skagit-promo-single__grid {
    grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
    grid-template-rows: auto auto auto 1fr auto;
    column-gap: var(--sk-space-xl);
    row-gap: var(--sk-space-md);
    grid-template-areas:
      "eyebrow media"
      "title   media"
      "facts   media"
      "body    media"
      "actions media";
  }

  .skagit-promo-single__media {
    align-self: start;
    /* Optically aligns the top of the plate with the cap height of the
       headline rather than the top of the eyebrow. */
    margin-top: calc(var(--sk-space-2xs) * -1);

    /* STAYS WITH THE READER ON A LONG PROMOTION.
       The copy column runs to 634px on Stars, Stripes & Swipes while the plate
       is 460px, so the artwork scrolled away while the rules were still being
       read. Sticky keeps the thing being described on screen. Offset clears
       the sticky header. */
    position: sticky;
    top: calc(var(--sk-header-h, 150px) + var(--sk-space-md));
  }

  /* FLUSH TO THE RIGHT EDGE, AND IT FILLS ITS COLUMN.
     This was `width: min(100%, 460px); margin-inline: 0 auto`, which pinned a
     460px plate to the LEFT of a 539px column and left a 79px dead gap down
     the right-hand side. The artwork read as something that had drifted rather
     than as part of the layout, which is what the owner was seeing.

     Now it fills the column and aligns to the container's right edge, so the
     page has a straight outer margin on both sides. The 560px cap stops the
     plate from becoming a billboard on very wide screens — these are square
     social graphics, and past ~560px they gain nothing. */
  .skagit-promo-single__media-frame {
    width: min(100%, 560px);
    margin-inline: auto 0;
  }

  .skagit-promo-single__actions { align-self: end; }

  /* Must follow the rule above: same specificity, later wins. */
  .skagit-promo-single__grid--no-media {
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto;
    grid-template-areas:
      "eyebrow"
      "title"
      "facts"
      "body"
      "actions";
  }
}

/* ---- 6.3 >= 90em (1440px): the target desktop -------------------------- */
@media (min-width: 90em) {
  .skagit-promo-single__media-frame { width: min(100%, 500px); }
}

/* ---- 6.4 <= 47.99em (768px and below): phones -------------------------
   The plate is capped hard so the copy is never pushed off the first
   viewport. At 390x844 the headline, both chips and the first lines of the
   offer are visible; the CTA is one short scroll. */
@media (max-width: 47.99em) {
  .skagit-promo-single {
    padding-block: var(--sk-space-lg) var(--sk-space-xl);
  }

  .skagit-promo-single__media-frame {
    width: min(100%, 300px);
  }

  .skagit-promo-single__actions > .sk-btn { width: 100%; }

  .skagit-promo-dialog__foot {
    flex-direction: column;
    align-items: stretch;
  }

  .skagit-promo-dialog__foot-actions { justify-content: space-between; }

  .skagit-promo-dialog__viewport { padding: var(--sk-space-2xs); }
}

/* ---- 6.5 <= 37.49em (600px): small phones ----------------------------- */
@media (max-width: 37.49em) {
  /* One card per row at this width, so the reserved boxes can relax a
     little — the excerpt gets more characters per line here. */
  .sno-promo-archive,
  .skagit-promo-single { --skagit-promo-excerpt-lines: 3; }

  /* Measured at 390x844: every 40px shaved off the plate is 40px more of the
     actual offer above the fold. 240px is the point where the artwork is
     still legible as artwork. */
  .skagit-promo-single__media-frame { width: min(66vw, 240px); }

  .skagit-promo-single__fact {
    width: 100%;
    justify-content: flex-start;
  }

  .skagit-promo-dialog.is-fallback[open] { padding: 0; }
  .skagit-promo-dialog.is-fallback .skagit-promo-dialog__panel {
    max-height: 100vh;
    max-height: 100dvh;
    border-radius: 0;
  }
}

/* ---- 6.6 Touch pointers ------------------------------------------------ */
@media (hover: none), (pointer: coarse) {
  /* The card button never receives a real hover on touch, so give it the
     resting outline treatment permanently rather than a state that can be
     stuck on after a tap. */
  .promotions-grid .skagit-promo-card:hover .skagit-promo-card__btn {
    --sk-btn-fg: var(--sk-navy-700);
    --sk-btn-bg: transparent;
    --sk-btn-border: var(--sk-navy-700);
    --sk-btn-shadow: none;
  }

  .skagit-promo-dialog__img { cursor: default; }
}


/* ==========================================================================
   7. PRINT
   The single promotion is the one page guests actually print (to bring the
   offer in). Strip the chrome, keep the copy and the plate.
   ========================================================================== */

@media print {
  .skagit-promo-single {
    padding-block: 0;
    background: none;
  }

  .skagit-promo-single::before,
  .skagit-promo-single__back,
  .skagit-promo-single__actions { display: none; }

  .skagit-promo-single__grid {
    display: block;
  }

  .skagit-promo-single__media-frame {
    width: 3in;
    box-shadow: none;
    break-inside: avoid;
  }

  /* A dialog left open when the user hits print must not paper over the page. */
  .skagit-promo-dialog,
  .skagit-promo-dialog[open] { display: none; }

  /* Card clamps hide content on paper; release them. */
  .promotions-grid .skagit-promo-card .skagit-promo-card__title,
  .promotions-grid .skagit-promo-card .skagit-promo-card__excerpt {
    display: block;
    overflow: visible;
    min-height: 0;
  }
}


/* ==========================================================================
   7. THE SHOW PAGE
   --------------------------------------------------------------------------
   single-entertainment.php now renders the same offer-sheet grid as
   single-promotion.php, so everything above applies. Only the differences
   between a promotion and a dated show live here.

   The difference that matters: a show has one or two DATES, each with its own
   ticket link, where a promotion has a date line and a rules button. So the
   fact list becomes a list of rows, each pairing a date with its own control.
   ========================================================================== */

.skagit-ent-single__dates {
  display: flex;
  flex-direction: column;
  gap: var(--sk-space-2xs);
}

.skagit-ent-single__date {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sk-space-xs);
  /* Wider than the promotion's inline chip, because this row carries a button
     as well as a date and the two need separating rather than crowding. */
  width: 100%;
  padding: var(--sk-space-2xs) var(--sk-space-xs);
}

.skagit-ent-single__date-label {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  min-width: 0;
}

.skagit-ent-single__date-action { flex: 0 0 auto; }

/* The ticket button keeps its own styling from the entertainment layer; all
   that is needed here is that it does not stretch to the row width. */
.skagit-ent-single__date-action .ent-btn {
  display: inline-flex;
  align-items: center;
  white-space: nowrap;
}

/* The countdown follows the description instead of leading the column, so it
   needs its own top margin rather than the old wrapper's. */
.skagit-ent-single__timer {
  margin-block-start: var(--sk-space-lg);
}

/* Narrow: the date and its button stack, and the button goes full width so it
   is a proper tap target rather than a chip floating on the right. */
@media (max-width: 33.99em) {
  .skagit-ent-single__date {
    align-items: stretch;
    flex-direction: column;
  }

  .skagit-ent-single__date-action,
  .skagit-ent-single__date-action .ent-btn {
    width: 100%;
    justify-content: center;
  }
}

/* ==========================================================================
   9. TICKETING NOTICE (entertainment singles)

   Legal fine print, and it should read as fine print. A hairline rule
   separates it from the description — which is the thing that was missing
   when this text was glued to the end of the copy — and the type drops a
   step so the eye files it as a footnote rather than the closing paragraph
   of the act's biography.

   Not a tinted callout box: a warning panel here would shout louder than
   the show it is attached to.
   ========================================================================== */
.skagit-ent-single__notice {
  margin-top: var(--sk-space-lg);
  padding-top: var(--sk-space-sm);
  border-top: 1px solid var(--sk-border);
  max-width: var(--sk-measure);
}

.skagit-ent-single__notice-title {
  margin: 0 0 var(--sk-space-2xs);
  font-family: var(--sk-font-body);
  font-size: var(--sk-fs-xs);
  font-weight: var(--sk-weight-black, 800);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--sk-text-faint);
}

/* Beats .skagit-promo-single__body p, which sets the body copy size. */
.skagit-promo-single .skagit-ent-single__notice p {
  margin: 0 0 var(--sk-space-2xs);
  font-size: var(--sk-fs-xs);
  line-height: 1.5;
  color: var(--sk-text-faint);          /* 6.01:1 on white */
}

.skagit-promo-single .skagit-ent-single__notice p:last-child { margin-bottom: 0; }

.skagit-ent-single__notice a {
  color: inherit;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.skagit-ent-single__notice a:hover,
.skagit-ent-single__notice a:focus-visible { color: var(--sk-bronze-700); }

/* ==========================================================================
   10. THE SHOW DATE, MADE UNMISSABLE

   The one thing somebody opens a show page for is WHEN. It was rendering at
   fact-list size — the same weight as "Venue" and the ticket small print — so
   the single most important line on the page had no more presence than its
   own label. On a phone it was easily missed entirely.

   Now it is a card: a brass-ruled panel, the date at display size and weight,
   the time on its own line beneath. The calendar icon becomes a block mark
   rather than an inline glyph, so the eye lands on the panel before it reads
   anything.

   Two dates still work — a show that runs two nights gets two panels, each
   with its own ticket button, which is why the row remains the unit.
   ========================================================================== */
.skagit-ent-single__dates {
  display: grid;
  gap: var(--sk-space-sm);
  margin: var(--sk-space-md) 0 var(--sk-space-lg);
  padding: 0;
  list-style: none;
}

/* Beats `.skagit-promo-single__fact` (0,1,0) from the shared offer sheet. */
.skagit-promo-single .skagit-ent-single__date {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: var(--sk-space-sm);
  margin: 0;
  padding: var(--sk-space-sm) var(--sk-space-md);
  border: 1px solid var(--sk-border);
  border-left: 4px solid var(--sk-bronze-700);
  border-radius: var(--sk-radius-md);
  background: var(--sk-white);
  box-shadow: var(--sk-shadow-sm);
}

.skagit-promo-single .skagit-ent-single__date-label {
  display: flex;
  align-items: baseline;
  gap: 0.7rem;
  min-width: 0;
  flex: 1 1 16rem;
}

/* The icon reads as a mark beside the date, not a character in it. */
.skagit-promo-single .skagit-ent-single__date-label > i {
  flex: none;
  font-size: 1.15rem;
  line-height: 1;
  color: var(--sk-bronze-700);
  transform: translateY(0.15em);
}

/* THE DATE ITSELF. Display face, tight leading, and big enough to be the
   first thing read after the headline. */
.skagit-promo-single .skagit-ent-single__date-label > span:not(.sk-visually-hidden) {
  font-family: var(--sk-font-display);
  font-size: clamp(1.35rem, 1.05rem + 1.4vw, 2rem);
  font-weight: var(--sk-weight-bold, 700);
  line-height: var(--sk-lh-tight);
  letter-spacing: var(--sk-tracking-display, 0);
  color: var(--sk-navy-900);
  /* "Friday, July 31st | 8pm" arrives as one string — the pipe is the only
     separator available, so it is given room to act as one. */
  word-spacing: 0.04em;
}

@media (max-width: 47.99em) {
  .skagit-promo-single .skagit-ent-single__date {
    /* Button under the date on a phone, both full width, nothing cramped. */
    flex-direction: column;
    align-items: stretch;
    text-align: left;
  }

  .skagit-promo-single .skagit-ent-single__date-action,
  .skagit-promo-single .skagit-ent-single__date-action .ent-btn {
    width: 100%;
    justify-content: center;
  }
}


/* ==========================================================================
   THE ENTERTAINMENT SINGLE — POSTER SIZE AND THE DATE ROW
   --------------------------------------------------------------------------
   Three measured problems, all on /entertainment/<show>/.

   1. THE POSTER LOOKS SMALL, AND jQuery CANNOT FIX IT.
      The request was to scale the artwork with the length of the copy. It is
      worth writing down why that is the wrong tool: the image is a block inside
      a grid column and its width is bounded by THAT COLUMN, not by the text
      beside it. Measured at 1280px, the column is 538px and the image renders
      537px — it is already filling every pixel it is given. Growing it with JS
      would either overflow the column or crop the poster, and the script would
      have to re-run on resize, on webfont load and on orientation change to stay
      correct. The honest fix is to give the column more room, which is CSS.

      So the split moves from 1.06/0.94 to 0.95/1.05 in favour of the artwork,
      and the 560px cap that was also binding goes to 660px. Same layout, a
      poster about 20% larger, nothing to keep in sync at runtime.

   2. ON MOBILE THE POSTER WAS 240px INSIDE A 420px COLUMN.
      A 240px square with 90px of dead space either side, which is what made it
      read as a thumbnail. It now fills the column.

   3. THE DATE CARD HAD A 200px VOID.
      Measured at 470px: the card is 352px tall, the label inside it is 256px
      tall, and the label contains two lines of text. Below 34em the card is
      `flex-direction: column`, and the label was absorbing the leftover height
      instead of sitting at its natural size — so the button was pushed to the
      bottom of a mostly empty box.

      Both the card and the label are pinned to their content height here. The
      calendar icon is also dropped, as agreed: the line already begins with the
      word "Saturday", so the glyph was repeating what the text says.
   ====================================================================== */

/* ---- 1. Desktop: a bigger poster ---------------------------------------- */
@media (min-width: 62em) {

  .skagit-promo-single__grid {
    grid-template-columns: minmax(0, 0.95fr) minmax(0, 1.05fr);
  }

  .skagit-promo-single__media-frame {
    max-width: 660px;
  }
}

/* ---- 2. Mobile: the poster fills its column ----------------------------- */
@media (max-width: 61.99em) {

  .skagit-promo-single__media-frame {
    width: 100%;
    max-width: 520px;
    margin-inline: auto;
  }
}

/* ---- 3. The date row ---------------------------------------------------- */

/*
 * The icon goes. `display: none` rather than removing it from the template so
 * this stays a presentation change — the markup is shared with the promotions
 * single, which still uses its own icons.
 */
.skagit-ent-single__date-label > i,
.skagit-ent-single__date-label > svg,
.skagit-promo-single .skagit-ent-single__date-label > i {
  display: none;
}

/*
 * The date now carries itself typographically instead of leaning on a glyph:
 * the display face, a size that reads as the most important line in the card,
 * and tabular figures so "19th" and "8pm" do not wobble against other shows.
 */
.skagit-promo-single .skagit-ent-single__date-label {
  flex: 0 1 auto;
  height: auto;
  min-height: 0;
  align-items: baseline;
  gap: 0.5rem;
  font-family: var(--sk-font-display);
  font-size: clamp(1.05rem, 0.6vw + 0.95rem, 1.35rem);
  font-weight: var(--sk-weight-semi);
  line-height: 1.25;
  letter-spacing: 0.01em;
  font-variant-numeric: tabular-nums;
  text-wrap: balance;
}

/* Nothing in this card may stretch to fill leftover height. */
.skagit-promo-single .skagit-ent-single__date {
  height: auto;
  align-self: start;
}

.skagit-promo-single__facts,
.skagit-promo-single__facts > .skagit-promo-single__fact {
  align-self: start;
  height: auto;
}

@media (max-width: 33.99em) {

  /* The column layout is kept — the button below the date is right on a phone —
     but the label stops absorbing the surplus. */
  .skagit-promo-single .skagit-ent-single__date {
    gap: var(--sk-space-sm);
  }

  .skagit-promo-single .skagit-ent-single__date-label {
    flex: 0 0 auto;
    width: 100%;
  }
}
