/*
Theme Name: Tecnologolilla
Theme URI: https://tecnologolilla.com/
Author: Wook2
Description: AI와 테크 흐름을 기록하는 개인 블로그를 위한 자체 블록 테마입니다. 외부 요청 없이 시스템 폰트와 순수 CSS만 사용합니다.
Version: 1.0.1
Requires at least: 6.5
Tested up to: 7.0
Requires PHP: 7.4
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: tecnologolilla
Tags: blog, one-column, block-patterns, full-site-editing
*/

/**
 * Tecnologolilla Design Tokens
 * Single source of truth for the WordPress block theme.
 * All values are plain CSS custom properties on :root so they can be read
 * by theme.json style generation, block editor styles, and component CSS.
 * Do not add computed values, mixins, or selectors here.
 */

:root {
  /* --------------------------------------------------------------------------
   * 1. COLOR
   * Use semantic names. Always pair foreground/background to meet WCAG AA.
   * Light scheme is default; dark overrides live in [data-theme="dark"].
   * -------------------------------------------------------------------------- */

  /* Neutral ramp: ink on paper */
  --color-ink-900: #0f1410;
  --color-ink-800: #1a211b;
  --color-ink-700: #2a3530;
  --color-ink-600: #445048;
  --color-ink-500: #667269;
  --color-ink-400: #8b968d;
  --color-ink-300: #b2bab2;
  --color-ink-200: #d6dbd6;
  --color-ink-100: #eef1ee;
  --color-ink-50:  #f8faf8;

  /* Brand accent: moss / pine */
  --color-brand-700: #1c4a36;
  --color-brand-600: #236144;
  --color-brand-500: #2f7a58;
  --color-brand-400: #5c9e7e;
  --color-brand-300: #96c4ab;
  --color-brand-200: #c7e3d4;
  --color-brand-100: #e7f4ed;
  --color-brand-50:  #f4fbf7;

  /* Warm highlight: used sparingly for rank badges, focus rings */
  --color-warm-700: #7c3f12;
  --color-warm-600: #a45317;
  --color-warm-500: #cd6b24;
  --color-warm-400: #e58a45;
  --color-warm-300: #f5b88a;
  --color-warm-200: #fce0cd;
  --color-warm-100: #fff2e8;

  /* Semantic assignments */
  --color-bg-body:        var(--color-ink-50);
  --color-bg-card:        #ffffff;
  --color-bg-hero:        var(--color-ink-100);
  --color-bg-elevated:    #ffffff;
  --color-bg-muted:       var(--color-ink-100);
  --color-bg-inverted:    var(--color-ink-900);

  --color-text-primary:   var(--color-ink-900);
  --color-text-secondary: var(--color-ink-600);
  --color-text-tertiary:  var(--color-ink-500);
  --color-text-inverted:  #ffffff;
  --color-text-brand:     var(--color-brand-700);

  --color-border-default: var(--color-ink-200);
  --color-border-strong:  var(--color-ink-300);
  --color-border-brand:   var(--color-brand-300);

  --color-link-default:   var(--color-brand-700);
  --color-link-hover:     var(--color-brand-500);
  --color-link-active:    var(--color-brand-600);
  --color-link-visited:   var(--color-brand-700);

  --color-focus-ring:     var(--color-warm-500);
  --color-focus-ring-offset: #ffffff;

  /* --------------------------------------------------------------------------
   * 2. DARK SCHEME
   * Override only tokens that actually change. Keep WCAG AA contrast.
   * -------------------------------------------------------------------------- */
  --dark-color-bg-body:        var(--color-ink-900);
  --dark-color-bg-card:        var(--color-ink-800);
  --dark-color-bg-hero:        var(--color-ink-800);
  --dark-color-bg-elevated:    var(--color-ink-700);
  --dark-color-bg-muted:       var(--color-ink-800);
  --dark-color-bg-inverted:    var(--color-ink-50);

  --dark-color-text-primary:   var(--color-ink-50);
  --dark-color-text-secondary: var(--color-ink-300);
  --dark-color-text-tertiary:  var(--color-ink-400);
  --dark-color-text-inverted:  var(--color-ink-900);
  --dark-color-text-brand:     var(--color-brand-300);

  --dark-color-border-default: var(--color-ink-700);
  --dark-color-border-strong:  var(--color-ink-600);
  --dark-color-border-brand:   var(--color-brand-600);

  --dark-color-link-default:   var(--color-brand-300);
  --dark-color-link-hover:     var(--color-brand-200);
  --dark-color-link-active:    var(--color-brand-400);
  --dark-color-link-visited:   var(--color-brand-300);

  --dark-color-focus-ring:     var(--color-warm-400);
  --dark-color-focus-ring-offset: var(--color-ink-900);

  /* --------------------------------------------------------------------------
   * 3. TYPOGRAPHY
   * System-only stack. Korean-first line-height.
   * -------------------------------------------------------------------------- */
  --font-family-sans:  -apple-system, BlinkMacSystemFont, "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-family-mono:  "SFMono-Regular", Consolas, "Liberation Mono", Menlo, "Noto Sans Mono", "Droid Sans Mono", monospace;

  --font-weight-regular: 400;
  --font-weight-medium:  500;
  --font-weight-semibold:600;
  --font-weight-bold:    700;
  --font-weight-extrabold:800;

  /* Type scale. Sizes in rem assume 16px root. */
  --text-xs:    0.75rem;   /* 12px */
  --text-sm:    0.8125rem; /* 13px */
  --text-base:  1rem;      /* 16px */
  --text-md:    1.125rem;  /* 18px */
  --text-lg:    1.25rem;   /* 20px */
  --text-xl:    1.5rem;    /* 24px */
  --text-2xl:   1.75rem;   /* 28px */
  --text-3xl:   2rem;      /* 32px */
  --text-4xl:   2.5rem;    /* 40px */
  --text-5xl:   3rem;      /* 48px */
  --text-6xl:   3.75rem;   /* 60px */

  /* Line-height. Korean needs generous leading. */
  --leading-none:    1;
  --leading-tight:   1.25;
  --leading-snug:    1.375;
  --leading-normal:  1.6;
  --leading-relaxed: 1.75;
  --leading-loose:   1.95;

  /* Letter-spacing */
  --tracking-tight:  -0.02em;
  --tracking-normal: 0;
  --tracking-wide:   0.04em;
  --tracking-wider:  0.08em;

  /* --------------------------------------------------------------------------
   * 4. SPACING
   * 4px base grid. Prefer these steps over arbitrary values.
   * -------------------------------------------------------------------------- */
  --space-0:  0;
  --space-1:  0.25rem;   /* 4px */
  --space-2:  0.5rem;    /* 8px */
  --space-3:  0.75rem;   /* 12px */
  --space-4:  1rem;      /* 16px */
  --space-5:  1.25rem;   /* 20px */
  --space-6:  1.5rem;    /* 24px */
  --space-8:  2rem;      /* 32px */
  --space-10: 2.5rem;    /* 40px */
  --space-12: 3rem;      /* 48px */
  --space-16: 4rem;      /* 64px */
  --space-20: 5rem;      /* 80px */
  --space-24: 6rem;      /* 96px */

  /* Layout gutters */
  --gutter-sm:  var(--space-4);
  --gutter-md:  var(--space-5);
  --gutter-lg:  var(--space-6);
  --gutter-xl:  var(--space-8);

  /* --------------------------------------------------------------------------
   * 5. LAYOUT
   * Container widths and reading measure.
   * -------------------------------------------------------------------------- */
  --container-max: clamp(1200px, 92vw, 1400px);
  --reading-max:   800px;
  --header-height: 64px;
  --rail-card-min: 260px;
  --rail-card-max: 340px;

  /* --------------------------------------------------------------------------
   * 6. RADIUS
   * -------------------------------------------------------------------------- */
  --radius-sm:  6px;
  --radius-md:  10px;
  --radius-lg:  14px;
  --radius-xl:  20px;
  --radius-full:9999px;

  /* --------------------------------------------------------------------------
   * 7. SHADOWS
   * Static only; never animate box-shadow (it forces paint).
   * -------------------------------------------------------------------------- */
  --shadow-sm:  0 1px 2px rgba(15, 20, 16, 0.06);
  --shadow-md:  0 4px 12px rgba(15, 20, 16, 0.08);
  --shadow-lg:  0 14px 32px rgba(15, 20, 16, 0.12);
  --shadow-xl:  0 24px 48px rgba(15, 20, 16, 0.16);
  --shadow-inset: inset 0 0 0 1px var(--color-border-default);

  /* --------------------------------------------------------------------------
   * 8. MOTION
   * -------------------------------------------------------------------------- */
  --duration-instant: 0ms;
  --duration-fast:    150ms;
  --duration-normal:  220ms;
  --duration-slow:    350ms;
  --duration-reveal:  700ms;

  --ease-out:      cubic-bezier(0.16, 1, 0.3, 1);
  --ease-in-out:   cubic-bezier(0.65, 0, 0.35, 1);
  --ease-spring:   cubic-bezier(0.34, 1.56, 0.64, 1);

  /* Scroll-driven reveal animation name (defined in motion.css) */
  --reveal-animation: reveal-up;
}

