/* ============================================================
   Screens added in PRD v1.3: the landing page, the terms, the
   course material in its two modes, and the recording player.
   Loaded after app.css; defines no colour of its own.
   ============================================================ */

/* ---------------------------------------------------- whatsapp ----------- */

.wa-btn { display: inline-flex; align-items: center; gap: var(--s2) }
.wa-icon { flex: 0 0 auto }

/* Always reachable, never in the way of the content underneath. */
.wa-float {
  position: fixed;
  inset-inline-end: var(--s4);
  inset-block-end: var(--s4);
  z-index: 30;
  display: inline-flex;
  align-items: center;
  gap: var(--s2);
  padding: var(--s3) var(--s4);
  min-height: 48px;
  border-radius: var(--r-pill);
  background: var(--ink-600);
  border: 1px solid var(--ok);
  color: var(--ok);
  font-size: var(--fs-micro);
  font-family: var(--font);
}
.wa-float:hover { background: var(--ink-500); color: var(--ok) }
.wa-float span { display: none }
@media (min-width: 560px) { .wa-float span { display: inline } }

/* ---------------------------------------------------- landing ------------ */

.hero {
  padding: var(--s8) var(--s4) var(--s7);
  text-align: center;
  background: var(--ink-900);
  border-bottom: 1px solid var(--ink-500);
}
.hero .logo { height: 64px; width: auto; margin-bottom: var(--s5) }
.hero h1 {
  font-size: var(--fs-h3);
  max-width: 20ch;
  margin: 0 auto var(--s4);
}
@media (min-width: 720px) { .hero h1 { font-size: var(--fs-h2) } }
.hero .sub {
  color: var(--text-mid);
  font-size: var(--fs-body);
  max-width: 46ch;
  margin: 0 auto var(--s6);
}
.hero .cta-row { display: flex; gap: var(--s3); justify-content: center; flex-wrap: wrap }

.section-title {
  text-align: center;
  margin-bottom: var(--s6);
}
.section-title .eyebrow {
  color: var(--accent);
  font-size: var(--fs-micro);
  font-weight: 700;
  display: block;
  margin-bottom: var(--s2);
}

.path-step {
  display: flex;
  gap: var(--s4);
  padding: var(--s4) 0;
  border-bottom: 1px solid var(--ink-500);
  align-items: flex-start;
  min-width: 0;
}
.path-step:last-child { border-bottom: 0 }
.path-num {
  flex: 0 0 auto;
  width: 34px; height: 34px;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
  border: 1px solid var(--ink-400);
  font-family: var(--font-mono);
  color: var(--text-mid);
}
.path-step.is-promise .path-num { border-color: var(--accent); color: var(--accent) }
.path-body { min-width: 0 }
.path-body h3 { margin-bottom: var(--s1) }

