Files Origin · The Magnus Institute ● Link Secure Clearance 05 SYS 0451
THE BUREAU obsidian declassified
File OCV-04232005 Clearance 05 · SEALED Vol. I · Jun 14, 2026
The Red Demon

YouTube

Statement Begins

A thumbnail, a channel, a runtime, a link. Not much, until the card builds the strip you would see under a player: the still up top, the channel as a byline, the runtime where it belongs.

It keeps the road back to the source, the url and the id, so the note is always one click from the thing itself.

A bookmark that grew a face, out of the few lines I saved when I filed it.

Custom Views Code

<div class="video-card" data-name="{{file.name}}" data-url="{{url}}" data-vid="{{video_id}}">
    <!-- Hero: thumbnail + gradient -->
    <div class="hero">
        <img id="bgImg" class="hero-img" src="{{banner}}" crossorigin="anonymous" alt="" />
        <div class="hero-gradient" id="gradientOverlay"></div>
    </div>

    <!-- Content overlaps hero -->
    <div class="content-area">
        <div class="info-row">
            <div class="movie-info">
                <p class="movie-title">{{file.basename}}</p>
                <p class="movie-genre vid-channel"></p>
                <p class="movie-desc vid-lead"></p>
                <div class="meta-row">
                    <p class="movie-meta vid-meta"></p>
                </div>
                <a class="vid-watch" target="_blank" rel="noopener">
                    <span class="vid-play" aria-hidden="true"></span>
                    <span class="vid-watch-label">Watch<br>on YouTube</span>
                </a>
            </div>
        </div>

        <div class="bottom-section">
            <div class="file-content-wrap">
                <button class="movie-more" type="button">SHOW MORE</button>
                <div class="movie-notes"></div>
            </div>
        </div>
    </div>
</div>
/* ============================================================
   Harker — shared Movies/Shows card CSS
   Used by the Custom Views "Movies" (harker-movies) and "Shows"
   (harker-shows) views. Both render .movie-card; this is loaded
   once here instead of duplicated in each view's css field.
   (Games/Books/Albums have their own gv-/bk-/alb- styles.)
   ============================================================ */

.obsidian-custom-view-editable .obsidian-custom-view-render, .obsidian-custom-view-render {
    padding: 0 !important;
    --line-width: 100%;
    --max-width: none;
}
.file-content-wrap .markdown-rendered-content.markdown-preview-view.markdown-rendered {
    margin: 0;
    padding: 0;
} 

blockquote {
        color: var(--blockquote-color);
    font-style: var(--blockquote-font-style);
    background-color: var(--blockquote-background-color);
    border-inline-start: var(--blockquote-border-thickness) solid var(--blockquote-border-color);
    padding-top: 0;
    padding-bottom: 0;
    padding-inline-start: var(--size-4-6);
    margin-inline-start: 0;
    margin-inline-end: 0;
}
.cm-content.cm-lineWrapping {
    padding-bottom: 40px !important;
}
/* ================================================================
   Movie Card — Obsidian Custom View
   Faithful translation of Figma node 1:2
   ================================================================ */
.obsidian-custom-view-render, .obsidian-custom-view-editable .obsidian-custom-view-render {
    padding: 0;
}


