/* ==========================================================================
   StudyApp AI — design system
   Single stylesheet for the whole site. No build step, no external requests.
   Colours and typefaces follow the brand sheet in imagesofimage/.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Newsreader — a serif drawn for reading on screen.

   The font is served from this site, not from Google. That keeps the pages
   working with no third-party request: nothing to load from elsewhere, nothing
   about your students reported to anyone else, and no broken typography if that
   service is unreachable.

   These are variable fonts: one file covers every weight from 200 to 800, and
   the optical-size axis makes large headings slightly tighter and small text
   slightly more open on its own.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("../fonts/newsreader-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Newsreader";
  font-style: normal;
  font-weight: 200 800;
  font-display: swap;
  src: url("../fonts/newsreader-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
    U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Newsreader";
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
  src: url("../fonts/newsreader-italic-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Newsreader";
  font-style: italic;
  font-weight: 200 800;
  font-display: swap;
  src: url("../fonts/newsreader-italic-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
    U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   Archivo — the brand's support face.

   Newsreader carries the name, the headings and anything meant to be read.
   Archivo carries the interface: buttons, navigation, labels, table headers,
   form fields. A serif is built for running prose and goes muddy at label
   sizes; a grotesque stays legible at 12px and reads as controls rather than
   as text, so the eye can tell them apart without thinking about it.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/archivo-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304,
    U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Archivo";
  font-style: normal;
  font-weight: 400 700;
  font-display: swap;
  src: url("../fonts/archivo-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308,
    U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113,
    U+2C60-2C7F, U+A720-A7FF;
}

:root {
  /* Brand palette. Navy, warm off-white and warm grey come straight from the
     brand sheet; everything else is derived from them so nothing on the page
     is a colour the brand did not choose. */
  --navy: #1b1b3a;
  --paper: #f4f3ef;
  --stone: #8a897f;

  --bg: var(--paper);
  --surface: #ffffff;
  --surface-muted: #eceae4;
  --text: var(--navy);
  --text-muted: var(--stone);
  --border: #ddd9d0;

  --brand: var(--navy);
  --brand-hover: #2c2c56;
  --brand-soft: #e6e5ec;
  --brand-contrast: var(--paper);

  /* Status colours, desaturated to sit beside the warm paper without shouting. */
  --success: #2f6b4f;
  --success-soft: #e3ece5;
  --warning: #8a6516;
  --warning-soft: #f2eadb;
  --danger: #9d3327;
  --danger-soft: #f1e3e0;

  --radius: 12px;
  --radius-sm: 8px;
  --shadow: 0 1px 2px rgba(16, 20, 32, 0.06), 0 8px 24px rgba(16, 20, 32, 0.06);
  --shadow-sm: 0 1px 2px rgba(16, 20, 32, 0.08);

  /* Newsreader reads; Archivo operates. */
  --font: "Newsreader", Georgia, "Times New Roman", serif;
  --font-ui: "Archivo", "Helvetica Neue", Arial, sans-serif;
  --font-mono: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;

  --header-height: 64px;
  --content-width: 1180px;

  /* ------------------------------------------------------------------------
     Background texture

     The brand symbol repeated on a 72x76 grid at low opacity. It is inlined
     here as a data URI rather than loaded as a file: it is under 500 bytes, so
     a separate request would cost more than the bytes, and writing it inline
     lets the same shape be tinted for light and dark surfaces instead of
     shipping two images.

     16% on paper, slightly lower on navy — the same opacity reads stronger
     against a dark ground.
     ------------------------------------------------------------------------ */
  --texture-light: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='72' height='76' viewBox='0 0 72 76'%3E%3Cg fill='%231B1B3A' fill-opacity='0.045' transform='translate(25.9 26.5) scale(0.24)'%3E%3Crect x='18' y='16' width='56' height='14'/%3E%3Crect x='10' y='41' width='56' height='14'/%3E%3Crect x='18' y='66' width='56' height='14'/%3E%3Crect x='18' y='16' width='14' height='39'/%3E%3Crect x='52' y='41' width='14' height='39'/%3E%3C/g%3E%3C/svg%3E");

  --texture-dark: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='72' height='76' viewBox='0 0 72 76'%3E%3Cg fill='%23F4F3EF' fill-opacity='0.07' transform='translate(25.9 26.5) scale(0.24)'%3E%3Crect x='18' y='16' width='56' height='14'/%3E%3Crect x='10' y='41' width='56' height='14'/%3E%3Crect x='18' y='66' width='56' height='14'/%3E%3Crect x='18' y='16' width='14' height='39'/%3E%3Crect x='52' y='41' width='14' height='39'/%3E%3C/g%3E%3C/svg%3E");

  --texture-size: 72px 76px;
}

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

