/* NLH Equestrian — page layout.
   Direction A ("Industry") from the design handoff.

   Every colour, font, space and radius comes from css/styles.css, which is the
   source of truth. Nothing here hard-codes a hex or a px value that a token
   already carries; the literal px values below are type sizes and grid widths
   the handoff specifies directly.

   The handoff's prototype carried its layout in inline styles so both visual
   directions could live in one document. Here that layout is lifted into
   classes — same computed result, editable in one place. */

/* ── page frame ───────────────────────────────────────────────────────────
   The prototype drew each screen inside a 1240px frame. On the real site that
   is the desktop max content width. */
.page { max-width: 1240px; margin: 0 auto; }
.page-body { padding: var(--space-8); }

body { margin: 0; text-wrap: pretty; }

/* Skip link — visible only on keyboard focus. */
.skip {
  position: absolute; left: -9999px; top: 0; z-index: 10;
  padding: var(--space-2) var(--space-4);
  background: var(--color-accent); color: var(--color-bg);
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  text-decoration: none;
}
.skip:focus { left: 0; }

/* ── header ───────────────────────────────────────────────────────────── */
.nav {
  padding: var(--space-4) var(--space-8);
  border-bottom: 1px solid var(--color-divider);
  gap: var(--space-6);
  flex-wrap: wrap;
  row-gap: var(--space-3);
}
.nav-brand { letter-spacing: 0.06em; text-transform: uppercase; }
.nav-brand a { color: inherit; text-decoration: none; }
/* The active page lights up in the base steel accent and carries a 2px rule
   beneath it. Every link reserves that rule in transparent so nothing shifts
   when the active page changes.

   The base accent measures 3.7:1 on this ground — below the 4.5:1 that 14px
   text wants. The underline is why that is acceptable here: selection is not
   carried by colour alone, and the label is still legible. Dropping the colour
   to --color-accent-700 returns it to 5.8:1 if the lighter blue reads as too
   faint on a real screen. */
.nav > a { border-bottom: 2px solid transparent; padding-bottom: 3px; }
.nav > a[aria-current='page'] {
  color: var(--color-accent);
  border-bottom-color: var(--color-accent);
}
@media (max-width: 720px) {
  .nav { gap: var(--space-4); }
  .nav-brand { flex: 1 0 100%; margin-right: 0; }
}

/* ── footer ───────────────────────────────────────────────────────────── */
.site-footer {
  padding: var(--space-4) var(--space-8);
  border-top: 1px solid var(--color-divider);
  display: flex; gap: var(--space-4); flex-wrap: wrap;
  font-size: 12px;
}
.site-footer .footer-lead { margin-right: auto; }

/* ── headings ─────────────────────────────────────────────────────────────
   The handoff sets h1 to 58px on Home and 52px on the interior pages. Those
   are the desktop values; the clamp scales them down on narrow viewports,
   which the prototype did not have to do. */
.h1-hero { font-size: clamp(38px, 5.4vw, 58px); margin-bottom: var(--space-4); }
.h1-page { font-size: clamp(36px, 5vw, 52px); }
.measure-20 { max-width: 20ch; }

/* ── section rules ────────────────────────────────────────────────────────
   Sections are separated by a 1px divider with a space-8 gutter either side. */
.rule-top {
  margin-top: var(--space-8);
  padding-top: var(--space-8);
  border-top: 1px solid var(--color-divider);
}
.rule-top-tight { /* Home's discipline row: the hero already pads below it */
  padding-top: var(--space-8);
  border-top: 1px solid var(--color-divider);
}

/* ── grids ────────────────────────────────────────────────────────────── */
.grid-2, .grid-3, .grid-4 { display: grid; gap: var(--space-6); }
.grid-2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
.grid-4 { grid-template-columns: repeat(4, minmax(0, 1fr)); }
.gap-8 { gap: var(--space-8); }
.mt-3 { margin-top: var(--space-3); }
.mt-4 { margin-top: var(--space-4); }
.mt-6 { margin-top: var(--space-6); }
.mt-8 { margin-top: var(--space-8); }

/* Home hero: two equal columns, copy left, photograph right.
   minmax(0, 1fr) rather than 1fr throughout: a bare 1fr track carries an
   implicit min-width:auto, so any child with a min-width (the scrollable
   tables) would widen the whole column instead of scrolling inside itself. */
