/* HossTrain — shared styles for the marketing pages.
 *
 * One stylesheet for both landing pages, so the school page and the student
 * page cannot drift into looking like two different products.
 *
 * Screenshot slots are deliberately placeholders: .shot renders a labelled
 * frame until a real image is dropped in, so the page can be built, reviewed
 * and reorganised before a single screenshot exists.
 */

:root {
  --ink: #eaf1ff;
  --ink-soft: #a9bbd8;
  --ink-faint: #6f83a4;

  --bg: #050b18;
  --bg-lift: #0a1428;
  --panel: rgba(14, 26, 48, 0.72);
  --panel-solid: #0d1a31;
  --line: rgba(120, 158, 214, 0.18);
  --line-strong: rgba(120, 158, 214, 0.38);

  /* One accent, used sparingly, plus a second for the student pages so the
   * two sites are recognisably siblings rather than identical. */
  --brand: #ff8a4c;
  --brand-deep: #e5622a;
  --brand-soft: rgba(255, 138, 76, 0.14);
  --accent: #4cc4ff;
  --accent-soft: rgba(76, 196, 255, 0.12);
  --good: #3ddc97;
  --bad: #ff6b6b;

  --radius: 16px;
  --radius-lg: 26px;
  --shadow: 0 24px 70px rgba(0, 0, 0, 0.45);
  --maxw: 1180px;

  --font: "Inter", "Segoe UI", system-ui, -apple-system, sans-serif;
  --display: "Barlow Condensed", "Inter", system-ui, sans-serif;
}

/* Student pages lead with the cooler accent. */
body.student-theme {
  --brand: #4cc4ff;
  --brand-deep: #2aa3e5;
  --brand-soft: rgba(76, 196, 255, 0.14);
  --accent: #ff8a4c;
  --accent-soft: rgba(255, 138, 76, 0.12);
}

* { box-sizing: border-box; }

html { scroll-behavior: smooth; }

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font);
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* ---- Background field ---------------------------------------------------
 * Three soft light sources and a faint grid, fixed behind everything. This is
 * what stops a dark page reading as a flat black rectangle.
 */