.tier-grid { display: grid; gap: var(--s4); grid-template-columns: minmax(0, 1fr) }
@media (min-width: 640px) { .tier-grid { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (min-width: 1000px) { .tier-grid { grid-template-columns: repeat(3, minmax(0, 1fr)) } }
/* Five cards since 1.8 — the four packages plus Special (PRD 5.17). Three
   across is the honest middle: at four the fifth card sits alone on a second
   row looking like an afterthought, which is the thing moving it into the grid
   was meant to stop.

   The five only appear in one row once there is room for them to be readable.
   The page wrap is 1280px, and five columns inside it leave about 190px of
   text per card — Arabic at that measure runs six lines a bullet. So above
   1500px the grid alone steps outside the wrap, by a symmetric negative
   margin: symmetric because `margin-inline` is direction-agnostic and this
   page is RTL, where a start/end pair written by hand is the classic way to
   end up with the layout mirrored. */
@media (min-width: 1500px) {
  .tier-grid {
    grid-template-columns: repeat(5, minmax(0, 1fr));
    margin-inline: calc((100% - min(1460px, 100vw - var(--s8))) / 2);
  }
}

.tier {
  background: var(--ink-700);
  border: 1px solid var(--ink-500);
  border-radius: var(--r-card);
  padding: var(--s5);
  display: flex; flex-direction: column; min-width: 0;
}

/* The ladder, drawn (1.8). Each card's ground is a gradient between two ink
   tokens, lifting one step per plan, so the four read as degrees of the same
   thing rather than as four parallel choices — and Pro, the one most people
   take, is the only one warmed by the accent.

   ⚠️ Every stop is a var(--token). No colour is written here, and none may be:
   tokens.css is the source and launch criterion 12 is mechanical. */
.tier[data-tier="basic"]   { background: linear-gradient(180deg, var(--ink-700), var(--ink-800)) }
.tier[data-tier="plus"]    { background: linear-gradient(180deg, var(--ink-600), var(--ink-700)) }
.tier[data-tier="pro"]     { background: linear-gradient(180deg, var(--accent-wash), var(--ink-600)) }
.tier[data-tier="premium"] { background: linear-gradient(180deg, var(--ink-500), var(--ink-700)) }
/* Special is not a rung on that ladder — it is the door beside it — so it is
   drawn as an outline rather than as a heavier version of Premium. */
.tier[data-tier="special"] {
  background: linear-gradient(180deg, var(--ink-800), var(--ink-700));
  border-style: dashed;
  border-color: var(--ink-400);
}

.tier.is-featured {
  border-color: var(--accent);
  box-shadow: var(--e-focus);
}
/* Pro is lifted, not merely outlined: on a row of five, a border colour alone
   is a difference the eye has to look for. */
@media (min-width: 1500px) {
  .tier.is-featured { transform: translateY(calc(var(--s3) * -1)) }
}
.tier .name { font-weight: 700; font-size: var(--fs-body); margin-bottom: var(--s2) }
.tier .price { font-family: var(--font-mono); font-size: var(--fs-h3); line-height: var(--lh-tight) }
.tier .per { color: var(--text-low); font-size: var(--fs-micro); margin-bottom: var(--s4) }
.tier ul { flex: 1 1 auto }

/* ---------------------------------------------------- material ----------- */

.block {
  background: var(--ink-700);
  border: 1px solid var(--ink-500);
  border-inline-start-width: 3px;
  border-radius: var(--r-card);
  padding: var(--s5);
  margin-bottom: var(--s4);
}
/* The block type is the session loop from the pedagogy framework, so the
   colour is state, not decoration: it tells the trainer where they are. */
.block[data-type="driving_question"] { border-inline-start-color: var(--accent) }
.block[data-type="hook"]             { border-inline-start-color: var(--accent-soft) }
.block[data-type="example"]          { border-inline-start-color: var(--info) }
.block[data-type="activity"]         { border-inline-start-color: var(--ok) }
.block[data-type="prompt"]           { border-inline-start-color: var(--accent-deep) }
.block[data-type="mistake"]          { border-inline-start-color: var(--err) }
.block[data-type="checkpoint"]       { border-inline-start-color: var(--warn) }
.block[data-type="recap"]            { border-inline-start-color: var(--text-mid) }

.block-kind {
  font-size: var(--fs-micro);
  color: var(--text-low);
  margin-bottom: var(--s2);
}
.block h3 { margin-bottom: var(--s3) }
.block-body p { margin: 0 0 var(--s2); color: var(--text-hi) }
.block-body p:last-child { margin-bottom: 0 }

.block-note {
  margin-top: var(--s4);
  padding-top: var(--s3);
  border-top: 1px dashed var(--ink-400);
  color: var(--text-low);
  font-size: var(--fs-micro);
}

.prompt-box {
  background: var(--ink-900);
  border: 1px solid var(--ink-400);
  border-radius: var(--r-chip);
  padding: var(--s4);
  font-family: var(--font-mono);
  font-size: var(--fs-micro);
  line-height: var(--lh-dense);
  white-space: pre-wrap;
  overflow-x: auto;
  color: var(--text-hi);
}

/* -------------------------------------------- presenter mode ------------- */

/* The deck used to be one flat fill of --ink-900 on every slide, which made an
   hour of teaching look like one unchanging screen. Depth here is built out of
   the tokens that already exist — the ink ramp and the accent washes — because
   the identity is used as-is and nothing new is invented for it (PRD 8.1).

   Three layers, from front to back: an accent bloom where the eye lands, a soft
   pool under the text, and the ink gradient itself. `transparent` is a keyword,
   not a colour value, so no literal ever appears in this file. */
.deck {
  position: relative;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background:
    radial-gradient(90% 55% at 50% 0%, var(--accent-wash), transparent 70%),
    radial-gradient(70% 50% at 50% 100%, var(--ink-700), transparent 75%),
    linear-gradient(var(--ink-800), var(--ink-900) 55%);
}

/* A vignette, so the edges fall away and the centre reads as lit. On a
   projector in a bright room this is the difference between a slide that has a
   focus and a rectangle of text. */
.deck::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(120% 90% at 50% 45%, transparent 45%, var(--ink-900));
  z-index: 0;
}
.deck-stage,
.deck-bar,
.deck-progress { position: relative; z-index: 1 }

.deck-stage {
  flex: 1 1 auto;
  display: grid;
  place-items: center;
  padding: var(--s6) var(--s5);
  min-height: 0;
}
.slide { width: 100%; max-width: 1000px; display: none }
.slide.is-current { display: block }
.slide .block-kind { font-size: var(--fs-small) }
.slide h2 {
  font-size: var(--fs-h3);
  margin-bottom: var(--s5);
}
.slide .block-body p {
  font-size: var(--fs-lead);
  line-height: var(--lh-body);
  margin-bottom: var(--s4);
}
@media (min-width: 900px) {
  .slide h2 { font-size: var(--fs-h2) }
  .slide .block-body p { font-size: var(--fs-h3); line-height: 1.5 }
}
/* ---- one look per block type -------------------------------------------
   Nine block types are the session loop from PEDAGOGY-FRAMEWORK.md, and they
   are meant to feel different in the room: a driving question is not a prompt
   and neither is a common mistake. Before this they were nine identical dark
   rectangles, so the structure the material enforces was invisible to the
   people it was built for.

   Each type moves the light and adds one accent rule. Only the accent family
   and the ink ramp are used — tokens.css reserves --ok/--warn/--err/--info for
   state and forbids them as decoration. */

.slide { padding-inline-start: var(--s5); border-inline-start: 2px solid transparent }

/* The question that opens the stage: brightest, centred, nothing competing. */
.deck:has(.slide.is-current[data-type="driving_question"]) {
  background:
    radial-gradient(80% 60% at 50% 35%, var(--accent-glow), transparent 70%),
    linear-gradient(var(--ink-800), var(--ink-900) 60%);
}
.slide[data-type="driving_question"] { text-align: center; border-inline-start-color: transparent }
.slide[data-type="driving_question"] h2 { font-size: var(--fs-h2) }

/* The hook: light from the top corner, the way an opening arrives. */
.deck:has(.slide.is-current[data-type="hook"]) {
  background:
    radial-gradient(70% 60% at 85% 0%, var(--accent-wash), transparent 70%),
    linear-gradient(var(--ink-800), var(--ink-900) 55%);
}
.slide[data-type="hook"] { border-inline-start-color: var(--accent-soft) }

.slide[data-type="concept"] { border-inline-start-color: var(--accent-line) }
.slide[data-type="example"] { border-inline-start-color: var(--ink-400) }
.slide[data-type="activity"] { border-inline-start-color: var(--accent) }

/* The prompt is text to be read out and copied, so the room goes quiet around
   it: no bloom, no rule, just the mono block on the deepest ink. */
.deck:has(.slide.is-current[data-type="prompt"]) { background: var(--ink-900) }
.slide[data-type="prompt"] { border-inline-start-color: transparent; padding-inline-start: 0 }
.slide[data-type="prompt"] .prompt-box { font-size: var(--fs-lead) }

/* A common mistake is lit from below — it is the thing to look down at. */
.deck:has(.slide.is-current[data-type="mistake"]) {
  background:
    radial-gradient(80% 55% at 50% 100%, var(--ink-600), transparent 75%),
    linear-gradient(var(--ink-900), var(--ink-800) 90%);
}
.slide[data-type="mistake"] { border-inline-start-color: var(--accent-deep) }

/* A checkpoint is a question to the room: narrow, centred, everything else off. */
.deck:has(.slide.is-current[data-type="checkpoint"]) {
  background: radial-gradient(55% 55% at 50% 45%, var(--ink-800), var(--ink-900) 80%);
}
.slide[data-type="checkpoint"] {
  max-width: 720px;
  text-align: center;
  border-inline-start-color: transparent;
  padding-inline-start: 0;
}

/* The recap is the widest slide — it is the one people photograph. */
.slide[data-type="recap"] { max-width: 1180px; border-inline-start-color: var(--accent) }

/* :has() is unsupported in a few older browsers, and the fallback there is the
   plain deck background — a graceful loss of emphasis, never a broken slide. */

/* The presenter note is for the person holding the room, not the room.
   ⚠️ This rule is emphasis, NOT a lock: for a student the note is never in the
   page at all, because the server strips it (criterion 25). Anything hidden
   only here would still be in view-source and in any print. */
.slide .block-note { display: none }
.deck.show-notes .slide .block-note { display: block; font-size: var(--fs-small) }

/* A clip or a document sitting on a block. */
.block-video { margin-top: var(--s5) }
.slide .block-video { max-width: 900px; margin-inline: auto }
.block-files {
  margin-top: var(--s4);
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--s2);
}
.block-files li {
  display: flex;
  gap: var(--s3);
  align-items: baseline;
  padding: var(--s3);
  border: 1px solid var(--ink-500);
  border-radius: var(--r-chip);
  background: var(--ink-700);
}
.block-files li::before { content: none }

