/*
Theme Name: GWill Tech Blog
Theme URI: https://github.com/godschi10/gwill-tech-theme
Author: G-will Chijioke
Author URI: https://github.com/godschi10
Description: Tech blog theme for Android, Web-Dev, and Software guides. Built from wireframe with forced dark mode.
Version: 1.22.30
Requires at least: 6.4
Requires PHP: 7.4
Tested up to: 7.0
License: GNU General Public License v2 or later
License URI: https://www.gnu.org/licenses/gpl-2.0.html
Text Domain: gwill-tech
Tags: custom, blog, dark-mode
*/

/*
Table of Contents
1. CSS VARIABLES - Forced Dark Mode (Wireframe Source of Truth)
2. RESET & BASE
3. TYPOGRAPHY SCALE
4. GUTENBERG BLOCK STYLES (v1.6.0) - every block gets a design
5. GUTENBERG BLOCK STYLES - widget/utility blocks (v1.6.2)
6. LAYOUT UTILITIES
7. BUTTONS
8. CARDS
9. BADGES & PILLS
10. FORM INPUTS
11. HEADER - Brand Spec: .prompt (green glow), .gap, .name, .cursor, BELL PANEL (v1.19.32)
12. SEARCH DROPDOWN
13. COOKIE BAR
14. NEWSLETTER BAND (premium widget - homepage + in-article variants)
15. FOOTER
16. HERO SECTION
17. HERO BOOT ANIMATION
18. FEATURED POST (replaces old hero)
19. TOC (TABLE OF CONTENTS) - Terminal branded
20. PAGE HERO & BREADCRUMB
21. READING PROGRESS BAR
22. ARTICLE LAYOUT (Single Post)
23. SHARE ROW
24. AUTHOR BOX (premium - avatar, role, bio, follow links, terminal card)
25. POST NAVIGATION
26. RELATED POSTS (premium 3-card grid - card system)
27. COMMENTS
28. CONTACT FORM (gwill-form)
29. LEGAL PAGES - card-grouped layout with sidebar ToC
30. VIBE COMMENTS - theme-level overrides
31. AD SLOT
32. FILTER BAR (Home/Archive)
33. EMPTY STATE / 404
34. REVEAL ANIMATIONS
35. MOBILE BOTTOM TAB BAR
36. MOBILE NAV OVERLAY
37. MOBILE NAV - TERMINAL OS UPGRADE (v1.15.8)
38. PWA INSTALL CARD (v1.18.89)
*/

/* ==========================================================================
   1. CSS VARIABLES - Forced Dark Mode (Wireframe Source of Truth)
   ========================================================================== */
:root {
  color-scheme: dark;
  --bg: #0d0d0d;
  --surface: #111318;
  --surface-2: #181c24;
  --border: #596276; /* ≥3:1 vs bg/surface - WCAG 1.4.11 non-text contrast */
  --border-2: #252836;
  --text: #e2e8f0;
  --mid: #8896aa;
  --dim: #7586a0;
  --dim2: #7788a3;
  --green: #00ff91;
  --gwill-red: #ff4545;
  --on-green: #08160f; /* theme error/danger - used by form validation + app fault states */
  --green-hover: #33ffa8;
  --green-dim: rgba(0, 255, 145, .06);
  --green-glow: rgba(0, 255, 145, .14);
  --green-border: rgba(0, 255, 145, .22);
  --cat-android: #00ff91;
  --cat-android-dim: rgba(0, 255, 145, .10);
  --cat-android-border: rgba(0, 255, 145, .22);
  --cat-webdev: #9f7aea;
  --cat-webdev-dim: rgba(124, 58, 237, .10);
  --cat-webdev-border: rgba(124, 58, 237, .22);
  --cat-software: #22d3ee;
  --cat-software-dim: rgba(34, 211, 238, .10);
  --cat-software-border: rgba(34, 211, 238, .22);
  --font-mono: 'JetBrains Mono', monospace;
  --font-body: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
  --sp-4: 16px;
  --sp-2: 8px;
  --sp-5: 20px;
  --sp-6: 24px;
  --sp-8: 32px;
  --sp-10: 40px;
  --sp-12: 48px;
  --sp-16: 64px;
  --sp-20: 80px;
  --sp-24: 96px;
  --sp-32: 128px;
  /* ── 1a. Radius scale (premium pass v1.17.0) ─────────────────────────────── */
     Soft radii on surfaces/cards/buttons/inputs; keep sharpness ONLY on
     terminal micro-elements (--r-xs: inline code, kbd, caret chips). */
  --r-xs: 4px;   /* terminal micro-elements - sharpness IS the identity */
  --r-sm: 8px;   /* buttons, inputs, badges, chips, dropdowns */
  --r: 12px;     /* cards, widgets, surfaces */
  --r-lg: 16px;  /* featured card, cookie, toc-sidebar, large surfaces */
  --r-xl: 22px;  /* hero carousel, CTA band, premium panels */
  --r-pill: 100px;

  /* ── 1b. Shadow scale (dark-appropriate depth, premium pass) ─────── */
  --shadow-xs: 0 1px 2px rgba(0, 0, 0, .35);
  --shadow-sm: 0 2px 10px rgba(0, 0, 0, .38);
  --shadow-md: 0 8px 24px rgba(0, 0, 0, .45);
  --shadow-lg: 0 16px 44px rgba(0, 0, 0, .55);
  --shadow-glow: 0 0 18px rgba(0, 255, 145, .10);
  --shadow-glow-strong: 0 0 28px rgba(0, 255, 145, .20);
  --ring-green: 0 0 0 3px var(--green-glow);

  --ease-out: cubic-bezier(.23, 1, .32, 1);
  --ease-quick: cubic-bezier(.2, .8, .2, 1);
  --content-w: 1180px;
  --sidebar-w: 300px;
  --btm-tab-h: 56px;
  --z-sticky: 200;
  --z-btm-tab: 200;
  --z-cookie: 400;
  --z-mob-nav: 500;
}

/* ── 1c. Accessibility: skip link + screen-reader-only helper ────── */
.skip-link, .screen-reader-text {
  position: absolute !important; width: 1px; height: 1px; overflow: hidden;
  clip: rect(1px,1px,1px,1px); clip-path: inset(50%); white-space: nowrap;
}
.skip-link:focus {
  position: fixed; top: 8px; left: 8px; z-index: 9999; width: auto; height: auto;
  clip: auto; clip-path: none; white-space: normal;
  background: var(--green); color: #0d0d0d;
  padding: 10px 16px; border-radius: var(--r-sm);
  font-family: var(--font-mono); font-size: 12px; font-weight: 700;
  box-shadow: 0 0 0 3px rgba(0,255,145,.3), 0 6px 24px rgba(0,0,0,.5);
}

/* ==========================================================================
  BRANDED SCROLLBAR - dark terminal aesthetic (webkit + Firefox)
   --------------------------------------------------------------------------
   NOTE: NOT gated behind (hover: hover). Android Chrome applies
   ::-webkit-scrollbar on touch devices when scrolling; Firefox Android
   honors scrollbar-width/scrollbar-color. iOS Safari does not support
   styling native scrollbars at all (OS-level overlay scrollbar) - that
   is a platform limitation, not a theme bug.
   ========================================================================== */
/* ── 1d. Firefox: branded thin scrollbar - desktop (fine pointer) only ──── */
   Firefox Android renders `scrollbar-width: thin` as a PERMANENT visible
   scrollbar gutter (touch Firefox has no overlay scrollbars), so the
   branding is gated behind hover-capable pointers. Touch devices fall
   back to an overlay (none) scrollbar that hides when idle - the same
   auto-hide behaviour the WebKit/Chromium ::-webkit-scrollbar rules
   produce on Android Chrome. */
@media (hover: hover) and (pointer: fine) {
  * {
    scrollbar-width: thin;
    scrollbar-color: var(--green-border) var(--surface);
  }
}
@media (hover: none) {
  * {
    scrollbar-width: none;
  }
}
/* ── 1e. WebKit / Chromium (desktop + Android) ───────────────────── */
::-webkit-scrollbar {
  width: 6px;
  height: 6px;
}
::-webkit-scrollbar-track {
  background: var(--surface);
  border-radius: 3px;
}
::-webkit-scrollbar-thumb {
  background: var(--green-border);
  border-radius: 3px;
  transition: background .2s;
}
::-webkit-scrollbar-thumb:hover {
  background: var(--green);
}
::-webkit-scrollbar-corner {
  background: transparent;
}

/* ==========================================================================
   2. RESET & BASE
   ========================================================================== */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0 }
html { font-size: 16px; scroll-behavior: smooth; overflow-x: clip; scrollbar-gutter: stable; -webkit-text-size-adjust: 100%; text-size-adjust: 100% }
html body {
  font-family: var(--font-body);
  background: var(--bg);
  /* v1.16.14: noise texture removed entirely - the fixed ::before overlay and
     the background-image layer both made axe unable to compute color-contrast
     (semi-transparent layer / image-backed ancestor). At 0.025 opacity it was
     visually imperceptible, so removing it costs nothing visually and lets
     every contrast check resolve. */
  color: var(--text);
  line-height: 1.8;
  -webkit-font-smoothing: antialiased;
  overflow-wrap: break-word;
  overflow-x: clip;
}
/* ── 2a. Brand text selection - terminal green highlight ───────────── */
::selection { background: rgba(0, 255, 145, .28); color: var(--text) }
::-moz-selection { background: rgba(0, 255, 145, .28); color: var(--text) }
img, svg, video { display: block; max-width: 100%; height: auto }
body a { color: inherit; text-decoration: none }
/* [hidden] must ALWAYS beat element-level display rules (e.g. .gbp-btn sets
 * display directly, silently un-hiding hidden buttons - v1.19.37 bug). */
[hidden] { display: none !important; }
button { cursor: pointer; font-family: inherit }
input, textarea, select { font-family: inherit }
ul, ol { list-style: none }
/* Touch ergonomics - suppress double-tap-zoom on interactive elements. The
   width=device-width viewport meta already removed the 300ms click delay;
   this also kills the double-tap zoom flash on buttons/links. */
button, a, .pill, .page-numbers, .mtb-t, .mno-caret { touch-action: manipulation }
body h1, body h2, body h3, body h4, body h5, body h6 { font-family: var(--font-mono); font-weight: 800; line-height: 1.15; color: var(--text) }

/* ── 2b. Focus visible - visible ring + soft glow (premium pass) ───── */
:focus-visible { outline: 2px solid var(--green); outline-offset: 3px; border-radius: 4px; box-shadow: 0 0 0 4px rgba(0, 255, 145, .12) }
@media (hover: none) { :focus-visible { box-shadow: none } }

/* ── 2c. Reduced motion ────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
}

/* ==========================================================================
   3. TYPOGRAPHY SCALE
   ========================================================================== */
.h1 { font-size: 40px; font-size: clamp(30px, 5vw, 52px); font-weight: 800; line-height: 1.1; letter-spacing: -.03em }
.h2 { font-size: 28px; font-size: clamp(22px, 3vw, 34px); font-weight: 700; line-height: 1.2 }
.h3 { font-size: 19px; font-size: clamp(17px, 2vw, 22px); font-weight: 700 }
.body { font-size: 18px; line-height: 1.8 }
.body-sm { font-size: 16px; line-height: 1.75 }
.label { font-size: 12px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--dim); font-family: var(--font-mono) }
.label-green { color: var(--green) }

/* ── 3a. Section headers (homepage) ────────────────────────────────── */
.sec-head { margin-bottom: 20px }
.sec-head-link { transition: color .15s }
.sec-grid-bottom { margin-bottom: 24px }
.filter-pills { gap: 8px; flex-wrap: wrap }

/* ── 3b. Prose styles for article content ──────────────────────────── */
.prose { max-width: 68ch; min-width: 0; width: 100% }
.prose p { margin-bottom: 1.2em; font-size: 17px; line-height: 1.8 }
.prose h2 { font-size: 24px; font-weight: 800; margin: 2.8em 0 .8em }
.prose h3 { font-size: 18px; font-weight: 700; margin: 2em 0 .6em }
.prose ul, .prose ol { margin: 0 0 1.4em; padding-left: 0; list-style: none }
/* Branded markers ONLY on plain content lists - Gutenberg wp-block-list or
   classic editor lists with no class. Widget/utility lists (categories,
   archives, social links, latest comments) keep their own dedicated rules. */
.prose ul.wp-block-list > li,
.prose ol.wp-block-list > li,
.prose ul:not([class]) > li,
.prose ol:not([class]) > li {
  margin-bottom: .6em;
  line-height: 1.8;
  padding-left: 1.6em;
  position: relative;
}
.prose ul.wp-block-list > li::before,
.prose ul:not([class]) > li::before {
  content: '\003E\005F';
  position: absolute;
  left: 0;
  font-family: var(--font-mono);
  color: var(--green);
  font-weight: 700;
}
.prose ol.wp-block-list, .prose ol:not([class]) { counter-reset: gwill-step }
.prose ol.wp-block-list > li, .prose ol:not([class]) > li { counter-increment: gwill-step }
.prose ol.wp-block-list > li::before,
.prose ol:not([class]) > li::before {
  content: counter(gwill-step, decimal-leading-zero);
  position: absolute;
  left: 0;
  font-family: var(--font-mono);
  color: var(--green);
  font-weight: 700;
  font-size: .85em;
}
.prose blockquote { border-left: 3px solid var(--green); padding: .2em 0 .2em 20px; margin: 1.6em 0; color: var(--mid); font-style: italic }
.prose a { color: var(--green); text-decoration: underline; text-underline-offset: 3px }
.prose .btn { text-decoration: none }
.prose .badge { text-decoration: none }
.prose pre { background: #08090b; border: 1px solid var(--border); border-radius: var(--r); padding: 20px; overflow-x: auto; -webkit-overflow-scrolling: touch; font-size: 13px; line-height: 1.7; margin: 1.4em 0; position: relative; max-width: 100% }
.prose pre code { color: #c9d1d9; font-family: var(--font-mono); word-break: break-all }
.prose .code-lang { position: absolute; top: 10px; right: 52px; font-size: 10px; color: var(--dim2); text-transform: uppercase }
.prose .copy-btn { position: absolute; top: 8px; right: 8px; min-height: 44px; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 9px 14px; font-size: 11px; font-weight: 600; color: var(--mid); cursor: pointer }
@media (hover: hover) { .prose .copy-btn:hover { color: var(--text); border-color: var(--border-2) } }
.prose code:not(pre code) { background: var(--surface-2); padding: 2px 6px; border-radius: var(--r-xs); font-size: .9em; color: var(--green); font-family: var(--font-mono) }

/* ── 3c. Post tags (premium pill chips, terminal # prompt) ───────── */
/* The .post-tags container receives the post's category color vars
   (gwill_category_vars in single.php) - every chip inherits the category
   tint via var(--c, …) with the brand green as fallback, so the tag row
   reads as a colored chip set instead of generic grey pills. */
.post-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  margin: var(--sp-6) 0;
  padding-top: var(--sp-4);
  border-top: 1px solid var(--border);
}
.post-tag {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  padding: 8px 16px;
  min-height: 44px;
  border-radius: var(--r-pill);
  border: 1px solid var(--c-border, var(--border));
  font-size: 12px;
  font-weight: 600;
  color: var(--c, var(--mid));
  font-family: var(--font-mono);
  text-decoration: none;
  background: var(--surface);
  transition: border-color .15s, color .15s, background .15s, transform .12s var(--ease-quick), box-shadow .2s;
}
.post-tag::before {
  content: '#';
  color: var(--c, var(--dim2));
  font-weight: 700;
  transition: color .15s;
}
@media (hover: hover) {
  .post-tag:hover {
    border-color: var(--c, var(--green-border));
    color: var(--c, var(--green));
    background: var(--c-dim, var(--green-dim));
    transform: translateY(-1px);
    box-shadow: var(--shadow-glow);
  }
  .post-tag:hover::before { color: var(--c, var(--green)) }
}

/* ── 3d. Images in prose ─────────────────────────────────────────── */
.prose img { cursor: zoom-in; transition: opacity .2s }
/* Single images get the SAME rounding as gallery images (var(--r), matching
   .prose .wp-block-gallery img below) - ad-slot imagery excluded (already
   clipped by the slot's own rounded overflow). */
.prose img:not(.ad-slot__content img) { border-radius: var(--r) }
@media (hover: hover) { .prose img:hover { opacity: .92 } }

/* Image captions - terminal comment style: mono, muted, # prefix.
   Without this, figcaption inherits body text styles and reads as
   paragraph content. The # marks it as metadata, not prose. */
.prose figcaption,
.wp-element-caption,
.wp-caption-text {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--mid);
  line-height: 1.6;
  text-align: center;
  margin: 10px auto 0;
  max-width: 92%;
}
.prose figcaption::before,
.wp-element-caption::before,
.wp-caption-text::before { content: '# '; color: var(--green); font-weight: 700 }
.prose figcaption a,
.wp-element-caption a,
.wp-caption-text a { color: var(--green); text-decoration: underline; text-underline-offset: 2px }

/* Image figures need bottom breathing room - the universal reset
   (* { margin: 0 }) kills Gutenberg's default figure margins, so
   stacked images used to touch the next element with zero gap. */
.prose figure { margin: 0 0 var(--sp-6) }
.prose figure:last-child { margin-bottom: 0 }

/* ── 3e. About page ──────────────────────────────────────────────── */
.about-hero { margin-bottom: var(--sp-8); position: relative }
.about-hero::before { content: ""; position: absolute; top: -10%; right: -20%; bottom: -10%; left: -20%; inset: -10% -20%; width: 140%; height: 140%; background: radial-gradient(ellipse at 30% 50%, rgba(0, 255, 145, 0.06), transparent 65%); pointer-events: none }
.about-intro { display: grid; grid-template-columns: 1fr auto; gap: var(--sp-10); align-items: center; position: relative; z-index: 2 }
.about-text { min-width: 0 }
#search-results.has-results { border-top: 1px solid var(--border); padding-top: var(--sp-4) }
/* ── 3f. Disable reveal animation on search results page cards ───── */
.search .card.reveal { animation: none }
.about-avatar {
  width: 180px; height: 180px; border-radius: var(--r-lg);
  background: linear-gradient(160deg, #0a1f22, var(--surface) 75%);
  border: 1px solid var(--border);
  display: flex; align-items: center; justify-content: center;
  font-size: 56px; font-weight: 800; color: var(--green);
  font-family: var(--font-mono); flex-shrink: 0;
  text-shadow: 0 0 20px rgba(0,255,145,.3);
  overflow: hidden;
}
.about-avatar img,
.about-avatar .author-gravatar {
  width: 100%; height: 100%; object-fit: cover;
  border-radius: var(--r-lg);
}
.about-stats {
  display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-5);
  padding: var(--sp-6); background: var(--surface);
  border: 1px solid var(--border); border-radius: var(--r);
  margin-bottom: var(--sp-8);
}
.about-stat { font-size: 13px; color: var(--mid); font-family: var(--font-mono); text-align: center; border-right: 1px solid var(--border); padding: 0 var(--sp-4) }
.about-stat:last-child { border-right: none }
.about-stat strong { display: block; font-size: 24px; font-weight: 800; color: var(--green); margin-bottom: 4px }
.about-cta { text-align: center; padding: var(--sp-10) 0 }
.about-cta p { font-size: 17px; color: var(--mid); margin-bottom: var(--sp-5); line-height: 1.7 }
@media (max-width: 1023px) { .about-avatar { margin: 0 auto } .about-stats { grid-template-columns: repeat(2, 1fr); gap: var(--sp-4) } .about-stat:nth-child(2n) { border-right: none } .about-stat { padding: var(--sp-3) 0 } }
@media (max-width: 767px) { .about-intro { grid-template-columns: 1fr; text-align: left } .about-avatar { width: 120px; height: 120px; font-size: 36px } .about-stats { grid-template-columns: repeat(2, 1fr) } .about-stat strong { font-size: 20px } }

/* ── 3g. About Content (word-break safety) ───────────────────────── */
.about-content { max-width: 66ch; margin: 0 auto var(--sp-8); padding: 0 var(--sp-4) }
.start-here-content { max-width: 100% }
.start-here-grid { margin-top: var(--sp-8) }
.start-here-grid .card-body { display: flex; flex-direction: column; flex: 1 }
.resources-page-content { max-width: 100% }
.disclaimer-content { max-width: 100% }
.privacy-content { max-width: 100% }
.about-hero h1 { overflow-wrap: break-word; word-break: break-word }
/* Archive/category description links - brand green + underline so users see
   there's a link (the description <p> inherits gray var(--mid) otherwise). */
.about-hero .about-text p a { color: var(--green); text-decoration: underline; text-underline-offset: 3px }
@media (hover: hover) { .about-hero .about-text p a:hover { color: var(--green); text-decoration: none; opacity: .85 } }
@media (max-width: 767px) { .about-content { max-width: 100%; padding: 0 var(--sp-5) } }

/* ── 3h. Lightbox ────────────────────────────────────────────────── */
.gl-overlay {
  position: fixed; top: 0; right: 0; bottom: 0; left: 0; inset: 0; z-index: 99999;
  background: rgba(0, 0, 0, .92);
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .25s ease, visibility 0s linear .25s;
  -webkit-backdrop-filter: blur(8px); backdrop-filter: blur(8px);
}
.gl-overlay.gl-open { opacity: 1; visibility: visible; pointer-events: auto; transition: opacity .25s ease }
.gl-image-wrap { display: flex; align-items: center; justify-content: center; max-width: 90vw; max-height: 80vh }
.gl-image { max-width: 100%; max-height: 80vh; object-fit: contain; border-radius: var(--r-sm); box-shadow: 0 8px 40px rgba(0,0,0,.5) }
.gl-close {
  position: absolute; top: 16px; right: 16px;
  width: 44px; height: 44px; border-radius: 50%;
  background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.12);
  color: #fff; font-size: 24px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background .15s; z-index: 2;
  font-family: var(--font-mono);
}
@media (hover: hover) { .gl-close:hover { background: rgba(255,255,255,.16) } }
.gl-nav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 48px; height: 48px; border-radius: 50%;
  background: rgba(255,255,255,.08); border: 1px solid rgba(255,255,255,.12);
  color: #fff; font-size: 28px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background .15s; z-index: 2;
  font-family: var(--font-mono);
}
@media (hover: hover) { .gl-nav:hover { background: rgba(255,255,255,.16) } }
.gl-prev { left: 16px }
.gl-next { right: 16px }
.gl-caption {
  position: absolute; bottom: 0; left: 0; right: 0;
  text-align: center; padding: 20px;
  color: rgba(255,255,255,.7); font-size: 14px;
  background: linear-gradient(transparent, rgba(0,0,0,.6));
}
.gl-counter {
  position: absolute; top: 20px; left: 50%; transform: translateX(-50%);
  font-family: 'JetBrains Mono', monospace;
  font-size: 13px; font-weight: 600;
  color: rgba(255,255,255,.6);
  background: rgba(0,0,0,.4);
  padding: 4px 14px;
  border-radius: 100px;
  border: 1px solid rgba(255,255,255,.1);
  pointer-events: none;
  z-index: 2;
}
@media (max-width: 767px) {
  .gl-nav { width: 44px; height: 44px; font-size: 22px }
  .gl-prev { left: 8px }
  .gl-next { right: 8px }
  .gl-image { max-height: 70vh }
}

/* ── 3i. Tables in prose - override WP block defaults ────────────── */
.prose table { width: 100%; border-collapse: collapse; margin: 1.4em 0; font-size: 14px; line-height: 1.6 }
.prose th, .prose td { border: 1px solid var(--border); padding: 12px 14px; text-align: left }
.prose th { background: var(--surface-2); font-weight: 700; font-size: 12px; text-transform: uppercase; letter-spacing: .06em; color: var(--mid); font-family: var(--font-mono) }
.prose td { background: var(--surface) }
.prose tr:nth-child(even) td { background: rgba(255,255,255,.02) }
@media (hover: hover) { .prose tbody tr:hover td { background: var(--green-dim) } }
.prose thead { border-bottom: none } /* Kill WP's 3px white-ish thead border */
.prose .wp-block-table thead { border-bottom: 1px solid var(--border) } /* Our thin border instead */
@media (max-width: 767px) { .prose table { font-size: 12px; display: block; overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100% } .prose th, .prose td { padding: 8px 10px } }

/* ── 3j. Figure wrapper for WP block tables ──────────────────────── */
.prose figure.wp-block-table { margin: 1.4em 0; overflow-x: auto; -webkit-overflow-scrolling: touch; max-width: 100% }

/* ── 3k. WP Separator ────────────────────────────────────────────── */
.prose hr, .prose .wp-block-separator { border: none; border-top: 1px solid var(--border); margin: 3em 0; height: 1px }