html {
  -webkit-text-size-adjust: 100%;
  /* Lets the variable font pick a cut suited to the size it is set at. */
  font-optical-sizing: auto;
}

body {
  margin: 0;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  flex-direction: column;
  background-color: var(--bg);
  background-image: var(--texture-light);
  background-size: var(--texture-size);
  color: var(--text);
  font-family: var(--font);
  /* A serif reads a little small at 16px, and wants more leading than a
     sans-serif at the same measure. */
  font-size: 17px;
  line-height: 1.65;
}

/* --------------------------------------------------------------------------
   Dark pages

   The log-in and enrolment pages carry nothing but a form, so they get the
   navy treatment: the page itself becomes the brand, and the white card holding
   the form is the only thing competing for attention.
   -------------------------------------------------------------------------- */

body[data-surface="dark"] {
  background-color: var(--navy);
  background-image: var(--texture-dark);
  color: var(--paper);
}

body[data-surface="dark"] .site-header {
  background: rgba(27, 27, 58, 0.82);
  border-bottom-color: rgba(244, 243, 239, 0.14);
}

body[data-surface="dark"] .site-header .brand,
body[data-surface="dark"] .site-nav a {
  color: var(--paper);
}

/* Any solid panel on the dark ground carries its own text colour, so nothing
   inherits paper-on-white. */
body[data-surface="dark"] .auth__card,
body[data-surface="dark"] .card,
body[data-surface="dark"] .panel {
  color: var(--text);
}

body[data-surface="dark"] .auth__card .brand {
  color: var(--text);
}

body[data-surface="dark"] .site-nav a:hover {
  background: rgba(244, 243, 239, 0.1);
  color: var(--paper);
}

body[data-surface="dark"] .site-nav a[aria-current="page"] {
  background: rgba(244, 243, 239, 0.14);
  color: var(--paper);
}

body[data-surface="dark"] .site-nav .btn {
  background: var(--paper);
  color: var(--navy);
}

body[data-surface="dark"] .site-footer {
  border-top: 1px solid rgba(244, 243, 239, 0.14);
}

h1,
h2,
h3,
h4 {
  margin: 0;
  line-height: 1.22;
  /* Serif letterforms already sit close together; negative tracking would
     close the counters and muddy them. */
  letter-spacing: 0;
  font-weight: 600;
}

h1 {
  font-size: clamp(2rem, 1.4rem + 2vw, 3rem);
}
h2 {
  font-size: clamp(1.4rem, 1.1rem + 1vw, 1.9rem);
}
h3 {
  font-size: 1.15rem;
}

p {
  margin: 0;
}

a {
  color: var(--brand);
  text-decoration: none;
}

a:hover {
  text-decoration: underline;
}

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

/* --------------------------------------------------------------------------
   Protecting the artwork

   Be clear about what this is: friction, not security. Anything the browser
   renders has already been downloaded, and a screenshot always works. What
   these rules do is stop the casual attempts — dragging the logo onto the
   desktop, right-clicking to save it, selecting and copying it.

   The real protection is elsewhere: the brand marks are drawn with code rather
   than loaded as files, so there is no image to open in a tab, and .htaccess
   stops other sites from hotlinking whatever image files do exist.
   -------------------------------------------------------------------------- */

img,
svg,
.brand,
.brand__mark {
  /* Kills the drag-to-desktop gesture in every engine. */
  -webkit-user-drag: none;
  -khtml-user-drag: none;
  -moz-user-drag: none;
  user-drag: none;
  -webkit-touch-callout: none;
}

svg,
.brand__mark {
  -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
}

:focus-visible {
  outline: 2px solid var(--brand);
  outline-offset: 2px;
  border-radius: 4px;
}

