/**
 * Vanshap Capital — the investor portal (Zone B).
 *
 * Loaded only on portal views. Every value resolves through tokens.css; there
 * are no hex values or raw sizes in this file, and there must never be.
 *
 * The design's portal is the public site's system at a different density: the
 * same Ocean band, the same 64×2 accent rule, the same tracked-caps eyebrow —
 * but a working two-column reading surface rather than a marketing page. What
 * changes here is rhythm and structure, never the palette or the type.
 */

/* ── Full-bleed sections ─────────────────────────────────────────────────── */

/* A Vanshap section reaches the viewport edge through GeneratePress's own
   `.no-sidebar .entry-content .alignfull` rule — but only when it is a core
   block living in post content. The portal's PHP-templated views put their
   sections straight into .site-main, where they match nothing and are left at
   the container's width. Same break-out, same arithmetic, applied where they
   actually are.

   The arithmetic is relative on purpose: 50% resolves against whatever width
   .site-main happens to have, so this holds regardless of what is constraining
   the container above it.

   ⚠️ This lived in portfolio.css until 17 Sep 2026, scoped with a comment saying
   the templated case was "exactly and only" what that file introduced. It stopped
   being true the moment the materials pages became a template too, and the
   symptom was a boxed Ocean band on every page under /portal/materials/ —
   portfolio.css is not loaded there. It belongs with the zone, not with one
   surface inside it.

   Scoped to a direct child of .site-main, so the pattern-built portal pages,
   whose sections sit inside .entry-content, are untouched. */
.vc-portal .site-main > .vc-section {
	margin-inline: calc(50% - 50vw);
	max-inline-size: 100vw;
	inline-size: auto;
}

/* ── Nav ─────────────────────────────────────────────────────────────────── */

/* The portal nav is never transparent — there is no hero behind it — so it
   carries a permanent hairline instead of the scroll-triggered one. */
.vc-nav--portal {
	background: var(--ocean);
	border-bottom: 1px solid rgb(255 255 255 / 25%);
}

.vc-nav__brand {
	display: flex;
	align-items: center;
	gap: var(--space-5);
}

.vc-nav__divider {
	width: 1px;
	height: 26px;
	background: rgb(255 255 255 / 35%);
}

/* The zone label. Not a link: it names where you are, and making it clickable
   would imply a destination that does not exist. */
.vc-nav__zone {
	font-size: var(--size-footnote);
	font-weight: var(--weight-regular);
	letter-spacing: 0.28em;
	text-transform: uppercase;
	color: var(--sky);
	white-space: nowrap;
}

.vc-nav__public {
	font-size: var(--size-nav);
	letter-spacing: var(--track-nav);
	text-transform: uppercase;
	color: var(--paper);
	text-decoration: none;
	white-space: nowrap;
	transition: color 0.2s ease;
}

.vc-nav__public:hover,
.vc-nav__public:focus-visible {
	color: var(--sky);
}

/* ── Content offset ──────────────────────────────────────────────────────── */

/* The nav offset is NOT cancelled here any more. It was a .vc-portal rule, which
   described where the header band happened to be used rather than what the band
   does — so a non-portal page using the band (the public Thoughts page) was
   offset twice. It now lives in chrome.css, keyed on the band itself, and covers
   both. */

/* ── Page header band ──────────────────────────────────────────────────────

   Not here any more. The band is the default header for every inner page, not a
   portal component — the login, registration and public Thoughts pages all use
   it and none of them loads this file — so it moved to sections.css, which is
   always enqueued. The class keeps its --portal-head name because renaming it
   would orphan the markup already frozen into every page built from a pattern. */

/* ── Two-column body ─────────────────────────────────────────────────────── */

.vc-section--portal-body {
	padding-block: var(--space-8) var(--space-9);
	padding-inline: var(--gutter-page);
	background: var(--surface-page);
}

.vc-portal-grid {
	display: grid;
	grid-template-columns: 240px minmax(0, 1fr);
	gap: var(--space-8);
	align-items: start;
}

