/* ==========================================================================
   components.css
   Buttons, primitives, and every named component.
   All values reference tokens.css. Nothing is hardcoded.
   Load order is base -> chrome -> components -> responsive and must not
   change: responsive.css contains the overrides that depend on coming last.
   ========================================================================== */

/* ---------- Buttons ---------- */
.btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    gap: var(--space-sm);
    min-height: 48px;
    padding: 0.65rem 1.25rem;
    font-family: var(--font-sans);
    font-size: var(--fs-small);
    font-weight: var(--fw-semibold);
    line-height: 1;
    text-decoration: none;
    white-space: nowrap;
    border: var(--border-width) solid transparent;
    border-radius: var(--radius-sm);
    cursor: pointer;
    transition: var(--transition-interactive);
}

.btn .icon { width: 18px; height: 18px; }

.btn--primary {
    background: var(--color-accent);
    color: var(--color-on-accent);
}

.btn--primary:hover {
    background: var(--color-accent-hover);
    color: var(--color-on-accent);
}

.btn--secondary {
    background: transparent;
    color: var(--color-accent);
    border-color: var(--color-accent);
}

.btn--secondary:hover {
    color: var(--color-accent-hover);
    border-color: var(--color-accent-hover);
}

/* Third tier: a text action inside a .cta, where a bordered button competes. */
.btn--ghost {
    background: transparent;
    color: var(--color-text-secondary);
    border-color: transparent;
    padding-inline: var(--space-2);
}

.btn--ghost:hover {
    color: var(--color-accent);
}

/* Larger tap and visual weight for the primary action in a .cta or hero. */
.btn--lg {
    min-height: 52px;
    padding: var(--space-3) var(--space-6);
    font-size: var(--fs-body);
}

.btn--block {
    width: 100%;
}

/* ==========================================================================
   PRIMITIVES
   The recipes every component composes from. Nothing here knows about a page.
   Add a modifier, never a page-scoped override.
   ========================================================================== */

/* ---------- .panel: the one box recipe ---------- */
.panel {
    padding: var(--panel-pad);
    background: var(--color-surface-raised);
    border: var(--border-strong);
    border-radius: var(--radius-md);
}

/* Sunken: regions that should sit behind rather than above. */
.panel--sunken {
    background: var(--color-surface);
    border-color: var(--color-border);
}

.panel--accent {
    background: var(--color-accent-wash);
    border-color: var(--color-accent-line);
    border-left: 3px solid var(--color-accent);
}

.panel--warning {
    background: var(--color-warning-wash);
    border-color: var(--color-warning);
    border-left: 3px solid var(--color-warning);
}

.panel--success {
    background: var(--color-success-wash);
    border-color: var(--color-success);
    border-left: 3px solid var(--color-success);
}

.panel--lg { padding: var(--panel-pad-lg); }
.panel--flush { padding: 0; }

.panel--interactive {
    transition: var(--transition-interactive),
        transform var(--dur-mid) var(--ease-brand);
}

.panel--interactive:hover {
    border-color: var(--color-accent);
    box-shadow: var(--shadow-raised);
}

/* ---------- .label: the one small-caps label recipe ---------- */
.label {
    display: inline-block;
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    font-weight: var(--fw-medium);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--color-text-secondary);
}

.label--accent { color: var(--color-accent); font-weight: var(--fw-semibold); }
.label--muted { color: var(--color-text-tertiary); }
.label--block { display: block; margin-bottom: var(--space-2); }

/* Usage: <span class="label label--numbered" data-n="01">Scope</span> */
.label--numbered::before {
    content: attr(data-n) " ";
    color: var(--color-accent);
    font-weight: var(--fw-bold);
}

/* ---------- .badge: status, not prose ---------- */
.badge {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    padding: var(--space-1) var(--space-2);
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    font-weight: var(--fw-semibold);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    white-space: nowrap;
    border: var(--border-width) solid transparent;
    border-radius: var(--radius-xs);
}

.badge--live {
    color: var(--color-success);
    background: var(--color-success-wash);
    border-color: var(--color-success);
}

.badge--dev {
    color: var(--color-warning);
    background: var(--color-warning-wash);
    border-color: var(--color-warning);
}

.badge--private {
    color: var(--color-text-secondary);
    background: var(--color-surface-tint);
    border-color: var(--color-border-strong);
}