.backdrop {
  position: fixed;
  inset: 0;
  z-index: -2;
  background:
    radial-gradient(60rem 40rem at 12% -10%, rgba(255, 138, 76, 0.16), transparent 60%),
    radial-gradient(50rem 36rem at 92% 8%, rgba(76, 196, 255, 0.14), transparent 62%),
    radial-gradient(46rem 40rem at 50% 108%, rgba(120, 90, 220, 0.14), transparent 60%),
    linear-gradient(180deg, #050b18 0%, #071026 55%, #050b18 100%);
}

.backdrop::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    linear-gradient(rgba(120, 158, 214, 0.055) 1px, transparent 1px),
    linear-gradient(90deg, rgba(120, 158, 214, 0.055) 1px, transparent 1px);
  background-size: 64px 64px;
  mask-image: radial-gradient(80% 60% at 50% 30%, #000 40%, transparent 100%);
}

/* The `hidden` attribute is a UA-stylesheet rule and loses to any author
 * `display` declaration. Anything laid out with grid or flex therefore stays
 * visible while claiming to be hidden. Said once, here, for the whole site. */
[hidden] { display: none !important; }

a { color: inherit; }

.wrap {
  width: min(var(--maxw), calc(100% - 40px));
  margin: 0 auto;
}

/* ---- Header -------------------------------------------------------------- */
.site-head {
  position: sticky;
  top: 0;
  z-index: 40;
  backdrop-filter: blur(14px);
  background: rgba(5, 11, 24, 0.76);
  border-bottom: 1px solid var(--line);
}

.site-head .wrap {
  display: flex;
  align-items: center;
  gap: 18px;
  padding: 14px 0;
}

.brand-mark {
  display: flex;
  align-items: center;
  gap: 10px;
  font-family: var(--display);
  font-size: 24px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
  text-decoration: none;
  font-weight: 700;
}

/* The badge sits on a ground within a few points of the page's own, so it
 * needs no plate or border to sit cleanly — rounding it just keeps the
 * corners from reading as a pasted square. */
.brand-badge {
  width: 38px;
  height: 38px;
  border-radius: 9px;
  display: block;
}

/* ---- Hero wash ----------------------------------------------------------
 * The badge as the page's own background at the top, rather than as a picture
 * placed somewhere in the layout. Absolute rather than fixed, so it scrolls
 * away and the normal backdrop simply carries on underneath it — which is the
 * whole effect: the mark is what you land on, not something that follows you
 * down the page.
 *
 * Sits above .backdrop (z-index -2) and below every bit of content.
 */
.hero-wash {
  position: absolute;
  /* Well down into the hero rather than at the page top: the mark reads as
   * something you come to as the copy runs out, not as a backdrop the
   * headline is fighting. Scales with viewport height so it lands in the same
   * place on a laptop and a tall monitor. */
  top: clamp(320px, 52vh, 700px);
  left: 0;
  right: 0;
  height: min(880px, 104vh);
  z-index: -1;
  pointer-events: none;
  background: url("../marketing/hosstrain-badge.png") no-repeat center top;
  background-size: min(760px, 96vw) auto;
  opacity: 0.85;
  /* Faded out over the lower half so it dissolves into the page instead of
   * ending on a hard edge. The badge's own ground is within a few points of
   * the page's, so the sides need no help; only the bottom does. */
  -webkit-mask-image: linear-gradient(180deg, #fff 0%, #fff 42%, transparent 96%);
  mask-image: linear-gradient(180deg, #fff 0%, #fff 42%, transparent 96%);
}

/* The main page's hero is two columns and much taller than the student page's,
 * so the mark needs its own vertical placement: low enough to sit clear of
 * the copy rather than behind it. Horizontally it is centred, same as the
 * student page.
 *
 * Only on the wide layout. Stacked, there are no columns to sit beside and
 * off-centre reads as misaligned — and the student page's placement, which is
 * the shared default, is already right there. */
@media (min-width: 941px) {
  .hero-wash-main {
    background-position: center top;
    top: clamp(516px, 84vh, 1134px);
  }
}

@media (max-width: 940px) {
  /* Narrower screens put the copy directly over the middle of the mark, where
   * the neon is brightest. Smaller and higher keeps it behind the header. */
  .hero-wash {
    top: clamp(240px, 34vh, 450px);
    height: min(560px, 72vh);
    background-size: min(460px, 86vw) auto;
    opacity: 0.7;
  }
}

.nav {
  margin-left: auto;
  display: flex;
  gap: 22px;
  align-items: center;
}

.nav a {
  color: var(--ink-soft);
  text-decoration: none;
  font-size: 15px;
  font-weight: 500;
}

.nav a:hover { color: var(--ink); }

@media (max-width: 860px) {
  .nav .nav-link { display: none; }
}

@media (min-width: 861px) and (max-width: 1120px) {
  .nav { gap: 15px; }
  .nav a { font-size: 14px; }
}

/* ---- Buttons ------------------------------------------------------------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  padding: 13px 24px;
  border-radius: 999px;
  font-weight: 650;
  font-size: 15px;
  text-decoration: none;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.16s ease, box-shadow 0.16s ease, background 0.16s ease;
  white-space: nowrap;
}

.btn:hover { transform: translateY(-2px); }

.btn-primary {
  background: linear-gradient(135deg, var(--brand), var(--brand-deep));
  color: #17110b;
  box-shadow: 0 12px 34px rgba(255, 138, 76, 0.3);
}

body.student-theme .btn-primary { color: #04121c; }

.btn-ghost {
  border-color: var(--line-strong);
  color: var(--ink);
  background: rgba(255, 255, 255, 0.02);
}

.btn-ghost:hover { background: rgba(255, 255, 255, 0.06); }

.btn-sm { padding: 10px 18px; font-size: 14px; }

.btn-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: center;
}

/* ---- Type ---------------------------------------------------------------- */
.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-size: 12px;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--brand);
  background: var(--brand-soft);
  border: 1px solid var(--line-strong);
  padding: 6px 14px;
  border-radius: 999px;
}

h1, h2, h3 { line-height: 1.1; text-wrap: balance; margin: 0; }

h1 {
  font-family: var(--display);
  font-size: clamp(42px, 6.4vw, 78px);
  letter-spacing: -0.01em;
  font-weight: 700;
}

h2 {
  font-family: var(--display);
  font-size: clamp(30px, 4vw, 48px);
  font-weight: 700;
  letter-spacing: 0.01em;
}

h3 { font-size: 20px; font-weight: 650; }

.lede { font-size: clamp(17px, 2vw, 20px); color: var(--ink-soft); max-width: 62ch; }

.muted { color: var(--ink-soft); }
.faint { color: var(--ink-faint); font-size: 14px; }

.grad {
  background: linear-gradient(120deg, var(--brand), var(--accent));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* ---- Sections ------------------------------------------------------------ */
section { padding: 84px 0; position: relative; }

.section-head { max-width: 70ch; margin-bottom: 40px; display: grid; gap: 14px; }

.rule {
  height: 1px;
  background: linear-gradient(90deg, var(--line-strong), transparent);
  border: 0;
  margin: 0;
}

/* ---- Hero ---------------------------------------------------------------- */
.hero { padding: 76px 0 64px; }

.hero-grid {
  display: grid;
  grid-template-columns: 1.05fr 0.95fr;
  gap: 54px;
  align-items: center;
}

@media (max-width: 940px) {
  .hero-grid { grid-template-columns: 1fr; gap: 40px; }
}

.hero-copy {
  display: grid;
  gap: 22px;
  justify-items: start;
  position: relative;
  isolation: isolate;
}

/* Outlined glyphs rather than a card behind them.
 *
 * A scrim did fix the contrast, but it covered the mark it was supposed to sit
 * in front of — the point of putting artwork there is to see it. The stroke is
 * painted *behind* the fill via paint-order, so the letterforms keep their
 * weight instead of being eaten from the inside, which is what a plain
 * text-stroke does. A soft halo underneath catches the rest.
 *
 * The eyebrow and the buttons are left alone: they carry their own background
 * and already have contrast.
 */
.hero-copy h1 {
  text-shadow: 0 2px 26px rgba(5, 11, 24, 0.92);
}

.hero-copy .lede,
.hero-copy .faint,
.hero-copy .stat b,
.hero-copy .stat span {
  paint-order: stroke fill;
  -webkit-text-stroke: 4px rgba(5, 11, 24, 0.8);
  text-shadow: 0 1px 14px rgba(5, 11, 24, 0.92);
}

/* Larger in the hero than elsewhere on the page: this copy is read over
   artwork and at arm's length, and the rest of the page is not. */
.hero-copy .lede { font-size: clamp(20px, 2.3vw, 24px); max-width: 60ch; }
.hero-copy .faint { font-size: 17px; }
.hero-copy .stat b { font-size: 36px; }
.hero-copy .stat span { font-size: 15px; }

.stat-strip {
  display: flex;
  flex-wrap: wrap;
  gap: 26px;
  padding-top: 8px;
}

.stat b {
  display: block;
  font-family: var(--display);
  font-size: 30px;
  color: var(--ink);
  line-height: 1;
}

.stat span { font-size: 13px; color: var(--ink-faint); }

/* ---- Cards --------------------------------------------------------------- */
.grid { display: grid; gap: 18px; }
.g2 { grid-template-columns: repeat(2, 1fr); }
.g3 { grid-template-columns: repeat(3, 1fr); }
.g4 { grid-template-columns: repeat(4, 1fr); }

@media (max-width: 980px) { .g3, .g4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 680px) { .g2, .g3, .g4 { grid-template-columns: 1fr; } }

.card {
  background: var(--panel);
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 22px;
  display: grid;
  gap: 10px;
  align-content: start;
  position: relative;
  overflow: hidden;
}

.card::before {
  content: "";
  position: absolute;
  inset: 0 0 auto 0;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--line-strong), transparent);
}