.hero-grid {
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--space-8); align-items: center;
  padding-bottom: var(--space-8);
}
.hero-lead { font-size: 17px; max-width: 46ch; }

/* The home hero photo, in the same 4:3 frame the placeholder used, zoomed 20%
   and centred on the middle of the horse and jump.

   The photo is wider than the frame, so the sides are cropped and a 28%
   position centres the group left-to-right (it spans 20.6%-69.6% across). Top
   to bottom it runs from the rider's helmet at 15.8% to the jump's base at
   92.3%, centred at 54% — below the frame's middle, and with no vertical crop
   to move it, the zoom origin does the job: 74% puts that 54% point dead centre.
   After zooming the group fills ~92% of the frame's height, so the helmet and
   the base rails each keep ~4% clearance — that is the limit of how far in
   this can zoom without cropping the rider or the jump. */
.home-photo-crop { overflow: hidden; aspect-ratio: 4 / 3; }
.home-photo img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: 28% 50%;
  transform: scale(1.2); transform-origin: 50% 74%;
}

/* An interior page's title beside a photograph. Unlike .hero-grid this does
   NOT flip the figure above the copy on a phone — on a page the reader landed
   on deliberately, the heading should still come first. */
.page-hero {
  /* 5:7, not 1:1 — the title is capped at 20ch and does not need half the
     page, so the frame reaches further left toward it */
  display: grid; grid-template-columns: minmax(0, 5fr) minmax(0, 7fr);
  gap: var(--space-8);
  align-items: end; /* not centred: the title sits on the image's baseline so
     both columns leave the same gap above whatever follows */
  padding-bottom: var(--space-4);
}

.hero-actions { display: flex; gap: var(--space-3); margin-top: var(--space-6); flex-wrap: wrap; }

/* Trainer: fixed portrait column beside the bio. */
.trainer-grid { display: grid; grid-template-columns: 400px minmax(0, 1fr); gap: var(--space-8); }
.trainer-lead { font-size: 17px; max-width: 58ch; }
/* the closing note under the bio — deliberately a step down from the two
   17px bio paragraphs, so it reads as an addendum rather than a third beat */
.trainer-body { max-width: 58ch; font-size: 14px; margin-top: var(--space-4); }

/* The trainer photo fills the same 3:4 frame the placeholder did, so the page
   layout does not move. The corner marks stay outside the frame as before. */
/* the crop box clips the zoom; the figure itself can't, or it would clip the
   registration marks that sit just outside its edges */
.trainer-photo-crop { overflow: hidden; aspect-ratio: 3 / 4; }
.trainer-photo img {
  display: block; width: 100%; height: 100%;
  object-fit: cover;
  /* framed a little low, so a strip of ground shows below the rails */
  object-position: 50% 58%;
  /* zoomed 20%. The photo fills the frame's width exactly, so object-position
     can't move it sideways — the zoom origin does that instead. Every 1% the
     origin moves shifts the picture 0.2% the other way. 73% balances the
     horse's body near the middle, with the helmet just right of centre. */
  transform: scale(1.2); transform-origin: 73% 52%;
}

/* The Lessons photo, in the same 2:1 frame the placeholder used.
   The three horses span 9%-84% across the photo, so their group centre sits at
   46.5% — left of middle. The photo fills the frame's width exactly, so a small
   zoom is the only way to slide it: at 1.1x with an 11.5% origin the group
   lands centred, with ~9% clear either side. Vertically, a 68% crop position
   and a 50% origin leave ~14% of sky above the lead rider's helmet and the
   bay's hooves ~6% clear of the bottom — the hooves are the limit on how much
   more sky can come in. */
.lessons-photo-crop { overflow: hidden; aspect-ratio: 2 / 1; }
.lessons-photo img {
  display: block; width: 100%; height: 100%;
  object-fit: cover; object-position: 50% 68%;
  transform: scale(1.1); transform-origin: 11.5% 50%;
}

/* Contact: two equal columns. */
.contact-grid { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: var(--space-8); }

/* ── photographs ──────────────────────────────────────────────────────────
   Every photo slot now holds a real photograph (.home-photo, .trainer-photo,
   .lessons-photo); the striped placeholder styles that stood in for them are
   gone. Photos are full colour. The system's own treatment would be to add
   `duotone` to the figure, which washes the photograph into the steel accent. */
