/* =====================================================================
   ETP BASE
   Reset, page scaffold, brand type scale, layout primitives, and the
   three shared patterns the whole system reuses. Load AFTER tokens.css
   and BEFORE components.css.
   ===================================================================== */

/* --- Custom fonts ---------------------------------------------------
   Brand faces. Local .woff2 only; never Google/Adobe. Point the src
   paths at wherever your app serves the font files. */
@font-face { font-family: 'Monument Wide'; src: url('/fonts/PPMonumentWide-Black.woff2') format('woff2'); font-weight: 900; font-style: normal; font-display: swap; }
@font-face { font-family: 'Neue Montreal'; src: url('/fonts/PPNeueMontreal-Book.woff2')   format('woff2'); font-weight: 400; font-style: normal; font-display: swap; }
@font-face { font-family: 'Neue Montreal'; src: url('/fonts/PPNeueMontreal-Medium.woff2') format('woff2'); font-weight: 500; font-style: normal; font-display: swap; }
@font-face { font-family: 'Neue Montreal'; src: url('/fonts/PPNeueMontreal-Bold.woff2')   format('woff2'); font-weight: 700; font-style: normal; font-display: swap; }
@font-face { font-family: 'Neue Montreal'; src: url('/fonts/PPNeueMontreal-Italic.woff2') format('woff2'); font-weight: 400; font-style: italic; font-display: swap; }

/* --- Reset ---------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
h1, h2, h3, h4, h5, h6, p, ul, ol, li, button, a, label, input, select, textarea {
  color: inherit; font-family: inherit; font-size: inherit; font-weight: inherit;
  line-height: inherit; letter-spacing: inherit; text-decoration: none; margin: 0;
}
ul, ol { padding: 0; list-style: none; }
h1, h2, h3, h4, h5, h6 { font-weight: 500; }
html, body { margin: 0; padding: 0; background: var(--color-offwhite); color: var(--color-black); }
body {
  font-family: var(--font-body);
  font-size: 16px; line-height: 1.4;
  -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale;
}
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; cursor: pointer; }
button:disabled { cursor: not-allowed; }

/* Global focus ring. Accessibility is a baseline, not a feature. */
:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }

/* =====================================================================
   TYPE SCALE
   PP Monument Wide Black for display. PP Neue Montreal for everything.
   Lowercase hero copy. Sentence-case body. Tracked UPPERCASE labels.
   ===================================================================== */

/* Hero display headline. Asymmetric two-line stagger. */
.display {
  font-family: var(--font-display); font-weight: 900;
  text-transform: lowercase; letter-spacing: var(--tracking-display); line-height: 0.95;
  font-size: clamp(48px, 12vw, 76px);
  display: flex; flex-direction: column; gap: 0.06em;
}
.display > span { display: block; }
.display .line-2 { padding-left: 1.1em; }

/* Section / secondary display headline. */
.h2 {
  font-family: var(--font-display); font-weight: 900;
  text-transform: lowercase; letter-spacing: var(--tracking-display); line-height: 0.95;
  font-size: clamp(28px, 5vw, 48px);
}

/* Tracked uppercase label. The brand's workhorse meta type. */
.label {
  font-family: var(--font-body); font-weight: 500;
  font-size: 12px; letter-spacing: var(--tracking-label); text-transform: uppercase;
  color: var(--color-black);
}
.label--muted { color: var(--color-muted); }

/* Body copy. Capped ~60ch. */
.type-body {
  font-family: var(--font-body); font-weight: 400;
  font-size: 16px; line-height: 1.4;
  max-width: 60ch;
}

/* Tabular numerals. Any column of figures: prices, counts, times, days. */
.type-num {
  font-variant-numeric: tabular-nums;
  font-family: var(--font-body); font-weight: 500;
  font-size: 24px; letter-spacing: var(--tracking-ui);
}

/* =====================================================================
   LAYOUT PRIMITIVES
   ===================================================================== */
.wrap {
  max-width: 1240px;
  margin: 0 auto;
  padding: 56px var(--space-4) 96px;
}
.header {
  display: flex; flex-direction: row;
  justify-content: space-between; align-items: flex-start;
  flex-wrap: wrap; gap: 64px;
}

.stack        { display: flex; flex-direction: column; gap: var(--space-4); }
.stack--tight { gap: var(--space-2); }
.stack--loose { gap: 56px; }

.row        { display: flex; flex-wrap: wrap; gap: var(--space-3); align-items: flex-start; }
.row--tight { gap: var(--space-1); }

.grid-2 { display: grid; grid-template-columns: 1fr; gap: var(--space-3); }
.grid-3 { display: grid; grid-template-columns: 1fr; gap: var(--space-3); }
@media (min-width: 720px) {
  .grid-2 { grid-template-columns: 1fr 1fr; }
  .grid-3 { grid-template-columns: 1fr 1fr 1fr; }
}

/* =====================================================================
   SHARED PATTERNS
   Declared once, reused everywhere.
   ===================================================================== */

/* Motif 1 — accent bar.
   6% accent tint + 3px left-edge bar that scales in on hover. The
   selected state takes the full accent fill. Apply .has-accent-bar to
   any row-like element (schedule rows, dropdown options, nav links). */