/* For a badge sitting inside an accent-washed panel, where the green of
   badge--live reads as a second, unrelated signal. */
.badge--accent {
    color: var(--color-accent-hover);
    background: var(--color-surface-raised);
    border-color: var(--color-accent);
}

/* No fill: "coming soon" should recede rather than announce. */
.badge--soon {
    color: var(--color-text-tertiary);
    border-color: var(--color-border);
}

/* Hypothesis / verdict badges for case files (theme-wide, token-only). */
.badge--confirmed {
    color: var(--color-success);
    background: var(--color-success-wash);
    border-color: var(--color-success);
}

.badge--refuted {
    color: var(--color-text-primary);
    background: var(--color-surface-tint);
    border-color: var(--color-border-strong);
}

.badge--partial {
    color: var(--color-warning);
    background: var(--color-warning-wash);
    border-color: var(--color-warning);
}

.badge--inf {
    color: var(--color-accent-hover);
    background: var(--color-accent-wash);
    border-color: var(--color-accent-line);
}

@media (max-width: 767px) {
    .panel,
    .panel--lg {
        padding: var(--panel-pad-mobile);
    }
}

/* ---------- Tags / badges ---------- */
.tag {
    display: inline-flex;
    align-items: center;
    padding: var(--space-xs) var(--space-sm);
    font-family: var(--font-mono);
    font-size: var(--fs-micro);
    font-weight: var(--fw-medium);
    letter-spacing: 0.04em;
    text-transform: uppercase;
    color: var(--color-text-secondary);
    background: var(--color-surface-tint);
    border: var(--border);
    border-radius: var(--radius-base);
}

.tag-list {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    margin: 0;
    padding: 0;
    list-style: none;
}

a.tag {
    text-decoration: none;
    color: var(--color-text-secondary);
    transition: border-color var(--dur-fast) var(--ease-brand),
        color var(--dur-fast) var(--ease-brand);
}

a.tag:hover {
    color: var(--color-accent);
    border-color: var(--color-accent);
}

/* Active filter inverts to a solid fill. A border-colour change alone does not
   answer "which filter am I looking at" at a glance. */
.tag--active {
    color: var(--color-on-accent);
    background: var(--color-accent);
    border-color: var(--color-accent);
}

.tag--active:hover {
    color: var(--color-on-accent);
    background: var(--color-accent-hover);
    border-color: var(--color-accent-hover);
}

/* In-page section nav for a long single-column landing/service page —
   layout only, composes .tag for the chip itself rather than a new link
   style. Not the boxed .contents sidebar (that stays reserved for
   blog/research/case); this is a lighter, non-sticky wayfinding aid for a
   page with several major H2 sections and no other way to jump between them.
   Use via includes/landing-nav.php. See docs/rules/theme-layout.md. */
.landing-nav {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-sm);
    margin-bottom: var(--space-2xl);
    padding-bottom: var(--space-lg);
    border-bottom: var(--border);
    list-style: none;
}

/* ==========================================================================
   COMPONENTS
   ========================================================================== */

/* ---------- .cta: the one call-to-action recipe ---------- */
.cta {
    display: grid;
    gap: var(--space-6);
    padding: var(--panel-pad-lg);
    margin-block: var(--space-16);
    background: var(--color-accent-wash);
    border: var(--border-width) solid var(--color-accent-line);
    border-left: 3px solid var(--color-accent);
    border-radius: var(--radius-lg);
    box-shadow: var(--shadow-raised);
}

.cta__title {
    margin: 0;
    font-family: var(--font-display);
    font-weight: var(--fw-semibold);
    font-size: var(--fs-h3);
    letter-spacing: var(--tracking-tight);
    line-height: var(--lh-heading);
    color: var(--color-text-primary);
}

.cta__body {
    max-width: var(--measure-lede);
    margin: 0;
    color: var(--color-text-secondary);
}

.cta__body > p:last-child { margin-bottom: 0; }

.cta__actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-4);
}

/* Meta strip: price/turnaround/next-date after actions in .cta, safety notes
   before actions in hero.php. margin-bottom covers both orders — trailing
   whitespace before </aside> in .cta is harmless; in hero.php it's the fix
   for meta sitting flush against the buttons below it with no gap at all. */
