/* ==========================================================================
   AETHER SPORTS ACADEMY — STYLESHEET
   ==========================================================================
   Carries the printed poster's identity onto the web. Read this section
   before changing colours, or the site and the poster will drift apart.

   THE IDENTITY IN ONE PARAGRAPH
   Night-indigo ground with a faint chessboard texture. Bone-coloured Scrabble
   tiles carrying real tournament letter values. Amber is the single loud
   accent and is reserved for the inclusion promise and calls to action —
   spend it anywhere else and it stops meaning anything. Cricket-ball red is
   a punctuation mark, never a fill.

   ORDER OF SECTIONS
   1. Tokens          2. Reset          3. Typography
   4. Layout          5. Motifs         6. Components
   7. Sections        8. Forms          9. Responsive   10. Print
   ========================================================================== */


/* ==========================================================================
   1. TOKENS
   ========================================================================== */

:root {
  /* --- Colour. Hex values are lifted straight from the poster. --------- */
  --ink:        #141433;  /* page ground                                  */
  --ink-2:      #1C1A44;  /* raised surface: cards                        */
  --ink-3:      #232156;  /* raised surface: rate panels, inputs          */
  --tile:       #EFDFC0;  /* Scrabble tile face                           */
  --tile-hi:    #F7EDD8;  /* tile highlight, top of the gradient          */
  --tile-edge:  #D8C39C;  /* tile inner bevel                             */
  --amber:      #FFB020;  /* THE accent. Inclusion + CTAs only.           */
  --amber-deep: #E09405;  /* amber pressed state                          */
  --ball:       #C8402C;  /* cricket ball. Punctuation only.              */
  --cream:      #FAF4E8;  /* primary text                                 */
  --muted:      #A9A6C9;  /* secondary text                               */
  --line:       rgba(250, 244, 232, 0.16);

  /* --- Type ------------------------------------------------------------
     Display is condensed and heavy to match the poster's headlines. Mono
     is used for eyebrows and phone numbers — it echoes a scoreboard and
     makes digits easy to read aloud off a phone screen.
     Web fonts are loaded in base.html.twig; these stacks degrade to
     reasonable system faces if the CDN is blocked. ------------------- */
  --font-display: 'Barlow Condensed', 'Arial Narrow', 'DejaVu Sans Condensed', sans-serif;
  --font-body:    'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono:    'IBM Plex Mono', ui-monospace, 'DejaVu Sans Mono', monospace;

  /* --- Type scale. clamp() so headings shrink on phones without a stack
         of media queries. --------------------------------------------- */
  --step-hero:  clamp(2.6rem, 7.5vw, 5rem);
  --step-h2:    clamp(2rem, 5vw, 3.25rem);
  --step-h3:    clamp(1.35rem, 3vw, 1.9rem);
  --step-body:  clamp(1rem, 1.15vw, 1.15rem);
  --step-small: 0.85rem;
  --step-eyebrow: 0.78rem;

  /* --- Space. A 4px base; named so intent survives refactoring. -------- */
  --space-xs: 0.5rem;
  --space-sm: 1rem;
  --space-md: 1.75rem;
  --space-lg: 3rem;
  --space-xl: 5rem;
  --space-2xl: 7rem;

  /* --- Structure ------------------------------------------------------- */
  --measure: 1180px;     /* max content width                             */
  --measure-text: 62ch;  /* max width for reading prose                   */
  --radius: 10px;
  --radius-tile: 12%;    /* percentage keeps tile corners proportional    */
  --strip-h: 14px;       /* the chessboard rule at top and bottom         */

  --shadow-tile: 0 4px 0 rgba(0, 0, 0, 0.30);
  --shadow-card: 0 12px 30px rgba(0, 0, 0, 0.28);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}


/* ==========================================================================
   2. RESET
   ========================================================================== */

*,
*::before,
*::after { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background-color: var(--ink);
  color: var(--cream);
  font-family: var(--font-body);
  font-size: var(--step-body);
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;

  /* The chessboard texture. Two 45-degree gradients offset by half a cell
     produce alternating squares without an image request. Opacity is kept
     very low (0.024) — it should read as texture, not as a pattern. */
  background-image:
    linear-gradient(45deg, rgba(255, 255, 255, 0.024) 25%, transparent 25%,
                           transparent 75%, rgba(255, 255, 255, 0.024) 75%),
    linear-gradient(45deg, rgba(255, 255, 255, 0.024) 25%, transparent 25%,
                           transparent 75%, rgba(255, 255, 255, 0.024) 75%);
  background-size: 120px 120px;
  background-position: 0 0, 60px 60px;
  background-attachment: fixed;
}

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

a { color: var(--amber); text-decoration-thickness: 1px; text-underline-offset: 3px; }
a:hover { color: var(--cream); }

/* Visible keyboard focus everywhere. Never remove this without a
   replacement — it is how keyboard and switch users navigate. */
:focus-visible {
  outline: 3px solid var(--amber);
  outline-offset: 3px;
  border-radius: 2px;
}

/* Screen-reader-only text: present for assistive tech, invisible on screen. */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* Skip link, revealed once focused. */
.skip-link {
  position: absolute;
  top: -100px; left: var(--space-sm);
  z-index: 100;
  padding: var(--space-xs) var(--space-sm);
  background: var(--amber);
  color: var(--ink);
  font-weight: 700;
  border-radius: 0 0 var(--radius) var(--radius);
  transition: top 0.2s var(--ease);
}
.skip-link:focus { top: 0; }


/* ==========================================================================
   3. TYPOGRAPHY
   ========================================================================== */

h1, h2, h3, h4 {
  font-family: var(--font-display);
  font-weight: 700;
  line-height: 1.02;
  letter-spacing: 0.01em;
  margin: 0 0 var(--space-sm);
  text-transform: uppercase;
}

h1 { font-size: var(--step-hero); }
h2 { font-size: var(--step-h2); }
h3 { font-size: var(--step-h3); }

p { margin: 0 0 var(--space-sm); max-width: var(--measure-text); }

/* The eyebrow: a small tracked-out mono label above a heading. Used as a
   structural signpost throughout, exactly as on the poster. */
.eyebrow {
  font-family: var(--font-mono);
  font-size: var(--step-eyebrow);
  letter-spacing: 0.38em;
  text-transform: uppercase;
  color: var(--muted);
  margin: 0 0 var(--space-sm);
}
.eyebrow--amber { color: var(--amber); }

/* The amber full stop that ends each poster headline. */
.dot { color: var(--amber); }

.lede { font-size: clamp(1.1rem, 2vw, 1.4rem); color: var(--cream); }
.muted { color: var(--muted); }


/* ==========================================================================
   4. LAYOUT
   ========================================================================== */

.wrap {
  width: min(100% - 2.5rem, var(--measure));
  margin-inline: auto;
}

.section { padding-block: var(--space-xl); }
.section--tight { padding-block: var(--space-lg); }
.section--center { text-align: center; }
.section--center p { margin-inline: auto; }

/* Hairline divider matching the poster's rules. */
.rule {
  border: 0;
  height: 1px;
  background: var(--line);
  margin-block: var(--space-lg);
}


/* ==========================================================================
   5. MOTIFS
   --------------------------------------------------------------------------
   The three devices borrowed from the poster: the chessboard strip, the
   Scrabble tile, and the cricket-ball dot. Everything distinctive about this
   site lives in this section.
   ========================================================================== */

/* --- 5a. Chessboard strip ------------------------------------------------
   Alternating amber and dim-cream squares. repeating-linear-gradient gives
   us 20 cells across any width with no markup. Sits at the very top and
   bottom of the page. ---------------------------------------------------- */
.strip {
  height: var(--strip-h);
  width: 100%;
  background: repeating-linear-gradient(
    90deg,
    var(--amber) 0 5%,
    rgba(250, 244, 232, 0.20) 5% 10%
  );
}
/* The bottom strip is offset half a cell so it reads as the opposite rank
   of the board, not a copy of the top. */