.deck-bar {
  display: flex; align-items: center; gap: var(--s4);
  padding: var(--s3) var(--s5);
  border-top: 1px solid var(--ink-500);
  background: var(--ink-800);
  flex-wrap: wrap;
}
.deck-bar .spacer { flex: 1 1 auto; min-width: 0 }
.deck-count { font-family: var(--font-mono); color: var(--text-mid) }
.deck-progress { height: 3px; background: var(--ink-500) }
.deck-progress span { display: block; height: 100%; background: var(--accent); transition: width var(--t-ui) }

/* --------------------------------------------- recording player ---------- */

.player-frame {
  position: relative;
  width: 100%;
  aspect-ratio: 16 / 9;
  background: var(--ink-900);
  border: 1px solid var(--ink-500);
  border-radius: var(--r-card);
  overflow: hidden;
}
.player-frame iframe {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  border: 0;
}

/* ---------------------------------------------------- terms -------------- */

.terms article { max-width: 70ch }
.terms h2 { margin-top: var(--s6) }
.terms .rule-hard {
  border: 1px solid var(--err);
  border-radius: var(--r-card);
  padding: var(--s4);
  margin: var(--s5) 0;
}

/* ---------------------------------------------------- figures ------------ */

/* Images sit under the words they explain. A comparison set lays out side by
   side, because the comparison IS the teaching — three shot sizes stacked
   vertically stop being a comparison. */