/* Visible only to screen readers, until focused. */
.skip-link {
  position: absolute;
  left: -9999px;
  top: 0;
  background: var(--brand);
  color: var(--brand-contrast);
  padding: 10px 16px;
  z-index: 100;
}

.skip-link:focus {
  left: 8px;
  top: 8px;
}

/* --------------------------------------------------------------------------
   Layout
   -------------------------------------------------------------------------- */

.container {
  width: 100%;
  max-width: var(--content-width);
  margin: 0 auto;
  padding: 0 24px;
}

.page {
  flex: 1;
  padding: 40px 0 72px;
}

.page-head {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: flex-end;
  justify-content: space-between;
  margin-bottom: 32px;
}

.page-head p {
  color: var(--text-muted);
  margin-top: 6px;
  max-width: 60ch;
}

.breadcrumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 6px;
  margin-bottom: 8px;
}

.stack {
  display: grid;
  gap: 16px;
}

.stack-lg {
  display: grid;
  gap: 32px;
}

.grid {
  display: grid;
  gap: 20px;
}

@media (min-width: 720px) {
  .grid-2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 1000px) {
  .grid-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */

.site-header {
  position: sticky;
  top: 0;
  z-index: 20;
  background: rgba(244, 243, 239, 0.9);
  backdrop-filter: saturate(140%) blur(12px);
  border-bottom: 1px solid var(--border);
}

.site-header__inner {
  height: var(--header-height);
  display: flex;
  align-items: center;
  gap: 28px;
}

/* The lockup follows the brand sheet: symbol, then the name set in Newsreader
   with "StudyApp" at 400 and "AI" at 600. The gap is the clear space the sheet
   asks for — at least one bar height around the symbol. */
.brand {
  display: inline-flex;
  align-items: center;
  gap: 11px;
  color: var(--text);
  letter-spacing: 0;
}

.brand:hover {
  text-decoration: none;
}

.brand__mark {
  width: 22px;
  height: 25px;
  flex: none;
  /* currentColor, so the symbol follows the text it sits next to. */
  color: inherit;
}

.brand__name {
  font-size: 1.22rem;
  line-height: 1;
  font-weight: 400;
  white-space: nowrap;
}

.brand__name b {
  font-weight: 600;
}

.site-nav {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: auto;
}

.site-nav a {
  font-family: var(--font-ui);
  padding: 8px 12px;
  border-radius: var(--radius-sm);
  color: var(--text-muted);
  font-size: 0.94rem;
  font-weight: 550;
}

.site-nav a:hover {
  background: var(--surface-muted);
  color: var(--text);
  text-decoration: none;
}

.site-nav a[aria-current="page"] {
  background: var(--brand-soft);
  color: var(--brand);
}

.site-nav__divider {
  width: 1px;
  height: 24px;
  background: var(--border);
  margin: 0 8px;
}

/* --------------------------------------------------------------------------
   Buttons
   -------------------------------------------------------------------------- */

.btn {
  font-family: var(--font-ui);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  height: 42px;
  padding: 0 18px;
  border: 1px solid transparent;
  border-radius: var(--radius-sm);
  background: var(--brand);
  color: var(--brand-contrast);
  font: inherit;
  font-size: 0.94rem;
  font-weight: 600;
  cursor: pointer;
  transition: background-color 0.15s ease, border-color 0.15s ease;
}

.btn:hover {
  background: var(--brand-hover);
  text-decoration: none;
  color: var(--brand-contrast);
}

.btn:disabled {
  opacity: 0.55;
  cursor: not-allowed;
}

.btn--secondary {
  background: var(--surface);
  border-color: var(--border);
  color: var(--text);
}

.btn--secondary:hover {
  background: var(--surface-muted);
  color: var(--text);
}

.btn--ghost {
  background: transparent;
  color: var(--text-muted);
}

.btn--ghost:hover {
  background: var(--surface-muted);
  color: var(--text);
}

.btn--danger {
  background: var(--danger);
}

.btn--danger:hover {
  background: #a32819;
}

.btn--lg {
  height: 50px;
  padding: 0 26px;
  font-size: 1rem;
}

.btn--sm {
  height: 34px;
  padding: 0 12px;
  font-size: 0.86rem;
}

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

/* --------------------------------------------------------------------------
   Cards and surfaces
   -------------------------------------------------------------------------- */

.card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 24px;
  box-shadow: var(--shadow-sm);
}