/* Dark scheme overrides */
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) {
    --color-bg-body:        var(--dark-color-bg-body);
    --color-bg-card:        var(--dark-color-bg-card);
    --color-bg-hero:        var(--dark-color-bg-hero);
    --color-bg-elevated:    var(--dark-color-bg-elevated);
    --color-bg-muted:       var(--dark-color-bg-muted);
    --color-bg-inverted:    var(--dark-color-bg-inverted);

    --color-text-primary:   var(--dark-color-text-primary);
    --color-text-secondary: var(--dark-color-text-secondary);
    --color-text-tertiary:  var(--dark-color-text-tertiary);
    --color-text-inverted:  var(--dark-color-text-inverted);
    --color-text-brand:     var(--dark-color-text-brand);

    --color-border-default: var(--dark-color-border-default);
    --color-border-strong:  var(--dark-color-border-strong);
    --color-border-brand:   var(--dark-color-border-brand);

    --color-link-default:   var(--dark-color-link-default);
    --color-link-hover:     var(--dark-color-link-hover);
    --color-link-active:    var(--dark-color-link-active);
    --color-link-visited:   var(--dark-color-link-visited);

    --color-focus-ring:     var(--dark-color-focus-ring);
    --color-focus-ring-offset: var(--dark-color-focus-ring-offset);

    /* WordPress generates --wp--preset--color--* and --wp--custom--* straight
     * from theme.json in a single unconditional :root rule with no dark
     * variant. Core blocks (has-accent-color, has-base-background-color, the
     * editor color picker, …) read those WP variables, not our --color-*
     * tokens, so without this bridge dark mode never reaches anything
     * WordPress generates. Mirror every theme.json palette slug here, plus
     * the box-shadow values, which are light/dark sensitive (a shadow tuned
     * for a light background is barely visible on a dark one). Radii,
     * durations, and easings do not depend on color scheme and are
     * intentionally left alone. Do NOT delete this as "duplication" of the
     * --color-* overrides above - the WP variable namespace does not alias
     * the raw token namespace. */
    --wp--preset--color--base:     var(--dark-color-bg-body);
    --wp--preset--color--contrast: var(--dark-color-text-primary);
    --wp--preset--color--accent:   var(--dark-color-text-brand);
    --wp--preset--color--surface:  var(--dark-color-bg-card);
    --wp--preset--color--muted:    var(--dark-color-bg-muted);

    --wp--custom--shadow--sm: 0 1px 2px rgba(15, 20, 16, 0.24);
    --wp--custom--shadow--md: 0 4px 12px rgba(15, 20, 16, 0.32);
    --wp--custom--shadow--lg: 0 14px 32px rgba(15, 20, 16, 0.48);
    --wp--custom--shadow--xl: 0 24px 48px rgba(15, 20, 16, 0.64);
  }
}