/* ── 3l. WP Gallery block ────────────────────────────────────────── */
.prose .wp-block-gallery { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin: 1.4em 0; list-style: none; padding: 0 }
.prose .wp-block-gallery .wp-block-image { margin: 0; width: 100% !important }
.prose .wp-block-gallery img { width: 100%; height: 200px; object-fit: cover; border-radius: var(--r); cursor: zoom-in }
@media (max-width: 1023px) { .prose .wp-block-gallery { grid-template-columns: repeat(2, 1fr) } }
@media (max-width: 767px) { .prose .wp-block-gallery { grid-template-columns: 1fr } .prose .wp-block-gallery img { height: 180px } }

/* ── 3m. WP Code block ───────────────────────────────────────────── */
.prose .wp-block-code { margin: 1.4em 0 }
.prose .wp-block-code code { display: block; font-family: var(--font-mono); font-size: 13px; line-height: 1.7; color: #c9d1d9; overflow-x: auto; -webkit-overflow-scrolling: touch }

/* ── 3n. WP Blockquote ───────────────────────────────────────────── */
.prose .wp-block-quote { border-left: 3px solid var(--green); padding: .2em 0 .2em 20px; margin: 1.6em 0; color: var(--mid); font-style: italic }
.prose .wp-block-quote cite { display: block; margin-top: 8px; font-size: 13px; font-style: normal; color: var(--dim); font-family: var(--font-mono) }

/* ==========================================================================
   4. GUTENBERG BLOCK STYLES (v1.6.0) - every block gets a design
   ========================================================================== */

/* ── 4a. Embed blocks (YouTube, Vimeo, Spotify, SoundCloud, X, TikTok…) ── */
.prose .wp-block-embed { margin: 1.6em 0; max-width: 100% }
.prose .wp-block-embed__wrapper { max-width: 100% }
.prose .wp-block-embed__wrapper > iframe { display: block; max-width: 100% }
/* ── 4a. Video embeds hold 16:9; rich embeds (Spotify/SoundCloud) keep provider height ──── */
.prose .wp-block-embed.is-type-video .wp-block-embed__wrapper { aspect-ratio: 16/9 }
.prose .wp-block-embed.is-type-video .wp-block-embed__wrapper > iframe { width: 100%; height: 100%; border: 1px solid var(--border); border-radius: var(--r) }
.prose .wp-block-embed:not(.is-type-video) .wp-block-embed__wrapper > iframe { border: 1px solid var(--border); border-radius: var(--r) }
/* Spotify - the player's natural height is 152px (per Spotify's own oEmbed).
   Do NOT override the height: forcing 200px stretched the iframe box and
   left white space under the player. Also drop the theme border - the
   player has its own 12px radius; a wrapping border shows as corner gaps.
   The generic .prose figure bottom margin (--sp-6) stacks with the embed's
   own 1.6em margin → double space under short embeds (Spotify especially);
   kill it for embed figures so spacing is uniform. */
.prose .wp-block-embed.is-provider-spotify .wp-block-embed__wrapper > iframe { height: 152px; border: none }
.prose figure.wp-block-embed { margin-bottom: 1.6em }

/* X / Twitter embeds - blockquote shell styled as a terminal card; the
   widgets.js script replaces the inner content with the live tweet. */
.prose .wp-block-embed.is-provider-twitter .wp-block-embed__wrapper,
.prose .wp-block-embed.is-provider-x .wp-block-embed__wrapper { min-height: 120px }
.prose .wp-block-embed.is-provider-twitter blockquote.twitter-tweet,
.prose .wp-block-embed.is-provider-x blockquote.twitter-tweet { border: 1px solid var(--border); border-radius: var(--r); background: var(--surface); padding: var(--sp-5); margin: 0; color: var(--text); font-size: 14px; line-height: 1.6 }

/* ── 4b. Video block (locally uploaded video) ── */
.prose .wp-block-video { margin: 1.6em 0 }
.prose .wp-block-video video { width: 100%; display: block; background: #000; border: 1px solid var(--border); border-radius: var(--r) }
.prose .wp-block-video figcaption { margin-top: 10px }

/* ── 4c. Audio block ── */
.prose .wp-block-audio { margin: 1.6em 0 }
.prose .wp-block-audio audio { width: 100%; display: block; color-scheme: dark }
.prose .wp-block-audio figcaption { margin-top: 10px }

/* ── 4d. Cover block ── */
.prose .wp-block-cover { position: relative; min-height: 260px; margin: 1.6em 0; display: flex; align-items: center; justify-content: center; overflow: hidden; border: 1px solid var(--border); border-radius: var(--r) }
/* Background image/video must fill the cover absolutely - without these
   rules the image stays in normal flow (a flex item beside the text)
   instead of behind it. Mirrors core's cover styles, which the theme
   strips (no wp-block-library CSS shipped). */
.prose .wp-block-cover .wp-block-cover__image-background,
.prose .wp-block-cover video.wp-block-cover__video-background { position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 100%; height: 100%; object-fit: cover; border: none; margin: 0; padding: 0; max-width: none; max-height: none; outline: none; box-shadow: none }
.prose .wp-block-cover .wp-block-cover__background,
.prose .wp-block-cover .wp-block-cover__gradient-background { position: absolute; top: 0; left: 0; right: 0; bottom: 0; opacity: .5 }
/* Dim levels - mirror core's has-background-dim-* scale (theme ships no
   wp-block-library CSS, so these must exist here or dimming silently
   falls back to the .5 default above). */
.prose .wp-block-cover .has-background-dim-10 { opacity: .1 }
.prose .wp-block-cover .has-background-dim-20 { opacity: .2 }
.prose .wp-block-cover .has-background-dim-30 { opacity: .3 }
.prose .wp-block-cover .has-background-dim-40 { opacity: .4 }
.prose .wp-block-cover .has-background-dim-50 { opacity: .5 }
.prose .wp-block-cover .has-background-dim-60 { opacity: .6 }
.prose .wp-block-cover .has-background-dim-70 { opacity: .7 }
.prose .wp-block-cover .has-background-dim-80 { opacity: .8 }
.prose .wp-block-cover .has-background-dim-90 { opacity: .9 }
.prose .wp-block-cover .has-background-dim-100 { opacity: 1 }
.prose .wp-block-cover__inner-container { position: relative; z-index: 1; width: 100%; max-width: 640px; padding: 32px 24px }
.prose .wp-block-cover__inner-container > :first-child { margin-top: 0 }
.prose .wp-block-cover__inner-container > :last-child { margin-bottom: 0 }

/* ── 4e. File block ── */
.prose .wp-block-file { margin: 1.6em 0; display: flex; align-items: center; gap: 12px; flex-wrap: wrap; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); padding: 16px 20px }
.prose .wp-block-file a:first-child { color: var(--text); text-decoration: none }
.prose .wp-block-file a:first-child::before { content: '📎 '; font-size: 13px }
@media (hover: hover) { .prose .wp-block-file a:first-child:hover { color: var(--green) } }
.prose .wp-block-file__button { display: inline-flex; align-items: center; min-height: 44px; background: var(--green); color: var(--on-green); font-family: var(--font-mono); font-size: 12px; font-weight: 700; padding: 8px 14px; border-radius: var(--r-sm); text-decoration: none; border: 1px solid transparent }
@media (hover: hover) { .prose .wp-block-file__button:hover { filter: brightness(1.08); color: var(--on-green) } }

/* ── 4f. Pullquote ── */
.prose .wp-block-pullquote { border: 1px solid var(--border); border-left: 3px solid var(--green); background: var(--surface); border-radius: var(--r); padding: 24px; margin: 1.6em 0 }
.prose .wp-block-pullquote blockquote { margin: 0; padding: 0; border: none; color: var(--text); font-style: normal; font-size: 18px; line-height: 1.6 }
.prose .wp-block-pullquote cite { display: block; margin-top: 12px; font-size: 12px; font-style: normal; color: var(--mid); font-family: var(--font-mono) }

/* ── 4g. Columns ── */
.prose .wp-block-columns { display: flex; gap: 24px; margin: 1.6em 0 }
.prose .wp-block-column { flex: 1; min-width: 0 }
@media (max-width: 781px) { .prose .wp-block-columns:not(.is-not-stacked-on-mobile) { flex-direction: column; gap: 16px } }

/* ── 4h. Media + text ── */
.prose .wp-block-media-text { display: grid; grid-template-columns: 50% 1fr; gap: 24px; margin: 1.6em 0; align-items: center }
.prose .wp-block-media-text.has-media-on-the-right { grid-template-columns: 1fr 50% }
.prose .wp-block-media-text__media { margin: 0 }
.prose .wp-block-media-text__media img, .prose .wp-block-media-text__media video { width: 100%; height: auto; display: block; border: 1px solid var(--border); border-radius: var(--r) }
@media (max-width: 781px) { .prose .wp-block-media-text, .prose .wp-block-media-text.has-media-on-the-right { grid-template-columns: 1fr } }

/* ── 4i. Buttons ── */
.prose .wp-block-buttons { display: flex; flex-wrap: wrap; gap: 12px; margin: 1.6em 0 }
.prose .wp-block-button__link { display: inline-flex; align-items: center; background: var(--green); color: var(--on-green); font-family: var(--font-mono); font-size: 13px; font-weight: 700; padding: 12px 22px; border-radius: var(--r-sm); text-decoration: none; border: 1px solid transparent; transition: filter .15s }
.prose .wp-block-button.is-style-outline .wp-block-button__link { background: transparent; color: var(--green); border-color: var(--green) }
@media (hover: hover) { .prose .wp-block-button__link:hover { filter: brightness(1.08) } }
@media (hover: hover) { .prose .wp-block-button.is-style-outline .wp-block-button__link:hover { background: rgba(0,255,145,.08) } }

/* ── 4j. Group ── */
.prose .wp-block-group { margin: 1.6em 0 }
.prose .wp-block-group.has-background { padding: 20px; border-radius: var(--r) }

/* ── 4k. Details / summary ── */
.prose .wp-block-details { margin: 1.6em 0; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r) }
.prose .wp-block-details summary { -webkit-user-select: none; user-select: none; cursor: pointer; font-family: var(--font-mono); font-size: 13px; font-weight: 600; color: var(--green); padding: 14px 20px; list-style: none }
.prose .wp-block-details summary::-webkit-details-marker { display: none }
.prose .wp-block-details summary::before { content: '>_ ' }
.prose .wp-block-details[open] summary { border-bottom: 1px solid var(--border) }
.prose .wp-block-details > :not(summary) { margin: 14px 20px }

/* ── 4l. Preformatted ── */
.prose .wp-block-preformatted { background: #08090b; border: 1px solid var(--border); border-radius: var(--r); padding: 20px; overflow-x: auto; -webkit-overflow-scrolling: touch; font-family: var(--font-mono); font-size: 13px; line-height: 1.7; margin: 1.4em 0; color: #c9d1d9; white-space: pre-wrap }

/* ── 4m. Latest posts (widget block inside content) ── */
.prose .wp-block-latest-posts { list-style: none; padding: 0; margin: 1.4em 0 }
.prose .wp-block-latest-posts li { margin-bottom: 10px }
.prose .wp-block-latest-posts a { color: var(--text); text-decoration: none }
@media (hover: hover) { .prose .wp-block-latest-posts a:hover { color: var(--green) } }
.prose .wp-block-latest-posts__post-date { display: block; font-size: 12px; color: var(--dim2); font-family: var(--font-mono) }

/* ==========================================================================
   5. GUTENBERG BLOCK STYLES - widget/utility blocks (v1.6.2)
   ========================================================================== */

/* ── 4n. Search block ── */
.prose .wp-block-search { margin: 1.6em 0 }
.prose .wp-block-search__label { display: block; font-family: var(--font-mono); font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; color: var(--mid); margin-bottom: 8px }
.prose .wp-block-search__inside-wrapper { display: flex; gap: 8px }
.prose .wp-block-search__input { flex: 1; min-width: 0; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r-sm); color: var(--text); padding: 12px 14px; font-size: 16px; font-family: inherit }
.prose .wp-block-search__input:focus { outline: none; border-color: var(--green); box-shadow: var(--ring-green) }
.prose .wp-block-search__button { background: var(--green); color: var(--on-green); border: none; font-family: var(--font-mono); font-weight: 700; font-size: 13px; padding: 10px 18px; border-radius: var(--r-sm); cursor: pointer }
@media (hover: hover) { .prose .wp-block-search__button:hover { filter: brightness(1.08) } }

/* ── 4o. Categories / archives / RSS lists ── */
.prose .wp-block-categories, .prose .wp-block-archives, .prose .wp-block-rss { list-style: none; padding: 0; margin: 1.4em 0 }
.prose .wp-block-categories li, .prose .wp-block-archives li, .prose .wp-block-rss li { margin-bottom: 8px }
.prose .wp-block-categories a, .prose .wp-block-archives a, .prose .wp-block-rss a { color: var(--text); text-decoration: none }
@media (hover: hover) { .prose .wp-block-categories a:hover, .prose .wp-block-archives a:hover, .prose .wp-block-rss a:hover { color: var(--green) } }
.prose .wp-block-categories .wp-block-categories__list { margin-top: 8px; padding-left: 16px; border-left: 1px solid var(--border) }
.prose .wp-block-categories .wp-block-categories__list li { margin-bottom: 6px }
.prose .wp-block-categories-list .current-cat > a { color: var(--green) }

/* ── 4p. Tag cloud ── */
.prose .wp-block-tag-cloud { display: flex; flex-wrap: wrap; gap: 8px; margin: 1.4em 0 }
.prose .wp-block-tag-cloud a { display: inline-flex; align-items: center; padding: 4px 12px; min-height: 44px; border-radius: var(--r-pill); border: 1px solid var(--border); font-family: var(--font-mono); font-size: 12px !important; color: var(--mid); text-decoration: none; transition: border-color .15s, color .15s }
@media (hover: hover) { .prose .wp-block-tag-cloud a:hover { border-color: var(--green); color: var(--green) } }

/* ── 4q. Social links ── */
.prose .wp-block-social-links { display: flex; flex-wrap: wrap; gap: 10px; padding: 0; margin: 1.4em 0; list-style: none }
.prose .wp-block-social-links .wp-social-link { display: inline-flex }
.prose .wp-block-social-links .wp-social-link a { display: inline-flex; align-items: center; justify-content: center; width: 40px; height: 40px; border-radius: var(--r); background: var(--surface-2); border: 1px solid var(--border); transition: border-color .15s, transform .15s }
@media (hover: hover) { .prose .wp-block-social-links .wp-social-link a:hover { border-color: var(--green); transform: translateY(-2px) } }
.prose .wp-block-social-links .wp-social-link svg { fill: var(--text); width: 20px; height: 20px }

/* ── 4r. Latest comments ── */
.prose .wp-block-latest-comments { list-style: none; padding: 0; margin: 1.4em 0 }
.prose .wp-block-latest-comments li { margin-bottom: 14px; padding: 12px 16px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r) }
.prose .wp-block-latest-comments__comment-author, .prose .wp-block-latest-comments__comment-link { color: var(--green); text-decoration: none; font-weight: 600 }
.prose .wp-block-latest-comments__comment-meta { font-size: 12px; color: var(--dim2); font-family: var(--font-mono); margin-bottom: 6px }
.prose .wp-block-latest-comments__comment-excerpt p { font-size: 14px; color: var(--mid); margin: 0 }

/* ── 4s. Verse ── */
.prose .wp-block-verse { background: #08090b; border: 1px solid var(--border); border-left: 3px solid var(--green); border-radius: var(--r); padding: 20px; font-family: var(--font-mono); font-size: 14px; line-height: 1.9; color: #c9d1d9; margin: 1.4em 0; white-space: pre-wrap }

/* ── 4t. Footnotes ── */
.prose .wp-block-footnotes { margin: 2em 0 0; padding-top: 1.4em; border-top: 1px solid var(--border); font-size: 13px; color: var(--mid) }
.prose .wp-block-footnotes li { margin-bottom: 6px }
.prose .wp-block-footnotes a { color: var(--mid); text-decoration: none }
@media (hover: hover) { .prose .wp-block-footnotes a:hover { color: var(--green) } }
.prose sup a { color: var(--green); text-decoration: none }

/* ── 4u. Calendar ── */
.prose .wp-block-calendar { margin: 1.4em 0; font-size: 13px }
.prose .wp-block-calendar table { margin: 0 }
.prose .wp-block-calendar caption { font-family: var(--font-mono); color: var(--mid); padding-bottom: 10px; caption-side: top }
.prose .wp-block-calendar a { color: var(--green); text-decoration: none; font-weight: 700 }
.prose .wp-block-calendar td, .prose .wp-block-calendar th { text-align: center; padding: 8px 6px }
.prose .wp-block-calendar tbody td { background: var(--surface) }

/* -- Accordion (WP 7 block) - behavior theme-owned since v1.7.3 (no WP
      interactivity runtime; main.js drives open/close/autoclose) -- */
.prose .wp-block-accordion { margin: 1.6em 0 }
.prose .wp-block-accordion-item { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); margin-bottom: 12px; overflow: hidden }
.prose .wp-block-accordion-heading { margin: 0 }
.prose .wp-block-accordion-heading__toggle { cursor: pointer; width: 100%; text-align: left; background: none; border: none; font-family: var(--font-mono); font-size: 14px; font-weight: 600; color: var(--green); padding: 18px 22px }
.prose .wp-block-accordion-heading__toggle::before { content: '>_ ' }
.prose .wp-block-accordion-heading__toggle { transition: color .15s, background .15s }
@media (hover: hover) { .prose .wp-block-accordion-heading__toggle:hover { background: var(--green-dim); color: var(--green-hover) } }
.prose .wp-block-accordion-panel { border-top: 1px solid var(--border); padding: 18px 22px; display: none }
.prose .wp-block-accordion-item.is-open .wp-block-accordion-panel { display: block }
.prose .wp-block-accordion-panel > :first-child { margin-top: 0 }
.prose .wp-block-accordion-panel > :last-child { margin-bottom: 0 }

/* ── 4v. Widget group / page break / math ── */
.prose .wp-block-widget-group { margin: 1.4em 0 }
.prose .wp-block-nextpage { display: block; text-align: center; margin: 2em 0; color: var(--dim2); font-family: var(--font-mono); font-size: 11px; text-transform: uppercase; letter-spacing: .1em }
.prose .wp-block-math { font-family: var(--font-mono); font-size: 14px }

/* ==========================================================================
   GUTENBERG UTILITY CLASSES (v1.7.1) - these lived in the wp-block-library
   stylesheet we removed; without them blocks render visibly broken:
   screen-reader labels show as text, centered/large text is inert.
   ========================================================================== */

/* Visually hidden but accessible - the standard sr-only pattern. Social
   link labels (GitHub/X/LinkedIn), search labels etc. depend on it. */
.screen-reader-text { position: absolute !important; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0,0,0,0); border: 0; white-space: nowrap; word-wrap: normal }

/* ── 5a. Text alignment utilities ──────────────────────────────────── */
.has-text-align-left { text-align: left }
.has-text-align-center { text-align: center }
.has-text-align-right { text-align: right }

/* ── 5b. Font-size utilities (prose body is 17px) ──────────────────── */
.has-small-font-size { font-size: 13px }
.has-medium-font-size { font-size: 16px }
.has-large-font-size { font-size: 20px }
.has-x-large-font-size { font-size: 24px }
.has-xx-large-font-size { font-size: 32px }

/* Palette utilities - theme.json slugs (green/bg/surface/surface-2/text/muted).
   !important matches how core generates these. */
