:root {
  --canvas: #F3EFE8; --surface: #FFFDF8;
  --text: #31211C; --text-soft: #675E59; --border: #DED6CC;
  --brown-deep: #463133; --brown-darkest: #2F211C;
  --orange: #FA7338; --orange-hover: #E85E27; --orange-soft: #F48E50;
  --yellow: #FBD129; --green: #1B804A; --green-dark: #1D6E50;
  --blue: #4896CC; --lime: #79CE53;
  /* The palette ran orange→yellow→green with no red, because nothing here had
     to say "gone" until batches could sell out. Pulled toward the brown end of
     red so it sits with the warm set instead of reading as a browser error;
     5.3:1 on the surface. */
  --red: #C4392C;
}
* { box-sizing: border-box; }

/* Every layout on this site is an INLINE style, and an inline `display` beats
   the UA's `[hidden] { display: none }` — so `el.hidden = true` painted nothing
   and the page rendered as if nothing were hidden at all. nitro.js drives the
   enroll wizard's steps, the success screen and the course pages' track panels
   entirely through the `hidden` property, so without this rule all four steps
   stacked on one page, the success screen sat under the form before payment,
   and both track tabs showed at once (fixed 2026-07-17). `!important` is what
   beats the inline style — same reason the breakpoint below needs it. */
[hidden] { display: none !important; }

body {
  margin: 0; background: var(--canvas);
  font-family: Inter, system-ui, sans-serif; color: var(--text);
  -webkit-font-smoothing: antialiased;
}
h1,h2,h3,h4 { font-family: 'Baloo 2', sans-serif; font-weight: 600; }
/* Only h1/h2 are tracked in the source; h3 declares no letter-spacing, so
   scoping this keeps 32px h3s from silently tightening by ~0.32px. */
h1,h2 { letter-spacing: -0.01em; }
a { color: var(--text); text-decoration: none; }
a:hover { color: var(--orange-hover); }

/* Form controls don't inherit body's font, and the source sets both of these
   explicitly in its <helmet> — without them the whole enroll form falls back
   to the UA face and loses the designed focus ring. */
input, select, textarea, button { font-family: Inter, system-ui, sans-serif; }
input:focus, select:focus, textarea:focus {
  outline: 2px solid var(--blue); outline-offset: 1px;
}
button:focus-visible, a:focus-visible {
  outline: 2px solid var(--blue); outline-offset: 2px;
}

/* --- mobile (source's breakpoint: collapse grids, drop the nav, shrink pad) ---
   Every layout in this site is an INLINE style, including the markup nitro.js
   injects at runtime — so these match on the declaration itself rather than on
   class hooks. That way a hydrated grid (the hero) collapses exactly like a
   static one; a class-hook approach would need the class mirrored into nitro.js
   and would silently miss anything it forgot. `!important` is required to beat
   the inline style.

   The trade-off is that a selector only matches its exact spelling — so
   test_build.test_every_grid_is_responsive enumerates every
   grid-template-columns in the tree and fails if one isn't handled here. Add a
   new grid shape → add it below, or the test goes red. */