.cta__meta {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-2) var(--space-6);
    margin: 0 0 var(--space-lg);
    padding: 0;
    list-style: none;
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    color: var(--color-text-secondary);
}

/* Full-bleed band, for the end of a page. */
.cta--band {
    margin-inline: calc(50% - 50vw);
    padding-inline: max(var(--space-4), calc(50vw - var(--container-max) / 2));
    border-inline: 0;
    border-radius: 0;
    border-block: var(--border-width) solid var(--color-accent-line);
}

/* Narrow variant that can sit inside .prose without breaking the measure. */
.cta--inline {
    margin-block: var(--space-12);
    padding: var(--panel-pad);
    gap: var(--space-4);
    border-radius: var(--radius-md);
}

.cta--inline .cta__title { font-size: var(--fs-h4); }

/* ---------- .callout--action: a callout that ends in a link ---------- */
.callout--action {
    display: grid;
    gap: var(--space-3);
    border-left: 3px solid var(--color-accent);
}

.callout--action .btn { justify-self: start; }

/* ---------- Grid utilities ----------
   Gap declared once. Modifiers supply columns only. */
.grid {
    display: grid;
    gap: var(--space-6);
    min-width: 0;
}

.grid > * { min-width: 0; }

.grid--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
.grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }

.grid--auto {
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
}

@media (max-width: 1023px) {
    .grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 767px) {
    .grid--2,
    .grid--3 { grid-template-columns: minmax(0, 1fr); }
    .grid { gap: var(--space-4); }
    .cta { padding: var(--panel-pad-mobile); }
    .cta__actions .btn { flex: 1 1 auto; }
}

/* ---------- .pricing: tier panels for product and course pages ---------- */
.pricing {
    display: grid;
    gap: var(--space-6);
    grid-template-columns: minmax(0, 1fr);
    align-items: stretch;
    margin-block: var(--space-10);
}

@media (min-width: 768px) {
    .pricing--2 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
    .pricing--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

.tier {
    display: flex;
    flex-direction: column;
    height: 100%;
    border-radius: var(--radius-lg);
}

/* Exactly one tier may be recommended. It gains a border and a badge, not a
   different size, so the row still scans as one comparison. */
.tier--featured {
    border: 2px solid var(--color-accent);
    background: var(--color-accent-wash);
}

.tier__head {
    padding-bottom: var(--space-4);
    border-bottom: var(--border);
}

.tier__name {
    margin: var(--space-2) 0 0;
    font-family: var(--font-display);
    font-size: var(--fs-card-title);
    font-weight: var(--fw-semibold);
    line-height: var(--lh-heading);
}

.tier__price {
    display: flex;
    align-items: baseline;
    gap: var(--space-2);
    margin: var(--space-3) 0 0;
    font-family: var(--font-mono);
    font-size: var(--fs-h3);
    font-weight: var(--fw-semibold);
    color: var(--color-text-primary);
}

.tier__price-note {
    font-size: var(--fs-label);
    font-weight: var(--fw-regular);
    color: var(--color-text-secondary);
}

.tier__desc {
    margin: var(--space-4) 0 0;
    color: var(--color-text-secondary);
}

.tier__list {
    margin: var(--space-4) 0 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: var(--space-2);
}

.tier__list li {
    position: relative;
    padding-left: var(--space-6);
    color: var(--color-text-secondary);
}

.tier__list li::before {
    content: "";
    position: absolute;
    left: 0;
    /* Half of --lh-body, so the rule centres on the first line rather than
       riding above it. */
    top: 0.8em;
    width: 8px;
    height: 2px;
    background: var(--color-accent);
}

.tier__list li[data-excluded]::before { background: var(--color-border-strong); }
.tier__list li[data-excluded] { color: var(--color-text-tertiary); }

.tier__spacer { flex: 1 1 auto; min-height: var(--space-6); }

.tier__action { margin-top: var(--space-6); }

/* ---------- .spec-list: key/value facts, product and course pages ---------- */
.spec-list {
    display: grid;
    gap: 0;
    margin: var(--space-8) 0;
    padding: 0;
}

.spec-list__row {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    gap: var(--space-1);
    padding: var(--space-3) 0;
    border-bottom: var(--border);
}

.spec-list__row:first-child { border-top: var(--border); }

.spec-list dt {
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--color-text-secondary);
}