.has-green-color { color: #00ff91 !important }
.has-bg-color { color: #0d0d0d !important }
.has-surface-color { color: #111318 !important }
.has-surface-2-color { color: #181c24 !important }
.has-text-color { color: #e2e8f0 !important }
.has-muted-color { color: #8896aa !important }
.has-green-background-color { background-color: #00ff91 !important }
.has-bg-background-color { background-color: #0d0d0d !important }
.has-surface-background-color { background-color: #111318 !important }
.has-surface-2-background-color { background-color: #181c24 !important }
.has-text-background-color { background-color: #e2e8f0 !important }
.has-muted-background-color { background-color: #8896aa !important }

/* ── 5c. Align-wide - expand figures/covers beyond the 68ch prose column ──── */
.prose .alignwide { margin-left: -64px; margin-right: -64px; max-width: calc(100% + 128px) }
@media (max-width: 767px) { .prose .alignwide { margin-left: -16px; margin-right: -16px; max-width: calc(100% + 32px) } }

/* ── 5d. Inline code in paragraphs ─────────────────────────────────── */
/* handled by .prose code:not(pre code) above */

/* ==========================================================================
   6. LAYOUT UTILITIES
   ========================================================================== */
.wrap { max-width: var(--content-w); margin: 0 auto; padding: 0 var(--sp-8); position: relative; z-index: 2 }
.grid-2 { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-6) var(--sp-6); min-width: 0 }
.grid-3 { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-6) var(--sp-5); min-width: 0 }
.grid-4 { display: grid; grid-template-columns: repeat(4, 1fr); gap: var(--sp-6) var(--sp-5); min-width: 0 }
.flex { display: flex }
.flex-col { display: flex; flex-direction: column }
.items-center { align-items: center }
.justify-between { justify-content: space-between }
.section { padding: var(--sp-20) 0 }
.section-sm { padding: var(--sp-12) 0 }

@media (max-width: 1023px) {
  .grid-3, .grid-4 { grid-template-columns: repeat(2, 1fr) }
  .wrap { padding: 0 var(--sp-5) }
}
@media (max-width: 767px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr }
  .wrap { padding: 0 var(--sp-4) }
  .header-row { padding: 6px var(--sp-4) }
  .section { padding: var(--sp-16) 0 }
  .section-sm { padding: var(--sp-8) 0 }
}

/* ==========================================================================
   7. BUTTONS
   ========================================================================== */
.btn { font-family: var(--font-mono); font-size: 13px; font-weight: 700; padding: 12px 22px; min-height: 44px; border-radius: var(--r-sm); display: inline-flex; align-items: center; gap: 8px; border: 1px solid transparent; transition: transform .12s var(--ease-quick), background .15s, border-color .15s, box-shadow .2s; text-decoration: none }
.btn:active { transform: scale(.97) }
body .btn-primary { background: var(--green); color: var(--on-green); text-decoration: none; box-shadow: 0 1px 0 rgba(255, 255, 255, .08) inset, var(--shadow-xs) }
@media (hover: hover) { body .btn-primary:hover { background: var(--green-hover); text-decoration: none; transform: translateY(-1px); box-shadow: 0 4px 18px var(--green-glow-strong) } }
body .btn-secondary { background: transparent; border-color: var(--green); color: var(--green); text-decoration: none }
@media (hover: hover) { body .btn-secondary:hover { background: var(--green-dim); text-decoration: none; transform: translateY(-1px); box-shadow: var(--shadow-glow) } }
body .btn-ghost { background: transparent; color: var(--mid); border-color: var(--border); text-decoration: none }
@media (hover: hover) { body .btn-ghost:hover { color: var(--text); border-color: var(--border-2); text-decoration: none; transform: translateY(-1px); box-shadow: var(--shadow-sm) } }
.btn-sm { padding: 8px 16px; font-size: 12px; min-height: 44px }

/* ==========================================================================
   8. CARDS
   ========================================================================== */
.card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; transition: border-color .2s var(--ease-quick), transform .2s var(--ease-quick), box-shadow .2s var(--ease-quick), background-color .2s var(--ease-quick); display: flex; flex-direction: column; width: 100%; min-width: 0; height: 100%; position: relative }
/* v1.18.00: terminal-selection hover - the card lifts AND takes a clearly
   perceptible green-dim wash (bumped from 6% so it reads against the dark
   surface) + a brighter border, so the whole site shares one signature
   interaction. Straight/clean brand: tint + border, not ornament. */
/* v1.19.01 (King: "some categories have different colors shouldn't they have
   different hover, just like their category colors"): card hovers wear the
   card's OWN category color (--c, present since v1.16.34). Fallback keeps
   brand green for any surface without vars. color-mix line upgrades the
   wash where supported (Chrome 111+); the rgba above is the fallback. */
.card:hover { border-color: var(--c, var(--green)); background: rgba(0, 255, 145, .10); background: color-mix(in srgb, var(--c, #00ff91) 10%, transparent); transform: translateY(-3px); box-shadow: var(--shadow-md), var(--shadow-glow-strong) }
@media (hover: none) { .card:hover { transform: none } }
.card-link { display: block; text-decoration: none; color: inherit }
.card-link:hover { color: inherit }
.card h3 a::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; z-index: 1 }
.card h3 a:focus-visible::after { outline: 2px solid var(--green); outline-offset: -4px; border-radius: var(--r) }
.card-media { aspect-ratio: 16/9; display: flex; align-items: center; justify-content: center; font-size: 38px; overflow: hidden; position: relative }
.card-media.cat-tint { background: linear-gradient(160deg, var(--c-grad, rgba(0, 255, 145, .16)), var(--surface) 75%) }
.card-media-relative { position: relative }
.card-body { padding: var(--sp-5); min-width: 0; overflow-wrap: break-word }
.card h3 { font-size: 16px; font-weight: 700; line-height: 1.4; margin: 10px 0; overflow-wrap: break-word }
body .card h3 a:hover { color: var(--c, var(--green)) }
.card-meta { font-size: 11px; color: var(--mid); display: flex; gap: 10px; align-items: center; margin-bottom: 4px }
/* Optional ACF "Read guide" CTA (v1.18.76) - only renders when the
   site-settings field is filled; terminal-green mono link under the meta row. */
.card-cta-link { display: inline-flex; align-items: center; gap: 6px; margin-top: 10px; font-family: var(--font-mono); font-size: 12px; font-weight: 600; letter-spacing: .04em; color: var(--green); text-decoration: none }
.card-cta-link:hover { opacity: .85 }
.card-excerpt { font-size: 13px; color: var(--mid); line-height: 1.65; margin-bottom: 16px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden }
.card-lead { display: grid; grid-template-columns: 1.1fr 1fr; margin-bottom: var(--sp-6) }
.card-lead .card-media { aspect-ratio: auto; height: 100% }
.card-lead .card-body { padding: var(--sp-8); display: flex; flex-direction: column; justify-content: center }
.card-lead h3 { font-size: 24px }
.resource-card { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); padding: var(--sp-5); transition: border-color .2s var(--ease-quick), transform .2s var(--ease-quick), box-shadow .2s var(--ease-quick); display: flex; flex-direction: column }
.resource-card:hover { border-color: var(--green-border); transform: translateY(-2px); box-shadow: var(--shadow-md), var(--shadow-glow) }
.resource-card .flex { justify-content: space-between; align-items: flex-start; gap: 10px }
.resource-card .body-sm { flex: 1 }
/* Firefox device-font resilience: with device font size applied, the track
   title+badge row (space-between, no wrap) inflated wider than the card and
   pushed the grid past the viewport right edge ("content flows right").
   Let the row wrap, keep the card shrinkable, and allow long titles to break. */
.resource-card { min-width: 0 }
.resource-card .flex { flex-wrap: wrap }
.resource-card h2 { overflow-wrap: break-word }
/* ── 8a. Categories index (/category/) - category cards ────────────── */
.category-card .cat-head { display: flex; align-items: center; gap: 10px }
/* v1.19.01: category-index card wears the category color on hover.
   Selector fixed h3→h2 to match the actual markup (old rule was dead). */
.category-card .cat-head a:hover { color: var(--c, var(--green)) }
.category-card:hover { border-color: var(--c-border, var(--green-border)) }
.category-card { border-color: var(--c-border, var(--border)) }
.cat-child-chip { display: inline-flex; align-items: center; font-size: 12px; font-weight: 600; color: var(--mid); border: 1px solid var(--border); border-radius: var(--r-pill); padding: 7px 12px; min-height: 44px; text-decoration: none; transition: color .15s, border-color .15s }
.cat-child-chip:hover { color: var(--c, var(--green)); border-color: var(--c-border, var(--green-border)) }

/* ── 8b. Resource section headers with colored dot ─────────────────── */
.resources-section-header { font-size: 22px; font-weight: 800 }
.dot { width: 10px; height: 10px; border-radius: 50%; flex-shrink: 0 }
.dot-android { background: var(--cat-android); box-shadow: 0 0 8px var(--cat-android) }
.dot-webdev { background: var(--cat-webdev); box-shadow: 0 0 8px var(--cat-webdev) }
.dot-software { background: var(--cat-software); box-shadow: 0 0 8px var(--cat-software) }
.dot-cat { background: var(--c); box-shadow: 0 0 8px var(--c) }

@media (max-width: 767px) {
  .card-lead { grid-template-columns: 1fr }
  .card-lead .card-media { aspect-ratio: 16/9 }
  .card-lead h3 { font-size: 19px }
  .resources-section-header { font-size: 19px }
}

/* ==========================================================================
   9. BADGES & PILLS
   ========================================================================== */
.badge { display: inline-flex; align-items: center; gap: 5px; padding: 6px 12px; border-radius: var(--r-sm); font-size: 10px; font-weight: 700; letter-spacing: .06em; text-transform: uppercase; border: 1px solid transparent; position: relative; z-index: 2 }
.badge a { color: inherit }
.badge-android { background: var(--cat-android-dim); border-color: var(--cat-android-border); color: var(--cat-android) }
.badge-webdev { background: var(--cat-webdev-dim); border-color: var(--cat-webdev-border); color: var(--cat-webdev) }
.badge-software { background: var(--cat-software-dim); border-color: var(--cat-software-border); color: var(--cat-software) }
.badge-cat { background: var(--c-dim); border-color: var(--c-border); color: var(--c) }
.badge-tag { background: var(--green-dim) !important; border-color: var(--green-border) !important; color: var(--green) !important }
.filter-pills { gap: 8px; flex-wrap: wrap; display: flex; align-items: center }

/* ── 9a. Pill filter buttons ───────────────────────────────────────── */
.pill { display: inline-flex; align-items: center; gap: 8px; padding: 10px 20px; min-height: 44px; border-radius: var(--r-pill); border: 1px solid var(--border); font-size: 13px; font-weight: 600; color: var(--mid); background: var(--surface); transition: all .2s var(--ease-quick); cursor: pointer; white-space: nowrap; font-family: var(--font-mono) }
@media (hover: hover) { .pill:hover { border-color: var(--border-2); color: var(--text); background: var(--surface-2); transform: translateY(-1px); box-shadow: var(--shadow-sm) } }
.pill.on { background: var(--green-dim); border-color: var(--green-border); color: var(--green); box-shadow: 0 0 12px var(--green-glow); cursor: default }

/* ── 9b. Category-colored dots for pills (driven by inline --c via gwill_category_vars()) ──── */
.pill-cat::before { content: ""; width: 8px; height: 8px; border-radius: 50%; background: var(--c); box-shadow: 0 0 6px var(--c); flex-shrink: 0 }
.pill.on::before { box-shadow: 0 0 6px currentColor }

/* AJAX category filter grid - loading state (category-filter.js).
   category-filter.js injects a .filter-grid__spinner INTO the first card's
   .card-media (on top of its featured image) while a pill loads, so the
   indicator is visible even on slow connections. The ring + "Loading…"
   caption mirror the ad-slot spinner (gwill-spin, 26px ring, 9px label). */
.filter-grid { position: relative; min-height: 160px }
.filter-grid.is-loading { pointer-events: none }
.filter-grid__spinner {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  background: rgba(13, 13, 13, .55);
  color: var(--green);
  z-index: 5;
}
.filter-grid__spinner::before {
  content: "";
  width: 26px; height: 26px;
  border-radius: 50%;
  border: 2.5px solid var(--green-dim);
  border-top-color: var(--green);
  animation: gwill-spin 1s linear infinite;
}
.filter-grid__spinner::after {
  content: "Loading…";
  font-size: 9px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dim2);
}
.filter-grid__error { grid-column: 1 / -1; color: var(--mid); font-size: 15px; text-align: center; padding: var(--sp-8) 0 }

/* Image-loading placeholder - a CSS ring BEHIND the <img> shows while a
   featured image downloads (the not-yet-loaded <img> box is transparent,
   so the ring is visible), then the loaded image covers it. Pure CSS, zero
   JS, zero extra requests: lazy loading stays untouched, nothing slows down. */
.card-media.has-img::before {
  content: "";
  position: absolute;
  top: 50%; left: 50%;
  width: 26px; height: 26px;
  margin: -13px 0 0 -13px;
  border-radius: 50%;
  border: 2.5px solid var(--green-dim);
  border-top-color: var(--green);
  animation: gwill-spin 1s linear infinite;
  z-index: 1;
}
.card-media img { position: relative; z-index: 2 }

/* "View all …" CTA under the filter grid - hidden when a filter returns no
   posts (JS sets the element's HTML to empty). */
.filter-cta:empty { display: none }

/* ── 9c. Scrollable on mobile ──────────────────────────────────────── */
@media (max-width: 767px) {
  .filter-pills { overflow-x: auto; flex-wrap: nowrap; padding-bottom: 8px; scroll-snap-type: x mandatory; -webkit-overflow-scrolling: touch }
  .filter-pills::-webkit-scrollbar { display: none }
  .pill { scroll-snap-align: start; flex-shrink: 0 }
}

/* ==========================================================================
   10. FORM INPUTS
   ========================================================================== */
.input { width: 100%; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 12px 14px; font-size: 16px; color: var(--text); transition: border-color .15s, box-shadow .2s }
.input::placeholder { color: var(--dim2) }
.input:focus { outline: none; border-color: var(--green); box-shadow: var(--ring-green) }
/* Autofill - keep the dark terminal look when browsers fill inputs
   (Chrome/Edge/Firefox paint light yellow/blue fills by default). The
   inset box-shadow paints the surface color BEHIND the fill; the
   transition freeze stops WebKit's background flash.
   v1.19.20 (cross-browser audit): -webkit- and -moz- rules MUST be separate
   blocks - Chrome/Edge/Safari discard an entire selector list containing an
   unknown pseudo (:-moz-autofill), so the merged form silently disabled the
   dark autofill fix on every WebKit browser. */
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus,
textarea:-webkit-autofill,
select:-webkit-autofill {
  -webkit-box-shadow: 0 0 0 1000px var(--surface) inset;
  box-shadow: 0 0 0 1000px var(--surface) inset;
  -webkit-text-fill-color: var(--text);
  caret-color: var(--text);
  transition: background-color 9999s ease-out;
}
@-moz-document url-prefix() {
  input:-moz-autofill,
  textarea:-moz-autofill,
  select:-moz-autofill {
    box-shadow: 0 0 0 1000px var(--surface) inset;
    -moz-text-fill-color: var(--text);
    caret-color: var(--text);
    transition: background-color 9999s ease-out;
  }
}

/* ==========================================================================
   11. HEADER - Brand Spec: .prompt (green glow), .gap, .name, .cursor
   BELL PANEL (v1.19.32) - terminal status dialog under the bell
   ========================================================================== */
.site-header { position: -webkit-sticky; position: sticky; top: 0; z-index: var(--z-sticky); /* v1.17.09: ghost + blur so the sticky bar stays legible over ANY
     content scrolling beneath it (premium, pure-CSS - no scroll JS). */
  background: rgba(13, 13, 13, .82); -webkit-backdrop-filter: blur(10px); backdrop-filter: blur(10px); border-bottom: 1px solid var(--border) }
.header-row { display: flex; align-items: center; min-height: 48px; width: 100%; padding: 6px var(--sp-8); max-width: var(--content-w); margin: 0 auto; border-bottom: 1px solid var(--border); gap: var(--sp-4) }
.header-row > * { flex-shrink: 0 }
.header-row-2 { display: flex; align-items: center; min-height: 44px; width: 100%; padding: 6px var(--sp-8); max-width: var(--content-w); margin: 0 auto; background: var(--surface) }
/* Header side padding MUST mirror the page .wrap at every breakpoint.
   These overrides sit AFTER the base rule so they win by source order
   (media queries add no specificity). Body .wrap: ≤1023=20px, ≤767=16px,
   600-767=24px, 768-1023=24px. */
@media (max-width: 1023px) { .header-row, .header-row-2 { padding: 6px var(--sp-5) } }
@media (max-width: 767px) { .header-row, .header-row-2 { padding: 6px var(--sp-4) } }
@media (min-width: 600px) and (max-width: 767px) { .header-row, .header-row-2 { padding: 6px var(--sp-6) } }
@media (min-width: 768px) and (max-width: 1023px) { .header-row, .header-row-2 { padding: 6px var(--sp-6) } }
.header-actions { display: flex; align-items: center; gap: 10px; margin-left: auto; position: relative; flex-shrink: 0 }
/* v1.19.45: header bell is for screens WITHOUT the sticky footer (footer bell
   covers mobile). Hide the header bell at ≤767px so there's never two bells. */
@media (max-width: 767px) { .header-actions .gwill-bell { display: none } }

/* ── 11a. Logo - Brand Spec ────────────────────────────────────────── */
.logo { display: flex; align-items: center; font-family: var(--font-mono); font-weight: 800; font-size: 17px; text-decoration: none }
.logo .prompt { color: var(--green); text-shadow: 0 0 12px rgba(0, 255, 145, 0.5), 0 0 32px rgba(0, 255, 145, 0.2); transition: text-shadow 0.15s }
@media (hover: hover) { .logo:hover .prompt { text-shadow: 0 0 16px rgba(0, 255, 145, 0.7), 0 0 40px rgba(0, 255, 145, 0.3) } }
.logo .gap { display: inline-block; width: 0.4em; }
.logo .name { color: var(--text); letter-spacing: -0.02em; white-space: nowrap }
.logo .cursor { display: inline-block; width: 0.55em; height: 1em; background: var(--green); margin-left: 3px; vertical-align: middle; position: relative; top: -0.05em; box-shadow: 0 0 10px rgba(0, 255, 145, 0.7); animation: blink 1.1s step-end infinite; }
@keyframes blink { 0%, 100% { opacity: 1 } 50% { opacity: 0 } }
.logo-sm { font-size: 14px }
.logo-sm .cursor { width: 0.45em; height: 0.85em; }

.site-nav { display: flex; gap: 30px }
.site-nav-list { display: flex; gap: 30px; list-style: none; margin: 0; padding: 0 }
.site-nav-list > li { position: relative }
.site-nav a, .site-nav-list a { font-size: 13px; font-weight: 500; color: var(--mid); transition: color .15s; text-decoration: none; display: inline-flex; align-items: center; gap: 4px }
.site-nav a.active, .site-nav-list a.active { color: var(--green) }
/* v1.18.99 (King: apply the comments hover logic to nav, esp. mobile nav):
   ALL nav :hover rules are UNGATED - Android sticky hover becomes the
   highlight mechanism (press-and-hold paints; tap elsewhere moves/clears),
   identical to the comments section. Bars are freed together with their
   foregrounds so a stuck state is always the full legible terminal look. */
.site-nav a:hover, .site-nav-list a:hover { color: var(--green) }
/* ── 11b. Desktop dropdowns - hover to open (no click needed, pointer-only) ──── */
.site-nav-list .sub-menu { display: none; position: absolute; top: 100%; left: -12px; min-width: 200px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 6px; list-style: none; margin: 0; z-index: 100; box-shadow: 0 12px 32px rgba(0, 0, 0, .45) }
.site-nav-list > li:hover > .sub-menu, .site-nav-list > li:focus-within > .sub-menu { display: block }
.site-nav-list .sub-menu a { display: flex; width: 100%; padding: 8px 12px; font-size: 12px; border-radius: var(--r-sm); color: var(--mid) }
.site-nav-list .sub-menu a:hover { background: var(--surface-2); color: var(--green) }
.site-nav-list .sub-menu--nested { left: 100%; top: 0 }
.site-nav-list .nav-caret { opacity: .6; transition: transform .15s }
.site-nav-list > li:hover > a .nav-caret { transform: rotate(180deg) }
/* ── 11c. Mobile accordion (inside .mno overlay) ───────────────────── */
.mno-list { list-style: none; margin: 0; padding: 0 }
.mno-list > li > a, .mno-list .mno-parent > a, .mno-list .sub-menu a, .mno-items > .nav-link { display: flex; align-items: center; padding: var(--sp-4) var(--sp-5); font-size: 15px; font-weight: 600; color: var(--text); border-radius: var(--r-sm); transition: background .15s, color .15s; text-decoration: none }
/* v1.19.01 FIX (King: "Category with Sub is fucked up"): .mno-parent rows
   are EXCLUDED here - their label must stay transparent so the split-row's
   own full-bright-bar treatment (bg + dark label + dark arrow) shows.
   Previously this generic opaque bar painted UNDER the dark label = dark
   text trapped on a dark patch. */
.mno-list > li > a:hover, .mno-list .sub-menu a:hover, .mno-items > .nav-link:hover { background: var(--surface); color: var(--green) }
.mno-list > li > a.active, .mno-list .sub-menu a.active, .mno-items > .nav-link.active { color: var(--green); background: var(--green-dim) }
/* v1.18.85: active split-button rows highlight the FULL bar (link + caret chip). */
.mno-list li.has-submenu > .mno-parent.active { background: var(--green-dim) }
.mno-list li.has-submenu > .mno-parent.active > a { color: var(--green); background: transparent }
.mno-list .sub-menu { display: none; list-style: none; margin: 2px 0 8px var(--sp-5); padding: var(--sp-2) 0 var(--sp-2) var(--sp-4); position: relative; background: rgba(17,19,24,.5); border-radius: 0 var(--r-sm) var(--r-sm) 0 }
/* v1.22.26 (King: "remove that side border you added to the active design"):
   the green border-left rail beside expanded sub-menu rows is BANNED - it was
   the bar in his last screenshot. Indent + tint stay, the line goes.
   DESIGN-LANGUAGE law: no side bars on nav rows. */
.mno-list li.open > .sub-menu { display: block }
.mno-list .sub-menu a { font-size: 14px; font-weight: 500; padding: var(--sp-2) var(--sp-4); color: var(--mid); border-radius: var(--r-sm) }
.mno-list .sub-menu a:hover { background: var(--surface); color: var(--green) }
.mno-list .sub-menu a.active { color: var(--green); background: var(--green-dim) }
.mno-list .sub-menu .sub-menu { margin-left: 0 }
/* Split-tap affordance: the .mno-caret is a distinct 30px square CHIP on the
   right of the row. Tap IT to expand/collapse the sub-menu; tap the category
   TEXT (left) to navigate. The square chip STAYS FIXED when opened - only the
   inner .nav-caret chevron rotates 180° to indicate open/close. */
.mno-list li.has-submenu > .mno-parent { display: flex; align-items: center }
.mno-list li.has-submenu > .mno-parent > a { flex: 1; min-width: 0 }
.mno-list .mno-caret {
  flex-shrink: 0;
  width: 44px; height: 44px;            /* square chip; stays put */
  display: flex; align-items: center; justify-content: center;
  margin-right: var(--sp-5);
  border: 1px solid var(--green-border); /* visible square */
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--green); opacity: .9;
  transition: border-color .15s, background .15s;
}
/* the inner chevron svg - THIS rotates, the square does not */
.mno-list .mno-caret .nav-caret {
  width: 12px; height: 12px;
  transition: transform .15s;
  flex-shrink: 0;
}
.mno-list li.open > .mno-parent .mno-caret .nav-caret { transform: rotate(180deg) }
.mno-list .mno-caret:hover { border-color: var(--green-border); background: var(--green-dim) }
/* when a parent is open, give its row breathing room below (bottom padding) */
.mno-list li.open > .mno-parent { margin-bottom: var(--sp-2) }
.icon-btn { width: 44px; height: 44px; border-radius: var(--r-sm); border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; color: var(--mid); background: transparent; transition: all .15s }
@media (hover: hover) { .icon-btn:hover { border-color: var(--green-border); color: var(--green) } }
.icon-btn svg { width: 16px; height: 16px }
.icon-btn.gwill-bell.is-on { border-color: var(--green-border); color: var(--green); background: color-mix(in srgb, var(--green) 8%, transparent) }
.icon-btn.gwill-bell.is-on svg { animation: gwill-bell-ring .5s ease }
.icon-btn.gwill-bell.is-blocked { opacity: .45 }
.icon-btn.gwill-bell.is-blocked svg { stroke-dasharray: 2 3 }
@keyframes gwill-bell-ring { 0%{transform:rotate(0)} 25%{transform:rotate(8deg)} 50%{transform:rotate(-8deg)} 75%{transform:rotate(5deg)} 100%{transform:rotate(0)} }

/* ── Bell panel (v1.19.32) - terminal-styled status dialog under the bell ── */
/* Fixed below the header like .search-dropdown; never affects layout or ads. */
.gwill-bell-panel {
  position: fixed; bottom: calc(var(--btm-tab-h, 56px) + 12px); right: 16px; z-index: 9990;
  width: min(340px, calc(100vw - 24px));
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg, 12px);
  box-shadow: 0 20px 40px rgba(0, 0, 0, .4);
  padding: 12px 16px 16px;
  font-family: var(--font-body);
  overflow-wrap: break-word;
}
/* When a sticky ad is live, float the panel above it so nothing overlaps. */
body.ad-sticky-visible .gwill-bell-panel { bottom: calc(var(--btm-tab-h, 56px) + 116px + 12px) }
.gwill-bell-panel.is-open { animation: gbp-rise .18s var(--ease-out, ease-out) }
@keyframes gbp-rise { from { opacity: 0; transform: translateY(24px) } to { opacity: 1; transform: translateY(0) } }
.gbp-top { display: flex; align-items: center; gap: 5px; margin-bottom: 8px }
.gbp-dot { width: 8px; height: 8px; border-radius: 50% }
.gbp-dot--r { background: #ff5f56 } .gbp-dot--a { background: #ffbd2e } .gbp-dot--g { background: #27c93f }
.gbp-x { margin-left: auto; width: 30px; height: 30px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid transparent; border-radius: var(--r-xs, 4px); background: transparent; color: var(--mid); cursor: pointer }
.gbp-path { font-family: var(--font-mono); font-size: 11px; color: var(--dim); margin: 0 0 6px }
.gbp-path::after { content: '▋'; color: var(--green); margin-left: 4px; animation: gbp-caret 1.1s steps(1) infinite }
@keyframes gbp-caret { 50% { opacity: 0 } }
.gbp-title { font-family: var(--font-mono); font-size: 15px; font-weight: 700; color: var(--text); margin: 0 0 6px }
.gbp-status { font-family: var(--font-mono); font-size: 12px; color: var(--dim); margin: 0 0 8px }
.gbp-status--on { color: var(--green) }
.gbp-status--bad { color: #ff6b6b }
.gbp-body { font-size: clamp(12.5px, 3.4vw, 13.5px); line-height: 1.6; color: var(--mid); margin: 0 0 12px; overflow-wrap: break-word }
.gbp-steps { margin: 0 0 10px; padding-left: 0; list-style: none; counter-reset: gbp-step }
.gbp-steps li { counter-increment: gbp-step; position: relative; padding-left: 24px; font-family: var(--font-mono); font-size: 12.5px; line-height: 1.7; color: var(--text) }
.gbp-steps li::before { content: counter(gbp-step); position: absolute; left: 0; top: 1px; width: 16px; height: 16px; display: inline-flex; align-items: center; justify-content: center; border: 1px solid var(--green-border); border-radius: var(--r-xs, 4px); color: var(--green); font-size: 10px; background: var(--green-dim) }
.gbp-other { font-size: 12px; line-height: 1.6; color: var(--dim); margin: 0 0 12px }
.gbp-actions { display: flex; gap: 8px; flex-wrap: wrap }
.gbp-btn { font-family: var(--font-mono); font-size: 13px; min-height: 44px; padding: 0 14px; border-radius: var(--r-sm, 8px); cursor: pointer; border: 1px solid var(--border); background: transparent; color: var(--text) }
.gbp-btn--primary { border-color: var(--green-border); background: var(--green-dim); color: var(--green) }
.gbp-btn--ghost { color: var(--dim) }
/* Loading state - the primary button becomes a disabled spinner while the
   subscription is being created. Shows the user it's working, doesn't double-fire. */
.gbp-btn.is-loading {
  cursor: default;
  opacity: .85;
  gap: 8px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
.gbp-spinner {
  width: 14px;
  height: 14px;
  border: 2px solid rgba(0, 255, 145, .25);
  border-top-color: var(--green);
  border-radius: 50%;
  animation: gbp-spin .7s linear infinite;
  flex-shrink: 0;
}
@keyframes gbp-spin { to { transform: rotate(360deg) } }
@media (prefers-reduced-motion: reduce) { .gbp-spinner { animation-duration: 1.6s } }
@media (hover: hover) {
  .gbp-btn--primary:hover { background: var(--green); color: var(--on-green) }
  .gbp-btn--ghost:hover { color: var(--text); border-color: var(--mid) }
  .gbp-x:hover { color: var(--text); border-color: var(--border) }
}
.gbp-btn:focus-visible, .gbp-x:focus-visible { outline: 2px solid var(--green); outline-offset: 2px }
.hamburger { display: none; width: 44px; height: 44px; border-radius: var(--r-sm); border: 1px solid var(--border); background: transparent; align-items: center; justify-content: center; flex-direction: column; gap: 4px }
.hamburger span { display: block; width: 16px; height: 2px; background: var(--text) }
@media (max-width: 1023px) {
  .header-row { min-height: 56px; border-bottom: none }
  .header-row-2, .site-nav { display: none }
  .hamburger { display: flex }
  .logo { font-size: 15px }
  /* Search dropdown sits just below the 56px header on every small/tablet
     breakpoint - incl. coarse-pointer tablets that use the hamburger. */
  .search-dropdown { top: 60px; width: calc(100% - 24px) }
}
/* Tablet: 768-1023px - show full nav, keep desktop layout. Gated behind
   (hover:hover) and (pointer:fine): the sub-menus are hover/focus dropdowns,
   which touch tablets (coarse pointer) can never open - they get the
   hamburger + overlay accordion instead (the ≤1023 rules below apply). */
@media (min-width: 768px) and (max-width: 1023px) and (hover: hover) and (pointer: fine) {
  .header-row { min-height: 48px; border-bottom: 1px solid var(--border) }
  .header-row-2, .site-nav { display: flex }
  .site-nav { gap: 24px }
  .site-nav a { font-size: 12px }
  .hamburger { display: none }
}

/* ==========================================================================
   HEADER ELEVATION - v1.18.10 (King: "upgrade header, nav + mobile nav")
   On-brand: terminal-dark sacred, straight/clean. All motion reduced-motion
   safe (global @media (prefers-reduced-motion) zeroes every duration).
   ========================================================================== */

/* A. Sticky header scroll-state - deepens legibility WITHOUT killing the
   transparency the King loves: more blur + a hairline green glow border.
   Toggled by premium.js (.is-scrolled after 8px scroll). Enhancement only. */
.site-header.is-scrolled {
  background: rgba(8, 10, 9, .9);
  -webkit-backdrop-filter: blur(14px); backdrop-filter: blur(14px);
  border-bottom-color: var(--border);
  box-shadow: 0 1px 0 rgba(0, 255, 145, .14);
}

/* B. Desktop nav - animated terminal-green underline (the premium nav
   signal). Draws in from the left on hover/active; straight, not decorative.
   Only top-level links (sub-menu links are nested, not direct children). */
.site-nav-list > li > a { position: relative; padding-bottom: 4px }
.site-nav-list > li > a::after {
  content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 2px;
  background: var(--green); box-shadow: 0 0 8px var(--green-glow);
  transform: scaleX(0); transform-origin: left; transition: transform .22s var(--ease-out);
}
.site-nav-list > li > a:hover::after,
.site-nav-list > li > a.active::after,
.site-nav-list > li > a:focus-visible::after { transform: scaleX(1) }

/* C. Desktop sub-menu - gentle fade + rise (matches search dropdown).
   Swapped from display:none so it can animate; focus-within kept for
   keyboard users. */
.site-nav-list .sub-menu {
  opacity: 0; visibility: hidden; transform: translateY(-4px);
  transition: opacity .15s var(--ease-out), transform .15s var(--ease-out), visibility .15s;
}
.site-nav-list > li:hover > .sub-menu,
.site-nav-list > li:focus-within > .sub-menu { opacity: 1; visibility: visible; transform: none }

/* D. Hamburger -> X morph (pure CSS via aria-expanded; no JS change needed).
   The 3 bars rotate into an X when the mobile nav opens. */
.hamburger span { transition: transform .25s var(--ease-out), opacity .18s var(--ease-out) }
.hamburger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg) }
.hamburger[aria-expanded="true"] span:nth-child(2) { opacity: 0 }
.hamburger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg) }

/* E. Mobile drawer - staggered item entrance when opened (premium cascade).
   Reduced-motion zeroes the animation so items simply appear. */
.mno.open .mno-list > li { animation: mno-in .42s var(--ease-out) both }
.mno.open .mno-list > li:nth-child(1) { animation-delay: .04s }
.mno.open .mno-list > li:nth-child(2) { animation-delay: .08s }
.mno.open .mno-list > li:nth-child(3) { animation-delay: .12s }
.mno.open .mno-list > li:nth-child(4) { animation-delay: .16s }
.mno.open .mno-list > li:nth-child(5) { animation-delay: .20s }
.mno.open .mno-list > li:nth-child(6) { animation-delay: .24s }
.mno.open .mno-list > li:nth-child(7) { animation-delay: .28s }
.mno.open .mno-list > li:nth-child(8) { animation-delay: .32s }
@keyframes mno-in { from { opacity: 0; transform: translateX(14px) } to { opacity: 1; transform: none } }

/* F. Search box elevation - terminal command-line feel. A >_ prompt prefixes
   the input (replacing the magnifier as the in-field cue); focusing lights
   the field + panel edge green (focus rule lives in the SEARCH DROPDOWN block). */
.search-input-wrap::before {
  content: '>_';
  position: absolute; left: 12px; top: 50%; transform: translateY(-50%);
  font-family: var(--font-mono); font-size: 13px; font-weight: 600; line-height: 1;
  color: var(--green); pointer-events: none; z-index: 1;
}
.search-input-wrap:focus-within::before { color: var(--green-hover); text-shadow: 0 0 8px var(--green-glow) }
.search-dropdown-icon { display: none } /* >_ replaces the magnifier as the in-field prompt */

/* G. Hamburger elevation - bars turn terminal-green + glow ring when open;
   green accent on hover + a clear focus ring (a11y). */
.hamburger[aria-expanded="true"] {
  border-color: var(--green-border); background: var(--green-dim);
  box-shadow: var(--ring-green), 0 0 16px rgba(0, 255, 145, .14);
}
.hamburger[aria-expanded="true"] span { background: var(--green); box-shadow: 0 0 6px var(--green-glow) }
@media (hover: hover) {
  .hamburger:hover { border-color: var(--green-border) }
  .hamburger:hover span { background: var(--green) }
}
.hamburger:focus-visible { outline: 2px solid var(--green); outline-offset: 2px }
.header-actions .icon-btn:focus-visible { outline: 2px solid var(--green); outline-offset: 2px }

/* ==========================================================================
   H. NAV HOVER UPGRADE - v1.22.25 REVISED (King v1.22.24 round: "WTF I hate
   that side border. I was complaining about the hover, not the active,
   including sub menu"). Three laws now: (1) NO side bars anywhere; (2) the
   ACTIVE state keeps its long-standing look untouched - every flourish is
   HOVER/Focus-only; (3) sub-menus get hover love too. Terminal prompt
   language stays: '> Web-Dev' caret + phosphor bloom + hot underline.
   Ungated (v1.18.99 law: hover doubles as the Android sticky-touch
   highlight); reduced-motion zeroed globally.
   ========================================================================== */
/* Desktop top-level: prompt caret slides in (absolute - zero layout shift) */
.site-nav-list > li > a::before {
  content: '>'; position: absolute; left: -13px; top: 50%; margin-top: -0.6em;
  font-family: var(--font-mono); font-weight: 700; font-size: 13px; line-height: 1.2;
  color: var(--green); opacity: 0; transform: translateX(5px);
  transition: opacity .18s var(--ease-out), transform .18s var(--ease-out);
}
.site-nav-list > li > a:hover::before,
.site-nav-list > li > a:focus-visible::before { opacity: 1; transform: translateX(0) }
/* Desktop top-level: phosphor bloom + hotter underline - hover/focus ONLY */
.site-nav-list > li > a:hover,
.site-nav-list > li > a:focus-visible { text-shadow: 0 0 14px rgba(0, 255, 145, .45) }
.site-nav-list > li > a:hover::after,
.site-nav-list > li > a:focus-visible::after {
  box-shadow: 0 0 10px var(--green-glow), 0 2px 18px rgba(0, 255, 145, .30);
}
/* Desktop DROPDOWN rows (sub-menu): same bloom + a soft green wash - no bars */
.site-nav-list .sub-menu a:hover,
.site-nav-list .sub-menu a:focus-visible {
  background: var(--green-dim);
  text-shadow: 0 0 12px rgba(0, 255, 145, .40);
}
/* Mobile drawer rows: green-dim wash + bloom (replaces the old flat grey).
   Active rows keep their pre-existing green-dim look (1069/1070) - NOT
   re-styled here per the King's law. No side bar, ever. */
.mno-list > li > a:hover, .mno-list > li > a:focus-visible {
  background: var(--green-dim);
  text-shadow: 0 0 12px rgba(0, 255, 145, .40);
}
/* Mobile sub-menu rows: same wash + bloom, no caret, no bar */
.mno-list .sub-menu a:hover, .mno-list .sub-menu a:focus-visible {
  background: var(--green-dim);
  text-shadow: 0 0 12px rgba(0, 255, 145, .40);
}

/* ==========================================================================
   12. SEARCH DROPDOWN
   ========================================================================== */
.search-dropdown { position: fixed; top: 72px; left: 50%; transform: translateX(-50%); z-index: 10000; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; box-shadow: 0 20px 40px rgba(0, 0, 0, .4); width: min(480px, calc(100% - 32px)) }
.search-dropdown[hidden] { display: none }
/* v1.17.09: intentional entrance - fade + 6px rise (prefers-reduced-motion
   globally zeroes the duration, so no motion for users who opt out). */
.search-dropdown:not([hidden]) { animation: sd-rise .18s var(--ease-out) both }
.search-dropdown:not([hidden]) { border-color: var(--border); box-shadow: 0 20px 40px rgba(0, 0, 0, .4) }
@keyframes sd-rise { from { opacity: 0; transform: translateX(-50%) translateY(-6px) } to { opacity: 1; transform: translateX(-50%) translateY(0) } }
.search-dropdown-inner { padding: var(--sp-5) }
#search-results { max-height: 300px; overflow-y: auto; -webkit-overflow-scrolling: touch }
.search-dropdown-form { display: flex; gap: 8px; margin-bottom: var(--sp-4) }
.search-dropdown-icon { width: 18px; height: 18px; flex-shrink: 0; color: var(--mid); margin-top: 4px }
.search-dropdown-input { flex: 1 1 0; min-width: 0; background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 10px 44px 10px 34px; font-size: 16px; color: var(--text); outline: none; font-family: var(--font-mono); letter-spacing: .2px }
.search-dropdown-input:focus { border-color: var(--green); background: rgba(0, 255, 145, .05); box-shadow: var(--ring-green), 0 0 16px rgba(0, 255, 145, .12) }
/* v1.16.92: in-field clear ("x") button - clears all text + closes, visible only when the input has text */
.search-input-wrap { position: relative; flex: 1 1 0; min-width: 0 }
.search-input-wrap .search-dropdown-input { width: 100%; padding-right: 44px }
.search-clear { position: absolute; top: 50%; right: 2px; transform: translateY(-50%); width: 44px; height: 44px; border: 0; border-radius: 50%; background: transparent; color: var(--mid); display: flex; align-items: center; justify-content: center; cursor: pointer }
/* v1.16.94: display:flex above defeats the hidden attribute (UA display:none
   loses to any explicit display) - restore the [hidden] contract so the
   in-field X truly vanishes with an empty field. */
.search-clear[hidden] { display: none }
@media (hover: hover) { .search-clear:hover { color: var(--green); background: var(--green-glow) } }
.search-clear:focus-visible { outline: 2px solid var(--green); outline-offset: 2px }
/* ── 12a. The King's original X - closes the search form (kept alongside the in-field clear) ──── */
.search-dropdown-close { width: 44px; height: 44px; border-radius: var(--r-sm); border: 1px solid var(--border); background: transparent; display: flex; align-items: center; justify-content: center; color: var(--mid); flex-shrink: 0 }
@media (hover: hover) { .search-dropdown-close:hover { border-color: var(--green-border); color: var(--green) } }
#search-results { max-height: 300px; overflow-y: auto; -webkit-overflow-scrolling: touch }
.search-results.has-results { border-top: 1px solid var(--border); padding-top: var(--sp-4) }
.search-result-item { display: flex; align-items: center; gap: 12px; padding: 10px 0; border-bottom: 1px solid var(--border); text-decoration: none; color: inherit }
.search-result-item:last-child { border-bottom: none }
.search-result-item.highlighted { background: var(--green-dim) }
/* v1.17.09: hover affordance + focus ring so each result reads as a real
   control (keyboard + pointer parity with the rest of the site). */
@media (hover: hover) { .search-result-item:hover { background: var(--surface-2) } }
.search-result-item:focus-visible { outline: 2px solid var(--green); outline-offset: -2px; border-radius: var(--r-xs) }
#search-results .badge { flex-shrink: 0 }
.search-result-badge { flex-shrink: 0 }
.search-result-content { flex: 1; min-width: 0 }
.sr-title { font-weight: 600; font-size: 14px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis }
/* v1.16.80 smart search: matched-term highlight + excerpt snippet line */
.sr-title mark, .sr-snippet mark { background: rgba(0, 255, 145, .22); color: var(--green); border-radius: 2px; padding: 0 1px; font-weight: 700 }
.sr-snippet { font-size: 12.5px; line-height: 1.45; color: var(--mid); margin-top: 3px; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden }
.sr-meta { font-size: 12px; color: var(--mid); margin-top: 2px }
.search-loading, .search-empty { padding: var(--sp-6); text-align: center; color: var(--mid); font-size: 13px }
.search-dropdown-footer { padding-top: var(--sp-4); border-top: 1px solid var(--border); font-size: 11px; color: var(--dim2); text-align: center; font-family: var(--font-mono) }
.search-dropdown-footer kbd { background: var(--surface-2); padding: 2px 6px; border-radius: var(--r-xs); font-family: var(--font-mono); font-size: 10px; margin: 0 4px }

/* ==========================================================================
   13. COOKIE BAR
   ========================================================================== */
#cookie {
  position: fixed; bottom: 16px; left: 50%; right: auto;
  z-index: 400; background: var(--surface);
  border: 1px solid var(--border-2); border-radius: var(--r-lg);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .45);
  width: min(720px, calc(100vw - 32px));
  padding: var(--sp-4) var(--sp-5);
  display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
  /* v1.15.5: opacity/visibility guard - the widget is FULLY invisible
     until .show adds it, so no flash can appear before the popup
     (transform-only hiding could glitch visible for a frame on slow
     loads / late style application). */
  opacity: 0; visibility: hidden;
  transform: translateX(-50%) translateY(calc(100% + 24px));
  transition: transform .3s var(--ease-out), opacity .3s var(--ease-out), visibility .3s var(--ease-out);
}
#cookie.show {
  opacity: 1; visibility: visible;
  transform: translateX(-50%) translateY(0);
}
#cookie p { font-size: 13px; color: var(--mid); background: var(--surface); max-width: 60ch; flex: 1 1 auto; min-width: 0; margin: 0 }
#cookie .cookie-actions { display: flex; align-items: center; gap: 10px; flex-shrink: 0 }
/* Card language shared by ALL breakpoints (v1.15.4) - same border/radius/
   shadow/button hierarchy as the mobile card: floating centered card on
   PC + tablet, stacked card on phones. */
#cookie .btn { min-height: 44px; justify-content: center }
#cookie .btn[data-gwill-cookie-accept] { background: var(--green); border-color: var(--green); color: var(--on-green) }
@media (hover: hover) { #cookie .btn[data-gwill-cookie-accept]:hover { background: var(--green-hover) } }
#cookie .btn[data-gwill-cookie-decline] { border-color: var(--border-2); color: var(--mid) }
#cookie .btn:focus-visible { outline: 2px solid var(--green); outline-offset: 2px }
/* Tablet/mini-tab (641-767px): the bottom tab bar is visible, so the card
   floats ABOVE it; still roomy enough for the row layout. */
@media (max-width: 767px) and (min-width: 641px) {
  #cookie { bottom: calc(var(--btm-tab-h) + 12px) }
  /* v1.18.78: stack above the sticky ad bar instead of overlapping it.
     v1.19.18: offset raised - the mobile sticky creative renders 320×100
     (100px tall + 8px gap), not the 50px the original math assumed. */
  body.ad-sticky-visible #cookie { bottom: calc(var(--btm-tab-h) + 116px) }
}
@media (max-width: 640px) {
  /* ── 13a. Mobile: stacked + centered consent card above the bottom tab bar ────*/
  #cookie {
    left: 12px; right: 12px; width: auto;
    bottom: calc(var(--btm-tab-h) + 10px);
    padding: var(--sp-5);
    transform: translateX(0) translateY(calc(100% + 24px));
    flex-direction: column;
    justify-content: center;
    align-items: center;
    text-align: center;
    gap: var(--sp-4);
  }
  #cookie.show { transform: translateX(0) translateY(0) }
  #cookie p { max-width: 40ch; font-size: 13px; margin-bottom: 0 }
  #cookie .cookie-actions { width: 100%; max-width: 320px; gap: 10px }
  #cookie .btn { flex: 1 1 0; padding: 8px 12px; font-size: 13px }
  /* v1.18.78: keep the consent card clear of the sticky ad bar.
     v1.19.18: offset raised - mobile sticky creative is 320×100 (100px tall),
     not 50px; +74px left a 34px overlap with the ad bar's top edge. */
  body.ad-sticky-visible #cookie { bottom: calc(var(--btm-tab-h) + 116px) }
}

/* ==========================================================================
   14. NEWSLETTER BAND (premium widget - homepage + in-article variants)
   ========================================================================== */
.nl-band {
  margin: var(--sp-10) 0;
  border-radius: var(--r-xl);
  background:
    radial-gradient(120% 200% at 100% 0%, var(--green-glow), transparent 55%),
    radial-gradient(90% 180% at 0% 100%, rgba(159, 122, 234, .10), transparent 60%),
    var(--surface);
  border: 1px solid var(--border);
  box-shadow: var(--shadow-md);
  padding: 36px; padding: clamp(28px, 5vw, 48px);
  display: grid;
  grid-template-columns: 1.3fr 1fr;
  gap: var(--sp-8);
  align-items: center;
  position: relative;
  overflow: hidden;
}
.nl-band::before {
  content: 'g';
  position: absolute;
  top: -40px;
  right: -14px;
  font-family: var(--font-mono);
  font-size: 160px;
  font-weight: 800;
  color: transparent;
  -webkit-text-stroke: 1px rgba(0, 255, 145, .10);
  pointer-events: none;
  line-height: 1;
}
.nl-kicker {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--green);
  margin-bottom: 14px;
}
.nl-kicker-prompt { text-shadow: 0 0 12px rgba(0, 255, 145, .5) }
.nl-title { font-size: 26px; font-size: clamp(22px, 3vw, 32px); font-weight: 800; line-height: 1.15; letter-spacing: -.02em; margin-bottom: 12px }
.nl-desc { color: var(--mid); font-size: 15px; line-height: 1.7; max-width: 48ch }
.nl-form { display: flex; gap: 10px }
.nl-input { flex: 1; min-width: 0 }
.nl-submit { flex-shrink: 0; min-height: 50px }
.nl-note { font-size: 12px; color: var(--dim2); font-family: var(--font-mono); margin-top: 12px }
/* ── 14a. In-article variant - tighter, sits inside the prose column ──── */
.nl-band--article {
  margin: var(--sp-8) 0;
  padding: 30px; padding: clamp(24px, 4vw, 36px);
  grid-template-columns: 1fr;
  gap: var(--sp-5);
}
.nl-band--article .nl-desc { max-width: 60ch }
@media (max-width: 767px) {
  .nl-band { grid-template-columns: 1fr; gap: var(--sp-5); padding: 28px 20px }
  .nl-form { flex-direction: column }
  .nl-submit { width: 100%; justify-content: center }
}

/* ==========================================================================
   15. FOOTER
   ========================================================================== */
.site-footer { background: var(--surface); border-top: 1px solid var(--border) }

/* ── 15a. Grid - Desktop: 4 columns ────────────────────────────────── */
.footer-grid { display: grid; grid-template-columns: 1.5fr 1fr 1fr 1fr 1fr; gap: var(--sp-12) var(--sp-12); padding: var(--sp-20) 0 }

/* ── 15b. Link columns - always visible, with terminal headings and generous tap targets. ──── */
.footer-col { min-width: 0; padding: 0 var(--sp-2) }
.footer-col-heading {
  display: flex; align-items: center; gap: 6px;
  font-size: 11px; font-weight: 700; letter-spacing: .08em;
  text-transform: uppercase; color: var(--dim2);
  padding: 4px 0 14px 4px; margin-bottom: 0;
}
.footer-col-heading .bc-prompt { font-size: inherit; color: var(--green); margin-right: 2px }
.footer-col-links { display: grid; gap: 2px }
.footer-col-links a {
  display: block; font-size: 13px; color: var(--mid);
  padding: 8px 0 8px 4px; transition: color .15s, padding .15s, background .15s;
  border-left: 2px solid transparent; border-radius: 0 var(--r-sm) var(--r-sm) 0;
}
@media (hover: hover) {
  .footer-col-links a:hover { color: var(--green); border-left-color: var(--green); padding-left: 14px; background: var(--green-dim) }
}

/* ── 15c. Brand column ─────────────────────────────────────────────── */
.footer-brand { padding: 0 var(--sp-4) }
.footer-brand p { font-size: 13px; color: var(--mid); margin-top: 12px; max-width: 40ch; line-height: 1.7 }
.footer-social { display: flex; gap: 12px; margin-top: 20px; flex-wrap: wrap }
.footer-social .icon-btn { width: 44px; height: 44px; border-radius: var(--r); transition: all .2s }
.footer-social .icon-btn svg { width: 18px; height: 18px }
@media (hover: hover) {
  .footer-social .icon-btn:hover { background: var(--green-dim); border-color: var(--green-border); color: var(--green); transform: translateY(-2px) }
}

/* ── 15d. Bottom bar ───────────────────────────────────────────────── */
.footer-bottom { border-top: 1px solid var(--border); padding: 20px var(--sp-4); display: flex; justify-content: space-between; font-size: 12px; color: var(--dim2); flex-wrap: wrap; gap: 10px }
.footer-bottom a { color: var(--dim2); transition: color .15s }
.footer-credit { white-space: nowrap }
.footer-credit a { color: var(--green); font-weight: 600 }
.gwill-google-news { display: inline-flex; align-items: center; gap: 6px; color: var(--dim2); text-decoration: none; white-space: nowrap; transition: color .15s }
.gwill-google-news .gwill-google-news-mark { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; background: #fff; color: #4285f4; font-weight: 700; font-size: 11px }
.gwill-google-news svg { color: var(--dim2); transition: color .15s, transform .2s }
@media (hover: hover) {
  .footer-bottom a:hover { color: var(--green) }
}
/* ── 15e. Footer elevation - v1.18.30 (King: "footer is next") ─────  Terminal-console panel: glowing top edge, refined social icons, Terminal-console panel: glowing top edge, refined social icons, "you are here" green rail, back-to-top. Straight/clean, on-brand. */

/* ── 15f. Green glow edge along the top of the footer - reads as a panel seam. ──── */
.site-footer {
  border-top: 1px solid var(--border);
  box-shadow: 0 -1px 0 rgba(0, 255, 145, .10), 0 -8px 30px rgba(0, 0, 0, .35) inset;
  background: linear-gradient(180deg, #0f1216, var(--surface) 120px);
}
/* ── 15g. Brand as a subtle green-glow badge. ────────────────────── */
.footer-brand .logo { padding: 6px 10px; border: 1px solid var(--border); border-radius: var(--r-sm); display: inline-flex; transition: border-color .2s, box-shadow .2s }
.footer-brand .logo .cursor { background: var(--green); width: 7px; height: 14px; display: inline-block; animation: caret-blink 1.1s step-end infinite }
@keyframes caret-blink { 0%, 100% { opacity: 1 } 50% { opacity: 0 } }
@media (hover: hover) {
  .footer-brand .logo:hover { border-color: var(--green-border); box-shadow: var(--ring-green) }
}
/* ── 15h. Link columns: persistent "you are here" green rail + arrow cue on hover. ──── */
.footer-col-links a.is-current { color: var(--green); border-left-color: var(--green); padding-left: 14px; background: var(--green-dim) }
@media (hover: hover) {
  .footer-col-links a:hover { color: var(--green); border-left-color: var(--green); padding-left: 14px; background: var(--green-dim) }
  .footer-col-links a:hover::after { content: "\2192"; margin-left: 6px; font-family: var(--font-mono); font-size: 11px; color: var(--green) }
}
/* ── 15i. Social icons - defined border + green glow-ring lift. ──── */
.footer-social .icon-btn { border: 1px solid var(--border); color: var(--mid) }
@media (hover: hover) {
  .footer-social .icon-btn:hover { background: var(--green-dim); border-color: var(--green-border); color: var(--green); transform: translateY(-2px); box-shadow: var(--ring-green) }
}
/* ── 15j. Back-to-top + home in the bottom bar. ──────────────────── */
.footer-bottom .js-to-top { display: inline-flex; align-items: center; gap: 6px; color: var(--dim2); font-weight: 600 }
.footer-bottom .js-to-top span { color: var(--green); transition: transform .2s }
@media (hover: hover) { .footer-bottom .js-to-top:hover span { transform: translateY(-2px) } }

.footer-bottom { border-top: 1px solid var(--border) }
.footer-credit a { text-shadow: 0 0 10px rgba(0, 255, 145, .12) }

/* ── 15k. Small tablet / foldable: 600-767px ─────────────────────── */
@media (min-width: 600px) and (max-width: 767px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: repeat(2, 1fr); gap: var(--sp-4) }
  .wrap { padding: 0 var(--sp-6) }
  .page-hero { padding: var(--sp-6) 0 0 }
  .section { padding: var(--sp-16) 0 }
  .section-sm { padding: var(--sp-10) 0 }
  .about-stats { grid-template-columns: repeat(4, 1fr) }
  .about-stat strong { font-size: 20px }
  .footer-grid { grid-template-columns: 1fr 1fr; gap: var(--sp-5); padding: var(--sp-6) var(--sp-6) var(--sp-10) }
  .footer-col-heading { padding-top: var(--sp-2) }
  .footer-col { margin-top: var(--sp-4) }
  .footer-bottom { padding: 20px var(--sp-4) }
  .header-row { min-height: 56px; border-bottom: none; padding: 6px var(--sp-6) }
  .header-row-2, .site-nav { display: none }
  .hamburger { display: flex }
  .logo { font-size: 13px; font-size: clamp(11px, 4vw, 14px) }
}

/* ── 600-640px: card grids back to ONE column - two-up gives only ~268px
   columns at 600px (below the ~280px comfort minimum). Footer/about keep
   their 600-767 two-column layout. ─────────────────────────────────────── */
@media (min-width: 600px) and (max-width: 640px) {
  .grid-2, .grid-3, .grid-4 { grid-template-columns: 1fr; gap: var(--sp-4) }
}

/* ── 15l. Standard tablet portrait: 768-1023px ───────────────────── */
@media (min-width: 768px) and (max-width: 1023px) {
  .wrap { padding: 0 var(--sp-6) }
  .header-row, .header-row-2 { padding-left: var(--sp-6); padding-right: var(--sp-6) }
  .footer-grid { grid-template-columns: 1fr 1fr 1fr; gap: var(--sp-6) var(--sp-8); padding: var(--sp-10) var(--sp-6) var(--sp-12) }
  .footer-brand { grid-column: 1 / -1; padding: 0 0 var(--sp-6); border-bottom: 1px solid var(--border); margin-bottom: var(--sp-6) }
  .footer-brand p { max-width: 50ch }
  .footer-col { padding-top: var(--sp-2) }
  .footer-col-links a { padding-left: 0 }
  .footer-col-heading { margin-bottom: 12px }
  .footer-col-links a::after { content: "→"; margin-left: 4px; font-size: 10px; color: var(--dim2); font-family: var(--font-mono) }
  .footer-social .icon-btn { width: 44px; height: 44px }
  .footer-bottom { padding: 24px var(--sp-4) }
}

/* ── 15m. Mobile: ≤767px ─────────────────────────────────────────── */
@media (max-width: 767px) {
  .site-footer { padding-bottom: calc(var(--btm-tab-h) + 20px) }

  /* ── 15n. Grid - single column (footer mobile) ──────────────────────*/
  .footer-grid { grid-template-columns: 1fr; gap: 0; padding: var(--sp-4) var(--sp-4) var(--sp-8) }

  /* ── 15o. Full-width terminal section headings (footer mobile) ──────*/
  .footer-col-heading {
    display: flex; align-items: center; gap: 8px;
    padding: 0 var(--sp-5) var(--sp-2); margin-bottom: 0;
    border-bottom: 1px solid var(--border);
  }
  .footer-col-heading .bc-prompt { display: inline; color: var(--green) }
  .footer-col-links { padding: var(--sp-2) var(--sp-5) }
  .footer-col-links a { border-left: none; padding: 12px 4px }

  /* ── 15p. Brand section - top of footer grid ────────────────────────*/
  .footer-brand {
    padding: var(--sp-6) var(--sp-5);
    border-bottom: 1px solid var(--border);
    margin-bottom: 0;
  }
  .footer-brand p { max-width: 100%; font-size: 14px; margin-top: 14px; line-height: 1.7 }
  .footer-brand .logo { margin-bottom: 4px }

  /* ── 15q. Link columns - card-like blocks with clear hit areas ──────*/
  .footer-col {
    padding: var(--sp-5);
    border: 1px solid var(--border);
    margin-top: var(--sp-4);
    background: var(--surface-2);
    border-radius: var(--r);
  }
  .footer-col-links a {
    padding: 12px 8px;
    font-size: 14px;
    border-left: none;
    border-bottom: 1px solid var(--border);
    border-radius: 0; /* straight divider - no curved end (King Aug 17 2026) */
    display: flex;
    align-items: center;
    justify-content: space-between;
  }
  /* ── 15r. Last child keeps its divider (footer rows) ────────────────*/
  .footer-col-links a::after {
    content: "→";
    color: var(--dim2);
    font-family: var(--font-mono);
    font-size: 12px;
    transition: color .15s;
  }
  @media (hover: hover) {
    .footer-col-links a:hover::after { color: var(--green) }
    .footer-col-links a:hover {
      color: var(--green);
      border-left: none;
      padding-left: var(--sp-5);
      background: var(--green-dim);
    }
  }

  /* ── 15s. Social icons ──────────────────────────────────────────────*/
  .footer-social { gap: 16px; margin-top: 24px }

  /* ── 15u. "You are here" rail on touch - straight left border ───────*/
  .footer-col-links a.is-current { color: var(--green); background: var(--green-dim); box-shadow: inset 2px 0 0 var(--green); padding-left: 12px }

  /* ── 15t. Bottom bar ────────────────────────────────────────────────*/
  .footer-bottom { flex-direction: column; align-items: center; text-align: center; gap: 8px; padding: 20px var(--sp-4) }
  .footer-bottom span { font-size: 12px }
  @media (hover: hover) {
    .footer-bottom a:hover { border-color: var(--green-border); color: var(--green) }
  }
}

/* ==========================================================================
   16. HERO SECTION
   ========================================================================== */
.hero { position: relative; padding: var(--sp-32) 0 var(--sp-24); overflow: hidden }
.hero::before { content: ""; position: absolute; top: -20%; right: -10%; width: 600px; height: 600px; background: radial-gradient(circle, var(--green-glow), transparent 65%); pointer-events: none }
.hero-inner { position: relative; z-index: 2; max-width: 760px }
.hero .h1 { margin-bottom: 22px }
.hero .h1 .accent { color: var(--green) }
.hero-sub { font-size: 18px; color: var(--mid); line-height: 1.7; max-width: 56ch; margin-bottom: 36px }
.hero-cta { display: flex; gap: 14px; margin-bottom: 56px; flex-wrap: wrap }
.stat-strip { display: grid; grid-template-columns: repeat(4, 1fr); border-top: 1px solid var(--border); padding-top: 32px }
.stat-strip .stat { border-right: 1px solid var(--border); padding-right: 24px }
.stat-strip .stat:last-child { border-right: none }
.stat-num { font-size: 26px; font-weight: 800 }
.stat-label { font-size: 11px; color: var(--dim); text-transform: uppercase; letter-spacing: .06em; margin-top: 6px }
@media (max-width: 767px) {
  .hero { padding: var(--sp-16) 0 var(--sp-12) }
  .hero::before { width: 340px; height: 340px; top: -15%; right: -20% }
  .hero-sub { font-size: 16px }
  .stat-strip { grid-template-columns: repeat(2, 1fr); row-gap: 20px }
  .stat-strip .stat:nth-child(2n) { border-right: none }
  .hero-cta { flex-direction: column }
  .hero-cta .btn { width: 100%; justify-content: center }
}

/* ==========================================================================
   17. HERO BOOT ANIMATION
   ========================================================================== */
.hero-boot { opacity: 0; transform: translateY(20px); transition: opacity .6s var(--ease-out), transform .6s var(--ease-out) }
.hero-boot.visible { opacity: 1; transform: translateY(0) }
.boot-terminal { font-family: var(--font-mono); font-size: 14px; color: var(--green); margin-bottom: var(--sp-6); min-height: 120px; line-height: 1.8 }
.boot-line { opacity: 0; transform: translateY(10px); transition: opacity .3s var(--ease-out), transform .3s var(--ease-out) }
.boot-line.visible { opacity: 1; transform: translateY(0) }
.boot-buttons { opacity: 0; transition: opacity .4s var(--ease-out) }
.boot-buttons.visible { opacity: 1 }
.hero-static { opacity: 0; transition: opacity .5s var(--ease-out) }
.hero-static[style*="block"] { opacity: 1 }

/* ==========================================================================
   18. FEATURED POST (replaces old hero)
   ========================================================================== */
.featured-section { padding: var(--sp-8) 0 var(--sp-6); position: relative }
.featured-link { display: block; text-decoration: none; color: inherit }
@media (hover: hover) { .featured-link:hover { color: inherit } }
.featured-title a::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; z-index: 1 }
.featured-title a:focus-visible::after { outline: 2px solid var(--green); outline-offset: -4px; border-radius: var(--r-lg) }
.featured-media { aspect-ratio: 16/9; display: flex; align-items: center; justify-content: center; font-size: 56px; overflow: hidden; min-height: 220px; position: relative }
.featured-media::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; background: linear-gradient(180deg, rgba(13,13,13,0) 55%, rgba(13,13,13,.38)); pointer-events: none; z-index: 1 }
.featured-media .featured-img { width: 100%; height: 100%; object-fit: cover }
.featured-media .featured-emoji { font-size: 64px }
.featured-media .badge { z-index: 2 }
.card-img { width: 100%; height: 100%; object-fit: cover }
.featured-body { padding: var(--sp-6) var(--sp-6) var(--sp-6) 0; display: flex; flex-direction: column; justify-content: center }
.featured-body .badge { margin-bottom: 14px; align-self: flex-start }
.featured-title { font-size: 24px; font-size: clamp(20px, 2.4vw, 28px); font-weight: 800; line-height: 1.25; margin-bottom: 12px; letter-spacing: -.01em }
.featured-title a { color: var(--text) }
@media (hover: hover) { .featured-title a:hover { color: var(--green) } }
.featured-excerpt { font-size: 15px; color: var(--mid); line-height: 1.65; margin-bottom: 16px }
.featured-meta { font-size: 12px; color: var(--mid); display: flex; gap: 10px; align-items: center; margin-bottom: 20px }
.featured-body .btn { align-self: flex-start }