.strip--flipped {
  background: repeating-linear-gradient(
    90deg,
    rgba(250, 244, 232, 0.20) 0 5%,
    var(--amber) 5% 10%
  );
}

/* --- 5b. Scrabble tile ---------------------------------------------------
   A bone square with a bevel, a big letter, and its real tournament score
   in the corner. The score is written into `data-score` by the template and
   printed by CSS, so the markup stays a single element. ------------------ */
.tile-row {
  display: flex;
  flex-wrap: wrap;
  gap: clamp(4px, 1vw, 12px);
  justify-content: center;
  margin-bottom: clamp(6px, 1.2vw, 16px);
}

.tile {
  --tile-size: clamp(38px, 8.5vw, 104px);
  position: relative;
  width: var(--tile-size);
  height: var(--tile-size);
  flex: 0 0 auto;
  display: grid;
  place-items: center;

  background: linear-gradient(180deg, var(--tile-hi), var(--tile));
  border-radius: var(--radius-tile);
  box-shadow: var(--shadow-tile);

  font-family: var(--font-body);
  font-weight: 800;
  font-size: calc(var(--tile-size) * 0.54);
  line-height: 1;
  color: var(--ink);
  user-select: none;
}

/* Inner bevel line, drawn rather than added as a second element. */
.tile::before {
  content: '';
  position: absolute;
  inset: 3px;
  border: 2px solid var(--tile-edge);
  border-radius: calc(var(--radius-tile) - 1%);
  pointer-events: none;
}

/* The letter's point value. */
.tile::after {
  content: attr(data-score);
  position: absolute;
  right: 8%;
  bottom: 5%;
  font-size: calc(var(--tile-size) * 0.18);
  font-weight: 700;
  opacity: 0.7;
}

/* Tile entrance animation lives in section 18h — tiles now land like a tile
   being placed rather than simply fading down. Disabled under
   prefers-reduced-motion by section 9. */

/* --- 5c. Cricket-ball dot ------------------------------------------------
   Red circle with two seam curves, used to separate the county names. Built
   from a radial gradient plus two borders so it needs no SVG. ------------ */
.ball {
  display: inline-block;
  width: 0.62em;
  height: 0.62em;
  border-radius: 50%;
  background: var(--ball);
  position: relative;
  vertical-align: 0.18em;
  margin-inline: 0.55em;
  flex: 0 0 auto;
}
.ball::before,
.ball::after {
  content: '';
  position: absolute;
  top: 12%;
  width: 30%;
  height: 76%;
  border: 1.5px solid rgba(250, 244, 232, 0.9);
  border-radius: 50%;
}
.ball::before { left: 12%; border-right: 0; border-top: 0; border-bottom: 0; }
.ball::after  { right: 12%; border-left: 0; border-top: 0; border-bottom: 0; }


/* ==========================================================================
   6. COMPONENTS
   ========================================================================== */

/* --- Buttons ------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.6em;
  padding: 0.85em 1.9em;
  border: 2px solid transparent;
  border-radius: var(--radius);
  font-family: var(--font-display);
  font-size: 1.15rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.15s var(--ease), background-color 0.15s var(--ease);
}
.btn:active { transform: translateY(1px); }

.btn--primary { background: var(--amber); color: var(--ink); }
.btn--primary:hover { background: var(--amber-deep); color: var(--ink); }

.btn--ghost { background: transparent; color: var(--cream); border-color: var(--line); }
.btn--ghost:hover { border-color: var(--amber); color: var(--amber); }

.btn--block { width: 100%; }

/* --- Header -------------------------------------------------------------- */
.site-header {
  position: sticky;
  top: 0;
  z-index: 50;
  background: rgba(20, 20, 51, 0.94);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
}

.site-header__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  padding-block: var(--space-sm);
}

/* Wordmark: a 3x3 board fragment with one live amber square, then the name.
   Same mark as the poster's masthead. */
.brand { display: flex; align-items: center; gap: 0.9rem; text-decoration: none; }

.brand__mark {
  display: grid;
  grid-template-columns: repeat(3, 9px);
  grid-auto-rows: 9px;
  gap: 2px;
  flex: 0 0 auto;
}
.brand__mark i {
  background: var(--cream);
  opacity: 0.28;
  border-radius: 1px;
}
.brand__mark i:nth-child(5) { background: var(--amber); opacity: 1; }

.brand__name {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.4rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--cream);
  line-height: 1;
}
.brand__tag {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.6rem;
  letter-spacing: 0.24em;
  color: var(--amber);
  margin-top: 4px;
}

.nav { display: flex; align-items: center; gap: var(--space-md); }
.nav a {
  color: var(--cream);
  text-decoration: none;
  font-family: var(--font-display);
  font-size: 1.1rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
}
.nav a:hover { color: var(--amber); }

/* Hamburger, shown only on narrow screens (see section 9). */
.nav-toggle {
  display: none;
  background: none;
  border: 2px solid var(--line);
  border-radius: var(--radius);
  color: var(--cream);
  padding: 0.45em 0.7em;
  cursor: pointer;
  font-size: 1.2rem;
}

/* --- Cards --------------------------------------------------------------- */
.card {
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-md);
  box-shadow: var(--shadow-card);
}

.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
  gap: var(--space-md);
}

/* Programme card: heading, tagline, skill list, link. */
.programme__score {
  font-family: var(--font-mono);
  font-size: var(--step-small);
  color: var(--amber);
  letter-spacing: 0.1em;
}
.programme__skills {
  list-style: none;
  padding: 0;
  margin: var(--space-sm) 0;
}
.programme__skills li {
  position: relative;
  padding-left: 1.5em;
  margin-bottom: 0.4em;
  color: var(--muted);
}
/* Checked-off marker rather than a bullet — these are outcomes, not items. */
.programme__skills li::before {
  content: '';
  position: absolute;
  left: 0; top: 0.55em;
  width: 8px; height: 8px;
  background: var(--amber);
  border-radius: 2px;
}

/* --- Inclusion band ------------------------------------------------------
   The loudest element on the page, exactly as on the poster. Amber fill,
   ink text, cricket-red spine on the left edge. --------------------------- */
.inclusion {
  background: var(--amber);
  color: var(--ink);
  border-radius: var(--radius);
  border-left: 10px solid var(--ball);
  padding: var(--space-md) var(--space-lg);
  text-align: center;
}
.inclusion .eyebrow { color: rgba(20, 20, 51, 0.72); }
.inclusion h2 { color: var(--ink); text-transform: none; }
.inclusion p {
  color: rgba(20, 20, 51, 0.88);
  margin-inline: auto;
  margin-bottom: 0;
}

/* --- Rate panels --------------------------------------------------------- */
.rates {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: var(--space-md);
}
.rate {
  background: var(--ink-3);
  border: 1px solid rgba(255, 176, 32, 0.5);
  border-radius: var(--radius);
  padding: var(--space-md);
  text-align: center;
}
.rate__amount {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.8rem, 6vw, 4.2rem);
  line-height: 1;
  margin: var(--space-xs) 0;
}
.rate__unit { color: var(--muted); font-size: var(--step-small); }
.rate__note {
  color: var(--muted);
  font-size: var(--step-small);
  margin: var(--space-sm) auto 0;
  max-width: 34ch;
}

/* --- Locations ----------------------------------------------------------- */
.locations {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.7rem, 4.5vw, 3rem);
  text-transform: uppercase;
  letter-spacing: 0.02em;
}

/* --- Contact cards ------------------------------------------------------- */
.contacts {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-md);
}
.contact { text-align: center; }
.contact__name {
  font-family: var(--font-display);
  font-size: 1.6rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.05em;
}
.contact__phone {
  display: block;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: 1.35rem;
  color: var(--amber);
  text-decoration: none;
  margin-block: 0.3em 0.8em;
}
.contact__phone:hover { color: var(--cream); }

