/* --------------------------------------------------------------------
   Self-hosted type -- LMS-Upgraded V1, Phase 2 (Design System
   Foundation). Replaces the Google Fonts @import that used to sit in
   every page <head> (see partials/header.php and admin/partials/
   layout-header.php) -- no external request, no fonts.googleapis.com/
   fonts.gstatic.com in the CSP at all anymore (.htaccess). Files are
   WOFF (not WOFF2) -- see the project notes on why, this build
   environment had no path to a Brotli encoder; still a self-hosted,
   zero-third-party-request, ~83% smaller-than-source-TTF result, and
   WOFF has effectively the same browser support footprint as WOFF2 for
   every browser this site needs to support. Re-run with a WOFF2
   encoder available and drop the extra `format('woff2')` src line in
   whenever convenient -- no other change needed anywhere in this file.
   -------------------------------------------------------------------- */
@font-face {
  font-family: 'Cinzel';
  src: url('../fonts/cinzel_regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Cinzel';
  src: url('../fonts/cinzel_bold.woff') format('woff');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Cormorant Garamond';
  src: url('../fonts/CormorantGaramond-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Cormorant Garamond';
  src: url('../fonts/CormorantGaramond-Italic.woff') format('woff');
  font-weight: 400;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Cormorant Garamond';
  src: url('../fonts/CormorantGaramond-Bold.woff') format('woff');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Cormorant Garamond';
  src: url('../fonts/CormorantGaramond-BoldItalic.woff') format('woff');
  font-weight: 700;
  font-style: italic;
  font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('../fonts/Montserrat-Regular.woff') format('woff');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}
@font-face {
  font-family: 'Montserrat';
  src: url('../fonts/Montserrat-Bold.woff') format('woff');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* --------------------------------------------------------------------
   Design tokens -- LMS-Upgraded V1, Phase 2 (Design System Foundation).
   Full rebrand, not a re-tint: names changed along with values because
   the old names (--ink, --parchment, --oxblood, --gilt) described the
   OLD palette's hues and would actively mislead a future maintainer if
   left in place pointing at new colors (var(--oxblood) rendering blue,
   for instance). Confirmed via a full-codebase search before renaming
   that every one of these tokens is only ever referenced from this
   file, pages/admin.css, and pages/lms.css -- no template anywhere
   reads them, so this rename has zero blast radius beyond those three
   files, all updated together in this same phase.

   --gilt from the old token set is not carried forward at all: it was
   declared but never once read via var(--gilt) anywhere in the
   codebase -- only its raw rgb() triplet was hand-copied into one
   badge rule in pages/lms.css. That rule now reads var(--gold)
   properly instead of a magic number that happened to match a token
   nothing else pointed to.

   One deliberate semantic split from the old system: --oxblood used to
   serve two unrelated jobs at once -- "the brand's interactive accent
   color" (hover states, focus rings, eyebrow labels) AND "the color
   for a form/validation error." Those are different concerns that
   shouldn't be forced to share one variable, especially now that the
   brand accent is blue: an error message rendered in the interactive-
   accent blue would read as a link or a call-to-action, not a warning.
   --error is its own token below, independent of the brand palette,
   and --royal-blue is reserved purely for interactive/brand-accent use.
   --gold is reserved purely for decorative/typographic accents
   (eyebrow labels, dividers) -- never for anything interactive -- so
   the two accents each mean one consistent thing across the whole
   site rather than blurring together.
   -------------------------------------------------------------------- */
:root {
  /* --------------------------------------------------------------------
     GKA [V1], Phase 8 (Performance, Accessibility & Compliance Pass).
     This block was rewritten this phase after an exhaustive audit
     found that, while every color pairing in this file had been
     verified against WCAG AA (4.5:1 normal text, 3:1 large text) as
     each was introduced across Phases 2, 5, and 7, several did NOT
     clear AAA (7:1 / 4.5:1) -- and §10 of the system spec states the
     WCAG conformance target as AAA explicitly, not AA. That's a real
     miss worth naming plainly rather than glossing over: AA was the
     bar actually being checked against turn to turn; AAA was the bar
     the spec asked for from the start. Every token below is rechecked
     against AAA specifically, with the exact numbers in each token's
     own comment, not just asserted.

     Worth understanding going in, not as an excuse but as context: full
     AAA compliance sitewide is explicitly NOT something WCAG itself
     recommends as a blanket target (the W3C's own Understanding
     WCAG 2.1 guidance says AAA "is not required for entire sites" as a
     general matter) -- there is real design cost here, and it shows up
     concretely below: --gold-dark had to move from a warm gold-brown
     toward a noticeably more olive/brown tone (gold is an inherently
     light, high-luminance hue family, which is fundamentally in
     tension with how dark AAA requires small text to be), and the two
     old "muted text" tiers (--charcoal-65 at 4.9:1, --charcoal-70 at
     5.75:1 -- both comfortably AA, both short of 7:1) had to collapse
     into a single darker --charcoal-muted, because AAA leaves no
     headroom below ~76% charcoal for a text color to exist at all.
     "Secondary/muted text" as a visual category gets measurably closer
     in weight to primary text under AAA than it would under AA -- that
     is the actual, visible trade this phase makes across every page
     already built, in exchange for meeting a target the spec asked for
     explicitly and repeatedly (§10, and again in the type-scale notes:
     "Body copy remains at 18px to guarantee WCAG AAA readability").
     -------------------------------------------------------------------- */
  --royal-blue: #105bae;      /* the spec's literal authoritative brand hex -- kept for the one large-text use (endowment.php numerals) and for focus-ring outlines (non-text UI, held to a different, already-cleared WCAG criterion) -- see --royal-blue-text below for where AAA required moving off this value instead */
  --royal-blue-dark: #0c4488; /* hover/active shade -- 9.09:1 on --cream, already cleared AAA before this phase, unchanged */
  --gold: #c29b0c;            /* decorative-only, never for text -- unchanged, still 2.5:1 on --cream */
  /* --gold-dark darkened from #7e6407 (5.38:1 -- AA only) to clear
     AAA: 7.72:1 on --cream, 7.11:1 against the badge-in_progress tint
     background (assets/css/pages/lms.css) -- both with real margin.
     This is the one token where the AAA-mandated darkening is most
     visually noticeable: #614e06 reads as a muted olive-bronze, not a
     bright gold, in a way #7e6407 didn't quite. Kept in the gold
     family deliberately rather than abandoned for an unrelated hue --
     see this block's header comment. */
  --gold-dark: #614e06;
  --cream: #fbf9f5;
  --charcoal: #222222;
  /* --error darkened from #9b2226 (6.82:1 against its own 6%-tint
     background -- just short of AAA) to #932024, 7.29:1 against that
     same tint, 8.05:1 directly on --cream. Barely perceptible change. */
  --error: #932024;
  /* --success darkened from #3A6E42 (5.28:1 against its own tint --
     the furthest off AAA of any single-use token in this file) to
     #2d5633, 7.41:1 against that tint, 8.03:1 directly on --cream.
     LMS-Upgraded V1 note: this codebase's own pages/lms.css had three
     places that hardcoded #3A6E42 directly rather than referencing
     var(--success) at all -- all three now reference the variable
     instead, both to pick up this fix and so a future change here
     doesn't require hunting for copies again. */
  --success: #2d5633;
  /* --royal-blue-text, new this phase: #0e529d, a ~10% darker step
     from the spec's own #105bae -- 7.38:1 on --cream, and (since
     contrast is symmetric) 7.38:1 for cream text ON this color too,
     which matters because .btn-primary's resting/default state needed
     to pass AAA on its own, not just on :hover -- --royal-blue-dark
     already cleared AAA, but the button's DEFAULT fill didn't before
     this existed. Used everywhere royal-blue appears as normal-sized
     text, a link, or any fill with text on top of it (buttons, the
     nav CTA). True --royal-blue is kept for the one large-text use in
     this codebase (endowment.php's --endowment-value, 2-3rem numerals,
     clamp()'d well past the 18px/24px AAA large-text threshold, so it
     already clears the more lenient 4.5:1 large-text bar at 6.38:1
     without needing to move at all) -- preserving the spec's literal
     authoritative hex everywhere AAA's own rules actually permit it,
     rather than replacing it site-wide for a fix only some of its uses
     needed. */
  --royal-blue-text: #0e529d;

  /* --charcoal-65 and --charcoal-70 (4.9:1 and 5.75:1 on --cream --
     both solid AA, both short of AAA's 7:1) are retired and merged
     into one token: AAA leaves no room for two visually-distinct
     "muted" tiers the way AA did -- anything lighter than ~76%
     charcoal fails outright, so there was nothing left to
     differentiate two steps with. Every previous --charcoal-65 and
     --charcoal-70 reference across this file, assets/css/pages/site.css,
     assets/css/pages/lms.css, and assets/css/pages/admin.css now points
     at this single token instead. */
  --charcoal-muted: #525150; /* 7.51:1 on --cream, 7.90:1 on white */
  --charcoal-15: rgba(34, 34, 34, 0.15); /* border/non-text UI only -- WCAG's non-text contrast criterion (1.4.11) is AA-only with no AAA equivalent, so this never needed to move */
  --charcoal-50: rgba(34, 34, 34, 0.5);  /* same -- border/non-text UI only */

  --font-display: 'Cinzel', Georgia, serif;             /* institutional headings */
  --font-serif: 'Cormorant Garamond', Georgia, serif;   /* editorial/long-form serif -- see assets/css/pages/lms.css header for where this comes into play */
  --font-body: 'Montserrat', system-ui, sans-serif;
  /* Renamed from the old --font-mono: nothing on this site was ever
     actually monospaced -- IBM Plex Mono was used purely decoratively
     for small-caps, letter-spaced "label" text (eyebrows, table
     headers, badges). Montserrat Bold does that job on-brand; the old
     name would have been actively confusing attached to a sans-serif. */
  --font-label: 'Montserrat', system-ui, sans-serif;
}

* { box-sizing: border-box; }

body {
  margin: 0;
  background: var(--cream);
  color: var(--charcoal);
  font-family: var(--font-body);
  line-height: 1.5;
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    transition-duration: 0.001ms !important;
  }
}

a { color: inherit; }
img { max-width: 100%; display: block; }

.container { max-width: 72rem; margin: 0 auto; padding: 0 1.5rem; }
.container-narrow { max-width: 42rem; margin: 0 auto; padding: 0 1.5rem; }

/* GKA [V1], Phase 8 (Performance, Accessibility & Compliance Pass):
   this used to be :focus-visible only. §11 of the system spec requires
   graceful support on Android platforms up to 7 years old, and
   :focus-visible reached broad browser support only around 2020-2021 --
   an older, unpatched mobile browser simply doesn't match that
   selector at all, which meant EVERY .focus-ring element (every button,
   every link styled this way across both sites) could render with
   NO visible focus indicator whatsoever on exactly the browsers this
   spec calls out by name. That's worse than showing a ring on a mouse
   click; it's the "Keyboard Focus Strategy" §10 describes not existing
   at all for part of the target audience.

   Fixed with a standard progressive-enhancement pattern: the base
   :focus rule (universally supported, works on every browser this
   spec needs to support) is the guaranteed fallback. @supports
   selector(:focus-visible) then refines that experience only for
   browsers that actually support it -- suppressing the ring for a
   mouse click there, same clean behavior as before, while every older
   browser still gets a visible ring on every focus event rather than
   none at all. */
.focus-ring:focus {
  outline: 2px solid var(--royal-blue);
  outline-offset: 3px;
}
@supports selector(:focus-visible) {
  .focus-ring:focus:not(:focus-visible) {
    outline: none;
  }
  .focus-ring:focus-visible {
    outline: 2px solid var(--royal-blue);
    outline-offset: 3px;
  }
}

/* Skip-to-content link: invisible until keyboard-focused, then jumps
   above everything else so a keyboard/screen-reader user isn't forced
   to tab through the full nav on every single page. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  z-index: 1000;
  background: var(--charcoal);
  color: var(--cream);
  padding: 0.75rem 1.25rem;
  font-family: var(--font-label);
  font-weight: 700;
  font-size: 0.85rem;
  text-decoration: none;
}
.skip-link:focus {
  left: 1rem;
  top: 1rem;
  outline: 2px solid var(--royal-blue);
  outline-offset: 2px;
}

/* Header -- LMS-Upgraded V1, Phase 2: solid fill, no backdrop-filter.
   The brand's "border-only depth, no glassmorphism" principle rules
   out the translucent-blur header the old design used; a plain
   opaque cream fill with a hairline border reads just as crisp and
   costs nothing on low-end GPUs (backdrop-filter is not free). */
.site-header {
  position: sticky; top: 0; z-index: 40;
  background: var(--cream);
  border-bottom: 1px solid var(--charcoal-15);
}
.site-header .inner {
  display: flex; align-items: center; justify-content: space-between;
  height: 4rem;
}
.brand { display: flex; align-items: center; gap: 0.65rem; text-decoration: none; }
.brand-crest { flex-shrink: 0; }
.brand-wordmark { display: flex; flex-direction: column; line-height: 1.15; }
.brand-name { font-family: var(--font-display); font-weight: 700; font-size: 1.05rem; letter-spacing: 0.01em; }
.brand-tag { font-family: var(--font-label); font-weight: 700; font-size: 0.6rem; letter-spacing: 0.15em; text-transform: uppercase; color: var(--gold-dark); }
.nav-links { display: flex; gap: 2rem; font-size: 0.9rem; }
.nav-links a { text-decoration: none; }
.nav-links a:hover { color: var(--royal-blue-text); }
.nav-cta {
  display: none;
  background: var(--royal-blue-text); color: var(--cream);
  padding: 0.5rem 1rem; font-size: 0.75rem; text-decoration: none;
}
.nav-cta:hover { background: var(--royal-blue-dark); }
@media (max-width: 640px) {
  .nav-links { display: none; }
  .nav-cta { display: inline-block; }
}

/* Buttons */
.btn {
  display: inline-block; text-decoration: none; font-size: 0.9rem; font-weight: 700;
  padding: 0.75rem 1.5rem; border: 1px solid transparent; cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease;
}
.btn-primary { background: var(--royal-blue-text); color: var(--cream); }
.btn-primary:hover { background: var(--royal-blue-dark); }
.btn-outline { border-color: var(--charcoal-15); color: var(--charcoal); background: transparent; }
.btn-outline:hover { border-color: var(--royal-blue-text); color: var(--royal-blue-text); }

/* Hero */
.hero { padding: 4rem 0 2rem; }
.hero .eyebrow { font-family: var(--font-label); font-weight: 700; text-transform: uppercase; letter-spacing: 0.2em; font-size: 0.75rem; color: var(--gold-dark); }
.hero h1 {
  font-family: var(--font-display);
  /* GKA [V1], Phase 8: fallback font-size declared before the clamp()
     line, not instead of it -- a browser that can't parse clamp() (per
     §11's legacy-Android requirement) ignores that whole declaration
     and keeps this earlier plain value instead of falling through to
     an unstyled default; a browser that CAN parse it uses the more
     specific, later clamp() value as normal. Same pattern applied
     everywhere else clamp() is used in this codebase (endowment.php's
     --endowment-value, the Command Palette's --search-input). */
  font-size: 3rem;
  font-size: clamp(2rem, 5vw, 3.75rem);
  line-height: 1.1; max-width: 42rem; margin: 1rem 0;
}
.hero p { max-width: 34rem; color: var(--charcoal-muted); font-size: 1.1rem; }
.hero .actions { display: flex; gap: 1rem; margin-top: 2rem; flex-wrap: wrap; }
.hero-image-wrap { margin-top: 2.5rem; }
.hero-image { width: 100%; max-height: 28rem; object-fit: cover; border: 1px solid var(--charcoal-15); }

/* Ticker (signature element) */
.ticker-wrap { margin-top: 3rem; background: var(--charcoal); overflow: hidden; border-top: 1px solid var(--charcoal-15); border-bottom: 1px solid var(--charcoal-15); padding: 0.75rem 0; }
.ticker-track { display: flex; width: max-content; gap: 2.5rem; animation: ticker 32s linear infinite; }
.ticker-track:hover { animation-play-state: paused; }
.ticker-track span { font-family: var(--font-label); font-weight: 700; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.2em; color: rgba(251, 249, 245, 0.7); white-space: nowrap; }
@keyframes ticker { from { transform: translateX(0); } to { transform: translateX(-50%); } }

/* Program cards */
.program-grid { display: grid; gap: 1.5rem; grid-template-columns: repeat(auto-fill, minmax(260px, 1fr)); margin-top: 2rem; }
.program-card {
  display: block; text-decoration: none; color: inherit;
  border: 1px solid var(--charcoal-15); background: #fff;
  transition: border-color 0.15s ease; overflow: hidden;
}
.program-card:hover { border-color: var(--royal-blue-text); }
.program-card-img { width: 100%; height: 10rem; object-fit: cover; display: block; }
.program-card-body { padding: 1.5rem; }
.program-card .meta { display: flex; justify-content: space-between; font-family: var(--font-label); font-weight: 700; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--charcoal-muted); }
.program-card h3 { font-family: var(--font-display); font-size: 1.25rem; margin: 0.75rem 0 0.5rem; }
.program-card:hover h3 { color: var(--royal-blue-text); }
.program-card p { font-size: 0.9rem; color: var(--charcoal-muted); margin: 0; }
.program-card .duration { font-family: var(--font-label); font-weight: 700; font-size: 0.75rem; color: var(--charcoal-muted); margin-top: 1rem; }

/* Sections */
.section { padding: 3.5rem 0; }
.section-head { display: flex; align-items: baseline; justify-content: space-between; flex-wrap: wrap; gap: 1rem; }
.section h2 { font-family: var(--font-display); font-size: 1.6rem; margin: 0; }

/* Program detail */
.stat-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1.5rem; border-top: 1px solid var(--charcoal-15); border-bottom: 1px solid var(--charcoal-15); padding: 1.5rem 0; margin: 2rem 0; }
@media (min-width: 640px) { .stat-grid { grid-template-columns: repeat(4, 1fr); } }
.stat-label { font-family: var(--font-label); font-weight: 700; font-size: 0.65rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--charcoal-muted); }
.stat-value { font-family: var(--font-display); font-size: 1.1rem; font-weight: 700; margin-top: 0.25rem; }