@media (max-width: 1023px) {
  .featured-media { min-height: 200px }
  .featured-body { padding: var(--sp-6) }
}
@media (max-width: 767px) {
  .featured-section { padding: var(--sp-6) 0 var(--sp-4) }
  .featured-media { min-height: 170px; font-size: 44px }
  .featured-body { padding: var(--sp-5) }
  .featured-title { font-size: 20px; font-size: clamp(18px, 4.6vw, 22px) }
  .featured-excerpt { font-size: 14px }
}

/* ==========================================================================
   HERO CAROUSEL (premium featured section - v1.17.0)
   ==========================================================================
   Homepage featured carousel - the verge.html #hero-carousel pattern:
   each slide is ONE full-bleed cover image with the category kicker,
   title, a single short deck line and the mono byline row OVERLAID at the
   bottom-left over a bottom-weighted scrim (image + title only - no excerpt
   panel, no CTA button, no two-column layout). The section wraps its content
   in the same .wrap box as the homepage card sections, so the slide aligns
   edge-to-edge with the content cards (NOT full-bleed). Compact desktop
   slide (~400px) so the whole carousel fits the 1440×900 viewport above the
   fold. Terminal-premium skin - soft radius, dark depth shadow, green
   progress bar under the active slide, mono timestamps. Graceful no-JS:
   slide 1 renders visible, controls + progress are JS-gated (.hc-js). */