.card--flush {
  padding: 0;
  overflow: hidden;
}

.card__head {
  padding: 20px 24px;
  border-bottom: 1px solid var(--border);
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
}

.card__body {
  padding: 24px;
}

.panel {
  background: var(--surface-muted);
  border-radius: var(--radius);
  padding: 20px 24px;
}

.muted {
  color: var(--text-muted);
}

.small {
  font-size: 0.88rem;
}

.mono {
  font-family: var(--font-mono);
  font-size: 0.86em;
}

/* --------------------------------------------------------------------------
   Badges and progress
   -------------------------------------------------------------------------- */

.badge {
  font-family: var(--font-ui);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 11px;
  border-radius: 999px;
  /* Serif text needs a touch more size than a sans at label scale. */
  font-size: 0.82rem;
  font-weight: 600;
  background: var(--surface-muted);
  color: var(--text-muted);
  white-space: nowrap;
}

.badge--brand {
  background: var(--brand-soft);
  color: var(--brand);
}
.badge--success {
  background: var(--success-soft);
  color: var(--success);
}
.badge--warning {
  background: var(--warning-soft);
  color: var(--warning);
}
.badge--danger {
  background: var(--danger-soft);
  color: var(--danger);
}

.progress {
  height: 8px;
  border-radius: 999px;
  background: var(--surface-muted);
  overflow: hidden;
}

.progress__bar {
  height: 100%;
  background: var(--brand);
  border-radius: 999px;
  transition: width 0.3s ease;
}

/* --------------------------------------------------------------------------
   Forms
   -------------------------------------------------------------------------- */

.field {
  display: grid;
  gap: 6px;
}

.field > label {
  font-family: var(--font-ui);
  font-size: 0.9rem;
  font-weight: 600;
}

.field input,
.field select,
.field textarea {
  width: 100%;
  padding: 11px 13px;
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 0.95rem;
  line-height: 1.45;
}

.field input:focus,
.field select:focus,
.field textarea:focus {
  outline: 2px solid var(--brand);
  outline-offset: 0;
  border-color: var(--brand);
}

.field__hint {
  font-family: var(--font-ui);
  font-size: 0.83rem;
  color: var(--text-muted);
}

.field__error {
  font-family: var(--font-ui);
  font-size: 0.85rem;
  color: var(--danger);
}

.form-message {
  font-family: var(--font-ui);
  padding: 12px 14px;
  border-radius: var(--radius-sm);
  font-size: 0.9rem;
  display: none;
}

.form-message[data-variant="error"] {
  display: block;
  background: var(--danger-soft);
  color: var(--danger);
}

.form-message[data-variant="success"] {
  display: block;
  background: var(--success-soft);
  color: var(--success);
}

/* --------------------------------------------------------------------------
   Auth pages
   -------------------------------------------------------------------------- */

.auth {
  flex: 1;
  display: grid;
  place-items: center;
  padding: 48px 24px;
}

.auth__card {
  width: 100%;
  max-width: 420px;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 32px;
  box-shadow: var(--shadow);
}

/* The full lockup sits on the auth cards, where a visitor arriving from a link
   may not have seen the header yet. Drawn, not placed as an image: there is no
   file to open in a tab or save, and it stays sharp on any screen. */
.auth__lockup {
  justify-content: center;
  margin-bottom: 26px;
}

.auth__lockup .brand__mark {
  width: 26px;
  height: 30px;
}

.auth__lockup .brand__name {
  font-size: 1.45rem;
}

.auth__card h1 {
  font-size: 1.6rem;
}

.auth__foot {
  margin-top: 22px;
  padding-top: 20px;
  border-top: 1px solid var(--border);
  font-size: 0.92rem;
  color: var(--text-muted);
  text-align: center;
}

/* --------------------------------------------------------------------------
   Landing
   -------------------------------------------------------------------------- */