.figures { margin-top: var(--s4); display: grid; gap: var(--s3); grid-template-columns: minmax(0, 1fr) }
@media (min-width: 640px) {
  .figures-set[data-count="2"] { grid-template-columns: repeat(2, minmax(0, 1fr)) }
  .figures-set[data-count="4"] { grid-template-columns: repeat(2, minmax(0, 1fr)) }
}
@media (min-width: 900px) {
  .figures-set[data-count="3"] { grid-template-columns: repeat(3, minmax(0, 1fr)) }
  .figures-set[data-count="4"] { grid-template-columns: repeat(4, minmax(0, 1fr)) }
}

.figure { margin: 0; min-width: 0 }
.figure img {
  display: block;
  width: 100%;
  height: auto;
  /* Identity rule: contain, never cover, and never a pre-shrunk crop. */
  object-fit: contain;
  border: 1px solid var(--ink-500);
  border-radius: var(--r-card);
  background: var(--ink-900);
}
.figure figcaption {
  margin-top: var(--s2);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  line-height: var(--lh-dense);
}

/* Admin-only: a picture that is planned but not produced yet. The student
   never sees this, and never sees a broken image either. */
.figure-missing {
  margin-top: var(--s3);
  padding: var(--s3);
  border: 1px dashed var(--warn);
  border-radius: var(--r-chip);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  display: grid;
  gap: var(--s1);
}
.figure-missing strong { color: var(--warn) }
.figure-missing .mono { word-break: break-all }

/* On a projector the picture is the slide, so it gets the room. */
.slide .figures { margin-top: var(--s5) }
.slide .figure img { max-height: 56vh }
.slide .figure figcaption { font-size: var(--fs-small); margin-top: var(--s3) }

/* ------------------------------------------------- the guided tour ------- */
/* One step at a time, styled like a lesson because it is one (PRD 5.19). */

.tour-progress {
  height: 4px;
  background: var(--ink-600);
  border-radius: var(--r-pill);
  overflow: hidden;
  margin-bottom: var(--s5);
}
.tour-progress span {
  display: block;
  height: 100%;
  background: var(--accent);
  transition: width var(--t-reveal);
}

/* The thing to actually go and do. It is set apart because it is the half of
   the step that teaches; the paragraphs above it only explain. */
.tour-try {
  margin-top: var(--s5);
  padding: var(--s4);
  border: 1px solid var(--accent-line);
  border-radius: var(--r-card);
  background: var(--accent-wash);
}
.tour-try-kind {
  display: block;
  color: var(--accent);
  font-size: var(--fs-micro);
  font-weight: 700;
  margin-bottom: var(--s2);
}
.tour-try p { margin: 0; color: var(--text-hi) }

.tour-actions {
  display: flex;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-top: var(--s5);
}

.tour-list { margin: 0; padding-inline-start: var(--s6); display: grid; gap: var(--s2) }
.tour-list li::marker { color: var(--text-low); font-family: var(--font-mono) }
.tour-list li.is-current::marker { color: var(--accent) }
.tour-list li.is-current a { color: var(--accent); font-weight: 700 }