.has-accent-bar { position: relative; }
.has-accent-bar::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 0;
  width: 3px; background: var(--color-accent);
  transform: scaleY(0); transform-origin: top;
  transition: transform var(--transition-fast);
}
/* GUARDED. On touch a tap fires :hover and can leave the bar drawn and the tint painted until
   something else is touched -- reading as a selected state the user did not choose. This is the
   widget's rule, adopted here rather than invented: classes.etpbjj.com gates 18 of its 20 hover
   rules, and the only two it leaves open are bare text links that recolour and nothing more.
   The line is the BOX: a hover that changes a border, a background, a fill or a drawn mark is
   gated; a hover that only recolours text is not. */
@media (hover: hover) {
  .has-accent-bar:hover::before { transform: scaleY(1); }
  .has-accent-bar:hover { background: var(--color-accent-tint); }
}
.has-accent-bar[aria-selected="true"] {
  background: var(--color-accent);
  color: var(--color-offwhite);
}

/* Drawn icon primitives: a two-member family. Siblings by shared construction
   (a mitered border-corner head) and currentColor, NOT by identical stroke.
   Weight is tuned per job: the chevron stands alone so it carries more weight
   (1.5px); the arrow sits beside text so it runs lighter (1px). Each keeps a
   fallback glyph in the HTML that font-size:0 hides.

   .icon-chevron: a pixel-symmetric L from two borders, in four rotations
   (is-down/up/left/right). Open/closed states overlap with no drift (a rotated
   text glyph would mirror-shift). Means "more / expand / browse": dropdowns,
   the select trigger, navigation. (Formerly named .icon-arrow.)

   .icon-arrow: a true arrow. The same border-corner head, smaller and mitered to
   a sharp point, plus a longer shaft for a lean, light silhouette (1px stroke,
   head 4.5, shaft 16). Means "go / onward": external links, forward navigation.
   Right by default; .is-left mirrors it. */
.icon-chevron {
  display: inline-flex; align-items: center; justify-content: center;
  width: 18px; height: 18px;
  line-height: 1; vertical-align: middle; font-size: 0;
}
.icon-chevron::before {
  content: ""; display: block;
  width: 6px; height: 6px;
  border-right: 1.5px solid currentColor;
  border-bottom: 1.5px solid currentColor;
}
.icon-chevron.is-down::before  { transform: rotate(45deg);  }
.icon-chevron.is-up::before    { transform: rotate(225deg); }
.icon-chevron.is-left::before  { transform: rotate(135deg); }
.icon-chevron.is-right::before { transform: rotate(-45deg); }

.icon-arrow {
  position: relative; display: inline-block;
  width: 16px; height: 8px;
  vertical-align: middle; font-size: 0;
}
.icon-arrow::before {   /* shaft — full length, closes the join to the head */
  content: ""; position: absolute; left: 0; top: 50%;
  transform: translateY(-50%);
  width: 16px; height: 1px; background: currentColor;
}
.icon-arrow::after {    /* head: one border-corner, mitered to a sharp point */
  content: ""; position: absolute; right: 0; top: 50%;
  width: 4.5px; height: 4.5px;
  border-right: 1px solid currentColor;
  border-bottom: 1px solid currentColor;
  transform: translateY(-50%) rotate(-45deg);
}
.icon-arrow.is-left { transform: scaleX(-1); }

/* Quiet overlay — sibling element, NOT opacity inheritance.
   Place .page-fade as a sibling of your page content (not a child).
   Setting body.modal-open fades it in. A native <dialog> paints in the
   top layer above this, so the modal stays sharp above the quiet page.
   Result: the page reads quiet off-white, not dimmed to gray. */
.page-fade {
  position: fixed; inset: 0;
  background: var(--overlay-quiet-bg);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--transition-fast);
  z-index: 90;
}
body.modal-open .page-fade { opacity: var(--overlay-quiet-opacity); }

/* =====================================================================
   STATE OVERRIDES
   Source-order tiebreak: states are declared after hover at equal
   specificity, so they win on both background and text. No !important.
   ===================================================================== */
/* THREE RULES IN THIS FILE ARE REACHED BY THE CLASSES WIDGET AND FULLY OVERRIDDEN BY IT.
   Measured 2026-08-16 by resolving the cascade (importance, specificity, source order) against
   the live document, not by reading computed values -- a transition or a backgrounded pane
   corrupts that read. They are NOT dead: they match real elements every load and would apply to
   any other consumer. They win nothing here, and that is the correct outcome -- the widget
   shipped and was looked at, so its values are the proven ones.
     .is-past                     -> beaten by index.html's .etp-day.is-past, .etp-day.is-beyond
     ul, ol (padding, list-style) -> beaten by index.html's .etp-classlist
     h1..h6 (font-weight: 500)    -> beaten by index.html's .etp-headline
   Recorded so the next reader does not re-derive it. Do not "fix" the widget to match.

   ONE PROPERTY OF .is-cancelled DOES WIN, AND NOBODY PLANNED IT. The widget overrides opacity
   and text-decoration on the row (.etp-class.is-cancelled) and on the status spans
   (.etp-class.is-cancelled .is-cancelled) -- but neither override sets pointer-events, so the
   bare rule below still supplies it to the status chips. Harmless today; it becomes a defect the
   moment someone edits those overrides believing they carry the whole state. They do not. */
.is-cancelled { opacity: 0.4; text-decoration: line-through; pointer-events: none; }
.is-past      { opacity: 0.5; pointer-events: none; }