/* --------------------------------------------------------------------------
   Hero

   A photograph under a heavy navy scrim. The scrim is doing two jobs: it puts
   the contrast well past the accessible threshold for the text on top, and it
   pulls a generic office photograph into the brand's own colour, so it reads
   as texture rather than as stock photography. The brand tile sits over the
   top of it, which is what ties it to every other section.

   The gradient is denser on the left, where the words are, and opens up on the
   right, where the picture can be seen — which is also the side of the hero
   that used to be empty.
   -------------------------------------------------------------------------- */

.hero {
  position: relative;
  isolation: isolate;
  padding: 104px 0 88px;
  background-color: var(--navy);
  color: var(--paper);
  overflow: hidden;
}

.hero::before,
.hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
}

.hero::before {
  background-image: image-set(
    url("../img/hero.avif") type("image/avif"),
    url("../img/hero.jpg") type("image/jpeg")
  );
  background-size: cover;
  background-position: center 38%;
}

.hero::after {
  background-image: var(--texture-dark),
    linear-gradient(
      100deg,
      rgba(27, 27, 58, 0.95) 20%,
      rgba(27, 27, 58, 0.79) 58%,
      rgba(27, 27, 58, 0.54) 100%
    );
  background-size: var(--texture-size), cover;
}

.hero .hero__eyebrow {
  color: rgba(244, 243, 239, 0.66);
}

.hero h1 {
  color: var(--paper);
}

.hero__lead {
  color: rgba(244, 243, 239, 0.8);
}

/* On navy the filled button has to invert, or it disappears into the ground. */
.hero .btn {
  background: var(--paper);
  color: var(--navy);
}

.hero .btn:hover {
  background: #ffffff;
}

.hero .btn--secondary {
  background: transparent;
  border-color: rgba(244, 243, 239, 0.4);
  color: var(--paper);
}

.hero .btn--secondary:hover {
  background: rgba(244, 243, 239, 0.12);
  color: var(--paper);
}

.hero__eyebrow {
  font-family: var(--font-ui);
  color: var(--text-muted);
  font-weight: 600;
  font-size: 0.76rem;
  text-transform: uppercase;
  /* Same treatment as "UNIVERSITY OF AI" in the logo: small, spaced, quiet. */
  letter-spacing: 0.16em;
}

.hero h1 {
  margin-top: 14px;
  max-width: 18ch;
}

.hero__lead {
  margin-top: 20px;
  max-width: 58ch;
  font-size: 1.12rem;
}

.hero__actions {
  margin-top: 32px;
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
}

/* --------------------------------------------------------------------------
   Key figures

   Four numbers on their own read as an afterthought. Giving them a surface,
   hairlines between the columns and a real hierarchy — figure, then noun, then
   the detail — turns them into the block of key figures a serious prospectus
   would run, which is the register this brand is in.

   The numerals are where Newsreader earns its keep, so they are set large and
   light: a display serif at 3rem wants less weight than the same face at
   reading size, not more.
   -------------------------------------------------------------------------- */

.stats {
  margin: 0;
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}

.stat {
  padding: 30px 26px 32px;
  border-left: 1px solid var(--border);
}

.stat:first-child {
  border-left: 0;
}

.stat__value {
  display: block;
  font-size: clamp(2.4rem, 1.7rem + 1.8vw, 3.4rem);
  font-weight: 450;
  line-height: 0.95;
  color: var(--navy);
  /* Lining figures of even width, so the four columns line up on the baseline
     and the digits do not sit at different heights. */
  font-variant-numeric: lining-nums tabular-nums;
}

.stat__body {
  display: block;
  margin: 0;
}

.stat__label {
  display: block;
  font-family: var(--font-ui);
  font-size: 0.78rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: var(--text);
}

/* A short rule ties the figure to its label and gives the block its rhythm. */
.stat__label::before {
  content: "";
  display: block;
  width: 26px;
  height: 2px;
  background: var(--navy);
  margin: 18px 0 13px;
}

.stat__note {
  display: block;
  margin-top: 5px;
  color: var(--text-muted);
  font-size: 0.95rem;
  line-height: 1.45;
}

/* Four columns stop working once each is narrower than its longest label.
   Two columns keep the figures large instead of shrinking them to fit. */