:root[data-theme="dark"] {
  --color-bg-body:        var(--dark-color-bg-body);
  --color-bg-card:        var(--dark-color-bg-card);
  --color-bg-hero:        var(--dark-color-bg-hero);
  --color-bg-elevated:    var(--dark-color-bg-elevated);
  --color-bg-muted:       var(--dark-color-bg-muted);
  --color-bg-inverted:    var(--dark-color-bg-inverted);

  --color-text-primary:   var(--dark-color-text-primary);
  --color-text-secondary: var(--dark-color-text-secondary);
  --color-text-tertiary:  var(--dark-color-text-tertiary);
  --color-text-inverted:  var(--dark-color-text-inverted);
  --color-text-brand:     var(--dark-color-text-brand);

  --color-border-default: var(--dark-color-border-default);
  --color-border-strong:  var(--dark-color-border-strong);
  --color-border-brand:   var(--dark-color-border-brand);

  --color-link-default:   var(--dark-color-link-default);
  --color-link-hover:     var(--dark-color-link-hover);
  --color-link-active:    var(--dark-color-link-active);
  --color-link-visited:   var(--dark-color-link-visited);

  --color-focus-ring:     var(--dark-color-focus-ring);
  --color-focus-ring-offset: var(--dark-color-focus-ring-offset);

  /* WordPress generates --wp--preset--color--* and --wp--custom--* straight
   * from theme.json in a single unconditional :root rule with no dark
   * variant. Core blocks (has-accent-color, has-base-background-color, the
   * editor color picker, …) read those WP variables, not our --color-*
   * tokens, so without this bridge dark mode never reaches anything
   * WordPress generates. Mirror every theme.json palette slug here, plus
   * the box-shadow values, which are light/dark sensitive (a shadow tuned
   * for a light background is barely visible on a dark one). Radii,
   * durations, and easings do not depend on color scheme and are
   * intentionally left alone. Do NOT delete this as "duplication" of the
   * --color-* overrides above - the WP variable namespace does not alias
   * the raw token namespace. */
  --wp--preset--color--base:     var(--dark-color-bg-body);
  --wp--preset--color--contrast: var(--dark-color-text-primary);
  --wp--preset--color--accent:   var(--dark-color-text-brand);
  --wp--preset--color--surface:  var(--dark-color-bg-card);
  --wp--preset--color--muted:    var(--dark-color-bg-muted);

  --wp--custom--shadow--sm: 0 1px 2px rgba(15, 20, 16, 0.24);
  --wp--custom--shadow--md: 0 4px 12px rgba(15, 20, 16, 0.32);
  --wp--custom--shadow--lg: 0 14px 32px rgba(15, 20, 16, 0.48);
  --wp--custom--shadow--xl: 0 24px 48px rgba(15, 20, 16, 0.64);
}

/**
 * Tecnologolilla Component Catalog Styles
 * Pure CSS pattern library. No imports. Token names match tokens.css.
 * All selectors are documented in README.md with anatomy + rules.
 */

/* ---------------------------------------------------------------------------
 * BASE RESET (very small; front-end baseline only, not admin)
 * --------------------------------------------------------------------------- */
*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  scroll-behavior: smooth;
}

body {
  background: var(--color-bg-body);
  color: var(--color-text-primary);
  font-family: var(--font-family-sans);
  font-size: var(--text-base);
  line-height: var(--leading-normal);
  margin: 0;
  min-width: 320px;
  overflow-x: hidden;
  -webkit-font-smoothing: antialiased;
}

img,
svg,
video {
  display: block;
  height: auto;
  max-width: 100%;
}

a {
  color: var(--color-link-default);
  text-decoration: none;
}

a:hover {
  color: var(--color-link-hover);
  text-decoration: underline;
}

a:active {
  color: var(--color-link-active);
}

:focus-visible {
  outline: 3px solid var(--color-focus-ring);
  outline-offset: 2px;
  border-radius: var(--radius-sm);
}

.sr-only {
  clip: rect(0 0 0 0);
  clip-path: inset(50%);
  height: 1px;
  overflow: hidden;
  position: absolute;
  white-space: nowrap;
  width: 1px;
}

/* ---------------------------------------------------------------------------
 * SHELL & CONTAINERS
 * --------------------------------------------------------------------------- */
.container {
  box-sizing: border-box;
  margin-inline: auto;
  max-width: var(--container-max);
  padding-inline: var(--gutter-md);
  width: 100%;
}

.reading-column {
  box-sizing: border-box;
  margin-inline: auto;
  max-width: var(--reading-max);
  width: 100%;
}

@media (max-width: 767px) {
  .container,
  .reading-column {
    padding-inline: var(--gutter-sm);
  }
}

/* ---------------------------------------------------------------------------
 * TYPOGRAPHY UTILITIES
 * --------------------------------------------------------------------------- */
.text-korean {
  word-break: keep-all;
  overflow-wrap: anywhere;
}

.line-clamp-2 {
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  display: -webkit-box;
  overflow: hidden;
}

.line-clamp-3 {
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 3;
  display: -webkit-box;
  overflow: hidden;
}

/* ---------------------------------------------------------------------------
 * 1. SITE HEADER
 * --------------------------------------------------------------------------- */
.site-header {
  background: var(--color-bg-card);
  border-bottom: 1px solid var(--color-border-default);
  height: var(--header-height);
  position: sticky;
  top: 0;
  z-index: 100;
}

.site-header__inner {
  align-items: center;
  display: flex;
  gap: var(--space-4);
  height: 100%;
  justify-content: space-between;
}

.site-header__brand {
  color: var(--color-text-primary);
  font-size: var(--text-lg);
  font-weight: var(--font-weight-extrabold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-none);
  text-decoration: none;
}

.site-header__brand:hover {
  color: var(--color-text-brand);
  text-decoration: none;
}

.desktop-nav .wp-block-navigation__container {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-5);
  list-style: none;
  margin: 0;
  padding: 0;
}

.desktop-nav .wp-block-navigation-item__content {
  color: var(--color-text-primary);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  padding-block: var(--space-2);
}

.desktop-nav .wp-block-navigation-item__content:hover,
.desktop-nav .wp-block-navigation-item__content[aria-current="page"] {
  color: var(--color-text-brand);
}

/* Mobile menu toggle */
.menu-toggle {
  align-items: center;
  background: transparent;
  border: 1px solid transparent;
  border-radius: var(--radius-md);
  color: var(--color-text-primary);
  cursor: pointer;
  display: none;
  font-size: var(--text-xl);
  height: 40px;
  justify-content: center;
  width: 40px;
}

.menu-toggle:hover {
  background: var(--color-bg-muted);
}

@media (max-width: 900px) {
  /* Scoped to the header wrapper, not bare .desktop-nav: navigation.html is
   * rendered twice (header + mobile drawer) and both instances carry
   * .desktop-nav. Only the header's copy should hide here — the drawer's
   * copy is exactly what the hamburger reveals at this width. */
  .site-header .desktop-nav {
    display: none;
  }

  .menu-toggle {
    display: inline-flex;
  }
}

/* Core gives no className hook on the auto-generated submenu <ul>
 * (.wp-block-navigation__submenu-container), so key off core's class here
 * but scope under .desktop-nav to keep it from leaking into any other
 * navigation block. Reuses .nav-item__flyout's visual treatment above. */
.desktop-nav .wp-block-navigation__submenu-container {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md);
  box-shadow: var(--shadow-lg);
  min-width: 160px;
  padding: var(--space-2) 0;
}