/* --- Footer -------------------------------------------------------------- */
.site-footer {
  border-top: 1px solid var(--line);
  padding-block: var(--space-lg);
  color: var(--muted);
  font-size: var(--step-small);
}
.site-footer a { color: var(--muted); }
.site-footer a:hover { color: var(--amber); }

/* --- Flash messages ------------------------------------------------------ */
.flash {
  border-radius: var(--radius);
  padding: var(--space-sm) var(--space-md);
  margin-bottom: var(--space-md);
  border-left: 6px solid;
}
.flash--success { background: rgba(45, 160, 120, 0.15); border-color: #2DA078; }
.flash--warning { background: rgba(255, 176, 32, 0.15); border-color: var(--amber); }
.flash--error   { background: rgba(200, 64, 44, 0.15);  border-color: var(--ball); }


/* ==========================================================================
   7. SECTIONS
   ========================================================================== */

.hero { padding-block: var(--space-xl) var(--space-lg); text-align: center; }

.hero__headline {
  font-size: var(--step-hero);
  margin-top: var(--space-lg);
}

/* Tile rows are wide; let them bleed to the viewport edge on phones so the
   longest word (SCRABBLE) keeps a readable tile size. */
.hero__tiles { margin-inline: calc(50% - 50vw); padding-inline: 0.5rem; }


/* ==========================================================================
   8. FORMS
   ========================================================================== */

.form-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--space-sm) var(--space-md);
}
/* Textareas and anything marked wide span the full grid. */
.form-row--wide { grid-column: 1 / -1; }

.form-row label {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--step-eyebrow);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 0.45em;
}

.form-row input,
.form-row select,
.form-row textarea {
  width: 100%;
  padding: 0.8em 1em;
  background: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--cream);
  font-family: var(--font-body);
  /* 16px minimum stops iOS Safari zooming in when a field is focused. */
  font-size: 1rem;
  transition: border-color 0.15s var(--ease);
}
.form-row input::placeholder,
.form-row textarea::placeholder { color: rgba(169, 166, 201, 0.55); }

.form-row input:focus,
.form-row select:focus,
.form-row textarea:focus { border-color: var(--amber); }

.form-row select {
  appearance: none;
  /* Chevron drawn with gradients so there is no image request. */
  background-image:
    linear-gradient(45deg, transparent 50%, var(--muted) 50%),
    linear-gradient(135deg, var(--muted) 50%, transparent 50%);
  background-position: right 1.3em top 55%, right 1em top 55%;
  background-size: 6px 6px, 6px 6px;
  background-repeat: no-repeat;
  padding-right: 2.6em;
}

.form-row .help {
  display: block;
  font-size: var(--step-small);
  color: var(--muted);
  margin-top: 0.4em;
  max-width: none;
}

/* Validation errors from Symfony's form renderer. */
.form-row ul { list-style: none; padding: 0; margin: 0.4em 0 0; }
.form-row ul li { color: #FF8D7A; font-size: var(--step-small); }
.form-row--error input,
.form-row--error select,
.form-row--error textarea { border-color: var(--ball); }

/* Honeypot. Hidden from sight and from screen readers, but NOT with
   display:none — some bots skip fields that are display:none. */
.hp-field {
  position: absolute !important;
  left: -9999px !important;
  width: 1px !important;
  height: 1px !important;
  opacity: 0 !important;
}


/* ==========================================================================
   9. RESPONSIVE
   ========================================================================== */

@media (max-width: 780px) {
  :root { --space-xl: 3.5rem; --space-2xl: 4.5rem; }

  .nav-toggle { display: block; }

  /* Nav collapses to a stacked panel, toggled by the button in app.js. */
  .nav {
    position: absolute;
    top: 100%;
    left: 0;
    right: 0;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    background: var(--ink-2);
    border-bottom: 1px solid var(--line);
    padding: var(--space-sm);
    display: none;
  }
  .nav[data-open='true'] { display: flex; }
  .nav a { padding: 0.7em 0.4em; border-bottom: 1px solid var(--line); }
  .nav .btn { margin-top: var(--space-sm); }

  .inclusion { padding: var(--space-md) var(--space-sm); }
}

/* Honour the OS "reduce motion" setting. Vestibular disorders are common and
   this is a genuine accessibility requirement, not a nicety. */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation-duration: 0.001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.001ms !important;
  }
  .tile--animated { opacity: 1; transform: none; }
}


/* ==========================================================================
   10. PRINT
   --------------------------------------------------------------------------
   Parents do print these pages to pin on a school noticeboard. Flip to ink
   on white, drop the furniture, keep the phone numbers.
   ========================================================================== */

@media print {
  body { background: #fff; color: #000; }
  .site-header, .site-footer, .strip, .nav, .btn, form { display: none !important; }
  .tile { box-shadow: none; border: 1px solid #999; }
  .inclusion { border: 2px solid #000; background: #fff; color: #000; }
  a[href^='tel:']::after { content: ' (' attr(href) ')'; }
}


/* ==========================================================================
   11. DECORATIVE LAYER  (added in the landing-page upgrade)
   --------------------------------------------------------------------------
   Chess pieces and cricket equipment behind the hero.

   THREE RULES, and the layout breaks if any is ignored:

   1. PLACEMENT IS DELIBERATE, NOT SCATTERED. The two heaviest pieces (knight,
      king) sit at opposite ends of the main diagonal — bottom-left and
      top-right — so the composition balances the way a board does. The
      cricket ball takes the remaining top-left corner, the bat and stumps
      weight the bottom-right. Nothing sits in the centre column, because the
      centre column is where the headline and buttons live.

   2. DECOR NEVER TOUCHES TEXT. The layer is `pointer-events: none` and sits
      at z-index 0; content sits at z-index 2. Opacity is kept low enough that
      body text over it still clears contrast requirements.

   3. THE PARENT CLIPS. `overflow: clip` on .hero is what allows pieces to
      bleed past the edge without producing a horizontal scrollbar. Remove it
      and the page scrolls sideways on mobile.
   ========================================================================== */

.hero {
  position: relative;
  /* `clip` rather than `hidden`: it prevents the scrollbar without turning
     the element into a scroll container, so position:sticky still works. */
  overflow: clip;
  isolation: isolate;
}

.hero__decor {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  overflow: clip;
}

.hero__content { position: relative; z-index: 2; }

/* --- 11a. Chessboard in perspective --------------------------------------
   A checkerboard laid flat and tilted away from the viewer, then faded out
   toward the horizon. Reads as depth and strategy rather than as a playable
   board, which is the whole point. ---------------------------------------- */
/* Board geometry moved to section 18a, which owns the whole stage. Keeping
   it in one place stops the two definitions drifting apart. */

/* --- 11b. Pieces ---------------------------------------------------------
   SUPERSEDED BY SECTION 18. The corner-parked placements that used to live
   here were replaced by the board stage, where pieces stand on the
   perspective board in ranks. Section 18 owns all decor geometry now.
   ------------------------------------------------------------------------ */


/* ==========================================================================
   12. HERO CONTENT
   ========================================================================== */

/* FIX: the CTA buttons used to sit inside a bare <p>, which inherits
   `max-width: var(--measure-text)` from the global paragraph rule. In a
   centred hero that produces a 62ch box aligned to the LEFT of the container,
   so the buttons rendered visibly left of true page centre on desktop while
   the .lede above them (which had an inline margin-inline:auto) looked
   correct. Hence the misalignment. Buttons now live in their own flex
   container with no max-width at all. */
.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-sm);
  justify-content: center;
  align-items: center;
  max-width: none;
  margin: var(--space-md) 0 0;
}

/* Belt and braces: any paragraph directly in the centred hero centres itself,
   so this class of bug cannot come back via a new <p>. */
.hero p { margin-inline: auto; }

.hero__eyebrow { margin-bottom: var(--space-md); }


/* ==========================================================================
   13. CHIPS, CARDS AND PROGRAMME COMPONENTS
   ========================================================================== */

/* Short skill pills: "Strategy" "Timing" "Leadership". */
.chips {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-sm);
}
.chips li {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--amber);
  border: 1px solid rgba(255, 176, 32, 0.35);
  border-radius: 100px;
  padding: 0.25em 0.75em;
  white-space: nowrap;
}