.card h3 { font-size: 18px; }
.card p { margin: 0; color: var(--ink-soft); font-size: 15px; }

.card-icon {
  width: 40px;
  height: 40px;
  border-radius: 11px;
  display: grid;
  place-items: center;
  background: var(--brand-soft);
  border: 1px solid var(--line-strong);
  color: var(--brand);
}

.card-icon svg { width: 20px; height: 20px; }

/* A card marked as something competitors charge extra for, or lack. */
.card.flag { border-color: rgba(255, 138, 76, 0.4); }

.tag {
  align-self: start;
  font-size: 11px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
  padding: 4px 10px;
  border-radius: 999px;
  background: var(--brand-soft);
  color: var(--brand);
  border: 1px solid var(--line-strong);
}

/* ---- Feature blocks (alternating) ---------------------------------------- */
.feature {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 52px;
  align-items: center;
  padding: 30px 0;
}

.feature.flip .feature-media { order: -1; }

@media (max-width: 940px) {
  .feature { grid-template-columns: 1fr; gap: 30px; }
  .feature.flip .feature-media { order: 0; }
}

.feature-copy { display: grid; gap: 16px; align-content: start; }

.ticks { display: grid; gap: 10px; margin: 4px 0 0; padding: 0; list-style: none; }

.ticks li {
  display: grid;
  grid-template-columns: 22px 1fr;
  gap: 10px;
  color: var(--ink-soft);
  font-size: 15px;
}

.ticks li::before {
  content: "";
  width: 18px;
  height: 18px;
  margin-top: 3px;
  border-radius: 6px;
  background: var(--brand-soft);
  border: 1px solid var(--line-strong);
  background-image: linear-gradient(135deg, transparent 40%, var(--brand) 40%, var(--brand) 60%, transparent 60%);
}

/* ---- Screenshot slots ----------------------------------------------------
 * Until real images arrive, .shot renders its own label. Drop an <img> inside
 * and the placeholder disappears behind it.
 */
.shot {
  position: relative;
  border-radius: 14px;
  overflow: hidden;
  background:
    repeating-linear-gradient(45deg, rgba(120, 158, 214, 0.05) 0 12px, transparent 12px 24px),
    var(--panel-solid);
  border: 1px dashed var(--line-strong);
  min-height: 220px;
  display: grid;
  place-items: center;
  text-align: center;
  padding: 18px;
}

/* Once a real capture lands in a slot, the placeholder chrome has to go —
   the padding, the dashed edge and the hatch are scaffolding, and leaving
   them on makes the screenshot read as pasted onto the device rather than
   displayed by it. */
.shot:has(img) {
  padding: 0;
  border: 0;
  background: #000;
  min-height: 0;
  display: block;
}

.shot img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  object-position: top center;
  display: block;
}

.shot-name {
  font-family: var(--display);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  font-size: 14px;
  color: var(--ink-faint);
}

.shot-hint { font-size: 12px; color: var(--ink-faint); opacity: 0.75; }