/* ------------------------------------------- the month calendar ---------- */
/* A calendar, because everyone can already read one (PRD 5.20). The previous
   weeks-across-groups matrix was correct and unreadable: it made the reader
   hold "which row is my group" and "which column is this week" at once, and it
   never showed a date. Nothing here needs a key.

   Seven columns starting Saturday — the Egyptian week. Days from the
   neighbouring months are dimmed, not hidden: a session on the 1st is real, and
   dropping it would make the last row lie. */

.cal-scroll {
  overflow-x: auto;
  margin-top: var(--s5);
}
.cal {
  /* No floor above phone width. A fixed 900px min-width put a scrollbar
     under every laptop window narrower than that, and the bar sat on top
     of the last row and hid it. Seven columns genuinely do not fit a
     phone, so the floor comes back below 640px — and the ordered list
     under the calendar is the real answer on that screen anyway. */
  min-width: 0;
  border: 1px solid var(--ink-500);
  border-radius: var(--r-card);
  overflow: hidden;
  background: var(--ink-700);
}
.cal-head,
.cal-week {
  display: grid;
  grid-template-columns: repeat(7, minmax(0, 1fr));
}
.cal-dayname {
  padding: var(--s3);
  text-align: center;
  color: var(--text-mid);
  font-size: var(--fs-micro);
  font-weight: 700;
  background: var(--ink-600);
  border-inline-start: 1px solid var(--ink-500);
}
.cal-dayname:first-child { border-inline-start: 0 }

.cal-day {
  min-height: 150px;
  padding: var(--s2);
  background: var(--ink-800);
  border-inline-start: 1px solid var(--ink-500);
  border-top: 1px solid var(--ink-500);
  display: flex;
  flex-direction: column;
  gap: var(--s2);
}
.cal-day:first-child { border-inline-start: 0 }

/* A day outside the month is context, not content. */
.cal-day.is-outside { background: var(--ink-900) }
.cal-day.is-outside .cal-number { color: var(--text-low) }

.cal-date { display: flex; align-items: center; justify-content: center; gap: var(--s2); margin-bottom: var(--s1) }
.cal-number {
  font-family: var(--font-mono);
  font-size: var(--fs-small);
  color: var(--text-mid);
  width: 30px; height: 30px;
  display: grid; place-items: center;
  border-radius: var(--r-pill);
}
.cal-month { color: var(--text-low); font-size: var(--fs-micro) }

/* Today is the one thing the eye should find without looking. */
.cal-day.is-today .cal-number {
  background: var(--accent);
  color: var(--ink-900);
  font-weight: 700;
}

/* Events read as pills, the way every calendar people already use draws them:
   a solid rounded chip with the time and the title on one line. The earlier
   bordered card looked like a form field and made four sessions in a week feel
   like four documents. */
/* Tight on purpose. A day has to be able to hold two sessions and still
   read as one square, so the box carries the time, the title and the one
   button that does something — the badge and the written room moved out
   to the screens that arrange the month rather than attend it. */
.cal-event {
  display: block;
  padding: var(--s1) var(--s2);
  margin-bottom: var(--s1);
  border-radius: var(--r-chip);
  background: var(--accent-wash);
  border-inline-start: 3px solid var(--accent-line);
  font-size: var(--fs-micro);
  line-height: var(--lh-dense);
  overflow: hidden;
}
.cal-event[data-tier="plus"]    { border-inline-start-color: var(--accent-soft) }
.cal-event[data-tier="pro"]     { border-inline-start-color: var(--accent) }
.cal-event[data-tier="premium"] { border-inline-start-color: var(--accent-deep) }
/* The opening lecture belongs to the whole intake, so it reads as its own thing. */
.cal-event.is-opening {
  background: var(--accent-glow);
  border-inline-start-color: var(--accent);
}
.cal-time  { display: block; color: var(--accent-soft); font-family: var(--font-mono) }
/* Two lines, then an ellipsis, with the whole title on hover and written out
   in full in the ordered list under the calendar. The title is the only
   thing left in the box that can grow, and a day has to be able to hold a
   second session without pushing the week off the screen. */
.cal-title {
  color: var(--text-hi);
  overflow-wrap: anywhere;
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  overflow: hidden;
}
.cal-badge { display: block; color: var(--text-low); margin-top: var(--s1) }

/* The room is a URL, and a URL is what broke this screen. In a day cell
   about a hundred pixels wide, sharing a flex row with the copy button,
   the address had a few pixels to lay out in — and `overflow-wrap:
   anywhere` did exactly what it was asked to: one character per line,
   seven hundred pixels tall, one day swallowing the whole month.
   A cell says *that* there is a room, on one line that cannot grow. The
   whole address is still in the DOM, on the title attribute and on the
   copy button — truncation here is visual only, so the scoping checks
   that read the response body are untouched. */