/* Programme card: glyph, then text. */
.programme {
  display: flex;
  flex-direction: column;
}
/* Hover behaviour is in section 18e (lifting a piece off the board). */

.programme__icon {
  width: 54px;
  height: 64px;
  margin-bottom: var(--space-sm);
}
/* The sprite carries its own material colour, so there is no `color` here.
   Setting one would do nothing — the gradients are baked in. */
.programme__glyph { width: 100%; height: 100%; display: block; }

.btn--sm { font-size: 0.95rem; padding: 0.6em 1.3em; }


/* ==========================================================================
   14. PROGRAMME DETAIL PAGE
   ========================================================================== */

/* Detail hero: glyph beside the title rather than centred above it, so the
   page reads differently from the landing hero. */
.prog-hero {
  position: relative;
  overflow: clip;
  padding-block: var(--space-xl);
}
.prog-hero__grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--space-lg);
  align-items: center;
  position: relative;
  z-index: 2;
}
@media (min-width: 860px) {
  .prog-hero__grid { grid-template-columns: 1.4fr 0.6fr; }
}
.prog-hero__glyph {
  width: min(100%, 240px);
  aspect-ratio: 100 / 120;
  opacity: 0.95;
  justify-self: center;
}

/* Ordered stages. Numbered via a counter so the markup stays a plain list. */
.curriculum {
  list-style: none;
  counter-reset: stage;
  padding: 0;
  margin: 0;
  display: grid;
  gap: var(--space-md);
}
.curriculum li {
  counter-increment: stage;
  position: relative;
  padding-left: 3.6rem;
}
.curriculum li::before {
  content: counter(stage, decimal-leading-zero);
  position: absolute;
  left: 0;
  top: 0.1em;
  font-family: var(--font-mono);
  font-size: 0.95rem;
  font-weight: 700;
  color: var(--amber);
  border: 1px solid rgba(255, 176, 32, 0.35);
  border-radius: var(--radius);
  padding: 0.25em 0.5em;
  line-height: 1;
}
.curriculum h4 {
  font-size: 1.15rem;
  margin: 0 0 0.25rem;
  letter-spacing: 0.04em;
}
.curriculum p { margin: 0; color: var(--muted); }

/* History: set apart with a rule and a slightly warmer treatment, because it
   is background reading rather than a selling point. */
.history {
  border-left: 3px solid rgba(255, 176, 32, 0.4);
  padding-left: var(--space-md);
}
.history p { color: var(--muted); }

/* Two-column prose block for "why it matters". */
.split {
  display: grid;
  gap: var(--space-lg);
  grid-template-columns: minmax(0, 1fr);
}
@media (min-width: 860px) {
  .split { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}


/* ==========================================================================
   15. RESPONSIVE OVERRIDES FOR THE DECORATIVE LAYER
   --------------------------------------------------------------------------
   The mobile hero is a deliberately different composition, not a squeezed
   desktop one: the two big chess pieces are dropped entirely (they would sit
   under the headline at that width), leaving the ball and a smaller knight to
   carry the identity.
   ========================================================================== */

@media (max-width: 780px) {
  .decor--hero-tr,
  .decor--hero-br,
  .decor--hero-b { display: none; }

  .decor--hero-bl {
    width: 170px;
    left: -12%;
    bottom: -4%;
    opacity: 0.06;
  }
  .decor--hero-tl {
    width: 66px;
    left: auto;
    right: 6%;
    top: 4%;
  }

  .hero__board { height: 42%; background-size: 70px 70px; }
  .prog-hero__glyph { width: 150px; }
}

/* Very narrow phones: drop to the ball alone. One motif is enough. */
@media (max-width: 420px) {
  .decor--hero-bl { display: none; }
}


/* ==========================================================================
   16. BOOKING FORM — ENQUIRER TYPES
   --------------------------------------------------------------------------
   The form serves parents, group organisers and schools. A radio picks the
   type and public/js/app.js shows the matching [data-when] fieldsets.

   With JavaScript off, every fieldset is visible and the visitor fills the
   one that applies. That is intentional — do NOT hide branches with CSS by
   default, or the form breaks entirely without JS.
   ========================================================================== */

.fieldset {
  border: 0;
  border-top: 1px solid var(--line);
  padding: var(--space-md) 0 0;
  margin: 0 0 var(--space-md);
  min-width: 0; /* stops fieldset forcing its grid children to overflow */
}
.fieldset:first-of-type { border-top: 0; padding-top: 0; }

.fieldset legend {
  padding: 0;
  margin-bottom: var(--space-sm);
}

/* --- The type picker -----------------------------------------------------
   Symfony renders `expanded` choices as input+label pairs. The native radio
   is hidden and the label becomes the target, so the whole card is tappable
   — important on a phone, where a 16px radio dot is a poor hit area. --- */
.type-picker {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--space-sm);
}

.type-picker input[type='radio'] {
  /* Removed from view but NOT from the accessibility tree, so keyboard
     navigation and screen readers still work normally. */
  position: absolute;
  opacity: 0;
  width: 1px;
  height: 1px;
}

.type-picker label {
  display: block;
  padding: 1em 1.1em;
  background: var(--ink-3);
  border: 2px solid var(--line);
  border-radius: var(--radius);
  cursor: pointer;
  font-family: var(--font-display);
  font-size: 1.15rem;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  color: var(--cream);
  /* Overrides the small tracked-out label styling used elsewhere in forms. */
  margin: 0;
  transition: border-color 0.15s var(--ease), background-color 0.15s var(--ease);
}

.type-picker label:hover { border-color: rgba(255, 176, 32, 0.5); }

.type-picker input[type='radio']:checked + label {
  border-color: var(--amber);
  background: rgba(255, 176, 32, 0.12);
  color: var(--amber);
}

/* Keyboard focus has to land on the visible label, since the input itself is
   invisible. Without this, tabbing through the picker shows nothing at all. */
.type-picker input[type='radio']:focus-visible + label {
  outline: 3px solid var(--amber);
  outline-offset: 3px;
}


/* ==========================================================================
   17. INTERACTION LAYER
   --------------------------------------------------------------------------
   Motion and interactive components. Two standing rules:

   1. ANYTHING THAT HIDES CONTENT SITS BEHIND .js-enabled. That class is set
      by an inline script in <head>. With JavaScript off it is never added, so
      the rules below never apply and nothing is hidden. Break this and the
      site silently loses content for a slice of visitors.

   2. Section 9's prefers-reduced-motion block neutralises every animation
      here. Do not add motion that bypasses it.
   ========================================================================== */

/* --- 17a. Scroll progress ------------------------------------------------ */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 90;
  height: 3px;
  width: 100%;
  background: var(--amber);
  transform: scaleX(0);
  transform-origin: 0 50%;
  /* Only the compositor touches transform, so this cannot cause layout
     thrash however fast the visitor scrolls. */
  will-change: transform;
  pointer-events: none;
}

/* --- 17b/c. Reveal and parallax -----------------------------------------
   SUPERSEDED BY SECTION 18. Reveals now read as a piece being placed, and
   parallax is applied to the .decor slot rather than the artwork.
   ------------------------------------------------------------------------ */


/* --- 17d. Tile hover -----------------------------------------------------
   Tiles lift and tilt very slightly, like a Scrabble tile being picked off
   the rack. One of the few places the identity can be felt rather than just
   seen, so it is worth the four lines. ---------------------------------- */
.tile {
  transition: transform 0.22s var(--ease), box-shadow 0.22s var(--ease);
}
.tile-row:hover .tile:hover {
  transform: translateY(-6px) rotate(-2deg);
  box-shadow: 0 10px 0 rgba(0, 0, 0, 0.32);
}