/* A phone bezel, so a plain capture reads as a device rather than a crop. */
.device {
  position: relative;
  margin: 0 auto;
  width: min(300px, 82%);
  padding: 9px;
  border-radius: 36px;
  background: linear-gradient(155deg, #2a3854, #131c2e 45%, #070d18);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow), inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

/* The power button, on the bezel edge where a real one is. The speaker bar
   this replaces was drawn at the top of the screen area, so it landed on the
   capture instead of on the phone. */
.device::before {
  content: "";
  position: absolute;
  top: 92px;
  right: -2px;
  width: 2px;
  height: 46px;
  border-radius: 2px;
  background: linear-gradient(180deg, #35435f, #1a2437);
}

/* A light sweep across the glass. This is what actually sells the illusion:
   a screenshot with nothing in front of it reads as a rectangle laid on top,
   however good the bezel is. */
.device::after {
  content: "";
  position: absolute;
  inset: 9px;
  border-radius: 28px;
  pointer-events: none;
  z-index: 2;
  background: linear-gradient(
    205deg,
    rgba(255, 255, 255, 0.16) 0%,
    rgba(255, 255, 255, 0.05) 16%,
    rgba(255, 255, 255, 0) 38%
  );
  box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.06);
}

/* 24/49 is the captures' own ratio once the Android navigation bar is cropped
   off. Matching it exactly means object-fit has nothing left to crop, so no
   part of a screen is quietly cut away to make it fit. */
.device .shot {
  border-radius: 28px;
  border-style: solid;
  min-height: 0;
  aspect-ratio: 24 / 49;
}

/* Two phones, slightly fanned, for sections that show a flow. */
.device-pair {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  align-items: center;
}

.device-pair .device { width: 100%; }
.device-pair .device:first-child { transform: rotate(-4deg); }
.device-pair .device:last-child { transform: rotate(4deg) translateY(14px); }

@media (max-width: 520px) {
  .device-pair { grid-template-columns: 1fr; }
  .device-pair .device { transform: none !important; }
}

/* A laptop, for the desktop apps: bezel, glass, and a base underneath so it
   sits on something rather than floating. */
.desk {
  position: relative;
  margin: 0 auto 22px;
  border-radius: 14px 14px 6px 6px;
  padding: 12px 12px 26px;
  background: linear-gradient(155deg, #2a3854, #131c2e 45%, #070d18);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow), inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

/* Camera dot, centred in the chin below the screen. */
.desk::before {
  content: "";
  position: absolute;
  bottom: 11px;
  left: 50%;
  transform: translateX(-50%);
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.22);
}

/* The base: wider than the lid, with the notch a thumb lifts it by. */
.desk::after {
  content: "";
  position: absolute;
  left: 50%;
  bottom: -12px;
  transform: translateX(-50%);
  width: 112%;
  max-width: none;
  height: 12px;
  border-radius: 0 0 12px 12px;
  background: linear-gradient(180deg, #202c44, #0c1424);
  box-shadow: 0 14px 26px rgba(0, 0, 0, 0.45);
}

.desk .shot {
  border-radius: 5px;
  border-style: solid;
  min-height: 0;
  aspect-ratio: 16 / 10;
}

/* Same light sweep as the phone, over the laptop glass. */
.desk .shot:has(img)::after {
  content: "";
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: linear-gradient(
    205deg,
    rgba(255, 255, 255, 0.13) 0%,
    rgba(255, 255, 255, 0.04) 14%,
    rgba(255, 255, 255, 0) 34%
  );
}

/* A tablet: between the two, and the shape the instructor app is used in. */
.tablet {
  position: relative;
  margin: 0 auto;
  width: min(460px, 92%);
  padding: 14px;
  border-radius: 24px;
  background: linear-gradient(155deg, #2a3854, #131c2e 45%, #070d18);
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow), inset 0 1px 0 rgba(255, 255, 255, 0.12);
}

.tablet .shot {
  border-radius: 12px;
  border-style: solid;
  min-height: 0;
  aspect-ratio: 4 / 3;
}

.tablet::after {
  content: "";
  position: absolute;
  inset: 14px;
  border-radius: 12px;
  pointer-events: none;
  z-index: 2;
  background: linear-gradient(
    205deg,
    rgba(255, 255, 255, 0.14) 0%,
    rgba(255, 255, 255, 0.04) 15%,
    rgba(255, 255, 255, 0) 36%
  );
}

/* ---- Comparison table ---------------------------------------------------- */
.table-scroll {
  overflow-x: auto;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
  -webkit-overflow-scrolling: touch;
}

.table-scroll table {
  border-collapse: collapse;
  width: 100%;
  min-width: 940px;
  font-size: 14px;
}

.table-scroll th,
.table-scroll td {
  padding: 13px 14px;
  text-align: center;
  border-bottom: 1px solid var(--line);
  white-space: nowrap;
}

.table-scroll thead th {
  position: sticky;
  top: 0;
  background: var(--panel-solid);
  color: var(--ink);
  font-weight: 650;
  text-align: center;
  z-index: 1;
}

.table-scroll tbody th {
  text-align: left;
  font-weight: 600;
  color: var(--ink-soft);
  position: sticky;
  left: 0;
  background: var(--panel-solid);
  min-width: 260px;
  white-space: normal;
}

.table-scroll tbody tr:hover td { background: rgba(120, 158, 214, 0.05); }

.col-ours { background: rgba(255, 138, 76, 0.07); }
thead .col-ours { background: rgba(255, 138, 76, 0.14); color: var(--brand); }

.yes { color: var(--good); font-weight: 700; }
.no { color: var(--bad); opacity: 0.75; }
.part { color: var(--ink-faint); font-size: 12px; }

.scroll-hint {
  font-size: 13px;
  color: var(--ink-faint);
  margin: 10px 2px 0;
}

/* ---- Beta / pricing placeholder ------------------------------------------ */
.beta-panel {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  padding: clamp(28px, 5vw, 52px);
  background:
    radial-gradient(30rem 20rem at 15% 0%, var(--brand-soft), transparent 65%),
    var(--panel);
  display: grid;
  gap: 22px;
  justify-items: center;
  text-align: center;
}

.beta-panel h2 { max-width: 20ch; }

.beta-note {
  font-size: 14px;
  color: var(--ink-faint);
  max-width: 56ch;
}

/* ---- Steps --------------------------------------------------------------- */
.steps { counter-reset: step; display: grid; gap: 16px; }

.step {
  display: grid;
  grid-template-columns: 48px 1fr;
  gap: 18px;
  align-items: start;
  padding: 20px;
  border: 1px solid var(--line);
  border-radius: var(--radius);
  background: var(--panel);
}

.step::before {
  counter-increment: step;
  content: counter(step);
  width: 44px;
  height: 44px;
  border-radius: 12px;
  display: grid;
  place-items: center;
  font-family: var(--display);
  font-size: 22px;
  color: var(--brand);
  background: var(--brand-soft);
  border: 1px solid var(--line-strong);
}

/* ---- Cross-promotion band ------------------------------------------------ */
.crosslink {
  border: 1px solid var(--line-strong);
  border-radius: var(--radius-lg);
  padding: clamp(24px, 4vw, 40px);
  background:
    radial-gradient(28rem 18rem at 85% 20%, var(--accent-soft), transparent 60%),
    var(--panel);
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 26px;
  align-items: center;
}

@media (max-width: 780px) {
  .crosslink { grid-template-columns: 1fr; }
}

/* ---- FAQ ----------------------------------------------------------------- */
details.faq {
  border: 1px solid var(--line);
  border-radius: var(--radius);
  padding: 16px 20px;
  background: var(--panel);
}

details.faq + details.faq { margin-top: 10px; }

details.faq summary {
  cursor: pointer;
  font-weight: 650;
  list-style: none;
}

details.faq summary::-webkit-details-marker { display: none; }

details.faq summary::after {
  content: "+";
  float: right;
  color: var(--brand);
  font-size: 20px;
  line-height: 1;
}

details.faq[open] summary::after { content: "\2013"; }

details.faq p { color: var(--ink-soft); margin: 12px 0 0; font-size: 15px; }

/* ---- Footer -------------------------------------------------------------- */
.site-foot {
  border-top: 1px solid var(--line);
  padding: 40px 0 60px;
  color: var(--ink-faint);
  font-size: 14px;
}

.site-foot .wrap { display: grid; gap: 16px; }

.foot-row { display: flex; flex-wrap: wrap; gap: 18px; align-items: center; }
.foot-row a { color: var(--ink-soft); text-decoration: none; }
.foot-row a:hover { color: var(--ink); }

/* ---- Motion -------------------------------------------------------------- */
.reveal {
  opacity: 0;
  transform: translateY(14px);
  transition: opacity 0.6s ease, transform 0.6s ease;
}

.reveal.in { opacity: 1; transform: none; }

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  .reveal { opacity: 1; transform: none; transition: none; }
  .btn:hover { transform: none; }
}

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 3px;
  border-radius: 6px;
}

/* ---- Hero rig: laptop with a phone standing in front of it -------------- */
.hero-rig { position: relative; padding-bottom: 34px; }
.hero-rig .desk { width: 100%; margin-bottom: 0; }
.hero-rig .device {
  position: absolute;
  right: -6px;
  bottom: 0;
  width: 132px;
  margin: 0;
  z-index: 3;
}

@media (max-width: 940px) {
  .hero-rig .device { width: 112px; }
}

@media (max-width: 520px) {
  .hero-rig { padding-bottom: 0; }
  .hero-rig .device { position: static; width: min(190px, 56%); margin: -26px auto 0; }
}

/* ---- Frame sizing -------------------------------------------------------
 * The captures are 1080px wide; rendering them into a 265px frame threw away
 * three quarters of the detail and made every screen unreadable. Give the
 * media column more of the grid and let the frames use it.
 */
.hero-grid { grid-template-columns: 1fr 1.15fr; }
.feature { grid-template-columns: 1fr 1.12fr; }

.device { width: min(340px, 100%); }

/* Two phones side by side in half a column leaves each one tiny. Overlapping
 * them lets both be much larger for the same width, and reads as a pair
 * rather than two separate pictures. */
.device-pair {
  display: block;
  position: relative;
  padding: 0 0 30px;
  max-width: 460px;
  margin: 0 auto;
}

.device-pair .device {
  width: 66%;
  margin: 0;
}

.device-pair .device:first-child {
  transform: rotate(-3deg);
}

.device-pair .device:last-child {
  position: absolute;
  right: 0;
  bottom: 0;
  transform: rotate(3deg);
  z-index: 2;
}

.hero-rig .device { width: 34%; max-width: 190px; }

@media (max-width: 940px) {
  .hero-grid, .feature { grid-template-columns: 1fr; }
  .hero-rig .device { width: 26%; }
}

@media (max-width: 520px) {
  .device-pair { max-width: 340px; padding-bottom: 22px; }
  .device-pair .device { width: 70%; }
  .device-pair .device:first-child,
  .device-pair .device:last-child { transform: none; }
  .hero-rig .device { width: min(180px, 50%); max-width: none; }
}

/* ---- Bezels --------------------------------------------------------------
 * These started as one fixed padding for every frame, which is only right at
 * one width: 9px is 3% of a 300px phone but 5.3% of a 170px one, so the small
 * frames showed a broad band of device body around the capture and stopped
 * reading as a screen.
 *
 * Percentages are the obvious fix and the wrong one — percentage padding
 * resolves against the containing block, not the element, so the absolutely
 * positioned hero phone resolved 2.4% against the whole rig and came out at
 * 8%. Explicit values per context, checked by measuring the rendered result.
 */
.device { padding: 7px; border-radius: 30px; }
.device .shot { border-radius: 24px; }
.device::after { inset: 7px; border-radius: 24px; }

.hero-rig .device { padding: 4px; border-radius: 18px; }
.hero-rig .device .shot { border-radius: 15px; }
.hero-rig .device::after { inset: 4px; border-radius: 15px; }
.hero-rig .device::before { top: 26%; height: 14%; }

.desk { padding: 8px 8px 18px; border-radius: 12px 12px 6px 6px; }
.desk .shot { border-radius: 4px; }
.desk::before { bottom: 7px; width: 4px; height: 4px; }

.tablet { padding: 10px; border-radius: 20px; }
.tablet .shot { border-radius: 11px; }
.tablet::after { inset: 10px; border-radius: 11px; }

/* The laptop holds captures of different shapes — a 16:10 roster and a wider
 * desktop-window grab. Forcing one ratio would crop whichever does not match,
 * so when the slot holds an image it takes that image's own proportions. The
 * placeholder keeps 16/10, since it has no image to take them from. */
.desk .shot:has(img) { aspect-ratio: auto; }
.desk .shot:has(img) img { height: auto; }

/* ---- Stack rig: a laptop behind a pair of phones -------------------------
 * The same thing seen from both ends — the instructor's screen behind, the
 * student's two phone screens in front of it.
 *
 * Laid out rather than absolutely positioned. The first version pinned the
 * phones to the bottom of the rig, whose height came from the laptop; phones
 * are taller than a 16:10 laptop at these widths, so they overflowed upward
 * and sat on top of the paragraph above. Flex with a common baseline and a
 * negative margin gives the same overlap and cannot escape its container.
 */
.stack-rig {
  position: relative;
  display: flex;
  align-items: flex-end;
}

.stack-rig .device-pair {
  order: 1;
  width: 34%;
  max-width: 360px;
  margin: 0 -7% 0 0;
  z-index: 3;
}

/* Lifted, so the phones hang below it the way things do on a desk. */
.stack-rig .desk {
  order: 2;
  width: 70%;
  margin: 0 0 5% 0;
}

/* Stacked on a phone: the overlap stops reading as depth and starts reading
 * as clutter, so they simply sit one above the other. */
@media (max-width: 520px) {
  .stack-rig { flex-direction: column; align-items: stretch; }
  .stack-rig .desk { width: 100%; margin: 0 0 18px; order: 1; }
  .stack-rig .device-pair {
    order: 2;
    width: 100%;
    max-width: 340px;
    margin: 0 auto;
  }
}

/* ---- Stacked feature -----------------------------------------------------
 * Copy above, picture below, both full width. For a composition that needs
 * room to spread sideways: squeezing three frames into half a two-column grid
 * makes each of them too small to read, which defeats the point of showing
 * them at all.
 */
.feature.stacked {
  grid-template-columns: 1fr;
  gap: 28px;
}

/* The prose still stops at a readable measure even though its column is now
 * the full page width — long lines are harder to read, not easier. */
.feature.stacked .feature-copy { max-width: 68ch; }

.feature.stacked .feature-media { width: 100%; }

/* With the full width to work in, both can be larger — but the phones stay
 * the smaller of the two, because the instructor's screen is half the point
 * of the picture. */
.feature.stacked .stack-rig { justify-content: center; }
.feature.stacked .stack-rig .desk { width: 62%; }
.feature.stacked .stack-rig .device-pair { width: 30%; max-width: 340px; }

@media (max-width: 940px) {
  .feature.stacked .stack-rig .desk { width: 68%; }
  .feature.stacked .stack-rig .device-pair { width: 34%; }
}

/* ---- Beta signup --------------------------------------------------------
 * The only form on the site, so the controls are defined here rather than in
 * a shared form system that would have one member.
 */
.beta-form { display: grid; gap: 18px; max-width: 620px; margin: 0 auto; }

.field { display: grid; gap: 7px; }

.field > label {
  font-size: 13px;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  font-weight: 700;
  color: var(--ink-soft);
}

.field input,
.field select,
.field textarea {
  font: inherit;
  color: var(--ink);
  background: rgba(255, 255, 255, 0.04);
  border: 1px solid var(--line-strong);
  border-radius: 12px;
  padding: 13px 15px;
  width: 100%;
  box-sizing: border-box;
}

.field textarea { min-height: 110px; resize: vertical; }

.field input:focus-visible,
.field select:focus-visible,
.field textarea:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
}

/* The code itself: monospaced and spaced out, because it is read off a card
 * or an email one character at a time and typos are the whole failure mode. */
.field input.code-input {
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
  font-size: 22px;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  text-align: center;
  padding: 16px 15px;
}

.field-row { display: grid; grid-template-columns: 1fr 1fr; gap: 18px; }
@media (max-width: 620px) { .field-row { grid-template-columns: 1fr; } }

/* Said in place, under the control it belongs to — an error at the top of a
 * form is an error nobody reads. */
.form-note { font-size: 15px; margin: 0; }
.form-note.bad { color: #ff9a8a; }
.form-note.good { color: #7fdba0; }

/* See [hidden] note above — this is the same rule, kept for the beta steps
 * even though the global one now covers them. */
.beta-step[hidden] { display: none; }

.beta-done {
  text-align: center;
  display: grid;
  gap: 14px;
  justify-items: center;
}

/* ---- Language strip: one screen, every language --------------------------
 * The claim is the count, not the detail, so these frames are small and all
 * show the same student home — the eye is meant to compare words, not screens.
 *
 * Eight frames, two rows of four. One row of eight is what the count wants
 * and the wrap cannot pay for: at 1180px wide that is 130px a frame, small
 * enough that the words stop being readable and the point is lost. Four and
 * four buys back nearly twice the width.
 *
 * A grid rather than wrapped flex, because eight divides exactly by both
 * column counts this uses — four and two — so no row is ever left short and
 * there is no orphan to centre. Three columns is the one split that strands a
 * remainder, so the layout skips it entirely and steps from four straight to
 * two.
 *
 * Bezels get explicit values here for the reason given under "Bezels" above —
 * the shared 7px is 4.6% of a 152px frame and reads as a broad band of plastic
 * instead of a phone.
 */
.lang-strip {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  gap: 20px 16px;
  align-items: start;
  max-width: 1000px;
  margin: 0 auto;
}

.lang-strip .lang { margin: 0; }
.lang-strip .device { width: 100%; padding: 4px; border-radius: 16px; }
.lang-strip .device .shot { border-radius: 13px; }
.lang-strip .device::after { inset: 4px; border-radius: 13px; }
.lang-strip .device::before { top: 26%; height: 14%; }

/* Each language named in itself first, then in English — a reader who wants
   their own language is scanning for the word they already know. */
.lang-strip figcaption {
  margin-top: 11px;
  text-align: center;
  font-size: 12px;
  line-height: 1.35;
  color: var(--ink-faint);
}

.lang-strip figcaption b {
  display: block;
  font-size: 14px;
  font-weight: 600;
  color: var(--ink);
}

.lang-note {
  margin: 20px auto 0;
  max-width: 620px;
  text-align: center;
  font-size: 14px;
  color: var(--ink-faint);
}

/* Two columns from here down. The cap keeps the frames near the size they
   were on the row above rather than letting two of them fill a tablet: 193px
   at the last four-column width, 204px at the first two-column one, so the
   step across the breakpoint is invisible. */
@media (max-width: 860px) {
  .lang-strip {
    grid-template-columns: repeat(2, 1fr);
    max-width: 420px;
    gap: 18px 12px;
  }
}

/* ---- The live section's rig ---------------------------------------------
 * Same idea as the hero — desktop behind, phone in front — with one
 * difference that matters. The hero's phone sits over the right third of the
 * laptop, which costs nothing on a roster capture. Here the laptop holds a
 * whole application window whose controls run along its bottom edge, and that
 * same overlap covers the host's own camera and half the control bar: record,
 * mute, whiteboard, end session. Those buttons are the evidence that this is
 * a room being run rather than a video being played.
 *
 * So the phone is pulled out to the margin and overlaps by a hair — enough to
 * read as standing in front of the laptop, not enough to hide anything.
 */
#live .hero-rig { padding-bottom: 0; }
#live .hero-rig .desk { width: 80%; margin: 0 0 22px 0; }
#live .hero-rig .device { width: 22%; max-width: 200px; right: 0; }

/* On a phone the rig stops being side by side and stacks, and the percentage
   widths above would leave the student's screen at 78px — a smudge. The
   shared .hero-rig rule already stacks it; these restate the sizes, which are
   the only part the #live selector is still winning. */
@media (max-width: 520px) {
  #live .hero-rig .desk { width: 100%; margin: 0 0 16px 0; }
  #live .hero-rig .device {
    width: min(190px, 56%);
    max-width: none;
    margin: -20px auto 0;
  }
}

/* ---- Brand wall: one screen, five schools --------------------------------
 * "Your school, not our template" is worth nothing as a sentence. These are
 * the same owner dashboard, capture for capture, under five schools' own
 * marks and palettes — the claim shown rather than asserted.
 *
 * No laptop bezel on these. Five of them would spend a third of the width on
 * drawn plastic, and what has to read here is the colour and the mark, not
 * the device they happen to be on.
 *
 * Wrapped flex with a fixed basis, for the reason the language strip stopped
 * using a grid: five divides into three columns leaving two behind, and a
 * grid strands them at the left of the last row. Flex centres the short row
 * for free — three then two on a desktop, two then two then one on a tablet,
 * one at a time on a phone.
 */
.brand-wall {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 18px;
  margin: 32px auto 0;
}

.brand-wall figure {
  margin: 0;
  flex: 0 1 366px;
  border-radius: 10px;
  overflow: hidden;
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow);
  background: #000;
}

/* A school's own phone, over its own desk.
   The wall's argument is that none of this is our template, and a dashboard
   alone only shows the half a school owner sees. The phone is what their
   members carry, in the same colours, so each tile carries both ends.

   It breaks the frame on purpose. Sitting wholly inside the desktop capture,
   it read as part of the screen rather than as a second device -- the one
   thing it has to say is "this is a phone". So the tile stops clipping, the
   border and shadow move onto the desktop image itself, and the margin is
   there to be overhung into rather than to space the wall out. */
.brand-wall figure.brand-pair {
  position: relative;
  overflow: visible;
  border: 0;
  background: transparent;
  box-shadow: none;
  margin: 30px 26px 0 0;
}

.brand-wall figure.brand-pair > img:first-of-type {
  border-radius: 10px;
  border: 1px solid var(--line-strong);
  box-shadow: var(--shadow);
  background: #000;
}

.brand-wall .brand-phone {
  position: absolute;
  top: -26px;
  right: -22px;
  width: 25%;
  height: auto;
  border-radius: 9px;
  border: 1px solid rgba(255, 255, 255, 0.28);
  /* Darker and wider than the desktop tile's, so it lifts off rather than
     sitting flush against it. */
  box-shadow: 0 14px 30px rgba(0, 0, 0, 0.62);
  z-index: 2;
}

.brand-wall img {
  display: block;
  width: 100%;
  height: auto;
}

.brand-note {
  margin: 18px auto 0;
  max-width: 660px;
  text-align: center;
  font-size: 14px;
  color: var(--ink-faint);
}

/* ---- A photograph beside a section heading -------------------------------
 * A section head is capped at 70ch, which leaves the right of the band empty
 * on a wide screen. This puts a picture there.
 *
 * The picture carries its own fade to transparent, baked into the file rather
 * than applied here, and that is the whole reason it can sit on this page at
 * all: it has no edge to align to anything, so it occupies the space instead
 * of filling a box in it. It follows that it gets no background, no border,
 * no radius and no shadow — every one of those would draw the rectangle
 * straight back on.
 */
.head-art {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 460px);
  gap: 24px;
  align-items: center;
  margin-bottom: 40px;
}