.vc-portal-grid__aside {
	position: sticky;
	/* The nav is fixed, so the sidebar has to stop below it, not at the top. */
	top: calc(var(--nav-height) + var(--space-4));
}

/* Anything in the main column carrying an id is a jump target for the sidebar,
   and the site nav is fixed — without this the browser scrolls the heading to
   y=0 and puts it underneath the bar. Same offset the sticky sidebar uses, so
   a jumped-to section lines up with the menu item that sent you there. */
.vc-portal-grid__main > [id],
.vc-thoughts-panel {
	scroll-margin-top: calc(var(--nav-height) + var(--space-4));
}

/* ── The public page's section filter ─────────────────────────────────────

   Mirrors the portfolio grid's treatment, and for the same reason: with no
   JavaScript every panel is on screen and the sidebar is a set of jump links,
   so the panels need the spacing that a stacked reading requires. Once the
   script runs only one is ever visible and that spacing is moot — the
   .is-filtered guard is what stops the first entry looking selected during a
   no-JavaScript visit while everything is still stacked. */
.vc-thoughts-panel + .vc-thoughts-panel {
	margin-block-start: var(--space-8);
}

.is-filtered .vc-thoughts-panel + .vc-thoughts-panel {
	margin-block-start: 0;
}

.vc-docnav.is-filtering .vc-docnav__link {
	cursor: pointer;
}

.vc-docnav.is-filtering .vc-docnav__item.is-current .vc-docnav__link {
	font-weight: var(--weight-semibold);
	color: var(--vanshap-navy);
}

/* ── Sidebar ─────────────────────────────────────────────────────────────── */

.vc-docnav__topline,
.vc-doclist__topline {
	height: 0;
	margin: var(--space-3) 0 0;
	border: 0;
	border-top: var(--rule-accent-h) solid var(--rule-accent);
}

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

.vc-docnav__link {
	display: flex;
	justify-content: space-between;
	align-items: baseline;
	gap: var(--space-3);
	padding-block: var(--space-4);
	border-bottom: var(--rule);
	font-size: var(--size-body-sm);
	font-weight: var(--weight-light);
	color: var(--ocean);
	text-decoration: none;
	transition: color 0.2s ease;
}

a.vc-docnav__link:hover,
a.vc-docnav__link:focus-visible {
	color: var(--vanshap-navy);
}

/* The current page reads as the heading of the column, not as a disabled link. */
.vc-docnav__item.is-current .vc-docnav__link {
	font-weight: var(--weight-semibold);
	color: var(--vanshap-navy);
}

.vc-docnav__count {
	flex: none;
	font-size: var(--size-footnote);
	font-weight: var(--weight-regular);
	color: var(--text-muted);
	font-variant-numeric: tabular-nums;
}

/* --text-label, for the role rather than the colour — --text-muted on the count
   above it is the same grey now (see tokens.css). The count is chrome; this is a
   sentence somebody typed into the block because they wanted it read. */
.vc-docnav__note {
	margin: var(--space-5) 0 0;
	font-size: var(--size-footnote);
	font-weight: var(--weight-light);
	line-height: var(--lh-body);
	color: var(--text-label);
	text-wrap: pretty;
}

/* ── Featured card ───────────────────────────────────────────────────────── */

.vc-doclist__featured {
	background: var(--surface-panel);
	padding: var(--space-7) calc(var(--space-7) - var(--space-1));
	margin-bottom: var(--space-7);
}

.vc-doclist__featured-title {
	margin: var(--space-4) 0 0;
	font-family: var(--font-display);
	font-weight: var(--weight-regular);
	font-size: 1.875rem; /* 30px — between --size-subhead and --size-h2-ocean */
	line-height: var(--lh-display);
	color: var(--text-display);
}

.vc-doclist__quote {
	display: block;
	margin: var(--space-3) 0 0;
	font-family: var(--font-display);
	font-style: italic;
	font-size: var(--size-body);
	color: var(--text-subhead);
	text-wrap: pretty;
}