/* --- 17e. Quick-look dialog ----------------------------------------------
   Native <dialog>. showModal() provides focus trapping, Escape-to-close and
   background inerting with no library. ---------------------------------- */
.quicklook {
  padding: 0;
  border: 1px solid rgba(255, 176, 32, 0.35);
  border-radius: var(--radius);
  background: var(--ink-2);
  color: var(--cream);
  width: min(92vw, 620px);
  max-height: 86vh;
  box-shadow: 0 30px 80px rgba(0, 0, 0, 0.55);
}
.quicklook::backdrop {
  background: rgba(10, 10, 30, 0.72);
  backdrop-filter: blur(3px);
}
.quicklook[open] { animation: quicklook-in 0.28s var(--ease); }

@keyframes quicklook-in {
  from { opacity: 0; transform: translateY(14px) scale(0.98); }
  to   { opacity: 1; transform: none; }
}

.quicklook__inner {
  padding: var(--space-md);
  overflow-y: auto;
  max-height: 86vh;
}
.quicklook__head {
  display: flex;
  align-items: center;
  gap: var(--space-sm);
  margin-bottom: var(--space-sm);
}
.quicklook__glyph {
  width: 52px;
  height: 62px;
  flex: 0 0 auto;
}
.quicklook h3 { margin: 0; }
.quicklook__close {
  position: absolute;
  top: var(--space-sm);
  right: var(--space-sm);
  background: none;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--cream);
  font-size: 1.2rem;
  line-height: 1;
  padding: 0.35em 0.6em;
  cursor: pointer;
}
.quicklook__close:hover { border-color: var(--amber); color: var(--amber); }

/* The trigger only makes sense when the dialog can actually open. */
.quicklook-trigger { display: none; }
.js-enabled .quicklook-trigger { display: inline-flex; }

/* --- 17f. FAQ accordion --------------------------------------------------
   Built on <details>/<summary>, so it opens and closes with no JavaScript
   at all and is keyboard accessible by default. ------------------------- */
.faq { display: grid; gap: 0.75rem; }

.faq details {
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  transition: border-color 0.2s var(--ease);
}
.faq details[open] { border-color: rgba(255, 176, 32, 0.4); }

.faq summary {
  cursor: pointer;
  padding: 1.1em 3em 1.1em 1.2em;
  position: relative;
  font-family: var(--font-display);
  font-size: 1.2rem;
  letter-spacing: 0.03em;
  list-style: none;   /* Firefox */
}
.faq summary::-webkit-details-marker { display: none; }  /* Safari/Chrome */

/* Plus that becomes a minus. Drawn from two bars so it can rotate. */
.faq summary::after {
  content: '';
  position: absolute;
  right: 1.2em;
  top: 50%;
  width: 14px;
  height: 2px;
  background: var(--amber);
  transform: translateY(-50%);
}
.faq summary::before {
  content: '';
  position: absolute;
  right: calc(1.2em + 6px);
  top: 50%;
  width: 2px;
  height: 14px;
  background: var(--amber);
  transform: translateY(-50%);
  transition: transform 0.2s var(--ease), opacity 0.2s var(--ease);
}
.faq details[open] summary::before { transform: translateY(-50%) rotate(90deg); opacity: 0; }

.faq details > div { padding: 0 1.2em 1.3em; }
.faq details p { color: var(--muted); margin: 0; }

/* --- 17g. Stats band ----------------------------------------------------- */
.stats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: var(--space-md);
  text-align: center;
}
.stat__figure {
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(2.4rem, 5vw, 3.4rem);
  line-height: 1;
  color: var(--amber);
}
.stat__label {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 0.5em;
}

/* --- 17h. Button ---------------------------------------------------------
   SUPERSEDED BY SECTION 18: the sweep is now a square stepping across the
   button rather than a generic gloss highlight.
   ------------------------------------------------------------------------ */


/* ==========================================================================
   18. THE BOARD STAGE, AND RESTRAINT
   --------------------------------------------------------------------------
   THE PRINCIPLE, because it governs every value below.

   An earlier version of this section had the knight hopping an L-shape, a
   highlight stepping across buttons in four discrete jumps, and squares
   flashing amber as cards arrived. All of it was clever. None of it was
   elegant — clever motion asks to be noticed, and anything that asks to be
   noticed reads as cheap.

   Premium motion is SLOW, FEW and SMALL:
     · durations are long (0.8s–1.2s), never snappy
     · easing decelerates and stops — no bounce, no overshoot, no steps()
     · movement is measured in single-digit pixels
     · at any moment, almost nothing on the page is moving

   The pieces are polished ivory standing on a board that recedes into the
   dark. They breathe. That is the whole effect, and it is enough.

   If you are tempted to add motion, the question is not "would this be
   cool" but "would a visitor notice it?" If yes, it is too much.

   All of it is disabled by the prefers-reduced-motion block in section 9.
   ========================================================================== */

/* --- 18a. The board ------------------------------------------------------
   Tilted away from the viewer and faded toward the horizon. No sweep, no
   pulsing squares. It is a stage, not a performance. -------------------- */