.head-art .section-head { margin-bottom: 0; }

.head-art-img {
  display: block;
  width: 100%;
  height: auto;
}

/* Once the two stop sitting side by side the picture goes under the words,
   and the gap closes up: the fade already leaves plenty of air above it. */
@media (max-width: 940px) {
  .head-art {
    grid-template-columns: 1fr;
    gap: 0;
    margin-bottom: 28px;
  }
  .head-art-img { max-width: 460px; margin: 0 auto; }
}

/* ---- A drawing beside a copy block ---------------------------------------
 * Same idea as .head-art, one level down: prose runs out well before the
 * column does, and the drawing takes the space that leaves rather than
 * being given a box of its own.
 *
 * The picture has no background of its own — it was cut off the grey card it
 * was drawn on — so like .head-art it gets no frame, radius or shadow here.
 * There is nothing to frame.
 */
/* A stacked feature caps its copy at 68ch so the prose keeps a readable
   measure across the full band. That cap has to come off the container here
   and go onto the text column instead, or the grid shrinks to its contents
   and the paragraph ends up in a 260px gutter. */
.feature.stacked .feature-copy.copy-art { max-width: none; }

.copy-art {
  grid-template-columns: minmax(0, 68ch) minmax(0, 320px);
  justify-content: start;
  gap: 40px;
  align-items: center;
}