.spec-list dd {
    margin: 0;
    color: var(--color-text-primary);
}

@media (min-width: 768px) {
    .spec-list__row {
        grid-template-columns: minmax(0, 14rem) minmax(0, 1fr);
        gap: var(--space-6);
        align-items: baseline;
    }
}

/* ---------- .faq: native disclosure, no JS ---------- */
.faq {
    margin: var(--space-8) 0;
    border-top: var(--border);
}

.faq__item {
    border-bottom: var(--border);
}

.faq__q {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: var(--space-4);
    padding: var(--space-4) 0;
    cursor: pointer;
    font-weight: var(--fw-semibold);
    color: var(--color-text-primary);
    list-style: none;
}

.faq__q::-webkit-details-marker { display: none; }

.faq__q::after {
    content: "+";
    flex-shrink: 0;
    font-family: var(--font-mono);
    font-size: var(--fs-h4);
    line-height: 1;
    color: var(--color-accent);
}

.faq__item[open] > .faq__q::after { content: "\2212"; }
.faq__q:hover { color: var(--color-accent); }

.faq__a {
    padding: 0 0 var(--space-4);
    max-width: var(--measure-prose);
    color: var(--color-text-secondary);
}

.faq__a > :last-child { margin-bottom: 0; }

/* ---------- .syllabus: course module list ---------- */
.syllabus {
    display: grid;
    gap: var(--space-3);
    margin: var(--space-8) 0;
    padding: 0;
    list-style: none;
    counter-reset: module;
}

.module {
    counter-increment: module;
    position: relative;
    padding-left: calc(var(--panel-pad) + 2.5rem);
}

.module::before {
    content: counter(module, decimal-leading-zero);
    position: absolute;
    left: var(--panel-pad);
    top: var(--panel-pad);
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    font-weight: var(--fw-bold);
    color: var(--color-accent);
}

.module__title {
    margin: 0;
    font-size: var(--fs-h4);
    font-weight: var(--fw-semibold);
}

.module__meta {
    margin: var(--space-1) 0 0;
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    color: var(--color-text-tertiary);
}

.module__desc {
    margin: var(--space-2) 0 0;
    max-width: var(--measure-prose);
    color: var(--color-text-secondary);
}

@media (max-width: 767px) {
    .module {
        padding-left: calc(var(--panel-pad-mobile) + 2.5rem);
    }

    .module::before {
        left: var(--panel-pad-mobile);
        top: var(--panel-pad-mobile);
    }
}

/* ---------- .instructor: who is teaching, on a course page ---------- */
/* Flex rather than grid: a course page without a photo should close the gap
   instead of leaving an empty 7rem track. */
.instructor {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-6);
    align-items: start;
    margin: var(--space-10) 0;
}

.instructor > :not(.instructor__photo) {
    flex: 1 1 18rem;
    min-width: 0;
}

.instructor__photo {
    flex: 0 0 auto;
    width: 7rem;
    height: 7rem;
    object-fit: cover;
    border-radius: var(--radius-pill);
    border: var(--border-strong);
}

.instructor__name {
    margin: 0;
    font-size: var(--fs-h4);
    font-weight: var(--fw-semibold);
}

.instructor__role {
    margin: var(--space-1) 0 var(--space-3);
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    color: var(--color-text-secondary);
}

.instructor__bio {
    max-width: var(--measure-prose);
    margin: 0;
    color: var(--color-text-secondary);
}

/* ---------- .clause: scope and disclaimer copy that must be findable ---------- */
.clause {
    margin: var(--space-10) 0;
    font-size: var(--fs-small);
}

.clause__title {
    margin: 0 0 var(--space-2);
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--color-text-secondary);
}

.clause p:last-child { margin-bottom: 0; }

/* ---------- Hero (homepage) ---------- */
.hero {
    padding-block: var(--space-3xl) var(--space-2xl);
}

.hero__grid {
    display: grid;
    grid-template-columns: 1fr;
    gap: var(--space-2xl);
    align-items: center;
}

/* Hero without a visual column: use full container width */
.hero__grid--solo {
    grid-template-columns: 1fr;
}

.hero__grid--solo .hero__lede {
    max-width: var(--measure-lede);
}