.hero__board {
  position: absolute;
  left: -20%;
  right: -20%;
  bottom: 0;
  height: 56%;
  background-image:
    linear-gradient(45deg, rgba(250, 244, 232, 0.085) 25%, transparent 25%,
                           transparent 75%, rgba(250, 244, 232, 0.085) 75%),
    linear-gradient(45deg, rgba(250, 244, 232, 0.085) 25%, transparent 25%,
                           transparent 75%, rgba(250, 244, 232, 0.085) 75%);
  background-size: 118px 118px;
  background-position: 0 0, 59px 59px;
  transform: perspective(780px) rotateX(67deg);
  transform-origin: bottom center;
  -webkit-mask-image: linear-gradient(to top, #000 0%, transparent 76%);
          mask-image: linear-gradient(to top, #000 0%, transparent 76%);
}

/* --- 18b. Slots ----------------------------------------------------------
   Two nested elements: .decor owns PLACEMENT and pointer parallax,
   .decor__piece owns its own drift. Both need `transform`, and one element
   cannot have two. Do not collapse them back together. ------------------- */
.decor {
  position: absolute;
  display: block;
  transform: translate3d(var(--px, 0), var(--py, 0), 0);
  /* Long and decelerating: the pieces follow the pointer the way something
     heavy would, not the way a cursor does. */
  transition: transform 1.1s cubic-bezier(0.16, 1, 0.3, 1);
  will-change: transform;
}

.decor__piece {
  display: block;
  width: 100%;
  aspect-ratio: 100 / 120;
}

/* The artwork carries its own material colour (ivory, leather, willow), so
   there is no tinting here — only how present each piece is. Pieces at the
   back are barely there; that is what creates depth. */
.decor--front-l { width: clamp(190px, 25vw, 400px); left: 1%;   bottom: 0;   opacity: 0.30; }
.decor--front-r { width: clamp(74px, 9.5vw, 148px); right: 6%;  bottom: 4%;  opacity: 0.42; }
.decor--mid-r   { width: clamp(112px, 15vw, 240px); right: 20%; bottom: 15%; opacity: 0.16; }
.decor--back-c  { width: clamp(62px, 8vw, 124px);   left: 40%;  bottom: 27%; opacity: 0.10; }
.decor--back-r  { width: clamp(56px, 7vw, 110px);   right: 10%; bottom: 30%; opacity: 0.09; }
.decor--back-l  { width: clamp(52px, 6.5vw, 98px);  left: 30%;  bottom: 32%; opacity: 0.085; }

/* --- 18c. Breathing ------------------------------------------------------
   A few pixels over fifteen-plus seconds. Durations are deliberately
   coprime-ish so the pieces never fall into step with one another, which is
   what would make the motion legible — and therefore noticeable. -------- */
@keyframes breathe {
  from { transform: translateY(0); }
  to   { transform: translateY(-7px); }
}
.decor__piece--drift   { animation: breathe 17s ease-in-out infinite alternate; }
.decor--front-r .decor__piece--drift { animation-duration: 13s; }
.decor--mid-r   .decor__piece--drift { animation-duration: 21s; }
.decor--back-l  .decor__piece--drift { animation-duration: 19s; }

/* --- 18d. Reveal ---------------------------------------------------------
   Fade and a small rise, decelerating to a stop. No overshoot: a bounce is
   playful, and playful is not what we are selling to a parent deciding
   where to send their child. ------------------------------------------- */
.js-enabled [data-reveal] {
  opacity: 0;
  transform: translateY(16px);
  transition:
    opacity 0.9s cubic-bezier(0.16, 1, 0.3, 1),
    transform 0.9s cubic-bezier(0.16, 1, 0.3, 1);
}
.js-enabled [data-reveal][data-revealed='true'] {
  opacity: 1;
  transform: none;
}
/* Stagger is generous — 130ms reads as considered, 40ms reads as a ripple. */
.js-enabled [data-reveal][style*='--i'] {
  transition-delay: calc(var(--i, 0) * 130ms);
}

/* --- 18e. Card hover ----------------------------------------------------- */
.programme {
  transition:
    transform 0.5s cubic-bezier(0.16, 1, 0.3, 1),
    border-color 0.5s var(--ease),
    box-shadow 0.5s var(--ease);
}
.programme:hover {
  transform: translateY(-5px);
  border-color: rgba(255, 176, 32, 0.4);
  box-shadow: 0 18px 40px rgba(0, 0, 0, 0.38);
}

/* --- 18f. Button ---------------------------------------------------------
   No sweeping highlight at all. A premium button deepens slightly and lifts
   a hair. That is the entire interaction. ------------------------------- */
.btn {
  transition:
    background-color 0.35s var(--ease),
    border-color 0.35s var(--ease),
    color 0.35s var(--ease),
    transform 0.35s cubic-bezier(0.16, 1, 0.3, 1),
    box-shadow 0.35s var(--ease);
}
.btn--primary:hover {
  transform: translateY(-2px);
  box-shadow: 0 10px 24px rgba(255, 176, 32, 0.22);
}
.btn--ghost:hover { transform: translateY(-2px); }

/* --- 18g. Tiles ----------------------------------------------------------
   They settle rather than drop. Same principle: no bounce. ------------- */
.tile--animated {
  opacity: 0;
  animation: tile-settle 0.8s cubic-bezier(0.16, 1, 0.3, 1) forwards;
  animation-delay: calc(var(--i, 0) * 60ms);
}
@keyframes tile-settle {
  from { opacity: 0; transform: translateY(-14px); }
  to   { opacity: 1; transform: none; }
}

.tile { transition: transform 0.45s cubic-bezier(0.16, 1, 0.3, 1); }
.tile-row:hover .tile:hover { transform: translateY(-4px); }

/* --- 18h. Mobile ---------------------------------------------------------
   A different composition, not a compressed one: the back and mid ranks go
   entirely, leaving the knight and the ball to carry the identity. ------ */
@media (max-width: 780px) {
  .decor--mid-r,
  .decor--back-c,
  .decor--back-r,
  .decor--back-l { display: none; }

  .decor--front-l { width: 158px; left: -5%; bottom: 1%; opacity: 0.22; }
  .decor--front-r { width: 58px;  right: 5%; bottom: 7%; opacity: 0.34; }

  .hero__board { height: 40%; background-size: 74px 74px; }
}

@media (max-width: 420px) {
  .decor--front-l { display: none; }
}


/* ==========================================================================
   19. AUTHENTICATION AND ADMIN
   --------------------------------------------------------------------------
   Shares the public design system — same tokens, same motifs — but reads as
   a different MODE. Denser, quieter, no decorative pieces. The public site
   persuades; this one is a working tool.
   ========================================================================== */

/* --- 19a. Sign in -------------------------------------------------------- */
.auth {
  min-height: 62vh;
  display: flex;
  align-items: center;
  justify-content: center;
}
.auth__panel {
  width: min(100%, 420px);
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: var(--space-lg);
  box-shadow: var(--shadow-card);
}
.auth__title { font-size: clamp(2rem, 5vw, 2.6rem); margin-bottom: var(--space-md); }
.auth__form .form-row { margin-bottom: var(--space-sm); }
.auth__note { font-size: var(--step-small); margin: var(--space-md) 0 0; }

.checkbox {
  display: flex;
  align-items: center;
  gap: 0.6em;
  /* Overrides the tracked-out uppercase label styling used by form rows —
     a checkbox label is a sentence, not a field name. */
  font-family: var(--font-body);
  font-size: var(--step-small);
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted);
  cursor: pointer;
}
.checkbox input { width: auto; }

/* --- 19b. Admin bar ------------------------------------------------------ */
.admin-bar {
  /* Sticky, like the public header. On the admin and parent areas you are
     scrolling long lists, so the navigation and the sign-out button need to
     stay reachable — having to scroll back to the top to change section is
     exactly the friction a working tool should not have.

     Semi-transparent with a blur, matching .site-header, so content scrolling
     beneath it reads as passing behind rather than being covered. */
  position: sticky;
  top: 0;
  z-index: 60;
  background: rgba(28, 26, 68, 0.94);
  backdrop-filter: blur(8px);
  border-bottom: 1px solid var(--line);
  padding-block: var(--space-sm);
}

/* Anchor links (#rates, #book) would otherwise scroll their target underneath
   the sticky bar. This tells the browser to stop that many pixels short. */
:target { scroll-margin-top: 6rem; }
.admin-bar__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
}
.admin-bar__brand { display: flex; align-items: center; gap: var(--space-md); }
.admin-bar__link {
  font-family: var(--font-display);
  font-size: 1.1rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--cream);
  text-decoration: none;
}
.admin-bar__link:hover { color: var(--amber); }
.admin-bar__user { display: flex; align-items: center; gap: var(--space-sm); flex-wrap: wrap; }

.admin__title { font-size: clamp(1.9rem, 4vw, 2.8rem); margin-bottom: var(--space-md); }

/* --- 19c. Filters -------------------------------------------------------- */
.filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: var(--space-md); }
.filter {
  display: inline-flex;
  align-items: center;
  gap: 0.5em;
  padding: 0.45em 0.9em;
  border: 1px solid var(--line);
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
  text-decoration: none;
}
.filter:hover { border-color: rgba(255, 176, 32, 0.5); color: var(--cream); }
.filter--on { border-color: var(--amber); color: var(--amber); }
.filter__count { opacity: 0.7; }

/* --- 19d. Enquiry list --------------------------------------------------- */
.enquiries { display: grid; gap: 0.6rem; margin-top: var(--space-md); }

.enquiry {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--space-md);
  flex-wrap: wrap;
  padding: var(--space-sm) var(--space-md);
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  text-decoration: none;
  color: inherit;
  transition: border-color 0.25s var(--ease), transform 0.25s var(--ease);
}
.enquiry:hover { border-color: rgba(255, 176, 32, 0.45); transform: translateY(-2px); }

/* Unactioned enquiries carry an amber spine. Scanning the list, the ones
   still needing a call are obvious without reading a single status label. */
.enquiry--new { border-left: 4px solid var(--amber); }

.enquiry__main { min-width: 0; }
.enquiry__headline {
  margin: 0 0 0.2em;
  font-family: var(--font-display);
  font-size: 1.25rem;
  letter-spacing: 0.02em;
  color: var(--cream);
}
.enquiry__meta { margin: 0; font-size: var(--step-small); }
.enquiry__side { display: flex; align-items: center; gap: var(--space-sm); flex-shrink: 0; }
.enquiry__when { font-family: var(--font-mono); font-size: 0.72rem; }

/* --- 19e. Tags and statuses ---------------------------------------------- */
.tag {
  display: inline-block;
  vertical-align: middle;
  margin-left: 0.5em;
  padding: 0.2em 0.6em;
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: 0.62rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}
/* Amber, because it is the same promise the poster makes. */
.tag--support { background: var(--amber); color: var(--ink); font-weight: 700; }

