/* Options course portal.
   Standalone: the sales page borrows the analyst design system, but the portal
   is a working surface and needs its own layout, so nothing here depends on
   program.css or the #ao-gate scope. */

:root {
  --oc-ink: #0a0303;
  --oc-ink-2: #120606;
  --oc-surface: rgba(255,255,255,.045);
  --oc-line: rgba(255,255,255,.12);
  --oc-line-soft: rgba(255,255,255,.07);
  --oc-red: #ae1f19;
  --oc-red-br: #e8635a;
  --oc-text: #f7f2f1;
  --oc-muted: #b6a5a2;
  --oc-r: 16px;
}

body.oc-portal-body { background: var(--oc-ink); color: var(--oc-text); }

.ocp {
  max-width: 1320px; margin: 0 auto; padding: 22px 18px 90px;
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

/* ── banners ─────────────────────────────────────────────────────────── */
.ocp-note {
  display: flex; gap: 12px; align-items: center; flex-wrap: wrap;
  border: 1px solid var(--oc-line); background: var(--oc-surface);
  border-radius: 12px; padding: 12px 16px; margin-bottom: 18px;
  font-size: .86rem; color: var(--oc-muted);
}
.ocp-note b { color: #fff; font-weight: 650; }
.ocp-note--warn { border-color: rgba(232,99,90,.42); background: rgba(232,99,90,.10); }
.ocp-note--preview { border-color: rgba(212,167,44,.5); background: rgba(212,167,44,.12); color: #f0dfae; }
.ocp-note--preview b { color: #ffe9ad; }

/* ── header ──────────────────────────────────────────────────────────── */
.ocp-head {
  display: flex; justify-content: space-between; align-items: flex-end;
  gap: 20px; flex-wrap: wrap; margin-bottom: 20px;
}
.ocp-head h1 { font-size: 1.5rem; font-weight: 800; margin: 0; letter-spacing: -.02em; }
.ocp-head p { margin: 5px 0 0; font-size: .85rem; color: var(--oc-muted); }
.ocp-me { display: flex; align-items: center; gap: 12px; font-size: .82rem; color: var(--oc-muted); }
.ocp-me b { color: #fff; font-weight: 600; }
.ocp-chip {
  border: 1px solid var(--oc-line); border-radius: 999px; padding: 5px 12px;
  font-size: .74rem; color: var(--oc-muted); white-space: nowrap;
}
.ocp-chip--ok { border-color: rgba(120,200,150,.4); color: #a9e2c0; background: rgba(120,200,150,.10); }

/* ── main grid ───────────────────────────────────────────────────────── */
.ocp-grid { display: grid; grid-template-columns: 1fr 322px; gap: 22px; align-items: start; }

.ocp-stage { min-width: 0; }
.ocp-video {
  position: relative; aspect-ratio: 16/9; width: 100%; background: #000;
  border: 1px solid var(--oc-line); border-radius: var(--oc-r); overflow: hidden;
}
.ocp-video iframe, .ocp-video video { width: 100%; height: 100%; border: 0; display: block; }
.ocp-video__ph {
  position: absolute; inset: 0; display: grid; place-items: center; text-align: center;
  padding: 26px; background-size: cover; background-position: center;
}
.ocp-video__ph::before { content: ""; position: absolute; inset: 0; background: rgba(6,2,2,.74); }
.ocp-video__ph > div { position: relative; max-width: 44ch; }
.ocp-video__ph b { display: block; color: #fff; font-size: 1.02rem; margin-bottom: 8px; }
.ocp-video__ph span { font-size: .85rem; color: var(--oc-muted); line-height: 1.6; }

/* per-viewer watermark, pinned to the top-left corner of the player. */
.ocp-wm {
  position: absolute; z-index: 5; pointer-events: none; user-select: none;
  top: 10px; left: 14px;
  font-size: .68rem; color: rgba(255,255,255,.30); letter-spacing: .04em;
  text-shadow: 0 1px 3px rgba(0,0,0,.6);
}

.ocp-bar {
  display: flex; align-items: center; gap: 14px; flex-wrap: wrap;
  margin-top: 12px; padding: 11px 14px;
  border: 1px solid var(--oc-line); border-radius: 12px; background: var(--oc-surface);
}
.ocp-bar__t { font-size: .84rem; color: var(--oc-muted); }
.ocp-bar__t b { color: #fff; font-weight: 600; }
.ocp-toggle { display: flex; align-items: center; gap: 9px; margin-left: auto; cursor: pointer; font-size: .8rem; color: var(--oc-muted); }
.ocp-toggle input { appearance: none; width: 38px; height: 21px; border-radius: 999px; background: rgba(255,255,255,.14); position: relative; cursor: pointer; transition: background .25s; }
.ocp-toggle input::after { content: ""; position: absolute; top: 3px; left: 3px; width: 15px; height: 15px; border-radius: 50%; background: #fff; transition: transform .25s; }
.ocp-toggle input:checked { background: var(--oc-red); }
.ocp-toggle input:checked::after { transform: translateX(17px); }

/* ── slide track ─────────────────────────────────────────────────────── */
.ocp-slidewrap { margin-top: 18px; }
.ocp-slide {
  position: relative; border: 1px solid var(--oc-line); border-radius: var(--oc-r);
  overflow: hidden; background: #08090b;
}
.ocp-slide img { width: 100%; display: block; }
.ocp-slide__n {
  position: absolute; right: 12px; bottom: 12px; background: rgba(0,0,0,.66);
  border: 1px solid var(--oc-line); border-radius: 999px; padding: 4px 11px;
  font-size: .74rem; color: #fff; font-variant-numeric: tabular-nums;
}
.ocp-film {
  display: flex; gap: 9px; overflow-x: auto; padding: 12px 2px 4px;
  scrollbar-width: thin; scrollbar-color: rgba(255,255,255,.2) transparent;
}
.ocp-film::-webkit-scrollbar { height: 7px; }
.ocp-film::-webkit-scrollbar-thumb { background: rgba(255,255,255,.18); border-radius: 4px; }
.ocp-film img {
  height: 58px; width: auto; border-radius: 5px; cursor: pointer; flex: 0 0 auto;
  border: 2px solid transparent; opacity: .48; transition: opacity .2s, border-color .2s, transform .2s;
}
.ocp-film img:hover { opacity: .85; transform: translateY(-2px); }
.ocp-film img.on { opacity: 1; border-color: var(--oc-red-br); }

/* ── rail ────────────────────────────────────────────────────────────── */
.ocp-rail { position: sticky; top: 16px; display: grid; gap: 16px; }
.ocp-card {
  border: 1px solid var(--oc-line); border-radius: var(--oc-r);
  background: var(--oc-surface); overflow: hidden;
}
.ocp-card__h {
  padding: 13px 16px; border-bottom: 1px solid var(--oc-line-soft);
  font-size: .72rem; font-weight: 800; letter-spacing: .16em; text-transform: uppercase; color: var(--oc-red-br);
}
.ocp-chaps { max-height: 60vh; overflow-y: auto; }
.ocp-part { border-bottom: 1px solid var(--oc-line-soft); }
.ocp-part__h {
  padding: 11px 16px 7px; font-size: .78rem; font-weight: 700; color: #fff;
  display: flex; justify-content: space-between; gap: 10px;
}
.ocp-part__h span { color: var(--oc-muted); font-weight: 400; font-variant-numeric: tabular-nums; }
.ocp-ch {
  display: grid; grid-template-columns: 62px 1fr; gap: 9px; align-items: baseline;
  padding: 6px 16px; cursor: pointer; font-size: .81rem; color: #ddd2d0;
  border-left: 2px solid transparent;
}
.ocp-ch:hover { background: rgba(255,255,255,.05); }
.ocp-ch.on { background: rgba(232,99,90,.13); border-left-color: var(--oc-red-br); color: #fff; }
.ocp-ch time { font-variant-numeric: tabular-nums; font-size: .74rem; color: var(--oc-red-br); }

.ocp-res { padding: 14px 16px; display: grid; gap: 10px; }
.ocp-dl {
  display: flex; align-items: center; gap: 12px; width: 100%; text-align: left;
  border: 1px solid var(--oc-line); border-radius: 11px; background: rgba(255,255,255,.03);
  padding: 11px 13px; cursor: pointer; color: inherit; font: inherit;
  transition: border-color .25s, transform .25s, background .25s;
}
.ocp-dl:hover:not(:disabled) { border-color: rgba(232,99,90,.42); transform: translateY(-2px); background: rgba(255,255,255,.06); }
.ocp-dl:disabled { opacity: .5; cursor: not-allowed; }
.ocp-dl__ic { width: 30px; height: 30px; flex: 0 0 auto; display: grid; place-items: center; border-radius: 7px; background: rgba(232,99,90,.14); color: var(--oc-red-br); }
.ocp-dl b { display: block; font-size: .84rem; color: #fff; font-weight: 650; }
.ocp-dl span { display: block; font-size: .74rem; color: var(--oc-muted); margin-top: 1px; }

.ocp-cert { padding: 14px 16px; }
.ocp-cert img { width: 100%; border-radius: 8px; display: block; border: 1px solid var(--oc-line); }
.ocp-cert p { font-size: .78rem; color: var(--oc-muted); line-height: 1.55; margin: 11px 0 0; }
.ocp-prog { height: 5px; border-radius: 999px; background: var(--oc-line); overflow: hidden; margin-top: 10px; }
.ocp-prog i { display: block; height: 100%; background: var(--oc-red-br); width: 0; transition: width .4s; }

/* ── gate ────────────────────────────────────────────────────────────── */
.ocp-gate { max-width: 560px; margin: 8vh auto; text-align: center; padding: 0 18px; }
.ocp-gate h2 { font-size: 1.6rem; margin: 0 0 10px; }
.ocp-gate p { color: var(--oc-muted); line-height: 1.65; font-size: .93rem; margin: 0 0 20px; }
.ocp-btn {
  display: inline-block; border: 0; border-radius: 999px; padding: 13px 26px;
  font-weight: 700; font-size: .95rem; cursor: pointer; text-decoration: none;
  background: var(--oc-red); color: #fff; transition: background .2s, transform .2s;
}
.ocp-btn:hover { background: #c4241d; transform: translateY(-2px); }
.ocp-btn--ghost { background: transparent; border: 1px solid var(--oc-line); color: var(--oc-text); }
.ocp-terms {
  text-align: left; border: 1px solid var(--oc-line); border-radius: 12px;
  background: var(--oc-surface); padding: 18px 20px; margin: 0 0 18px;
}
.ocp-terms label { display: flex; gap: 11px; align-items: flex-start; font-size: .85rem; line-height: 1.6; color: #ddd2d0; margin-bottom: 12px; cursor: pointer; }
.ocp-terms input { margin-top: 3px; flex: 0 0 auto; accent-color: var(--oc-red); width: 16px; height: 16px; }
.ocp-terms .fine { font-size: .76rem; color: var(--oc-muted); line-height: 1.6; border-top: 1px solid var(--oc-line-soft); padding-top: 12px; margin: 4px 0 0; }

@media (max-width: 1040px) {
  .ocp-grid { grid-template-columns: 1fr; }
  .ocp-rail { position: static; }
  .ocp-chaps { max-height: none; }
}

/* ── quiz overlay ────────────────────────────────────────────────────────
   Sits over the player and pauses it. The course assumes this exists: Sven
   waits, and Vincent says on tape that the answer appears on screen. */
/* Screen-level, not player-level. Fixed rather than absolute so it covers the
   viewport whether the stage is inline or full screen, and so it never inherits
   a small floating player's box. */
.ocp-quiz {
  position: fixed; inset: 0; z-index: 80; display: grid; place-items: center;
  padding: 22px; background: rgba(6,2,2,.93); backdrop-filter: blur(8px);
  animation: ocp-fade .28s ease;
}
@keyframes ocp-fade { from { opacity: 0; } to { opacity: 1; } }
.ocp-quiz__box { width: 100%; max-width: 620px; }
.ocp-quiz__k {
  display: flex; justify-content: space-between; gap: 12px; margin: 0 0 10px;
  font-size: .7rem; font-weight: 800; letter-spacing: .16em; text-transform: uppercase;
  color: var(--oc-red-br);
}
.ocp-quiz__k em { font-style: normal; color: var(--oc-muted); letter-spacing: .1em; }
.ocp-quiz h3 { font-size: 1.12rem; line-height: 1.45; color: #fff; margin: 0 0 16px; font-weight: 650; }
.ocp-quiz__opts { display: grid; gap: 8px; }
.ocp-quiz__opt {
  display: flex; gap: 11px; align-items: flex-start; width: 100%; text-align: left;
  border: 1px solid var(--oc-line); border-radius: 11px; background: rgba(255,255,255,.04);
  color: #e7dcda; font: inherit; font-size: .9rem; line-height: 1.45; padding: 12px 14px;
  cursor: pointer; transition: border-color .2s, background .2s, transform .2s;
}
.ocp-quiz__opt:hover:not(:disabled) { border-color: rgba(232,99,90,.5); background: rgba(255,255,255,.07); transform: translateX(2px); }
.ocp-quiz__opt:disabled { cursor: default; }
.ocp-quiz__opt i {
  flex: 0 0 auto; width: 21px; height: 21px; border-radius: 50%; display: grid; place-items: center;
  border: 1px solid var(--oc-line); font-style: normal; font-size: .7rem; font-weight: 800; color: var(--oc-muted);
}
.ocp-quiz__opt.right { border-color: rgba(120,200,150,.6); background: rgba(120,200,150,.13); color: #d8f3e3; }
.ocp-quiz__opt.right i { border-color: rgba(120,200,150,.7); color: #a9e2c0; }
.ocp-quiz__opt.wrong { border-color: rgba(232,99,90,.6); background: rgba(232,99,90,.12); color: #f6d7d4; }
.ocp-quiz__opt.wrong i { border-color: rgba(232,99,90,.7); color: var(--oc-red-br); }
.ocp-quiz__why {
  margin-top: 14px; padding: 13px 15px; border-radius: 11px;
  border: 1px solid var(--oc-line-soft); background: rgba(255,255,255,.04);
  font-size: .87rem; line-height: 1.6; color: #ddd2d0;
}
.ocp-quiz__act { display: flex; gap: 10px; justify-content: flex-end; margin-top: 16px; }
.ocp-quiz__act .ocp-btn { padding: 10px 20px; font-size: .86rem; }

.ocp-score {
  display: flex; align-items: center; gap: 8px; font-size: .74rem; color: var(--oc-muted);
}
.ocp-score b { color: var(--oc-text); font-weight: 700; }

@media (max-width: 700px) {
  .ocp-quiz { padding: 14px; }
  .ocp-quiz h3 { font-size: .98rem; }
  .ocp-quiz__opt { font-size: .84rem; padding: 10px 12px; }
}

/* ── quiz countdown ──────────────────────────────────────────────────────
   20 seconds, shown as a draining ring. Hitting zero does not lock anything;
   it turns amber and the answer is simply logged as over time. */
.ocp-quiz__box { position: relative; }
.ocp-timer {
  position: absolute; top: -6px; right: 0; width: 46px; height: 46px;
  display: grid; place-items: center;
}
.ocp-timer svg { position: absolute; inset: 0; width: 100%; height: 100%; transform: rotate(-90deg); }
.ocp-timer circle { fill: none; stroke-width: 3; }
.ocp-timer .bg { stroke: rgba(255,255,255,.12); }
.ocp-timer .fg {
  stroke: var(--oc-red-br); stroke-linecap: round;
  stroke-dasharray: 106.8; stroke-dashoffset: 0;
  transition: stroke-dashoffset .1s linear, stroke .3s ease;
}
.ocp-timer b {
  position: relative; font-size: .78rem; font-weight: 800; color: #fff;
  font-variant-numeric: tabular-nums;
}
.ocp-timer.warn .fg { stroke: #e0a53a; }
.ocp-timer.over .fg { stroke: #7a6a52; stroke-dashoffset: 106.8; }
.ocp-timer.over b { font-size: .58rem; color: #d9c79a; letter-spacing: .06em; text-transform: uppercase; }
.ocp-timer.done { opacity: .35; }
@media (max-width: 700px) { .ocp-timer { width: 38px; height: 38px; top: -4px; } }

/* A build stage that is not the first of its slide sits slightly lower and
   narrower, so 253 frames still read as grouped slides rather than one long
   undifferentiated run. */
.ocp-film img.sub { height: 48px; align-self: flex-end; opacity: .34; }
.ocp-film img.sub:hover { opacity: .8; }
.ocp-film img.sub.on { opacity: 1; }
.ocp-film { align-items: flex-start; }

/* ── slide arrows ────────────────────────────────────────────────────────
   Primary way to move through the deck. Each press is one build stage, and it
   seeks the video with it so the panel and the player never drift apart.
   Arrow keys do the same, unless a quiz is open. */
.ocp-slide { position: relative; }
.ocp-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 46px; height: 46px; border-radius: 50%; display: grid; place-items: center;
  background: rgba(10,4,4,.66); border: 1px solid var(--oc-line); color: #fff;
  cursor: pointer; opacity: 0; transition: opacity .25s, background .25s, transform .25s;
  backdrop-filter: blur(6px); z-index: 3;
}
.ocp-slide:hover .ocp-nav, .ocp-nav:focus-visible { opacity: 1; }
.ocp-nav:hover { background: var(--oc-red); border-color: var(--oc-red); }
.ocp-nav--prev { left: 14px; }
.ocp-nav--next { right: 14px; }
.ocp-nav--prev:hover { transform: translateY(-50%) translateX(-3px); }
.ocp-nav--next:hover { transform: translateY(-50%) translateX(3px); }
@media (hover: none) { .ocp-nav { opacity: .85; } }

/* ── certificate requirements ───────────────────────────────────────────
   Watching is not completing. The certificate says "successful completion",
   so it needs the quizzes too, and the list says so up front. */
.ocp-req { list-style: none; margin: 12px 0 0; padding: 0; display: grid; gap: 7px; }
.ocp-req li {
  display: grid; grid-template-columns: 18px 1fr auto; gap: 9px; align-items: center;
  font-size: .78rem; color: var(--oc-muted);
}
.ocp-req i {
  width: 16px; height: 16px; border-radius: 50%; display: grid; place-items: center;
  border: 1px solid var(--oc-line); font-style: normal; font-size: .6rem; color: transparent;
}
.ocp-req li.ok { color: #cfe8da; }
.ocp-req li.ok i { border-color: rgba(120,200,150,.65); background: rgba(120,200,150,.16); color: #a9e2c0; }
.ocp-req b { font-variant-numeric: tabular-nums; font-weight: 700; color: #fff; font-size: .75rem; }
.ocp-req li.ok b { color: #a9e2c0; }

/* ── quiz header spacing + timer ─────────────────────────────────────────
   The counter was running underneath the absolutely-positioned timer ring, and
   "over" never fitted inside a 46px circle. Counter is a small pill kept clear
   of the ring; expiry just greys the ring and shows 0. */
.ocp-quiz__k { padding-right: 62px; align-items: center; }
.ocp-quiz__k em {
  font-style: normal; font-size: .64rem; font-weight: 700; letter-spacing: .1em;
  color: var(--oc-muted); background: var(--oc-surface);
  border: 1px solid var(--oc-line); border-radius: 999px; padding: 3px 9px; white-space: nowrap;
}
.ocp-quiz h3 { padding-right: 56px; }
.ocp-timer.over b { font-size: .78rem; color: #8d7f6a; letter-spacing: 0; text-transform: none; }
.ocp-timer.over .fg { stroke: rgba(255,255,255,.14); stroke-dashoffset: 0; }

/* ── view settings ──────────────────────────────────────────────────────── */
.ocp-viewbtn {
  display: inline-flex; align-items: center; gap: 7px; margin-left: 14px;
  border: 1px solid var(--oc-line); background: rgba(255,255,255,.04); color: var(--oc-muted);
  border-radius: 999px; padding: 7px 13px; font: inherit; font-size: .78rem; cursor: pointer;
  transition: border-color .2s, color .2s, background .2s;
}
.ocp-viewbtn:hover, .ocp-viewbtn.on { color: #fff; border-color: rgba(232,99,90,.5); background: rgba(232,99,90,.12); }

.ocp-view {
  margin-top: 10px; padding: 16px 18px; display: grid; gap: 16px;
  border: 1px solid var(--oc-line); border-radius: 14px; background: rgba(255,255,255,.045);
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
}
.ocp-view__h {
  margin: 0 0 8px; font-size: .66rem; font-weight: 800; letter-spacing: .16em;
  text-transform: uppercase; color: var(--oc-red-br);
}
.ocp-view__opts { display: flex; gap: 7px; flex-wrap: wrap; }
.ocp-view__note { margin: 9px 0 0; font-size: .68rem; line-height: 1.4; color: var(--oc-muted); opacity: .85; }
.ocp-view__opts button {
  display: grid; justify-items: center; gap: 5px; padding: 9px 11px;
  border: 1px solid var(--oc-line); border-radius: 10px; background: rgba(255,255,255,.03);
  color: var(--oc-muted); font: inherit; font-size: .7rem; cursor: pointer;
  transition: border-color .2s, color .2s, background .2s, transform .2s;
}
.ocp-view__opts button:hover { transform: translateY(-2px); color: #fff; }
.ocp-view__opts button.on { border-color: var(--oc-red-br); color: #fff; background: rgba(232,99,90,.14); }
.ocp-view__reset {
  grid-column: 1 / -1; justify-self: start; border: 0; background: none; padding: 0;
  color: var(--oc-muted); font: inherit; font-size: .74rem; cursor: pointer; text-decoration: underline;
}
.ocp-view__reset:hover { color: #fff; }

/* little diagrams on each option */
.lay { width: 30px; height: 20px; border: 1px solid currentColor; border-radius: 3px; position: relative; opacity: .75; }
.lay::before, .lay::after { content: ""; position: absolute; background: currentColor; opacity: .55; }
.lay--stack::before { left: 2px; right: 2px; top: 2px; height: 7px; }
.lay--stack::after  { left: 2px; right: 2px; bottom: 2px; height: 5px; }
.lay--split::before { left: 2px; top: 2px; bottom: 2px; width: 12px; }
.lay--split::after  { right: 2px; top: 2px; bottom: 2px; width: 12px; opacity: .3; }
.lay--slides::before { left: 2px; right: 2px; top: 2px; bottom: 2px; opacity: .3; }
.lay--slides::after  { right: 3px; bottom: 3px; width: 11px; height: 7px; }
.lay--video::before { left: 2px; right: 2px; top: 2px; bottom: 2px; }
.lay--video::after  { display: none; }
.lay--l::before { left: 2px; top: 2px; bottom: 2px; width: 10px; }
.lay--l::after  { display: none; }
.lay--r::before { right: 2px; top: 2px; bottom: 2px; width: 10px; }
.lay--r::after  { display: none; }
.lay--off::before, .lay--off::after { display: none; }
.lay--below::before { left: 2px; right: 2px; top: 2px; height: 9px; opacity: .3; }
.lay--below::after  { left: 2px; right: 2px; bottom: 2px; height: 4px; }

/* ── layouts ────────────────────────────────────────────────────────────── */
.ocp-grid[data-rail="left"]  { grid-template-columns: 322px 1fr; }
.ocp-grid[data-rail="left"] .ocp-rail  { order: -1; }
.ocp-grid[data-rail="off"]   { grid-template-columns: 1fr; }
.ocp-grid[data-rail="off"] .ocp-rail   { display: none; }

/* side by side: video and slides share one row, controls span underneath.
   Explicit areas, because mixing grid-row with spanning children left the
   auto-placement to guess and it guessed wrong.
   The row is the whole point of this arrangement, so three things give way to
   it (Sven's feedback, Sep 2026: both panes came out at 463px on a laptop,
   because the 1320px page cap, the 322px rail and a 50/50 split all took
   their cut first). The page cap lifts to 1800px, the chapters leave the side
   and sit under the stage as a strip, and the slide takes the larger share of
   the row: the video is a talking head, the slide carries the content. */
#ocp-course[data-layout="split"] { max-width: 1800px; }
.ocp-grid[data-layout="split"] { grid-template-columns: 1fr; }
.ocp-grid[data-layout="split"] .ocp-stage {
  display: grid; gap: 14px; align-items: start;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1.5fr);
  /* The slide is taller than the video now and spans both rows. With two
     auto rows the surplus is shared between them and the timeline floats
     away from the player; the 1fr second row takes all of it instead. */
  grid-template-rows: auto 1fr auto auto;
  grid-template-areas: "video slides" "tl slides" "bar bar" "view view";
}
/* The timeline had no place in this template, so it auto-placed into an
   implicit row below the bar: full-width controls, then a stray scrubber under
   them. It belongs directly beneath the player, matching its width. */
.ocp-grid[data-layout="split"] .ocp-tl { grid-area: tl; margin-top: 12px; align-self: start; }
.ocp-grid[data-layout="split"] .ocp-video     { grid-area: video; }
.ocp-grid[data-layout="split"] .ocp-slidewrap { grid-area: slides; margin-top: 0; min-width: 0; }
.ocp-grid[data-layout="split"] .ocp-bar       { grid-area: bar; margin-top: 0; }
.ocp-grid[data-layout="split"] .ocp-view      { grid-area: view; margin-top: 0; }
.ocp-grid[data-layout="split"][data-side="right"] .ocp-stage {
  grid-template-columns: minmax(0, 1.5fr) minmax(0, 1fr);
  grid-template-rows: auto 1fr auto auto;
  grid-template-areas: "slides video" "slides tl" "bar bar" "view view";
}
/* Chapters strip under the stage. The parts become columns, so the list runs
   as wide as the row instead of one long scrolling column. Left and Right
   both land here (the View panel shows a single "Below" for them); Hidden
   still hides. Later in the file than the data-rail rules on purpose, so it
   wins the tie on specificity. */
.ocp-grid[data-layout="split"] .ocp-rail { order: 1; position: static; top: auto; }
.ocp-grid[data-layout="split"] .ocp-chaps {
  max-height: none; overflow: visible; display: grid;
  grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
}
.ocp-grid[data-layout="split"] .ocp-part { border-bottom: 0; border-right: 1px solid var(--oc-line-soft); }
.ocp-grid[data-layout="split"] .ocp-part:last-child { border-right: 0; }

/* slides first: the video shrinks into a corner over the slide, clear of the
   filmstrip so it never covers the thumbnails. */
.ocp-grid[data-layout="slides"] .ocp-stage {
  position: relative; display: grid; gap: 0;
  grid-template-columns: minmax(0, 1fr);
  grid-template-areas: "slides" "tl" "bar" "view";
}
.ocp-grid[data-layout="slides"] .ocp-slidewrap { grid-area: slides; }
.ocp-grid[data-layout="slides"] .ocp-tl        { grid-area: tl; }
.ocp-grid[data-layout="slides"] .ocp-bar       { grid-area: bar; }
.ocp-grid[data-layout="slides"] .ocp-view      { grid-area: view; }
.ocp-grid[data-layout="slides"] .ocp-video {
  position: absolute; top: 14px; width: 28%; min-width: 210px; max-width: 340px; z-index: 6;
  box-shadow: 0 18px 44px rgba(0,0,0,.62);
}
.ocp-grid[data-layout="slides"][data-side="left"]  .ocp-video { left: 14px; }
.ocp-grid[data-layout="slides"][data-side="right"] .ocp-video { right: 14px; }
.ocp-grid[data-layout="slides"] .ocp-slidewrap { margin-top: 0; }
.ocp-grid[data-layout="slides"] .ocp-bar { margin-top: 12px; }

/* video only */
.ocp-grid[data-layout="video"] .ocp-slidewrap { display: none; }
.ocp-grid[data-layout="video"] .ocp-bar .ocp-toggle { display: none; }

@media (max-width: 1040px) {
  .ocp-grid[data-rail="left"] { grid-template-columns: 1fr; }
  /* No room for two columns: the split stacks. Both side variants are named,
     because the data-side rule above carries its own column template now and
     would outrank a bare selector here. */
  .ocp-grid[data-layout="split"] .ocp-stage,
  .ocp-grid[data-layout="split"][data-side="right"] .ocp-stage {
    grid-template-columns: 1fr; grid-template-rows: auto;
    grid-template-areas: "video" "tl" "slides" "bar" "view";
  }
  .ocp-grid[data-layout="slides"] .ocp-video { position: static; width: 100%; }
}

/* ══════════════════════════════════════════════════════════ light theme ═══
   The portal is dark because it sits under a video. Some people read slides
   better on a light ground, so the whole palette flips off one attribute.
   Only the hard-coded colours need restating; everything else is a token. */
[data-theme="light"] {
  --oc-ink: #f7f4f2;
  --oc-ink-2: #fff;
  --oc-surface: rgba(20,5,3,.035);
  --oc-line: rgba(20,5,3,.14);
  --oc-line-soft: rgba(20,5,3,.07);
  --oc-red: #ae1f19;
  --oc-red-br: #ae1f19;
  --oc-text: #191110;
  --oc-muted: #6d605d;
}
[data-theme="light"] .ocp-note b,
[data-theme="light"] .ocp-head h1,
[data-theme="light"] .ocp-me b,
[data-theme="light"] .ocp-bar__t b,
[data-theme="light"] .ocp-part__h,
[data-theme="light"] .ocp-part__t,
[data-theme="light"] .ocp-ch.on,
[data-theme="light"] .ocp-dl b,
[data-theme="light"] .ocp-gate h2,
[data-theme="light"] .ocp-req b,
[data-theme="light"] .ocp-viewbtn:hover,
[data-theme="light"] .ocp-viewbtn.on,
[data-theme="light"] .ocp-view__opts button:hover,
[data-theme="light"] .ocp-view__opts button.on,
[data-theme="light"] .ocp-view__reset:hover { color: var(--oc-text); }

[data-theme="light"] .ocp-ch { color: #4a403e; }
[data-theme="light"] .ocp-ch:hover { background: rgba(20,5,3,.05); }
[data-theme="light"] .ocp-ch.on { background: rgba(174,31,25,.10); }
[data-theme="light"] .ocp-terms label { color: #3f3634; }
[data-theme="light"] .ocp-req li.ok { color: #2f6b48; }
[data-theme="light"] .ocp-req li.ok i { background: rgba(46,140,90,.14); color: #2f6b48; border-color: rgba(46,140,90,.45); }
[data-theme="light"] .ocp-req li.ok b { color: #2f6b48; }
[data-theme="light"] .ocp-chip--ok { color: #2f6b48; border-color: rgba(46,140,90,.4); background: rgba(46,140,90,.10); }

/* the slide panel keeps a light ground either way, but loses the black box */
[data-theme="light"] .ocp-slide { background: #fff; }
[data-theme="light"] .ocp-film img { opacity: .6; }
[data-theme="light"] .ocp-film img.on { opacity: 1; }
[data-theme="light"] .ocp-nav { background: rgba(255,255,255,.9); color: #191110; }
[data-theme="light"] .ocp-nav:hover { background: var(--oc-red); color: #fff; }
[data-theme="light"] .ocp-slide__n { background: rgba(255,255,255,.88); color: #191110; }

/* quiz stays high contrast: it is an overlay on video either way */
[data-theme="light"] .ocp-quiz { background: rgba(247,244,242,.94); }
[data-theme="light"] .ocp-quiz h3 { color: var(--oc-text); }
[data-theme="light"] .ocp-quiz__opt { color: #3f3634; background: #fff; }
[data-theme="light"] .ocp-quiz__opt.right { background: rgba(46,140,90,.12); color: #235c3c; border-color: rgba(46,140,90,.5); }
[data-theme="light"] .ocp-quiz__opt.wrong { background: rgba(174,31,25,.10); color: #8e1814; border-color: rgba(174,31,25,.45); }
[data-theme="light"] .ocp-quiz__why { background: #fff; color: #3f3634; }
[data-theme="light"] .ocp-timer b { color: var(--oc-text); }
[data-theme="light"] .ocp-timer .bg { stroke: rgba(20,5,3,.12); }

[data-theme="light"] .ocp-btn--ghost { color: var(--oc-text); }
[data-theme="light"] .ocp-cert img { border-color: var(--oc-line); }
.lay--dark  { background: #14100f; border-color: rgba(255,255,255,.35); }
.lay--dark::before, .lay--dark::after { display: none; }
.lay--light { background: #fff; border-color: rgba(20,5,3,.35); }
.lay--light::before, .lay--light::after { display: none; }
.ocp-part__t { padding: 0 16px 6px; font-size: .8rem; color: var(--oc-text); font-weight: 600; }

/* ── draggable floating video ────────────────────────────────────────────
   In "Slides first" the player floats over the slide, and wherever it starts it
   will be in someone's way. The handle is a separate strip because an iframe
   eats pointer events, so the player itself cannot be a drag target. */
.ocp-drag { display: none; }
.ocp-grid[data-layout="slides"] .ocp-drag {
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
  position: absolute; top: 0; left: 0; right: 0; height: 26px; z-index: 8;
  padding: 0 8px; cursor: grab; touch-action: none;
  background: linear-gradient(rgba(8,3,3,.86), rgba(8,3,3,0));
  opacity: 0; transition: opacity .2s;
}
.ocp-grid[data-layout="slides"] .ocp-video:hover .ocp-drag,
.ocp-grid[data-layout="slides"] .ocp-drag.dragging { opacity: 1; }
.ocp-drag.dragging { cursor: grabbing; }
.ocp-drag__grip {
  width: 34px; height: 4px; border-radius: 2px; background: rgba(255,255,255,.5);
  margin: 0 auto;
}
.ocp-drag__reset {
  border: 0; background: rgba(255,255,255,.14); color: #fff; font: inherit;
  font-size: .64rem; padding: 3px 8px; border-radius: 5px; cursor: pointer;
}
.ocp-drag__reset:hover { background: rgba(255,255,255,.28); }
.ocp-grid[data-layout="slides"] .ocp-video { cursor: default; }

/* ══════════════════════════════════════════════════════════ timeline ═══
   The whole 3h32m in one bar: parts as alternating bands, chapters as ticks,
   quizzes as red markers, watched progress filled. Click to seek. */
.ocp-tl { position: relative; margin-top: 12px; user-select: none; }
.ocp-tl__track {
  position: relative; height: 30px; border-radius: 8px; overflow: hidden;
  border: 1px solid var(--oc-line); background: var(--oc-surface); cursor: pointer;
}
.ocp-tl__part {
  position: absolute; top: 0; bottom: 0;
  border-right: 1px solid rgba(255,255,255,.16);
}
.ocp-tl__part:nth-child(odd)  { background: rgba(255,255,255,.045); }
.ocp-tl__part:nth-child(even) { background: rgba(255,255,255,.015); }
.ocp-tl__part:last-of-type { border-right: 0; }
.ocp-tl__part span {
  position: absolute; left: 7px; top: 50%; transform: translateY(-50%);
  font-size: .64rem; font-weight: 700; letter-spacing: .06em; text-transform: uppercase;
  color: var(--oc-muted); white-space: nowrap; pointer-events: none;
}
.ocp-tl__ch {
  position: absolute; top: 0; bottom: 0; width: 1px;
  background: rgba(255,255,255,.22); pointer-events: none;
}
.ocp-tl__q {
  position: absolute; top: 4px; width: 3px; height: 22px; border-radius: 2px;
  background: var(--oc-red-br); box-shadow: 0 0 6px rgba(232,99,90,.7);
  pointer-events: none;
}
.ocp-tl__prog {
  position: absolute; top: 0; bottom: 0; left: 0; width: 0;
  background: rgba(232,99,90,.20); border-right: 1px solid rgba(232,99,90,.5);
  pointer-events: none; transition: width .25s linear;
}
.ocp-tl__head {
  position: absolute; top: -3px; width: 2px; height: calc(100% + 6px);
  background: #fff; box-shadow: 0 0 8px rgba(255,255,255,.8);
  pointer-events: none; transition: left .25s linear;
}
.ocp-tl__foot { display: flex; align-items: center; gap: 14px; margin-top: 5px; }
.ocp-tl__labels {
  display: flex; justify-content: space-between; flex: 1 1 auto; min-width: 0;
  font-size: .68rem; color: var(--oc-muted); font-variant-numeric: tabular-nums;
}
.ocp-tl__zoom { display: flex; align-items: center; gap: 5px; flex: 0 0 auto; }
.ocp-tl__zoom button {
  border: 1px solid var(--oc-line); background: rgba(255,255,255,.04);
  color: var(--oc-muted); border-radius: 7px; padding: 2px 8px; min-width: 24px;
  font: inherit; font-size: .7rem; line-height: 1.5; cursor: pointer;
  transition: color .2s, border-color .2s, background .2s;
}
.ocp-tl__zoom button:hover { color: #fff; border-color: rgba(232,99,90,.5); background: rgba(232,99,90,.12); }
.ocp-tl__zoom button.on { border-color: var(--oc-red-br); color: #fff; background: rgba(232,99,90,.14); }
#ocp-tl-span {
  font-size: .66rem; color: var(--oc-muted); font-variant-numeric: tabular-nums;
  min-width: 78px; text-align: center; white-space: nowrap;
}
/* a zoomed track is a scrubbing surface, so say so */
.ocp-tl__track { touch-action: pan-y; }
.ocp-tl__tip {
  position: absolute; bottom: calc(100% + 8px); transform: translateX(-50%);
  background: rgba(8,3,3,.96); border: 1px solid var(--oc-line); color: #fff;
  padding: 6px; border-radius: 9px; font-size: .74rem; width: 214px;
  pointer-events: none; z-index: 5; box-shadow: 0 12px 30px rgba(0,0,0,.6);
}
.ocp-tl__tipI {
  display: block; width: 100%; height: auto; border-radius: 5px;
  background: #0c0605; border: 1px solid var(--oc-line-soft);
}
.ocp-tl__tipL { display: block; padding: 6px 4px 2px; line-height: 1.4; }
.ocp-tl__tip b { color: var(--oc-red-br); font-variant-numeric: tabular-nums; }
.ocp-tl__tip em { font-style: normal; color: var(--oc-muted); }

[data-theme="light"] .ocp-tl__zoom button:hover,
[data-theme="light"] .ocp-tl__zoom button.on { color: var(--oc-text); }
[data-theme="light"] .ocp-tl__part:nth-child(odd)  { background: rgba(20,5,3,.045); }
[data-theme="light"] .ocp-tl__part:nth-child(even) { background: rgba(20,5,3,.015); }
[data-theme="light"] .ocp-tl__part { border-right-color: rgba(20,5,3,.16); }
[data-theme="light"] .ocp-tl__ch { background: rgba(20,5,3,.22); }
[data-theme="light"] .ocp-tl__head { background: #191110; box-shadow: 0 0 8px rgba(0,0,0,.4); }
[data-theme="light"] .ocp-tl__tip { background: #fff; color: var(--oc-text); }

/* ════════════════════════════════════════════════════ present mode ═══
   Native video fullscreen shows only the video, which is the wrong thing for a
   course built around slides. This takes the whole stage fullscreen instead, so
   the player and the deck are both on screen at once. */
/* NOTE ON SPECIFICITY: these are prefixed with #ocp-course on purpose.
   Without the id, `.ocp-stage:fullscreen` (0,2,0) loses to
   `.ocp-grid[data-layout="split"] .ocp-stage` (0,3,0) above, the split template
   wins, and because that template has no `tl` area the timeline gets
   auto-placed into an implicit column in the bottom-right corner. */
#ocp-course .ocp-stage:fullscreen {
  position: relative; background: var(--oc-ink); padding: 18px; display: grid; gap: 14px;
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr);
  grid-template-rows: 1fr auto auto;
  grid-template-areas: "video slides" "tl tl" "bar bar";
  align-content: stretch;
}
#ocp-course .ocp-stage:fullscreen .ocp-video     { grid-area: video; align-self: center; position: relative; width: 100%; min-width: 0; max-width: none; }
#ocp-course .ocp-stage:fullscreen .ocp-slidewrap { grid-area: slides; margin: 0; align-self: center; min-width: 0; }
#ocp-course .ocp-stage:fullscreen .ocp-tl        { grid-area: tl; margin: 0; }
#ocp-course .ocp-stage:fullscreen .ocp-bar       { grid-area: bar; margin: 0; }
/* View settings in Present mode. It used to be hidden outright, which left the
   View button opening nothing. It cannot be a grid item here (the present
   template has no `view` area, and an unplaced item lands in an implicit track
   in the corner), so it floats over the stage as a popover anchored above the
   bar. Note the deliberate absence of !important on display: the toggle sets
   inline display:none to close, and an !important rule would outrank it. */
#ocp-course .ocp-stage:fullscreen .ocp-view {
  position: absolute; z-index: 40;
  right: 18px; bottom: 94px; left: auto; top: auto;
  width: min(760px, calc(100vw - 36px)); margin: 0;
  background: rgba(20,11,10,.97); border-color: rgba(255,255,255,.16);
  box-shadow: 0 26px 64px rgba(0,0,0,.62);
  backdrop-filter: blur(10px);
}
[data-theme="light"] #ocp-course .ocp-stage:fullscreen .ocp-view {
  background: rgba(255,252,250,.98); border-color: rgba(20,5,3,.16);
}
#ocp-course .ocp-stage:fullscreen .ocp-film      { max-height: 74px; }
#ocp-course .ocp-stage:fullscreen .ocp-slide img { max-height: 62vh; width: 100%; object-fit: contain; }

/* video-side preference still applies while presenting */
#ocp-course .ocp-stage:fullscreen[data-fs-side="right"] {
  grid-template-areas: "slides video" "tl tl" "bar bar";
}

/* slides-only and video-only presenting */
#ocp-course .ocp-stage:fullscreen[data-fs="slides"] { grid-template-columns: 1fr; grid-template-areas: "slides" "tl" "bar"; }
#ocp-course .ocp-stage:fullscreen[data-fs="slides"] .ocp-video { display: none; }
#ocp-course .ocp-stage:fullscreen[data-fs="video"]  { grid-template-columns: 1fr; grid-template-areas: "video" "tl" "bar"; }
#ocp-course .ocp-stage:fullscreen[data-fs="video"] .ocp-slidewrap { display: none; }

@media (max-width: 1000px) {
  #ocp-course .ocp-stage:fullscreen { grid-template-columns: 1fr; grid-template-areas: "video" "slides" "tl" "bar"; }
}

/* ── Present mode: video only ────────────────────────────────────────────
   `aspect-ratio: 16/9; width: 100%` sizes the player off the stage width, which
   in a full-width single column is taller than the row it sits in, so the frame
   ended up small and letterboxed. Size it from the row height instead and let
   the width follow. */
#ocp-course .ocp-stage:fullscreen[data-fs="video"] .ocp-video {
  align-self: stretch; justify-self: center;
  height: 100%; width: auto; max-width: 100%; margin: 0 auto;
}

/* ── Present mode: chapters rail ─────────────────────────────────────────
   The rail is moved inside the stage on entering (it is a sibling otherwise and
   would not render at all in fullscreen), so it needs a place in every present
   template. */
#ocp-course .ocp-stage:fullscreen .ocp-rail {
  grid-area: rail; position: static; top: auto;
  min-height: 0; overflow-y: auto; align-self: stretch;
}
#ocp-course .ocp-stage:fullscreen .ocp-chaps { max-height: none; }

#ocp-course .ocp-stage:fullscreen[data-fs-rail="right"] {
  grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr) 300px;
  grid-template-areas: "video slides rail" "tl tl rail" "bar bar rail";
}
#ocp-course .ocp-stage:fullscreen[data-fs-rail="left"] {
  grid-template-columns: 300px minmax(0, 1.05fr) minmax(0, 1fr);
  grid-template-areas: "rail video slides" "rail tl tl" "rail bar bar";
}
#ocp-course .ocp-stage:fullscreen[data-fs-rail="right"][data-fs-side="right"] {
  grid-template-areas: "slides video rail" "tl tl rail" "bar bar rail";
}
#ocp-course .ocp-stage:fullscreen[data-fs-rail="left"][data-fs-side="right"] {
  grid-template-areas: "rail slides video" "rail tl tl" "rail bar bar";
}

#ocp-course .ocp-stage:fullscreen[data-fs="video"][data-fs-rail="right"],
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-rail="right"] {
  grid-template-columns: minmax(0, 1fr) 300px;
}
#ocp-course .ocp-stage:fullscreen[data-fs="video"][data-fs-rail="right"] {
  grid-template-areas: "video rail" "tl rail" "bar rail";
}
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-rail="right"] {
  grid-template-areas: "slides rail" "tl rail" "bar rail";
}
#ocp-course .ocp-stage:fullscreen[data-fs="video"][data-fs-rail="left"],
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-rail="left"] {
  grid-template-columns: 300px minmax(0, 1fr);
}
#ocp-course .ocp-stage:fullscreen[data-fs="video"][data-fs-rail="left"] {
  grid-template-areas: "rail video" "rail tl" "rail bar";
}
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-rail="left"] {
  grid-template-areas: "rail slides" "rail tl" "rail bar";
}

@media (max-width: 1200px) {
  #ocp-course .ocp-stage:fullscreen[data-fs-rail] .ocp-rail { display: none; }
}

/* ── header chips + reference overlay ────────────────────────────────────
   Resources, certificate, terms and course notes used to be three cards in the
   rail, crowding the chapters. They are reference material, so they sit behind
   these chips and open over the page instead. */
.ocp-tools { display: flex; gap: 7px; flex-wrap: wrap; margin-right: 4px; }
.ocp-tool {
  border: 1px solid var(--oc-line); background: rgba(255,255,255,.04); color: var(--oc-muted);
  border-radius: 999px; padding: 6px 13px; font: inherit; font-size: .74rem; font-weight: 600;
  cursor: pointer; transition: color .2s ease, border-color .2s ease, background .2s ease;
}
a.ocp-tool--link { text-decoration: none; display: inline-flex; align-items: center; }
.ocp-tool--soon { cursor: default; opacity: .6; }
.ocp-tool--soon:hover { color: inherit; border-color: var(--oc-line); background: transparent; }
.ocp-tool:hover { color: #fff; border-color: rgba(232,99,90,.5); background: rgba(232,99,90,.12); }

.ocp-modal {
  position: fixed; inset: 0; z-index: 90; display: grid; place-items: center;
  background: rgba(6,2,2,.72); backdrop-filter: blur(4px); padding: 24px;
}
.ocp-modal__box {
  width: min(680px, 100%); max-height: 84vh; overflow-y: auto;
  background: var(--oc-surface); border: 1px solid var(--oc-line);
  border-radius: 16px; padding: 22px 24px 24px;
  box-shadow: 0 32px 80px rgba(0,0,0,.62);
}
.ocp-modal__top { display: flex; align-items: center; justify-content: space-between; gap: 16px; margin-bottom: 16px; }
.ocp-modal__top h3 { margin: 0; font-size: 1.02rem; letter-spacing: -.01em; }
.ocp-modal__x {
  border: 0; background: none; color: var(--oc-muted); font-size: 1.6rem; line-height: 1;
  cursor: pointer; padding: 0 4px;
}
.ocp-modal__x:hover { color: var(--oc-text); }
.ocp-modal__p { display: grid; gap: 12px; font-size: .9rem; line-height: 1.62; color: var(--oc-muted); }
.ocp-modal__p b { color: #fff; font-weight: 650; }
.ocp-fine { font-size: .74rem; line-height: 1.55; color: var(--oc-muted); opacity: .82; margin: 0; }
.ocp-termlist, .ocp-about { margin: 0; padding-left: 20px; display: grid; gap: 9px; }
.ocp-termlist li, .ocp-about li { line-height: 1.6; }
.ocp-modal .ocp-cert img { width: 100%; height: auto; border-radius: 6px; display: block; }
[data-theme="light"] .ocp-tool { background: rgba(20,5,3,.04); }
[data-theme="light"] .ocp-modal { background: rgba(60,40,38,.5); }

/* ── full screen: every arrangement, not just two ────────────────────────
   `stack` and `split` both collapsed to one side-by-side template, so picking
   Stacked did nothing, and `slides` hid the video outright instead of floating
   it the way the normal layout does. */
#ocp-course .ocp-stage:fullscreen[data-fs="stack"] {
  grid-template-columns: 1fr;
  grid-template-rows: minmax(0, 1fr) minmax(0, 1.15fr) auto auto;
  grid-template-areas: "video" "slides" "tl" "bar";
}
#ocp-course .ocp-stage:fullscreen[data-fs="stack"] .ocp-video {
  align-self: center; justify-self: center; height: 100%; width: auto; max-width: 100%;
}
#ocp-course .ocp-stage:fullscreen[data-fs="stack"] .ocp-slide img { max-height: 100%; }
#ocp-course .ocp-stage:fullscreen[data-fs="stack"][data-fs-rail="right"] {
  grid-template-columns: minmax(0, 1fr) 300px;
  grid-template-areas: "video rail" "slides rail" "tl rail" "bar rail";
}
#ocp-course .ocp-stage:fullscreen[data-fs="stack"][data-fs-rail="left"] {
  grid-template-columns: 300px minmax(0, 1fr);
  grid-template-areas: "rail video" "rail slides" "rail tl" "rail bar";
}

/* slides first: the player floats over the deck, as it does outside full screen */
#ocp-course .ocp-stage:fullscreen[data-fs="slides"] .ocp-video {
  display: block; position: absolute; top: 28px; z-index: 6;
  width: 24%; min-width: 230px; max-width: 400px; height: auto;
  align-self: auto; justify-self: auto;
  box-shadow: 0 20px 50px rgba(0,0,0,.66);
}
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-side="left"]  .ocp-video { left: 28px; right: auto; }
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-side="right"] .ocp-video { right: 28px; left: auto; }
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-rail="left"][data-fs-side="left"] .ocp-video { left: 346px; }
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-rail="right"][data-fs-side="right"] .ocp-video { right: 346px; }

/* the wrapper can be fullscreened on its own (the player's own button is
   redirected here) so the watermark stays visible over the video */
.ocp-video:fullscreen { width: 100vw; height: 100vh; aspect-ratio: auto; border: 0; border-radius: 0; }
.ocp-video:fullscreen .ocp-wm { top: 14px; left: 18px; font-size: .74rem; color: rgba(255,255,255,.38); }

/* ── full screen, stacked ────────────────────────────────────────────────
   Two 16:9 boxes in a 16:9 viewport is a bad hand, and it was worse than it
   needed to be: the slide panel is not just an image, it carries the filmstrip
   too, and nothing capped it to its row. It overflowed, pushed the player up and
   left the video stranded. Cap the panel to its row, let the image take what is
   left, and centre both so it reads as a column. */
#ocp-course .ocp-stage:fullscreen[data-fs="stack"] {
  grid-template-rows: minmax(0, 1fr) minmax(0, 1.3fr) auto auto;
}
#ocp-course .ocp-stage:fullscreen[data-fs="stack"] .ocp-video {
  justify-self: center; align-self: center; height: 100%; width: auto; max-width: 100%;
}
#ocp-course .ocp-stage:fullscreen[data-fs="stack"] .ocp-slidewrap {
  height: 100%; width: 100%; min-height: 0; margin: 0;
  display: flex; flex-direction: column; gap: 6px;
}
#ocp-course .ocp-stage:fullscreen[data-fs="stack"] .ocp-slide {
  flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center;
  background: transparent; border: 0;
}
#ocp-course .ocp-stage:fullscreen[data-fs="stack"] .ocp-slide img {
  height: 100%; width: auto; max-width: 100%; max-height: 100%; object-fit: contain;
  border-radius: var(--oc-r); border: 1px solid var(--oc-line);
}
#ocp-course .ocp-stage:fullscreen[data-fs="stack"] .ocp-film { flex: 0 0 auto; max-height: 62px; }

/* ── overlay panels read as body copy, not fine print ───────────────────── */
.ocp-modal__p { color: var(--oc-text); }
.ocp-modal__p .ocp-fine { color: var(--oc-muted); }

/* ── links out of the About panel ───────────────────────────────────────── */
.ocp-links { display: grid; gap: 10px; margin: 2px 0 0; }
.ocp-link {
  display: flex; align-items: center; gap: 12px; text-decoration: none;
  border: 1px solid var(--oc-line); border-radius: 11px; padding: 11px 14px;
  background: rgba(255,255,255,.035); color: var(--oc-text);
  transition: border-color .25s ease, background .25s ease, transform .25s ease;
}
.ocp-link:hover { border-color: rgba(232,99,90,.5); background: rgba(232,99,90,.1); transform: translateY(-2px); }
.ocp-link b { display: block; font-size: .9rem; font-weight: 650; }
.ocp-link span { display: block; font-size: .78rem; color: var(--oc-muted); line-height: 1.45; }
.ocp-link__go { margin-left: auto; color: var(--oc-red-br); font-size: 1.05rem; }
.ocp-promo {
  border: 1px solid rgba(232,99,90,.34); background: rgba(232,99,90,.09);
  border-radius: 12px; padding: 14px 16px;
}
.ocp-promo b { color: #fff; }
.ocp-promo code {
  background: rgba(0,0,0,.34); border: 1px solid var(--oc-line); border-radius: 6px;
  padding: 2px 8px; font-size: .84rem; letter-spacing: .04em;
}
[data-theme="light"] .ocp-link { background: rgba(20,5,3,.035); }
[data-theme="light"] .ocp-promo code { background: rgba(20,5,3,.06); }

/* ── player loading dial ─────────────────────────────────────────────────
   The placeholder used to explain, in prose, that the video was not connected.
   That is the normal state for the second or two before the signed token comes
   back, and it read as a fault. A dial now, prose only if it really fails. */
.ocp-spin {
  position: relative; width: 42px; height: 42px; border-radius: 50%;
  border: 3px solid rgba(255,255,255,.14);
  border-top-color: var(--oc-red-br);
  animation: ocp-spin 850ms linear infinite;
}
@keyframes ocp-spin { to { transform: rotate(360deg); } }
@media (prefers-reduced-motion: reduce) {
  .ocp-spin { animation-duration: 2.4s; }
}
[data-theme="light"] .ocp-spin { border-color: rgba(20,5,3,.14); border-top-color: var(--oc-red-br); }


/* ── overlay headings ────────────────────────────────────────────────────
   These h3s set no colour of their own, so they took whatever the site's
   global heading rule gives them: a dark navy meant for cream pages, which on
   the dark overlay reads as black on black. Every heading inside our own
   surfaces states its colour. */
.ocp-modal__top h3,
.ocp-idle__box h3 { color: var(--oc-text); }
.ocp-modal__p b, .ocp-link b, .ocp-promo b { color: var(--oc-text); }
[data-theme="light"] .ocp-modal__top h3,
[data-theme="light"] .ocp-idle__box h3 { color: var(--oc-text); }

/* ── our own expand control ──────────────────────────────────────────────
   Mirrors the exit button. Sits on the wrapper, so the fullscreen element is
   ours and the watermark stays painted over the video. */
.ocp-vfs {
  display: grid; place-items: center; position: absolute; top: 12px; right: 12px;
  width: 36px; height: 36px; border-radius: 50%; z-index: 8;
  background: rgba(10,4,4,.62); border: 1px solid rgba(255,255,255,.24); color: #fff;
  cursor: pointer; backdrop-filter: blur(6px);
  opacity: 0; transition: opacity .3s ease, background .25s ease;
}
.ocp-video:hover .ocp-vfs, .ocp-vfs:focus-visible { opacity: 1; }
.ocp-vfs:hover { background: var(--oc-red); }
.ocp-video:fullscreen .ocp-vfs { display: none; }
/* the stamp has to clear the button in the corner it shares */
.ocp-video:fullscreen .ocp-wm { z-index: 21; }

/* ── every heading in the portal states its colour ───────────────────────
   None of these set one, so they inherited the site's global heading rule: a
   navy chosen for cream pages, which on this dark ground is black on black.
   Patching them one at a time missed the next one each time (the modal, then
   the h1, then the gates), so this covers the whole document body.

   Scoped through body.oc-portal-body, which is (0,1,2): it outranks a bare
   `h1 {}` from the site chrome, while any of our own deliberate colours —
   `.ocp-quiz h3` and friends, all (0,2,0) — still win over it. */
body.oc-portal-body h1,
body.oc-portal-body h2,
body.oc-portal-body h3,
body.oc-portal-body h4 { color: var(--oc-text); }
body.oc-portal-body .ocp-head p,
body.oc-portal-body .ocp-gate p { color: var(--oc-muted); }

/* ── controls moved to the top of the page ───────────────────────────────
   Slides-follow, Full screen and View sat in a bar under the player, which put
   them in a different place on screen for every arrangement and buried them
   entirely when the video was small. They live in the header now, with the View
   panel hanging off them as a dropdown rather than pushing the page around. */
.ocp-ctrls { position: relative; display: flex; align-items: center; gap: 9px; flex-wrap: wrap; }
.ocp-ctrls .ocp-toggle { margin-left: 0; }
.ocp-ctrls .ocp-view {
  /* Anchored to the LEFT edge of the group. The group sits at the start of its
     row, and a 720px panel hung off its right edge began 200px past the left
     edge of the screen: Arrangement and Chapters were simply not visible. */
  position: absolute; top: calc(100% + 10px); left: 0; right: auto; z-index: 60;
  width: min(720px, calc(100vw - 48px)); margin: 0;
  background: rgba(20,11,10,.98); box-shadow: 0 26px 64px rgba(0,0,0,.6);
  backdrop-filter: blur(10px);
}
[data-theme="light"] .ocp-ctrls .ocp-view { background: rgba(255,252,250,.99); }

/* the bar is only a caption now */
.ocp-bar { justify-content: flex-start; }

/* Full screen: the group rides along inside the stage, pinned to the corner so
   it needs no grid area of its own. */
#ocp-course .ocp-stage:fullscreen .ocp-ctrls {
  position: absolute; top: 16px; right: 16px; z-index: 50;
  padding: 8px 10px; border-radius: 12px;
  background: rgba(12,5,5,.72); border: 1px solid var(--oc-line); backdrop-filter: blur(8px);
}
#ocp-course .ocp-stage:fullscreen .ocp-ctrls .ocp-view { top: calc(100% + 8px); }
#ocp-course .ocp-stage:fullscreen[data-fs-rail="right"] .ocp-ctrls { right: 332px; }

@media (max-width: 760px) {
  .ocp-ctrls { width: 100%; }
  .ocp-ctrls .ocp-view { width: calc(100vw - 32px); right: auto; left: 0; }
}

/* ── overlays are solid, not glass ───────────────────────────────────────
   Translucency plus a blur let the page behind bleed through, and the text on
   top ended up competing with whatever slide happened to be underneath. These
   are reading surfaces: give them an opaque ground and a settled colour. */
.ocp-modal, .ocp-idle { background: rgba(6,2,2,.86); backdrop-filter: none; }
.ocp-modal__box, .ocp-idle__box {
  background: #17100f; backdrop-filter: none; border-color: rgba(255,255,255,.16);
}
.ocp-modal__p, .ocp-modal__p li, .ocp-modal__p p { color: #e9e1df; }
.ocp-modal__p b, .ocp-link b, .ocp-promo b, .ocp-modal__top h3 { color: #fff; }
.ocp-link, .ocp-promo { background: rgba(255,255,255,.05); }
.ocp-link span, .ocp-promo span { color: #cbbfbc; }
.ocp-fine { color: #b3a5a2; opacity: 1; }
.ocp-modal a { color: var(--oc-red-br); }
.ocp-ctrls .ocp-view { background: #17100f; backdrop-filter: none; }
#ocp-course .ocp-stage:fullscreen .ocp-ctrls { background: #17100f; backdrop-filter: none; }
/* Bright mode reached every panel except this one: the control group pinned to
   the corner in full screen kept its near-black ground, so dark-on-dark text
   sat on it. Both of its backgrounds need the counterpart, and it has to beat
   #ocp-course ... .ocp-ctrls on specificity, hence the id plus the attribute. */
[data-theme="light"] #ocp-course .ocp-stage:fullscreen .ocp-ctrls {
  background: rgba(255,252,250,.96); border-color: rgba(20,5,3,.16);
  box-shadow: 0 10px 30px rgba(20,5,3,.12);
}
[data-theme="light"] #ocp-course .ocp-stage:fullscreen .ocp-ctrls .ocp-toggle,
[data-theme="light"] #ocp-course .ocp-stage:fullscreen .ocp-ctrls .ocp-viewbtn {
  color: #4a403e;
}
/* And the inverse: anything that stays dark in both themes must keep light
   text on it, or the bright-mode colour rules bleed onto a dark ground. */
[data-theme="light"] .ocp-caps,
[data-theme="light"] .ocp-video__ph b,
[data-theme="light"] .ocp-drag__reset,
[data-theme="light"] .ocp-wm { color: #fff; }
[data-theme="light"] .ocp-slide__n { color: #f2ecea; }
#ocp-course .ocp-stage:fullscreen .ocp-view { background: #17100f; backdrop-filter: none; }

[data-theme="light"] .ocp-modal, [data-theme="light"] .ocp-idle { background: rgba(60,40,38,.5); }
[data-theme="light"] .ocp-modal__box,
[data-theme="light"] .ocp-idle__box,
[data-theme="light"] .ocp-ctrls .ocp-view { background: #fffdfc; border-color: rgba(20,5,3,.16); }
[data-theme="light"] .ocp-modal__p,
[data-theme="light"] .ocp-modal__p li,
[data-theme="light"] .ocp-modal__p p { color: #3a2c2a; }
[data-theme="light"] .ocp-modal__p b,
[data-theme="light"] .ocp-link b,
[data-theme="light"] .ocp-promo b,
[data-theme="light"] .ocp-modal__top h3 { color: #191110; }
[data-theme="light"] .ocp-link span, [data-theme="light"] .ocp-promo span { color: #5c4a47; }
[data-theme="light"] .ocp-fine { color: #6b5854; }

/* ── header ──────────────────────────────────────────────────────────────
   Controls, reference chips and status stay on one line while they fit, and
   fall to a second row when they do not. They used to be pinned with nowrap,
   which held one line right up until the content outgrew the width and then
   ran straight over the title instead of wrapping. */
.ocp-head { flex-wrap: wrap; align-items: center; row-gap: 12px; }
.ocp-head > div:first-child { flex: 1 1 auto; min-width: 0; }
/* The signed-in address holds the top-right corner, level with the title, and
   the controls take the row beneath. It used to ride along at the end of the
   control cluster, so it moved every time that cluster wrapped. */
.ocp-head > #ocp-who { flex: 0 0 auto; margin-left: auto; align-self: center; }
/* The controls own the row under the title, so spread them across it rather
   than bunching everything against the right edge. */
.ocp-me { flex: 1 1 100%; flex-wrap: wrap; justify-content: space-between;
          gap: 8px; row-gap: 9px; min-width: 0; }
.ocp-me > span { white-space: nowrap; }
#ocp-who {
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; max-width: 32ch;
  font-size: .82rem; color: var(--oc-muted);
}
.ocp-tools { flex-wrap: wrap; gap: 5px; row-gap: 7px; }
.ocp-tool { padding: 5px 10px; font-size: .7rem; }
.ocp-ctrls { flex-wrap: wrap; gap: 7px; row-gap: 9px; }
.ocp-ctrls .ocp-toggle { font-size: .74rem; gap: 7px; white-space: nowrap; }
.ocp-ctrls .ocp-toggle input { width: 32px; height: 18px; }
.ocp-ctrls .ocp-toggle input::after { width: 13px; height: 13px; top: 2.5px; left: 2.5px; }
.ocp-ctrls .ocp-toggle input:checked::after { transform: translateX(14px); }
.ocp-viewbtn { padding: 6px 10px; font-size: .74rem; white-space: nowrap; }
.ocp-chip { padding: 4px 10px; font-size: .7rem; }
.ocp-score { white-space: nowrap; font-size: .74rem; }
@media (max-width: 1180px) { .ocp-head h1 { font-size: 1.25rem; } .ocp-head p { display: none; } }
@media (max-width: 980px)  { .ocp-head, .ocp-me, .ocp-tools, .ocp-ctrls { flex-wrap: wrap; } }

/* ── per-viewer stamp on the slide itself ────────────────────────────────
   The page watermark sits on the video. A screenshot of the deck would carry
   nothing, and the deck is the part worth taking. */
.ocp-slide__wm {
  position: absolute; left: 50%; bottom: 7px; transform: translateX(-50%);
  font-size: .58rem; letter-spacing: .05em; color: rgba(255,255,255,.34);
  text-shadow: 0 1px 2px rgba(0,0,0,.55); pointer-events: none; user-select: none;
  max-width: 90%; overflow: hidden; white-space: nowrap; z-index: 4;
}
[data-theme="light"] .ocp-slide__wm { color: rgba(20,5,3,.34); text-shadow: none; }

/* ── resize from any edge or corner ──────────────────────────────────────
   One corner grip meant the player could only grow down and right, and only
   from wherever it already sat. Every side is now a handle; the 16:9 ratio is
   fixed, so a drag decides the width and which edge stays anchored. */
.ocp-sizes { display: none; }
.ocp-grid[data-layout="slides"] .ocp-sizes {
  display: block; position: absolute; inset: 0; z-index: 7; pointer-events: none;
}
.ocp-grid[data-layout="slides"] .ocp-size { position: absolute; pointer-events: auto; touch-action: none; }
.ocp-size--n, .ocp-size--s { left: 12px; right: 12px; height: 9px; cursor: ns-resize; }
.ocp-size--e, .ocp-size--w { top: 12px; bottom: 12px; width: 9px; cursor: ew-resize; }
.ocp-size--n { top: -4px; }   .ocp-size--s { bottom: -4px; }
.ocp-size--w { left: -4px; }  .ocp-size--e { right: -4px; }
.ocp-size--ne, .ocp-size--nw, .ocp-size--se, .ocp-size--sw { width: 16px; height: 16px; }
.ocp-size--nw { top: -4px; left: -4px; cursor: nwse-resize; }
.ocp-size--ne { top: -4px; right: -4px; cursor: nesw-resize; }
.ocp-size--sw { bottom: -4px; left: -4px; cursor: nesw-resize; }
.ocp-size--se { bottom: -4px; right: -4px; cursor: nwse-resize; }
.ocp-video:fullscreen .ocp-sizes { display: none !important; }

/* ── full screen, slides first: keep the player inside the deck ──────────
   The floating position is stored as a percentage of the stage, and the stage
   is a very different shape full screen, so a position that sat neatly over the
   deck in the page ended up under the controls in the corner. Pin it clear of
   them for the duration; the size the viewer chose still applies. */
#ocp-course .ocp-stage:fullscreen[data-fs="slides"] .ocp-video {
  top: 84px !important; bottom: auto !important;
  max-width: 34% !important;
}
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-side="left"] .ocp-video {
  left: 28px !important; right: auto !important;
}
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-side="right"] .ocp-video {
  right: 28px !important; left: auto !important;
}
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-rail="left"][data-fs-side="left"] .ocp-video {
  left: 346px !important;
}
#ocp-course .ocp-stage:fullscreen[data-fs="slides"][data-fs-rail="right"][data-fs-side="right"] .ocp-video {
  right: 346px !important;
}
/* dragging it around full screen would only put it back under the controls */
#ocp-course .ocp-stage:fullscreen .ocp-sizes,
#ocp-course .ocp-stage:fullscreen .ocp-drag { display: none !important; }

/* ── overlays sit above the site chrome ──────────────────────────────────
   The site nav is position:sticky at z-index 9999 and the drawer 9998, so an
   overlay at 90 rendered underneath: the About panel appeared to be cut by the
   header. Above both, quiz highest since it blocks progress. */
.ocp-modal { z-index: 10000; }
.ocp-idle  { z-index: 10001; }
.ocp-quiz  { z-index: 10002; }

/* ── view settings in full screen ────────────────────────────────────────
   Hanging a 720px panel off a corner-pinned group ran it off the stage. Fixed
   to the viewport, capped in height and scrollable, so it opens the same way
   in every arrangement instead of reflowing whatever is behind it. */
#ocp-course .ocp-stage:fullscreen .ocp-ctrls .ocp-view {
  position: fixed; top: auto; bottom: 20px; right: 20px; left: auto;
  width: min(680px, calc(100vw - 40px));
  max-height: min(520px, calc(100vh - 120px)); overflow-y: auto;
  z-index: 60; box-shadow: 0 26px 64px rgba(0,0,0,.66);
}

/* ── slides first gives the deck the width ───────────────────────────────
   The chapters rail was taking 322px of a mode whose entire point is that the
   deck is the thing you are looking at. Timeline and chapter titles are still
   right there under the slide. */
.ocp-grid[data-layout="slides"] { grid-template-columns: 1fr; }
.ocp-grid[data-layout="slides"] .ocp-rail { display: none; }

/* ── restored after an over-broad deletion ───────────────────────────────
   Removing the obsolete single-grip block took three live rules with it: the
   width release the resize handles depend on, the idle overlay, and the exit
   button on the promoted player. Without the last one the button lost its
   `display: none` and sat unstyled in the corner, where its four-bracket icon
   read as a stray plus. */
.ocp-grid[data-layout="slides"] .ocp-video[style*="width"] { max-width: none; min-width: 0; }

.ocp-idle {
  position: fixed; inset: 0; z-index: 10001; display: grid; place-items: center;
  background: rgba(6,2,2,.93); padding: 24px; animation: ocp-fade .28s ease;
}
.ocp-idle__box {
  width: min(430px, 100%); text-align: center;
  background: #17100f; border: 1px solid rgba(255,255,255,.16);
  border-radius: 16px; padding: 30px 28px; box-shadow: 0 32px 80px rgba(0,0,0,.62);
}
.ocp-idle__box h3 { margin: 0 0 10px; font-size: 1.12rem; color: var(--oc-text); }
.ocp-idle__box p { margin: 0 0 20px; font-size: .88rem; line-height: 1.6; color: var(--oc-muted); }
[data-theme="light"] .ocp-idle__box { background: #fffdfc; border-color: rgba(20,5,3,.16); }

.ocp-vfx { display: none; }
.ocp-video:fullscreen .ocp-vfx {
  display: grid; place-items: center; position: absolute; top: 18px; right: 18px;
  width: 42px; height: 42px; border-radius: 50%; z-index: 20;
  background: rgba(10,4,4,.7); border: 1px solid rgba(255,255,255,.28); color: #fff;
  cursor: pointer; backdrop-filter: blur(6px);
  opacity: 0; transition: opacity .3s ease, background .25s ease;
}
.ocp-video:fullscreen:hover .ocp-vfx,
.ocp-video:fullscreen .ocp-vfx:focus-visible { opacity: 1; }
.ocp-video:fullscreen .ocp-vfx:hover { background: var(--oc-red); }

/* ── "Now showing" moved above the stage ─────────────────────────────────
   It was a strip under the player, which put it in a different place for every
   arrangement and below the fold when the deck was tall. It reads as a subtitle
   to the course title, so it sits there. */
.ocp-bar {
  margin: 0 0 16px; padding: 9px 14px;
  background: rgba(255,255,255,.035);
}
[data-theme="light"] .ocp-bar { background: rgba(20,5,3,.035); }
#ocp-course .ocp-stage:fullscreen .ocp-bar { margin: 0; }

/* ══════════════════════════════════════════════════════ mobile ═══
   Everything below 760px. The portal was laid out for a desk: rows that wrap
   into ragged stacks, tap targets sized for a cursor, and a settings panel whose
   group headings got lost once the columns collapsed. */
@media (max-width: 760px) {
  .ocp-head { flex-direction: column; align-items: center; text-align: center; gap: 14px; }
  .ocp-head h1 { font-size: 1.45rem; }
  .ocp-head p { display: block; font-size: .8rem; }
  .ocp-me { flex-wrap: wrap; justify-content: center; gap: 10px; width: 100%; }
  #ocp-who { max-width: 100%; }

  /* one row of controls, one row of reference chips, both centred */
  .ocp-ctrls { width: 100%; justify-content: center; gap: 10px; }
  .ocp-tools { width: 100%; justify-content: center; gap: 8px; }

  /* fingers, not cursors */
  .ocp-tool, .ocp-viewbtn {
    min-height: 42px; padding: 10px 16px; font-size: .82rem; border-radius: 999px;
  }
  .ocp-ctrls .ocp-toggle { min-height: 42px; font-size: .82rem; }
  .ocp-chip, .ocp-score { font-size: .78rem; padding: 6px 12px; }

  .ocp-bar { justify-content: center; text-align: center; }
  .ocp-bar__t { width: 100%; font-size: .8rem; }

  /* View settings: full-width sheet, every group titled, every option a row you
     can actually read, so "Hidden" and "Bright" are never orphaned labels. */
  .ocp-ctrls .ocp-view {
    position: fixed; left: 12px; right: 12px; width: auto;
    bottom: 12px; top: auto;
    max-height: 78vh; overflow-y: auto;
    grid-template-columns: 1fr; gap: 18px; padding: 20px 18px 22px;
    border-radius: 16px; z-index: 10005;
  }
  .ocp-view__h {
    font-size: .74rem; letter-spacing: .14em; color: var(--oc-red-br);
    margin: 0 0 10px; opacity: 1;
  }
  .ocp-view__opts { display: grid; grid-template-columns: 1fr 1fr; gap: 9px; }
  .ocp-view__opts button {
    grid-template-columns: auto 1fr; justify-items: start; align-items: center;
    gap: 10px; min-height: 50px; padding: 11px 13px; font-size: .84rem; text-align: left;
  }
  .ocp-view__opts button span { line-height: 1.25; }
  .ocp-view__opts button:hover { transform: none; }
  .ocp-view__reset { justify-self: center; min-height: 42px; font-size: .84rem; }

  /* overlays and their actions */
  .ocp-modal__box, .ocp-idle__box { padding: 22px 18px; border-radius: 14px; }
  .ocp-modal__top h3 { font-size: 1rem; }
  .ocp-btn, .ocp-idle__box .ocp-btn { min-height: 48px; width: 100%; }
  .ocp-quiz__act { display: grid; gap: 10px; }
  .ocp-quiz__act .ocp-btn { width: 100%; }
  .ocp-dl { min-height: 60px; }
  .ocp-link { min-height: 58px; }

  /* the deck and its controls */
  .ocp-nav { width: 42px; height: 42px; opacity: .9; }
  .ocp-slide__wm { font-size: .5rem; }
  .ocp-tl__tip { width: 176px; }
}

/* The strip is scrolled to centre the current frame, so make it a positioning
   context and give the ends breathing room: the first and last frames can then
   reach the middle instead of stopping at the edge. */
.ocp-film { position: relative; scroll-behavior: smooth; }
.ocp-film img.on { outline: 2px solid var(--oc-red-br); outline-offset: 1px; }

/* ── the strip must have a stable width ──────────────────────────────────
   253 thumbnails with loading="lazy" have no intrinsic width until they load,
   so scrollWidth grew as you scrolled and every position computed against it
   went stale: the strip jumped and the highlighted frame drifted. The frames
   are 16:9, so pin the box and let the image fill it. Layout is then identical
   whether or not a thumbnail has arrived. */
.ocp-film img { width: 103px; height: 58px; object-fit: cover; }
.ocp-film img.sub { width: 85px; height: 48px; }
@media (max-width: 760px) {
  .ocp-film img { width: 84px; height: 47px; }
  .ocp-film img.sub { width: 70px; height: 39px; }
}

/* ── the follow toggle in bright mode ────────────────────────────────────
   Its off state is a translucent white track with a white knob, which is fine
   on the dark ground and all but invisible on the light one. Give it a real
   track, a bordered knob and a readable label. */
[data-theme="light"] .ocp-toggle { color: #4a403e; }
[data-theme="light"] .ocp-toggle input {
  background: #d9cfcb; box-shadow: inset 0 0 0 1px rgba(20,5,3,.16);
}
[data-theme="light"] .ocp-toggle input::after {
  background: #fff; box-shadow: 0 1px 3px rgba(20,5,3,.35);
}
[data-theme="light"] .ocp-toggle input:checked { background: var(--oc-red); box-shadow: none; }
[data-theme="light"] .ocp-toggle:hover { color: var(--oc-text); }

/* ── quiz overview ───────────────────────────────────────────────────────
   The score chip says how many; this says which. Rows seek to the question. */
.ocp-ql { display: grid; gap: 6px; }
.ocp-ql__h {
  font-family: inherit; font-size: .72rem; font-weight: 800; letter-spacing: .14em;
  text-transform: uppercase; color: var(--oc-red-br); margin: 12px 0 4px;
}
.ocp-ql__h:first-child { margin-top: 0; }
.ocp-ql__row {
  display: flex; align-items: flex-start; gap: 12px; width: 100%; text-align: left;
  border: 1px solid var(--oc-line); border-radius: 10px; padding: 10px 12px;
  background: rgba(255,255,255,.03); color: inherit; font: inherit; font-size: .86rem;
  cursor: pointer; transition: border-color .2s, background .2s;
}
.ocp-ql__row:hover { border-color: rgba(232,99,90,.5); background: rgba(232,99,90,.1); }
.ocp-ql__q { flex: 1 1 auto; line-height: 1.45; }
.ocp-ql__s {
  flex: 0 0 auto; align-self: center; font-size: .68rem; font-weight: 700;
  letter-spacing: .06em; text-transform: uppercase; padding: 4px 9px; border-radius: 999px;
  border: 1px solid transparent; white-space: nowrap;
}
.ocp-ql__s--ok   { color: #6fcf8b; border-color: rgba(111,207,139,.42); background: rgba(111,207,139,.12); }
.ocp-ql__s--no   { color: #e8635a; border-color: rgba(232,99,90,.45);  background: rgba(232,99,90,.14); }
.ocp-ql__s--skip { color: #e0a53a; border-color: rgba(224,165,58,.42); background: rgba(224,165,58,.12); }
.ocp-ql__s--miss { color: #c9a26a; border-color: rgba(201,162,106,.35); background: rgba(201,162,106,.1); }
.ocp-ql__s--todo { color: var(--oc-muted); border-color: var(--oc-line); }
[data-theme="light"] .ocp-ql__row { background: rgba(20,5,3,.03); }
[data-theme="light"] .ocp-ql__s--ok { color: #1f7a3d; }
[data-theme="light"] .ocp-ql__s--no { color: #a3241c; }
[data-theme="light"] .ocp-ql__s--skip { color: #8a6414; }
@media (max-width: 760px) {
  .ocp-ql__row { flex-direction: column; gap: 8px; }
  .ocp-ql__s { align-self: flex-start; }
}

/* ── certificate issuing ─────────────────────────────────────────────── */
.ocp-issue { display: grid; gap: 9px; margin-top: 14px; padding-top: 14px; border-top: 1px solid var(--oc-line); }
.ocp-issue label { font-size: .74rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--oc-red-br); }
.ocp-issue input {
  border: 1px solid var(--oc-line); border-radius: 9px; background: rgba(255,255,255,.05);
  color: var(--oc-text); font: inherit; font-size: .92rem; padding: 11px 13px; min-height: 44px;
}
.ocp-issue input:focus { outline: none; border-color: var(--oc-red-br); }
.ocp-issue .ocp-btn { min-height: 46px; }
.ocp-issue .ocp-fine { min-height: 1.2em; }
.ocp-issue a { color: var(--oc-red-br); }
[data-theme="light"] .ocp-issue input { background: rgba(20,5,3,.04); }

/* ── captions ────────────────────────────────────────────────────────────
   Option B: Open Sans 600, white, a soft shadow rather than an outline. Drawn
   by us because Cloudflare's own captions live inside the iframe in the
   browser's default styling, which we cannot reach or match. */
.ocp-caps {
  position: absolute; left: 0; right: 0; bottom: 7%; z-index: 6;
  text-align: center; padding: 0 6%;
  pointer-events: none; user-select: none;
  font-family: 'Open Sans', system-ui, -apple-system, Segoe UI, Arial, sans-serif;
  font-weight: 600; color: #fff; line-height: 1.32; letter-spacing: .005em;
  text-shadow: 0 2px 6px rgba(0,0,0,.95), 0 0 2px rgba(0,0,0,.9);
  font-size: clamp(calc(13px * var(--capk, 1)), calc(3.1cqw * var(--capk, 1)),
                   calc(30px * var(--capk, 1)));
  container-type: inline-size;
}
.ocp-video { container-type: inline-size; }
.ocp-grid[data-caps="off"] .ocp-caps { display: none; }
.ocp-video:fullscreen .ocp-caps { bottom: 10%; }
/* Full screen is the portal's own mode: the stage goes fullscreen, not the
   video, so this is a separate rule from the one above. Captions sat at the
   page position there, which crowds the bottom edge of a large player. */
#ocp-course .ocp-stage:fullscreen .ocp-caps { bottom: 11%; }

/* the subtitle popover: one row for on/off, one for size, each button showing
   the size it sets rather than describing it */
.ocp-view--caps { grid-template-columns: repeat(auto-fit, minmax(150px, 1fr)); max-width: 460px; }
/* the language row takes the full width of the popover: eleven pills do not
   fit a 150px column, and each is labelled in its own language */
.ocp-view__g--lang { grid-column: 1 / -1; }
.ocp-view__opts--lang button { padding: 7px 11px; font-size: .72rem; }
.ocp-view__opts--lang button span { line-height: 1.2; white-space: nowrap; }
.capsw {
  display: grid; place-items: center; width: 30px; height: 20px;
  font-family: 'Open Sans', system-ui, Arial, sans-serif; font-weight: 600;
  color: currentColor; opacity: .85; font-size: 14px; line-height: 1;
}
.capsw--on { text-shadow: 0 1px 3px rgba(0,0,0,.9); }
.capsw--off { opacity: .3; text-decoration: line-through; }
/* the header button carries the state, so you can see captions are off
   without opening anything */
#ocp-capsbtn.off svg { opacity: .45; }
#ocp-capsbtn.off::after {
  content: ""; position: absolute; left: 9px; right: 9px; top: 50%;
  height: 1px; background: currentColor; opacity: .5; transform: rotate(-9deg);
}
#ocp-capsbtn { position: relative; }

/* ── partner offers at the foot of the portal ────────────────────────────
   Lifted from the home page (assets/styles.css, .featured-pages-section) so
   the two banners look the same in both places. The portal does not load that
   stylesheet, so the rules are restated here scoped to .ocp-offers. The cards
   are black in either theme, exactly as on the home page. */
/* hidden until portal.js says the course is up; see openCourse() */
/* hidden until portal.js says the course is up; see openCourse().
   It sits outside .ocp, so it carries its own gutter. */
.ocp-offers { display: none; margin: 40px auto 4px; max-width: 720px; padding: 0 18px; }
.ocp-offers.ready { display: block; }
.ocp-offers__h {
  font-size: .66rem; text-transform: uppercase; letter-spacing: .18em;
  color: var(--oc-muted); margin: 0 0 12px; font-weight: 700; text-align: center;
}
.ocp-offers__grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 12px; }

.ocp-offers .featured-banner {
  position: relative; display: flex; flex-direction: column;
  background: #000; border: 1px solid rgba(255,255,255,0.09);
  border-radius: 12px; padding: 14px 16px; text-decoration: none;
  transition: all 0.4s cubic-bezier(0.4,0,0.2,1);
  box-shadow: 0 4px 14px rgba(0,0,0,0.3);
  height: 100%; overflow: hidden; color: #fff;
}
.ocp-offers .featured-banner::before {
  content: ''; position: absolute; top: 0; left: -100%;
  width: 100%; height: 100%;
  background: linear-gradient(90deg, transparent, rgba(255,153,0,0.1), transparent);
  transition: left 0.6s ease;
}
.ocp-offers .featured-banner:hover { transform: translateY(-2px); }
.ocp-offers .featured-banner:hover::before { left: 100%; }
.ocp-offers .featured-banner-content {
  display: flex; align-items: center; text-align: left;
  gap: 12px; height: 100%; position: relative; z-index: 2;
}
.ocp-offers .featured-banner-image {
  width: 44px; height: 34px; flex: 0 0 44px; object-fit: contain;
  filter: drop-shadow(0 0 8px rgba(255,153,0,0.25)); transition: all 0.4s ease;
}
.ocp-offers .featured-banner:hover .featured-banner-image { transform: scale(1.05); }
.ocp-offers .featured-banner-text { min-width: 0; display: flex; flex-direction: column; align-items: flex-start; }
.ocp-offers .featured-banner-badge {
  display: none;
}
.ocp-offers .featured-banner-title {
  font-size: 14px; font-weight: 700; margin: 0 0 5px;
  background: linear-gradient(135deg, #ae1f19 0%, #d64a1a 50%, #FF9900 100%);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
  transition: all 0.3s ease;
}
.ocp-offers .featured-banner-description {
  font-size: 11.5px; color: #b3b7d4; line-height: 1.45; margin: 0 0 8px;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.ocp-offers .featured-banner-features { display: flex; gap: 6px; flex-wrap: wrap; }
.ocp-offers .featured-banner-feature {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 2px 7px; border-radius: 999px;
  background: rgba(255,153,0,0.1); border: 1px solid rgba(255,153,0,0.2);
  font-size: 10px; color: #ffcc99;
}
.ocp-offers .featured-banner-feature::before { content: "\2713"; color: #FF9900; font-weight: bold; font-size: 10px; }

/* Trading Interview: light-blue */
.ocp-offers .featured-banner.trading-interview-banner {
  border-color: rgba(127,163,212,0.3); box-shadow: 0 4px 14px rgba(0,0,0,0.3), 0 0 12px rgba(127,163,212,0.10);
}
.ocp-offers .featured-banner.trading-interview-banner::before {
  background: linear-gradient(90deg, transparent, rgba(127,163,212,0.1), transparent);
}
.ocp-offers .featured-banner.trading-interview-banner:hover {
  border-color: rgba(127,163,212,0.5); box-shadow: 0 8px 22px rgba(0,0,0,0.4), 0 0 18px rgba(127,163,212,0.20);
}
.ocp-offers .featured-banner.trading-interview-banner .featured-banner-image {
  filter: brightness(0) invert(1) drop-shadow(0 0 12px rgba(127,163,212,0.3));
}
.ocp-offers .featured-banner.trading-interview-banner .featured-banner-badge {
  background: linear-gradient(135deg, rgba(26,47,83,0.3), rgba(42,79,115,0.3));
  border-color: rgba(127,163,212,0.4); color: #7fa3d4;
}
.ocp-offers .featured-banner.trading-interview-banner .featured-banner-title {
  background: linear-gradient(135deg, #ffffff 0%, #7fa3d4 50%, #b8c8e0 100%);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
}
.ocp-offers .featured-banner.trading-interview-banner .featured-banner-feature {
  background: rgba(127,163,212,0.1); border-color: rgba(127,163,212,0.2); color: #b8c8e0;
}
.ocp-offers .featured-banner.trading-interview-banner .featured-banner-feature::before { color: #7fa3d4; }

/* Market Making Games: violet/magenta */
.ocp-offers .featured-banner.market-making-games-banner {
  border-color: rgba(192,132,252,0.35); box-shadow: 0 4px 14px rgba(0,0,0,0.3), 0 0 12px rgba(192,132,252,0.14);
}
.ocp-offers .featured-banner.market-making-games-banner::before {
  background: linear-gradient(90deg, transparent, rgba(236,72,153,0.15), transparent);
}
.ocp-offers .featured-banner.market-making-games-banner:hover {
  border-color: rgba(236,72,153,0.55); box-shadow: 0 8px 22px rgba(0,0,0,0.4), 0 0 18px rgba(236,72,153,0.22);
}
.ocp-offers .featured-banner.market-making-games-banner .featured-banner-badge {
  background: linear-gradient(135deg, rgba(124,58,237,0.32), rgba(236,72,153,0.32));
  border-color: rgba(192,132,252,0.45); color: #e9b3ff;
}
.ocp-offers .featured-banner.market-making-games-banner .featured-banner-title {
  background: linear-gradient(135deg, #ffffff 0%, #c084fc 45%, #ec4899 100%);
  -webkit-background-clip: text; -webkit-text-fill-color: transparent; background-clip: text;
}
.ocp-offers .featured-banner.market-making-games-banner .featured-banner-feature {
  background: rgba(192,132,252,0.10); border-color: rgba(192,132,252,0.22); color: #f0d4ff;
}
.ocp-offers .featured-banner.market-making-games-banner .featured-banner-feature::before { color: #ec4899; }
.ocp-offers .featured-banner.market-making-games-banner .featured-banner-image.market-making-games-logo {
  filter: drop-shadow(0 0 8px rgba(192,132,252,0.4)); width: 58px;
}

/* the drifting symbols behind the content */
.ocp-offers .banner-float-icon {
  position: absolute; pointer-events: none; z-index: 1; font-weight: bold;
  animation: ocpBannerFloat 18s ease-in-out infinite;
}
.ocp-offers .trading-interview-banner .banner-float-icon {
  color: #ae1f19;
  text-shadow: 0 0 12px rgba(174,31,25,0.8), 0 0 24px rgba(174,31,25,0.6), 0 0 36px rgba(174,31,25,0.3);
  filter: drop-shadow(0 0 6px rgba(174,31,25,0.8));
}
.ocp-offers .trading-interview-banner .banner-float-icon:nth-child(1) { top: 8%;  left: 6%;  font-size: 12px; animation-duration: 18s; animation-delay: 0s; }
.ocp-offers .trading-interview-banner .banner-float-icon:nth-child(2) { top: 15%; right: 8%; font-size: 9px; animation-duration: 22s; animation-delay: 2s; }
.ocp-offers .trading-interview-banner .banner-float-icon:nth-child(3) { bottom: 22%; left: 10%; font-size: 10px; animation-duration: 20s; animation-delay: 4s; }
.ocp-offers .trading-interview-banner .banner-float-icon:nth-child(4) { bottom: 10%; right: 10%; font-size: 9px; animation-duration: 19s; animation-delay: 1s; }
.ocp-offers .trading-interview-banner .banner-float-icon:nth-child(5) { top: 50%; left: 4%; font-size: 9px; animation-duration: 23s; animation-delay: 3s; }
.ocp-offers .trading-interview-banner .banner-float-icon:nth-child(6) { top: 35%; right: 5%; font-size: 11px; animation-duration: 17s; animation-delay: 5s; }
.ocp-offers .market-making-games-banner .banner-float-icon {
  color: #ec4899;
  text-shadow: 0 0 12px rgba(236,72,153,0.8), 0 0 24px rgba(192,132,252,0.55), 0 0 36px rgba(124,58,237,0.35);
  filter: drop-shadow(0 0 6px rgba(236,72,153,0.7));
}
.ocp-offers .market-making-games-banner .banner-float-icon:nth-child(1) { top: 9%;  left: 7%;  font-size: 12px; animation-duration: 18s; animation-delay: 0s; }
.ocp-offers .market-making-games-banner .banner-float-icon:nth-child(2) { top: 17%; right: 9%; font-size: 9px; animation-duration: 22s; animation-delay: 2s; }
.ocp-offers .market-making-games-banner .banner-float-icon:nth-child(3) { bottom: 24%; left: 10%; font-size: 10px; animation-duration: 20s; animation-delay: 4s; }
.ocp-offers .market-making-games-banner .banner-float-icon:nth-child(4) { bottom: 11%; right: 11%; font-size: 9px; animation-duration: 19s; animation-delay: 1s; }
.ocp-offers .market-making-games-banner .banner-float-icon:nth-child(5) { top: 52%; left: 4%; font-size: 9px; animation-duration: 23s; animation-delay: 3s; }
.ocp-offers .market-making-games-banner .banner-float-icon:nth-child(6) { top: 38%; right: 5%; font-size: 11px; animation-duration: 17s; animation-delay: 5s; }

@keyframes ocpBannerFloat {
  0%,100% { transform: translate(0,0) rotate(0deg);          opacity: 0.35; }
  25%     { transform: translate(10px,-15px) rotate(90deg);  opacity: 0.5; }
  50%     { transform: translate(-8px,-25px) rotate(180deg); opacity: 0.4; }
  75%     { transform: translate(12px,-10px) rotate(270deg); opacity: 0.5; }
}
/* drifting symbols are decoration; respect a reduced-motion preference */
@media (prefers-reduced-motion: reduce) {
  .ocp-offers .banner-float-icon { animation: none; opacity: .3; }
  .ocp-offers .featured-banner, .ocp-offers .featured-banner::before { transition: none; }
}

/* ── subtitle size slider ────────────────────────────────────────────────
   Three fixed sizes were not enough, and the largest was too small to read
   from any distance. Nine steps, with an Aa at each end showing the range. */
.ocp-capsize { display: flex; align-items: center; gap: 10px; }
.ocp-capsize input[type="range"] {
  flex: 1 1 auto; min-width: 90px; height: 4px; -webkit-appearance: none; appearance: none;
  background: var(--oc-line); border-radius: 999px; outline: none; cursor: pointer;
}
.ocp-capsize input[type="range"]::-webkit-slider-thumb {
  -webkit-appearance: none; appearance: none; width: 15px; height: 15px; border-radius: 50%;
  background: var(--oc-red-br); border: 2px solid var(--oc-ink); cursor: grab;
  box-shadow: 0 1px 5px rgba(0,0,0,.4);
}
.ocp-capsize input[type="range"]::-moz-range-thumb {
  width: 15px; height: 15px; border-radius: 50%; background: var(--oc-red-br);
  border: 2px solid var(--oc-ink); cursor: grab;
}
.ocp-capsize input[type="range"]:focus-visible { outline: 2px solid var(--oc-red-br); outline-offset: 3px; }
.ocp-capsize .capsw { flex: 0 0 auto; opacity: .6; width: auto; }
.ocp-capsize__v {
  float: right; font-size: .68rem; font-weight: 600; letter-spacing: .04em;
  text-transform: none; color: var(--oc-red-br);
}

/* ── gate buttons ────────────────────────────────────────────────────────
   Two inline-blocks separated by an inline margin ran into each other once
   the line wrapped. A flex row that stacks below 420px instead. */
.ocp-gate__btns { display: flex; flex-wrap: wrap; gap: 10px; justify-content: center; }
.ocp-gate__btns .ocp-btn { flex: 0 1 auto; }
@media (max-width: 420px) {
  .ocp-gate__btns { flex-direction: column; align-items: stretch; }
  .ocp-gate__btns .ocp-btn { width: 100%; text-align: center; }
}

/* ── header controls on a phone ──────────────────────────────────────────
   Centring a ragged row left odd gaps and orphans. Lay the four controls out
   on a two-column grid so they line up, and let the reference chips flow. */
@media (max-width: 760px) {
  .ocp-head { row-gap: 10px; }
  .ocp-ctrls {
    display: grid; grid-template-columns: 1fr 1fr; gap: 8px; width: 100%;
    justify-content: stretch; align-items: stretch;
  }
  .ocp-ctrls .ocp-toggle { grid-column: 1 / -1; justify-content: center; }
  .ocp-ctrls .ocp-viewbtn { width: 100%; justify-content: center; margin-left: 0; }
  .ocp-tools { display: flex; flex-wrap: wrap; justify-content: center; gap: 7px; }
  .ocp-me { gap: 10px; row-gap: 10px; }
  .ocp-offers { padding: 0 14px; }
  .ocp-offers .featured-banner { padding: 13px 14px; }
}

/* the takeover button on the "playing somewhere else" placeholder */
.ocp-ph-take { margin-top: 14px; padding: 10px 20px; font-size: .86rem; }
.ocp-ph-take[disabled] { opacity: .6; cursor: default; transform: none; }

/* Arrangement: the two roomy layouts are not offered on a phone. Hidden rather
   than disabled, since a greyed-out control invites a tap that does nothing. */
@media (max-width: 760px) {
  .ocp-view__opts[data-set="layout"] button[data-v="split"],
  .ocp-view__opts[data-set="layout"] button[data-v="slides"] { display: none; }
  .ocp-view__opts[data-set="layout"] { grid-template-columns: 1fr 1fr; }
}


/* ── Progress panel: video quizzes left, module tests right (26 Sep 2026) ── */
.ocp-modal__box--wide { width: min(1080px, 100%); }
.ocp-prog2 { display: grid; grid-template-columns: 1fr; gap: 26px; }
@media (min-width: 860px) { .ocp-prog2 { grid-template-columns: 1fr 1fr; gap: 30px; } }
.ocp-prog2 > section { display: grid; gap: 8px; align-content: start; min-width: 0; }
.ocp-prog2__h { margin: 0; font-size: .95rem; font-weight: 800; color: var(--oc-text); letter-spacing: -.01em; }
.ocp-prog2 .ocp-ql__h:first-child { margin-top: 0; }
a.ocp-ql__row { text-decoration: none; }
.ocp-prog2__go { margin-top: 6px; font-weight: 700; font-size: .86rem; text-decoration: none; }
[data-theme="light"] .ocp-prog2__h { color: #1a0a08; }
.ocp-modal a.ocp-ql__row { color: inherit; }

/* Phones: the header is a centred column, so the address must not keep the
   desktop margin-left:auto that pins it to the right. */
@media (max-width: 760px) { .ocp-head > #ocp-who { margin-left: 0; margin-right: 0; align-self: center; text-align: center; } }