@media (max-width: 900px) {
  /* two- and three-column → single column */
  [style*="grid-template-columns:1fr 1fr"],
  [style*="grid-template-columns:1fr 1.1fr"],
  [style*="grid-template-columns:1fr 1.4fr"],
  [style*="grid-template-columns:1.1fr 1fr"],
  [style*="grid-template-columns:1.15fr 1fr"],
  [style*="grid-template-columns:1.2fr 1fr"],
  [style*="grid-template-columns:1.6fr 1fr"],
  [style*="grid-template-columns:repeat(3,1fr)"],
  [style*="grid-template-columns:1fr 1px 1fr 1px 1fr"] {
    grid-template-columns: 1fr !important;
  }
  /* four- and five-up → two-up (the source keeps these paired, not stacked) */
  [style*="grid-template-columns:repeat(4,1fr)"],
  [style*="grid-template-columns:repeat(5,1fr)"] {
    grid-template-columns: repeat(2, 1fr) !important;
  }
  /* section gutters 40px → 20px (matches .section-pad in the source) */
  [style*="px 40px"] { padding-left: 20px !important; padding-right: 20px !important; }
  /* the sticky nav's own bar, whose shorthand starts at 0 and so isn't caught above */
  [style*="padding:0 40px"] { padding-left: 20px !important; padding-right: 20px !important; }
  /* nav links collapse; the logo and the Reserve-a-seat CTA stay */
  .nav-links { display: none !important; }
  /* hero card: the source drops its generous inset on mobile */
  [style*="padding:52px 96px 52px 64px"] { padding: 36px 28px !important; }
  /* the carousel arrows sit at -18px and would hang off a narrow viewport.
     `!important` is required here too: the unconditional `.ns-arrow--prev
     { left: -18px }` / `.ns-arrow--next { right: -18px }` pair lives further
     down this file at equal specificity, so on any viewport under 900px both
     rules are in scope and the later one in source order was winning,
     silently no-op'ing this override — the arrows rendered at -18px (half
     off-screen) at every mobile width, not just "a narrow" one. */
  .ns-arrow--prev { left: 4px !important; }
  .ns-arrow--next { right: 4px !important; }
  /* the order-summary sidebar stops being a sidebar once the wizard is 1-up */
  #ns-wizard aside { position: static !important; }
  /* enroll wizard stepper: 4 dot+label pairs plus 3 connecting rules in one
     non-wrapping flex row have a combined min-content width (~367px, from
     the un-shrinkable step-dots + the labels' longest words) that clears a
     390px viewport by only ~3px and overflows anything narrower (a 360px
     phone loses by ~27px, clipping every field below it since the grid
     track that holds the whole step is forced to that width). Tightening
     the row's own gap and dot size — not the copy — buys back the room
     without touching the label text or any other spacing on the page.
     `!important` for the same reason as the arrows above: `.ns-step-dot`'s
     unconditional 26px size rule lives later in this file at equal
     specificity. */
  [aria-label="Enrollment progress"] { gap: 6px !important; }
  .ns-step-dot { width: 20px !important; height: 20px !important; font-size: 10px !important; }
}

/* --- intro-video play button pulse (ported from source <helmet> style) --- */
@keyframes pulseplay {
  0%   { box-shadow: 0 0 0 0 rgba(250,115,56,.45); }
  70%  { box-shadow: 0 0 0 22px rgba(250,115,56,0); }
  100% { box-shadow: 0 0 0 0 rgba(250,115,56,0); }
}

/* --- FAQ accordion (native <details>, ported from source <helmet> style) --- */
details > summary { list-style: none; cursor: pointer; }
details > summary::-webkit-details-marker { display: none; }

/* --- interactive elements (replace source style-hover attributes) --- */
.nav-link { color: var(--text-soft); }
.nav-link:hover { color: var(--text); }
.nav-link--active { color: var(--text); font-weight: 600; }
.btn-primary { background: var(--orange); color: var(--surface); }
.btn-primary:hover { background: var(--orange-hover); color: var(--surface); }
.btn-dark { background: var(--brown-darkest); color: var(--surface); }
.btn-dark:hover { background: var(--text); color: var(--surface); }
.btn-secondary:hover { background: var(--canvas); }
.btn-outline-invert:hover { background: rgba(255,255,255,.12); }
/* Source has no inline background here, so its style-hover lifts the button to
   near-white against the canvas. A translucent brown wash resolves DARKER than
   the canvas — i.e. the opposite direction from the design. */
.btn-outline-dark:hover { background: var(--surface); }
/* The enroll wizard's "← Back" hovers to surface, not canvas — a different
   value from .btn-secondary's, which the landing/course pages rely on. */
.btn-back:hover { background: var(--surface); }
.btn-green { background: var(--green); color: var(--surface); }
.btn-green:hover { background: var(--green-dark); color: var(--surface); }
.course-card:hover { transform: translateY(-4px); }
.footer-next:hover { color: var(--orange-hover); }

/* --- hero carousel (source: prev/next arrows + expanding-pill dots) --- */
.ns-arrow {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 44px; height: 44px; border-radius: 50%;
  background: var(--surface); border: 1px solid var(--border);
  cursor: pointer; display: flex; align-items: center; justify-content: center;
  font-size: 17px; color: var(--text);
  box-shadow: 0 8px 24px -8px rgba(49,33,28,.25);
}
.ns-arrow:hover { background: var(--canvas); }
.ns-arrow--prev { left: -18px; }
.ns-arrow--next { right: -18px; }
/* The active dot is an expanding pill, not a colour swap — width is animated. */
.ns-dot {
  height: 9px; border: none; border-radius: 5px; cursor: pointer; padding: 0;
  width: 9px; background: var(--border); transition: width .25s;
}
.ns-dot[aria-current="true"] { width: 28px; background: var(--text); }
@media (prefers-reduced-motion: reduce) { .ns-dot { transition: none; } }