@media (max-width: 900px) {
  .stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .stat:nth-child(odd) {
    border-left: 0;
  }

  .stat:nth-child(n + 3) {
    border-top: 1px solid var(--border);
  }
}

.section {
  padding: 64px 0;
  border-top: 1px solid var(--border);
}

/* The figures panel rides up over the edge of the hero. A white card breaking
   the boundary between the photograph and the page reads as depth, and it
   stops the two sections from looking stacked like bricks. */
.section--figures {
  position: relative;
  z-index: 1;
  border-top: 0;
  padding-top: 0;
  margin-top: -46px;
}

@media (max-width: 640px) {
  .section--figures {
    margin-top: -30px;
  }
}

/* Navy closing band on the landing page. The lockup here is drawn rather than
   placed as an image: the exported logo is navy on transparent, so it would
   disappear against this background, and drawn type stays crisp at any width. */
.cta-band {
  background-color: var(--navy);
  background-image: var(--texture-dark);
  background-size: var(--texture-size);
  color: var(--paper);
  padding: 72px 0;
  text-align: center;
}

.cta-band .brand {
  color: var(--paper);
  justify-content: center;
}

.cta-band .brand__mark {
  width: 30px;
  height: 34px;
}

.cta-band .brand__name {
  font-size: 1.7rem;
}

.cta-band__tagline {
  font-family: var(--font-ui);
  font-size: 0.76rem;
  text-transform: uppercase;
  letter-spacing: 0.18em;
  color: rgba(244, 243, 239, 0.5);
  margin-top: 10px;
}

.cta-band h2 {
  margin-top: 32px;
  color: var(--paper);
}

.cta-band p {
  margin: 14px auto 0;
  max-width: 52ch;
  color: rgba(244, 243, 239, 0.72);
}

.cta-band .row {
  justify-content: center;
  margin-top: 32px;
}

/* On navy, the filled button has to invert or it vanishes. */
.cta-band .btn {
  background: var(--paper);
  color: var(--navy);
}

.cta-band .btn:hover {
  background: #ffffff;
}

.cta-band .btn--secondary {
  background: transparent;
  border-color: rgba(244, 243, 239, 0.35);
  color: var(--paper);
}

.cta-band .btn--secondary:hover {
  background: rgba(244, 243, 239, 0.1);
  color: var(--paper);
}

/* --------------------------------------------------------------------------
   Course list and lessons
   -------------------------------------------------------------------------- */

.module-card {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.module-card__meta {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
}

.module-card__number {
  font-family: var(--font-ui);
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--text-muted);
}

.lesson-list {
  list-style: none;
  margin: 0;
  padding: 0;
}

.lesson-row {
  display: flex;
  align-items: center;
  gap: 16px;
  padding: 16px 24px;
  border-bottom: 1px solid var(--border);
}

.lesson-row:last-child {
  border-bottom: 0;
}