.cal-room {
  display: flex; align-items: center; gap: var(--s1);
  flex-wrap: wrap;
  margin-top: var(--s1);
  padding-top: var(--s1);
  border-top: 1px solid var(--ink-500);
}
.cal-room .mono {
  flex: 1 1 100%;
  min-width: 0; max-width: 100%;
  direction: ltr; text-align: start;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  color: var(--text-low);
}
/* The same size as the join button. It was inheriting the full-size button
   padding, so the trainer's own square — the one screen still showing the
   written room — kept the tall box the student's had lost. */
.cal-room .btn { flex: 0 0 auto; padding: var(--s1) var(--s2); font-size: var(--fs-micro) }

.cal-join { margin-top: var(--s1); display: flex; align-items: center; gap: var(--s1); flex-wrap: wrap }
/* Full width: it is the only thing in the box a student presses, and a
   small button floating in the middle of a cell reads as decoration. */
.cal-join .btn { flex: 1 1 100%; padding: var(--s1) var(--s2); font-size: var(--fs-micro); text-align: center }

@media (max-width: 700px) {
  .cal-day { min-height: 104px }
}
@media (max-width: 640px) {
  .cal { min-width: 620px }
}

/* ---------------------------------------- the monthly schedule grid ------ */
/* Weeks across, tracks down (PRD 5.20). Five week columns do not fit a phone,
   and the parent is the person most likely to open this on one — so the table
   scrolls inside its own box and the page itself never scrolls sideways. */

.grid-scroll {
  overflow-x: auto;
  margin-top: var(--s5);
  border: 1px solid var(--ink-500);
  border-radius: var(--r-card);
}
.month-grid {
  width: 100%;
  border-collapse: collapse;
  min-width: 720px;
}
.month-grid th,
.month-grid td {
  padding: var(--s3);
  border-inline-start: 1px solid var(--ink-500);
  border-bottom: 1px solid var(--ink-500);
  vertical-align: top;
  text-align: start;
}
.month-grid thead th {
  background: var(--ink-700);
  color: var(--text-mid);
  font-size: var(--fs-micro);
  font-weight: 700;
  position: sticky;
  top: 0;
  z-index: 1;
}
.month-grid tbody th {
  background: var(--ink-700);
  color: var(--text-hi);
  font-size: var(--fs-micro);
  font-weight: 700;
  min-width: 150px;
  position: sticky;
  inset-inline-start: 0;
  z-index: 1;
}
.grid-corner { min-width: 150px }
.grid-dates {
  display: block;
  color: var(--text-low);
  font-family: var(--font-mono);
  font-weight: 400;
  margin-top: var(--s1);
}

/* An empty cell is the message, not the absence of one: a week with no session
   for a group is exactly what this screen is for. It is dimmed rather than
   blank so the eye can count the gaps down a column. */
.month-grid td.is-empty { background: var(--ink-800) }
.grid-none { color: var(--text-low); font-family: var(--font-mono) }

.grid-session {
  display: grid;
  gap: var(--s1);
  padding: var(--s3);
  margin-bottom: var(--s2);
  border-radius: var(--r-chip);
  background: var(--ink-600);
  border-inline-start: 2px solid var(--accent-line);
  font-size: var(--fs-micro);
  line-height: var(--lh-dense);
}
.grid-session:last-child { margin-bottom: 0 }
.grid-session[data-tier="premium"] { border-inline-start-color: var(--accent) }
.grid-session[data-tier="pro"] { border-inline-start-color: var(--accent-soft) }
.grid-when { color: var(--text-mid); font-weight: 700 }
.grid-time { color: var(--accent-soft) }
.grid-title { color: var(--text-hi) }

.month-nav {
  display: flex;
  align-items: flex-end;
  gap: var(--s4);
  flex-wrap: wrap;
  margin-bottom: var(--s4);
}
.month-nav .spacer { flex: 1 1 auto; min-width: 0 }

.clash-list { margin: var(--s3) 0 0; padding-inline-start: var(--s5) }
.clash-list li { margin-bottom: var(--s2) }

.date-list {
  margin: var(--s3) 0 0;
  padding: 0;
  list-style: none;
  display: grid;
  gap: var(--s2);
}
.date-list li {
  padding: var(--s3);
  border: 1px solid var(--ink-500);
  border-radius: var(--r-chip);
  background: var(--ink-700);
}
.date-list.is-skipped li { color: var(--text-low); border-style: dashed }