.copy-art > div {
  display: grid;
  gap: 16px;
  align-content: start;
}

.copy-art-img {
  display: block;
  width: 100%;
  height: auto;
}

@media (max-width: 940px) {
  .copy-art { grid-template-columns: 1fr; gap: 8px; }
  .copy-art-img { max-width: 300px; margin: 0 auto; }
}

/* ---- Hero headline ------------------------------------------------------
 * Lifted out of the left column so it spans both and centres. On one line it
 * occupies the band that used to be empty beside it, which is the whole
 * point of moving it.
 *
 * It keeps the text-shadow that .hero-copy h1 used to give it — the headline
 * is read over artwork and needs it wherever it lives.
 */
.hero-title {
  grid-column: 1 / -1;
  display: grid;
  justify-items: center;
  gap: 16px;
  text-align: center;
  margin-bottom: 4px;
}

.hero-title h1 {
  text-shadow: 0 2px 26px rgba(5, 11, 24, 0.92);
}

/* One line only where a line that long can fit. The cap is set where the
   string still clears the 1180px wrap; below the breakpoint it wraps, because
   sizing thirty characters to fit a phone in one line would leave a headline
   nobody could read. */
@media (min-width: 941px) {
  .hero-title h1 {
    white-space: nowrap;
    /* 76px measured, not guessed: the string renders 1074px there against a
       1180px wrap, so it holds one line with room and stays close to the 78px
       the headline had before it moved. */
    font-size: clamp(40px, 5.8vw, 76px);
  }
}