.status {
  display: inline-block;
  padding: 0.25em 0.7em;
  border-radius: 100px;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  border: 1px solid;
}
.status--new       { color: var(--amber);  border-color: rgba(255, 176, 32, 0.5); }
.status--contacted { color: #7FB2FF;       border-color: rgba(127, 178, 255, 0.5); }
.status--scheduled { color: #5FD3A5;       border-color: rgba(95, 211, 165, 0.5); }
.status--closed    { color: var(--muted);  border-color: var(--line); }

/* --- 19f. Detail --------------------------------------------------------- */
.detail { margin: 0; }
.detail dt {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted);
  margin-top: 0.9em;
}
.detail dd { margin: 0.2em 0 0; color: var(--cream); }

.status-form { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: var(--space-sm); }

.pager {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-md);
  margin-top: var(--space-lg);
}

@media (max-width: 620px) {
  .enquiry { flex-direction: column; align-items: flex-start; }
  .enquiry__side { width: 100%; justify-content: space-between; }
}

/* --- 19g. Admin shell (standalone, not the public header) ---------------- */
.admin-bar__brand { display: flex; align-items: center; gap: 0.8rem; text-decoration: none; }
.admin-bar__name {
  display: block;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: 1.2rem;
  letter-spacing: 0.05em;
  text-transform: uppercase;
  color: var(--cream);
  line-height: 1;
}
.admin-bar__tag {
  display: block;
  font-family: var(--font-mono);
  font-size: 0.58rem;
  letter-spacing: 0.24em;
  text-transform: uppercase;
  color: var(--amber);
  margin-top: 3px;
}
.admin-bar__nav { display: flex; gap: var(--space-md); }
.admin-bar__link.is-on { color: var(--amber); }
.admin-bar__who { font-family: var(--font-mono); font-size: 0.72rem; color: var(--muted); }

/* --- 19h. Reply thread ---------------------------------------------------
   Numbered, oldest first, so it reads as a record of what was said rather
   than a chat. This is a log of outgoing messages, not a conversation. --- */
.thread {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-md);
  display: grid;
  gap: 0.75rem;
}
.thread__item {
  background: var(--ink-3);
  border: 1px solid var(--line);
  border-left: 3px solid var(--amber);
  border-radius: var(--radius);
  padding: var(--space-sm) var(--space-md);
}
/* A failed send must not look like a sent one. */
.thread__item--failed { border-left-color: var(--ball); }
.thread__meta { margin: 0 0 0.5em; font-size: var(--step-small); }
.thread__body { margin: 0; color: var(--cream); }
.thread__error {
  margin: 0.6em 0 0;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: #FF8D7A;
}
.tag--failed { background: var(--ball); color: var(--cream); font-weight: 700; }

.reply-form .form-row { margin-bottom: var(--space-sm); }

/* --- 19i. Admin search bar ----------------------------------------------- */
.searchbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.6rem;
  align-items: center;
  margin-bottom: var(--space-md);
}
.searchbar__field { flex: 1 1 260px; min-width: 0; }
.searchbar__field--narrow { flex: 0 1 180px; }
.searchbar input,
.searchbar select {
  width: 100%;
  padding: 0.7em 1em;
  background: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--cream);
  font-family: var(--font-body);
  /* 16px minimum, or iOS Safari zooms the page when the field is focused. */
  font-size: 1rem;
}
.searchbar input:focus,
.searchbar select:focus { border-color: var(--amber); outline: none; }
.searchbar input::placeholder { color: rgba(169, 166, 201, 0.55); }

/* ==========================================================================
   20. SCHEDULE
   --------------------------------------------------------------------------
   A seven-column week that collapses to a single column on phones. CSS grid
   with auto-fit rather than a fixed 7-across, so it degrades by wrapping
   instead of by scrolling sideways.
   ========================================================================== */

.week {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
  gap: 0.6rem;
  margin-top: var(--space-md);
}

.week__day {
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 0.7rem 0.6rem;
  min-width: 0;
}

.week__label {
  margin: 0 0 0.6rem;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--cream);
}

.week__empty { margin: 0; font-size: var(--step-small); opacity: 0.5; }

.slot {
  background: var(--ink-3);
  border: 1px solid var(--line);
  border-left: 3px solid var(--amber);
  border-radius: 6px;
  padding: 0.55rem 0.6rem;
  margin-bottom: 0.5rem;
}
/* Full and closed slots must not read as bookable. */
.slot--full,
.slot--closed { border-left-color: var(--muted); opacity: 0.55; }

.slot__time {
  margin: 0 0 0.25rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  font-weight: 700;
  color: var(--amber);
}
.slot__meta { margin: 0 0 0.4rem; font-size: 0.72rem; line-height: 1.45; }

.slot__form { display: grid; gap: 0.35rem; }
.slot__form select {
  width: 100%;
  padding: 0.4em 0.5em;
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-radius: 5px;
  color: var(--cream);
  /* 16px minimum or iOS Safari zooms when the select is focused. */
  font-size: 16px;
}

/* Build credit — present, not shouting. */
.credit { font-size: var(--step-small); }
.credit a { color: var(--muted); text-decoration: underline; }
.credit a:hover { color: var(--amber); }

/* Below 1100px a seven-column week is unreadable, so it becomes a list of
   days. Deliberately not a horizontal scroller: on a phone you want to see
   the whole week by scrolling the page you are already scrolling. */