/* ------------------------------------------------ the handout ------------ */
/* One page, meant to be printed and handed out (PRD 5.16.4). It renders with a
   student's eyes whoever opens it, so there is nothing here to hide on paper —
   which is the point: safety is in what the page contains, not in what print
   happens to suppress. */

.handout {
  max-width: 880px;
  margin: 0 auto;
  padding: var(--s7) var(--s5) var(--s9);
}
.handout-head { margin-bottom: var(--s6) }
.handout-stage {
  color: var(--accent);
  font-size: var(--fs-micro);
  font-weight: 700;
  margin-bottom: var(--s2);
}
.handout-actions { margin-bottom: var(--s6); display: flex; gap: var(--s3); align-items: center }
.handout .block { break-inside: avoid }

@media print {
  /* Nothing on this page is secret, so these rules are about paper, not
     secrecy. The belt-and-braces hiding below covers the other two screens,
     which a person may still print from the browser menu. */
  .no-print,
  .deck-bar,
  .deck-progress,
  .block-note,
  .figure-missing,
  .site-header,
  .skip-link,
  .wa-float,
  footer { display: none !important }

  /* A deck prints as every slide, not just the one on screen. */
  .slide { display: block !important; break-after: page }
  .slide[hidden] { display: block !important }
  .deck, .deck-stage { display: block; min-height: 0 }

  /* A collapsed checkpoint on paper is a missing one. */
  .collapse > *:not(summary) { display: block !important }

  .handout { padding: 0; max-width: none }
  .figure img { max-height: none; break-inside: avoid }
}

/* ============================================================
   Landing page — the conversion funnel (PRD 5.17).
   Every colour is a token; no literal value appears here.
   ============================================================ */

.hero-kicker {
  color: var(--accent);
  font-size: var(--fs-micro);
  font-weight: 700;
  margin-bottom: var(--s3);
}
.hero h1 { max-width: 22ch }
.hero-video { max-width: 860px; margin: 0 auto var(--s6) }
.hero .cta-row .btn { min-width: 200px; justify-content: center }

/* The milestone cards carry the two moments that actually sell the course. */
.is-milestone { border-color: var(--accent-line) }
.is-milestone h3 { margin-top: var(--s2) }

/* ---------------------------------------------------- the trainer -------- */

.trainer-grid {
  display: grid;
  gap: var(--s6);
  grid-template-columns: minmax(0, 1fr);
  align-items: start;
}
@media (min-width: 860px) {
  .trainer-grid { grid-template-columns: minmax(0, 280px) minmax(0, 1fr) }
}

.trainer-photo { margin: 0 }
.trainer-photo img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
  border-radius: var(--r-card);
  border: 1px solid var(--ink-500);
}
.trainer-body { min-width: 0 }
.trainer-title {
  color: var(--accent);
  font-weight: 700;
  margin-bottom: var(--s4);
}
.trainer-body h3 { margin-top: var(--s5) }

/* The one thing a parent is actually deciding on. */
.trainer-note {
  margin-top: var(--s5);
  padding: var(--s4);
  border: 1px solid var(--accent-line);
  border-radius: var(--r-card);
  background: var(--ink-600);
  color: var(--text-mid);
}
.trainer-note strong { color: var(--text-hi); display: block; margin-bottom: var(--s2) }

/* ---------------------------------------------------- the showcase ------- */

.showcase { display: grid; gap: var(--s4); grid-template-columns: minmax(0, 1fr) }
@media (min-width: 720px) { .showcase { grid-template-columns: repeat(2, minmax(0, 1fr)) } }
@media (min-width: 1100px) { .showcase { grid-template-columns: repeat(3, minmax(0, 1fr)) } }
.showcase-item { min-width: 0 }
.showcase-item p { margin: var(--s2) 0 0 }

/* ---------------------------------------------------- fit / not fit ------ */

.fit-yes { border-inline-start: 3px solid var(--ok) }
.fit-no  { border-inline-start: 3px solid var(--warn) }
.fit-no .criteria li::before { background: var(--warn) }

/* ---------------------------------------------------- tiers -------------- */

.tier { position: relative }
.tier-flag {
  position: absolute;
  inset-block-start: calc(var(--s4) * -1);
  inset-inline-start: var(--s5);
  background: var(--accent);
  color: var(--ink-900);
  font-size: var(--fs-micro);
  font-weight: 700;
  padding: var(--s1) var(--s3);
  border-radius: var(--r-pill);
}
.tier-for {
  color: var(--text-low);
  font-size: var(--fs-micro);
  margin-bottom: var(--s4);
}
.tier .wa-btn { margin-top: var(--s4); justify-content: center }