/* min-width above overrides core's collapsed width:0, so the closed
 * submenu's invisible (visibility:hidden) box still occupies 160px,
 * anchored via core's own `.wp-block-navigation .has-child
 * .wp-block-navigation__submenu-container{left:-1px}` (specificity 0,3,0 -
 * matched here, not beaten, so source order decides). This nav only has
 * one submenu and it's the last (rightmost) item, so anchoring from the
 * right instead keeps that invisible box from padding out the page's
 * scrollable width at desktop widths where the container has no slack
 * left to absorb it. */
.desktop-nav .has-child .wp-block-navigation__submenu-container {
  left: auto;
  right: -1px;
}

.desktop-nav .wp-block-navigation__submenu-container a {
  padding: var(--space-2) var(--space-4);
}

/* Mobile drawer (dialog) */
.mobile-drawer {
  border: 0;
  margin: 0 0 0 auto;
  max-height: 100%;
  max-width: min(360px, 100%);
  min-height: 100%;
  padding: var(--space-6);
  width: 100%;
}

.mobile-drawer::backdrop {
  background: rgba(15, 20, 16, 0.32);
}

.mobile-drawer__close {
  background: transparent;
  border: 0;
  color: var(--color-text-primary);
  cursor: pointer;
  float: right;
  font-size: var(--text-3xl);
  line-height: 1;
  padding: var(--space-2);
}

/* The mobile drawer renders the exact same navigation.html template part as the
 * header, so it carries the same .desktop-nav / core classes - there is no separate
 * "mobile nav" markup to hook. Scope under .mobile-drawer to give it its own
 * vertical, full-size-touch-target layout instead of the header's inline row. */
.mobile-drawer .desktop-nav .wp-block-navigation__container {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: var(--space-12) 0 0;
}

.mobile-drawer .desktop-nav .wp-block-navigation-item__content {
  border-radius: var(--radius-md);
  display: block;
  font-size: var(--text-lg);
  padding: var(--space-3) var(--space-4);
}

.mobile-drawer .desktop-nav .wp-block-navigation-item__content:hover,
.mobile-drawer .desktop-nav .wp-block-navigation-item__content[aria-current="page"] {
  background: var(--color-bg-muted);
  color: var(--color-text-brand);
}

/* Reset the header's floating-flyout treatment (background/border/shadow) so the
 * submenu stacks inline as an indented nested list, matching the drawer's vertical
 * flow instead of popping up as a dropdown in a narrow panel. */
.mobile-drawer .desktop-nav .wp-block-navigation__submenu-container {
  background: transparent;
  border: 0;
  border-left: 2px solid var(--color-border-default);
  box-shadow: none;
  margin: var(--space-2) 0 0 var(--space-4);
  min-width: 0;
  padding: 0 0 0 var(--space-4);
  position: static;
}

.mobile-drawer .desktop-nav .wp-block-navigation__submenu-container .wp-block-navigation-item__content {
  font-size: var(--text-base);
}

/* ---------------------------------------------------------------------------
 * 2. SKIP LINK
 * --------------------------------------------------------------------------- */
.skip-link {
  background: var(--color-bg-inverted);
  border-radius: var(--radius-md);
  color: var(--color-text-inverted);
  font-weight: var(--font-weight-semibold);
  left: var(--space-4);
  padding: var(--space-3) var(--space-5);
  position: absolute;
  top: var(--space-4);
  transform: translateY(-150%);
  z-index: 200;
}

.skip-link:focus {
  transform: translateY(0);
}

/* ---------------------------------------------------------------------------
 * 3. BRAND INTRO / HERO
 * --------------------------------------------------------------------------- */
.brand-hero {
  background: var(--color-bg-hero);
  padding-block: var(--space-10);
}

.brand-hero__inner {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: minmax(0, 1.2fr) minmax(260px, 0.8fr);
}

.brand-hero__label {
  color: var(--color-text-brand);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-wide);
  margin: 0 0 var(--space-3);
  text-transform: uppercase;
}

.brand-hero__title {
  font-size: clamp(var(--text-3xl), 4vw, var(--text-5xl));
  font-weight: var(--font-weight-extrabold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-snug);
  margin: 0 0 var(--space-4);
}

.brand-hero__lede {
  color: var(--color-text-secondary);
  font-size: var(--text-md);
  line-height: var(--leading-relaxed);
  margin: 0;
  max-width: 520px;
}

.brand-hero__visual {
  align-items: center;
  display: flex;
  justify-content: center;
}

.brand-hero__mark {
  background: linear-gradient(135deg, var(--color-brand-300), var(--color-brand-500));
  border-radius: var(--radius-xl);
  height: 120px;
  width: 120px;
}

@media (max-width: 900px) {
  .brand-hero__inner {
    grid-template-columns: 1fr;
  }

  .brand-hero__visual {
    display: none;
  }
}

@media (max-width: 767px) {
  .brand-hero {
    padding-block: var(--space-8);
  }
}

/* Compact variant (used in directions that need a shorter hero) */
.brand-hero--compact {
  padding-block: var(--space-8);
}

.brand-hero--compact .brand-hero__inner {
  align-items: center;
  grid-template-columns: 1fr auto;
}

.brand-hero--compact .brand-hero__lede {
  max-width: 640px;
}

/* ---------------------------------------------------------------------------
 * 4. SECTION HEADING
 * --------------------------------------------------------------------------- */
.section-heading {
  align-items: center;
  display: flex;
  gap: var(--space-5);
  justify-content: space-between;
  margin-bottom: var(--space-5);
}

.section-title {
  font-size: var(--text-xl);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
  margin: 0;
}

.section-title a {
  align-items: center;
  color: var(--color-text-primary);
  display: inline-flex;
  gap: var(--space-2);
  text-decoration: none;
}

.section-title a:hover {
  color: var(--color-text-brand);
}

.section-title__chevron {
  color: var(--color-text-brand);
  font-weight: var(--font-weight-regular);
  transition: transform var(--duration-fast) var(--ease-out);
}

.section-title a:hover .section-title__chevron {
  transform: translateX(3px);
}

.section-note {
  color: var(--color-text-tertiary);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  margin: 0;
}

/* ---------------------------------------------------------------------------
 * 5. ARTICLE CARD (one component, five variants)
 * --------------------------------------------------------------------------- */
.card,
/* WordPress renders the query loop as <li class="wp-block-post"> with no
   wrapper class of its own; bind the shell styles directly to that markup. */