.vc-doclist__quote--lg {
	font-size: var(--size-body-lg);
}

.vc-doclist__featured-actions {
	display: flex;
	align-items: center;
	flex-wrap: wrap;
	gap: var(--space-5);
	margin-top: var(--space-5);
}

/* Square, hairline-bordered, filling on hover — the design's only button. */
.vc-doclist__button {
	display: inline-block;
	padding: var(--space-3) var(--space-5);
	border: 1px solid var(--vanshap-navy);
	border-radius: var(--radius);
	font-size: var(--size-nav);
	letter-spacing: var(--track-nav);
	text-transform: uppercase;
	color: var(--vanshap-navy);
	text-decoration: none;
	transition: background-color 0.2s ease, color 0.2s ease;
}

.vc-doclist__button:hover,
.vc-doclist__button:focus-visible {
	background: var(--vanshap-navy);
	color: var(--paper);
}

.vc-doclist__meta {
	font-size: var(--size-nav);
	font-weight: var(--weight-light);
	color: var(--text-muted);
}

/* ── Document rows ───────────────────────────────────────────────────────── */

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

.vc-doclist__item {
	display: grid;
	grid-template-columns: 130px minmax(0, 1fr) auto;
	gap: var(--space-5);
	align-items: baseline;
	padding-block: calc(var(--space-5) + var(--space-1));
	border-bottom: var(--rule);
}

.vc-doclist__date {
	font-weight: var(--weight-regular);
	font-size: var(--size-eyebrow);
	letter-spacing: var(--track-eyebrow);
	text-transform: uppercase;
	color: var(--text-label);
}

.vc-doclist__title {
	display: block;
	font-family: var(--font-display);
	font-size: var(--size-subhead);
	line-height: var(--lh-display);
	color: var(--text-display);
}

.vc-doclist__title a {
	color: inherit;
	text-decoration: none;
}

/* The whole row is the target, so the hit area matches what reads as clickable.
   Applied to the link rather than the row so keyboard focus lands somewhere
   real — a click handler on the <li> would not be reachable by tab. */
.vc-doclist__title a::after {
	content: "";
	position: absolute;
	inset: 0;
}

.vc-doclist__item {
	position: relative;
}

.vc-doclist__title a:hover,
.vc-doclist__title a:focus-visible {
	color: var(--ocean);
}

.vc-doclist__action {
	font-size: var(--size-footnote);
	letter-spacing: var(--track-nav);
	text-transform: uppercase;
	color: var(--ocean);
	white-space: nowrap;
}

/* A document whose file cannot be resolved still appears — silently dropping a
   published document would hide a broken upload rather than surface it. */
.vc-doclist__item.is-unavailable .vc-doclist__title,
.vc-doclist__item.is-unavailable .vc-doclist__action {
	color: var(--text-muted);
}

/* These were one rule, which is how the empty state ended up muted: the notice
   beside it is addressed to editors only and is genuinely subordinate, the empty
   state is the only sentence an investor sees on the page. Two roles, two rules. */
.vc-doclist__empty {
	margin: var(--space-6) 0 0;
	font-weight: var(--weight-light);
	color: var(--text-label);
}

.vc-doclist__notice {
	margin: var(--space-6) 0 0;
	font-weight: var(--weight-light);
	color: var(--text-muted);
}

/* ── Responsive ──────────────────────────────────────────────────────────── */

@media (max-width: 900px) {
	.vc-portal-grid {
		grid-template-columns: 1fr;
		gap: var(--space-7);
	}

	/* Sticky is meaningless once the sidebar is stacked above the list. */
	.vc-portal-grid__aside {
		position: static;
	}
}