.movie-card {
  background-color: var(--color-bg, #7baaba);
  position: relative;
  width: 100%;
  padding-bottom: 145px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
  caret-color: pink;
}

/* ── Hero ──────────────────────────────────────────────────────── */
.hero {
  position: absolute;
  width: 100%;
  flex-shrink: 0;
  line-height: 0;
}

.hero-img {
  display: block;
  width: 100%;
  aspect-ratio: 3840 / 2160;
  object-fit: cover;
  max-width: none;
}

/* Gradient overlay.
   Figma: div starting at mt-372px, h-600px, inside 972px hero.
   Stop 1 (transparent): 372 + 600×23.5%  = 513px from hero top = 52.77% of 972
   Stop 2 (solid):       372 + 600×53.08% = 690.5px            = 71.04% of 972
   Applied as inset-0 so % are of the image height at any width. */
.hero-gradient {
  position: absolute;
  inset: 0;
  background: linear-gradient(to bottom,
    transparent 52.77%,
    var(--color-bg, #7baaba) 71.04%
  );
  pointer-events: none;
}

/* ── Content area ──────────────────────────────────────────────── */
/* Figma: absolute top-583px over a 972px hero.
   HTML: negative margin = 583px - (image height as % of width).
   Image aspect 3840/2160 → height = width × 56.25%.
   So margin-top: calc(583px - 56.25%) replicates the overlap at any width. */
.content-area {
  margin-top: calc(100% * (6/16));
  position: relative;
  z-index: 1;
  width: 100%;
  box-sizing: border-box;
  padding: 0 100px 10px;
  display: flex;
  flex-direction: column;
  gap: 20px;
  align-items: flex-start;
}

/* ── Info row ──────────────────────────────────────────────────── */
.info-row {
  display: flex;
  flex-wrap: wrap;
  row-gap: 20px;
  column-gap: 30px;
  align-items: flex-end;
  justify-content: space-between;
  flex-shrink: 0;
  width: 100%;
}

/* Left: title / genre / description / meta */
.movie-info {
  display: flex;
  flex: 1 0 0;
  flex-direction: column;
  gap: 12px;
  align-items: flex-start;
  max-width: 900px;
  min-width: 800px;
  overflow: clip;
}

.movie-title {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'SF Pro', sans-serif;
  font-size: calc(36px + 1.5vw);
  font-weight: 500;
  line-height: normal;
  color: var(--text-normal);
  letter-spacing: -1.28px;
  width: 100%;
  margin: 0;
  word-break: break-word;
}

.movie-genre {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 24px;
  font-weight: 510;
  line-height: normal;
  color: var(--text-muted);
  letter-spacing: -0.48px;
  width: 100%;
  margin: 0;
  word-break: break-word;
}

.movie-genre a {
    text-decoration: none;
    color: var(--text-muted);
}
.movie-genre a:hover {
    text-decoration: none;
    color: var(--color-base-80);
}

.movie-desc {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 18px;
  font-weight: 400;
  line-height: 1.6;
  color: var(--text-muted);
  letter-spacing: -0.36px;
  width: 100%;
  margin: 0;
  word-break: break-word;
}

.meta-row {
  display: flex;
  align-items: center;
  justify-content: center;
  flex-shrink: 0;
  width: 100%;
}

.movie-meta {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 18px;
  font-weight: 400;
  line-height: normal;
  color: var(--text-faint);
  letter-spacing: -0.36px;
  flex: 1 0 0;
  min-width: 1px;
  margin: 0;
  word-break: break-word;
}

/* Right: Starring / Director */
.starring-col {
  display: flex;
  flex: 1 0 0;
  flex-direction: column;
  align-items: flex-start;
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 16px;
  font-weight: 400;
  line-height: 1.6;
  letter-spacing: -0.32px;
  max-width: 400px;
  min-width: 400px;
  overflow: clip;
  padding-top: 29px;
}

.starring-row {
  display: flex;
  gap: 10px;
  align-items: flex-start;
  flex-shrink: 0;
  width: 100%;
}

.starring-label {
  color: var(--text-faint);
  white-space: nowrap;
  flex-shrink: 0;
  margin: 0;
}

.starring-value {
  flex: 1 0 0;
  min-width: 1px;
  color: var(--text-muted);
  margin: 0;
}

.starring-value a {
    text-decoration: none;
    color: var(--text-normal);
}

/* ── Bottom section ────────────────────────────────────────────── */
.bottom-section {
  display: flex;
  flex-direction: column;
  gap: 20px;
  align-items: flex-start;
  padding-top: 30px;
  flex-shrink: 0;
  width: 100%;
}

/* Content + Watch Now row */
.content-watch-row {
  display: flex;
  gap: 30px;
  align-items: flex-start;
  flex-shrink: 0;
  width: 100%;
    justify-content: space-between;
}

.file-content-wrap {

  flex-shrink: 0;
    flex-grow: 1;
  width: auto;
    max-width: 700px;
}

.file-content-text {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 18px;
  font-weight: 400;
  line-height: 1.6;
  color: var(--text-muted);
  letter-spacing: -0.36px;
  flex: 1 0 0;
  min-width: 1px;
  margin: 0;
  word-break: break-word;
}

.watch-col {
  display: flex;
  flex: 1 0 0;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  min-width: 1px;
    max-width: 400px;
}

.watch-row {
  display: flex;
  gap: 10px;
  align-items: center;
  flex-shrink: 0;
  width: 100%;
}

.watch-label {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 22px;
  font-weight: 400;
  line-height: 1.6;
  color: var(--text-normal);
  letter-spacing: -0.44px;
  flex-shrink: 0;
  white-space: nowrap;
  margin: 0;
}

/* 4K badge: CSS grid stack (bg rect + text overlapping) */
.badge-4k {
  display: inline-grid;
  grid-template-columns: max-content;
  grid-template-rows: max-content;
  line-height: 0;
  place-items: start;
  flex-shrink: 0;
}

.badge-4k-bg {
  grid-column: 1;
  grid-row: 1;
  background-color: var(--color-base-30);
  height: 27px;
  width: 44px;
  border-radius: 7px;
}

.badge-4k-text {
  grid-column: 1;
  grid-row: 1;
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 14px;
  font-weight: 510;
  line-height: 1.6;
  color: var(--text-muted);
  letter-spacing: -0.28px;
  white-space: nowrap;
  margin-left: 13px;
  margin-top: 3px;
}

/* ── Trailers ──────────────────────────────────────────────────── */
.trailers-section {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
  flex-shrink: 0;
  width: 100%;
}

.section-heading {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 24px;
  font-weight: 400;
  line-height: 1.6;
  color: var(--text-normal);
  letter-spacing: -0.48px;
  white-space: nowrap;
  flex-shrink: 0;
  margin: 0;
}

.trailers-row {
  display: flex;
  gap: 20px;
    width: 100%;
    overflow: scroll;
  align-items: flex-start;
  flex-shrink: 0;
}

.trailer-card {
  position: relative;
  height: 159px;
  width: 282px;
  border-radius: 8px;
  flex-shrink: 0;
  overflow: hidden;
  cursor: pointer;
}

.trailer-thumb {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  max-width: none;
}

.trailer-dark-overlay {
  position: absolute;
  inset: 0;
  background: rgba(0, 0, 0, 0.2);
  pointer-events: none;
}

/* ── Cast and Crew ─────────────────────────────────────────────── */
.cast-section {
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
  flex-shrink: 0;
  width: 100%;
}

.cast-row {
  display: flex;
  align-items: flex-start;
  flex-shrink: 0;
  width: 100%;
    overflow: scroll;
}

.cast-inner {
  display: flex;
  flex: 1 0 0;
  gap: 20px;
  align-items: flex-start;
  min-width: 1px;
}

.cast-card {
  display: flex;
  flex-direction: column;
  gap: 16px;
  align-items: flex-start;
  flex-shrink: 0;
}

.cast-portrait {
  height: 179px;
  width: 120px;
  border-radius: 8px;
  object-fit: cover;
  display: block;
  flex-shrink: 0;
}

.cast-avatar {
  height: 179px;
  width: 120px;
  border-radius: 8px;
  background-color: var(--color-base-20, #2a2a2a);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--text-faint);
  font-size: 36px;
  font-weight: 300;
  flex-shrink: 0;
}

.cast-info {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  line-height: 1.6;
  flex-shrink: 0;
  width: 120px;
  word-break: break-word;
}

.cast-name {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 16px;
  font-weight: 400;
  letter-spacing: -0.32px;
  color: var(--text-normal);
  width: 100%;
  margin: 0;
}

.cast-role {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 14px;
  font-weight: 400;
  font-style: italic;
  letter-spacing: -0.28px;
  color: var(--text-muted);
  width: 100%;
  margin: 0;
}

.tmdb-loading {
  font-family: -apple-system, sans-serif;
  font-size: 14px;
  color: var(--text-faint);
}

/* ===== RESPONSIVE (added 2026-05-29) — narrow panes / mobile =====
   Gated >=1000px so desktop is unchanged; container queries + @media fallback. */
.movie-card { container-type: inline-size; container-name: mv; }

@container mv (max-width: 1000px) {
  .content-area { padding-left: clamp(18px, 5cqw, 100px); padding-right: clamp(18px, 5cqw, 100px); }
  .info-row { flex-direction: column; align-items: stretch; flex-wrap: nowrap; }
  .movie-info { min-width: 0; max-width: none; }
  .starring-col { min-width: 0; max-width: none; padding-top: 0; }
  .content-watch-row { flex-direction: column; gap: 20px; }
  .watch-col { max-width: none; align-items: flex-start; }
  .file-content-wrap { max-width: none; }
}
@container mv (max-width: 560px) {
  .content-area { padding-left: 18px; padding-right: 18px; }
  .movie-title { font-size: clamp(28px, 9cqw, 40px); }
}

@media (max-width: 1000px) {
  .content-area { padding-left: clamp(18px, 5vw, 100px); padding-right: clamp(18px, 5vw, 100px); }
  .info-row { flex-direction: column; align-items: stretch; flex-wrap: nowrap; }
  .movie-info { min-width: 0; max-width: none; }
  .starring-col { min-width: 0; max-width: none; padding-top: 0; }
  .content-watch-row { flex-direction: column; gap: 20px; }
  .watch-col { max-width: none; align-items: flex-start; }
  .file-content-wrap { max-width: none; }
}
@media (max-width: 560px) {
  .content-area { padding-left: 18px; padding-right: 18px; }
  .movie-title { font-size: clamp(28px, 9vw, 40px); }
}

/* ── SHOW MORE button + collapsible notes (added 2026-05-30) ──────
   Mirrors the Albums card: body is hidden until the pill is pressed. */
.movie-more {
  display: inline-block;
  align-self: flex-start;
  font: 600 12px/1 -apple-system, BlinkMacSystemFont, sans-serif;
  letter-spacing: .12em;
  color: var(--text-normal);
  background: var(--background-modifier-hover);
  border: 1px solid var(--background-modifier-border);
  padding: 10px 18px;
  border-radius: 999px;
  cursor: pointer;
  transition: background .15s ease;
}
.movie-more:hover { background: var(--background-modifier-active-hover); }
.movie-notes {
  display: none;
  margin-top: 16px;
  font-size: 18px;
  line-height: 1.6;
  color: var(--text-muted);
}
.movie-card.notes-open .movie-notes,
.video-card.notes-open .movie-notes { display: block; }
.movie-notes > :first-child { margin-top: 0; }

/* ── Computed 0–100 score + verdict (shared by movies/shows/books/games cards;
   the Albums card has its own .alb-score). Added 2026-05-30. ────────── */
.media-score {
  display: flex;
  flex-direction: column;
  gap: 3px;
  margin: 4px 0;
}
.media-score-num {
  font: 600 clamp(30px, 3vw, 42px)/1 -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif;
  letter-spacing: -1.2px;
  color: var(--text-normal);
}
.media-score-num[data-empty] {
  font-size: 17px;
  font-weight: 500;
  letter-spacing: 0;
  color: var(--text-faint);
}
.media-verdict {
  font-size: 14px;
  line-height: 1.45;
  color: var(--text-muted);
}

/* ============================================================
   Videos card (harker-videos) — YouTube hero.
   Reuses the Movies hero/info/notes classes above; this block
   only adds the .video-card shell, the channel byline link and
   the round "Watch on YouTube" play button. Added 2026-06-02.
   ============================================================ */
.video-card {
  background-color: var(--color-bg, #7baaba);
  position: relative;
  width: 100%;
  padding-bottom: 145px;
  box-sizing: border-box;
  display: flex;
  flex-direction: column;
  gap: 10px;
  align-items: flex-start;
  container-type: inline-size;
  container-name: mv;
}

/* channel byline reuses .movie-genre sizing; make its link inherit */
.vid-channel a { text-decoration: none; color: var(--text-muted); }
.vid-channel a:hover { color: var(--color-base-80); text-decoration: none; }

/* lead paragraph (TL;DW) — slightly tighter than a full .movie-desc */
.vid-lead { max-width: 760px; }

/* meta row: left-aligned for videos (movies centre it) */
.video-card .meta-row { justify-content: flex-start; }

/* ── Watch on YouTube — round red play button + label ─────────── */
.vid-watch {
  display: inline-flex;
  align-items: center;
  gap: 16px;
  margin-top: 8px;
  text-decoration: none;
  cursor: pointer;
}
.vid-watch:hover { text-decoration: none; }
.vid-play {
  position: relative;
  width: 58px;
  height: 58px;
  border-radius: 999px;
  background: #f5000f;
  flex-shrink: 0;
  box-shadow: 0 6px 24px rgba(245, 0, 15, 0.35);
  transition: transform .15s ease, box-shadow .15s ease;
}
.vid-play::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 54%;
  transform: translate(-50%, -50%);
  border-style: solid;
  border-width: 11px 0 11px 18px;
  border-color: transparent transparent transparent #fff;
}
.vid-watch:hover .vid-play {
  transform: scale(1.06);
  box-shadow: 0 8px 30px rgba(245, 0, 15, 0.5);
}
.vid-watch-label {
  font-family: -apple-system, BlinkMacSystemFont, 'SF Pro', sans-serif;
  font-size: 20px;
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.4px;
  color: var(--text-normal);
}

@container mv (max-width: 1000px) {
  .vid-lead { max-width: none; }
}
/* ================================================================
   Harker — YouTube "Videos" custom view
   Reuses the Movies Flexoki palette engine (samples the thumbnail's
   dominant colour and repaints the card), minus TMDB/cast/score.
   Idea-capture, not a review.
   ================================================================ */
const _container = this;

/* ===== COLOR MATH — sRGB / OKLCH / HSL ===== */
function hexToRGB(hex) {
    const h = hex.replace("#", "");
    return [parseInt(h.slice(0,2),16)/255, parseInt(h.slice(2,4),16)/255, parseInt(h.slice(4,6),16)/255];
}
function rgbToHex(r, g, b) {
    return "#" + [r,g,b].map(v => Math.round(Math.max(0,Math.min(255,v*255))).toString(16).padStart(2,"0")).join("");
}
function rgbToHSL(r, g, b) {
    const max = Math.max(r,g,b), min = Math.min(r,g,b);
    const l = (max+min)/2;
    if (max === min) return [0,0,l*100];
    const d = max-min;
    const s = l > 0.5 ? d/(2-max-min) : d/(max+min);
    let h;
    switch (max) { case r: h = ((g-b)/d+(g<b?6:0))/6; break; case g: h = ((b-r)/d+2)/6; break; default: h = ((r-g)/d+4)/6; }
    return [h*360, s*100, l*100];
}
function sRGBToLinear(v) { return v <= 0.04045 ? v/12.92 : Math.pow((v+0.055)/1.055, 2.4); }
function linearToSRGB(v) { return v <= 0.0031308 ? 12.92*v : 1.055*Math.pow(v,1/2.4)-0.055; }
function relativeLuminance(hex) { return hexToRGB(hex).map(sRGBToLinear).reduce((s,v,i)=>s+v*[0.2126,0.7152,0.0722][i],0); }
function hexToOKLCH(hex) {
    let [r,g,b] = hexToRGB(hex).map(sRGBToLinear);
    const l = 0.4122214708*r+0.5363325363*g+0.0514459929*b;
    const m = 0.2119034982*r+0.6806995451*g+0.1073969566*b;
    const s = 0.0883024619*r+0.2817188376*g+0.6299787005*b;
    const l_=Math.cbrt(l), m_=Math.cbrt(m), s_=Math.cbrt(s);
    const L = 0.2104542553*l_+0.793617785*m_-0.0040720468*s_;
    const a = 1.9779984951*l_-2.428592205*m_+0.4505937099*s_;
    const bk = 0.0259040371*l_+0.7827717662*m_-0.808675766*s_;
    const C = Math.sqrt(a*a+bk*bk);
    const H = ((Math.atan2(bk,a)*180)/Math.PI+360)%360;
    return [L,C,H];
}
function OKLCHToHex(L, C, H) {
    const a = C*Math.cos((H*Math.PI)/180);
    const bk = C*Math.sin((H*Math.PI)/180);
    const l_ = L+0.3963377774*a+0.2158037573*bk;
    const m_ = L-0.1055613458*a-0.0638541728*bk;
    const s_ = L-0.0894841775*a-1.291485548*bk;
    const lv=l_*l_*l_, mv=m_*m_*m_, sv=s_*s_*s_;
    const r = linearToSRGB(4.0767416621*lv-3.3077115913*mv+0.2309699292*sv);
    const g = linearToSRGB(-1.2684380046*lv+2.6097574011*mv-0.3413193965*sv);
    const b = linearToSRGB(-0.0041960863*lv-0.7034186147*mv+1.707614701*sv);
    return rgbToHex(r,g,b);
}
function multiplyColors(hex1, hex2) {
    const [r1,g1,b1] = hexToRGB(hex1); const [r2,g2,b2] = hexToRGB(hex2);
    return rgbToHex(r1*r2,g1*g2,b1*b2);
}
function buildScale(hex) {
    const PAPER = "#FFFCF0", BLACK = "#100F0F";
    const [L0,C0,H0] = hexToOKLCH(hex);
    const [Lp] = hexToOKLCH(PAPER); const [Lb] = hexToOKLCH(BLACK);
    const L400 = Lp+(L0-Lp)*0.88, C400 = C0*0.82;
    const L600 = L0+(Lb-L0)*0.18, C600 = C0*0.92;
    const scale = { paper: PAPER, black: BLACK };
    for (const step of [50,100,150,200,300,400,500,600,700,800,850,875,900,950]) {
        if (step < 400) { const t=step/400, te=t*t*(3-2*t); scale[step]=multiplyColors(OKLCHToHex(Lp+(L400-Lp)*te,C400*te,H0),PAPER); }
        else if (step === 400) scale[step]=multiplyColors(OKLCHToHex(L400,C400,H0),PAPER);
        else if (step === 500) scale[step]=hex;
        else if (step === 600) scale[step]=OKLCHToHex(L600,C600,H0);
        else { const t=(step-600)/400, te=t*t*(3-2*t); scale[step]=OKLCHToHex(L600+(Lb-L600)*te,C600*(1-te),H0); }
    }
    return scale;
}
function sampleDominantColor(img) {
    try {
        const canvas = document.createElement("canvas");
        canvas.width = 200; canvas.height = 20;
        const ctx = canvas.getContext("2d");
        ctx.drawImage(img, 0, img.naturalHeight*0.88, img.naturalWidth, img.naturalHeight*0.12, 0, 0, 200, 20);
        const d = ctx.getImageData(0,0,200,20).data;
        let R=0,G=0,B=0,n=0;
        for (let i=0;i<d.length;i+=4){R+=d[i];G+=d[i+1];B+=d[i+2];n++;}
        return "#" + [Math.round(R/n),Math.round(G/n),Math.round(B/n)].map(v=>v.toString(16).padStart(2,"0")).join("");
    } catch { return null; }
}
function applyPalette(sampledHex) {
    const scale = buildScale(sampledHex);
    const lum = relativeLuminance(sampledHex);
    const isLight = lum > 0.179;
    const bg = sampledHex;
    const [r,g,b] = hexToRGB(bg).map(v=>Math.round(v*255));
    const ordered = [scale.paper,scale[50],scale[100],scale[150],scale[200],scale[300],scale[400],scale[500],scale[600],scale[700],scale[800],scale[850],scale[875],scale[900],scale.black];
    const baseOrder = isLight ? ordered : [...ordered].reverse();
    const baseMap = {"00":baseOrder[0],"05":baseOrder[1],"10":baseOrder[2],"20":baseOrder[3],"25":baseOrder[4],"30":baseOrder[5],"35":baseOrder[6],"40":baseOrder[7],"50":baseOrder[8],"60":baseOrder[9],"70":baseOrder[10],"80":baseOrder[11],"85":baseOrder[12],"90":baseOrder[13],"100":baseOrder[14]};
    const [aR,aG,aB] = hexToRGB(scale[500]);
    const [accentH,accentS,accentL] = rgbToHSL(aR,aG,aB);
    const textNormal=baseMap["100"], textMuted=baseMap["85"], textFaint=baseMap["70"];
    const bgPrimary=baseMap["00"], bgSecond=baseMap["05"], bgHover=baseMap["10"];
    const bgModifierBorder = isLight ? baseMap["30"] : baseMap["70"];
    const bgModifierBorderHover = isLight ? baseMap["35"] : baseMap["65"];
    const bgModifierBorderFocus = isLight ? baseMap["40"] : baseMap["60"];
    const S = ".obsidian-custom-view-render, .obsidian-custom-view-editable .obsidian-custom-view-render";
    const baseVars = Object.entries(baseMap).map(([k,v])=>`    --color-base-${k}: ${v.toUpperCase()};`).join("\n");
    const css = `
${S} {
    --color-bg: ${bg};
    --color-gradient-start: rgba(${r},${g},${b},0);
    --accent-h: ${accentH.toFixed(1)};
    --accent-s: ${accentS.toFixed(1)}%;
    --accent-l: ${accentL.toFixed(1)}%;
${baseVars}
    --background-primary: ${bg};
    --background-secondary: ${bgSecond};
    --background-modifier-border: ${bgModifierBorder};
    --background-modifier-border-hover: ${bgModifierBorderHover};
    --background-modifier-border-focus: ${bgModifierBorderFocus};
    --background-modifier-hover: ${bgHover};
    --background-modifier-form-field: ${bgHover};
    --table-border-color: ${bgModifierBorder};
    --text-normal: ${textNormal};
    --text-muted: ${textMuted};
    --text-faint: ${textFaint};
    --blockquote-border-color: ${textFaint};
    --interactive-accent: ${textFaint};
    --text-on-accent: ${isLight ? scale.black : scale.paper};
    --text-on-accent-inverted: ${isLight ? scale.paper : scale.black};
    color: ${textNormal};
    background-color: ${bgPrimary};
}
${S} .theme-light, ${S} .theme-dark {
${baseVars}
    --accent-h: ${accentH.toFixed(1)};
    --accent-s: ${accentS.toFixed(1)}%;
    --accent-l: ${accentL.toFixed(1)}%;
    --text-normal: ${textNormal};
    --text-muted: ${textMuted};
    --text-faint: ${textFaint};
    --link-color: ${textNormal};
    --background-primary: ${bgPrimary};
    --background-secondary: ${bgSecond};
    --bases-table-header-background: ${bg};
    --bases-table-header-color: ${textMuted};
    --bases-embed-border-color: ${textMuted};
    --icon-color-active: ${textNormal};
    --caret-color: ${textMuted};
}`;
    let styleEl = _container.querySelector("#flexoki-palette");
    if (!styleEl) { styleEl = document.createElement("style"); styleEl.id = "flexoki-palette"; _container.appendChild(styleEl); }
    styleEl.textContent = css;
    const gradientEl = _container.querySelector("#gradientOverlay");
    if (gradientEl) gradientEl.style.background = `linear-gradient(to bottom, transparent 32.77%, ${bg} 83.04%)`;
}

/* ===== IMAGE -> PALETTE ===== */
const bgImg = _container.querySelector("#bgImg");
function onBgLoad() { applyPalette(sampleDominantColor(bgImg) || "#7baaba"); }
if (bgImg) {
    if (bgImg.complete && bgImg.naturalWidth > 0) onBgLoad();
    else { bgImg.addEventListener("load", onBgLoad); bgImg.addEventListener("error", () => applyPalette("#7baaba")); }
}

/* ===== resolve this note's frontmatter ===== */
const _vcard = _container.querySelector(".video-card");
function resolveFile() {
    const want = _vcard?.dataset.name || "";
    let f = app.workspace.getActiveFile();
    if (want && (!f || f.name !== want)) { const b = app.vault.getFiles().find(x => x.name === want); if (b) f = b; }
    return f;
}
const _file = resolveFile();
const _fm = _file ? ((app.metadataCache.getFileCache(_file) || {}).frontmatter || {}) : {};
const stripLink = s => String(s || "").replace(/^\[\[|\]\]$/g, "").replace(/\|.*$/, "").trim();

/* ===== channel byline (linked to channel_url when present) ===== */
(() => {
    const el = _vcard?.querySelector(".vid-channel"); if (!el) return;
    const name = stripLink(_fm.channel);
    if (!name) { el.remove(); return; }
    const url = _fm.channel_url || "";
    if (url) { const a = document.createElement("a"); a.href = url; a.target = "_blank"; a.rel = "noopener"; a.textContent = name; el.appendChild(a); }
    else el.textContent = name;
})();

/* ===== meta row: year · channel · duration ===== */
(() => {
    const el = _vcard?.querySelector(".vid-meta"); if (!el) return;
    const dateStr = String(_fm.last || _fm.created || "");
    const year = (dateStr.match(/^\d{4}/) || [""])[0];
    const dur = _fm.duration ? String(_fm.duration).trim() : "";
    const parts = [year, stripLink(_fm.channel), dur].filter(Boolean);
    const SEP = " <span style='color:var(--text-faint)'>·</span> ";
    el.innerHTML = parts.join(SEP);
})();

/* ===== watch button -> the video URL ===== */
(() => {
    const a = _vcard?.querySelector(".vid-watch"); if (!a) return;
    const url = _fm.url || _vcard.dataset.url || (_fm.video_id ? `https://www.youtube.com/watch?v=${_fm.video_id}` : "");
    if (!url) { a.remove(); return; }
    a.href = url;
})();

/* ===== lead paragraph: pull the TL;DW (or first body paragraph) ===== */
/* and SHOW MORE: render the full body, score-callout/frontmatter stripped ===== */
(async () => {
    try {
        const moreBtn = _vcard?.querySelector(".movie-more");
        const notesEl = _vcard?.querySelector(".movie-notes");
        const leadEl = _vcard?.querySelector(".vid-lead");
        if (!_file) { moreBtn?.remove(); notesEl?.remove(); leadEl?.remove(); return; }
        let raw = await app.vault.read(_file);
        let body = raw.replace(/^---[\s\S]*?\n---\n?/, "");
        body = body.replace(/^\s*((?:>.*\n?)+)\n?/, m => /dataviewjs|\[!abstract\]|\[!tldr\]/.test(m) ? "" : m);
        body = body.trim();

        // lead = first paragraph under "## TL;DW", else first non-heading paragraph
        if (leadEl) {
            let lead = "";
            const m = body.match(/##\s*TL;DW\s*\n+([^\n][\s\S]*?)(?:\n\s*\n|\n##|$)/i);
            if (m) lead = m[1].trim();
            else { const m2 = body.match(/(?:^|\n)([^#>\n][^\n]+)/); if (m2) lead = m2[1].trim(); }
            lead = lead.replace(/\[\[([^\]|]+)\|([^\]]+)\]\]/g, "$2").replace(/\[\[([^\]]+)\]\]/g, "$1").replace(/\*\*?([^*]+)\*\*?/g, "$1");
            if (lead) leadEl.textContent = lead; else leadEl.remove();
        }

        if (!notesEl) return;
        const meaningful = body.replace(/^#{1,6}\s.*$/gm, "").replace(/<!--[\s\S]*?-->/g, "").replace(/\s+/g, "");
        if (!meaningful) { moreBtn?.remove(); notesEl.remove(); return; }
        const obs = require("obsidian");
        notesEl.classList.add("markdown-rendered");
        notesEl.innerHTML = "";
        const comp = new obs.Component();
        if (obs.MarkdownRenderer && obs.MarkdownRenderer.render) await obs.MarkdownRenderer.render(app, body, notesEl, _file.path, comp);
        else if (obs.MarkdownRenderer) await obs.MarkdownRenderer.renderMarkdown(body, notesEl, _file.path, comp);
        if (moreBtn) moreBtn.addEventListener("click", () => {
            const open = _vcard.classList.toggle("notes-open");
            moreBtn.textContent = open ? "SHOW LESS" : "SHOW MORE";
        });
    } catch (e) { console.error("[Custom Views video]", e); }
})();

Templater Template

<%*
/**
 * YouTube → Video Frontmatter (Obsidian Templater)
 * No API key required. Reads a YouTube URL, pulls the title, channel and
 * thumbnail from YouTube's public oEmbed endpoint, writes idea-capture
 * frontmatter, and renames the note "Videos - Title". The thumbnail becomes
 * the `banner`, so the generic Custom Views banner card renders it. There is
 * no 0–10 score — this is a knowledge note, not a review: the body scaffolds
 * for takeaways and for promoting ideas into their own Concept notes.
 */
const OEMBED = "https://www.youtube.com/oembed";
const today = tp.date.now("YYYY-MM-DD");
const fileTitle = tp.file.title;

// 1) Ask for the video URL ----------------------------------------------
let url = await tp.system.prompt("Paste the YouTube URL (leave empty to fill by hand):");
url = (url || "").trim();

// 2) Pull the 11-char video id out of any common YouTube URL shape ------
function videoId(u) {
  const m = u.match(/(?:youtu\.be\/|youtube\.com\/(?:watch\?(?:.*&)?v=|embed\/|shorts\/|live\/|v\/))([\w-]{11})/);
  return m ? m[1] : "";
}
const id = videoId(url);
// Canonicalise the link so the note always stores a clean watch URL.
const canonUrl = id ? `https://www.youtube.com/watch?v=${id}` : url;

// 3) Fetch title / channel / thumbnail via oEmbed (keyless) -------------
let title = "", channel = "", channelUrl = "", oThumb = "";
if (url) {
  try {
    let resp = await tp.web.request(`${OEMBED}?format=json&url=${encodeURIComponent(canonUrl)}`);
    // tp.web.request may hand back a parsed object or a JSON string.
    if (typeof resp === "string") { try { resp = JSON.parse(resp); } catch (e) { resp = {}; } }
    title      = (resp && resp.title) || "";
    channel    = (resp && resp.author_name) || "";
    channelUrl = (resp && resp.author_url) || "";
    oThumb     = (resp && resp.thumbnail_url) || "";
  } catch (e) {
    tR += `oEmbed fetch failed (private/age-restricted?): ${e}\n`;
  }
}

// 4) Fall back to a hand-typed title when there was no URL / fetch ------
if (!title) {
  let typed = await tp.system.prompt("Video title:", fileTitle);
  title = (typed && typed.trim()) || fileTitle;
}

// 5) Thumbnail — prefer YouTube's maxres, fall back to the oEmbed one ---
const thumbnail = id ? `https://i.ytimg.com/vi/${id}/maxresdefault.jpg` : oThumb;

// 6) Link the channel to an existing note when one exists (host pattern)-
async function noteExists(name) {
  for (const folder of ["References", ""]) {
    const path = folder ? `${folder}/${name}.md` : `${name}.md`;
    try { if (await tp.file.exists(path)) return true; } catch (e) {}
  }
  return false;
}
const channelField = channel
  ? ((await noteExists(channel)) ? `"[[${channel}]]"` : `"${channel.replace(/"/g, '\\"')}"`)
  : "[]";

// 7) Watched date --------------------------------------------------------
let lastDate = await tp.system.prompt("Watched date (YYYY-MM-DD)", today);
if (!lastDate || !/^\d{4}-\d{2}-\d{2}$/.test(lastDate.trim())) lastDate = today;
lastDate = lastDate.trim();

// 8) Rename to "Videos - Title" (colon→dash, strip illegal chars) -------
const colonFixed = title.replace(/:/g, " - ");
let sanitized = colonFixed.replace(/[\/#%&{}<>*?$!'"@+`|=]/g, "").trim();
if (!sanitized) sanitized = fileTitle;
const newName = sanitized;
if (newName !== fileTitle) await tp.file.rename(newName);

// 9) Build YAML ----------------------------------------------------------
const L = [];
L.push("---");
L.push("connections:");
L.push(thumbnail ? `banner: ${thumbnail}` : 'banner: "[[32.jpg]]"');
L.push("categories:");
L.push('  - "[[Videos]]"');
L.push(`channel: ${channelField}`);
L.push(channelUrl ? `channel_url: "${channelUrl}"` : "channel_url: []");
L.push(canonUrl ? `url: "${canonUrl}"` : 'url: ""');
L.push(id ? `video_id: ${id}` : "video_id: []");
L.push("duration: ");
L.push("published: ");
L.push(`created: ${today}`);
L.push(`last: ${lastDate}`);
L.push("topics: []");
L.push("---");

// 10) Body scaffold — built for ideas, not scoring ----------------------
const body = [
  "",
  canonUrl ? `> [!tldr] [Watch on YouTube](${canonUrl})${channel ? ` · ${channel}` : ""}` : "> [!tldr] Watch",
  "",
  "## TL;DW",
  "",
  "## Key Ideas",
  "",
  "## Concepts",
  "<!-- Promote the load-bearing ones to their own bare-named concept notes. -->",
  "",
  "## Why It Matters",
  "",
  "## Quotes & Timestamps",
  ""
];

tR += L.join("\n") + "\n" + body.join("\n");
-%>
DECLASSIFIED

Field Assembly

Two plugins build this strip in your vault.

  • Custom Views: the renderer. Make a view, build its rule in the menu to match categories contains Videos (the screenshot above), then paste the template and JS blocks into their fields.
  • Templater: the note-maker. Paste the Templater block into a template file and bind it to a hotkey or a folder template.

The template fills the note from a public database when you create it, no key needed. After that the card runs on what is in the note.

Statement Ends

▌ Cross-Referenced Files