.hero-carousel { padding: var(--sp-8) 0 var(--sp-6); position: relative }
.hc-track { position: relative }
.hc-slide { display: none; position: relative; height: 400px; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-xl); overflow: hidden; box-shadow: var(--shadow-md) }
.hc-slide.is-active { display: block; animation: hc-fade .45s var(--ease-out) }
@keyframes hc-fade { from { opacity: 0 } to { opacity: 1 } }
.hc-media { position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 56px; overflow: hidden }
.hc-media.cat-tint { background: linear-gradient(160deg, var(--c-grad, rgba(0, 255, 145, .16)), var(--surface) 75%) }
.hc-scrim { position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; pointer-events: none; z-index: 1; background: radial-gradient(120% 85% at 18% 100%, rgba(0, 0, 0, .5), transparent 62%), linear-gradient(180deg, rgba(13, 13, 13, 0) 0%, rgba(13, 13, 13, .14) 34%, rgba(13, 13, 13, .55) 56%, rgba(13, 13, 13, .85) 76%, rgba(13, 13, 13, .97) 100%) }
.hc-img { width: 100%; height: 100%; object-fit: cover; display: block }
.hc-media-fallback { width: 50%; max-width: 300px; z-index: 1 }
/* Overlay body - spans the slide (so the stretched title link covers the
   WHOLE slide), text is bottom-left over the image with padding + inner
   max-widths so it never touches the edge. */
.hc-body { position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; z-index: 2; display: flex; flex-direction: column; justify-content: flex-end; padding: 34px; min-width: 0 }
.hc-body .badge { margin-bottom: 14px; align-self: flex-start; position: relative; z-index: 2 }
/* Carousel category badge - near-solid dark chip so it reads over ANY cover
   image (no reliance on the bottom-weighted scrim): backdrop blur, category
   color on the border + text, bumped padding/size. The generic .badge base is
   a 10px/6px-12px tint pill; this overrides it for the hero only. */