@media (max-width: 1100px) {
  .week { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (max-width: 620px) {
  .week { grid-template-columns: minmax(0, 1fr); }
}

/* ==========================================================================
   21. TOASTS
   --------------------------------------------------------------------------
   Flash messages, in the site's own language rather than a framework's.

   The colour rule matters: AMBER IS NOT USED HERE. Amber means "act on this"
   — the inclusion promise, primary buttons, the call to action. Spending it
   on a routine "Saved." would dilute the one signal the design leans on. So
   toasts get their own restrained palette and keep amber for the page.

   Positioning is behind .js-enabled. With JavaScript off they are static
   banners at the top of the content, which is correct: a fixed toast that
   cannot be dismissed would sit over the page forever.
   ========================================================================== */

.toasts {
  display: grid;
  gap: 0.6rem;
  width: min(100% - 2.5rem, var(--measure));
  margin-inline: auto;
  padding-top: var(--space-md);
}

.js-enabled .toasts {
  position: fixed;
  /* Clears the sticky header on every layout. The public pages have a
     chessboard strip above theirs, the admin and account areas do not, so
     this is set generously rather than computed per layout. */
  top: 5.5rem;
  right: 1rem;
  left: auto;
  z-index: 120;
  width: min(calc(100vw - 2rem), 420px);
  margin: 0;
  padding: 0;
  /* The container must not block clicks in the gaps between toasts. */
  pointer-events: none;
}
.js-enabled .toast { pointer-events: auto; }

.toast {
  display: flex;
  align-items: flex-start;
  gap: 0.8rem;
  padding: 0.9rem 1rem;
  background: var(--ink-2);
  border: 1px solid var(--line);
  /* The status colour lives on the left spine, echoing the inclusion band
     and the reply thread. */
  border-left: 4px solid var(--muted);
  border-radius: var(--radius);
  box-shadow: 0 14px 34px rgba(0, 0, 0, 0.42);
}

.js-enabled .toast {
  animation: toast-in 0.42s cubic-bezier(0.16, 1, 0.3, 1) both;
}
@keyframes toast-in {
  from { opacity: 0; transform: translateX(18px); }
  to   { opacity: 1; transform: none; }
}

/* Removed by app.js, which waits for the transition before detaching. */
.toast.is-leaving {
  opacity: 0;
  transform: translateX(18px);
  transition: opacity 0.3s var(--ease), transform 0.3s var(--ease);
}

.toast__mark {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border-radius: 50%;
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 700;
  line-height: 1;
  margin-top: 1px;
}

.toast__text {
  margin: 0;
  flex: 1 1 auto;
  font-size: 0.95rem;
  line-height: 1.5;
  color: var(--cream);
  max-width: none;
}

.toast__close {
  flex: 0 0 auto;
  background: none;
  border: 0;
  color: var(--muted);
  font-size: 1.2rem;
  line-height: 1;
  padding: 0 0.2em;
  cursor: pointer;
}
.toast__close:hover { color: var(--cream); }

/* Status colours. Deliberately not amber — see the section note. */
.toast--success { border-left-color: #2DA078; }
.toast--success .toast__mark { background: rgba(45, 160, 120, 0.2); color: #5FD3A5; }

.toast--error { border-left-color: var(--ball); }
.toast--error .toast__mark { background: rgba(200, 64, 44, 0.22); color: #FF8D7A; }

.toast--warning { border-left-color: #C9922B; }
.toast--warning .toast__mark { background: rgba(201, 146, 43, 0.2); color: #F0C167; }

.toast--info { border-left-color: #7FB2FF; }
.toast--info .toast__mark { background: rgba(127, 178, 255, 0.18); color: #7FB2FF; }

@media (max-width: 620px) {
  .js-enabled .toasts { left: 1rem; right: 1rem; width: auto; }
}

/* --- 19j. Live search ---------------------------------------------------- */
/* The submit button is hidden only once JS has taken over — the class is
   added by app.js, never in the template, so it stays visible for anyone the
   script did not reach. */
.searchbar.is-live .searchbar__submit { display: none; }

.searchbar__status {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Fades the list while a request is in flight, so a slow search does not
   look like nothing happened.
   
   The general sibling combinator (~) rather than adjacent (+): on the
   enquiries page the .filters row sits between the form and the results, so
   an adjacent selector matched nothing and there was no feedback at all. */
[data-search-results] { transition: opacity 0.2s var(--ease); }
.searchbar[aria-busy='true'] ~ [data-search-results] { opacity: 0.45; }

/* ==========================================================================
   22. PROGRESS NOTES AND THE PARENT DASHBOARD
   ========================================================================== */

/* --- 22a. Next session -------------------------------------------------
   The one thing a parent opens the dashboard for, so it gets the amber
   treatment reserved for things that matter. ---------------------------- */
.next-up {
  background: var(--ink-2);
  border: 1px solid rgba(255, 176, 32, 0.45);
  border-left: 5px solid var(--amber);
  border-radius: var(--radius);
  padding: var(--space-md);
  margin-top: var(--space-md);
}
.next-up__when {
  margin: 0 0 0.3em;
  font-family: var(--font-display);
  font-weight: 700;
  font-size: clamp(1.6rem, 4vw, 2.4rem);
  line-height: 1.05;
  color: var(--cream);
}
.next-up__who { margin: 0 0 0.5em; color: var(--cream); }

/* --- 22b. Note timeline ------------------------------------------------- */
.timeline { display: grid; gap: 0.9rem; margin-top: var(--space-md); }

.note {
  background: var(--ink-2);
  border: 1px solid var(--line);
  border-left: 3px solid var(--amber);
  border-radius: var(--radius);
  padding: var(--space-md);
}
/* A draft must never look publishable at a glance. */
.note--draft { border-left-color: var(--muted); opacity: 0.9; }

.note__head { margin: 0 0 0.9em; font-size: var(--step-small); }

.note__label {
  margin: 0.9em 0 0.2em;
  font-family: var(--font-mono);
  font-size: 0.64rem;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--amber);
}
.note__body { margin: 0; color: var(--cream); }

/* Private notes are visually walled off, in the staff view only, so nobody
   mistakes them for something the parent is reading. */
.note__private {
  margin-top: var(--space-sm);
  padding: 0.8rem 1rem;
  background: rgba(200, 64, 44, 0.10);
  border: 1px dashed rgba(200, 64, 44, 0.45);
  border-radius: 6px;
}
.note__private .note__label { color: #FF8D7A; margin-top: 0; }

/* Same treatment on the form, so a parent-facing sentence does not get typed
   into the private box by accident. */
.private-note {
  padding: 0.9rem 1rem;
  background: rgba(200, 64, 44, 0.08);
  border: 1px dashed rgba(200, 64, 44, 0.4);
  border-radius: 6px;
}
.private-note label { color: #FF8D7A !important; }

/* ==========================================================================
   23. PAYMENTS
   ========================================================================== */

.pay-form {
  display: flex;
  gap: 0.4rem;
  flex-wrap: wrap;
  align-items: center;
  margin: 0.6rem 0 0;
}
.pay-form input[type='tel'] {
  width: 9.5rem;
  padding: 0.5em 0.7em;
  background: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: 6px;
  color: var(--cream);
  font-family: var(--font-mono);
  /* 16px minimum or iOS Safari zooms the page on focus. */
  font-size: 16px;
}
.pay-form input[type='tel']:focus { border-color: var(--amber); outline: none; }

.next-up__paid {
  margin: 0.6rem 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: #5FD3A5;
}

/* The raw Safaricom payload. Monospace and scrollable — it is evidence, so
   it is shown verbatim rather than prettified. */
.raw-payload {
  margin: 0.8rem 0 0;
  padding: 1rem;
  background: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  line-height: 1.55;
  overflow-x: auto;
  white-space: pre-wrap;
  word-break: break-word;
  max-height: 320px;
  overflow-y: auto;
}

/* ==========================================================================
   24. PROSE PAGES
   --------------------------------------------------------------------------
   Long-form text: the privacy notice, and any terms or about page that
   follows. Narrower measure and looser leading than the marketing pages —
   this is material to be read carefully, not scanned.
   ========================================================================== */

.prose { max-width: 46rem; }
.prose h1 { margin-bottom: var(--space-md); }
.prose h2 {
  font-size: clamp(1.4rem, 3vw, 1.9rem);
  margin-top: var(--space-lg);
  margin-bottom: var(--space-sm);
}
.prose h3 {
  font-size: 1.1rem;
  letter-spacing: 0.06em;
  color: var(--amber);
  margin-top: var(--space-md);
  margin-bottom: 0.5rem;
}
.prose p { line-height: 1.75; max-width: none; }

.prose-list {
  list-style: none;
  padding: 0;
  margin: 0 0 var(--space-sm);
}
.prose-list li {
  position: relative;
  padding-left: 1.5em;
  margin-bottom: 0.6em;
  line-height: 1.7;
  color: var(--muted);
}
/* Square marker, matching the programme skill lists. */
.prose-list li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.62em;
  width: 7px;
  height: 7px;
  background: var(--amber);
  border-radius: 2px;
}
.prose-list li strong { color: var(--cream); }

/* --- 19k. Coaches and assignment ---------------------------------------- */
.assign-form {
  display: flex;
  gap: 0.4rem;
  align-items: center;
  flex-wrap: wrap;
  margin-top: 0.5rem;
}
.assign-form select {
  padding: 0.35em 0.6em;
  background: var(--ink-3);
  border: 1px solid var(--line);
  border-radius: 5px;
  color: var(--cream);
  /* 16px minimum or iOS Safari zooms the page on focus. */
  font-size: 16px;
  max-width: 12rem;
}

/* A deactivated account must be visibly different at a glance, not just by
   reading the label. */
.enquiry.is-inactive { opacity: 0.55; }

.tag--admin { background: rgba(127, 178, 255, 0.2); color: #7FB2FF; font-weight: 700; }
.tag--off { background: rgba(169, 166, 201, 0.2); color: var(--muted); font-weight: 700; }

/* --- 20a. Slot pricing label --------------------------------------------
   A parent must be able to tell at a glance which product a slot is: their
   own child at KSh 1,300, or the whole slot at KSh 2,400. The two look
   identical on a calendar otherwise. */
.slot__price {
  margin: 0 0 0.45rem;
  font-family: var(--font-mono);
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
}
/* Private groups are the exception, so they are the ones that stand out. */
.slot__price--group { color: var(--amber); }