.latest-grid li.wp-block-post {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: transform var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}

.card:hover,
.latest-grid li.wp-block-post:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.card:focus-within,
.latest-grid li.wp-block-post:focus-within {
  box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.card__media {
  aspect-ratio: 16 / 10;
  background: linear-gradient(135deg, var(--color-ink-200), var(--color-ink-100));
  display: block;
  flex: 0 0 auto;
  overflow: hidden;
  position: relative;
}

.card__media img {
  aspect-ratio: 16 / 10;
  height: 100%;
  object-fit: cover;
  transition: transform var(--duration-slow) var(--ease-out);
  width: 100%;
}

.card:hover .card__media img,
.latest-grid li.wp-block-post:hover .card__media img {
  transform: scale(1.03);
}

.card__body {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  padding: var(--space-5);
}

.card__date {
  color: var(--color-text-tertiary);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-semibold);
  letter-spacing: var(--tracking-wide);
  margin: 0 0 var(--space-2);
  text-transform: uppercase;
}

.card__title {
  font-size: var(--text-base);
  font-weight: var(--font-weight-bold);
  line-height: var(--leading-snug);
  margin: 0 0 var(--space-2);
}

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

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

.card__excerpt {
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  margin: 0;
}

/* Lead variant */
.card--lead .card__media,
.latest-grid li.wp-block-post:first-child .card__media {
  aspect-ratio: 16 / 9;
}

.card--lead .card__title,
.latest-grid li.wp-block-post:first-child .card__title {
  font-size: clamp(var(--text-lg), 2vw, var(--text-2xl));
  line-height: var(--leading-tight);
}

.card--lead .card__excerpt,
.latest-grid li.wp-block-post:first-child .card__excerpt {
  font-size: var(--text-base);
}

/* The query loop has no .card__body wrapper — date/title/excerpt sit
   directly in the <li>. Recreate its padding without insetting
   .card__media, which needs to stay flush with the card edge. */
.latest-grid li.wp-block-post:first-child {
  padding-bottom: var(--space-5);
}

.latest-grid li.wp-block-post:first-child:not(:has(.card__media)) {
  padding-top: var(--space-5);
}

.latest-grid li.wp-block-post:first-child > :not(.card__media) {
  padding-inline: var(--space-5);
}

/* Text-only lead fallback (no featured image). The lead still spans all
   three rows to match the compact column's height, but date + title + a
   2-line excerpt alone leaves most of that height blank. Give it the same
   "this is deliberate" treatment as the text-only compact/ranked variants
   (accent dot + more breathing room) instead of hiding the empty box:
   tint the background, center the stack in the available height, and let
   the excerpt run past its usual 2-line clamp since there's vertical room
   for it now. */
.latest-grid li.wp-block-post:first-child:not(:has(.card__media)) {
  background: var(--color-bg-muted);
  justify-content: center;
}

.latest-grid li.wp-block-post:first-child:not(:has(.card__media))::before {
  background: var(--color-border-brand);
  border-radius: var(--radius-full);
  content: "";
  display: block;
  height: 8px;
  margin: 0 var(--space-5) var(--space-3);
  width: 8px;
}

.latest-grid li.wp-block-post:first-child:not(:has(.card__media)) .card__excerpt {
  -webkit-line-clamp: 5;
}

/* Compact variant */
.card--compact,
.latest-grid li.wp-block-post:not(:first-child) {
  align-items: center;
  background: transparent;
  border: 0;
  border-bottom: 1px solid var(--color-border-default);
  border-radius: 0;
  box-shadow: none;
  gap: var(--space-4);
  padding-block: var(--space-3);
}

.card--compact {
  display: flex;
  flex-direction: row;
}

/* The query loop's date/title/excerpt are flat siblings of .card__media,
   not children of a .card__body wrapper, so flex-direction: row can't
   group them into a text column the way .card--compact does. A grid with
   .card__media spanning every row pushes the remaining siblings into the
   second column instead, without needing that wrapper. */
/* Compact rows show date + title only (the excerpt is hidden below) —
   two explicit rows so .card__media can span both by referencing the
   grid's actual last line instead of guessing a span count. */
.latest-grid li.wp-block-post:not(:first-child) {
  display: grid;
  grid-template-columns: 96px 1fr;
  grid-template-rows: auto auto;
}

.latest-grid li.wp-block-post:not(:first-child) > .card__media {
  grid-column: 1;
  grid-row: 1 / -1;
}

/* Compact rows show date + title only, matching the approved design —
   the excerpt is what makes the lead card read as the larger one. */
.latest-grid li.wp-block-post:not(:first-child) .card__excerpt {
  display: none;
}

.card--compact:first-child {
  padding-top: 0;
}

.card--compact:last-child,
.latest-grid li.wp-block-post:last-child {
  border-bottom: 0;
}

.card--compact:hover,
.latest-grid li.wp-block-post:not(:first-child):hover {
  box-shadow: none;
  transform: none;
}

.card--compact .card__media,
.latest-grid li.wp-block-post:not(:first-child) .card__media {
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-md);
  height: 96px;
  width: 96px;
}

.card--compact .card__media {
  flex: 0 0 96px;
}

.card--compact .card__media img,
.latest-grid li.wp-block-post:not(:first-child) .card__media img {
  aspect-ratio: 1 / 1;
  border-radius: var(--radius-md);
}

.card--compact .card__body {
  min-width: 0;
  padding: 0;
}

.card--compact .card__title,
.latest-grid li.wp-block-post:not(:first-child) .card__title {
  font-size: var(--text-base);
  line-height: var(--leading-snug);
}

/* Text-only compact fallback (no thumbnail) */
.card--compact:not(:has(.card__media)),
.latest-grid li.wp-block-post:not(:first-child):not(:has(.card__media)) {
  padding-left: var(--space-4);
}

.latest-grid li.wp-block-post:not(:first-child):not(:has(.card__media)) {
  grid-template-columns: 6px 1fr;
}

.card--compact:not(:has(.card__media))::before,
.latest-grid li.wp-block-post:not(:first-child):not(:has(.card__media))::before {
  background: var(--color-border-brand);
  border-radius: var(--radius-full);
  content: "";
  height: 6px;
}

.card--compact:not(:has(.card__media))::before {
  flex: 0 0 6px;
}

.latest-grid li.wp-block-post:not(:first-child):not(:has(.card__media))::before {
  align-self: center;
  grid-column: 1;
  grid-row: 1 / -1;
  width: 6px;
}

/* Ranked variant */
.card--ranked {
  position: relative;
}