.hc-body .badge-cat {
	background: rgba(8, 9, 11, .88);
	-webkit-backdrop-filter: blur(4px);
	backdrop-filter: blur(4px);
	border: 1px solid var(--c, var(--green));
	color: var(--c, var(--green));
	padding: 7px 14px;
	font-size: 11px;
	box-shadow: 0 2px 12px rgba(0, 0, 0, .45);
}
.hc-title { font-size: 28px; font-size: clamp(24px, 3vw, 34px); font-weight: 800; line-height: 1.18; margin-bottom: 10px; letter-spacing: -.02em; overflow-wrap: anywhere; max-width: 680px; color: #fff; text-wrap: balance; text-shadow: 0 2px 12px rgba(0, 0, 0, .45) }
.hc-title a { color: #fff; text-decoration: none }
/* ── 18a. Stretched link - the whole slide is one click target to the post. ──── */
.hc-title a::after { content: ""; position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; z-index: 1 }
@media (hover: hover) { .hc-title a:hover { color: var(--green); text-decoration: underline; text-decoration-thickness: 2px; text-underline-offset: 5px } }
.hc-deck { font-size: 15px; color: #fff; line-height: 1.6; margin-bottom: 16px; max-width: 600px; text-shadow: 0 1px 12px rgba(0, 0, 0, .65); display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden }
.hc-meta { font-size: 12px; color: rgba(255, 255, 255, .92); display: flex; gap: 10px; align-items: center; font-family: var(--font-mono); flex-wrap: wrap; text-shadow: 0 1px 8px rgba(0, 0, 0, .6) }
/* Meta separator - pure geometric green dot (no glyph, no halo). Kills the
   inherited text-shadow from .hc-meta and the generic .hc-dot border so the
   grey-ring effect is gone; the pager dots (.hc-dots .hc-dot) are untouched. */
.hc-meta .hc-dot { width: 3px; height: 3px; border-radius: 50%; background: var(--green); border: 0; opacity: .8; flex-shrink: 0; text-shadow: none; cursor: default }
.hc-meta time { color: rgba(255, 255, 255, .85) }

/* ── 18b. Controls + progress - JS-gated: hidden until .hc-js confirms the carousel runs. ──── */
.hc-controls { display: none; align-items: center; justify-content: center; gap: 16px; margin-top: var(--sp-5) }
.hc-js .hc-controls { display: flex }
.hc-arrow { display: flex; align-items: center; justify-content: center; width: 44px; height: 44px; border-radius: var(--r); background: var(--surface); border: 1px solid var(--border); color: var(--mid); cursor: pointer; transition: border-color .15s var(--ease-quick), color .15s, background .15s, transform .15s var(--ease-quick), box-shadow .2s var(--ease-quick) }
@media (hover: hover) { .hc-arrow:hover { border-color: var(--green-border); color: var(--green); background: var(--green-dim); transform: translateY(-1px); box-shadow: var(--shadow-glow) } }
.hc-dots { display: flex; gap: 8px; align-items: center }
/* Pager dots - 24x24 hit target (WCAG 2.5.8 target-size min), 10px visual dot
   drawn via ::before so the button itself meets the 24px minimum while the
   rendered dot keeps the original proportions (v1.16.74). */
.hc-dot { position: relative; width: 24px; height: 24px; padding: 0; border: 0; background: transparent; cursor: pointer; display: inline-flex; align-items: center; justify-content: center }
.hc-dot::before { content: ''; display: block; width: 10px; height: 10px; border-radius: var(--r-pill); border: 1px solid var(--border); background: var(--surface-2); transition: all .2s var(--ease-quick) }
.hc-dot.is-active::before { background: var(--green); border-color: var(--green); box-shadow: 0 0 10px var(--green-glow) }
@media (hover: hover) { .hc-dot:hover::before { border-color: var(--green-border) } }
.hc-progress { display: none; height: 3px; margin-top: var(--sp-4); background: var(--border-2); border-radius: var(--r-pill); overflow: hidden }
.hc-js .hc-progress { display: block }
.hc-progress-fill { display: block; height: 100%; background: var(--green); box-shadow: 0 0 8px var(--green-glow); transform: scaleX(0); transform-origin: left; will-change: transform }
.hc-single .hc-controls, .hc-single .hc-progress { display: none }

/* ── 18c. Hero carousel elevation - v1.18.40 (King: "next is the homepage") ────  Premium craft on the dominant above-the-fold element. Terminal-dark, Premium craft on the dominant above-the-fold element. Terminal-dark, straight/clean. Accent glows only (no structural green divider lines). straight/clean. Accent glows only (no structural green divider lines). Reduced-motion safe (global query zeroes every duration). */
.hc-slide { border: 1px solid var(--border); transition: box-shadow .3s var(--ease-out), transform .3s var(--ease-out) }
.hc-slide.is-active { box-shadow: var(--shadow-lg), 0 0 30px rgba(0, 255, 145, .12) }
/* ── 18d. Gentle life on the active cover image. ─────────────────── */
.hc-slide .hc-img { transition: transform .6s var(--ease-out) }
.hc-slide.is-active .hc-img { transform: scale(1.03) }
/* ── 18e. ACF "Featured" badge (v1.18.76) - slide-1 kicker, only when field is filled. ──── */
.hc-featured-badge { margin-right: 8px; text-transform: uppercase; letter-spacing: .08em }
/* ── 18f. Title gets a green accent bar under the kicker for presence. ──── */
.hc-body .badge-cat { box-shadow: 0 0 14px rgba(0, 0, 0, .5), 0 0 0 1px var(--c, var(--green-border)) }
/* ── 18g. Arrows - green glow-ring on hover/focus (matches header/footer). ──── */
.hc-arrow:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; border-color: var(--green-border); color: var(--green) }
@media (hover: hover) {
  .hc-arrow:hover { box-shadow: var(--ring-green), var(--shadow-glow) }
}
/* ── 18h. Progress bar - a touch thicker for presence; stays green (accent, not a divider). ──── */
.hc-progress { height: 4px }
.hc-progress-fill { box-shadow: 0 0 10px var(--green-glow) }

/* Section heading prompt - a faint green left-rail so each homepage section
   reads as a deliberate, intentional block (not a divider line). */
.sec-head { position: relative; padding-left: 14px }
/* v1.19.03 (King): the SECTION-TITLE side pill wears the category color.
   (.sec-head root now carries $vars from front-page.php so ::before and
   .label inherit var(--c); fallback keeps brand green.) */
.sec-head::before { content: ''; position: absolute; left: 0; top: 2px; bottom: 2px; width: 3px; border-radius: var(--r-pill); background: var(--c, var(--green)); box-shadow: 0 0 10px color-mix(in srgb, var(--c, #00ff91) 35%, transparent); opacity: .85 }
.sec-head .label { color: var(--c, var(--green)); overflow-wrap: anywhere }
/* v1.19.05 long-name law: the link never shrinks or breaks; a very long
   title wraps under the rail instead of colliding with the link. */
.sec-head .sec-head-link { flex-shrink: 0; white-space: nowrap }
/* v1.19.06 (King: "Put them back on the same line now that it's short"):
   single-row header restored on ALL viewports - the constant short CTA
   ("View all →") leaves ample slack even on phones. Long titles still wrap
   safely and the link never shrinks (v1.19.05 laws unchanged). */
.sec-head { gap: 12px }
/* Resources page section headers already carry a colored category DOT, so the
   green left-rail is redundant - suppress it there (King: "remove the side
   borders in the h2s, they already have something beautiful going on").
   Belt-and-suspenders: kill the ::before entirely on these headers whether or
   not a .sec-head class is present. */
.resources-section-header { padding-left: 0 !important }
.resources-section-header::before { content: none !important; display: none !important }

@media (max-width: 1023px) {
  .hc-slide { height: 340px }
  .hc-body { padding: 28px }
}
@media (max-width: 767px) {
  .hero-carousel { padding: var(--sp-6) 0 var(--sp-4) }
  .hc-slide { height: 320px }
  .hc-media { font-size: 44px }
  .hc-body { padding: 24px 20px }
  .hc-title { font-size: 21px; font-size: clamp(19px, 5.6vw, 24px); margin-bottom: 8px }
  .hc-deck { font-size: 13.5px; margin-bottom: 12px }
  .hc-meta { gap: 8px; font-size: 11px }
  .hc-controls { gap: 12px }
  .hc-arrow { width: 44px; height: 44px }
}

/* ==========================================================================
   19. TOC (TABLE OF CONTENTS) - Terminal branded
   ========================================================================== */
.toc-dropdown { position: relative; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); overflow: hidden; box-shadow: var(--shadow-xs) }
.toc-sidebar { border-radius: var(--r-lg); box-shadow: var(--shadow-sm) }
.toc-summary { -webkit-user-select: none; user-select: none; cursor: pointer; display: flex; align-items: center; justify-content: space-between; padding: 12px 16px; font-size: 12px; font-weight: 600; color: var(--green); font-family: var(--font-mono); background: var(--surface-2); border-bottom: 1px solid var(--border); transition: background .15s }
.toc-summary:hover { background: var(--green-dim) }
.toc-summary::after { content: '▼'; font-size: 8px; transition: transform .2s; margin-left: 8px; color: var(--dim) }
.toc-dropdown[open] .toc-summary::after { transform: rotate(180deg) }
/* Collapsed: the summary's divider border must NOT float inside the
   container outline - equal border all around (v1.16.86). */
.toc-dropdown:not( [open] ) .toc-summary { border-bottom: 0 }
.toc-list { padding: 8px 0; max-height: 360px; overflow-y: auto; -webkit-overflow-scrolling: touch }
.toc-list a { display: block; min-height: 44px; font-size: 13px; color: var(--mid); padding: 8px 16px 8px 36px; transition: color .15s, background .15s, padding .15s; font-family: var(--font-mono); border-left: 2px solid transparent; position: relative }
/* v1.16.7: every '>' prompt shares the heading's left edge so the heading and
   its contents read as one terminal line. Mobile: summary text starts at 16px
   (summary padding), so the item prompt moves 10px -> 16px. The sidebar
   overrides below anchor to the widget content edge (20px padding), matching
   the h3 heading's own '>'. */
.toc-list a::before { content: '>_'; color: var(--dim2); font-size: 10px; position: absolute; left: 16px; top: 8px; transition: color .15s }
/* v1.18.98 (King: "look at the comments hover effect") - the SAME pattern
   as the comments reaction buttons (.vibe-reaction-option): PLAIN ungated
   :hover, NO (hover:hover) gate. On Android Chrome a tap/press applies
   sticky :hover → the touched row paints green and STAYS until another row
   is touched - identical to how the comments behave on his phone. The gate
   was what hid hover from touch entirely. :active kept for the momentary
   press flash; padding-free since v1.18.95 (no scroll-flick jitter). */
.toc-list a:hover { color: var(--green); background: var(--green-dim); border-left-color: var(--green); padding-left: 42px }
.toc-list a:hover::before { color: var(--green) }
.toc-list a:active { color: var(--green); background: var(--green-dim); border-left-color: var(--green) }
.toc-list a:active::before { color: var(--green) }
/* ── 19a. Sub-items keep their deeper indent (same deltas as the old inline padding) ──── */
.toc-list li.toc-h3 a { padding-left: 46px }
.toc-sidebar .toc-list { padding: 0; max-height: 400px }
.toc-sidebar .toc-list a { padding-left: 20px }
.toc-sidebar .toc-list a::before { left: 0 }
.toc-sidebar .toc-list li.toc-h3 a { padding-left: 30px }
.toc-sidebar .toc-list a:hover { padding-left: 30px }
/* sidebar :active padding-left intentionally omitted - jitter law v1.18.95 */

/* ── 19b. TOC heading spacing - gap after >_ prefix ────────────────── */
.sidebar-widget h3, .sidebar-widget h4 { word-spacing: 8px }

/* v1.16.8 - sidebar TOC heading as a compact terminal band, twin of the mobile summary */
.toc-sidebar h3 {
  font-size: 12px;
  font-weight: 600;
  line-height: 1.6;
  color: var(--green);
  font-family: var(--font-mono);
  background: var(--surface-2);
  border-bottom: 1px solid var(--border);
  margin: calc(-1 * var(--sp-5)) calc(-1 * var(--sp-5)) 0;
  padding: 12px 20px;
  border-radius: var(--r) var(--r) 0 0;
  word-spacing: 4px;
}
.toc-sidebar .toc-list { border-radius: 0 0 var(--r) var(--r) }
.toc-summary { word-spacing: 4px }
.hero-static { opacity: 0; transition: opacity .5s var(--ease-out) }
.hero-static[style*="block"] { opacity: 1 }

/* ==========================================================================
   20. PAGE HERO & BREADCRUMB
   ========================================================================== */
.page-hero { padding: var(--sp-6) 0 0; border-bottom: 1px solid var(--border) }
.page-hero .h1 { margin-bottom: 14px }
.page-hero .wrap > p { font-size: 16px; color: var(--mid); max-width: 62ch }
.page-hero .wrap > p a { color: var(--green); text-decoration: underline; text-underline-offset: 3px }
.page-hero .wrap > p a:hover { color: var(--green-hover) }
/* ── 20a. Breadcrumb - terminal-style semantic list ────────────────────── */
.breadcrumb { margin-bottom: 20px; /* no overflow:hidden - list handles scroll */ }
.breadcrumb-list { display: flex; flex-wrap: nowrap; align-items: center; gap: 0; font-size: 12px; color: var(--dim2); font-family: var(--font-mono); list-style: none; margin: 0; padding: 0; overflow-x: auto; -webkit-overflow-scrolling: touch; scrollbar-width: none }
.breadcrumb-list::-webkit-scrollbar { display: none }
.breadcrumb-list li { display: inline-flex; align-items: center; white-space: nowrap; flex-shrink: 0 }
.breadcrumb-list li + li::before { content: '/'; margin: 0 6px; color: var(--border-2); font-weight: 400; font-size: 11px }
.breadcrumb-list a { display: inline-flex; align-items: center; min-height: 44px; color: var(--dim2); text-decoration: none; transition: color .15s }
.breadcrumb-list a:hover { color: var(--green) }
.breadcrumb-current { color: var(--text); font-weight: 600; opacity: .88 }
/* v1.18.89: the "Page N" depth chip is a real <li> now (was bare spans -
   jammed flush against the category name). Same current-crumb styling. */
.breadcrumb-page { color: var(--text); font-weight: 600; opacity: .88 }
.bc-prompt { color: var(--green); font-weight: 700; margin-right: 4px }
@media (max-width: 767px) {
  .breadcrumb-list { font-size: 11px }
  .breadcrumb-list li + li::before { margin: 0 5px; font-size: 10px }
}

/* ── 20b. Blog stats row ─────────────────────────────────────────── */
.blog-stats { display: flex; gap: 24px; margin-top: 20px }
.blog-stat { font-size: 13px; color: var(--mid); font-family: var(--font-mono) }
.blog-stat strong { color: var(--green); font-weight: 700 }
/* ── 20c. Author archive - socials centered on mobile ────────────── */
.author-socials { flex-wrap: wrap }
@media (max-width: 767px) {
  .author-socials { justify-content: center }
}

/* ── 20d. TOC mobile - phone only (≤767px). PC + tablet use the sticky sidebar TOC. ──── */
.toc-mobile { display: none; margin-bottom: var(--sp-6) }
@media (max-width: 767px) { .toc-mobile { display: block } }

/* TOC anchor jumps must clear the sticky header (v1.6.3) - otherwise the
   jumped-to H2 lands hidden behind it. Phone header = 56px single row;
   tablet/desktop = 92px two rows. scroll-padding-top on html covers every
   anchor jump; scroll-margin-top on headings is the per-element belt. */
html { scroll-padding-top: 68px }
.prose h2[id], .prose h3[id] { scroll-margin-top: 68px }
@media (min-width: 768px) {
  html { scroll-padding-top: 108px }
  .prose h2[id], .prose h3[id] { scroll-margin-top: 108px }
}

/* ==========================================================================
   21. READING PROGRESS BAR
   ========================================================================== */
/* Premium pass: transform scaleX (compositor-only, zero layout/CLS cost -
   width animation would reflow on every scroll frame) + solid brand-green fill + a
   dim track so the bar reads as a progress meter against the page top. */
.reading-progress {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 3px;
  background: var(--green);
  transform: scaleX(0);
  transform-origin: 0 0;
  z-index: 10000;
  pointer-events: none;
}

/* ==========================================================================
   22. ARTICLE LAYOUT (Single Post)
   ========================================================================== */
.article-layout { display: grid; grid-template-columns: 1fr var(--sidebar-w); gap: var(--sp-12); align-items: start; min-width: 0 }
.article-layout article, .article-layout > div { min-width: 0 }
.article-header { margin-bottom: var(--sp-6) }
.article-header .badge { margin-bottom: 16px }
.article-header h1 { font-size: 32px; font-size: clamp(26px, 4vw, 40px); font-weight: 800; line-height: 1.15; margin-bottom: 18px }
.article-meta { display: flex; align-items: center; gap: 14px; font-size: 13px; color: var(--mid) }
.avatar { width: 32px; height: 32px; border-radius: 50%; background: var(--surface-2); border: 1px solid var(--border); flex-shrink: 0; object-fit: cover }
.avatar--initial { display: flex; align-items: center; justify-content: center; font-size: 13px; font-weight: 700; color: var(--green) }
.article-cover { aspect-ratio: 16/8; border-radius: var(--r); overflow: hidden; margin: var(--sp-6) 0 var(--sp-8); background: linear-gradient(160deg, #0a1f22, var(--surface) 75%); display: flex; align-items: center; justify-content: center; font-size: 52px; width: 100%; max-width: 100%; min-width: 0 }
.article-cover--placeholder { min-height: 200px }
.article-cover--placeholder.cat-tint { background: linear-gradient(160deg, var(--c-grad, rgba(0, 255, 145, .16)), var(--surface) 75%) }

/* ── 22k. "Updated" label in article meta ───────────────────────────*/
.meta-updated { color: var(--green); font-family: var(--font-mono); font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .05em; margin-right: 3px }

/* ── 22a. Featured-image caption - terminal comment vibe, matches .prose figcaption (v1.4.7) ──── */
.article-cover-caption { margin: 0 0 var(--sp-8); font-family: var(--font-mono); font-size: 12px; color: var(--mid); text-align: center }
.article-cover-caption::before { content: '# '; color: var(--green) }
/* ── 22b. When a caption follows the cover, tighten the cover's bottom margin so the caption sits right under the image ──── */
/* Tighten cover->caption gap only when the sibling selector is supported
   (Firefox <121 / Safari <15.4 / Chrome <105 ignore the rule entirely -
   the cover keeps its standard var(--sp-8) bottom margin, no breakage). */
@supports selector(:has(*)) {
  .article-cover:has(+ .article-cover-caption) { margin-bottom: 10px }
}

/* Video cover - YouTube embed fills the same hero slot as the image.
   v1.16.79: the hero is now a click-to-load facade (same in-flow sizing;
   radius 0 to match the borderless iframe it replaced). */
.article-cover--video { aspect-ratio: 16/9; padding: 0; background: var(--bg) }
.article-cover--video iframe { width: 100%; height: 100%; border: 0; display: block }
.article-cover--video .gwill-embed-facade { border-radius: 0 }

/* Legacy fallback - browsers without aspect-ratio (Safari <15, Chrome <88,
   Firefox <89, Edge <88) collapse 100%-height iframes to 150px. The
   padding-top trick restores a fluid 16:9 box on those engines only;
   modern browsers keep the clean aspect-ratio rule above. */
@supports not (aspect-ratio: 16/9) {
  .prose .wp-block-embed.is-type-video .wp-block-embed__wrapper,
  .article-cover--video { position: relative; height: 0; padding-top: 56.25% }
  .prose .wp-block-embed.is-type-video .wp-block-embed__wrapper > iframe,
  .article-cover--video iframe { position: absolute; top: 0; left: 0; width: 100%; height: 100% }
  /* v1.16.79: facades must absolute-fill the padding-top box on legacy engines */
  .prose .wp-block-embed.is-type-video .wp-block-embed__wrapper > .gwill-embed-facade,
  .article-cover--video .gwill-embed-facade { position: absolute; top: 0; left: 0; width: 100%; height: 100% }
}

/* ── 22c. Media fallback - faint terminal logo SVG (no featured image) ──── */
.media-fallback { width: 62%; max-width: 220px; height: auto }
.card-media .media-fallback { width: 70%; max-width: 200px }
.article-cover .media-fallback { width: 42%; max-width: 320px }
.media-fallback-cursor { animation: blink 1.1s step-end infinite }
.sidebar-widget { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); padding: var(--sp-5); margin-bottom: var(--sp-5); box-shadow: var(--shadow-xs) }
.sidebar-widget h4 { font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--dim); margin-bottom: 16px; font-family: var(--font-mono) }
.sidebar-sticky { position: -webkit-sticky; position: sticky; top: 100px }
.sidebar-author { display: flex; align-items: center; gap: 12px }
.sidebar-author .avatar { width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0; background: var(--surface-2); border: 1px solid var(--border) }
/* ── 22d. Hide sidebar TOC on mobile - toc-mobile handles it instead ──── */
@media (max-width: 1023px) { .toc-sidebar { display: none } }
@media (max-width: 1023px) { .article-layout { grid-template-columns: 1fr } .sidebar-sticky { position: static } }
/* Sidebar is a tablet/desktop-only component - on phones the ad + widgets
   would dump into the single-column flow skin-to-skin below the article.
   Remove the whole sidebar on mobile; tablet re-enables it below. */
@media (max-width: 767px) { .sidebar-sticky { display: none } }
/* ── 22e. Tablet: keep sidebar visible ─────────────────────────────── */
@media (min-width: 768px) and (max-width: 1023px) {
  .article-layout { grid-template-columns: 1fr 280px; gap: var(--sp-8) }
  .sidebar-sticky { position: -webkit-sticky; position: sticky; top: 100px }
  .toc-sidebar { display: block }
}

/* ── 22f. Article elevation - v1.18.50 (King: "single blog posts, where SEO lands") ────  Premium craft on the first-impression article elements. Terminal-dark, Premium craft on the first-impression article elements. Terminal-dark, straight/clean, mobile + tablet first-class. Accent glows only - no straight/clean, mobile + tablet first-class. Accent glows only - no structural green divider lines (header/footer reverts stand). */
.article-cover { box-shadow: var(--shadow-lg), 0 0 24px rgba(0, 255, 145, .10) }
/* ── 22g. H1 gets a short, straight green rule beneath it - a premium article accent. ──── */
.article-header h1 { position: relative; padding-bottom: 18px }
.article-header h1::after { content: ''; position: absolute; left: 0; bottom: 0; width: 56px; height: 3px; border-radius: var(--r-pill); background: var(--green); box-shadow: 0 0 12px var(--green-glow) }
/* ── 22h. Author avatar in the meta - green ring + faint halo. ───── */
.article-meta .avatar { border-color: var(--green-border); box-shadow: 0 0 0 3px var(--green-dim) }
/* Section headings inside the reading body - green left-rail so the post
   reads as a deliberate, structured document (matches the homepage sec-head). */
.prose h2 { position: relative; padding-left: 18px }
.prose h2::before { content: ''; position: absolute; left: 0; top: .18em; bottom: .18em; width: 3px; border-radius: var(--r-pill); background: var(--green); box-shadow: 0 0 10px var(--green-glow); opacity: .85 }
/* Accordion headings are interactive toggles INSIDE a card - never draw the
   section left-rail or left padding on them (would read as stray side
   borders). They keep their own green mono toggle styling below. */
.prose .wp-block-accordion h2,
.prose .wp-block-accordion-heading { padding-left: 0 }
.prose .wp-block-accordion h2::before,
.prose .wp-block-accordion-heading::before { content: none; display: none }
/* ── 22i. Share buttons - green glow-ring on hover/focus (consistent with header/footer). ──── */
.share-row .btn { transition: border-color .15s, color .15s, background .15s, box-shadow .2s }
.share-row .btn:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; border-color: var(--green-border); color: var(--green) }
@media (hover: hover) { .share-row .btn:hover { border-color: var(--green-border); color: var(--green); box-shadow: var(--ring-green) } }
/* ── 22j. Post-nav - green focus ring for keyboard. ──────────────── */
.post-nav a:focus-visible { outline: 2px solid var(--green); outline-offset: 2px; border-color: var(--green-border) }

/* ==========================================================================
   23. SHARE ROW
   ========================================================================== */
.share-row { display: flex; gap: 10px; padding: var(--sp-6) 0; border-top: 1px solid var(--border); margin: var(--sp-8) 0; flex-wrap: wrap; align-items: center }
.share-label { font-size: 11px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--dim); font-family: var(--font-mono); white-space: nowrap }
.share-buttons { display: flex; gap: 8px; flex-wrap: wrap }
.share-row .btn { flex-shrink: 0 }
.share-row .btn svg { vertical-align: middle; margin-right: 4px; flex-shrink: 0 }

/* ==========================================================================
   24. AUTHOR BOX (premium - avatar, role, bio, follow links, terminal card)
   ========================================================================== */
/* ── Author box - v1.18.55 (King: "upgrade as you see fit, must look like the
   brand") ── Terminal "whoami" profile card. Forced-dark, straight/clean,
   premium through craft. Green is accent only (no gradients - King removed
   the top gradient bar); straight green rails match the article h2 rails. */
.author-box {
  display: flex;
  gap: var(--sp-6);
  background:
    repeating-linear-gradient(0deg, transparent, transparent 23px, rgba(255,255,255,.012) 24px),
    var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: var(--sp-6);
  margin: var(--sp-8) 0;
  align-items: flex-start;
  box-shadow: var(--shadow-sm);
  position: relative;
  overflow: hidden;
  transition: border-color .2s var(--ease-quick), box-shadow .2s var(--ease-quick), transform .2s var(--ease-quick);
}
@media (hover: hover) {
  .author-box:hover {
    border-color: var(--green-border);
    box-shadow: var(--shadow-sm), var(--shadow-glow);
    transform: translateY(-2px);
  }
}
.author-box__head {
  position: absolute;
  top: 0; left: 0; right: 0;
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 12px var(--sp-6);
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 600;
  color: var(--green);
  /* v1.18.89 (King: "add back that green underline under the >_whoami") - the
     green divider ruling was global; this one element gets an explicit
     exception. Green rail = emphasis on ONE element, not a separator. */
  border-bottom: 1px solid var(--green-border);
}
.author-box__head .author-box__prompt { color: var(--green); text-shadow: 0 0 8px rgba(0, 255, 145, .4) }
.author-box__head .author-box__cmd { letter-spacing: .04em; color: var(--text); opacity: .9 }
.author-box__avatar { flex-shrink: 0; margin-top: 44px }
.author-box__avatar img {
  width: 76px;
  height: 76px;
  border-radius: var(--r);
  object-fit: cover;
  border: 2px solid var(--green-border);
  box-shadow: 0 0 0 3px var(--green-dim), var(--shadow-sm);
  position: relative;
}
.author-box__info { flex: 1; min-width: 0; margin-top: 44px }
.author-box__label {
  font-size: 10px;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--dim2);
  font-family: var(--font-mono);
  margin-bottom: 6px;
}
.author-box__name {
  font-size: 21px;
  font-weight: 800;
  margin-bottom: 4px;
  letter-spacing: -.01em;
}
.author-box__name::before { content: '~/'; color: var(--green); font-family: var(--font-mono); font-weight: 600; opacity: .8 }
.author-box__role {
  font-size: 12px;
  font-weight: 600;
  color: var(--green);
  font-family: var(--font-mono);
  margin-bottom: 10px;
}
.author-box__bio { font-size: 14px; color: var(--mid); line-height: 1.8; margin-bottom: 14px }
.author-box__link {
  font-size: 13px;
  color: var(--green);
  font-weight: 600;
  font-family: var(--font-mono);
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 8px 14px;
  border: 1px solid var(--green-border);
  border-radius: var(--r-pill);
  background: var(--green-dim);
  transition: border-color .15s, background .15s, transform .12s var(--ease-quick), box-shadow .2s;
}
.author-box__link::before { content: '→ '; font-weight: 700 }
@media (hover: hover) {
  .author-box__link:hover {
    color: var(--green-hover);
    background: rgba(0, 255, 145, .10);
    border-color: var(--green);
    transform: translateY(-1px);
    box-shadow: var(--shadow-glow);
  }
}
.author-box__socials { display: flex; gap: 8px; margin-top: 16px; flex-wrap: wrap }
.author-box__social-link {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 42px;
  height: 42px;
  border-radius: var(--r);
  border: 1px solid var(--border);
  color: var(--mid);
  background: var(--surface-2);
  transition: border-color .15s, color .15s, background .15s, transform .12s var(--ease-quick), box-shadow .2s;
}
@media (hover: hover) {
  .author-box__social-link:hover {
    border-color: var(--green-border);
    color: var(--green);
    background: var(--green-dim);
    transform: translateY(-1px);
    box-shadow: var(--shadow-glow);
  }
}
.author-box__social-link svg { width: 16px; height: 16px }
@media (max-width: 767px) {
  .author-box { flex-direction: column; align-items: center; text-align: center; gap: var(--sp-5); padding-top: var(--sp-6) }
  .author-box__head { justify-content: center }
  .author-box__avatar { margin-top: 56px }
  .author-box__info { margin-top: 0 }
  .author-box__name::before { content: '' }
  .author-box__socials, .author-box__label { justify-content: center }
}

/* ==========================================================================
   25. POST NAVIGATION
   ========================================================================== */
.post-nav { display: flex; justify-content: space-between; padding: var(--sp-6) 0; margin-top: var(--sp-6); gap: var(--sp-4) }
.post-nav a { font-size: 13px; font-weight: 600; color: var(--mid); flex: 1; display: flex; flex-direction: column; gap: 6px; padding: var(--sp-4); border: 1px solid var(--border); border-radius: var(--r); transition: border-color .2s var(--ease-quick), transform .2s var(--ease-quick), box-shadow .2s var(--ease-quick), background .2s; background: var(--surface); position: relative; overflow: hidden }
.post-nav a::before { content: ''; position: absolute; top: 0; left: 0; width: 100%; height: 2px; background: linear-gradient(90deg, var(--green), transparent 75%); opacity: 0; transition: opacity .2s var(--ease-quick); pointer-events: none }
@media (hover: hover) { .post-nav a:hover::before { opacity: .7 } }
@media (hover: hover) { .post-nav a:hover { border-color: var(--green-border); transform: translateY(-1px); box-shadow: var(--shadow-sm); background: var(--surface-2) } }
.post-nav-next { text-align: right; align-items: flex-end }
.post-nav-prev { align-items: flex-start }
.post-nav-label { font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--dim2); font-family: var(--font-mono); transition: color .15s }
@media (hover: hover) { .post-nav a:hover .post-nav-label { color: var(--green); text-shadow: 0 0 8px rgba(0, 255, 145, 0.4) } }
.post-nav-title { font-size: 14px; color: var(--text); line-height: 1.4; transition: color .15s }
@media (hover: hover) { .post-nav a:hover .post-nav-title { color: var(--green); text-shadow: 0 0 10px rgba(0, 255, 145, 0.5) } }
.post-nav .badge { align-self: flex-start }
.post-nav-next .badge { align-self: flex-end }

/* ==========================================================================
   26. RELATED POSTS (premium 3-card grid - card system)
   ========================================================================== */
.related-posts { padding: var(--sp-8) 0; border-top: 1px solid var(--border); margin-top: var(--sp-8) }
.related-posts__heading {
  font-size: 14px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--dim);
  margin-bottom: var(--sp-6);
  font-family: var(--font-mono);
  display: flex;
  align-items: center;
  gap: 8px;
}
.related-posts__prompt { color: var(--green); text-shadow: 0 0 8px rgba(0, 255, 145, .4) }
.related-posts__grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: var(--sp-5) }
.related-posts__card {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  overflow: hidden;
  transition: border-color .2s var(--ease-quick), transform .2s var(--ease-quick), box-shadow .2s var(--ease-quick);
  min-width: 0;
  position: relative; /* anchor for the stretched title-link overlay */
}
@media (hover: hover) {
  .related-posts__card:hover { border-color: var(--green-border); transform: translateY(-2px); box-shadow: var(--shadow-md), var(--shadow-glow) }
}
.related-posts__thumb {
  aspect-ratio: 16/9;
  overflow: hidden;
  background: linear-gradient(160deg, #0a1f22, var(--surface) 75%);
  display: flex;
  align-items: center;
  justify-content: center;
  position: relative;
}
.related-posts__thumb.cat-tint { background: linear-gradient(160deg, var(--c-grad, rgba(0, 255, 145, .16)), var(--surface) 75%) }
.related-posts__thumb img { width: 100%; height: 100%; object-fit: cover; transition: transform .3s var(--ease-out) }
.related-posts__card:hover .related-posts__thumb img { transform: scale(1.04) }
.related-posts__body { padding: var(--sp-4); min-width: 0 }
.related-posts__body .badge { margin-bottom: 10px }
.related-posts__title { font-size: 14px; font-weight: 700; line-height: 1.4; margin: 0 0 8px; overflow-wrap: break-word }
/* Whole-card click target (same stretched-link pattern as .card h3 a::after):
   the title link's ::after covers the entire card, so clicking anywhere on
   the card (thumb, body, meta) navigates to the post - while the category
   badge stays independently clickable above it (base .badge z-index: 2). */
.related-posts__title a { color: inherit; text-decoration: none }
.related-posts__title a::after { content: ''; position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; z-index: 1 }
.related-posts__title a:focus-visible::after { outline: 2px solid var(--green); outline-offset: -4px; border-radius: var(--r) }
.related-posts__meta {
  display: flex;
  align-items: center;
  gap: 8px;
  font-size: 11px;
  color: var(--mid);
  font-family: var(--font-mono);
}
.related-posts__link { color: inherit; text-decoration: none; display: block }
.related-posts__card:hover .related-posts__title a { color: var(--green) }
@media (max-width: 1023px) { .related-posts__grid { grid-template-columns: repeat(2, 1fr) } }
@media (max-width: 767px) { .related-posts__grid { grid-template-columns: 1fr } }

/* ==========================================================================
   27. COMMENTS
   ========================================================================== */
.comments-area { padding: var(--sp-8) 0; border-top: 1px solid var(--border); margin-top: var(--sp-8) }
.comments-title { font-size: 14px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--dim); margin-bottom: var(--sp-6); font-family: var(--font-mono) }
.comment-list { list-style: none; margin-bottom: var(--sp-8) }
.comment-list .children { list-style: none; margin-left: var(--sp-8); border-left: 1px solid var(--border); padding-left: var(--sp-5) }
.comment { padding: var(--sp-5) 0; border-bottom: 1px solid var(--border) }
.comment:last-child { border-bottom: none }
.comment-body { display: flex; gap: 14px }
.comment-meta { display: flex; align-items: center; gap: 10px; font-size: 13px; color: var(--mid); margin-bottom: 8px; flex-wrap: wrap }
.comment-meta .fn { font-weight: 600; color: var(--text); font-style: normal }
.comment-meta a { color: var(--mid) }
.comment-meta a:hover { color: var(--green) }
.comment-content { font-size: 15px; line-height: 1.7; color: var(--text) }
.comment-content p { margin-bottom: 10px }
.reply { font-size: 12px }
.reply a { color: var(--green); font-weight: 600 }
.reply a:hover { text-decoration: underline }
.comment-respond { background: var(--surface); border: 1px solid var(--border); border-radius: var(--r); padding: var(--sp-6); box-shadow: var(--shadow-xs) }
.comment-reply-title { font-size: 14px; font-weight: 700; margin-bottom: var(--sp-5); font-family: var(--font-mono) }
.comment-reply-title small { font-weight: 400; margin-left: 8px; font-family: var(--font-body) }
.comment-reply-title small a { color: var(--green); font-size: 12px }
.comment-form { display: flex; flex-direction: column; gap: var(--sp-4) }
.comment-form textarea,
.comment-form input[type="text"],
.comment-form input[type="email"],
.comment-form input[type="url"] { width: 100%; background: var(--bg); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 12px 14px; font-size: 16px; color: var(--text); transition: border-color .15s, box-shadow .15s }
.comment-form textarea:focus,
.comment-form input:focus { outline: none; border-color: var(--green); box-shadow: var(--ring-green) }
.comment-form .form-submit { margin-top: var(--sp-2) }
.comment-form .form-submit input[type="submit"] { font-family: var(--font-mono); font-size: 13px; font-weight: 700; padding: 12px 22px; border-radius: var(--r-sm); border: none; background: var(--green); color: var(--on-green); cursor: pointer; transition: background .15s }
.comment-form .form-submit input[type="submit"]:hover { background: var(--green-hover) }
.comment-notes { font-size: 13px; color: var(--mid) }
.no-comments { text-align: center; padding: var(--sp-8); color: var(--mid); font-size: 14px }
.comment-form-cookies-consent { display: flex; align-items: center; gap: 8px; font-size: 13px; color: var(--mid) }
.comment-form-cookies-consent input[type="checkbox"] { accent-color: var(--green); width: 16px; height: 16px }
/* ── Vibe comments toolbar - mobile touch-up (v1.19.07, King: "this part in */
   the comments still needs some touch especially on mobile") ──────────────
   The plugin renders sort button + search + "N found" on one row; on phones
   the nowrap count clips at the viewport edge. Theme law: build in the
   theme, never the plugin - these overrides re-flow it:
   ≤640px the count drops to its own full-width line under the field
   (right-aligned, where it used to sit); controls get 44px touch height. */