.hero__title {
    margin-bottom: var(--space-lg);
}

.hero__lede {
    max-width: var(--measure-lede);
    margin-bottom: var(--space-8);
    color: var(--color-text-secondary);
    font-size: var(--fs-lede);
    line-height: var(--lh-lede);
}

.hero__actions {
    display: flex;
    flex-wrap: wrap;
    gap: var(--space-md);
}

/* Static abstract geometric pattern (forensic grid + nodes) */
.hero__visual {
    display: none;
    aspect-ratio: 4 / 3;
    background: var(--color-surface-raised);
    border: var(--border-strong);
    border-radius: var(--radius-lg);
    overflow: hidden;
}

.hero__visual svg {
    width: 100%;
    height: 100%;
}

/* img rule: a photograph can replace the SVG later without restructuring the hero */
.hero__visual img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    object-position: center;
}

.hero__visual .grid-line { stroke: var(--color-border); stroke-width: 1; }
.hero__visual .node { fill: var(--color-accent); }
.hero__visual .node--muted { fill: var(--chart-3); }
.hero__visual .edge { stroke: var(--color-accent); stroke-width: 1.25; opacity: 0.5; }

/* ---------- .card: one implementation for posts, tools, research, products ----
   Composes .panel. Every card has the same four regions in the same order, so
   a row of cards is aligned by construction rather than by luck. */
.card {
    display: flex;
    flex-direction: column;
    height: 100%;
    overflow: hidden;
    /* .panel supplies background, border and radius. Padding moves to __body
       so the media slot can bleed to the card edge. */
    padding: 0;
}

/* --- media: mandatory, so rows never go ragged --- */
.card__media {
    display: block;
    aspect-ratio: 16 / 9;
    overflow: hidden;
    background: var(--color-surface-tint);
    border-bottom: var(--border);
    text-decoration: none;
}

.card__media img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
    filter: saturate(0.85);
    transition: filter var(--dur-mid) var(--ease-brand);
}

.card:hover .card__media img { filter: saturate(1); }

/* A card with no image still occupies the same height, which is the point. */
.card__media--placeholder {
    display: flex;
    align-items: center;
    justify-content: center;
    padding: var(--space-4);
    text-align: center;
    color: var(--color-text-tertiary);
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
}

/* --- body: the only region that owns internal spacing --- */
.card__body {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    padding: var(--panel-pad);
}

/* One rhythm rule instead of a per-element margin chain. */
.card__body > * + * { margin-top: var(--space-2); }
.card__body > .card__desc { margin-top: var(--space-3); }

.card__title {
    margin: 0;
    font-family: var(--font-display);
    font-weight: var(--fw-semibold);
    font-size: var(--fs-card-title);
    letter-spacing: var(--tracking-tight);
    line-height: var(--lh-heading);
}

.card__title a {
    color: var(--color-text-primary);
    text-decoration: none;
}

.card__title a:hover { color: var(--color-accent); }

.card__desc {
    margin-bottom: 0;
    color: var(--color-text-secondary);
}

.card__meta {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2);
    margin: 0;
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    color: var(--color-text-tertiary);
}

.card__meta-dot {
    width: 3px;
    height: 3px;
    border-radius: 50%;
    background: currentColor;
    flex-shrink: 0;
}

/* --- foot: a defined region, not margin-top:auto on whatever is last.
   The spacer absorbs slack so every foot lands on the same line. --- */
.card__spacer { flex: 1 1 auto; min-height: var(--space-4); }

.card__foot {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: var(--space-2) var(--space-4);
    padding: 0 var(--panel-pad) var(--panel-pad);
}

.card__action {
    display: inline-flex;
    align-items: center;
    gap: var(--space-1);
    font-weight: var(--fw-semibold);
    font-size: var(--fs-small);
    color: var(--color-accent);
    text-decoration: none;
}

.card__action .icon { width: 16px; height: 16px; }
.card__action:hover { color: var(--color-accent-hover); }

.card__action--muted {
    font-weight: var(--fw-regular);
    color: var(--color-text-tertiary);
}

/* --- featured: text band only (front matter featured: true) ---
   No media. Diagram/text post images beside copy look like overlay.
   Stacked flex: label, title, dek, date, then action. */
