/* ===========================================================================
   Solex Network Solutions - one stylesheet for the whole site.
   Dark by default: the public marketing pages, the student app and the admin
   panel all share the same palette so the product feels like one thing.
   =========================================================================== */

:root {
  --bg:        #070b14;
  --bg-2:      #0c1424;
  --panel:     #101b30;
  --panel-2:   #16243d;
  --line:      #1e3050;
  --line-soft: #16233a;

  --ink:       #e8f0f8;
  --ink-2:     #b6c6da;
  --dim:       #7f94ad;

  --brand:     #2fa8e0;
  --brand-2:   #1b7fc0;
  --accent:    #3ad0b0;
  --warn:      #e0a63a;
  --danger:    #e0566f;
  --ok:        #3ac07a;

  /* Surfaces that used to be hardcoded. They are variables now so the light
     theme can move them; the dark values here are exactly what shipped. */
  --head-bg:    rgba(7, 11, 20, .86);
  --code-bg:    #06101f;
  --code-ink:   #cfe4f5;
  --link-hover: #6fc6f0;
  --card-hover: #2a4a76;
  --cover-fade: rgba(16, 27, 48, .95);
  --hero-fade:  rgba(7, 11, 20, .94);
  --hero-fade-2:rgba(7, 11, 20, .62);
  --overlay:    rgba(7, 11, 20, .82);
  --row-hover:  rgba(255, 255, 255, .02);
  --on-brand:   #04121e;   /* text sitting on a brand-coloured button */

  --radius:    14px;
  --radius-sm: 9px;
  --shadow:    0 18px 45px rgba(0,0,0,.45);
  --maxw:      1180px;
  --font:      -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --mono:      ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace;
}

/* ---------- light theme ----------------------------------------------------
   Public pages only. The student app and the admin panel stay dark: people
   work in those for hours, and a half-converted dashboard is worse than an
   honestly dark one.

   Three rules, in this order:
     1. the palette itself, in one place
     2. applied when the visitor's device asks for light and they have not
        chosen otherwise
     3. applied when the visitor has explicitly chosen light

   The `:not([data-theme="dark"])` in rule 2 is what lets someone on a
   light-mode laptop still pick dark and have it stick.
--------------------------------------------------------------------------- */
@media (prefers-color-scheme: light) {
  html[data-chrome="public"]:not([data-theme="dark"]) {
    --bg:        #f7f9fc;
    --bg-2:      #eef2f8;
    --panel:     #ffffff;
    --panel-2:   #f1f5fa;
    --line:      #d8e0ec;
    --line-soft: #e6ecf4;

    --ink:       #0d1b2c;
    --ink-2:     #3d5064;
    --dim:       #667c94;

    --brand-2:   #1b7fc0;
    --ok:        #1f8d54;

    --head-bg:    rgba(255, 255, 255, .88);
    --code-bg:    #0d1826;
    --code-ink:   #d6e6f5;
    --link-hover: #1b6ea3;
    --card-hover: #b9cbe2;
    --cover-fade: rgba(232, 239, 248, .96);
    --hero-fade:  rgba(247, 249, 252, .94);
    --hero-fade-2:rgba(247, 249, 252, .62);
    --overlay:    rgba(13, 27, 44, .78);
    --row-hover:  rgba(13, 27, 44, .035);

    --shadow:    0 18px 45px rgba(20, 40, 70, .12);
  }
}

html[data-chrome="public"][data-theme="light"] {
  --bg:        #f7f9fc;
  --bg-2:      #eef2f8;
  --panel:     #ffffff;
  --panel-2:   #f1f5fa;
  --line:      #d8e0ec;
  --line-soft: #e6ecf4;

  --ink:       #0d1b2c;
  --ink-2:     #3d5064;
  --dim:       #667c94;

  --brand-2:   #1b7fc0;
  --ok:        #1f8d54;

  --head-bg:    rgba(255, 255, 255, .88);
  --code-bg:    #0d1826;
  --code-ink:   #d6e6f5;
  --link-hover: #1b6ea3;
  --card-hover: #b9cbe2;
  --cover-fade: rgba(232, 239, 248, .96);
  --hero-fade:  rgba(247, 249, 252, .94);
  --hero-fade-2:rgba(247, 249, 252, .62);
  --overlay:    rgba(13, 27, 44, .78);
  --row-hover:  rgba(13, 27, 44, .035);

  --shadow:    0 18px 45px rgba(20, 40, 70, .12);
}

/* Tell the browser which way round we are, so form controls, scrollbars and
   autofill styling follow rather than staying stubbornly dark. */
html[data-chrome="public"] { color-scheme: dark; }
html[data-chrome="public"][data-theme="light"] { color-scheme: light; }
@media (prefers-color-scheme: light) {
  html[data-chrome="public"]:not([data-theme="dark"]) { color-scheme: light; }
}

* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
  margin: 0;
  font-family: var(--font);
  background: var(--bg);
  color: var(--ink);
  line-height: 1.62;
  -webkit-font-smoothing: antialiased;
}
img { max-width: 100%; height: auto; }
a { color: var(--brand); text-decoration: none; }
a:hover { color: var(--link-hover); }
h1, h2, h3, h4 { line-height: 1.22; margin: 0 0 .5em; font-weight: 700; letter-spacing: -.015em; }
h1 { font-size: clamp(2rem, 4.2vw, 3.1rem); }
h2 { font-size: clamp(1.5rem, 2.8vw, 2.1rem); }
h3 { font-size: 1.22rem; }
p  { margin: 0 0 1rem; }
.muted { color: var(--dim); }
.small { font-size: .87rem; }
.center { text-align: center; }
.wrap { width: 100%; max-width: var(--maxw); margin: 0 auto; padding: 0 20px; }
.inline { display: inline; }
hr { border: 0; border-top: 1px solid var(--line); margin: 2rem 0; }