/* v1.19.08 (King: "before and after typing something still bad especially on
   mobile"): full theme-token restyle of both states - idle is QUIET (1px
   neutral border on surface); focus wears the site-standard SINGLE ring
   (green border + 3px dim-green glow), replacing the plugin's heavy double
   ring; geometry matched (44px, --r-sm, 15px) across sort + search. */
.vibe-comments-toolbar .vibe-sort-icon-btn,
.vibe-comments-toolbar .vibe-search-input {
  height: 44px;
  border: 1px solid var(--border);
  border-radius: var(--r-sm);
  background: var(--surface);
  color: var(--text);
  /* Responsive Audit #6 (v1.21.32): 16px floor - iOS Safari zooms the
     viewport on focus when an input computes under 16px. Was 15px. */
  font-size: 16px;
}
.vibe-comments-toolbar .vibe-search-input::placeholder { color: var(--dim) }
.vibe-comments-toolbar .vibe-search-input:focus {
  outline: none;
  border-color: var(--green);
  box-shadow: var(--ring-green);
}
.vibe-comments-toolbar .vibe-sort-icon-btn:hover,
.vibe-comments-toolbar .vibe-sort-icon-btn:active { border-color: var(--green); color: var(--green) }
.vibe-comments-toolbar { gap: 10px }
@media (max-width: 640px) {
  .vibe-comments-toolbar { align-items: flex-start }
  .vibe-search-wrap { flex-wrap: wrap; row-gap: 6px }
  .vibe-search-status { flex-basis: 100%; text-align: right }
}

/* ==========================================================================
   28. CONTACT FORM (gwill-form)
   ========================================================================== */
.gwill-form { display: flex; flex-direction: column; gap: var(--sp-4) }
.gwill-form__field { display: flex; flex-direction: column; gap: 6px }
.gwill-form__field label { font-size: 13px; font-weight: 600; color: var(--text) }
.gwill-form__required { color: var(--green) }
.gwill-form__field input,
.gwill-form__field textarea,
.gwill-form__field select { width: 100%; background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm); padding: 12px 14px; font-size: 16px; color: var(--text); transition: border-color .15s, box-shadow .15s; font-family: var(--font-body) }
.gwill-form__field input:focus,
.gwill-form__field textarea:focus,
.gwill-form__field select:focus { outline: none; border-color: var(--green); box-shadow: var(--ring-green) }
.gwill-form__field textarea { resize: vertical; min-height: 120px }
.gwill-form__field select { cursor: pointer; appearance: auto }
.gwill-form__row--2col { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-4) }
.gwill-form__actions { margin-top: var(--sp-2) }
.gwill-form__submit { font-family: var(--font-mono); font-size: 13px; font-weight: 700; padding: 12px 22px; border-radius: var(--r-sm); border: none; background: var(--green); color: var(--on-green); cursor: pointer; transition: background .15s, opacity .15s; width: auto; display: inline-flex; align-items: center; gap: 10px }
.gwill-form__submit:hover { background: var(--green-hover) }
.gwill-form__submit:disabled { cursor: default }
.gwill-form__submit.is-sending { opacity: .85 }
.gwill-form__submit-loading { display: none; align-items: center; gap: 10px }
.gwill-form__submit-loading::before { content: ''; width: 14px; height: 14px; flex-shrink: 0; border: 2px solid rgba(8,22,15,.3); border-top-color: var(--on-green); border-radius: 50%; animation: gwill-form-spin .6s linear infinite }
.gwill-form__submit.is-sending .gwill-form__submit-text { display: none }
.gwill-form__submit.is-sending .gwill-form__submit-loading { display: inline-flex }
@keyframes gwill-form-spin { to { transform: rotate(360deg) } }
.gwill-form__success-msg { display: flex; align-items: flex-start; gap: 12px; background: var(--green-dim); border: 1px solid var(--green-border); border-radius: var(--r); padding: 20px 24px; color: var(--text); font-size: 15px; line-height: 1.6 }
.gwill-form__success-msg::before { content: '>_'; flex-shrink: 0; font-family: var(--font-mono); font-weight: 700; color: var(--green); text-shadow: 0 0 12px rgba(0,255,145,.5), 0 0 32px rgba(0,255,145,.2) }
.gwill-form__status { font-size: 14px; padding: 10px 14px; border-radius: var(--r-sm); display: none }
.gwill-form__status.is-visible { display: block }
.gwill-form__status.is-error { background: rgba(255,69,69,.1); border: 1px solid rgba(255,69,69,.3); color: var(--gwill-red) }
.gwill-form__status.is-success { background: var(--green-dim); border: 1px solid var(--green-border); color: var(--green) }
.gwill-honey { position: absolute; left: -9999px; opacity: 0; height: 0; overflow: hidden }
.gwill-form--routed .gwill-form__field:first-child { margin-bottom: var(--sp-2) }

/* ── 28a. Contact page layout ──────────────────────────────────────── */
.contact-card p strong { color: var(--text); font-weight: 700 }
.contact-card ul a { color: var(--text); text-decoration: underline; text-decoration-color: var(--border); text-underline-offset: 3px }
.disclaimer-content p strong, .privacy-content p strong { color: var(--text); font-weight: 700 }

/* ═══════════════════════════════════════════════════════════
   29. LEGAL PAGES - card-grouped layout with sidebar ToC
   ═══════════════════════════════════════════════════════════ */
.legal-hero { padding-bottom: var(--sp-8) }
.legal-section-title {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 15px;
  font-weight: 700;
  font-family: var(--font-mono);
  color: var(--green);
  margin: 0 0 var(--sp-3);
  letter-spacing: -.01em;
}
.legal-num {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 28px;
  height: 28px;
  border-radius: 6px;
  background: var(--green-dim);
  color: var(--green);
  font-size: 11px;
  font-weight: 800;
  flex-shrink: 0;
}
.legal-section-body {
  color: var(--mid);
  line-height: 1.85;
  font-size: 15px;
}
.legal-section-body a {
  color: var(--green);
  text-decoration: underline;
  text-decoration-color: var(--green-border);
  text-underline-offset: 3px;
  transition: color .15s;
}
.legal-section-body a:hover { color: var(--green-hover) }
/* ── 29a. Sidebar sticky ToC card ──────────────────────────────────── */
.legal-sidebar { position: -webkit-sticky; position: sticky; top: calc(70px + var(--sp-8)) }
.legal-card {
  background: var(--surface-2);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: var(--sp-5);
}
.legal-toc-heading {
  font-family: var(--font-mono);
  font-size: 11px;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--dim);
  margin: 0 0 12px;
}
.legal-toc {
  list-style: none;
  padding: 0;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  line-height: 2;
}
.legal-toc li a {
  color: var(--mid);
  text-decoration: none;
  display: block;
  padding: 4px 0;
  transition: color .15s, padding-left .15s;
}
.legal-toc-num { color: var(--green); margin-right: 6px }
.legal-sidebar .legal-card a:hover {
  color: var(--green) !important;
  padding-left: 6px;
}
/* ── 29b. Content section cards (shared by privacy + disclaimer) ───── */
.section-card,
.legal-group {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r);
  padding: var(--sp-6);
}
.section-card { margin-bottom: var(--sp-6) }
.section-card + .section-card { margin-top: 0 }
.legal-group .legal-section + .legal-section,
.section-card .legal-section + .legal-section {
  margin-top: var(--sp-8);
  padding-top: var(--sp-6);
  border-top: 1px solid var(--border);
}
/* ── 29c. Legal hero → TOC breathing room ──────────────────────────── */
.legal-page .about-hero { margin-bottom: var(--sp-4) }
.legal-grid { margin-top: var(--sp-8) }
/* v1.19.10 → CORRECTED v1.19.11 (King: "the TOC is not sticky anymore, you
   killed the sticky thing"): v1.19.10's align-items:stretch stretched the
   STICKY SIDEBAR ITSELF to full column height - a sticky element as tall as
   its travel room cannot travel. The repair: the sidebar keeps its NATURAL
   height (align-items:start restored for it) and only the CONTENT column
   stretches (align-self:stretch). The content card still fills its column
   via flex:1, so bottoms stay locked - and the TOC sticks and travels again. */
@media (min-width: 768px) {
  .legal-grid { align-items: start !important }
  .legal-content-main { align-self: stretch !important; display: flex; flex-direction: column }
  .legal-content-main .legal-group { flex: 1 }
}
/* v1.19.11 (King: "Even single Posts have this alignment issue, fix don't
   ruin my code"): the SAME safe pattern on .article-layout - the ARTICLE
   column stretches to the row height while .sidebar-sticky keeps its natural
   height (align-items:start preserved), so the sticky TOC still sticks and
   travels. The in-article newsletter band grows to fill the column tail
   (flex:1) and its bottom margin retires so its edge lands exactly on the
   column bottom - flush with the sidebar's last card. ≥1024px only (the
   2-column desktop layout); collapsed layouts untouched. */
@media (min-width: 1024px) {
  .article-layout > article { align-self: stretch; display: flex; flex-direction: column }
  .article-layout article .nl-band--article { flex: 1; margin-bottom: 0 }
}
/* Mobile: single column, sidebar becomes inline accordion.
   v1.19.09 (King: "space between the TOC and first content on legal pages
   is too [much], make it uniform"): the inline grid gap (--sp-10, a desktop
   COLUMN gap) becomes the ROW gap when stacked and the sidebar margin stacked
   on top → ~72px dead air. Uniform 24px rhythm now: gap 24px, sidebar margin
   retired (the grid gap alone separates the rows). */
@media (max-width: 767px) {
  .legal-grid { grid-template-columns: 1fr !important; margin-top: var(--sp-8); gap: var(--sp-6) !important }
  .legal-sidebar { position: static !important; margin-bottom: 0 }
  .legal-sidebar .legal-card { padding: var(--sp-4) }
  .legal-sidebar ol { display: flex; flex-wrap: wrap; gap: 6px }
  .legal-sidebar ol li { display: inline }
  .legal-sidebar ol li a { padding: 4px 8px !important; border-radius: var(--r-sm); font-size: 11px }
}

@media (max-width: 1023px) {
  .contact-layout { grid-template-columns: 1fr !important }
  .contact-form-col { order: 1 }
  .contact-info-col { order: 2 }
}
@media (max-width: 767px) {
  .gwill-form__row--2col { grid-template-columns: 1fr }
  /* Submit buttons ≥16px on mobile - iOS Safari auto-zooms focused controls
     smaller than 16px; also improves the tap target. Desktop keeps the
     compact mono 13px terminal aesthetic. */
  .comment-form .form-submit input[type="submit"],
  .gwill-form__submit,
  .vibe-btn-load-comments { font-size: 16px }
}

/* ==========================================================================
   30. VIBE COMMENTS - theme-level overrides
   ========================================================================== */
.vibe-comments-section { padding-top: var(--sp-6) }
.vibe-comments-title { font-family: var(--font-mono); font-size: 14px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em; color: var(--dim); border-bottom-color: var(--border); margin-bottom: var(--sp-6) }
#vibe-comments-trigger { text-align: center; padding: var(--sp-8) 0 }
.vibe-btn-load-comments { font-family: var(--font-mono); font-size: 13px; font-weight: 700; padding: 12px 22px; border-radius: var(--r-sm); background: var(--green); color: var(--on-green); border: 1px solid var(--green); transition: background .15s; cursor: pointer }
.vibe-btn-load-comments:hover { background: var(--green-hover) }

/* ==========================================================================
   31. AD SLOT
   ========================================================================== */
.ad-slot { background: linear-gradient(135deg, var(--surface-2), var(--surface)); border: 1px solid var(--border); border-radius: var(--r); display: flex; align-items: center; justify-content: center; color: var(--dim2); font-size: 11px; text-transform: uppercase; letter-spacing: .08em; min-height: 90px; position: relative; overflow: hidden }
.ad-slot::before { content: 'Advertisement'; position: absolute; top: 8px; right: 10px; background: none; padding: 0; font-size: 9px; color: var(--dim2); text-transform: uppercase; letter-spacing: .06em; z-index: 3 }
.ad-slot--filled::before { display: none }
.ad-slot--leaderboard { width: 100%; max-width: var(--content-w); margin: var(--sp-6) auto; min-height: 90px }
.ad-slot--before-footer { width: 100%; max-width: var(--content-w); margin: var(--sp-6) auto; min-height: 90px }
.ad-slot--content, .ad-slot--in-content { width: 100%; max-width: var(--content-w); margin: var(--sp-6) auto var(--sp-8); min-height: 100px }
.ad-slot--sidebar { min-height: 250px; max-width: 300px; width: 100%; margin-bottom: var(--sp-5) }
/* Sidebar slot sizing is content-driven when filled: the relative-position
   content lets the box grow to fit whatever ad fills it (300×250 now,
   300×600 half-page later) with zero dead space. */

/* Ad loading spinner - shows until the pasted ad code fills the slot.
   Also the honest state for adblock users: the network script never runs,
   the container never fills, and the spinner keeps spinning. */
.ad-slot__spinner {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  inset: 0;
  color: var(--green);
  opacity: .55;
  pointer-events: none;
}
.ad-slot__spinner-text {
  font-size: 9px;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--dim2);
}
.ad-spinner { animation: gwill-spin 1s linear infinite }

/* ── 31a. Filled slots: drop the spinner entirely (the ad covers it) ──── */
.ad-slot--filled .ad-slot__spinner { display: none }

/* Banner ads (image/iframe code pasted from Customizer) - centered,
   contained, never blow out the slot or the layout. */