.lesson-row__index {
  font-family: var(--font-ui);
  width: 30px;
  height: 30px;
  flex: none;
  border-radius: 50%;
  display: grid;
  place-items: center;
  background: var(--surface-muted);
  color: var(--text-muted);
  font-size: 0.86rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

.lesson-row[data-state="done"] .lesson-row__index {
  background: var(--success-soft);
  color: var(--success);
}

.lesson-row[data-state="current"] .lesson-row__index {
  background: var(--brand);
  color: #fff;
}

.lesson-row__body {
  min-width: 0;
  flex: 1;
}

.lesson-row__title {
  font-weight: 600;
}

.lesson-row__meta {
  color: var(--text-muted);
  font-size: 0.87rem;
}

.lesson-row[data-state="locked"] .lesson-row__title,
.lesson-row[data-state="locked"] .lesson-row__meta {
  opacity: 0.55;
}

/* --------------------------------------------------------------------------
   Tables
   -------------------------------------------------------------------------- */

.table {
  width: 100%;
  border-collapse: collapse;
  font-size: 0.94rem;
}

.table th,
.table td {
  text-align: left;
  padding: 13px 24px;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.table th {
  font-family: var(--font-ui);
  font-size: 0.76rem;
  text-transform: uppercase;
  letter-spacing: 0.07em;
  color: var(--text-muted);
  font-weight: 600;
  background: var(--surface-muted);
}

.table tr:last-child td {
  border-bottom: 0;
}

/* --------------------------------------------------------------------------
   Empty states
   -------------------------------------------------------------------------- */

.empty {
  padding: 48px 24px;
  text-align: center;
  color: var(--text-muted);
}

.empty__title {
  font-weight: 650;
  color: var(--text);
  margin-bottom: 6px;
}

/* --------------------------------------------------------------------------
   Footer
   -------------------------------------------------------------------------- */

/* A navy band closes every page. It is the only large field of brand colour on
   a mostly paper-coloured site, which is what keeps the palette present without
   the interface shouting. */
.site-footer {
  font-family: var(--font-ui);
  background-color: var(--navy);
  background-image: var(--texture-dark);
  background-size: var(--texture-size);
  padding: 34px 0;
  color: rgba(244, 243, 239, 0.62);
  font-size: 0.86rem;
}

.site-footer a {
  color: rgba(244, 243, 239, 0.9);
}

.site-footer__inner {
  display: flex;
  flex-wrap: wrap;
  gap: 16px;
  align-items: center;
  justify-content: space-between;
}

.site-footer .brand {
  color: var(--paper);
}

.site-footer .brand__name {
  font-size: 1.05rem;
}

.site-footer__tagline {
  font-size: 0.75rem;
  text-transform: uppercase;
  letter-spacing: 0.16em;
  color: rgba(244, 243, 239, 0.45);
  margin-top: 4px;
}

/* --------------------------------------------------------------------------
   Small screens

   The site is built for a desktop, because that is where you write code with
   an editor, a terminal and this page open at once. On a phone it has a
   different job: checking progress and re-reading theory. These rules serve
   that job rather than pretending a phone is a small desktop.
   -------------------------------------------------------------------------- */

/* Notched and curved screens: keep content out from under the rounded corners
   and the home indicator, in portrait and in landscape. */
@supports (padding: env(safe-area-inset-left)) {
  .container {
    padding-left: max(24px, env(safe-area-inset-left));
    padding-right: max(24px, env(safe-area-inset-right));
  }

  .site-footer {
    padding-bottom: max(34px, calc(28px + env(safe-area-inset-bottom)));
  }
}

@media (max-width: 860px) {
  /* The nav no longer fits beside the name, so it takes its own row. Without
     this the last links are pushed off the right edge and become unreachable —
     the page does not scroll sideways, they are simply gone. */
  .site-header__inner {
    height: auto;
    flex-wrap: wrap;
    gap: 0;
    padding-top: 10px;
    padding-bottom: 10px;
  }

  .site-nav {
    width: 100%;
    margin-left: 0;
    margin-top: 8px;
    /* If they still do not fit, they scroll rather than disappear. */
    overflow-x: auto;
    scrollbar-width: none;
    -webkit-overflow-scrolling: touch;
  }

  .site-nav::-webkit-scrollbar {
    display: none;
  }

  .site-nav > * {
    flex: none;
  }

  .site-nav__divider {
    margin: 0 4px;
  }
}

/* Below this the four nav items no longer fit on one line. They stay on one
   line anyway, tightened, because a nav that has to be swiped sideways is a nav
   half the visitors never discover. */
@media (max-width: 430px) {
  .site-nav a,
  .site-nav button {
    padding-left: 8px;
    padding-right: 8px;
    font-size: 0.86rem;
  }

  .site-nav__divider {
    margin: 0 2px;
  }
}

@media (max-width: 640px) {
  :root {
    --radius: 10px;
  }

  body {
    font-size: 16px;
  }

  h1 {
    font-size: 1.75rem;
  }

  h2 {
    font-size: 1.3rem;
  }

  .container {
    padding-left: 16px;
    padding-right: 16px;
  }

  @supports (padding: env(safe-area-inset-left)) {
    .container {
      padding-left: max(16px, env(safe-area-inset-left));
      padding-right: max(16px, env(safe-area-inset-right));
    }
  }

  .page {
    padding: 26px 0 52px;
  }

  .hero {
    padding: 44px 0 36px;
  }

  .hero__lead {
    font-size: 1.02rem;
  }

  .section,
  .cta-band {
    padding: 44px 0;
  }

  .card,
  .card__body,
  .auth__card {
    padding: 18px;
  }

  .card__head {
    padding: 16px 18px;
    flex-wrap: wrap;
  }

  .panel {
    padding: 16px 18px;
  }

  .stat {
    padding: 22px 20px 24px;
  }

  .stat__label::before {
    margin: 14px 0 11px;
  }

  .page-head {
    margin-bottom: 24px;
  }

  /* A single call to action reads better full width than stranded at the left. */
  .page-head > .btn,
  .hero__actions .btn,
  .cta-band .row .btn {
    width: 100%;
  }

  .lesson-row {
    padding: 14px 18px;
    align-items: flex-start;
  }

  .lesson-row__index {
    margin-top: 2px;
  }

  .stack-lg {
    gap: 22px;
  }
}

/* --------------------------------------------------------------------------
   Tables on a phone

   A five-column table on a 360px screen gives one word per line. Below this
   width each row becomes its own block and every value is introduced by the
   label from its column header, carried in `data-label`.
   -------------------------------------------------------------------------- */

@media (max-width: 720px) {
  .table thead {
    /* Hidden from sight, still announced to screen readers through the
       labels on each cell. */
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip: rect(0, 0, 0, 0);
  }

  .table,
  .table tbody,
  .table tr,
  .table td {
    display: block;
    width: 100%;
  }

  .table tr {
    padding: 16px 18px;
    border-bottom: 1px solid var(--border);
  }

  .table tr:last-child {
    border-bottom: 0;
  }

  .table td {
    padding: 0;
    border: 0;
  }

  .table td + td {
    margin-top: 8px;
  }

  /* Cells that carry a label get it as a small caption above the value. */
  .table td[data-label]:not(:first-child)::before {
    content: attr(data-label);
    display: block;
    font-family: var(--font-ui);
    font-size: 0.75rem;
    font-weight: 600;
    text-transform: uppercase;
    letter-spacing: 0.08em;
    color: var(--text-muted);
    margin-bottom: 2px;
  }

  /* The action cell is a button, not a value: no caption, full width. */
  .table td[data-action] {
    margin-top: 14px;
    text-align: left !important;
  }

  .table td[data-action] .btn {
    width: 100%;
  }
}

/* --------------------------------------------------------------------------
   Touch input

   Applies wherever the primary pointer is a finger, which is the honest test —
   it covers phones and tablets without catching a small laptop window.
   Apple asks for 44px, Google for 48dp; 44 satisfies both in practice.
   -------------------------------------------------------------------------- */

@media (pointer: coarse) {
  .btn {
    min-height: 46px;
  }

  .btn--sm {
    min-height: 44px;
    padding: 0 16px;
  }

  .site-nav a,
  .site-nav button {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  .brand {
    padding: 6px 0;
    min-height: 44px;
  }

  /* Anything below 16px makes iOS Safari zoom the page in when the field takes
     focus, and it does not zoom back out. */
  .field input,
  .field select,
  .field textarea {
    font-size: 16px;
    min-height: 46px;
  }

  .field textarea {
    min-height: 88px;
  }

  /* Inline links in prose get a little more room without becoming blocks. */
  .page a:not(.btn):not(.brand):not(.lesson-row__title):not(.breadcrumb a) {
    padding: 2px 0;
    display: inline-block;
  }

  /* The auth cards sit outside .page, so they need naming explicitly — the
     "create one" / "log in" link at the foot of the card is the whole reason
     someone is on the other page. */
  .breadcrumb a,
  .auth__foot a {
    min-height: 44px;
    display: inline-flex;
    align-items: center;
  }

  /* A lesson title is one line of text, far short of a comfortable tap target.
     Rather than padding the link — which would push the duration and summary
     around — the link stretches an invisible layer over its whole row. The row
     becomes the target, which is what a thumb expects anyway. */
  .lesson-row {
    position: relative;
  }

  a.lesson-row__title::after {
    content: "";
    position: absolute;
    inset: 0;
  }
}

/* --------------------------------------------------------------------------
   Utilities
   -------------------------------------------------------------------------- */

.row {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.row--between {
  justify-content: space-between;
}

.hidden {
  display: none !important;
}

.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;
}