@media (max-width: 600px) {
	/* The date column cannot hold "September 2026" at 130px on a phone, so the
	   row becomes two lines with the date as a label above the title. */
	.vc-doclist__item {
		grid-template-columns: 1fr auto;
		gap: var(--space-2) var(--space-4);
	}

	.vc-doclist__date {
		grid-column: 1 / -1;
	}

	.vc-doclist__featured {
		padding: var(--space-6) var(--space-5);
	}

	.vc-convlist__featured {
		padding: var(--space-6) var(--space-5);
	}

	/* A 300px poster column leaves the title nowhere to go at this width, so the
	   card stacks: poster above, everything else beneath it. */
	.vc-convlist__featured.has-image {
		grid-template-columns: 1fr;
	}

	/* The brand cluster is the wordmark, a hairline and the zone label, and at
	   375px it runs under the menu toggle. The label is scaled to fit rather
	   than hidden: "Investor portal" is what tells a partner which side of the
	   login they are on, and CLAUDE.md rules out hiding content with CSS. */
	.vc-nav--portal .vc-nav__inner {
		gap: var(--space-4);
	}

	.vc-nav__brand {
		gap: var(--space-3);
		min-width: 0;
	}

	.vc-nav--portal .vc-nav__logo img {
		height: 24px !important; /* Overrides the inline height from vanshap_the_logo(). */
	}

	.vc-nav__divider {
		height: 20px;
	}

	.vc-nav__zone {
		font-size: 0.625rem; /* 10px */
		letter-spacing: 0.16em;
	}
}


/* ════ Conversations ═══════════════════════════════════════════════════════

   External interviews. Shares the vc-entry rhythm with the document lists so
   the two read as one system; the poster thumbnail is the only structural
   difference.

   Superseded note, 1 Sep 2026: this used to say there was deliberately no
   aspect-ratio on the poster, because every image carried its own dimensions
   and the intrinsic ratio held the row without CSS. That was true while every
   poster was a 1280x720 YouTube still. It stopped being true when podcasts and
   articles gained images an editor picks by hand — podcast artwork is square —
   and the mixed ratios made the column edge sawtooth. There is an
   aspect-ratio now, and the reasoning is on .vc-convlist__poster below.    */

/* ── Featured conversation ───────────────────────────────────────────────── */

/* The same panel as .vc-doclist__featured, which is the point: the lead item on
   a materials page and the lead item here are one component, and they must not
   drift apart. The background and padding are repeated rather than shared
   through a common class because the two lists are independent blocks, and a
   shared class would couple their markup as well as their appearance.

   What differs is the poster. A document has nothing to show; a conversation is
   podcast artwork or a video still, and the list below already leads with one. */
.vc-convlist__featured {
	background: var(--surface-panel);
	padding: var(--space-7) calc(var(--space-7) - var(--space-1));
	margin-bottom: var(--space-7);
	display: grid;
	gap: var(--space-6);
	grid-template-columns: 1fr;
}

/* Two columns whenever there is an IMAGE — not whenever there is a video. The
   same distinction as .vc-convlist__item, for the same reason: keying the
   layout on the video is what hid hand-picked podcast artwork entirely. */
.vc-convlist__featured.has-image {
	grid-template-columns: 300px 1fr;
	align-items: start;
}

.vc-convlist__featured-title {
	margin: var(--space-4) 0 0;
	font-family: var(--font-display);
	font-weight: var(--weight-regular);
	font-size: 1.875rem; /* Matches .vc-doclist__featured-title exactly. */
	line-height: var(--lh-display);
	color: var(--text-display);
}

/* The title is the control — it opens the conversation on its source page, in
   a new tab. It carries no link colour because the panel is the affordance;
   the underline on hover is what says it is clickable. */
.vc-convlist__featured-title a {
	color: inherit;
	text-decoration: none;
}

.vc-convlist__featured-title a:hover,
.vc-convlist__featured-title a:focus-visible {
	text-decoration: underline;
	text-underline-offset: 0.12em;
}

.vc-convlist__topline {
	border: 0;
	border-top: var(--rule);
	margin: var(--rule-gap-top) 0 0;
}

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

.vc-convlist__item {
	display: grid;
	gap: var(--space-4);
	grid-template-columns: 1fr;
}