.gwill-ad-banner,
.ad-slot__content > * {
  display: flex;
  align-items: center;
  justify-content: center;
  max-width: 100%;
}
.ad-slot__content img {
  display: block;
  max-width: 100%;
  height: auto;
  border-radius: var(--r-sm);
  box-shadow: 0 2px 12px rgba(0, 0, 0, .25);
}
.ad-slot--leaderboard .ad-slot__content img,
.ad-slot--before-footer .ad-slot__content img { max-height: 90px; width: auto }
.ad-slot--content .ad-slot__content img,
.ad-slot--in-content .ad-slot__content img { max-height: 280px; width: auto }
.ad-slot--sidebar .ad-slot__content img { max-height: 250px; width: auto }
.ad-slot--sticky .ad-slot__content img,
.ad-slot--menu .ad-slot__content img { max-height: 100px; width: auto }
@keyframes gwill-spin { to { transform: rotate(360deg) } }
.ad-slot__content {
  position: absolute;
  top: 0; right: 0; bottom: 0; left: 0;
  inset: 0;
  z-index: 2;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
/* Filled slots: take the content out of absolute positioning so the
   slot sizes to the actual ad - no clipping, no collapsed boxes. Each
   placement gets an EXACT height matching its img max-height cap below,
   so the slot can never grow after paint. (min-height is not enough:
   the capped image + 6px padding still overflowed it and re-triggered
   the shift - exact height + zero padding on the filled content box is
   the guarantee. CLS measured 0.109 → 0.00, v1.16.42.) */
.ad-slot--filled .ad-slot__content {
  position: relative;
  top: auto; right: auto; bottom: auto; left: auto;
  inset: auto;
  padding: 0;
  /* v1.17.09: gentle fade-in when the ad fills (replaces the hard pop).
     prefers-reduced-motion zeros the duration globally. */
  animation: ad-fade .22s var(--ease-out) both;
}
@keyframes ad-fade { from { opacity: 0 } to { opacity: 1 } }
.ad-slot--filled { height: 90px }
.ad-slot--filled.ad-slot--leaderboard,
.ad-slot--filled.ad-slot--before-footer { height: 90px }
.ad-slot--filled.ad-slot--content,
.ad-slot--filled.ad-slot--in-content { height: 280px }
.ad-slot--filled.ad-slot--sidebar { height: 250px }
.ad-slot--filled.ad-slot--sticky,
.ad-slot--filled.ad-slot--menu { height: 100px }
.ad-slot__content > * { max-width: 100%; max-height: 100% }
.ad-slot__content iframe, .ad-slot__content ins { display: block; margin: 0 auto }

/* ── 31b. Sticky footer ad (all devices; dismissible on phones only) ──── */
.ad-sticky {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 12px; /* tablet + desktop: no tab bar to clear */
  z-index: 350; /* above tab bar (200), below cookie (400) + mob nav (500) */
  display: none; /* JS reveals via body.ad-sticky-visible (waits for consent) */
  justify-content: center;
  padding: 0 12px;
  pointer-events: none; /* let clicks pass through the empty bar area */
}
.ad-sticky-inner {
  position: relative;
  width: 100%;
  max-width: 728px;
  pointer-events: auto;
}
.ad-sticky-media--mobile { display: block }
.ad-sticky-media--desktop { display: none }
.ad-sticky .ad-slot--sticky {
  margin: 0 auto;
  max-width: 320px;
  min-height: 50px;
  aspect-ratio: 320/100; /* 320×100 Large Mobile Banner - bigger, earns more
                            than the 320×50 (AdSense best mobile anchor size) */
  width: 100%;
  box-shadow: 0 8px 32px rgba(0, 0, 0, .55);
  border-color: rgba(0, 255, 145, .18);
}
.ad-sticky .ad-slot--leaderboard {
  margin: 0;
  min-height: 90px;
  aspect-ratio: 728/90;
  width: 100%;
  box-shadow: 0 8px 32px rgba(0, 0, 0, .55);
  border-color: rgba(0, 255, 145, .18);
}
.ad-sticky .ad-slot::before { display: none } /* label too cramped on sticky bars */
.ad-sticky .ad-slot__spinner { gap: 4px }
.ad-sticky .ad-spinner { width: 18px; height: 18px }
.ad-sticky .ad-slot__spinner-text { display: none }
.ad-sticky-x {
  position: absolute;
  top: 50%;
  right: -14px; /* half-outside the ad's right edge - always visible */
  transform: translateY(-50%);
  z-index: 2; /* paint above the .ad-slot surface (later in DOM, position:relative) */
  width: 44px;
  height: 44px;
  border-radius: 50%;
  border: 1px solid var(--border);
  background: var(--surface-2);
  color: var(--mid);
  display: flex;
  align-items: center;
  justify-content: center;
  pointer-events: auto;
  box-shadow: 0 0 0 3px rgba(13, 13, 13, .9), 0 2px 8px rgba(0, 0, 0, .5);
  transition: color .15s, border-color .15s, box-shadow .15s;
}
@media (hover: hover) { .ad-sticky-x:hover { color: var(--green); border-color: var(--green); box-shadow: 0 0 10px rgba(0, 255, 145, .3) } }
/* ── 31c. Dismissible on ALL devices - phone, small tablet, tablet, PC. ──── */
/* ── 31d. Phone + small tablet (≤767px): 320×50 above the bottom tab bar ──── */
@media (max-width: 767px) {
  body.ad-sticky-visible .ad-sticky { display: flex }
  .ad-sticky { bottom: calc(var(--btm-tab-h) + 8px) }
  .ad-sticky-media--desktop { display: none }
  .ad-sticky-media--mobile { display: block }
  body.ad-sticky-visible .site-footer { padding-bottom: calc(var(--btm-tab-h) + 88px) }
}
/* ── 31e. Tablet + desktop (≥768px): 728×90 leaderboard at the viewport bottom ──── */
@media (min-width: 768px) {
  body.ad-sticky-visible .ad-sticky { display: flex }
  .ad-sticky-media--mobile { display: none }
  .ad-sticky-media--desktop { display: block }
  body.ad-sticky-visible .site-footer { padding-bottom: 130px }
}

/* ==========================================================================
   32. FILTER BAR (Home/Archive)
   ========================================================================== */
.filter-bar { display: flex; gap: 10px; flex-wrap: wrap; padding: var(--sp-6) 0; margin-bottom: var(--sp-8) }
@media (max-width: 767px) { .filter-bar { overflow-x: auto; flex-wrap: nowrap; padding-bottom: 10px } .filter-bar::-webkit-scrollbar { display: none } }

/*** ==========================================================================
   PAGINATION (Dark theme)
   ========================================================================== */
.pagination { margin: var(--sp-8) 0 0; display: flex; justify-content: center; gap: 8px }
.pagination .page-numbers { display: inline-flex; align-items: center; justify-content: center; min-width: 44px; height: 44px; padding: 0 12px; font-size: 13px; font-weight: 600; color: var(--mid); background: var(--surface); border: 1px solid var(--border); border-radius: var(--r-sm); transition: all .15s; font-family: var(--font-mono); text-decoration: none; flex-shrink: 0 }
@media (hover: hover) { .pagination .page-numbers:hover { border-color: var(--green-border); color: var(--green) } }
.pagination .page-numbers.current { background: var(--green-dim); border-color: var(--green-border); color: var(--green) }
.pagination .page-numbers.dots { border: none; background: none; color: var(--dim2); min-width: auto; padding: 0 2px }

/* Long pagination stays on ONE row everywhere - never wraps into a messy
   multi-row blob. Desktop/tablet: centered, and over-long lists scroll
   horizontally with an edge fade + snap. Mobile: same, tighter touch targets. */
.pagination { flex-wrap: nowrap; max-width: 100%; overflow-x: auto; scroll-snap-type: x proximity; -webkit-overflow-scrolling: touch; scrollbar-width: none; padding: 2px }
.pagination::-webkit-scrollbar { display: none }
.pagination .page-numbers { scroll-snap-align: center }

@media (max-width: 767px) {
  .pagination { justify-content: flex-start; gap: 8px }
  .pagination .page-numbers { min-width: 44px; height: 44px; font-size: 12px }
}

/* ==========================================================================
   33. EMPTY STATE / 404
   ========================================================================== */
.empty-state { text-align: center; padding: var(--sp-32) 0 }
.empty-state .icon-wrap { width: 64px; height: 64px; border-radius: 50%; background: var(--surface); border: 1px solid var(--border); display: flex; align-items: center; justify-content: center; margin: 0 auto 24px; color: var(--mid) }
.error-code { font-size: 100px; font-size: clamp(70px, 12vw, 130px); font-weight: 800; color: var(--surface-2); line-height: 1; letter-spacing: -.04em }

/* ==========================================================================
   34. REVEAL ANIMATIONS
   ========================================================================== */
@keyframes fadeUp { from { opacity: 0; transform: translateY(14px) } to { opacity: 1; transform: translateY(0) } }
.reveal { animation: fadeUp .5s var(--ease-out) both }
.reveal-d1 { animation-delay: .05s }
.reveal-d2 { animation-delay: .1s }
.reveal-d3 { animation-delay: .15s }
.reveal-d4 { animation-delay: .2s }
.reveal-d5 { animation-delay: .25s }
.reveal-d6 { animation-delay: .3s }

/* ==========================================================================
   35. MOBILE BOTTOM TAB BAR
   ========================================================================== */
.mob-btm { position: fixed; bottom: 0; left: 0; right: 0; z-index: var(--z-btm-tab); background: rgba(13, 13, 13, .98); border-top: 1px solid var(--border); height: var(--btm-tab-h); display: none; transform: translateZ(0) }
.mtb-i { display: flex; align-items: center; justify-content: space-around; height: 100%; max-width: 500px; margin: 0 auto; width: 100% }
.mtb-t { background: transparent; border: none; color: var(--dim); font-size: 11px; font-weight: 600; padding: 6px 10px; border-radius: var(--r-sm); transition: color .15s; display: flex; flex-direction: column; align-items: center; gap: 2px; font-family: var(--font-body) }
.mtb-t .ti { width: 20px; height: 20px; display: block; margin: 0 auto 2px }
.mtb-t.on { color: var(--green) }
/* Footer bell (v1.19.45): push.js toggles is-on/is-blocked on every [data-gwill-bell];
   the footer (.mtb-t) bell has no .icon-btn wrapper, so give it the same state cues. */
.mtb-t.gwill-bell.is-on, .mtb-t[data-gwill-bell].is-on { color: var(--green) }
.mtb-t.gwill-bell:not(.is-on):not(.is-blocked), .mtb-t[data-gwill-bell]:not(.is-on):not(.is-blocked) { color: var(--green-dim, #7fbf7f); }
.mtb-t.gwill-bell.is-blocked, .mtb-t[data-gwill-bell].is-blocked { opacity: .45 }
.mtb-t.gwill-bell.is-on .ti, .mtb-t[data-gwill-bell].is-on .ti { animation: gwill-bell-ring .5s ease }
#vp { max-width: 100vw; min-height: 100vh; min-height: 100dvh }
@media (max-width: 767px) { .mob-btm { display: block } #vp { padding-bottom: 56px } }
@media (min-width: 768px) { .mob-btm { display: none !important } }

/* ── 35a. Tablet-specific padding optimizations ────────────────────── */
@media (min-width: 768px) and (max-width: 1023px) {
  .page-hero { padding: var(--sp-6) 0 0 }
  .section { padding: var(--sp-16) 0 }
  .section-sm { padding: var(--sp-10) 0 }
  .grid-3 { gap: var(--sp-4) }
  .grid-2 { gap: var(--sp-4) }
  .about-stats { gap: var(--sp-3) }
  .about-stat strong { font-size: 22px }
  .related-posts__grid { gap: var(--sp-4) }
  .footer-grid { gap: var(--sp-8) }
  .footer-bottom { padding: 16px var(--sp-4) }
}

/* ==========================================================================
   36. MOBILE NAV OVERLAY
   ========================================================================== */
.mno { position: fixed; top: 0; right: 0; bottom: 0; left: 0; inset: 0; z-index: var(--z-mob-nav); background: rgba(5, 5, 5, .98); -webkit-backdrop-filter: blur(16px); backdrop-filter: blur(16px); display: flex; flex-direction: column; transform: translateX(100%); transition: transform .3s var(--ease-out); overflow-y: auto; scrollbar-width: thin; scrollbar-color: var(--green-border) var(--surface); -ms-overflow-style: auto }
.mno::-webkit-scrollbar { width: 6px }
.mno::-webkit-scrollbar-track { background: var(--surface); border-radius: 3px }
.mno::-webkit-scrollbar-thumb { background: var(--green-border); border-radius: 3px }
/* Overlay-style scrollbar: visible when the menu opens AND while scrolling,
   fades out ~700ms after the scroll gesture ends. Any new scroll brings it
   back. JS toggles .mno--idle (hide) on a scroll-end debounce. */
.mno--idle { scrollbar-width: none; -ms-overflow-style: none }
.mno--idle::-webkit-scrollbar { display: none; width: 0; height: 0 }
.mno.open { transform: translateX(0) }
.mno-top { display: flex; justify-content: space-between; align-items: center; padding: var(--sp-4) var(--sp-8); border-bottom: 1px solid var(--border); height: 56px; flex-shrink: 0 }
/* v1.22.9 (King decree): the drawer header's side rails mirror .header-row
   at every breakpoint - the same mirror law the header block follows.
   Same ladder + source-order trick as the header overrides near the top of
   this file: base 32px, ≤1023 20px, ≤767 16px, 600-767 24px, 768-1023 24px.
   Longhand on purpose - ONLY the sides are overridden; the base rule's
   vertical rhythm is untouched. The esc button (.mno-x, margin-left:auto,
   no right margin) rides this right rail - no direct .mno-x edit needed. */
@media (max-width: 1023px) { .mno-top { padding-left: var(--sp-5); padding-right: var(--sp-5) } }
@media (max-width: 767px) { .mno-top { padding-left: var(--sp-4); padding-right: var(--sp-4) } }
@media (min-width: 600px) and (max-width: 767px) { .mno-top { padding-left: var(--sp-6); padding-right: var(--sp-6) } }
@media (min-width: 768px) and (max-width: 1023px) { .mno-top { padding-left: var(--sp-6); padding-right: var(--sp-6) } }
.mno-x { width: 44px; height: 44px; border-radius: var(--r-sm); border: 1px solid var(--border); background: transparent; display: flex; align-items: center; justify-content: center; color: var(--mid); cursor: pointer }
.mno-x:hover { border-color: var(--green-border); color: var(--green) }
.mno-logo { font-size: 15px }
.mno-items { flex: 1; display: flex; flex-direction: column; padding: var(--sp-4); overflow-y: auto; -webkit-overflow-scrolling: touch; gap: 2px }
/* Mobile nav rows - hairline separators so the list reads as distinct rows,
   not a flat wall of text on the near-black overlay. */
.mno-list > li:not(:last-child) { border-bottom: 1px solid var(--border) }
.mni { display: flex; align-items: center; padding: var(--sp-4) var(--sp-5); font-size: 15px; font-weight: 600; color: var(--text); border-radius: var(--r-sm); transition: background .15s, color .15s }
@media (hover: hover) { .mni:hover { background: var(--surface); color: var(--green) } }
.mni.active { color: var(--green); background: var(--green-dim) }
.mno-bot { padding: var(--sp-4) var(--sp-5); border-top: 1px solid var(--border); flex-shrink: 0; display: flex; flex-direction: column; gap: var(--sp-4) }
/* Mobile-menu ad: sized as a compact banner (320×100), with clear breathing
   room so it never joins the nav list above or the Start-here CTA below.
   aspect-ratio fixed = CLS-safe; max-width keeps it from stretching full-bleed. */
.mno-bot .ad-slot--menu { width: 100%; max-width: 320px; margin: 0 auto; aspect-ratio: 320/100; border-radius: var(--r-sm) }
.mno-bot .ad-slot--in-content { margin: 0 0 var(--sp-4); aspect-ratio: auto; max-height: 120px }
.mno-cta { width: 100%; padding: 14px; background: var(--green); color: var(--on-green); border: none; border-radius: var(--r-sm); font-size: 14px; font-weight: 700; font-family: var(--font-mono); display: flex; align-items: center; justify-content: center; gap: 8px; cursor: pointer }
/* ==========================================================================
   37. MOBILE NAV - TERMINAL OS UPGRADE (v1.15.8)
   ========================================================================== */
.mno { background: rgba(4, 6, 5, .985) }

/* ── 37a. CRT scanlines + vignette overlay ───────────────────────── */
.mno::after { content: ""; position: absolute; top: 0; right: 0; bottom: 0; left: 0; inset: 0; z-index: 0; pointer-events: none;
  background: repeating-linear-gradient(0deg, rgba(0, 255, 145, .03) 0 1px, transparent 1px 3px) }
.mno > * { position: relative; z-index: 1 }

/* ── 37b. Terminal title bar ─────────────────────────────────────── */
.mno-top { justify-content: flex-start; gap: 12px; background: rgba(0, 255, 145, .05); border-bottom-color: var(--green-border) }
.mno-x { width: auto; height: 44px; margin-left: auto; padding: 0 14px; gap: 8px; border-color: var(--green-border); background: rgba(0, 255, 145, .05); font-family: var(--font-mono); font-size: 10px; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--mid); transition: border-color .15s, color .15s, background .15s, box-shadow .15s }
.mno-x::before { content: "esc"; color: var(--dim); transition: color .15s }
.mno-x:hover { border-color: var(--green); color: var(--green); background: rgba(0, 255, 145, .1); box-shadow: 0 0 10px rgba(0, 255, 145, .15) }
.mno-x:hover::before { color: var(--green) }
.mno-x:active { transform: translateY(1px) }
.mno-x:focus-visible { outline: 2px solid var(--green); outline-offset: 2px }

/* ── 37c. Menu items = shell command lines ───────────────────────── */
.mno-list > li > a, .mno-list .mno-parent > a, .mno-items > .nav-link { font-family: var(--font-mono); font-size: 15px; font-weight: 700; letter-spacing: -.01em }
.mno-list > li > a::before, .mno-list .mno-parent > a::before, .mno-items > .nav-link::before { content: ">"; color: var(--dim); font-weight: 800;
  margin-right: 10px; width: 20px; text-align: right; flex-shrink: 0; transition: color .15s, text-shadow .15s }
.mno-list > li > a.active::before, .mno-list .mno-parent > a.active::before, .mno-items > .nav-link.active::before { content: ">_"; color: var(--green); text-shadow: 0 0 12px rgba(0, 255, 145, .5), 0 0 32px rgba(0, 255, 145, .2) }
/* v1.18.88 (King: "> arrow STILL dark green on hover" on phone): the dark
   inversion must be hover-capable-only. On touch devices :hover STICKS after a
   tap while the bright/dim bars that justify it are (hover:hover)-gated - the
   near-black arrow sat alone on the dark drawer. Gating it means touch taps
   keep the resting --dim arrow; desktop behaviour is unchanged. */
/* v1.18.99 (comments-hover logic on nav): ALL drawer :hover rules UNGATED.
   The v1.18.88 touch-stick concern is answered by pairing: the bright/dim
   hover bars ship in the SAME release as their arrow inversions - a stuck
   state is always the complete legible terminal look (bright green bar +
   dark var(--on-green) arrow), never a lone dark arrow on a dark drawer. */
.mno-list > li > a:hover::before, .mno-list .mno-parent > a:hover::before, .mno-items > .nav-link:hover::before { color: var(--on-green); text-shadow: none }
/* ── 37d. Parent rows: see v1.19.00 rules below - bright bar + dark > now. ──── */
/* v1.19.00: parent > inverts dark on the bright bar, same as plain rows
   (the old green-glow arrow belonged to the retired dim wash). */
.mno-list li.has-submenu > .mno-parent:hover > a::before { color: var(--on-green); text-shadow: none }
/* ── 37e. Inverted terminal selection on hover ───────────────────── */
.mno-list > li > a:hover, .mno-items > .nav-link:hover { background: var(--green); color: var(--on-green); border-radius: var(--r-sm) }
/* v1.19.00 (King: "you didn't add hover effect to nav menu with sub menu
   and their sub menu"): split-button parents get the SAME unmistakable
   hover as plain links - full bright inverted-terminal bar, not a faint
   dim wash. */
.mno-list li.has-submenu > .mno-parent:hover { background: var(--green); border-radius: var(--r-sm) }
.mno-list li.has-submenu > .mno-parent:hover > a { color: var(--on-green) }
/* Row hover keeps the caret chip VISIBLE by inverting INTO the bright bar:
   transparent fill + DARK border + DARK chevron (v1.19.02 - the old
   dark-chip/green-border combo dissolved against the bright bar and the
   drop-down button read as vanished on touch-sticky hover). */
.mno-list li.has-submenu > .mno-parent:hover .mno-caret { border-color: rgba(8, 22, 15, .55); background: transparent; color: var(--on-green) }
.mno-list li.has-submenu > .mno-parent:hover .mno-caret:hover { border-color: var(--on-green); background: rgba(8, 22, 15, .12); color: var(--on-green) }

/* ── 37f. Sub-menus = nested directories ─────────────────────────── */
.mno-list .sub-menu { border-left-color: var(--green-border); background: rgba(0, 255, 145, .03) }
.mno-list .sub-menu a { font-family: var(--font-mono); font-size: 13px; font-weight: 500 }
.mno-list .sub-menu a::before { content: "└"; color: var(--green-border); font-weight: 700; margin-right: 8px; flex-shrink: 0 }
.mno-list .sub-menu .sub-menu a::before { content: "├" }
.mno-list .sub-menu a:hover { background: var(--green-dim); color: var(--green) }

/* ── 37g. Status strip ───────────────────────────────────────────── */

/* ── 37h. CTA = run command ──────────────────────────────────────── */
.mno-cta { justify-content: flex-start; padding-left: var(--sp-5); background: rgba(0, 255, 145, .08);
  border: 1px solid var(--green-border); color: var(--green); transition: background .15s, color .15s, border-color .15s }
.mno-cta:hover { background: var(--green); color: var(--on-green); border-color: var(--green) }
.mno-cta-prompt { font-weight: 800; margin-right: 8px }

.sr-only { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0 }
/* ── 37i. Embed facades - privacy click-to-load (v1.16.79) ───────── */
/* Replaces oEmbed iframes (YouTube/Vimeo) with a local play button until the
   visitor activates it - zero third-party cookies on page load. In-flow like
   the theme's own iframe rule (the aspect-ratio wrapper gives the box its
   height), so it can never escape its container. Thumbnail is a CSS
   background-image - no <img> element, so lightbox.js never hooks the
   facade and the a11y tree stays well-formed (v1.16.79). */
.gwill-embed-facade { position:relative; display:block; width:100%; height:100%; padding:0; border:0; margin:0; background-color:#000; background-size:cover; background-position:center; background-repeat:no-repeat; cursor:pointer; overflow:hidden; border-radius:var(--r-sm); appearance:none; -webkit-appearance:none }
.prose .wp-block-embed.is-type-video .wp-block-embed__wrapper > .gwill-embed-facade { border:1px solid var(--border); border-radius:var(--r) }
.gwill-embed-facade__play { position:absolute; top:50%; left:50%; transform:translate(-50%,-50%); width:72px; height:72px; border-radius:50%; background:rgba(8,14,16,.78); display:flex; align-items:center; justify-content:center; box-shadow:0 2px 12px rgba(0,0,0,.4); transition:transform .15s, background .15s }
.gwill-embed-facade__play svg { width:28px; height:28px; fill:#fff; margin-left:4px }
.gwill-embed-facade:hover .gwill-embed-facade__play, .gwill-embed-facade:focus-visible .gwill-embed-facade__play { background:var(--green,#00ff91); transform:translate(-50%,-50%) scale(1.07) }
.gwill-embed-facade:hover .gwill-embed-facade__play svg, .gwill-embed-facade:focus-visible .gwill-embed-facade__play svg { fill:var(--on-green) }
.gwill-embed-facade:focus-visible { outline:3px solid var(--green,#00ff91); outline-offset:2px }
.gwill-embed-facade__iframe { display:block; width:100%; height:100%; border:0; background:#000 }

/* Embed player failsafe (v1.16.84) - shown when the player host is
   unreachable (blocked/throttled network): honest state + direct link. */
.gwill-embed-fallback {
	display: flex;
	flex-direction: column;
	align-items: center;
	justify-content: center;
	gap: var(--sp-3);
	min-height: 180px;
	padding: var(--sp-5);
	text-align: center;
	border: 1px dashed var(--border);
	border-radius: var(--r);
	background: var(--surface-2);
}
.gwill-embed-fallback__title {
	margin: 0;
	font-family: var(--font-mono);
	font-size: 14px;
	font-weight: 700;
	color: var(--green);
}
.gwill-embed-fallback__text {
	margin: 0;
	font-size: 14px;
	color: var(--muted);
}
.gwill-embed-fallback__actions {
	display: flex;
	flex-wrap: wrap;
	gap: var(--sp-3);
	margin: var(--sp-2) 0 0;
}

/* Form field validation errors (global - the nl-band and contact forms
   both inject .gwill-form__field-error spans via forms.js) + newsletter
   band status spacing (v1.16.85). */
.gwill-form__field-error { display: block; font-size: 13px; color: var(--gwill-red); margin-top: 6px }
.nl-band .gwill-form__status,
.nl-band .gwill-form__success-msg { margin-top: var(--sp-3) }

/* ── 37j. Search results - "Did you mean?" suggestion block (v1.16.87) ──── */
.search-suggest { margin: var(--sp-6) auto 0; max-width: 520px; text-align: left; background: var(--surface-2); border: 1px solid var(--border); border-radius: var(--r); padding: 20px 24px; box-shadow: var(--shadow-xs) }
.search-suggest-kicker { display: inline-flex; align-items: center; gap: 8px; font-family: var(--font-mono); font-size: 11px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; color: var(--green); margin-bottom: 12px }
.search-suggest-card { display: flex; align-items: center; gap: 12px; font-size: 15px; color: var(--text); padding: 10px 14px; border: 1px solid var(--green-border); border-radius: var(--r-sm); background: rgba(0,255,145,.05); transition: border-color .15s, background .15s, box-shadow .15s }
.search-suggest-card:hover { border-color: var(--green); background: var(--green-dim); box-shadow: 0 0 0 3px rgba(0,255,145,.08) }
.search-suggest-arrow { color: var(--green); font-family: var(--font-mono); font-size: 16px; flex-shrink: 0 }
.search-suggest-alt { margin-top: 10px; font-size: 12px; color: var(--dim); font-family: var(--font-mono) }

/* ── 37k. Search suggestions - runner-up "Or try" links (v1.16.89) ──── */
.search-suggest-alt-link { color: var(--green); text-decoration: underline dotted; text-underline-offset: 3px }
.search-suggest-alt-link:hover { text-decoration: underline solid }

/* Search - Google-grade results-page smarts (v1.16.90)
 * "Showing results for X. Search instead for Y?" header */
.search-correct { font-size: 15px; color: var(--mid); margin: 0 0 20px }
.search-correct a { color: var(--green); font-weight: 600; text-decoration: none; border-bottom: 1px dashed rgba(0,255,145,.4) }
@media (hover: hover) { .search-correct a:hover { border-bottom-style: solid } }
/* ── 37s. "People also searched for" - related term chips ───────────*/
.search-related { margin: var(--sp-4) 0 var(--sp-10); padding-top: var(--sp-6); border-top: 1px solid var(--border) }
.search-related-list { display: flex; flex-wrap: wrap; gap: 10px; margin-top: 14px }
.search-related-chip { display: inline-block; padding: 8px 14px; border: 1px solid var(--border); border-radius: var(--r-pill); color: var(--text); font-size: 14px; text-decoration: none; transition: border-color .15s, color .15s }
@media (hover: hover) { .search-related-chip:hover { border-color: var(--green); color: var(--green) } }
/* ── 37l. Query-term highlighting in result titles (wp_highlight_search_terms) ──── */
mark, mark.search-term { background: rgba(0,255,145,.14); color: inherit; padding: 0 2px; border-radius: 2px }

/* ==========================================================================
   PREMIUM FEATURES - v1.18.00 (King: "more expensive look + new features")
   On-brand: terminal-dark sacred, straight/clean. All motion is reduced-motion
   safe (the global @media (prefers-reduced-motion) block zeroes durations).
   ========================================================================== */

/* ── 37m. Display typeface stack (the single biggest "expensive" signal) ────  Space Grotesk reads as a premium tech display face; falls back to the Space Grotesk reads as a premium tech display face; falls back to the existing mono/grotesk stack if absent. Self-hosted woff2 is the preferred existing mono/grotesk stack if absent. Self-hosted woff2 is the preferred path (drop files in assets/fonts/ and uncomment the @font-face block), path (drop files in assets/fonts/ and uncomment the @font-face block), otherwise the system stack is used so nothing breaks when fonts are absent. */
:root { --font-display: 'Space Grotesk', 'JetBrains Mono', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; }
/* @font-face { font-family: 'Space Grotesk'; font-display: swap;
   src: url(../fonts/space-grotesk-700.woff2) format('woff2'); font-weight: 700; }
   @font-face { font-family: 'Space Grotesk'; font-display: swap;
   src: url(../fonts/space-grotesk-500.woff2) format('woff2'); font-weight: 500; } */
.h1, .h2, .hc-title, .card h3, .lead-grid h3, .toc-sidebar h3 {
  font-family: var(--font-display);
}

/* ── 37n. Reading progress bar (terminal-green, on-brand) ─────────  Targets BOTH #reading-progress (the existing enqueued element on Targets BOTH #reading-progress (the existing enqueued element on singular posts) and .reading-progress (generic) so the style is robust. */
.reading-progress, #reading-progress {
  position: fixed; top: 0; left: 0; height: 3px; width: 100%;
  transform: scaleX(0); transform-origin: 0 0;
  z-index: calc(var(--z-sticky) + 10);
  background: var(--green);
  /* NO transition, NO box-shadow: the bar is driven by scaleX() on every scroll
     frame (compositor-only). A transition makes it lag/morph into a smeared "3D"
     glitch that appears to stall; a box-shadow scales with the transform and
     stretches into a glow smear. Keep it bare and sharp. */
  pointer-events: none;
}

/* ── 37o. Scroll-reveal (IntersectionObserver toggles .is-visible) ──── */
.reveal { opacity: 0; transform: translateY(18px); transition: opacity .55s var(--ease-out), transform .55s var(--ease-out); }
.reveal.is-visible { opacity: 1; transform: none; }
/* stagger children for a curated cascade */
.reveal-d1 { transition-delay: .06s }
.reveal-d2 { transition-delay: .12s }
.reveal-d3 { transition-delay: .18s }
.reveal-d4 { transition-delay: .24s }
.reveal-d5 { transition-delay: .30s }
/* ── 37p. If JS never runs (no IO support / disabled), content must still show. ──── */
.no-js .reveal { opacity: 1; transform: none }

/* ── 37q. Code-block copy button (upgrade of existing .copy-btn) ────  The existing code-copy.js swaps the label text to "Copied!" itself, so we The existing code-copy.js swaps the label text to "Copied!" itself, so we only polish the state (color/border/scale) - never override its text. */
.prose .copy-btn {
  display: inline-flex; align-items: center; gap: 6px;
  transition: color .15s, border-color .15s, background .15s, transform .12s var(--ease-quick);
}
.prose .copy-btn:active { transform: scale(.94) }
.prose .copy-btn.copied { color: var(--green); border-color: var(--green-border); background: var(--green-dim) }

/* ── 37r. TOC active-section tracker (upgrade of existing .toc-sidebar) ──── */
.toc-list a.active { color: var(--green); background: var(--green-dim); border-left-color: var(--green); padding-left: 42px; font-weight: 600 }
.toc-sidebar .toc-list a.active { padding-left: 30px }
.toc-list a.active::before { color: var(--green) }

/* ── 8c. Card entrance polish - focus ring (moved note: lives here for cascade order after the TOC tracker; belongs to section 8 CARDS) ──── */
.card:focus-within { border-color: var(--green-border); box-shadow: var(--shadow-md), var(--ring-green); }

/* ==========================================================================
   38. PWA INSTALL CARD (v1.18.89)
   Bottom sheet in the consent-banner family: same geometry (#cookie), but
   green-accented. Z-order: sticky ad 350 < install card 380 < cookie 400
   < mob nav 500 - if two sheets ever coincide the cookie banner wins.
   ========================================================================== */
.gwill-pwa-card {
  position: fixed; bottom: 16px; left: 50%;
  transform: translate(-50%, calc(100% + 32px));
  z-index: 380;
  display: flex; align-items: center; gap: var(--sp-4); flex-wrap: wrap;
  width: min(560px, calc(100vw - 32px));
  padding: var(--sp-4) var(--sp-5);
  background: rgba(17, 19, 24, .96);
  -webkit-backdrop-filter: blur(12px); backdrop-filter: blur(12px);
  border: 1px solid var(--green-border); border-radius: var(--r-lg);
  box-shadow: 0 12px 32px rgba(0, 0, 0, .45), 0 0 0 1px rgba(0, 255, 145, .04) inset;
  opacity: 0; visibility: hidden;
  transition: transform .3s var(--ease-out), opacity .25s ease, visibility 0s linear .3s;
}
.gwill-pwa-card.is-in {
  transform: translate(-50%, 0);
  opacity: 1; visibility: visible;
  transition: transform .3s var(--ease-out), opacity .25s ease;
}
.gwill-pwa-card-icon {
  flex-shrink: 0; width: 44px; height: 44px;
  border-radius: var(--r-sm);
  box-shadow: 0 0 0 2px var(--green-dim), 0 0 14px rgba(0, 255, 145, .18);
}
.gwill-pwa-card-text { flex: 1; min-width: 180px }
.gwill-pwa-card-title {
  font-family: var(--font-mono); font-size: 13px; font-weight: 700;
  color: var(--green); margin: 0 0 2px;
}
.gwill-pwa-card-body { font-size: 13px; line-height: 1.5; color: var(--mid); margin: 0 }
.gwill-pwa-card-actions { display: flex; align-items: center; gap: var(--sp-2); flex-shrink: 0 }
.gwill-pwa-install {
  font-family: var(--font-mono); font-size: 13px; font-weight: 700;
  min-height: 44px; padding: 10px 20px;
  background: var(--green); color: var(--on-green);
  border: 1px solid var(--green); border-radius: var(--r-sm);
  cursor: pointer; transition: background .15s, transform .12s;
}
@media (hover: hover) { .gwill-pwa-install:hover { background: var(--green-hover); transform: translateY(-1px) } }
.gwill-pwa-later {
  font-family: var(--font-mono); font-size: 13px; font-weight: 600;
  min-height: 44px; padding: 10px 16px;
  background: transparent; color: var(--dim);
  border: 1px solid var(--border-2); border-radius: var(--r-sm);
  cursor: pointer; transition: color .15s, border-color .15s;
}
@media (hover: hover) { .gwill-pwa-later:hover { color: var(--text); border-color: var(--border) } }
.gwill-pwa-install:focus-visible, .gwill-pwa-later:focus-visible,
.gwill-pwa-card:focus-within { outline: 2px solid var(--green); outline-offset: 2px }
/* ── 38a. Mirror the cookie banner's clearance dance with tab bar + sticky ad. ──── */
@media (max-width: 767px) {
  .gwill-pwa-card { bottom: calc(var(--btm-tab-h) + 12px) }
  body.ad-sticky-visible .gwill-pwa-card { bottom: calc(var(--btm-tab-h) + 76px) }
}
/* ── 38b. Reduced motion: no slide. ────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .gwill-pwa-card { transition: opacity .15s ease, visibility 0s linear .15s }
  .gwill-pwa-card.is-in { transition: opacity .15s ease }
}