.card--featured {
    height: auto;
    background: var(--color-accent-wash);
    border-color: var(--color-accent-line);
    border-left: 3px solid var(--color-accent);
}

.card--featured .card__media {
    display: none;
}

.card--featured .card__title {
    font-size: var(--fs-h2);
    max-width: var(--measure-lede);
}

.card--featured .card__desc {
    max-width: var(--measure-lede);
}

.card--featured .card__body {
    padding: var(--panel-pad-lg);
}

.card--featured .card__foot {
    padding: 0 var(--panel-pad-lg) var(--panel-pad-lg);
}

.card--featured .card__spacer {
    display: none;
}

@media (max-width: 767px) {
    .card--featured .card__body,
    .card--featured .card__foot {
        padding-inline: var(--panel-pad-mobile);
    }

    .card--featured .card__body {
        padding-top: var(--panel-pad-mobile);
    }

    .card--featured .card__foot {
        padding-bottom: var(--panel-pad-mobile);
    }

    .card--featured .card__title {
        font-size: var(--fs-h3);
    }
}

/* --- grid: auto-fill removes the orphan problem at every width and needs no
   change when a card is added. --- */
.card-grid {
    display: grid;
    gap: var(--space-6);
    grid-template-columns: repeat(auto-fill, minmax(min(100%, 20rem), 1fr));
    align-items: stretch;
    min-width: 0;
}

.card-grid > * { min-width: 0; }

/* Fixed-column variants for grids with a known, small item count, where
   auto-fill would reflow unpredictably between breakpoints. */
.card-grid--2,
.card-grid--3 { grid-template-columns: minmax(0, 1fr); }