figure.blueprint { padding: 0; }

/* ── Home: the three program blocks ───────────────────────────────────────
   Unboxed. The system's rule is that a *framed* element never drops its
   registration marks — not that everything must be framed — so these read as
   plain columns separated by air. The gutter opens a step to compensate for
   the missing border, and the type sits one step up from the card scale
   (20px / 15px rather than 17px / 13px) now that it carries the block alone. */
.programs { gap: var(--space-8); }
.program-title {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 20px; line-height: 1.2; letter-spacing: -0.015em;
  margin: 0;
}
.program p {
  font-size: 15px; line-height: 1.6;
  margin: var(--space-2) 0 0;
  color: color-mix(in srgb, var(--color-text) 78%, transparent);
}

/* ── Home: testimonials ───────────────────────────────────────────────────
   The system's .card-body runs at 13px, which is too quiet for a quote
   carrying the section. Set here rather than inline on each of the three
   cards, so the size is one edit and cannot drift between them. */
.testimonials .card-body { font-size: 16px; }

/* ── Lessons: prices ──────────────────────────────────────────────────── */
.price {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 48px; line-height: 1;
}
.price .unit { font-size: 16px; }

/* ── Lessons: the arrival panels ──────────────────────────────────────────
   The most important content on the site. Two states, stated plainly. */
.panel { padding: var(--space-4); }
.panel-lead {
  font-size: 20px; font-family: var(--font-heading);
  font-weight: var(--font-heading-weight);
  margin-bottom: var(--space-2);
}
.panel p:last-child { font-size: 14px; margin: 0; }

/* ── The rider levels ─────────────────────────────────────────────────────
   Static rows, everything visible at once — no accordion, nothing to open.
   Rows keep the hairline rules of the table this replaced.

   The skill boxes are display-only — square markers, not form controls. They
   were real checkboxes at one point; that was dropped because nothing stored
   the ticks. Rendering them as decoration (rather than disabled inputs) keeps
   them out of the tab order and stops screen readers announcing controls that
   cannot be operated. */
.levels { border-top: 1px solid var(--color-divider); }

/* Two fixed columns rather than a flex row: the label column holds its width
   whatever the tag says, so every description starts on the same left axis
   instead of being pushed around by "Intro" vs "Intermediate". */
.level {
  display: grid;
  grid-template-columns: 13rem minmax(0, 1fr); /* fits the widest starred ribbon label */
  gap: var(--space-6);
  padding: var(--space-4) var(--space-2);
  border-bottom: 1px solid color-mix(in srgb, var(--color-text) 14%, transparent);
}
/* each ribbon title sits centred in its cell, both ways — the cell is as tall
   as the level's checklist, so the title lands level with its middle row */
.level-label { display: flex; align-items: center; justify-content: center; }

.checklist {
  list-style: none; margin: 0; padding: 0;
  display: grid; grid-template-columns: repeat(2, minmax(0, 1fr));
  /* an even GAP, not even row heights — forcing rows to a common height just
     parks whitespace under the short ones. Rows size to their text and the
     space between them stays constant, which is what reads as evenly spread. */
  gap: var(--space-4) var(--space-8);
}
.checklist li {
  display: flex; align-items: flex-start; gap: var(--space-3);
  font-size: 14px; line-height: 1.45;
}
.checklist .box {
  width: 16px; height: 16px; flex: none; margin: 2px 0 0;
  background: transparent; border: 1.5px solid var(--color-divider);
  border-radius: 0; /* square, like every other box in this system */
}

@media (max-width: 640px) {
  /* no room for a label column on a phone — the tag sits above its text */
  .level { grid-template-columns: minmax(0, 1fr); gap: var(--space-3); }
  .checklist { grid-template-columns: minmax(0, 1fr); }
}

/* a row of actions — wraps rather than overflowing on a phone */
.btn-row { display: flex; gap: var(--space-3); flex-wrap: wrap; }

/* ── the cancellation table ───────────────────────────────────────────────
   The design system tints a table row on hover, which reads as "this is
   clickable". These rows are a printed policy, not an interactive grid —
   nothing happens when you click one, so nothing should respond to the
   pointer either. */
#cancellation .table tbody tr:hover { background: none; }