/* ---------- buttons -------------------------------------------------------- */
.btn {
  display: inline-flex; align-items: center; gap: .5rem;
  background: linear-gradient(180deg, var(--brand), var(--brand-2));
  color: var(--on-brand); font-weight: 700; font-size: .95rem;
  padding: .72rem 1.25rem; border-radius: 999px; border: 0;
  cursor: pointer; transition: transform .12s ease, filter .12s ease;
  white-space: nowrap; font-family: inherit;
}
.btn:hover { filter: brightness(1.08); color: var(--on-brand); transform: translateY(-1px); }
.btn:active { transform: translateY(0); }
.btn.small { padding: .48rem .95rem; font-size: .85rem; }
.btn.ghost {
  background: transparent; color: var(--ink);
  border: 1px solid var(--line); font-weight: 600;
}
.btn.ghost:hover { background: var(--panel-2); color: var(--ink); }
.btn.danger { background: linear-gradient(180deg, #e0566f, #b8394f); color: #fff; }
.btn.wide { width: 100%; justify-content: center; }
.btn[disabled], .btn.disabled { opacity: .45; pointer-events: none; }
.btn svg { width: 1.05em; height: 1.05em; }

/* ---------- header --------------------------------------------------------- */
.site-head {
  position: sticky; top: 0; z-index: 60;
  background: var(--head-bg);
  backdrop-filter: blur(14px);
  border-bottom: 1px solid var(--line-soft);
}
.site-head.app { background: rgba(10, 16, 28, .95); }
.site-head.admin { border-bottom-color: #2a3f63; }
.nav { display: flex; align-items: center; gap: 1.5rem; height: 66px; }
.brand { display: flex; align-items: center; gap: .6rem; color: var(--ink); flex: 0 0 auto; }
.brand .mark {
  width: 34px; height: 34px; border-radius: 10px; display: grid; place-items: center;
  background: linear-gradient(135deg, var(--brand), var(--accent));
  color: var(--on-brand); font-weight: 800; font-size: 1.1rem;
}
.brand .bname { font-weight: 800; font-size: 1.02rem; letter-spacing: -.02em; line-height: 1.1; }
.brand .bname em {
  display: block; font-style: normal; font-weight: 500;
  font-size: .68rem; color: var(--dim); letter-spacing: .07em; text-transform: uppercase;
}
/* Theme switch. The icon shows what you will get if you press it, and which
   icon is visible is decided in CSS - so it is right on the first paint,
   before any script has run. */
.theme-btn {
  display: inline-grid; place-items: center;
  width: 34px; height: 34px; flex: 0 0 auto;
  background: transparent; border: 1px solid var(--line);
  border-radius: 999px; cursor: pointer; padding: 0;
  color: var(--ink-2); font-size: .95rem; line-height: 1;
  transition: color .12s ease, border-color .12s ease;
}
.theme-btn:hover { color: var(--ink); border-color: var(--card-hover); }
.theme-btn .moon { display: none; }
html[data-theme="light"] .theme-btn .sun  { display: none; }
html[data-theme="light"] .theme-btn .moon { display: block; }
@media (prefers-color-scheme: light) {
  html[data-chrome="public"]:not([data-theme="dark"]) .theme-btn .sun  { display: none; }
  html[data-chrome="public"]:not([data-theme="dark"]) .theme-btn .moon { display: block; }
}

.nav-panel { display: flex; align-items: center; gap: 1.35rem; margin-left: auto; flex-wrap: nowrap; }
.nav-cta { display: flex; align-items: center; gap: .6rem; }
.links { display: flex; gap: 1.35rem; flex-wrap: nowrap; }
/* Seven links plus a sign-in button is a lot for a 1000px laptop. Tighten the
   spacing before anything is forced to wrap. */
@media (max-width: 1200px) {
  .nav-panel { gap: 1rem; }
  .links { gap: .95rem; }
  .links a { font-size: .88rem; }
}
.links a { color: var(--ink-2); font-size: .93rem; font-weight: 500; }
.links a:hover, .links a.on { color: var(--ink); }
.links a.on { position: relative; }
.links a.on::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: -22px;
  height: 2px; background: var(--brand); border-radius: 2px;
}
.nav-cta { display: flex; align-items: center; gap: .6rem; }
.who { color: var(--ink-2); font-size: .9rem; font-weight: 600; }
.hours-pill {
  display: inline-flex; align-items: center; gap: .35rem;
  background: var(--panel); border: 1px solid var(--line);
  padding: .3rem .7rem; border-radius: 999px; font-size: .82rem;
  color: var(--accent); font-weight: 700; font-variant-numeric: tabular-nums;
}
.hours-pill svg { width: 14px; height: 14px; }
.burger { display: none; background: none; border: 0; cursor: pointer; padding: 8px; }
.burger span { display: block; width: 22px; height: 2px; background: var(--ink); margin: 4px 0; border-radius: 2px; }

@media (max-width: 1040px) {
  /* One panel holds the links AND the sign-in button, so opening the burger
     shows the whole menu instead of leaving Log in stranded in the header. */
  .nav-panel {
    position: fixed; inset: 60px 0 auto 0; z-index: 40;
    flex-direction: column; align-items: stretch; gap: 0; margin: 0;
    background: var(--bg-2); border-bottom: 1px solid var(--line);
    padding: .25rem 20px 1rem; display: none;
    max-height: calc(100vh - 60px); overflow-y: auto;
    box-shadow: 0 18px 40px rgba(0, 0, 0, .32);
  }
  body.nav-open .nav-panel { display: flex; }
  .links { flex-direction: column; gap: 0; }
  .links a { padding: .85rem .2rem; border-bottom: 1px solid var(--line-soft); font-size: 1rem; }
  .links a.on::after { display: none; }
  .links a.on { color: var(--brand); font-weight: 700; }
  .burger { display: block; margin-left: auto; }

  /* The sign-in row sits at the bottom of the open menu, full width and
     thumb-sized rather than a tiny pill in the corner of the screen. */
  .nav-cta {
    flex-direction: column; align-items: stretch; gap: .5rem;
    padding-top: .9rem; margin-top: .3rem;
  }
  .nav-cta .btn, .nav-cta form, .nav-cta form .btn { width: 100%; }
  .nav-cta .btn { justify-content: center; padding: .8rem 1rem; font-size: .98rem; }
  .nav-cta .who { display: block; text-align: center; padding: .3rem 0; }
  .nav-cta .hours-pill { justify-content: center; }
  /* A 34px circle stranded on its own row above a full-width button looks
     like a mistake. Give it a labelled full-width row of its own instead. */
  .nav-cta .theme-btn {
    width: 100%; height: auto; border-radius: 999px;
    padding: .7rem 1rem; font-size: .95rem;
    grid-auto-flow: column; gap: .5rem;
  }
  .theme-btn .sun::after  { content: ' Light mode'; font-size: .95rem; }
  .theme-btn .moon::after { content: ' Dark mode';  font-size: .95rem; }
  /* The menu covers the page, so nothing behind it should scroll away. */
  body.nav-open { overflow: hidden; }
}

/* ===========================================================================
   Student dashboard
   The first thing a student sees after logging in. One obvious action at the
   top - carry on where you stopped - then progress, then everything else.
   =========================================================================== */
.dash-head { margin-bottom: 1.4rem; }
.dash-head h1 { font-size: clamp(1.6rem, 3vw, 2.2rem); margin-bottom: .2rem; }
.dash-head .lede { color: var(--ink-2); margin: 0; }

.dash-section { margin: 2.2rem 0 1rem; }
.dash-section h2 { font-size: 1.15rem; margin: 0; }

/* the resume card - deliberately the biggest thing on the page */
.resume-card {
  display: flex; align-items: center; gap: 1.15rem;
  background: linear-gradient(135deg, rgba(47,168,224,.16), rgba(58,208,176,.09));
  border: 1px solid rgba(47,168,224,.35); border-radius: var(--radius);
  padding: 1.15rem 1.35rem; margin-bottom: 1.6rem; color: var(--ink);
  transition: transform .12s ease, border-color .12s ease;
}
.resume-card:hover { transform: translateY(-2px); border-color: var(--brand); color: var(--ink); }
.resume-play {
  width: 48px; height: 48px; flex: 0 0 auto; border-radius: 50%;
  display: grid; place-items: center; font-size: 1.05rem;
  background: var(--brand); color: var(--on-brand);
}
.resume-body { display: flex; flex-direction: column; gap: .18rem; min-width: 0; flex: 1; }
.resume-kicker {
  font-size: .72rem; letter-spacing: .09em; text-transform: uppercase;
  color: var(--accent); font-weight: 700;
}
.resume-body strong {
  font-size: 1.08rem; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.resume-course { font-size: .86rem; color: var(--dim); }
.resume-bar { display: flex; align-items: center; gap: .6rem; margin-top: .35rem; }
.resume-bar .bar { flex: 1; max-width: 260px; }
.resume-go { flex: 0 0 auto; font-weight: 700; color: var(--brand); white-space: nowrap; }
@media (max-width: 640px) {
  .resume-card { padding: 1rem; gap: .9rem; flex-wrap: wrap; }
  .resume-go { width: 100%; text-align: right; }
  .resume-bar .bar { max-width: none; }
}

/* Course list - full-width rows.
   A grid of cards looks wrong with one course (marooned in the left third of
   an empty screen) and cramped on a phone. Rows read correctly at any count
   and stack cleanly. */
.course-rows { display: flex; flex-direction: column; gap: .75rem; }
.course-row {
  display: flex; align-items: center; gap: 1.4rem;
  padding: 1.05rem 1.25rem; color: var(--ink);
  background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius);
  transition: border-color .12s ease, transform .12s ease;
}
.course-row:hover { border-color: var(--brand); transform: translateY(-1px); color: var(--ink); }
.cr-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: .2rem; }
.cr-title { font-weight: 700; font-size: 1.05rem; display: flex; align-items: center; gap: .5rem; }
.cr-meta {
  font-size: .86rem; color: var(--dim);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cr-note { color: var(--warn); }
.cr-progress {
  flex: 0 0 auto; display: flex; align-items: center; gap: .65rem; width: 190px;
}
.cr-progress .bar { flex: 1; }
.cr-pct {
  font-size: .84rem; font-weight: 700; color: var(--ink-2);
  font-variant-numeric: tabular-nums; min-width: 3.2ch; text-align: right;
}
.cr-go { flex: 0 0 auto; font-weight: 700; color: var(--brand); white-space: nowrap; }

@media (max-width: 760px) {
  /* On a phone: title, then the bar, then the action - each on its own line
     and full width, rather than three things fighting for one row. */
  .course-row { flex-wrap: wrap; gap: .7rem; padding: 1rem; }
  .cr-main { flex: 1 0 100%; }
  .cr-meta { white-space: normal; }
  .cr-progress { width: auto; flex: 1 1 auto; }
  .cr-go { margin-left: auto; }
}

/* the quick links strip at the bottom */
.dash-links {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-top: 2.4rem;
}
@media (max-width: 900px) { .dash-links { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 520px) { .dash-links { grid-template-columns: 1fr; } }
.dash-link {
  display: block; padding: 1rem 1.1rem; border-radius: var(--radius);
  background: var(--panel); border: 1px solid var(--line); color: var(--ink);
  transition: border-color .12s ease, transform .12s ease;
}
.dash-link:hover { border-color: var(--brand); transform: translateY(-2px); color: var(--ink); }
.dash-link strong { display: block; font-size: .96rem; margin-bottom: .15rem; }
.dash-link span { font-size: .82rem; color: var(--dim); }

/* a friendlier nothing-here state */
.empty-state {
  grid-column: 1 / -1; text-align: center; padding: 2.6rem 1.5rem;
  background: var(--panel); border: 1px dashed var(--line); border-radius: var(--radius);
}
.empty-state h3 { margin-bottom: .4rem; }
.empty-state p { color: var(--dim); max-width: 46ch; margin: 0 auto 1rem; }

/* ---------- hero ----------------------------------------------------------- */
.hero {
  position: relative; overflow: hidden;
  padding: clamp(3.5rem, 8vw, 6.5rem) 0 clamp(3rem, 6vw, 5rem);
  background:
    radial-gradient(900px 460px at 78% -8%, rgba(47,168,224,.20), transparent 62%),
    radial-gradient(700px 400px at 8% 105%, rgba(58,208,176,.13), transparent 60%);
}
.hero-grid { display: grid; grid-template-columns: 1.15fr .85fr; gap: 3rem; align-items: center; }
.eyebrow {
  display: inline-flex; align-items: center; gap: .5rem;
  font-size: .78rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase;
  color: var(--accent); background: rgba(58,208,176,.1);
  border: 1px solid rgba(58,208,176,.25); padding: .32rem .8rem; border-radius: 999px;
  margin-bottom: 1.1rem;
}
/* text-wrap: balance evens the lines out instead of leaving one orphaned word
   on the last row, which is most of what makes a long headline look amateur.
   The tighter line-height matters at display sizes: 1.22 is right for a
   sub-heading and too airy once the type is 3rem and running to four lines. */
.hero h1 {
  margin-bottom: .6rem;
  line-height: 1.1;
  text-wrap: balance;
  max-width: 16ch;
}
/* A headline only stays at 16ch while it is short enough to deserve the full
   display size. Past that the column is the limit, not the character count. */
@media (min-width: 981px) { .hero h1 { max-width: 20ch; } }

/* The second line, for a strapline that would otherwise be crammed into the
   headline itself and wreck its wrapping. */
.hero-sub {
  font-size: clamp(1.05rem, 1.7vw, 1.32rem);
  font-weight: 600;
  line-height: 1.35;
  color: var(--accent);
  margin: 0 0 1rem;
  max-width: 34ch;
  text-wrap: balance;
}
.hero h1 .grad {
  background: linear-gradient(120deg, var(--brand), var(--accent));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.lede { font-size: 1.1rem; color: var(--ink-2); max-width: 56ch; }
.hero-actions { display: flex; flex-wrap: wrap; gap: .75rem; margin-top: 1.6rem; }
.hero-stats { display: flex; gap: 2.2rem; margin-top: 2.4rem; flex-wrap: wrap; }
.hero-stats b { display: block; font-size: 1.6rem; color: var(--ink); line-height: 1.1; }
.hero-stats span { font-size: .82rem; color: var(--dim); }

.hero-card {
  background: linear-gradient(160deg, var(--panel), var(--bg-2));
  border: 1px solid var(--line); border-radius: 18px; padding: 1.4rem;
  box-shadow: var(--shadow);
}
.hero-card h4 { font-size: .78rem; letter-spacing: .1em; text-transform: uppercase; color: var(--dim); }
.stack-row {
  display: flex; align-items: center; gap: .75rem;
  padding: .7rem 0; border-bottom: 1px dashed var(--line-soft); font-size: .93rem;
}
.stack-row:last-child { border-bottom: 0; }
.stack-row .dot { width: 9px; height: 9px; border-radius: 50%; background: var(--brand); flex: 0 0 auto; }
.stack-row .dot.a { background: var(--accent); }
.stack-row .dot.w { background: var(--warn); }
.stack-row em { font-style: normal; color: var(--dim); margin-left: auto; font-size: .8rem; }

@media (max-width: 900px) { .hero-grid { grid-template-columns: 1fr; gap: 2rem; } }

/* ---------- sections & cards ------------------------------------------------ */
.section { padding: clamp(3rem, 6vw, 4.5rem) 0; }
.section.alt { background: var(--bg-2); border-top: 1px solid var(--line-soft); border-bottom: 1px solid var(--line-soft); }
.section-head { max-width: 62ch; margin-bottom: 2.2rem; }
.section-head.center { margin-left: auto; margin-right: auto; text-align: center; }

.grid { display: grid; gap: 1.15rem; }
.grid.c2 { grid-template-columns: repeat(2, 1fr); }
.grid.c3 { grid-template-columns: repeat(3, 1fr); }
.grid.c4 { grid-template-columns: repeat(4, 1fr); }
@media (max-width: 950px) { .grid.c3, .grid.c4 { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px) { .grid.c2, .grid.c3, .grid.c4 { grid-template-columns: 1fr; } }

.card {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.35rem;
  transition: border-color .15s ease, transform .15s ease;
}
.card:hover { border-color: var(--card-hover); }
.card h3 { margin-bottom: .4rem; }
.card p { color: var(--ink-2); font-size: .93rem; margin-bottom: 0; }
.card .kicker {
  font-size: .74rem; font-weight: 700; letter-spacing: .09em;
  text-transform: uppercase; color: var(--brand); margin-bottom: .5rem;
}

/* course cards */
.course-card { display: flex; flex-direction: column; overflow: hidden; padding: 0; }
.course-top { height: 106px; position: relative; display: grid; place-items: center; }
.course-top::after {
  content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, transparent 40%, var(--cover-fade));
}
.course-top span {
  position: relative; z-index: 1; font-size: 1.55rem; font-weight: 800;
  color: rgba(255,255,255,.92); letter-spacing: .04em;
}
/* That white is right on a dark card and invisible on a light one - it beats
   .chip's own colour on specificity, so it has to be undone explicitly. */
html[data-chrome="public"][data-theme="light"] .course-top span { color: var(--ink-2); }
@media (prefers-color-scheme: light) {
  html[data-chrome="public"]:not([data-theme="dark"]) .course-top span { color: var(--ink-2); }
}
.course-body { padding: 1.15rem 1.25rem 1.3rem; display: flex; flex-direction: column; flex: 1; }
.course-body h3 { font-size: 1.08rem; }
.course-meta {
  display: flex; flex-wrap: wrap; gap: .45rem; margin: .7rem 0 .9rem;
}
.course-foot { margin-top: auto; padding-top: .9rem; display: flex; align-items: center; gap: .6rem; }

.badge {
  display: inline-block; font-size: .74rem; font-weight: 700;
  padding: .2rem .6rem; border-radius: 6px;
  background: var(--panel-2); color: var(--ink-2); border: 1px solid var(--line);
}
.badge.ok    { color: var(--ok);     border-color: rgba(58,192,122,.35); background: rgba(58,192,122,.1); }
.badge.warn  { color: var(--warn);   border-color: rgba(224,166,58,.35); background: rgba(224,166,58,.1); }
.badge.danger{ color: var(--danger); border-color: rgba(224,86,111,.35); background: rgba(224,86,111,.1); }
.badge.brand { color: var(--brand);  border-color: rgba(47,168,224,.35);  background: rgba(47,168,224,.1); }

/* progress bar
   The fill is written as <i> in some templates and <span> in others; style
   both, or the bar renders as an empty grey pill at every percentage. */
.bar { height: 6px; background: var(--line-soft); border-radius: 99px; overflow: hidden; }
.bar span, .bar i { display: block; height: 100%; border-radius: 99px; background: linear-gradient(90deg, var(--brand), var(--accent)); transition: width .4s ease; }
.bar.thin { height: 4px; }
.bar.done span, .bar.done i { background: var(--ok); }

/* ---------- forms ---------------------------------------------------------- */
label { display: block; font-size: .84rem; font-weight: 600; color: var(--ink-2); margin-bottom: .35rem; }
/* input:not([type]) matters: an <input> with no type attribute defaults to
   text but is NOT matched by input[type=text], and would render unstyled. */
input:not([type]),
input[type=text], input[type=email], input[type=password], input[type=number],
input[type=date], input[type=url], input[type=tel], input[type=search],
select, textarea {
  width: 100%; background: var(--bg-2); border: 1px solid var(--line);
  color: var(--ink); padding: .68rem .8rem; border-radius: var(--radius-sm);
  font-family: inherit; font-size: .95rem; transition: border-color .12s ease;
}
input:focus, select:focus, textarea:focus { outline: 0; border-color: var(--brand); }
textarea { min-height: 130px; resize: vertical; line-height: 1.6; }
textarea.code { font-family: var(--mono); font-size: .88rem; min-height: 320px; }
.field { margin-bottom: 1rem; }
.field-row { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1rem; }
.field-row.c3 { grid-template-columns: repeat(3, 1fr); }
@media (max-width: 640px) { .field-row, .field-row.c3 { grid-template-columns: 1fr; } }
.hint { font-size: .8rem; color: var(--dim); margin-top: .3rem; }
.check { display: flex; align-items: center; gap: .5rem; font-size: .9rem; color: var(--ink-2); }
.check input { width: auto; }

.flash {
  padding: .8rem 1rem; border-radius: var(--radius-sm); margin-bottom: 1.2rem;
  font-size: .92rem; border: 1px solid;
}
.flash.ok    { background: rgba(58,192,122,.1); border-color: rgba(58,192,122,.35); color: #8ce0b3; }
.flash.error { background: rgba(224,86,111,.1); border-color: rgba(224,86,111,.35); color: #f0a0b0; }
.flash.info  { background: rgba(47,168,224,.1); border-color: rgba(47,168,224,.35); color: #94d3f2; }

/* auth page */
.auth-wrap { min-height: 100vh; display: grid; grid-template-columns: 1fr 1fr; }
.auth-side {
  padding: 3rem; display: flex; flex-direction: column; justify-content: center;
  background:
    radial-gradient(600px 400px at 20% 20%, rgba(47,168,224,.18), transparent 60%),
    var(--bg-2);
  border-right: 1px solid var(--line);
}
.auth-main { display: grid; place-items: center; padding: 2rem; }
.auth-box { width: 100%; max-width: 400px; }
@media (max-width: 860px) { .auth-wrap { grid-template-columns: 1fr; } .auth-side { display: none; } }
.auth-form { margin-top: 1.2rem; }
.auth-form .btn.big { width: 100%; justify-content: center; margin-top: .4rem; }

/* Show/hide sits inside the password box. On a phone, typing a password you
   cannot see into a login you did not choose is the most common reason people
   give up and email you instead. */
.pw-wrap { position: relative; display: block; }
.pw-wrap input { padding-right: 4.2rem; }
.pw-toggle {
  position: absolute; right: .4rem; top: 50%; transform: translateY(-50%);
  background: none; border: 0; color: var(--brand); cursor: pointer;
  font-size: .82rem; font-weight: 700; padding: .35rem .55rem; border-radius: 7px;
}
.pw-toggle:hover { background: var(--panel-2); }
@media (max-width: 860px) {
  .auth-wrap { align-items: start; }
  .auth-box { max-width: none; padding-top: 1rem; }
}

/* ---------- tables --------------------------------------------------------- */
.table-wrap { overflow-x: auto; border: 1px solid var(--line); border-radius: var(--radius); }
table { width: 100%; border-collapse: collapse; font-size: .91rem; }
thead th {
  text-align: left; background: var(--bg-2); color: var(--dim);
  font-size: .76rem; letter-spacing: .07em; text-transform: uppercase;
  padding: .75rem .9rem; border-bottom: 1px solid var(--line); white-space: nowrap;
}
tbody td { padding: .75rem .9rem; border-bottom: 1px solid var(--line-soft); vertical-align: middle; }
tbody tr:last-child td { border-bottom: 0; }
tbody tr:hover { background: var(--row-hover); }
td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
.row-actions { display: flex; gap: .4rem; flex-wrap: wrap; }

/* ---------- app / dashboard ------------------------------------------------- */
/* Top and bottom only. The shorthand used to be `2.2rem 0 4rem`, which also
   reset the 20px side padding .wrap sets - so every `class="wrap page"`
   element ran edge to edge on a phone. Invisible on a desktop, because the
   max-width leaves a margin anyway. */
.page { padding-top: 2.2rem; padding-bottom: 4rem; }
.page-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 1rem; margin-bottom: 1.8rem; flex-wrap: wrap;
}
.page-head h1 { font-size: clamp(1.6rem, 3vw, 2.1rem); margin: 0; }
.page-head p { margin: .3rem 0 0; color: var(--dim); }
.crumbs { font-size: .85rem; color: var(--dim); margin-bottom: .6rem; }
.crumbs a { color: var(--dim); }
.crumbs a:hover { color: var(--brand); }

.stat-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; margin-bottom: 2rem; }
@media (max-width: 900px) { .stat-cards { grid-template-columns: repeat(2, 1fr); } }
.stat {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.1rem 1.2rem;
}
/* The templates emit <strong>, so every one of these needs both tags or the
   big number silently renders as ordinary body text. */
.stat b, .stat strong { display: block; font-size: 1.75rem; line-height: 1.15; font-variant-numeric: tabular-nums; }
.stat span { font-size: .8rem; color: var(--dim); text-transform: uppercase; letter-spacing: .06em; }
.stat.accent b, .stat.accent strong { color: var(--accent); }
.stat.warn b, .stat.warn strong { color: var(--warn); }
.stat.danger b, .stat.danger strong { color: var(--danger); }

/* lesson list */
.lesson-list { border: 1px solid var(--line); border-radius: var(--radius); overflow: hidden; }
.week-head {
  background: var(--bg-2); padding: .6rem 1.1rem; font-size: .78rem;
  letter-spacing: .09em; text-transform: uppercase; color: var(--dim);
  border-bottom: 1px solid var(--line); font-weight: 700;
}
.lesson-row {
  display: flex; align-items: center; gap: 1rem;
  padding: .95rem 1.1rem; border-bottom: 1px solid var(--line-soft);
  background: var(--panel); color: var(--ink);
}
.lesson-row:last-child { border-bottom: 0; }
.lesson-row:hover { background: var(--panel-2); color: var(--ink); }
.lesson-row.locked { opacity: .58; pointer-events: none; }
/* When the row wraps a link, the link becomes the only flex child - so it has
   to carry the layout, or lesson-main never gets its flex:1 and the duration
   stops sitting on the right. */
.lesson-row a {
  display: flex; align-items: center; gap: 1rem;
  flex: 1; min-width: 0; color: inherit;
}
.lesson-row.preview { cursor: pointer; }
.lesson-row.preview .chip {
  background: rgba(47, 168, 224, .14); border-color: rgba(47, 168, 224, .4);
  color: var(--brand); font-weight: 700;
}
.lesson-row.preview:hover .chip { background: var(--brand); color: var(--on-brand); }
.lesson-icon {
  width: 34px; height: 34px; flex: 0 0 auto; border-radius: 9px;
  display: grid; place-items: center; background: var(--panel-2);
  border: 1px solid var(--line); color: var(--brand);
}
.lesson-icon svg { width: 15px; height: 15px; }
.lesson-icon.done { background: rgba(58,192,122,.13); border-color: rgba(58,192,122,.35); color: var(--ok); }
.lesson-icon.lock { color: var(--dim); }
.lesson-main { flex: 1; min-width: 0; }
.lesson-main b, .lesson-main strong { display: block; font-size: .96rem; font-weight: 600; }
.lesson-main .sub, .lesson-main .small { display: block; font-size: .8rem; color: var(--dim); }
.lesson-side { flex: 0 0 auto; display: flex; align-items: center; gap: .8rem; }
.lesson-pct { font-size: .82rem; color: var(--dim); font-variant-numeric: tabular-nums; min-width: 3ch; text-align: right; }
.lesson-row .bar { width: 90px; }
@media (max-width: 640px) { .lesson-row .bar { display: none; } }

/* ---------- the player ------------------------------------------------------ */
body.theatre { background: #000; }
/* One column. The stylesheet still carries a .theatre-side lesson rail, but no
   template renders it, so reserving 340px for it just squeezed the video and
   left a black strip down the side of every lesson on a desktop. */
.theatre-shell { display: grid; grid-template-columns: 1fr; min-height: 100vh; }
@media (max-width: 1050px) { .theatre-shell { grid-template-columns: 1fr; } }

.theatre-main { background: #000; display: flex; flex-direction: column; }
.theatre-bar {
  display: flex; align-items: center; gap: 1rem; padding: .75rem 1.2rem;
  border-bottom: 1px solid #16233a; background: #060a12;
}
.theatre-bar .back { color: var(--ink-2); font-size: .88rem; display: inline-flex; gap: .4rem; align-items: center; }
.theatre-bar .t { font-weight: 600; font-size: .95rem; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.theatre-bar .spacer { margin-left: auto; }
/* The lesson title is an <h1> inside this bar. Without this it inherits the
   page-heading clamp and renders at up to 3.1rem with a half-em margin, inside
   a strip padded for .95rem text. */
.theatre-bar h1 { font-size: 1.05rem; font-weight: 700; line-height: 1.3; margin: 0; flex: 1; min-width: 0; }
.theatre-bar .hours-pill { margin-left: auto; flex: 0 0 auto; }
@media (max-width: 600px) {
  .theatre-bar { flex-wrap: wrap; gap: .5rem; padding: .7rem .9rem; }
  .theatre-bar h1 { font-size: .98rem; flex: 1 0 100%; }
}

.player {
  position: relative; background: #000; width: 100%;
  aspect-ratio: 16 / 9; max-height: calc(100vh - 190px);
  overflow: hidden; user-select: none;
}
.player video { width: 100%; height: 100%; display: block; background: #000; object-fit: contain; }
.player.fs { max-height: none; height: 100vh; aspect-ratio: auto; }

/* Something always has to be on screen while a video is fetching or failing.
   A silent black rectangle reads as a broken site, and the most common cause
   of one - a signed link that has aged past its couple of hours - is fixed by
   a reload, so the error says so and offers the button. */
/* The watermark. White with a dark shadow so it stays legible over a bright
   slide and a dark terminal alike, and it survives a screen recording either
   way. Never intercepts a click. */
.vid-mark {
  position: absolute; z-index: 3; pointer-events: none; user-select: none;
  font-size: clamp(.7rem, 1.4vw, .95rem); font-weight: 700; letter-spacing: .04em;
  color: #fff; text-shadow: 0 1px 3px rgba(0,0,0,.85), 0 0 14px rgba(0,0,0,.6);
  transition: top .8s ease, right .8s ease, bottom .8s ease, left .8s ease;
  max-width: 60%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

.player-veil {
  position: absolute; inset: 0; display: flex; flex-direction: column;
  align-items: center; justify-content: center; gap: .8rem; text-align: center;
  padding: 1.5rem; background: rgba(4, 8, 16, .82); color: #e8eef6;
  font-size: .92rem; z-index: 2;
}
.player-veil[hidden] { display: none; }
.player-veil.error { background: rgba(4, 8, 16, .94); }
.player-veil strong { font-size: 1rem; }
.player-veil .spinner {
  width: 34px; height: 34px; border-radius: 50%;
  border: 3px solid rgba(255, 255, 255, .22); border-top-color: var(--brand);
  animation: spin .8s linear infinite;
}
@media (prefers-reduced-motion: reduce) { .player-veil .spinner { animation-duration: 2.4s; } }

.pl-ctrl {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 2.6rem .9rem .7rem;
  background: linear-gradient(180deg, transparent, rgba(0,0,0,.86) 55%);
  opacity: 0; transition: opacity .2s ease; z-index: 3;
}
.player:hover .pl-ctrl, .player.paused .pl-ctrl, .player.show-ui .pl-ctrl { opacity: 1; }
.player.hide-cursor { cursor: none; }

.pl-seek { position: relative; height: 16px; display: flex; align-items: center; cursor: pointer; }
.pl-seek .track { position: relative; height: 4px; width: 100%; background: rgba(255,255,255,.26); border-radius: 99px; transition: height .12s ease; }
.pl-seek:hover .track { height: 7px; }
.pl-seek .buf { position: absolute; left: 0; top: 0; bottom: 0; background: rgba(255,255,255,.32); border-radius: 99px; }
.pl-seek .fill { position: absolute; left: 0; top: 0; bottom: 0; background: var(--brand); border-radius: 99px; }
.pl-seek .furthest { position: absolute; top: -3px; bottom: -3px; width: 2px; background: var(--accent); opacity: .85; }
.pl-seek .knob {
  position: absolute; top: 50%; width: 13px; height: 13px; border-radius: 50%;
  background: var(--brand); transform: translate(-50%, -50%) scale(0);
  transition: transform .12s ease;
}
.pl-seek:hover .knob { transform: translate(-50%, -50%) scale(1); }

.pl-row { display: flex; align-items: center; gap: .55rem; margin-top: .45rem; }
.pl-btn {
  background: none; border: 0; color: #fff; cursor: pointer;
  width: 36px; height: 36px; border-radius: 8px; display: grid; place-items: center;
  transition: background .12s ease;
}
.pl-btn:hover { background: rgba(255,255,255,.14); }
.pl-btn svg { width: 20px; height: 20px; fill: currentColor; }
.pl-btn.big svg { width: 25px; height: 25px; }
.pl-time { font-size: .82rem; color: rgba(255,255,255,.86); font-variant-numeric: tabular-nums; margin-left: .3rem; }
.pl-spacer { margin-left: auto; }
.pl-vol { display: flex; align-items: center; gap: .4rem; }
.pl-vol input[type=range] { width: 0; opacity: 0; transition: width .18s ease, opacity .18s ease; accent-color: var(--brand); }
.pl-vol:hover input[type=range] { width: 74px; opacity: 1; }
.pl-rate {
  background: rgba(255,255,255,.12); border: 0; color: #fff; font-size: .8rem;
  padding: .3rem .45rem; border-radius: 7px; cursor: pointer; font-family: inherit;
}

.pl-center {
  position: absolute; inset: 0; display: grid; place-items: center; z-index: 2;
  pointer-events: none;
}
.pl-center button {
  pointer-events: auto; width: 76px; height: 76px; border-radius: 50%;
  background: rgba(0,0,0,.6); border: 2px solid rgba(255,255,255,.35);
  color: #fff; cursor: pointer; display: grid; place-items: center;
  opacity: 0; transform: scale(.85); transition: opacity .18s ease, transform .18s ease;
}
.player.paused .pl-center button { opacity: 1; transform: scale(1); }
.pl-center button svg { width: 32px; height: 32px; fill: currentColor; margin-left: 3px; }

.pl-toast {
  position: absolute; top: 14px; left: 50%; transform: translateX(-50%);
  background: rgba(0,0,0,.78); color: #fff; padding: .4rem .9rem;
  border-radius: 99px; font-size: .84rem; z-index: 5; opacity: 0;
  transition: opacity .25s ease; pointer-events: none;
}
.pl-toast.on { opacity: 1; }

.pl-overlay {
  position: absolute; inset: 0; z-index: 6; display: none;
  place-items: center; text-align: center; padding: 2rem;
  background: rgba(4,8,16,.94); backdrop-filter: blur(4px);
}
.pl-overlay.on { display: grid; }
.pl-overlay h3 { color: var(--warn); margin-bottom: .5rem; }
.pl-overlay p { color: var(--ink-2); max-width: 44ch; margin: 0 auto 1.2rem; }

.pl-spin {
  position: absolute; inset: 0; display: none; place-items: center; z-index: 4; pointer-events: none;
}
.player.buffering .pl-spin { display: grid; }
.pl-spin i {
  width: 42px; height: 42px; border-radius: 50%; display: block;
  border: 3px solid rgba(255,255,255,.2); border-top-color: var(--brand);
  animation: spin .8s linear infinite;
}
@keyframes spin { to { transform: rotate(360deg); } }

.theatre-below { padding: 1.3rem 1.4rem 3rem; background: var(--bg); flex: 1; }
.theatre-below h1 { font-size: 1.35rem; margin-bottom: .35rem; }
.watch-strip {
  display: flex; align-items: center; gap: 1.4rem; flex-wrap: wrap;
  padding: .8rem 1rem; background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); margin: 1rem 0;
}
.watch-strip div b { display: block; font-size: 1.05rem; font-variant-numeric: tabular-nums; }
.watch-strip div span { font-size: .74rem; color: var(--dim); text-transform: uppercase; letter-spacing: .06em; }

.theatre-side {
  background: var(--bg-2); border-left: 1px solid var(--line);
  overflow-y: auto; max-height: 100vh; position: sticky; top: 0;
}
.theatre-side .sh {
  padding: 1rem 1.1rem .7rem; border-bottom: 1px solid var(--line);
  font-size: .78rem; letter-spacing: .09em; text-transform: uppercase; color: var(--dim); font-weight: 700;
}
.theatre-side .lesson-row { background: transparent; padding: .8rem 1.1rem; align-items: flex-start; gap: .7rem; }
.theatre-side .lesson-row.current { background: rgba(47,168,224,.1); border-left: 3px solid var(--brand); }

/* The rail is only 340px wide. Without this the title column gets squeezed to
   a few characters and wraps one word per line. Drop the decorations that
   need horizontal room and stack what is left. */
.theatre-side .lesson-row .bar { display: none; }
.theatre-side .lesson-icon { margin-top: .15rem; }
.theatre-side .lesson-side {
  flex-direction: column; align-items: flex-end; gap: .3rem; margin-left: auto;
}
.theatre-side .lesson-main { min-width: 0; overflow-wrap: anywhere; }
.theatre-side .lesson-main b { font-size: .9rem; line-height: 1.35; }
.theatre-side .lesson-main .sub {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden; line-height: 1.35; margin-top: .15rem;
}
@media (max-width: 1050px) { .theatre-side { position: static; max-height: none; border-left: 0; border-top: 1px solid var(--line); } }

/* ---------- quiz ------------------------------------------------------------ */
.quiz-q {
  background: var(--panel); border: 1px solid var(--line);
  border-radius: var(--radius); padding: 1.25rem; margin-bottom: 1rem;
}
.quiz-q > b { display: block; margin-bottom: .9rem; font-size: 1rem; }
.quiz-q .qn { color: var(--brand); margin-right: .4rem; }
.opt {
  display: flex; align-items: flex-start; gap: .7rem; padding: .7rem .85rem;
  border: 1px solid var(--line); border-radius: var(--radius-sm);
  margin-bottom: .5rem; cursor: pointer; transition: border-color .12s ease, background .12s ease;
  font-size: .94rem;
}
.opt:hover { border-color: var(--brand); background: var(--panel-2); }
.opt input { margin-top: .25rem; accent-color: var(--brand); }
.opt.correct { border-color: rgba(58,192,122,.5); background: rgba(58,192,122,.09); }
.opt.wrong   { border-color: rgba(224,86,111,.5); background: rgba(224,86,111,.09); }
.explain {
  margin-top: .6rem; padding: .7rem .85rem; border-left: 3px solid var(--brand);
  background: var(--bg-2); font-size: .88rem; color: var(--ink-2); border-radius: 0 8px 8px 0;
}
.score-ring {
  width: 128px; height: 128px; border-radius: 50%; display: grid; place-items: center;
  margin: 0 auto 1rem; font-size: 1.9rem; font-weight: 800;
  background: conic-gradient(var(--brand) calc(var(--p) * 1%), var(--line-soft) 0);
  position: relative;
}
.score-ring::before { content: ''; position: absolute; inset: 9px; border-radius: 50%; background: var(--bg); }
.score-ring span { position: relative; z-index: 1; }
.score-ring.pass { background: conic-gradient(var(--ok) calc(var(--p) * 1%), var(--line-soft) 0); }

/* ---------- blog / prose ---------------------------------------------------- */
.prose { font-size: 1.03rem; color: var(--ink-2); max-width: 74ch; }
.prose h2 { margin-top: 2.2rem; color: var(--ink); }
.prose h3 { margin-top: 1.6rem; color: var(--ink); }
.prose a { text-decoration: underline; text-underline-offset: 3px; }
.prose code {
  font-family: var(--mono); font-size: .88em; background: var(--panel-2);
  padding: .12em .38em; border-radius: 5px; color: var(--accent);
}
.prose pre.code {
  background: var(--code-bg); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: 1rem 1.1rem; overflow-x: auto; margin: 1.2rem 0;
}
.prose pre.code code { background: none; padding: 0; color: var(--code-ink); font-size: .87rem; line-height: 1.65; }
.prose blockquote {
  margin: 1.3rem 0; padding: .2rem 0 .2rem 1.1rem;
  border-left: 3px solid var(--brand); color: var(--ink); font-style: italic;
}
.prose ul, .prose ol { padding-left: 1.3rem; }
.prose li { margin-bottom: .45rem; }
/* Author-chosen colours, written as [[red:some words]] in a post body.
   Not scoped to .prose so they work in course and lesson descriptions too. */
.c-brand  { color: var(--brand); }
.c-accent { color: var(--accent); }
.c-warn   { color: var(--warn); }
.c-danger { color: var(--danger); }
.c-dim    { color: var(--dim); }
.c-ink    { color: var(--ink); }

.prose img { border-radius: var(--radius-sm); border: 1px solid var(--line); }
.prose table { margin: 1.2rem 0; }

.post-head { padding: 3rem 0 1.5rem; border-bottom: 1px solid var(--line-soft); margin-bottom: 2rem; }
/* the standing-summary line under a post title gets the article's measure,
   not the 56ch used for short page ledes */
.post-layout .post-head .lede { max-width: 96ch; }
.post-meta { display: flex; gap: 1rem; flex-wrap: wrap; color: var(--dim); font-size: .86rem; margin-top: .8rem; }
/* The article page runs wider than the rest of the site: a technical post
   with code blocks and diagrams needs the room, and the recommendations sit
   in their own column rather than stealing width from the prose.
   The aside is second in the DOM but first on screen - so a phone gets the
   article immediately and only meets the recommendations at the end. */
.post-layout {
  max-width: min(1720px, 95vw);
  display: grid;
  grid-template-columns: 330px minmax(0, 1fr) 250px;
  column-gap: 2.6rem;
}
.post-layout > article     { grid-column: 2; grid-row: 1; min-width: 0; }
.post-layout > .post-aside { grid-column: 1; grid-row: 1; }
.post-layout > .post-toc   { grid-column: 3; grid-row: 1; padding-top: 3rem; }

/* A jump link must not park the heading underneath the fixed header. */
.post-layout .prose h2,
.post-layout .prose h3 { scroll-margin-top: 92px; }

/* Wider than before, but paragraphs still stop at a readable measure -
   a 900px line of body text is tiring to follow. Images, code blocks and
   tables are exempt and run the full column, which is what actually makes
   the page feel wide: diagrams get the room, prose stays legible. */
.post-layout .prose { max-width: none; font-size: 1.08rem; }
.post-layout .prose > p,
.post-layout .prose > ul,
.post-layout .prose > ol,
.post-layout .prose > blockquote,
.post-layout .prose > h2,
.post-layout .prose > h3,
.post-layout .prose > h4 { max-width: 88ch; }
/* markdown() wraps a lone image in a paragraph - let that one off the leash. */
.post-layout .prose > p:has(img) { max-width: none; }

/* Images open full size in a new tab - the only way a wide diagram is
   readable on a phone. */
.prose a.zoom { display: block; text-decoration: none; position: relative; }
.prose a.zoom img { display: block; margin: 0; }
@media (max-width: 760px) {
  .prose a.zoom::after {
    content: "Tap to enlarge";
    position: absolute; right: .5rem; bottom: .5rem;
    background: var(--overlay); color: var(--ink-2);
    font-size: .72rem; padding: .25rem .55rem; border-radius: 999px;
    border: 1px solid var(--line);
  }
}

/* The divider. It is on the aside so it runs the full height of the post
   rather than stopping where the cards end. */
.post-aside { border-right: 1px solid var(--line); padding-right: 2.6rem; }
.post-aside-in { position: sticky; top: 92px; padding-top: 3rem; }
.post-aside-head {
  font-size: .78rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--dim); margin: 0 0 1rem;
}
.post-aside-list { display: grid; gap: 1rem; }
.post-aside-list .post-card { padding: 1rem 1.1rem; }
.post-aside-list .post-card h3 { font-size: .98rem; line-height: 1.35; }
.post-aside-list .post-card p {
  font-size: .86rem; line-height: 1.5;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden;
}
.post-aside-all { margin-top: 1.1rem; width: 100%; text-align: center; }

/* Not enough room for three columns: drop the contents rail first, since it
   is the most expendable of the three, and go back to the fixed width. */
@media (max-width: 1400px) {
  .post-layout { max-width: 1320px; grid-template-columns: 310px minmax(0, 1fr); }
  .post-layout > .post-toc { display: none; }
}

/* Below the breakpoint everything collapses to one column and the aside
   falls back to its DOM position: after the article, where it belongs. */
@media (max-width: 980px) {
  .post-layout { grid-template-columns: 1fr; }
  .post-layout > article, .post-layout > .post-aside { grid-column: 1; grid-row: auto; }
  .post-aside {
    border-right: 0; padding-right: 0;
    border-top: 1px solid var(--line); margin-top: 2.5rem;
  }
  .post-aside-in { position: static; padding-top: 2rem; }
  .post-aside-list { grid-template-columns: repeat(2, 1fr); }
  .toc { display: none; }
}
@media (max-width: 640px) {
  .post-aside-list { grid-template-columns: 1fr; }
}
.toc { position: sticky; top: 90px; font-size: .87rem; }
.toc b { display: block; font-size: .74rem; letter-spacing: .09em; text-transform: uppercase; color: var(--dim); margin-bottom: .6rem; }
.toc a { display: block; padding: .28rem 0 .28rem .7rem; border-left: 2px solid var(--line); color: var(--ink-2); }
.toc a:hover { border-left-color: var(--brand); color: var(--brand); }
.toc a.l3 { padding-left: 1.4rem; font-size: .84rem; }

.post-card { display: flex; flex-direction: column; }
.post-card h3 { font-size: 1.05rem; }
.post-card .pm { font-size: .8rem; color: var(--dim); margin-top: auto; padding-top: .8rem; }

.chips { display: flex; flex-wrap: wrap; gap: .45rem; }
.chip {
  font-size: .8rem; padding: .3rem .75rem; border-radius: 999px;
  background: var(--panel); border: 1px solid var(--line); color: var(--ink-2);
}
.chip:hover, .chip.on { border-color: var(--brand); color: var(--brand); }

/* ---------- misc ------------------------------------------------------------ */
.site-foot { background: var(--bg-2); border-top: 1px solid var(--line); padding: 3rem 0 1.5rem; margin-top: 3rem; }
.foot-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr; gap: 2rem; }
@media (max-width: 1050px) { .foot-grid { grid-template-columns: 1fr 1fr 1fr; } }
@media (max-width: 850px) { .foot-grid { grid-template-columns: 1fr 1fr; } }
@media (max-width: 520px) { .foot-grid { grid-template-columns: 1fr; } }
.foot-grid h4 { font-size: .8rem; letter-spacing: .09em; text-transform: uppercase; color: var(--dim); }
.foot-grid a { display: block; color: var(--ink-2); font-size: .9rem; padding: .22rem 0; }
.foot-grid a.btn { display: inline-flex; color: var(--on-brand); }
.foot-brand { margin-bottom: .9rem; }
.foot-legal {
  display: flex; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
  border-top: 1px solid var(--line); margin-top: 2.2rem; padding-top: 1.2rem;
  font-size: .84rem; color: var(--dim);
}
.foot-legal a { color: var(--dim); }

.empty {
  text-align: center; padding: 3.5rem 1rem; color: var(--dim);
  border: 1px dashed var(--line); border-radius: var(--radius);
}
.empty h3 { color: var(--ink-2); }

.split { display: grid; grid-template-columns: 1fr 340px; gap: 2rem; align-items: start; }
@media (max-width: 950px) { .split { grid-template-columns: 1fr; } }

.panel { background: var(--panel); border: 1px solid var(--line); border-radius: var(--radius); padding: 1.35rem; }
.panel h3 { font-size: 1rem; margin-bottom: .9rem; }
.panel + .panel { margin-top: 1.2rem; }

/* A .kv is the CONTAINER; each child div is one label/value row.
   Making the container itself the flex row put every pair side by side on one
   non-wrapping line - seven fields squeezed across the admin order page, and
   unreadable on a phone. */
.kv { display: block; font-size: .9rem; }
.kv > div {
  display: flex; justify-content: space-between; align-items: baseline; gap: 1rem;
  padding: .45rem 0; border-bottom: 1px dashed var(--line-soft);
}
.kv > div:last-child { border-bottom: 0; }
.kv span { color: var(--dim); }
.kv b { font-variant-numeric: tabular-nums; }
@media (max-width: 520px) {
  .kv > div { flex-direction: column; gap: .15rem; }
}

.tabs { display: flex; gap: .35rem; border-bottom: 1px solid var(--line); margin-bottom: 1.5rem; flex-wrap: wrap; }
.tabs a {
  padding: .6rem 1rem; color: var(--ink-2); font-size: .9rem; font-weight: 600;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tabs a.on { color: var(--brand); border-bottom-color: var(--brand); }

.mono { font-family: var(--mono); font-size: .86rem; }
.nowrap { white-space: nowrap; }
.mt2 { margin-top: 2rem; } .mt1 { margin-top: 1rem; } .mb1 { margin-bottom: 1rem; }
.flex { display: flex; gap: .6rem; align-items: center; flex-wrap: wrap; }
.flex.end { justify-content: flex-end; }
.flex.between { justify-content: space-between; }

@media print { .site-head, .site-foot, .btn { display: none; } body { background: #fff; color: #000; } }

/* utility - the player toggles this on the completion card */
.hidden { display: none !important; }

/* ===========================================================================
   Brand mark, hero artwork and the floating WhatsApp button
   =========================================================================== */

/* An uploaded or built-in logo image replaces the lettered square. */
.brand .mark.img {
  background: none; border-radius: 9px; object-fit: contain;
  width: 34px; height: 34px; display: block;
}
.site-foot .brand .mark.img { width: 38px; height: 38px; }

/* The 5G core artwork sits behind the hero, under the existing glows. */
.hero::before {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: url("/assets/img/hero-5g.svg") right center/cover no-repeat;
  opacity: .62;
  -webkit-mask-image: linear-gradient(to bottom, #000 0%, #000 58%, transparent 94%);
          mask-image: linear-gradient(to bottom, #000 0%, #000 58%, transparent 94%);
  pointer-events: none;
}
/* A scrim over the left half, so the headline sits on clean background and the
   diagram only reads where there is room for it. */
.hero::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(95deg,
    var(--bg) 0%, var(--hero-fade) 24%, var(--hero-fade-2) 42%, transparent 60%);
}
/* The hero illustration is drawn for a dark page - its network-function
   boxes are filled with the dark navy panel colour, which reads as dirty
   grey rectangles on a light background. Inverting flips those fills to
   near-white and the hue rotation brings the blue and teal strokes back to
   roughly their own colours, so it becomes white cards with coloured
   outlines: the same picture, dressed for a light page. */
html[data-chrome="public"][data-theme="light"] .hero::before,
html[data-chrome="public"][data-theme="light"] .hero::after { filter: none; }
html[data-chrome="public"][data-theme="light"] .hero::before {
  filter: invert(1) hue-rotate(180deg); opacity: .5;
}
@media (prefers-color-scheme: light) {
  html[data-chrome="public"]:not([data-theme="dark"]) .hero::before {
    filter: invert(1) hue-rotate(180deg); opacity: .5;
  }
}

.hero > .wrap { position: relative; z-index: 1; }
@media (max-width: 900px) {
  .hero::before { opacity: .3; }
  .hero::after { background: linear-gradient(180deg, var(--hero-fade-2), var(--hero-fade)); }
}

/* ---------- floating WhatsApp button --------------------------------------- */
.wa-float {
  position: fixed; right: 18px; bottom: 18px; z-index: 60;
  display: inline-flex; align-items: center; gap: .55rem;
  padding: .72rem .95rem; border-radius: 999px;
  background: #25d366; color: #04220f; font-weight: 700; font-size: .92rem;
  text-decoration: none; border: 1px solid rgba(255,255,255,.22);
  box-shadow: 0 10px 30px rgba(0,0,0,.42), 0 0 0 6px rgba(37,211,102,.12);
  transition: transform .16s ease, box-shadow .16s ease;
}
.wa-float:hover {
  transform: translateY(-2px);
  box-shadow: 0 14px 36px rgba(0,0,0,.5), 0 0 0 8px rgba(37,211,102,.18);
}
.wa-float svg { width: 22px; height: 22px; flex: 0 0 auto; }

/* On a phone it collapses to just the icon so it never covers the content. */
@media (max-width: 720px) {
  .wa-float { right: 14px; bottom: 14px; padding: .8rem; border-radius: 50%; }
  .wa-float span { display: none; }
  .wa-float svg { width: 26px; height: 26px; }
}
@media print { .wa-float { display: none; } }

/* ===========================================================================
   Admin > Site: tabs, colour pickers, upload previews, sticky save bar
   =========================================================================== */
.tabs {
  display: flex; gap: .35rem; flex-wrap: wrap;
  border-bottom: 1px solid var(--line); margin: 0 0 1.5rem;
}
.tabs .tab {
  padding: .6rem 1rem; color: var(--ink-2); font-weight: 600; font-size: .92rem;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.tabs .tab:hover { color: var(--ink); }
.tabs .tab.on { color: var(--ink); border-bottom-color: var(--brand); }

/* Form field rows. NOTE: .three is also used as `class="grid three"` for card
   grids, which needs different breakpoints entirely - see the .grid.three rule
   below, which is deliberately more specific so it wins there and only there. */
.two  { display: grid; grid-template-columns: 1fr 1fr; gap: 0 1rem; }
.three { display: grid; grid-template-columns: repeat(3, 1fr); gap: 0 1rem; }
@media (max-width: 700px) { .two, .three { grid-template-columns: 1fr; } }

/* Card grids: three across on a desktop, two on a tablet, one on a phone -
   and with a real row gap, so rows of cards do not touch. */
.grid.three { grid-template-columns: repeat(3, 1fr); gap: 1.15rem; }
@media (max-width: 950px) { .grid.three { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 640px)  { .grid.three { grid-template-columns: 1fr; } }

label.check {
  display: flex; align-items: flex-start; gap: .6rem; cursor: pointer;
  padding: .45rem 0; font-size: .94rem; color: var(--ink-2);
}
label.check input { margin-top: .25rem; width: 16px; height: 16px; accent-color: var(--brand); }
label.check span { line-height: 1.45; }

.colour-field { display: flex; gap: .5rem; align-items: center; }
.colour-field input[type="color"] {
  width: 46px; height: 40px; padding: 2px; border-radius: 9px;
  border: 1px solid var(--line); background: var(--panel); cursor: pointer;
}
.colour-field input.mono { flex: 1; min-width: 0; }

.logo-pick { display: flex; gap: 1.1rem; align-items: flex-start; }
.logo-preview {
  width: 92px; height: 92px; flex: 0 0 auto; border-radius: 12px;
  border: 1px dashed var(--line); background: var(--bg-2);
  display: grid; place-items: center; padding: 8px; text-align: center;
}
.logo-preview img { max-width: 100%; max-height: 100%; object-fit: contain; }
.logo-preview.qr { width: 128px; height: 128px; background: #fff; }
@media (max-width: 620px) { .logo-pick { flex-direction: column; } }

.sticky-save {
  position: sticky; bottom: 0; display: flex; gap: .6rem; flex-wrap: wrap;
  margin: 1.8rem -1.25rem -1.25rem; padding: 1rem 1.25rem;
  background: linear-gradient(180deg, rgba(16,27,48,0), var(--panel) 34%);
  border-top: 1px solid var(--line-soft); border-radius: 0 0 var(--radius) var(--radius);
}

.back { display: inline-block; color: var(--dim); font-size: .88rem; margin-bottom: .3rem; }
.back:hover { color: var(--ink); }
.right { text-align: right; }
.table .sub { color: var(--dim); font-weight: 400; }

/* ===========================================================================
   Selling: prices, the buy panel, checkout and the live-batch strip
   =========================================================================== */
.course-price { margin-left: auto; font-weight: 800; color: var(--ink); font-size: .98rem; }
.course-price s { color: var(--dim); font-weight: 500; margin-right: .3rem; font-size: .85rem; }
.course-foot { display: flex; align-items: center; gap: .6rem; }

.buy-panel .price-block { margin-bottom: 1rem; }
.price-block s { color: var(--dim); font-size: 1rem; margin-right: .45rem; }
.price-block b, .price-block strong { font-size: 2rem; letter-spacing: -.02em; display: inline; }
.price-block span { display: block; color: var(--dim); font-size: .82rem; margin-top: .2rem; }

/* Product cards carry a longer spec list than a course card does. */
.product-card { display: flex; flex-direction: column; }
.product-card .buy-points { margin-top: .6rem; margin-bottom: 1.1rem; }
.product-card .buy-points li { align-items: flex-start; }
.product-card .buy-points li::before {
  content: '▸'; color: var(--brand); flex: 0 0 auto; font-size: .8rem; line-height: 1.6;
}
.product-card .btn { margin-top: auto; align-self: flex-start; }

/* Two buttons per course card - read the syllabus, or just buy it. */
.card-actions { display: flex; gap: .5rem; flex-wrap: wrap; margin-top: .9rem; }
.card-actions .btn { flex: 1 1 auto; justify-content: center; }

/* The pinned buy bar on a phone. On a desktop the panel in the sidebar is
   already beside the syllabus, so the bar only exists below 950px, which is
   exactly where the sidebar drops underneath everything. */
.buy-bar { display: none; }
@media (max-width: 950px) {
  .buy-bar {
    position: fixed; left: 0; right: 0; bottom: 0; z-index: 45;
    display: flex; align-items: center; gap: 1rem;
    padding: .7rem 1rem calc(.7rem + env(safe-area-inset-bottom, 0px));
    background: var(--panel); border-top: 1px solid var(--line);
    box-shadow: 0 -8px 26px rgba(0, 0, 0, .3);
  }
  .buy-bar-price { display: flex; flex-direction: column; line-height: 1.2; }
  .buy-bar-price strong { font-size: 1.2rem; letter-spacing: -.02em; }
  .buy-bar-price s { color: var(--dim); font-weight: 500; font-size: .82rem; }
  .buy-bar-price span { color: var(--dim); font-size: .76rem; }
  .buy-bar .btn { margin-left: auto; padding: .75rem 1.4rem; }
  /* Room so the bar never covers the last line of the page. */
  .has-buy-bar { padding-bottom: 5.5rem; }
  /* The menu has to sit above the buy bar when it is open. */
  body.nav-open .buy-bar { display: none; }
  /* On one column, show the price and the button before the long syllabus
     as well - some people never scroll far enough to meet either. */
  .course-body .split > aside { order: -1; }
}

.buy-points { list-style: none; margin: 1.1rem 0 .6rem; padding: 0; }
.buy-points li {
  display: flex; align-items: flex-start; gap: .55rem;
  font-size: .89rem; color: var(--ink-2); padding: .3rem 0;
}
.buy-points svg { width: 15px; height: 15px; color: var(--ok); flex: 0 0 auto; margin-top: .22rem; }

/* ---------- checkout -------------------------------------------------------- */
.checkout-grid { display: grid; grid-template-columns: 1.35fr .65fr; gap: 2.4rem; align-items: start; }
@media (max-width: 900px) {
  .checkout-grid { grid-template-columns: 1fr; gap: 1.6rem; }
  .checkout-grid aside { order: -1; }
}

.steps { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.4rem; }
.steps .step {
  font-size: .8rem; font-weight: 700; color: var(--dim);
  border: 1px solid var(--line); border-radius: 999px; padding: .3rem .8rem;
}
.steps .step.on { color: var(--on-brand); background: var(--brand); border-color: transparent; }
.steps .step.done { color: var(--ok); border-color: rgba(58,192,122,.4); }

.order-summary .order-line { padding: .3rem 0 .9rem; border-bottom: 1px solid var(--line-soft); }
.order-summary .order-line .sub { color: var(--dim); font-size: .84rem; margin-top: .2rem; }
.order-summary .kv.total b { font-size: 1.5rem; color: var(--ink); }
.order-summary .strike { text-decoration: line-through; color: var(--dim); font-weight: 500; }

.pay-methods { display: flex; gap: 1.4rem; align-items: flex-start; flex-wrap: wrap; }
.pay-qr {
  flex: 0 0 auto; background: #fff; padding: 10px; border-radius: 12px;
  width: 208px; display: grid; gap: .4rem;
}
.pay-qr img { width: 188px; height: 188px; object-fit: contain; display: block; }
.pay-qr .muted { color: #4a5a6b; }
.pay-details { flex: 1; min-width: 240px; }

.copy-row {
  display: flex; align-items: center; justify-content: space-between; gap: .8rem;
  background: var(--bg-2); border: 1px solid var(--line);
  border-radius: var(--radius-sm); padding: .6rem .8rem; margin-bottom: .8rem;
}
.copy-row span { display: block; }
.copy-row b { font-size: 1rem; word-break: break-all; }
pre.bank {
  background: var(--bg-2); border: 1px solid var(--line); border-radius: var(--radius-sm);
  padding: .8rem; font-size: .88rem; white-space: pre-wrap; margin: .6rem 0 0;
}
.only-mobile { display: none; }
@media (max-width: 760px) { .only-mobile { display: inline-flex; } }

.pay-done { border-color: rgba(58,192,122,.4); background: rgba(58,192,122,.07); }
.pay-done h2 { display: flex; align-items: center; gap: .6rem; color: var(--ok); }
.pay-done svg { width: 26px; height: 26px; }
.pay-waiting { border-color: rgba(224,166,58,.4); background: rgba(224,166,58,.06); }

/* ---------- the live batch strip -------------------------------------------
   Multicolour and moving, because it is an announcement - but a slow gradient
   sweep rather than a strobe. Anyone whose system asks for reduced motion gets
   the same colours holding still.
--------------------------------------------------------------------------- */
.batch-strip {
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  padding: .72rem 20px; color: var(--ink); font-size: .9rem;
  border-bottom: 1px solid rgba(255,255,255,.08);
  background: linear-gradient(90deg,
    #1c6fa8, #17897a, #a8761c, #a83d51, #6a49b0, #1c6fa8);
  background-size: 300% 100%;
  animation: batch-sweep 14s linear infinite;
}
@keyframes batch-sweep {
  0%   { background-position:   0% 50%; }
  100% { background-position: 300% 50%; }
}
/* The gap above never applied: the spans live inside the anchor, so the
   anchor is the flex container that matters. Without this the title, date
   and seat count are butted together with no space at all. */
.batch-strip a {
  display: flex; align-items: center; gap: .75rem; flex-wrap: wrap;
  width: 100%; color: inherit;
}
/* The sweeping gradient is always saturated and dark, so the strip keeps
   light text in both themes rather than following --ink. */
.batch-strip, .batch-strip:hover, .batch-strip a { color: #fff; }
.batch-strip .bt { color: rgba(255,255,255,.95); }
.batch-strip:hover { filter: brightness(1.18); }

.batch-strip .blabel {
  font-size: .72rem; letter-spacing: .1em; text-transform: uppercase;
  font-weight: 800; padding: .2rem .55rem; border-radius: 999px;
  background: rgba(0,0,0,.35); color: #fff;
  animation: batch-blink 2.4s ease-in-out infinite;
}
@keyframes batch-blink {
  0%, 100% { opacity: 1; }
  50%      { opacity: .45; }
}

.batch-strip .bt { font-weight: 700; }
.batch-strip .bd { color: #fff; font-weight: 600; }
.batch-strip .bm { color: rgba(255,255,255,.85); font-size: .84rem; }
.batch-strip .bs {
  color: #fff; font-weight: 700; font-size: .82rem;
  background: rgba(0,0,0,.32); padding: .12rem .5rem; border-radius: 999px;
}
.batch-strip .bgo {
  margin-left: auto; font-weight: 800; color: #fff;
  display: inline-flex; align-items: center; gap: .3rem;
}
.batch-strip .bgo svg { width: 14px; height: 14px; }

.batch-strip .pulse {
  width: 9px; height: 9px; border-radius: 50%; background: #fff;
  flex: 0 0 auto; animation: batch-pulse 1.6s ease-in-out infinite;
}
@keyframes batch-pulse {
  0%, 100% { opacity: 1; box-shadow: 0 0 0 0 rgba(255,255,255,.6); }
  50%      { opacity: .5; box-shadow: 0 0 0 8px rgba(255,255,255,0); }
}

/* Colour stays, movement goes. */
@media (prefers-reduced-motion: reduce) {
  .batch-strip { animation: none; background-position: 20% 50%; }
  .batch-strip .pulse, .batch-strip .blabel { animation: none; }
}
@media (max-width: 760px) {
  .batch-strip { font-size: .84rem; gap: .5rem; }
  .batch-strip .bm { display: none; }
  .batch-strip .bgo span { display: none; }
  .batch-strip .bgo { margin-left: 0; }
}

/* ---------- course code ----------------------------------------------------- */
.badge.code {
  font-family: var(--mono); font-size: .74rem; letter-spacing: .02em;
  background: rgba(47,168,224,.12); border-color: rgba(47,168,224,.35); color: var(--brand);
}
.course-code-line { font-size: .84rem; color: var(--dim); margin-bottom: .3rem; }
.course-code-line b { color: var(--ink-2); margin-left: .3rem; }

/* ---------- admin-only explanation on a public page ------------------------- */
.admin-hint {
  margin-top: 1rem; padding: .85rem 1rem; border-radius: var(--radius-sm);
  background: rgba(224,166,58,.09); border: 1px solid rgba(224,166,58,.35);
  font-size: .87rem; color: var(--ink-2);
}
.admin-hint b { color: var(--warn); display: block; margin-bottom: .3rem; font-size: .76rem;
  letter-spacing: .08em; text-transform: uppercase; }
.admin-hint p { margin: 0 0 .4rem; }
.admin-hint ul { margin: 0; padding-left: 1.1rem; }
.admin-hint li { margin-bottom: .35rem; line-height: 1.45; }

/* --- headline preview in the admin ---------------------------------------
   Renders the assembled heading at something close to its real weight, so a
   missing space or a bad wrap is obvious before saving. */
.hero-preview {
  margin: .2rem 0 1.1rem; padding: 1rem 1.1rem;
  background: var(--panel-2); border: 1px dashed var(--line);
  border-radius: var(--radius-sm);
}
.hero-preview-label {
  display: block; font-size: .7rem; letter-spacing: .1em; text-transform: uppercase;
  color: var(--dim); margin-bottom: .5rem;
}
#heroPreview {
  font-size: 1.5rem; font-weight: 700; line-height: 1.15;
  letter-spacing: -.015em; color: var(--ink); text-wrap: balance;
}
#heroPreview .grad {
  background: linear-gradient(120deg, var(--brand), var(--accent));
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.hint.warn { color: var(--warn); }

/* ===========================================================================
   v2.2 - home page sections, buying, products, and the writing toolbar
   =========================================================================== */

/* --- writing: colours, sizes, note boxes (blog, courses, pages) ---------- */
.c-orange { color: #f08a3c; }
.c-purple { color: #a67cf0; }
.fs-sm { font-size: .85em; }
.fs-lg { font-size: 1.3em; line-height: 1.35; }
.fs-xl { font-size: 1.7em; line-height: 1.25; font-weight: 700; }
.fw-b  { font-weight: 700; }
.hl    { background: rgba(224, 166, 58, .22); color: var(--ink); padding: 0 .2em; border-radius: 3px; }

.callout {
  --cl: var(--brand);
  margin: 1.4rem 0; padding: .9rem 1.1rem; border-radius: var(--radius-sm);
  border: 1px solid color-mix(in srgb, var(--cl) 40%, transparent);
  border-left: 4px solid var(--cl);
  background: color-mix(in srgb, var(--cl) 9%, transparent);
  color: var(--ink);
}
.callout > b {
  display: block; margin-bottom: .25rem; color: var(--cl);
  font-size: .76rem; letter-spacing: .08em; text-transform: uppercase;
}
.callout.tip       { --cl: var(--ok); }
.callout.warning   { --cl: #f08a3c; }
.callout.important { --cl: #a67cf0; }

/* --- spam trap: off screen for people, still in the form for bots -------- */
.hp { position: absolute !important; left: -9999px !important; width: 1px; height: 1px; overflow: hidden; }

/* --- shared bits ---------------------------------------------------------- */
.wrap.narrow { max-width: 820px; }
.grid.two { grid-template-columns: repeat(2, 1fr); gap: 1.15rem; }
@media (max-width: 760px) { .grid.two { grid-template-columns: 1fr; } }
.tick-list { list-style: none; padding: 0; margin: .6rem 0 1.1rem; }
.tick-list li {
  position: relative; padding: .28rem 0 .28rem 1.7rem; color: var(--ink-2); line-height: 1.5;
}
.tick-list li::before {
  content: '✓'; position: absolute; left: 0; top: .28rem;
  width: 1.15rem; height: 1.15rem; border-radius: 50%; display: grid; place-items: center;
  font-size: .72rem; font-weight: 800; color: var(--on-brand); background: var(--accent);
}
.pulse-dot, .chip.live .pulse {
  display: inline-block; width: 8px; height: 8px; border-radius: 50%; background: var(--danger);
  margin-right: .35rem; vertical-align: middle; animation: batch-pulse 1.6s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) { .chip.live .pulse { animation: none; } }

/* --- hero ----------------------------------------------------------------- */
.hero-shot { margin: 0; }
.hero-shot img {
  width: 100%; height: auto; border-radius: var(--radius);
  border: 1px solid var(--line); box-shadow: var(--shadow); object-fit: cover;
}

/* --- next live batch ------------------------------------------------------ */
.batch-sec { padding-top: 0; padding-bottom: 0; margin-top: -1rem; }
.batch-card {
  display: grid; grid-template-columns: 1fr auto; gap: 1.5rem 2.5rem; align-items: center;
  padding: 1.6rem 1.8rem; border-radius: var(--radius);
  background: linear-gradient(120deg, color-mix(in srgb, var(--brand) 16%, var(--panel)), var(--panel));
  border: 1px solid color-mix(in srgb, var(--brand) 35%, var(--line));
  box-shadow: var(--shadow);
}
.batch-card h2 { margin: .7rem 0 .3rem; font-size: clamp(1.25rem, 2.3vw, 1.7rem); }
.batch-card .muted { margin: 0; }
.chip.live { color: var(--ink); border-color: color-mix(in srgb, var(--danger) 45%, var(--line)); font-weight: 700; }
.batch-facts {
  list-style: none; padding: 0; margin: 1.1rem 0 0;
  display: flex; flex-wrap: wrap; gap: .6rem 1.8rem;
}
.batch-facts li { display: flex; flex-direction: column; }
.batch-facts b { font-size: .7rem; letter-spacing: .09em; text-transform: uppercase; color: var(--dim); font-weight: 600; }
.batch-facts span { font-weight: 700; color: var(--ink); }
.batch-go { display: flex; flex-direction: column; gap: .6rem; align-items: stretch; }
@media (max-width: 760px) {
  .batch-card { grid-template-columns: 1fr; padding: 1.3rem; }
  .batch-sec { margin-top: 0; padding-top: 1.5rem; }
}

/* --- learning path -------------------------------------------------------- */
.path { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1rem; counter-reset: step; }
.path-step {
  position: relative; display: block; padding: 1.3rem 1.2rem 1.2rem;
  border-radius: var(--radius); background: var(--panel); border: 1px solid var(--line);
  color: inherit; text-decoration: none; transition: border-color .15s, transform .15s;
}
a.path-step:hover { border-color: var(--brand); transform: translateY(-2px); color: inherit; }
.path-step:not(:last-child)::after {
  content: '→'; position: absolute; right: -.95rem; top: 50%; transform: translateY(-50%);
  color: var(--brand); font-weight: 800; z-index: 1;
}
.path-n {
  display: inline-block; font-size: .72rem; letter-spacing: .09em; text-transform: uppercase;
  color: var(--brand); font-weight: 700; margin-bottom: .5rem;
}
.path-step h3 { font-size: 1.05rem; margin-bottom: .35rem; }
.path-step p { color: var(--ink-2); font-size: .9rem; margin: 0; }
@media (max-width: 950px) {
  .path { grid-template-columns: repeat(2, 1fr); }
  .path-step::after { display: none; }
}
@media (max-width: 560px) { .path { grid-template-columns: 1fr; } }

/* --- trainer -------------------------------------------------------------- */
.trainer { display: grid; grid-template-columns: 320px 1fr; gap: 3rem; align-items: center; }
.trainer-photo img {
  width: 100%; height: auto; aspect-ratio: 6 / 7; object-fit: cover;
  border-radius: var(--radius); border: 1px solid var(--line); box-shadow: var(--shadow);
}
.trainer-initial {
  display: grid; place-items: center; aspect-ratio: 6 / 7; border-radius: var(--radius);
  font-size: 6rem; font-weight: 800; color: var(--on-brand);
  background: linear-gradient(140deg, var(--brand), var(--accent));
}
.trainer-role { color: var(--brand); font-weight: 600; margin-top: -.2rem; }
@media (max-width: 820px) {
  .trainer { grid-template-columns: 1fr; gap: 1.6rem; }
  .trainer-photo { max-width: 280px; }
}

/* --- lab screenshots ------------------------------------------------------ */
.lab-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 1rem; }
.lab-shot { margin: 0; }
.lab-shot img {
  width: 100%; aspect-ratio: 16 / 10; object-fit: cover; display: block;
  border-radius: var(--radius-sm); border: 1px solid var(--line); transition: transform .2s;
}
.lab-shot a:hover img { transform: scale(1.02); }
.lab-shot figcaption { font-size: .86rem; color: var(--dim); margin-top: .5rem; }
@media (max-width: 900px) { .lab-grid { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 560px) { .lab-grid { grid-template-columns: 1fr; } }

/* --- testimonials --------------------------------------------------------- */
.card.quote { margin: 0; display: flex; flex-direction: column; justify-content: space-between; gap: 1.2rem; }
.card.quote blockquote { margin: 0; color: var(--ink); font-size: 1rem; line-height: 1.6; border: 0; padding: 0; }
.card.quote figcaption { display: flex; align-items: center; gap: .75rem; }
.card.quote figcaption img, .q-initial {
  width: 44px; height: 44px; border-radius: 50%; object-fit: cover; flex: 0 0 auto;
}
.q-initial {
  display: grid; place-items: center; font-weight: 800; color: var(--on-brand);
  background: linear-gradient(140deg, var(--brand), var(--accent));
}
.card.quote figcaption span { display: flex; flex-direction: column; line-height: 1.3; }
.card.quote figcaption em { font-style: normal; font-size: .84rem; color: var(--dim); }

/* --- product band on the home page, and spec tiles ------------------------ */
.band {
  display: grid; grid-template-columns: 1.3fr 1fr; gap: 2rem 3rem; align-items: center;
  padding: 2rem; border-radius: var(--radius);
  background: radial-gradient(120% 140% at 100% 0%, color-mix(in srgb, var(--accent) 16%, transparent), transparent 60%), var(--panel);
  border: 1px solid var(--line);
}
.band h2 { margin-top: .6rem; }
.band-specs { display: grid; grid-template-columns: repeat(2, 1fr); gap: .75rem; }
.band-specs > div {
  padding: .9rem 1rem; border-radius: var(--radius-sm);
  background: var(--panel-2); border: 1px solid var(--line-soft);
}
.band-specs b { display: block; font-size: 1.15rem; color: var(--ink); line-height: 1.25; }
.band-specs span { font-size: .76rem; color: var(--dim); text-transform: uppercase; letter-spacing: .07em; }
@media (max-width: 860px) { .band { grid-template-columns: 1fr; padding: 1.4rem; } }

/* --- FAQ ------------------------------------------------------------------ */
.faq {
  border: 1px solid var(--line); border-radius: var(--radius-sm); background: var(--panel);
  margin-bottom: .7rem; transition: border-color .15s;
}
.faq[open] { border-color: color-mix(in srgb, var(--brand) 45%, var(--line)); }
.faq summary {
  cursor: pointer; list-style: none; padding: 1rem 3rem 1rem 1.2rem; position: relative;
  font-weight: 600; color: var(--ink);
}
.faq summary::-webkit-details-marker { display: none; }
.faq summary::after {
  content: '+'; position: absolute; right: 1.2rem; top: 50%; transform: translateY(-50%);
  font-size: 1.3rem; color: var(--brand); transition: transform .2s;
}
.faq[open] summary::after { transform: translateY(-50%) rotate(45deg); }
.faq p { padding: 0 1.2rem 1.1rem; margin: 0; color: var(--ink-2); line-height: 1.6; }

/* --- prices and buying ---------------------------------------------------- */
.save-badge {
  display: inline-block; margin-left: .35rem; padding: .12rem .5rem; border-radius: 999px;
  font-size: .72rem; font-weight: 700; vertical-align: middle; white-space: nowrap;
  color: var(--ok); background: color-mix(in srgb, var(--ok) 14%, transparent);
  border: 1px solid color-mix(in srgb, var(--ok) 35%, transparent);
}
.price-block .save-badge { font-size: .8rem; margin-top: .35rem; margin-left: 0; display: table; }
.inc-head {
  font-size: .74rem; letter-spacing: .09em; text-transform: uppercase; color: var(--dim);
  margin: 1.1rem 0 .2rem;
}
.buy-panel .btn.wide { margin-top: .4rem; }
.hint.refund { color: var(--ok); }
.trust {
  display: flex; flex-wrap: wrap; gap: .4rem .9rem; margin: .9rem 0 .6rem;
  font-size: .8rem; color: var(--dim);
}
.trust span::before { content: '✓ '; color: var(--accent); font-weight: 800; }
.wa-btn { border-color: color-mix(in srgb, #25d366 45%, var(--line)); }
.wa-btn::before {
  content: ''; width: .6rem; height: .6rem; border-radius: 50%; background: #25d366; margin-right: .1rem;
}
.buy-panel .wa-btn { width: 100%; justify-content: center; margin-top: .3rem; }
.save { color: var(--ok); font-weight: 700; }
.os-title { font-weight: 700; color: var(--ink); font-size: 1.05rem; margin: .2rem 0 0; }
.order-summary .tick-list { font-size: .9rem; }

/* Checkout progress: 1 details, 2 payment, 3 access. */
.steps { list-style: none; padding: 0; margin: 0 0 1.4rem; display: flex; gap: .5rem; flex-wrap: wrap; }
.steps li {
  display: flex; align-items: center; gap: .5rem; padding: .35rem .85rem .35rem .4rem;
  border-radius: 999px; border: 1px solid var(--line); background: var(--panel);
  font-size: .84rem; color: var(--dim);
}
.steps b {
  width: 1.5rem; height: 1.5rem; border-radius: 50%; display: grid; place-items: center;
  font-size: .78rem; background: var(--panel-2); color: var(--ink-2);
}
.steps li.on { color: var(--ink); border-color: var(--brand); }
.steps li.on b { background: var(--brand); color: var(--on-brand); }
.steps li.done b { background: var(--ok); color: #fff; }

/* --- products page -------------------------------------------------------- */
.product-card .tick-list li { font-size: .92rem; }
.product-card.featured {
  display: grid; grid-template-columns: 1.25fr 1fr; gap: 1.5rem 2.5rem; margin-bottom: 1.4rem;
  padding: 1.8rem; border-color: color-mix(in srgb, var(--accent) 45%, var(--line));
  background: radial-gradient(120% 120% at 100% 0%, color-mix(in srgb, var(--accent) 12%, transparent), transparent 55%), var(--panel);
}
.product-card.featured h3 { font-size: clamp(1.35rem, 2.4vw, 1.8rem); margin-top: .6rem; }
.product-card.featured .pc-actions { grid-column: 1 / -1; }
.pc-side h4 {
  font-size: .74rem; letter-spacing: .09em; text-transform: uppercase; color: var(--dim);
  margin: 1.2rem 0 .6rem;
}
.pc-side .chips { display: flex; flex-wrap: wrap; gap: .4rem; }
.product-card:not(.featured) .pc-side { margin-bottom: 1rem; }
.pc-actions { margin-top: auto; }
.chip.new { color: var(--on-brand); background: var(--accent); border-color: var(--accent); font-weight: 700; }
.products-grid { margin-bottom: 1rem; }
@media (max-width: 860px) { .product-card.featured { grid-template-columns: 1fr; padding: 1.3rem; } }

/* --- admin: login hand-over after confirming a payment -------------------- */
.panel.handover { border-color: var(--ok); }
.panel.handover textarea { width: 100%; font-family: var(--mono); font-size: .85rem; }
.big-code { font-size: 1.2rem; font-weight: 700; color: var(--ok); letter-spacing: .04em; }

/* --- admin: writing toolbar ----------------------------------------------- */
.md-toolbar {
  display: flex; flex-wrap: wrap; gap: .3rem; padding: .4rem;
  background: var(--panel-2); border: 1px solid var(--line); border-bottom: 0;
  border-radius: var(--radius-sm) var(--radius-sm) 0 0;
}
.md-toolbar + textarea, .md-area { border-top-left-radius: 0 !important; border-top-right-radius: 0 !important; }
.tb-btn, .tb-sel {
  font: inherit; font-size: .82rem; padding: .32rem .6rem; border-radius: 7px; cursor: pointer;
  background: var(--panel); color: var(--ink); border: 1px solid var(--line); line-height: 1.2;
}
.tb-btn:hover, .tb-sel:hover { border-color: var(--brand); }
.tb-btn mark { background: rgba(224, 166, 58, .35); color: inherit; padding: 0 .15em; }
.tb-preview { margin-left: auto; }
.tb-btn.on { background: var(--brand); color: var(--on-brand); border-color: var(--brand); }
.md-preview {
  min-height: 12rem; max-width: none; padding: 1rem 1.2rem; background: var(--bg);
  border: 1px solid var(--line); border-radius: 0 0 var(--radius-sm) var(--radius-sm);
}
.md-preview img { max-width: 100%; }
/* On a phone the summary sits above the form (see .checkout-grid). Keep it
   to the course and the price there, so the form is not pushed off screen. */
@media (max-width: 900px) {
  .order-summary .tick-list, .order-summary .trust { display: none; }
}

@media (max-width: 640px) {
  /* Four stats in a 2 x 2 grid instead of four full-width rows. */
  .hero-stats { display: grid; grid-template-columns: 1fr 1fr; gap: .7rem; }
  .hero-stats .stat { margin: 0; }
}
/* The sticky price bar on a course page sits at the bottom of the screen on
   phones; lift the WhatsApp bubble above it so it never covers "Buy". */
@media (max-width: 950px) {
  body:has(.buy-bar) .wa-float { bottom: 96px; }
}
/* The general form rules make every select full width; not in the toolbar. */
.md-toolbar .tb-sel, .md-toolbar .tb-btn { width: auto; flex: 0 0 auto; margin: 0; min-height: 0; }
.md-toolbar .tb-sel { padding-right: 1.8rem; max-width: 8.5rem; }

/* ===========================================================================
   v2.3 - home layout polish, course cards, document library
   =========================================================================== */

/* --- hero: one slim stats row instead of four chunky tiles ---------------- */
.hero-stats { display: flex; flex-wrap: wrap; gap: 0; margin-top: 2rem; }
.hero-stats .stat {
  background: none; border: 0; box-shadow: none; border-radius: 0;
  padding: .1rem 1.4rem; margin: 0; border-left: 1px solid var(--line);
}
.hero-stats .stat:first-child { padding-left: 0; border-left: 0; }
.hero-stats .stat strong { font-size: 1.45rem; }
.hero-stats .stat span { font-size: .72rem; }
@media (max-width: 640px) {
  .hero-stats { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem 0; }
  .hero-stats .stat, .hero-stats .stat:first-child { padding: 0 .9rem; border-left: 0; }
  .hero-stats .stat:nth-child(odd) { padding-left: 0; }
  .hero-stats .stat:nth-child(even) { border-left: 1px solid var(--line); }
}

/* --- hero side card: clean rows, tag on the right ------------------------- */
.hc-rows { list-style: none; padding: 0; margin: .4rem 0 0; }
.hc-rows li {
  display: flex; align-items: center; gap: .7rem; padding: .62rem 0;
  border-bottom: 1px dashed var(--line-soft); font-size: .92rem; color: var(--ink-2);
}
.hc-rows li:last-child { border-bottom: 0; }
.hc-rows .dot { width: 8px; height: 8px; border-radius: 50%; background: var(--brand); flex: 0 0 auto; }
.hc-rows .dot.teal { background: var(--accent); }
.hc-rows .dot.amber { background: var(--warn); }
.hc-rows em {
  margin-left: auto; font-style: normal; font-size: .72rem; font-weight: 600; white-space: nowrap;
  color: var(--dim); border: 1px solid var(--line); border-radius: 999px; padding: .12rem .55rem;
}
.hero-card { backdrop-filter: blur(6px); }

/* --- "our learners work at" ----------------------------------------------- */
.logos { padding: 1.6rem 0; border-bottom: 1px solid var(--line-soft); }
.logos p {
  text-align: center; font-size: .74rem; letter-spacing: .12em; text-transform: uppercase;
  color: var(--dim); margin: 0 0 1rem;
}
.logos ul {
  list-style: none; padding: 0; margin: 0; display: flex; flex-wrap: wrap;
  justify-content: center; align-items: center; gap: 1.1rem 2.6rem;
}
.logos img { height: 30px; width: auto; opacity: .75; filter: grayscale(1); transition: opacity .15s, filter .15s; }
.logos img:hover { opacity: 1; filter: none; }
.logos span { font-weight: 800; font-size: 1.1rem; color: var(--ink-2); letter-spacing: -.01em; opacity: .8; }

/* --- course card ---------------------------------------------------------- */
.card.cc { padding: 0; overflow: hidden; display: flex; flex-direction: column; }
.cc-cover {
  position: relative; display: block; height: 118px; overflow: hidden;
  background:
    radial-gradient(120% 140% at 100% 0%, rgba(255,255,255,.16), transparent 55%),
    linear-gradient(135deg, var(--cover), color-mix(in srgb, var(--cover) 45%, #000));
}
.cc-cover.has-img { height: 150px; background: var(--panel-2); }
.cc-cover img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform .3s; }
.card.cc:hover .cc-cover img { transform: scale(1.04); }
.cc-cover .chip {
  position: absolute; left: .9rem; bottom: .8rem; font-size: .74rem; font-weight: 700;
  background: rgba(4, 12, 24, .62); color: #fff; border-color: rgba(255,255,255,.22); backdrop-filter: blur(4px);
}
.cc-body { padding: 1.05rem 1.2rem 1.2rem; display: flex; flex-direction: column; flex: 1; }
.cc-code {
  font-family: var(--mono); font-size: .72rem; letter-spacing: .06em; color: var(--dim); margin-bottom: .35rem;
}
.cc-body h3 { font-size: 1.1rem; line-height: 1.3; margin-bottom: .45rem; }
.cc-body h3 a { color: var(--ink); }
.cc-body h3 a:hover { color: var(--brand); }
.cc-body > p { color: var(--ink-2); font-size: .9rem; line-height: 1.55; margin: 0 0 .9rem;
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden; }
.cc-foot {
  margin-top: auto; display: flex; flex-wrap: wrap; align-items: center; gap: .4rem .6rem;
  padding-top: .8rem; border-top: 1px solid var(--line-soft);
}
.cc-meta { font-size: .8rem; color: var(--dim); }
.cc-foot .course-price { margin-left: auto; }

/* --- why us: four compact blocks with icons ------------------------------- */
.why-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1.2rem; }
.why { padding: .2rem 0; }
.why-ico {
  display: grid; place-items: center; width: 44px; height: 44px; border-radius: 12px; margin-bottom: .9rem;
  color: var(--brand); background: color-mix(in srgb, var(--brand) 13%, transparent);
  border: 1px solid color-mix(in srgb, var(--brand) 30%, transparent);
}
.why-tag { display: block; font-size: .7rem; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); font-weight: 700; margin-bottom: .3rem; }
.why h3 { font-size: 1.02rem; margin-bottom: .35rem; }
.why p { color: var(--ink-2); font-size: .9rem; line-height: 1.55; margin: 0; }
@media (max-width: 950px) { .why-grid { grid-template-columns: repeat(2, 1fr); gap: 1.6rem 1.2rem; } }
@media (max-width: 520px) { .why-grid { grid-template-columns: 1fr; } }

/* The batch card no longer follows a strip, so give it room under the hero. */
.batch-sec { margin-top: 0; padding-top: 0; }

/* ===========================================================================
   Document library
   =========================================================================== */
.zone-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); gap: 1rem; margin-bottom: 1.6rem; }
.zone-card {
  --zc: var(--brand);
  display: flex; flex-direction: column; gap: .35rem; padding: 1.15rem 1.2rem 1.1rem;
  border-radius: var(--radius); background: var(--panel); border: 1px solid var(--line);
  border-top: 3px solid var(--zc); color: inherit; text-decoration: none; transition: transform .15s, border-color .15s;
}
.zone-card:hover { transform: translateY(-2px); border-color: var(--zc); color: inherit; }
.zone-card strong { font-size: 1.05rem; color: var(--ink); }
.zone-icon {
  display: grid; place-items: center; width: 40px; height: 40px; border-radius: 10px; margin-bottom: .3rem;
  color: var(--zc); background: color-mix(in srgb, var(--zc) 14%, transparent);
}
.zone-count { margin-top: auto; padding-top: .5rem; font-size: .82rem; font-weight: 700; color: var(--zc); }
.zone-head { border-left: 4px solid var(--zc); padding-left: 1rem; }
.zone-dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: .5rem; vertical-align: middle; }

.doc-list { list-style: none; padding: 0; margin: 0; display: grid; gap: .6rem; }
.doc-row {
  display: flex; align-items: center; gap: 1rem; padding: .9rem 1.1rem;
  border-radius: var(--radius-sm); background: var(--panel); border: 1px solid var(--line);
  color: inherit; text-decoration: none; transition: border-color .15s;
}
.doc-row:hover { border-color: var(--brand); color: inherit; }
.doc-type {
  flex: 0 0 auto; width: 46px; height: 54px; border-radius: 7px; display: grid; place-items: center;
  font-size: .72rem; font-weight: 800; letter-spacing: .05em; color: #fff; background: #d64545;
}
.doc-type.img { background: var(--brand-2); }
.doc-main { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.doc-main strong { color: var(--ink); overflow-wrap: anywhere; }
.doc-go { margin-left: auto; font-size: .85rem; font-weight: 700; color: var(--brand); white-space: nowrap; }
@media (max-width: 520px) { .doc-go { display: none; } .doc-row { padding: .8rem; } }

/* --- the reader ----------------------------------------------------------- */
.reader {
  -webkit-user-select: none; user-select: none; -webkit-touch-callout: none;
  max-width: 980px; margin: 0 auto; padding: 0 12px;
}
.reader-bar {
  position: sticky; top: 0; z-index: 30; display: flex; align-items: center; gap: .7rem;
  padding: .6rem 0; background: var(--bg); border-bottom: 1px solid var(--line-soft);
}
.reader-title { flex: 1; min-width: 0; font-size: .98rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.reader-ctl { display: flex; align-items: center; gap: .35rem; flex: 0 0 auto; }
.reader-ctl .btn { min-width: 2.3rem; justify-content: center; }
.reader-page { font-size: .8rem; color: var(--dim); font-variant-numeric: tabular-nums; margin-right: .3rem; white-space: nowrap; }
.reader-pages { padding: 1rem 0 2rem; overflow-x: auto; -webkit-overflow-scrolling: touch; }
.rd-page {
  margin: 0 auto 14px; background: #fff; border-radius: 4px; box-shadow: 0 6px 22px rgba(0,0,0,.35);
  max-width: none; overflow: hidden;
}
.rd-page canvas { display: block; pointer-events: none; }
.reader.zoomed .rd-page { margin-left: 0; }
.reader-msg { padding: 3rem 1rem; text-align: center; color: var(--dim); display: flex; gap: .7rem; justify-content: center; align-items: center; }
.reader-msg.err { color: var(--danger); }
.reader-note { text-align: center; margin: .5rem auto 2rem; max-width: 60ch; }
.reader-msg .spinner {
  width: 20px; height: 20px; border-radius: 50%; border: 3px solid var(--line); border-top-color: var(--brand);
  animation: rd-spin .9s linear infinite;
}
@keyframes rd-spin { to { transform: rotate(360deg); } }
@media (max-width: 600px) {
  .reader { padding: 0 6px; }
  .hide-sm { display: none; }
  .rd-page { margin-bottom: 8px; border-radius: 2px; }
}
/* Printing shows nothing but a notice. */
@media print {
  .reader, .reader-note, .site-head, .site-foot { display: none !important; }
  body::after { content: "Printing is disabled for course documents."; display: block; padding: 2rem; font: 16px sans-serif; }
}

/* --- admin bits ----------------------------------------------------------- */
.doc-edit { display: flex; gap: .4rem; align-items: center; margin-bottom: .25rem; flex-wrap: wrap; }
.doc-edit input[name="title"] { flex: 1 1 200px; min-width: 0; }
.doc-edit input[name="sort_order"] { width: 5rem; flex: 0 0 auto; }
.upload-row { margin-bottom: 1rem; }
/* Four equal columns so the stats never wrap onto a ragged second line;
   long labels wrap inside their own column instead. */
.hero-stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); max-width: 600px; }
.hero-stats .stat { padding: .1rem 1rem; }
.hero-stats .stat span { display: block; line-height: 1.35; margin-top: .2rem; }
@media (max-width: 640px) { .hero-stats { grid-template-columns: 1fr 1fr; } }
/* Breathing room between the logo strip (or the hero) and the batch card. */
.batch-sec { padding-top: 1.8rem; }
