Lesson elements reference

Every content element used in a lesson, with the exact HTML to paste. Copy from the snippet block under each example. All elements read from brand/tokens.css, no per-page styling needed.

1. YouTube embed (unlisted or public)

Free, fast globally, decent player. YouTube branding is visible.

<iframe class="embed-iframe"
  src="https://www.youtube.com/embed/YOUR_VIDEO_ID"
  loading="lazy"
  allowfullscreen></iframe>

2. Vimeo embed (paid, ~10 EUR/mo)

Clean player, password and domain locks, no ads.

<iframe class="embed-iframe"
  src="https://player.vimeo.com/video/YOUR_VIDEO_ID"
  loading="lazy"
  allow="autoplay; fullscreen; picture-in-picture"
  allowfullscreen></iframe>

3. Loom embed

Easy upload from desktop. Loom branding visible. Good for casual screen captures.

<iframe class="embed-iframe"
  src="https://www.loom.com/embed/YOUR_LOOM_ID"
  loading="lazy"
  allowfullscreen></iframe>

4. Self-hosted MP4 video

Plays on your domain. Anti-download flags are a soft deterrent (anyone determined can save it). Files live in body/website/videos/ and ship with the rsync deploy.

<video controls
  controlsList="nodownload"
  disablePictureInPicture
  oncontextmenu="return false"
  preload="metadata"
  poster="/videos/example-poster.png"
  style="width:100%;border-radius:16px;">
  <source src="/videos/example.mp4" type="video/mp4">
  Your browser cannot play this video.
</video>

5. Self-hosted audio (MP3 or M4A)

Pill-shaped player. Same hosting rules as video.

<audio controls
  controlsList="nodownload"
  preload="metadata"
  style="width:100%;border-radius:999px;">
  <source src="/videos/example.mp3" type="audio/mpeg">
</audio>

6. Code block

supabase functions deploy stripe-course-webhook
supabase secrets set STRIPE_WEBHOOK_SECRET=whsec_xxx
<pre style="background:var(--color-bg-soft);padding:1rem;border-radius:12px;overflow-x:auto;
  font-family:ui-monospace,Menlo,monospace;font-size:.8125rem;line-height:1.6;
  margin:.75rem 0">
your code here
</pre>

7. Inline code

Replace YOUR_PROJECT_ID with the value from your Supabase dashboard.

<code style="background:var(--color-bg-soft);padding:.15rem .4rem;border-radius:6px;
  font-family:ui-monospace,Menlo,monospace;font-size:.875rem">
inline_code
</code>

8. Callout / note box

Important

Webhooks must be HTTPS. Stripe will not deliver to localhost. Use a tunnel like ngrok or deploy to Supabase before testing.

<div class="callout">
  <div class="callout-title">Important</div>
  <p>The body of the callout.</p>
</div>

9. Resource card (link out)

Use for links to docs, tools, GitHub repos, downloads.

Stripe Checkout docs

Reference for the payment flow used in this lesson.

<a href="https://example.com" target="_blank" class="resource-card">
  <div class="resource-icon">
    <svg viewBox="0 0 24 24" fill="none" stroke="white" stroke-width="2">
      <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>
      <polyline points="14 2 14 8 20 8"/>
    </svg>
  </div>
  <div class="resource-info">
    <p class="resource-title">Title</p>
    <p class="resource-desc">One-line description.</p>
  </div>
  <svg class="resource-arrow" width="18" height="18" viewBox="0 0 24 24"
    fill="none" stroke="currentColor" stroke-width="2">
    <polyline points="9 18 15 12 9 6"/>
  </svg>
</a>

10. Downloadable resource

PDF, zip, anything. The download attribute hints to the browser to save instead of open.

Download example.zip
<a class="btn btn-secondary"
   href="/files/your-file.zip"
   download="your-file.zip">
  Download your-file.zip
</a>

11. Image with caption

Description for screen readers
The figcaption sits under the image, italic, muted.
<figure class="lesson-image">
  <img src="/path/to/image.png" alt="Description for screen readers">
  <figcaption>Caption text.</figcaption>
</figure>

12. Generic iframe embed (Tally, Cal.com, Notion, Figma, etc.)

Anything you can embed via iframe. Use the tall modifier for portrait aspect ratios (forms, calendars).

<iframe class="embed-iframe tall"
  src="https://tally.so/embed/YOUR_FORM_ID"
  loading="lazy"></iframe>