/* ── the ribbon wall ──────────────────────────────────────────────────────
   Seven rosettes hung from a sagging cord, one per level, drawn as a single
   SVG so the cord and the ribbons stay registered to each other at any width.
   The hang points are sampled off the same quadratic the cord is drawn with,
   which is why the middle ribbons sit lower — they hang where the cord dips.

   All greyed. Each rosette keeps its own --ribbon colour, so a rider's earned
   levels light up by adding .is-earned — no new markup or colours needed.

   Every shape carries a hairline stroke, which is what keeps the white ribbon
   visible on the paper ground once it is earned. */
/* Sits between the page title and the code box, taking whatever width is left
   between them. Pulled up by the body's own padding so the cord hangs off the
   rule under the masthead with no gap above it.

   The script sets the viewBox to the live pixel width, so one SVG unit is one
   pixel: the ribbons stay a fixed size at every screen width and only their
   spacing and the depth of the arc change. */
.ribbon-wall {
  flex: 1 1 380px; max-width: 560px;
  align-self: flex-start;
  margin-top: calc(var(--space-8) * -1);
}
.ribbon-wall svg { display: block; width: 100%; height: auto; }

.wall-cord {
  fill: none;
  stroke: color-mix(in srgb, var(--color-text) 38%, transparent);
  stroke-width: 2.5; stroke-linecap: round;
}
.wall-hook { fill: color-mix(in srgb, var(--color-text) 52%, transparent); }

.wall-ribbon { color: var(--color-neutral-400); }
.wall-ribbon.is-earned { color: var(--ribbon); }