/* --- course-page track switcher (source: a segmented control, not accordions;
       exactly one track is ever shown) --- */
.ns-tabs {
  display: flex; background: var(--surface); border: 1px solid var(--border);
  border-radius: 8px; padding: 4px; gap: 4px;
}
.ns-tab {
  height: 38px; padding: 0 18px; border: none; border-radius: 6px;
  font-size: 13px; font-weight: 600; cursor: pointer;
  background: transparent; color: var(--text-soft);
}
.ns-tab[aria-selected="true"] { background: var(--text); color: var(--surface); }

/* --- enroll wizard (source: 4 steps + a success screen) --- */
.ns-step-dot {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 12px; font-weight: 700;
  background: var(--surface); border: 1px solid var(--border); color: var(--text-soft);
}
.ns-step-dot[data-state="current"] { background: var(--orange); color: var(--surface); border-color: var(--orange); }
.ns-step-dot[data-state="done"]    { background: var(--green);  color: var(--surface); border-color: var(--green); }
.ns-step-rule { flex: 1; height: 1px; background: var(--border); }
.ns-step-label { font-size: 13px; font-weight: 600; color: var(--text-soft); }
.ns-step-label[data-state="current"] { color: var(--text); }

/* Selected states use a 2px border where the resting state is 1px — matching
   the source. Both keep the same box-sizing, so nothing shifts. */
.ns-course-chip {
  display: flex; align-items: center; gap: 10px; height: 52px; padding: 0 16px;
  border-radius: 10px; font-size: 14px; font-weight: 600; cursor: pointer;
  text-align: left; background: var(--surface);
  border: 2px solid transparent; box-shadow: inset 0 0 0 1px var(--border);
  color: var(--text-soft);
}
.ns-course-chip[aria-pressed="true"] {
  border-color: var(--text); box-shadow: none; color: var(--text);
}
.ns-swatch { flex: none; width: 12px; height: 12px; border-radius: 4px; }

.ns-plan, .ns-batch {
  display: flex; flex-direction: column; align-items: stretch;
  cursor: pointer; text-align: left; color: var(--text);
  background: var(--surface);
  border: 2px solid transparent; box-shadow: inset 0 0 0 1px var(--border);
}
.ns-plan  { gap: 8px; padding: 18px; border-radius: 14px; }
.ns-plan[aria-pressed="true"], .ns-batch[aria-pressed="true"] {
  border-color: var(--orange);
  box-shadow: 0 8px 18px -6px rgba(250,115,56,.25);
}

/* --- start-date cards -------------------------------------------------
   A batch card is a leaf off a calendar: month eyebrow, the day in the display
   face, its weekday, and the seat state at the foot. The states are the whole
   point of the control, so they live here as classes rather than as inline
   colours nitro.js has to re-decide per card.

   `min-height` + the foot's `margin-top:auto` keep the row a clean band: the
   foot is a chip on one card, a word on the next and empty on a third, and
   without this the five cards end at five different heights. */
.ns-batch { gap: 7px; padding: 14px 12px 12px; border-radius: 14px; min-height: 128px;
  transition: transform .12s ease, box-shadow .12s ease, background-color .12s ease; }
.ns-batch-mon { font-size: 11px; font-weight: 700; letter-spacing: .8px; color: var(--text-soft); }
.ns-batch-day { font-family: 'Baloo 2', sans-serif; font-weight: 600; font-size: 34px; line-height: 1; }
.ns-batch-dow { font-size: 12px; color: var(--text-soft); }
.ns-batch-foot { margin-top: auto; }

/* Seat-fill bar: a 5px track that fills with the seats already TAKEN, so a
   parent reads scarcity at a glance before reading the number. Sits just above
   the seat count, pushed down by the foot's margin-top:auto. */