.card--ranked .card__rank {
  align-items: center;
  background: var(--color-bg-inverted);
  border-radius: var(--radius-full);
  color: var(--color-text-inverted);
  display: inline-flex;
  font-size: var(--text-xs);
  font-weight: var(--font-weight-extrabold);
  height: 28px;
  justify-content: center;
  left: var(--space-4);
  position: absolute;
  top: var(--space-4);
  width: 28px;
  z-index: 2;
}

.card--ranked .card__title {
  font-size: var(--text-base);
}

.card--ranked .card__body {
  padding: var(--space-4);
}

/* Rail variant */
.card--rail {
  min-width: var(--rail-card-min);
  max-width: var(--rail-card-max);
  scroll-snap-align: start;
  width: 100%;
}

.card--rail .card__body {
  padding: var(--space-4);
}

/* Archive variant */
.card--archive .card__title {
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
}

/* Text-only variants (no media) */
.card:not(:has(.card__media)) .card__body {
  justify-content: center;
  min-height: 160px;
}

.card--ranked:not(:has(.card__media)) .card__rank {
  position: static;
  margin-bottom: var(--space-3);
}

/* ---------------------------------------------------------------------------
 * 6. LATEST SECTION
 * --------------------------------------------------------------------------- */
.latest-section {
  padding-block: var(--space-10) var(--space-8);
}

/* The query loop renders as a single <ul> (.latest-template) holding all
   four <li>, not a lead card plus a separate .latest-secondary column - so
   the two-column split has to live on that <ul> itself: the lead <li>
   spans column 1 across every row, the other three sit stacked in column 2. */
.latest-grid .latest-template {
  column-gap: var(--space-6);
  display: grid;
  grid-template-columns: minmax(0, 1.55fr) minmax(280px, 1fr);
  grid-template-rows: repeat(3, auto);
  row-gap: 0;
}

.latest-grid .latest-template > li:first-child {
  grid-column: 1;
  grid-row: 1 / -1;
}

.latest-grid .latest-template > li:not(:first-child) {
  grid-column: 2;
}

@media (max-width: 900px) {
  .latest-grid .latest-template {
    display: block;
  }
}

/* ---------------------------------------------------------------------------
 * 7. RANKED SECTIONS (Popular / This Week)
 * --------------------------------------------------------------------------- */
.ranked-section {
  padding-block: var(--space-8);
}

.ranked-grid {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(4, minmax(0, 1fr));
}

@media (max-width: 1200px) {
  .ranked-grid {
    gap: var(--space-4);
  }
}

/* Tablet landscape (e.g. 1024px) sat inside the old 901-1200px band that
   still rendered 4 columns - fine while the section spanned the full
   container, but a needless squeeze once the viewport itself narrows.
   Step down to 3 first so the jump to 2 columns lands at the
   tablet-portrait width instead of skipping straight past it. */
@media (max-width: 1100px) {
  .ranked-grid {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }
}

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

@media (max-width: 600px) {
  .ranked-grid {
    grid-template-columns: 1fr;
  }
}

/* Empty state */
.ranked-empty {
  align-items: center;
  background: var(--color-bg-muted);
  border: 1px dashed var(--color-border-strong);
  border-radius: var(--radius-lg);
  color: var(--color-text-secondary);
  display: flex;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-medium);
  gap: var(--space-3);
  justify-content: center;
  min-height: 160px;
  padding: var(--space-6);
}

/* ---------------------------------------------------------------------------
 * 8. CATEGORY RAIL
 * --------------------------------------------------------------------------- */
.category-section {
  padding-block: var(--space-8);
}

.rail-controls {
  display: flex;
  gap: var(--space-2);
}

.rail-control {
  align-items: center;
  background: var(--color-bg-card);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-full);
  color: var(--color-text-primary);
  cursor: pointer;
  display: inline-flex;
  height: 36px;
  justify-content: center;
  transition: background var(--duration-fast) var(--ease-out),
              transform var(--duration-fast) var(--ease-out);
  width: 36px;
}

.rail-control:hover {
  background: var(--color-bg-muted);
  transform: scale(1.05);
}

.rail-control:active {
  transform: scale(0.96);
}

.rail-control:disabled {
  cursor: not-allowed;
  opacity: 0.4;
}

.category-rail {
  display: grid;
  gap: var(--space-5);
  grid-auto-columns: minmax(var(--rail-card-min), 32%);
  grid-auto-flow: column;
  overflow-x: auto;
  padding-bottom: var(--space-2);
  scroll-behavior: smooth;
  scroll-snap-type: x mandatory;
  scrollbar-width: thin;
}

.category-rail::-webkit-scrollbar {
  height: 6px;
}

.category-rail::-webkit-scrollbar-thumb {
  background: var(--color-border-strong);
  border-radius: var(--radius-full);
}

@media (max-width: 767px) {
  .category-rail {
    grid-auto-columns: minmax(250px, 82%);
  }

  .rail-controls {
    display: none;
  }
}

/* ---------------------------------------------------------------------------
 * 9. CATEGORY ARCHIVE HERO
 * --------------------------------------------------------------------------- */
.category-hero {
  background: var(--color-bg-hero);
  padding-block: var(--space-16) var(--space-10);
}

.category-hero__eyebrow {
  color: var(--color-text-brand);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-wide);
  margin: 0 0 var(--space-3);
  text-transform: uppercase;
}