/* the streamers, and the pleated disc that sits over them */
.wall-ribbon .wr-tail,
.wall-ribbon .wr-pleat {
  fill: currentColor;
  stroke: color-mix(in srgb, var(--color-text) 22%, transparent);
  stroke-width: 0.8; stroke-linejoin: round;
}
.wall-ribbon .wr-tail { opacity: 0.92; }
.wall-ribbon .wr-tail-mid { opacity: 1; }
/* the inner rosette sits a shade deeper than the outer one */
.wall-ribbon .wr-pleat-in { fill: color-mix(in srgb, #000 12%, currentColor); stroke: none; }
/* fold lines, kept faint — at this size they read as texture, not as drawing */
.wall-ribbon .wr-folds {
  fill: none; stroke: color-mix(in srgb, #000 16%, transparent); stroke-width: 0.7;
}
/* the white centre medallion */
.wall-ribbon .wr-medallion {
  fill: var(--color-bg);
  stroke: color-mix(in srgb, var(--color-text) 22%, transparent); stroke-width: 0.9;
}
.wall-ribbon .wr-button { fill: currentColor; opacity: 0.55; }
.wall-ribbon .wr-knot { fill: color-mix(in srgb, var(--color-text) 50%, transparent); }

.wall-ribbon-purple { --ribbon: #6a3d9a; }
.wall-ribbon-green  { --ribbon: #2e7d32; }
.wall-ribbon-pink   { --ribbon: #d81b7a; }
.wall-ribbon-white  { --ribbon: #ffffff; }
.wall-ribbon-yellow { --ribbon: #d4a017; }
.wall-ribbon-red    { --ribbon: #c62828; }
.wall-ribbon-blue   { --ribbon: #1256a3; }

/* ── ribbon level labels ──────────────────────────────────────────────────
   Each level is named for a show ribbon, so the colour carries meaning here
   rather than decorating — which is why this is the one place the system's
   "no colour beyond the steel accent" rule is set aside.

   White and yellow are too pale to read as a line on this ground, so both
   get a dark hairline beneath the rule and an outline on the stars. Without
   that the white ribbon is invisible. */
.ribbon {
  display: inline-flex; align-items: center; gap: var(--space-2);
  white-space: nowrap; /* keeps the stars hugging the phrase */
  font-size: 12px; letter-spacing: 0.01em;
  padding-bottom: 4px;
  border-bottom: 2px solid var(--ribbon);
}
.ribbon .star { color: var(--ribbon); font-style: normal; font-size: 10px; line-height: 1; }

.ribbon-purple { --ribbon: #6a3d9a; }
.ribbon-green  { --ribbon: #2e7d32; }
.ribbon-pink   { --ribbon: #d81b7a; }
.ribbon-white  { --ribbon: #ffffff; }
.ribbon-yellow { --ribbon: #d4a017; }
.ribbon-red    { --ribbon: #c62828; }
.ribbon-blue   { --ribbon: #1256a3; }

/* the pale two: a hairline under the rule, and a stroke around the stars */
.ribbon-white, .ribbon-yellow { box-shadow: 0 1px 0 color-mix(in srgb, var(--color-text) 28%, transparent); }
.ribbon-white .star, .ribbon-yellow .star {
  text-shadow: 0 0 1px color-mix(in srgb, var(--color-text) 65%, transparent);
}

/* ── Rider Program: the password block beside the page title ──────────────
   Decorative — see the comment in program.html. Sits on the title's baseline
   at desktop width and drops below it on a phone. */
.program-head {
  display: flex; flex-wrap: wrap; align-items: end;
  justify-content: space-between;
  gap: var(--space-4) var(--space-8);
}
.lock-sub {
  font-size: 15px; line-height: 1.5; margin: 0 0 var(--space-2);
  color: color-mix(in srgb, var(--color-text) 62%, transparent);
}
.lock-input { width: min(220px, 100%); }
/* the placeholder is the system's muted ink, so "Password" reads as a hint
   rather than as a value already typed in */
.lock-input::placeholder {
  color: color-mix(in srgb, var(--color-text) 40%, transparent);
  opacity: 1; /* Firefox dims placeholders again on top of the colour */
}

/* On a phone the head row stacks: title, ribbons, code box. The pull-up that
   hangs the cord off the masthead rule on desktop would drag it into the title
   here, so it is cancelled, and the ribbons get equal space above and below so
   they sit centred between the title and the code box. Kept below the
   .program-head base rule so it wins at equal specificity. */
@media (max-width: 720px) {
  /* nowrap matters: in a wrapping column Chrome sizes the SVG's height at a
     default 300px width before stretching it, and the ribbons spill out */
  .program-head { flex-direction: column; flex-wrap: nowrap; align-items: stretch; gap: 0; }
  .ribbon-wall {
    flex: none; max-width: none; align-self: stretch;
    /* not quite equal on purpose: the title's line box leaves a little more
       room under its letters than the code label leaves above its own, so
       these are what make the VISIBLE gaps match (~28px each) */
    margin: 15px 0 16px;
  }
}

/* ── Contact ──────────────────────────────────────────────────────────── */
.contact-panel { padding: var(--space-6); }
.contact-email {
  font-family: var(--font-heading); font-weight: var(--font-heading-weight);
  font-size: 28px; overflow-wrap: anywhere;
}
.contact-email a { color: inherit; text-decoration: none; }
.contact-email a:hover { color: var(--color-accent-700); }
.steps-ol { font-size: 14px; padding-left: 18px; line-height: 2; margin: 0 0 var(--space-3); }
.contact-meta p { font-size: 14px; }

/* ── small print ──────────────────────────────────────────────────────── */
.note-12 { font-size: 12px; margin-top: var(--space-2); }
.note-13 { font-size: 13px; }
.lead-17 { font-size: 17px; }
.measure-62 { max-width: 62ch; }
.measure-46 { max-width: 46ch; }

/* ── responsive collapse ──────────────────────────────────────────────────
   The handoff did not design responsive behaviour beyond "multi-column grids
   collapse to one column on narrow viewports". */
/* The levels and competition-record tables carry too many columns for a narrow
   screen. They scroll inside their own box rather than pushing the page
   sideways — harmless at any width where the table already fits. */
.table-scroll { overflow-x: auto; }

@media (max-width: 980px) {
  .grid-4 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .trainer-grid { grid-template-columns: 320px minmax(0, 1fr); }
}
@media (max-width: 860px) {
  .hero-grid { grid-template-columns: minmax(0, 1fr); }
  .page-hero { grid-template-columns: minmax(0, 1fr); }
  .hero-grid figure { order: -1; }
  .grid-3 { grid-template-columns: minmax(0, 1fr); }
  .trainer-grid { grid-template-columns: minmax(0, 1fr); }
  .contact-grid { grid-template-columns: minmax(0, 1fr); }
}
@media (max-width: 640px) {
  .page-body { padding: var(--space-6) var(--space-4); }
  .nav { padding: var(--space-4); }
  .site-footer { padding: var(--space-4); }
  .grid-2, .grid-4 { grid-template-columns: minmax(0, 1fr); }
  .table-scroll .table { min-width: 34rem; }
}