/* Two columns whenever there is an IMAGE — not whenever there is a video.
   Those are different questions, and keying the layout on the video was what
   hid a podcast's hand-picked image entirely. */
.vc-convlist__item.has-image {
	grid-template-columns: 200px 1fr;
	align-items: start;
}

/* Every thumbnail occupies the same 16:9 box, whatever shape the image is.

   A YouTube still is 1280x720 and podcast artwork is square, so left to their
   intrinsic ratios a podcast row stood half again as tall as a video row and
   the column edge sawtoothed down the page.

   `cover`, so the image fills the box edge to edge and no row carries bars.
   Daniel's call, 1 Sep 2026, after seeing it both ways. This was `contain`
   first, on the reasoning that podcast artwork is a logo and cropping a logo
   reads as a mistake — the trade is real and it went the other way: a tidy
   column beats an uncropped logo.

   What that costs, so nobody re-derives it: a square cover loses about 44% of
   its height to a centre crop. Podcast artwork almost always centres its
   wordmark, so the name survives — but artwork with content at the top or
   bottom edge will lose it, and the fix for that one entry is a hand-picked
   16:9 image in the Poster field rather than a change here.

   Videos are 16:9 already, so `cover` is a no-op for them and they render
   exactly as they always have. The background survives as the field behind a
   slow-loading image; nothing else shows it now. */
.vc-convlist__poster {
	position: relative;
	line-height: 0;
	background: var(--rule-hairline);
	aspect-ratio: 16 / 9;
}

.vc-convlist__poster-img {
	width: 100%;
	height: 100%;
	object-fit: cover;
	display: block;
}

/* The poster is a click target as well as the title. The anchor has to fill the
   16:9 box: left inline it would shrink to the image's intrinsic height and the
   cover crop above would stop applying.

   It is aria-hidden and out of the tab order in the markup — see the note in
   the block's render.php — so this is a mouse affordance only, and the title
   remains the control for keyboard and screen-reader users. */
.vc-convlist__poster-link {
	display: block;
	inline-size: 100%;
	block-size: 100%;
}

/* The play affordance. Purely decorative — the title link is the control, and
   this is aria-hidden in the markup. It marks the row as a video; the video
   itself plays on its source page, in a new tab. */
.vc-convlist__play {
	position: absolute;
	inset: 0;
	display: grid;
	place-items: center;
	pointer-events: none;
}

.vc-convlist__play::before {
	content: "";
	width: 0;
	height: 0;
	border-style: solid;
	border-width: 11px 0 11px 18px;
	border-color: transparent transparent transparent var(--paper);
	filter: drop-shadow( 0 1px 3px rgba( 0, 0, 0, 0.45 ) );
}

.vc-convlist__platforms {
	margin: 10px 0 0;
	display: flex;
	flex-wrap: wrap;
	gap: var(--space-3);
	font-size: var(--size-meta);
}

.vc-convlist__platform {
	color: var(--ocean);
	text-decoration: underline;
	text-underline-offset: 0.2em;

	/* WCAG 2.2 SC 2.5.8 wants a 24x24px target. These are direct children of a
	   flex container, so they are blockified and their height is the line box:
	   --size-meta 14px x --lh-body 1.65 = 23.1px. Nine tenths of a pixel short,
	   which is exactly the kind of miss that never gets found by looking. 1px
	   each side takes it to 25.1px and changes nothing anyone can see — the row
	   gap is 12px, so wrapped rows move 2px apart and the rhythm holds.
	   Every other interactive element on the portal already clears the bar:
	   .vc-nav__toggle 12px of padding, .vc-docnav__link padding-block 16px,
	   .vc-doclist__button 12px/24px. */
	padding-block: 1px;
}

.vc-convlist__empty {
	color: var(--text-label);
	margin: var(--space-4) 0 0;
}


@media ( max-width: 782px ) {
	.vc-convlist__item.has-image {
		grid-template-columns: 140px 1fr;
	}
}

@media ( max-width: 480px ) {
	.vc-convlist__item.has-image {
		grid-template-columns: 1fr;
	}
}