@media (min-width: 768px) {
    .card-grid { gap: var(--space-8); }
    .card-grid--2,
    .card-grid--3 { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (min-width: 1024px) {
    .card-grid--3 { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

@media (min-width: 768px) and (hover: hover) {
    .card:hover { transform: translateY(-2px); }
}


/* ---------- Homepage: about strip ---------- */
.about-strip {
    display: grid;
    gap: var(--space-8);
    padding: var(--panel-pad-lg);
    background: var(--color-surface-raised);
    border: var(--border-strong);
    border-radius: var(--radius-md);
}

.about-strip__name {
    margin: 0 0 var(--space-xs);
    font-size: var(--fs-h3);
    font-weight: var(--fw-semibold);
    color: var(--color-text-primary);
}

.about-strip__title {
    margin: 0;
    font-family: var(--font-mono);
    font-size: var(--fs-small);
    color: var(--color-text-secondary);
}

.about-strip__bio p {
    color: var(--color-text-secondary);
}

.about-strip__bio p:last-child {
    margin-bottom: 0;
}

@media (min-width: 768px) {
    .about-strip {
        grid-template-columns: minmax(12rem, 0.35fr) 1fr;
        gap: var(--space-2xl);
        align-items: start;
    }
}

/* ---------- Homepage: On AI belief band ---------- */
.belief {
    position: relative;
    overflow: hidden;
    padding-block: var(--space-section);
    background: var(--color-surface-tint);
    border-block: var(--border);
}

.belief__graphic {
    position: absolute;
    inset: 0;
    z-index: 0;
    opacity: 0.16;
    pointer-events: none;
    animation: belief-drift 48s var(--ease-brand) infinite alternate;
}

.belief__graphic svg {
    width: 110%;
    height: 110%;
    margin: -5%;
}

.belief__grid-line {
    stroke: var(--color-border);
    stroke-width: 1;
}

.belief__edge {
    stroke: var(--color-accent);
    stroke-width: 1.25;
    opacity: 0.45;
}

.belief__node {
    fill: var(--color-accent);
}

.belief__node--muted {
    fill: var(--chart-3);
}

.belief__node--pulse {
    transform-box: fill-box;
    transform-origin: center;
    animation: belief-pulse 10s var(--ease-brand) infinite;
}

.belief__inner {
    position: relative;
    z-index: 1;
    max-width: var(--container-max);
    margin-inline: auto;
    padding-inline: var(--space-md);
}

.belief__inner .eyebrow {
    margin-bottom: var(--space-sm);
}

.belief__inner h2 {
    margin-bottom: var(--space-lg);
}

.belief__body {
    max-width: var(--measure-wide);
}

.belief__body p {
    color: var(--color-text-secondary);
}

.belief__body p:last-child {
    margin-bottom: 0;
}

@keyframes belief-drift {
    from { transform: translate3d(-1.5%, 0, 0); }
    to { transform: translate3d(1.5%, 0, 0); }
}

@keyframes belief-pulse {
    0%, 100% { opacity: 0.55; transform: scale(1); }
    50% { opacity: 1; transform: scale(1.15); }
}

@media (min-width: 768px) {
    .belief__inner {
        padding-inline: var(--space-xl);
    }
}

/* ---------- Session records (landing pages) ---------- */
.session-list {
    margin: 0;
    padding: 0;
    list-style: none;
    display: grid;
    gap: var(--space-lg);
}

.session-list__item {
    display: grid;
    gap: var(--space-xs);
}

.session-list__where,
.session-list__host {
    font-weight: var(--fw-semibold);
    color: var(--color-text-primary);
}

.session-list__what {
    margin: 0;
    color: var(--color-text-secondary);
}

/* ---------- Contact ---------- */
.contact__methods {
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    margin-top: var(--space-xl);
}

.contact__email {
    font-family: var(--font-mono);
    font-size: var(--fs-h4);
}

.contact__email a,
.contact__email .js-email {
    text-decoration: underline;
    text-underline-offset: 0.15em;
}

/* Pre-hydration obfuscated email control (main.js replaces with mailto <a>). */
.js-email {
    color: var(--color-accent);
    cursor: pointer;
}

.contact__noscript {
    margin: 0;
    font-size: var(--fs-small);
    color: var(--color-text-secondary);
}

/* ==========================================================================
   Phase A layout: section labels and numbered steps (site-wide)
   ========================================================================== */
.step-grid {
    list-style: none;
    margin: 0 0 var(--paragraph-gap);
    padding: 0;
    counter-reset: step;
    display: flex;
    flex-direction: column;
    gap: var(--space-md);
    text-align: left;
}

.landing ol.step-grid {
    padding-left: 0;
}

/* Badge + flowing copy. Do not use display:grid on .step: a bare <strong>
   plus text nodes become separate grid items and split the card (Process
   blowout). Absolute badge keeps one text flow for all present/future steps. */
.step {
    position: relative;
    margin: 0;
    padding: var(--space-4) var(--space-6);
    padding-left: calc(var(--space-6) + 2rem + var(--space-4));
    background: var(--color-surface-raised);
    border: var(--border-strong);
    border-radius: var(--radius-md);
    counter-increment: step;
    text-align: left;
    hyphens: manual;
}

.step::before {
    content: counter(step);
    position: absolute;
    left: var(--space-lg);
    top: var(--space-md);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2rem;
    height: 2rem;
    border-radius: 50%;
    background: var(--color-accent);
    color: var(--color-on-accent);
    font-family: var(--font-mono);
    font-size: var(--fs-small);
    font-weight: var(--fw-semibold);
    line-height: 1;
}

/* ==========================================================================
   Long-form layout (blog, research, case) - one theme type
   TOC position via --longform-toc-* tokens in tokens.css (easy site-wide revert).
   ========================================================================== */

.longform-layout {
    display: grid;
    gap: var(--space-xl);
    align-items: start;
    min-width: 0;
    width: 100%;
}

.longform-layout > * {
    min-width: 0;
}

.longform-main {
    min-width: 0;
    max-width: 100%;
}

.longform-main--wide .prose,
.longform-main--wide .research-prose {
    max-width: var(--measure-wide);
}

/* Mobile: Contents above the article so navigation is reachable first. */
.longform-layout > .contents {
    order: -1;
}

.longform-layout > .longform-main {
    order: 1;
}

@media (min-width: 1024px) {
    .longform-layout {
        grid-template-columns: var(--longform-cols);
        gap: var(--space-12);
    }

    .longform-layout--prose {
        grid-template-columns: var(--longform-cols-prose);
    }

    .longform-layout > .longform-main {
        order: var(--longform-toc-order-main);
    }

    .longform-layout > .contents {
        order: var(--longform-toc-order-nav);
        position: sticky;
        top: calc(64px + var(--space-6));
        max-height: calc(100vh - 6rem);
        overflow-y: auto;
        padding-right: var(--space-sm);
        align-self: start;
    }

    /* No Contents panel (post with < 4 H2s, or a case embed): collapse the
       reserved sidebar track instead of leaving it blank. Higher specificity
       than the rules above (two classes vs one) wins regardless of order. */
    .longform-layout:not(:has(> .contents)) {
        grid-template-columns: minmax(0, 1fr);
    }
}

/* Attribute revert: put Contents on the start (left) side without editing tokens. */
html[data-longform-toc="start"] {
    --longform-toc-side: start;
    --longform-toc-order-main: 2;
    --longform-toc-order-nav: 1;
    --longform-cols: minmax(12rem, 15.5rem) minmax(0, 1fr);
    --longform-cols-prose: minmax(12rem, 1fr) minmax(0, var(--measure-prose));
}

/* ---------- .contents: boxed TOC panel (blog + research + case) ---------- */
.contents {
    min-width: 0;
}

.contents__desktop,
.contents__mobile {
    padding: var(--panel-pad);
    background: var(--color-surface-raised);
    border: var(--border-strong);
    border-radius: var(--radius-md);
    max-width: 100%;
}

.contents__label {
    margin: 0 0 var(--space-md);
}

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

.contents__list li + li {
    margin-top: var(--space-sm);
}

.contents__list a {
    display: grid;
    grid-template-columns: auto 1fr;
    gap: var(--space-sm);
    align-items: baseline;
    color: var(--color-text-primary);
    text-decoration: none;
    font-size: var(--fs-small);
    line-height: 1.35;
}

.contents__list a:hover,
.contents__list a:focus-visible {
    color: var(--color-accent);
}

.contents__list a.is-active {
    color: var(--color-accent);
}

.contents__list a.is-active .contents__num {
    color: var(--color-accent);
    font-weight: var(--fw-semibold);
}

.contents__num {
    font-family: var(--font-mono);
    font-size: var(--fs-small);
    color: var(--color-accent);
}

.contents__text {
    min-width: 0;
}

.contents__sublist {
    list-style: none;
    margin: var(--space-xs) 0 0;
    padding-left: calc(var(--fs-small) + var(--space-sm));
    border-left: var(--border);
}

.contents__sublist li + li {
    margin-top: var(--space-xs);
}

.contents__sublist a {
    display: block;
    padding-left: var(--space-sm);
    color: var(--color-text-secondary);
    text-decoration: none;
    font-size: var(--fs-micro);
    line-height: 1.4;
}

.contents__sublist a:hover,
.contents__sublist a:focus-visible {
    color: var(--color-accent);
}

.contents__sublist a.is-active {
    color: var(--color-accent);
    font-weight: var(--fw-medium);
}

/* ---------- Reading progress: injected by longform.js on any .longform-layout page ---------- */
.reading-progress {
    position: fixed;
    top: 64px;
    left: 0;
    width: 100%;
    height: 2px;
    background: var(--color-border);
    z-index: 49;
}

.reading-progress__bar {
    height: 100%;
    width: 0%;
    background: var(--color-accent);
}

@media (prefers-reduced-motion: no-preference) {
    .reading-progress__bar {
        transition: width 100ms linear;
    }
}

.contents__desktop {
    display: none;
}

.contents__mobile summary {
    cursor: pointer;
    font-family: var(--font-mono);
    font-size: var(--fs-label);
    font-weight: var(--fw-medium);
    letter-spacing: var(--tracking-label);
    text-transform: uppercase;
    color: var(--color-text-secondary);
    overflow-wrap: anywhere;
    line-height: 1.4;
}

.contents__mobile .contents__list {
    margin-top: var(--space-md);
    max-height: min(60vh, 24rem);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
}

@media (min-width: 1024px) {
    .contents__mobile {
        display: none;
    }

    .contents__desktop {
        display: block;
    }
}

@media (max-width: 767px) {
    .contents__desktop,
    .contents__mobile {
        padding: var(--panel-pad-mobile);
    }
}

/* ---------- .index-head: shared index page opening ---------- */
.index-head {
    padding-block: var(--space-3xl) var(--space-xl);
}

.index-head__title {
    margin-bottom: var(--space-sm);
}

.index-head .lede {
    margin-bottom: 0;
}

.index-empty {
    color: var(--color-text-secondary);
    padding-bottom: var(--space-3xl);
}