/* Forms */
.field { display: block; margin-bottom: 1.5rem; }
.field-label { font-family: var(--font-label); font-weight: 700; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.08em; color: var(--charcoal-muted); display: block; margin-bottom: 0.35rem; }
.field input, .field select, .field textarea {
  width: 100%; border: 1px solid var(--charcoal-15); background: #fff;
  padding: 0.6rem 0.75rem; font-family: var(--font-body); font-size: 0.95rem; color: var(--charcoal);
}
.field textarea { resize: vertical; }
.form-grid { display: grid; gap: 1.5rem; }
@media (min-width: 640px) { .form-grid.two-col { grid-template-columns: 1fr 1fr; } }

.alert { padding: 0.9rem 1.1rem; border: 1px solid; font-size: 0.9rem; margin-bottom: 1.5rem; }
.alert-error { border-color: rgba(155, 34, 38, 0.4); background: rgba(155, 34, 38, 0.06); color: var(--error); }
.alert-success { border-color: rgba(58,110,66,0.4); background: rgba(58,110,66,0.06); color: var(--success); }

/* LMS-Upgraded V1, Phase 4. A deliberately heavier variant of
   .alert-error, reserved for the "this is your final attempt" warning --
   solid fill and bold text rather than a light tint, so it reads as
   meaningfully more serious than a routine form-validation error at a
   glance, not just the same style with different words. */
.alert-high-contrast { background: var(--error); border-color: var(--error); color: #fff; font-weight: 700; padding: 1.1rem 1.3rem; }

/* Footer */
.site-footer { border-top: 1px solid var(--charcoal-15); margin-top: 6rem; }
.footer-grid { display: grid; gap: 2rem; padding: 3rem 0; font-size: 0.9rem; }
@media (min-width: 640px) { .footer-grid { grid-template-columns: repeat(3, 1fr); } }
.footer-grid h4 { font-family: var(--font-label); font-weight: 700; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.1em; color: var(--charcoal-muted); margin: 0 0 0.5rem; }
.footer-grid p, .footer-grid li { color: var(--charcoal-muted); }
.footer-grid ul { list-style: none; padding: 0; margin: 0; }
.copyright { border-top: 1px solid var(--charcoal-15); text-align: center; padding: 1rem 0; font-family: var(--font-label); font-weight: 700; font-size: 0.7rem; color: var(--charcoal-muted); display: flex; align-items: center; justify-content: center; gap: 0.5rem; }
.copyright-crest { opacity: 0.7; }

.prose { max-width: 42rem; color: var(--charcoal-muted); }
.prose p { margin-bottom: 1rem; }