/* ---- A centred section heading -------------------------------------------
 * The eyebrow has to be centred by the grid, not by text-align. It is an
 * inline-flex box, and as a stretched grid item it spans the full width with
 * its label pinned left — so text-align alone leaves a left-aligned tag
 * sitting over a centred headline. justify-items shrink-wraps it instead.
 */
.section-head.centered {
  margin-inline: auto;
  justify-items: center;
  text-align: center;
}

/* Where something follows the heading immediately rather than after the
   usual gap — a lede that has been pulled out to sit beside a picture. */
.section-head.centered.tight { margin-bottom: 18px; }

/* ---- .head-art, mirrored ------------------------------------------------
 * Picture left, words right. The image keeps its place in the source after
 * the heading, so a screen reader still meets the section by its title; only
 * the painted order changes.
 */
.head-art.flip {
  grid-template-columns: minmax(0, 460px) minmax(0, 1fr);
}

.head-art.flip .head-art-img { order: -1; }

@media (max-width: 940px) {
  .head-art.flip { grid-template-columns: 1fr; }
  .head-art.flip .head-art-img { order: 0; }
}


/* ---- A centred copy block ------------------------------------------------
 * The tick list is not centred the way the prose around it is. Each row is an
 * icon in a fixed column beside its text, so centring the text inside the
 * rows would leave the icons in a ragged line down the middle. The list is
 * sized to its longest row and that block is centred instead, which keeps
 * every row starting on the same left edge.
 */