.category-hero__title {
  font-size: clamp(var(--text-3xl), 4vw, var(--text-5xl));
  font-weight: var(--font-weight-extrabold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
  margin: 0 0 var(--space-4);
}

.category-hero__desc {
  color: var(--color-text-secondary);
  font-size: var(--text-md);
  line-height: var(--leading-relaxed);
  margin: 0 0 var(--space-4);
  max-width: 640px;
}

.category-hero__count {
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  margin: 0;
}

/* ---------------------------------------------------------------------------
 * 10. CATEGORY CARD GRID & PAGINATION
 * --------------------------------------------------------------------------- */
.archive-grid {
  padding-block: var(--space-10);
}

/* The mockup's .archive-grid holds cards as direct children, but WordPress's
   query loop wraps them in a <ul class="wp-block-post-template"> - the grid
   columns have to live on that <ul> (given its own className below), not on
   .archive-grid itself, or the <ul> and the pagination <nav> that follows it
   would each become a single grid item instead of the cards inside it. */
.archive-grid .archive-template {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

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

@media (max-width: 600px) {
  .archive-grid .archive-template {
    grid-template-columns: 1fr;
  }
}

/* WordPress renders each post in the query loop as <li class="wp-block-post">
   with none of the .card/.card--archive/.card__body hooks the component CSS
   expects - bind the shell + archive title size directly to that markup,
   scoped under .archive-grid so it cannot collide with .latest-grid's
   lead/compact binding (Task 9). */
.archive-grid li.wp-block-post {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: transform var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}

.archive-grid li.wp-block-post:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.archive-grid li.wp-block-post:focus-within {
  box-shadow: 0 0 0 3px var(--color-focus-ring);
}

.archive-grid li.wp-block-post .card__title {
  font-size: var(--text-lg);
  line-height: var(--leading-snug);
}

.pagination {
  border-top: 1px solid var(--color-border-default);
  display: flex;
  gap: var(--space-4);
  justify-content: center;
  padding-block: var(--space-8);
}

/* Core's query-pagination block emits <a class="page-numbers">, the current page as
 * <span class="page-numbers current">, and the prev/next links as
 * .wp-block-query-pagination-previous / -next - none of which match the mockup's
 * .pagination__link / .pagination__current class names. Scope to .pagination
 * (set via the block's className attribute in each archive template). */
.pagination .wp-block-query-pagination-numbers {
  display: flex;
  gap: var(--space-2);
}

.pagination .page-numbers,
.pagination .wp-block-query-pagination-previous,
.pagination .wp-block-query-pagination-next {
  align-items: center;
  background: var(--color-bg-card);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md);
  color: var(--color-text-primary);
  display: inline-flex;
  font-size: var(--text-sm);
  font-weight: var(--font-weight-semibold);
  height: 40px;
  justify-content: center;
  min-width: 40px;
  padding-inline: var(--space-4);
}

.pagination .page-numbers:hover,
.pagination .wp-block-query-pagination-previous:hover,
.pagination .wp-block-query-pagination-next:hover {
  background: var(--color-bg-muted);
  text-decoration: none;
}

.pagination .page-numbers.current {
  background: var(--color-bg-inverted);
  color: var(--color-text-inverted);
}

/* ---------------------------------------------------------------------------
 * 11. SINGLE ARTICLE
 * --------------------------------------------------------------------------- */
.article-header {
  padding-block: var(--space-12) var(--space-8);
}

.article-header__eyebrow {
  color: var(--color-text-brand);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-wide);
  margin: 0 0 var(--space-3);
  text-transform: uppercase;
}

.article-header__title {
  font-size: clamp(var(--text-2xl), 4vw, var(--text-4xl));
  font-weight: var(--font-weight-extrabold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
  margin: 0 0 var(--space-5);
}

.article-header__meta {
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  margin: 0;
}

.article-cover {
  margin-bottom: var(--space-8);
}

.article-cover__image {
  aspect-ratio: 16 / 9;
  background: linear-gradient(135deg, var(--color-ink-200), var(--color-ink-100));
  border-radius: var(--radius-lg);
  display: block;
  overflow: hidden;
  width: 100%;
}

.article-cover__image img {
  height: 100%;
  object-fit: cover;
  width: 100%;
}

.article-body {
  color: var(--color-text-primary);
  font-size: var(--text-md);
  line-height: var(--leading-relaxed);
  /* Article bodies are author-written post content - the template has no
     opportunity to add a .text-korean class to every inner paragraph, so the
     wrap rule has to live here and inherit down to the actual text nodes. */
  word-break: keep-all;
}

.article-body > * + * {
  margin-top: var(--space-6);
}

.article-body h2 {
  font-size: var(--text-2xl);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
  margin-top: var(--space-12);
}

.article-body h3 {
  font-size: var(--text-xl);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-tight);
  line-height: var(--leading-tight);
  margin-top: var(--space-10);
}

/* Paragraph rhythm has to be carried by the paragraph itself, not by the
 * `.article-body > * + *` flow rule above. Two reasons, both of which showed up as
 * every article rendering as one unbroken wall of text:
 *   1. `.article-body p` is more specific than `.article-body > * + *`, so a
 *      `margin: 0` here beat the flow rule for paragraphs no matter the source order.
 *   2. The flow rule only reaches direct children. Real posts nest paragraphs inside
 *      tables, metric tiles and the table of contents - 31 of 74 in a typical article -
 *      and those can never be reached by a direct-child selector. */
.article-body p {
  margin: 0 0 var(--space-6);
}

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

/* Inside lists and tight components the full paragraph rhythm is too much. */
.article-body :where(li, td, th, figcaption, .metric-tile, .autop-toc) p {
  margin-bottom: var(--space-2);
}

.article-body a {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.article-body figure {
  margin: var(--space-8) 0;
}

.article-body figcaption {
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
  margin-top: var(--space-3);
  text-align: center;
}

.article-body blockquote {
  border-left: 4px solid var(--color-brand-500);
  color: var(--color-text-secondary);
  font-size: var(--text-lg);
  font-style: normal;
  line-height: var(--leading-relaxed);
  margin: var(--space-8) 0;
  padding-left: var(--space-6);
}

.article-body :where(ul, ol) {
  padding-left: var(--space-6);
}

.article-body li + li {
  margin-top: var(--space-2);
}

.article-body pre,
.article-body code {
  font-family: var(--font-family-mono);
}

.article-body pre {
  background: var(--color-bg-muted);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-md);
  font-size: var(--text-sm);
  line-height: var(--leading-normal);
  overflow-x: auto;
  padding: var(--space-5);
}

.article-body table {
  border-collapse: collapse;
  display: block;
  font-size: var(--text-sm);
  overflow-x: auto;
  width: max-content;
  max-width: 100%;
}

.article-body th,
.article-body td {
  border-bottom: 1px solid var(--color-border-default);
  padding: var(--space-3) var(--space-4);
  text-align: left;
}

.article-body th {
  background: var(--color-bg-muted);
  font-weight: var(--font-weight-semibold);
}

/* Table of contents */
.toc {
  background: var(--color-bg-muted);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-lg);
  padding: var(--space-6);
}

.toc__title {
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-wide);
  margin: 0 0 var(--space-4);
  text-transform: uppercase;
}

.toc__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.toc__list a {
  color: var(--color-text-secondary);
  font-size: var(--text-sm);
}

.toc__list a:hover {
  color: var(--color-text-brand);
}

/* Related posts */
.related-posts {
  border-top: 1px solid var(--color-border-default);
  margin-top: var(--space-16);
  padding-top: var(--space-10);
}