/* Special's flag says where it goes, not that it is popular — so it is quiet. */
.tier-flag.is-quiet { background: var(--ink-400); color: var(--text-hi) }
/* «بالاتفاق» is a word in the price slot. The mono face and the h3 size belong
   to a number; a word set that way reads as a truncated figure. */
.tier .price.is-word {
  font-family: var(--font);
  font-size: var(--fs-lead);
  font-weight: 700;
  color: var(--accent-soft);
}

/* Scarcity that is real. Every line in here is a fact that already exists in
   SUBSCRIPTION-MODEL.md — nothing on this page counts down. */
.scarcity {
  margin-top: var(--s6);
  padding: var(--s5);
  border: 1px solid var(--warn);
  border-radius: var(--r-card);
  background: var(--ink-600);
}
.scarcity h3 { color: var(--warn); margin-bottom: var(--s3) }

/* What every tier includes, stated once above the cards (PRD 5.13-أ). It sits
   before the prices on purpose: the reader should know the course is the same
   for everyone before they start comparing numbers, or the cheapest tier reads
   as a lesser course rather than less contact. */
.included {
  margin-bottom: var(--s6);
  padding: var(--s5);
  border: 1px solid var(--accent-line);
  border-radius: var(--r-card);
  background: var(--accent-wash);
}
.included h3 { color: var(--accent); margin-bottom: var(--s3) }

/* Bands under the tier cards, for things that are not a tier: the optional
   offline meetup, and the arrangements priced per case. They read as a
   different kind of thing from the cards above on purpose — a full-width strip
   rather than a fifth column — because putting either one in the grid would
   make it look like a package you choose instead of them. */
.addon-band {
  margin-top: var(--s6);
  padding: var(--s5);
  border: 1px solid var(--ink-400);
  border-radius: var(--r-card);
  background: var(--ink-700);
}
.addon-band.is-custom { border-style: dashed }
.addon-head {
  display: flex;
  align-items: center;
  gap: var(--s3);
  flex-wrap: wrap;
  margin-bottom: var(--s3);
}
.addon-head h3 { margin: 0 }
.addon-band .criteria { margin-top: var(--s4) }
.addon-band .wa-btn { margin-top: var(--s4) }

/* ---------------------------------------------------- objections --------- */

.faq {
  border-bottom: 1px solid var(--ink-500);
  padding-bottom: var(--s2);
}
.faq > summary { font-size: var(--fs-small); color: var(--text-hi); font-weight: 500 }
.faq p { padding-inline-start: var(--s5); margin-bottom: var(--s3) }

/* ---------------------------------------------------- closer ------------- */

.closer .cta-row { display: flex; gap: var(--s3); justify-content: center; flex-wrap: wrap }

/* The audience is on phones, so the one action follows them down the page.
   It hides on desktop, where the CTAs are already never far away. */
.sticky-cta {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  z-index: 25;
  padding: var(--s3) var(--s4);
  background: var(--ink-900);
  border-top: 1px solid var(--ink-500);
  display: flex;
  justify-content: center;
}
.sticky-cta .wa-btn { width: 100%; max-width: 420px; justify-content: center }
@media (min-width: 860px) { .sticky-cta { display: none } }

/* The floating support bubble and the sticky bar must never stack on mobile. */
@media (max-width: 859px) { .wa-float { inset-block-end: 84px } }
body { padding-block-end: 76px }
@media (min-width: 860px) { body { padding-block-end: 0 } }

/* ------------------------------------------- click-to-play video facade --- */

/* The player is not loaded until someone presses play. On 3G a third-party
   iframe on first paint is the most expensive thing on the page, and the
   platform has a two-second budget (PRD 8.2). */
.video-facade {
  display: block;
  position: relative;
  width: 100%;
  padding: 0;
  border: 1px solid var(--ink-500);
  border-radius: var(--r-card);
  background: var(--ink-900);
  cursor: pointer;
  overflow: hidden;
  min-height: 0;
}
.video-facade img {
  display: block;
  width: 100%;
  height: auto;
  object-fit: contain;
  opacity: .72;
  transition: opacity var(--t-ui);
}
.video-facade:hover img,
.video-facade:focus-visible img { opacity: 1 }

.video-play {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  color: var(--text-hi);
  pointer-events: none;
}
.video-facade:hover .video-play { color: var(--accent) }

.hero-reassure {
  color: var(--text-mid);
  font-size: var(--fs-micro);
  margin-top: var(--s4);
}
.hero-reassure span { display: block; margin-top: var(--s1); color: var(--text-low) }
.hero-reassure strong { color: var(--ok) }