.ns-batch-bar {
  height: 5px; border-radius: 3px; background: var(--border);
  overflow: hidden; margin-top: auto;
}
.ns-batch-bar + .ns-batch-foot { margin-top: 8px; }
.ns-batch-fill { height: 100%; background: var(--orange); border-radius: 3px; }
.ns-batch[disabled] .ns-batch-fill { background: var(--text-soft); }

/* There was no hover at all: five cards that look like buttons and answer to
   nothing until clicked. */
.ns-batch:not([disabled]):hover {
  transform: translateY(-2px);
  box-shadow: inset 0 0 0 1px var(--orange-soft), 0 8px 16px -10px rgba(49,33,28,.35);
}
.ns-batch[aria-pressed="true"] { background: #FFF6F1; }
.ns-batch[aria-pressed="true"] .ns-batch-mon { color: var(--orange-hover); }
/* The global focus ring is blue — the one cool colour in a warm system, and it
   lands on the orange selected card. */
.ns-batch:focus-visible { outline-color: var(--orange); }

/* A full batch is shown but dead: dropped back onto the canvas with a dashed
   outline, the way a full date reads as "not available" on a calendar. */
.ns-batch[disabled] {
  background: var(--canvas); cursor: not-allowed;
  border: 2px dashed var(--border); box-shadow: none;
}
.ns-batch[disabled] .ns-batch-mon,
.ns-batch[disabled] .ns-batch-day,
.ns-batch[disabled] .ns-batch-dow { color: var(--text-soft); }

/* Seat count under the bar. Now that the bar carries the scarcity signal, the
   text is plain coloured copy (matching the handoff), not a badge: green when
   there's room, orange when it's running low, muted grey when it's full. */
.ns-seats-ok   { font-size: 11px; font-weight: 600; color: var(--green); }
.ns-seats-low  { font-size: 11px; font-weight: 600; color: var(--orange-hover); }
.ns-seats-out  { font-size: 11px; font-weight: 600; color: var(--text-soft); }

@media (prefers-reduced-motion: reduce) {
  .ns-batch { transition: none; }
  .ns-batch:not([disabled]):hover { transform: none; }
}
.ns-check {
  width: 22px; height: 22px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  font-size: 11px; font-weight: 700;
  background: var(--canvas); color: var(--canvas); border: 1px solid var(--border);
}
.ns-plan[aria-pressed="true"] .ns-check {
  background: var(--orange); color: var(--surface); border-color: var(--orange);
}

/* --- image placeholders -------------------------------------------------
   Shown only when no asset has been uploaded. The idiom is the one already
   used by the course-page video slot: a 45° hatch plus a monospace hint.
   A REAL image uses .ar--* alone and never .ph, so this chrome is never
   painted over an admin's photo — see the media_box template tag.
------------------------------------------------------------------------- */
.ph {
  display: block; width: 100%;
  position: relative; overflow: hidden;
  border-radius: 12px;
  background: rgba(49, 33, 28, .06);
}
.ph::before {
  content: ""; position: absolute; inset: 0;
  background: repeating-linear-gradient(45deg,
    rgba(49, 33, 28, .10) 0 10px, transparent 10px 20px);
}
/* On a dark accent (the hero slide and most course cards) the hatch inverts. */
.ph--on-dark { background: rgba(255, 255, 255, .10); }
.ph--on-dark::before {
  background: repeating-linear-gradient(45deg,
    rgba(255, 255, 255, .16) 0 10px, transparent 10px 20px);
}
/* The label chip renders only when a hint exists — an empty chip is worse
   than none, so key the whole rule off the attribute's presence. */
.ph[data-label]::after {
  content: attr(data-label);
  position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);
  background: #FFFDF8; color: #31211C;
  font-family: ui-monospace, Menlo, monospace; font-size: 11px; line-height: 1;
  padding: 5px 10px; border-radius: 4px; white-space: nowrap;
  box-shadow: 0 1px 3px rgba(49, 33, 28, .12);
}
/* Aspect ratios are independent of the placeholder chrome: a REAL image uses
   .ar--* alone. Keep the .ph--* aliases — templates author against them. */
.ph--1x1             { aspect-ratio: 1 / 1; }
.ar--4x3,  .ph--4x3  { aspect-ratio: 4 / 3; }
.ar--16x9, .ph--16x9 { aspect-ratio: 16 / 9; }
.ph--circle { border-radius: 50%; }
.ph--circle::after { display: none; }