.feature-copy.centered {
  margin-inline: auto;
  text-align: center;
}

.feature-copy.centered .ticks {
  width: max-content;
  max-width: 100%;
  margin-inline: auto;
  text-align: left;
}

/* ---- The problem section, over the mark ----------------------------------
 * .hero-wash-main is placed to clear the hero copy, but it is 880px tall and
 * horizontally centred, so it runs on down behind this section. That cost
 * nothing while this copy was left-aligned and the mark was in the middle.
 * Centring the copy put the two on top of each other.
 *
 * Same remedy the hero already uses on its own copy: a stroke painted behind
 * the fill via paint-order, so the letterforms keep their weight instead of
 * being eaten from the inside, and a halo underneath for the rest. The pill
 * is translucent by design and simply stops reading as a pill over the
 * brightest part of the mark, so it gets a solid ground here.
 */
#problem .section-head h2 {
  text-shadow: 0 2px 26px rgba(5, 11, 24, 0.95);
}

#problem .section-head .lede {
  paint-order: stroke fill;
  -webkit-text-stroke: 4px rgba(5, 11, 24, 0.82);
  text-shadow: 0 1px 14px rgba(5, 11, 24, 0.95);
}

#problem .section-head .eyebrow {
  background: rgba(9, 17, 34, 0.94);
}

/* ---- Repeated calls to action -------------------------------------------- */
.cta-inline {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  justify-content: center;
  padding: 30px 0 4px;
}

/* Full width and stacked on a phone: two buttons side by side at this size
   are two half-buttons, and the second one wraps to its own line anyway. */
@media (max-width: 560px) {
  .cta-inline { flex-direction: column; align-items: stretch; }
  .cta-inline .btn { width: 100%; }
}