.related-posts__title {
  font-size: var(--text-xl);
  font-weight: var(--font-weight-bold);
  margin: 0 0 var(--space-6);
}

/* Same WordPress <ul class="wp-block-post-template"> wrapper problem as the
   archive grid above - the grid columns live on that <ul> (given its own
   className here), not on .related-posts__grid itself. */
.related-posts__grid .related-posts__template {
  display: grid;
  gap: var(--space-5);
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

@media (max-width: 900px) {
  .related-posts__grid .related-posts__template {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (max-width: 600px) {
  .related-posts__grid .related-posts__template {
    grid-template-columns: 1fr;
  }
}

/* Same query-loop markup gap as the archive grid: <li class="wp-block-post">
   carries none of the .card shell styling, scoped here so it can't collide
   with .latest-grid's or .archive-grid's own bindings. */
.related-posts__grid li.wp-block-post {
  background: var(--color-bg-card);
  border: 1px solid var(--color-border-default);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-sm);
  display: flex;
  flex-direction: column;
  overflow: hidden;
  transition: transform var(--duration-fast) var(--ease-out),
              box-shadow var(--duration-fast) var(--ease-out);
}

.related-posts__grid li.wp-block-post:hover {
  box-shadow: var(--shadow-md);
  transform: translateY(-2px);
}

.related-posts__grid li.wp-block-post:focus-within {
  box-shadow: 0 0 0 3px var(--color-focus-ring);
}

/* ---------------------------------------------------------------------------
 * 12. BREADCRUMB
 * --------------------------------------------------------------------------- */
.breadcrumb {
  color: var(--color-text-tertiary);
  font-size: var(--text-sm);
  margin-bottom: var(--space-6);
}

.breadcrumb__list {
  align-items: center;
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  list-style: none;
  margin: 0;
  padding: 0;
}

.breadcrumb__list a {
  color: var(--color-text-secondary);
}

.breadcrumb__sep {
  opacity: 0.6;
}

/* ---------------------------------------------------------------------------
 * 13. SITE FOOTER
 * --------------------------------------------------------------------------- */
.site-footer {
  background: var(--color-bg-inverted);
  color: var(--color-text-inverted);
  margin-top: var(--space-16);
}

.site-footer__inner {
  display: grid;
  gap: var(--space-6);
  grid-template-columns: minmax(0, 1fr) auto auto;
  padding-block: var(--space-10);
}

.site-footer__brand {
  color: var(--color-text-inverted);
  font-size: var(--text-lg);
  font-weight: var(--font-weight-extrabold);
  margin: 0 0 var(--space-2);
}

.site-footer__tagline {
  color: var(--color-ink-300);
  font-size: var(--text-sm);
  line-height: var(--leading-relaxed);
  margin: 0;
  max-width: 320px;
}

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

.site-footer__nav-list a {
  color: var(--color-text-inverted);
  font-size: var(--text-sm);
}

.site-footer__nav-list a:hover {
  color: var(--color-brand-300);
}

.site-footer__social {
  align-items: center;
  border: 1px solid var(--color-ink-600);
  border-radius: var(--radius-full);
  color: var(--color-text-inverted);
  display: inline-flex;
  font-weight: var(--font-weight-bold);
  height: 40px;
  justify-content: center;
  transition: background var(--duration-fast) var(--ease-out);
  width: 40px;
}

.site-footer__social:hover {
  background: var(--color-ink-700);
  color: var(--color-text-inverted);
}

.site-footer__bottom {
  border-top: 1px solid var(--color-ink-700);
  color: var(--color-ink-300);
  font-size: var(--text-sm);
  padding-block: var(--space-5);
  text-align: center;
}

@media (max-width: 900px) {
  .site-footer__inner {
    grid-template-columns: 1fr;
  }

  .site-footer__nav-list {
    justify-content: center;
  }

  .site-footer__social-wrap {
    justify-self: start;
  }
}

/* ---------------------------------------------------------------------------
 * 14. 404 PAGE
 * --------------------------------------------------------------------------- */
.not-found {
  padding-block: var(--space-20);
  text-align: center;
}

.not-found__code {
  color: var(--color-text-brand);
  font-size: clamp(var(--text-5xl), 10vw, var(--text-6xl));
  font-weight: var(--font-weight-extrabold);
  line-height: var(--leading-none);
  margin: 0 0 var(--space-4);
}

.not-found__title {
  font-size: var(--text-2xl);
  font-weight: var(--font-weight-bold);
  margin: 0 0 var(--space-4);
}

.not-found__lede {
  color: var(--color-text-secondary);
  margin: 0 0 var(--space-6);
}

.not-found__link {
  background: var(--color-bg-inverted);
  border-radius: var(--radius-full);
  color: var(--color-text-inverted);
  display: inline-flex;
  font-weight: var(--font-weight-semibold);
  padding: var(--space-3) var(--space-6);
}

.not-found__link:hover {
  background: var(--color-ink-700);
  color: var(--color-text-inverted);
}

/* ---------------------------------------------------------------------------
 * 15. FLUID PORTAL (direction B) — promoted to the default design.
 * Direction B is the approved design (see mockup/home-b.html). Its variant
 * overrides, previously scoped to a body-level modifier class in the
 * mockup, are promoted to defaults here with that scoping class removed.
 * Source order makes these win over the base rules above for the
 * properties they touch.
 * --------------------------------------------------------------------------- */
.brand-hero {
  background: linear-gradient(180deg, var(--color-bg-hero), var(--color-bg-body));
  text-align: center;
}

.brand-hero__inner {
  display: block;
  margin-inline: auto;
  max-width: 760px;
}

.brand-hero__label {
  justify-content: center;
}

.brand-hero__title {
  font-size: clamp(var(--text-3xl), 5vw, var(--text-5xl));
  /* No token matches 1.22 exactly (closest is --leading-tight at 1.25); kept
   * literal per the approved mockup rather than inventing a token. */
  line-height: 1.22;
  margin-inline: auto;
}

.brand-hero__lede {
  margin-inline: auto;
  max-width: 560px;
}

.brand-hero__visual {
  display: none;
}

.section-title {
  font-size: var(--text-2xl);
}

.section-title a {
  gap: var(--space-3);
}

.section-title__chevron {
  font-size: 1.2em;
}

.card {
  border-radius: var(--radius-xl);
}

.card--compact {
  border-radius: 0;
}

.ranked-grid {
  gap: var(--space-5);
}

.category-rail {
  gap: var(--space-4);
}

.rail-control {
  background: var(--color-bg-hero);
  border: 0;
}
