/* Phase 16n redesign — editorial system shared across every product's blog,
   brand identity carried entirely by --accent (set per-deploy in config.js).
   Design read: a content hub for four different B2B/consumer products,
   audience arriving from search/social, confident-magazine language —
   self-hosted display serif, a numbered contents-page list instead of a
   generic feature-card grid, a cinematic scrim hero for the lead story,
   and the brand accent used as a real color fill (CTA block), not just a
   hover tint. */

@font-face {
  font-family: "Fraunces Display";
  src: url("/blog/fonts/Fraunces-Display600.woff2") format("woff2");
  font-weight: 600;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: "Fraunces Display";
  src: url("/blog/fonts/Fraunces-Display900.woff2") format("woff2");
  font-weight: 900;
  font-style: normal;
  font-display: swap;
}

:root {
  --bg: #fafafa;
  --ink: #16160f;
  --ink-muted: #6b6862;
  --hairline: #e3e0da;
  --card-bg: #ffffff;
  --accent: #1a1a18; /* overridden per-deploy in config.js */
  /* Reason: --accent-fg is what every *text/border* rule below actually
     uses (see the toggle-safe block further down) — --accent itself is
     reserved for solid-fill contexts (CTA button, hero eyebrow badge)
     where white text sits on top, a separate contrast question that
     doesn't change between themes. In light mode --accent-fg is just
     --accent unchanged (every real per-product accent already clears
     4.5:1 against the light background); dark mode overrides this same
     variable with a lightened, contrast-verified value — see
     agent.tenancy.blog_render_service._accent_style, which computes it
     server-side per product rather than shipping one fixed formula that
     might not clear WCAG for every possible brand color. */
  --accent-fg: var(--accent);
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --font-display: "Fraunces Display", Georgia, "Times New Roman", serif;
}

/* Phase 16p: a manual toggle, not a prefers-color-scheme media query —
   this blog defaults to light regardless of OS/browser theme, and only
   switches when a visitor explicitly clicks the toggle (blog-template/
   theme.js), persisted in localStorage. [data-theme="dark"] is set on
   <html> by an inline, render-blocking script in <head> (see _head() in
   blog_render_service.py) before first paint, so a returning dark-mode
   visitor never sees a flash of the light theme. Token swap over the
   same custom properties every rule in this file already routes color
   through, same pattern as the design before this feature: nothing else
   needs to change. */
:root[data-theme="dark"] {
  --bg: #0c0c0e;
  --ink: #f1efe9;
  --ink-muted: #9b978f;
  --hairline: #2a2a2c;
  --card-bg: #171619;
  /* Defensive fallback only — the real per-product value is injected
     inline, later in <head>, by _accent_style() and wins the cascade. */
  --accent-fg: var(--accent);
}

* {
  box-sizing: border-box;
}

/* Reason: the comment form's inputs already show a placeholder, but a
   placeholder alone fails WCAG 1.3.1/3.3.2 (it disappears on input and
   isn't reliably announced as a label by every screen reader) — a real
   <label> is required; this pattern keeps it visually hidden without
   removing it from the accessibility tree, the standard sr-only recipe. */
.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;
}

html {
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif;
  font-size: 17px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
}

a {
  color: inherit;
  text-decoration: none;
}

a:focus-visible,
button:focus-visible,
input:focus-visible,
textarea:focus-visible {
  outline: 2px solid var(--accent-fg);
  outline-offset: 2px;
}

h1,
h2,
h3 {
  text-wrap: balance;
  font-family: var(--font-display);
  font-weight: 600;
}

.post-body p,
.post-excerpt {
  text-wrap: pretty;
}

@media (prefers-reduced-motion: reduce) {
  * {
    transition-duration: 0.001ms !important;
    animation-duration: 0.001ms !important;
  }
}

.wrap {
  max-width: 720px;
  margin: 0 auto;
  padding: 0 24px;
}

/* Phase 19: 1140px matches blog.aqee.io's real Elementor "boxed" content
   width (measured live: article body maxWidth: min(100%, 1140px)) — the
   founder's own reference for what a blog post page should look like,
   not an arbitrary number. Used for every primary reading surface (post
   body, index list, social-page card list), not just hero imagery. */
.wrap-wide {
  max-width: 1140px;
  margin: 0 auto;
  padding: 0 24px;
}

/* Reason: always keeps its own side padding, even at the mobile breakpoint
   where .wrap-wide intentionally loses its padding so hero imagery can go
   edge-to-edge — the masthead/footer must never touch the screen edges. */
.masthead-inner {
  max-width: 1140px;
  margin: 0 auto;
  padding: 0 24px;
}

/* --- masthead --- */

.masthead {
  border-bottom: 1px solid var(--hairline);
}

.masthead .masthead-inner {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding-top: 22px;
  padding-bottom: 22px;
}

.masthead-word {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 23px;
  letter-spacing: -0.01em;
}

@media (hover: hover) and (pointer: fine) {
  .masthead-word:hover {
    color: var(--accent-fg);
  }
}

.masthead-tag {
  font-size: 12px;
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-weight: 700;
}

@media (hover: hover) and (pointer: fine) {
  .masthead-tag:hover {
    color: var(--accent-fg);
  }
}

/* 2026-08-05: the "Social" masthead item is a <details> disclosure when a
   product has more than one social channel — a plain link when it doesn't
   (see blog_render_service._social_nav_html). */
.masthead-dropdown {
  position: relative;
}

.masthead-dropdown > summary {
  cursor: pointer;
  list-style: none;
}

.masthead-dropdown > summary::-webkit-details-marker {
  display: none;
}

.masthead-dropdown > summary::after {
  content: "";
  display: inline-block;
  margin-left: 4px;
  border: 4px solid transparent;
  border-top-color: currentColor;
  vertical-align: middle;
  transform: translateY(1px);
}

.masthead-dropdown-menu {
  position: absolute;
  top: calc(100% + 10px);
  left: 0;
  min-width: 200px;
  background: var(--card-bg);
  border: 1px solid var(--hairline);
  border-radius: 10px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
  padding: 6px;
  display: flex;
  flex-direction: column;
  z-index: 40;
}

.masthead-dropdown-item {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 8px 10px;
  border-radius: 6px;
  font-size: 13px;
  font-weight: 600;
  color: var(--ink);
  text-decoration: none;
  white-space: nowrap;
}

.masthead-dropdown-item .social-icon {
  width: 15px;
  height: 15px;
  flex: none;
}

.masthead-dropdown-item:hover {
  background: var(--hairline);
}

.masthead-dropdown-item-all {
  color: var(--ink-muted);
  border-bottom: 1px solid var(--hairline);
  border-radius: 6px 6px 0 0;
  margin-bottom: 4px;
  padding-bottom: 10px;
}

.masthead-actions {
  display: flex;
  align-items: center;
  gap: 16px;
}

.locale-switcher {
  display: flex;
  gap: 12px;
}

.locale-link {
  font-size: 12px;
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-weight: 700;
}

@media (hover: hover) and (pointer: fine) {
  .locale-link:hover {
    color: var(--accent-fg);
  }
}

/* Reason: 40x40px, not the previous 30x30px — real touch-target-size
   finding (WCAG 2.5.5): a 30px circular icon button is under the 44px
   floor most mobile guidance recommends. Kept the icon itself at 15px so
   the visual weight in the masthead doesn't change, just the hit area. */
.theme-toggle {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--card-bg);
  color: var(--ink-muted);
  cursor: pointer;
}

@media (hover: hover) and (pointer: fine) {
  .theme-toggle:hover {
    border-color: var(--accent-fg);
    color: var(--accent-fg);
  }
}

.theme-toggle:active {
  transform: scale(0.94);
}

.theme-toggle svg {
  width: 15px;
  height: 15px;
}

.theme-toggle .icon-moon {
  display: none;
}

[data-theme="dark"] .theme-toggle .icon-sun {
  display: none;
}

[data-theme="dark"] .theme-toggle .icon-moon {
  display: block;
}

@media (prefers-reduced-motion: no-preference) {
  body,
  .theme-toggle {
    transition: background-color 0.15s var(--ease-out), color 0.15s var(--ease-out), border-color 0.15s var(--ease-out), transform 0.12s var(--ease-out);
  }
}

main {
  padding: 32px 0 110px;
}

.empty-state {
  color: var(--ink-muted);
  padding: 40px 0;
}

/* --- shared media fallback --- */

.no-image {
  background: linear-gradient(135deg, var(--hairline), var(--bg));
}

.post-meta {
  font-size: 13px;
  color: var(--ink-muted);
}

.post-excerpt {
  color: var(--ink-muted);
  font-size: 15.5px;
  margin: 8px 0;
}

/* --- hero post (index page lead story) --- */

@keyframes hero-rise {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

/* Reason: NOT a fixed aspect-ratio box with the content absolutely
   bottom-anchored inside it — a long headline (real, model-generated
   titles run long) would then overflow *upward past the image itself*,
   landing light-colored text on the plain page background where it's
   invisible (a real bug this design caught on the first screenshot: a
   4-line headline pushed "Latest" off the top of the image entirely).
   Instead .hero-post-media/.hero-post-scrim are absolutely positioned to
   fill whatever height the content naturally needs (min-height sets the
   floor for short headlines; the box only grows for long ones), and
   .hero-post-content flows normally with flex to stay bottom-aligned
   within that height. */
.hero-post {
  position: relative;
  display: block;
  min-height: 420px;
  border-radius: 16px;
  overflow: hidden;
  margin-bottom: 60px;
  background: var(--hairline);
  animation: hero-rise 0.5s var(--ease-out) both;
}

.hero-post-media {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.hero-post-image,
.hero-post-media .no-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.6s var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .hero-post:hover .hero-post-image {
    transform: scale(1.03);
  }
}

.hero-post-scrim {
  position: absolute;
  inset: 0;
  z-index: 1;
  /* Reason: the hero photo is picked per-post by a live Pexels/Unsplash
     search (agent.stages.blog_hero_image) — its exact content behind the
     text is never known in advance, so the scrim can't just be tuned
     against one preview image. Covers most of the box (not just a bottom
     sliver) so a light patch anywhere the text sits still gets real
     darkening; text-shadow below is the second, independent guarantee. */
  background: linear-gradient(to top, rgba(8, 8, 6, 0.92) 0%, rgba(8, 8, 6, 0.62) 45%, rgba(8, 8, 6, 0.15) 80%, rgba(8, 8, 6, 0) 100%);
}

.hero-post-content {
  position: relative;
  z-index: 2;
  display: flex;
  flex-direction: column;
  justify-content: flex-end;
  min-height: 420px;
  padding: 44px 40px;
  color: #fdfdfc;
  max-width: 680px;
  /* Reason: a second, independent guarantee alongside the scrim above —
     if a particular photo still has a light patch right where the text
     sits, the shadow alone keeps it readable. */
  text-shadow: 0 1px 3px rgba(0, 0, 0, 0.45), 0 1px 12px rgba(0, 0, 0, 0.3);
}

.hero-post-eyebrow {
  display: inline-block;
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  color: rgba(253, 253, 252, 0.8);
  margin-bottom: 10px;
}

.hero-post-content h1 {
  font-size: clamp(2rem, 1.35rem + 2.6vw, 3.5rem);
  line-height: 1.08;
  letter-spacing: -0.02em;
  margin: 0 0 10px;
  color: #fdfdfc;
}

.hero-post-content .post-excerpt {
  color: rgba(253, 253, 252, 0.82);
  font-size: 16px;
  max-width: 46ch;
}

.hero-post-content .post-meta {
  color: rgba(253, 253, 252, 0.68);
}

.hero-post-content .tag-chips {
  margin-top: 14px;
}

.hero-post-content .tag-chip {
  border-color: rgba(253, 253, 252, 0.35);
  color: rgba(253, 253, 252, 0.85);
}

/* --- post index (the list — signature editorial rows, not cards) --- */

@keyframes row-rise {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: translateY(0);
  }
}

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

.post-row {
  display: flex;
  align-items: flex-start;
  gap: 22px;
  padding: 26px 0;
  border-bottom: 1px solid var(--hairline);
  animation: row-rise 0.4s var(--ease-out) both;
}

.post-index > .post-row:nth-child(1) {
  animation-delay: 0.02s;
}
.post-index > .post-row:nth-child(2) {
  animation-delay: 0.06s;
}
.post-index > .post-row:nth-child(3) {
  animation-delay: 0.1s;
}
.post-index > .post-row:nth-child(4) {
  animation-delay: 0.14s;
}

.post-row:first-child {
  padding-top: 0;
}

.post-row-number {
  flex-shrink: 0;
  width: 34px;
  padding-top: 2px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 17px;
  color: var(--ink-muted);
  opacity: 0.7;
}

.post-row-media {
  flex-shrink: 0;
  width: 96px;
  height: 96px;
  border-radius: 10px;
  overflow: hidden;
  background: var(--hairline);
}

.row-image,
.post-row-media .no-image {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
}

.post-row-body {
  flex: 1;
  min-width: 0;
}

.post-row-body h2 {
  font-size: 19px;
  line-height: 1.3;
  letter-spacing: -0.005em;
  margin: 0 0 4px;
  transition: color 0.15s var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .post-row:hover .post-row-body h2 {
    color: var(--accent-fg);
  }
}

.post-row-body .post-excerpt {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  margin: 0 0 6px;
}

.related-index .post-row-number {
  display: none;
}

/* --- tag chips + filter bar --- */

.tag-chips {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-top: 8px;
}

.tag-chip {
  padding: 3px 10px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  font-size: 12px;
  font-weight: 600;
  color: var(--ink-muted);
}

.filter-toggle {
  margin-top: 14px;
  padding: 7px 16px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--card-bg);
  color: var(--ink);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.1s var(--ease-out);
}

.filter-toggle[aria-expanded="true"] {
  border-color: var(--accent-fg);
  color: var(--accent-fg);
}

.filter-toggle:active,
.tag-filter-chip:active {
  transform: scale(0.96);
}

/* Reason: real finding — this panel used to swap display:none <-> flex,
   an instant, jarring toggle for an occasional (not keyboard-repeated)
   interaction that genuinely warrants a brief reveal. max-height/opacity
   is the pragmatic CSS-only approach here (grid-template-rows' "animate
   to auto height" trick needs an extra wrapper div this flat button list
   doesn't have); 400px comfortably covers real tag-count volumes without
   the animation racing past a shorter real height. */
.tag-filters {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  max-height: 0;
  margin-top: 0;
  opacity: 0;
  overflow: hidden;
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .tag-filters {
    transition: max-height 200ms var(--ease-out), opacity 150ms var(--ease-out), margin-top 200ms var(--ease-out);
  }
}

.tag-filters.open {
  max-height: 400px;
  margin-top: 12px;
  opacity: 1;
  pointer-events: auto;
}

.tag-filter-chip {
  padding: 5px 14px;
  border: 1px solid var(--hairline);
  border-radius: 999px;
  background: var(--card-bg);
  color: var(--ink-muted);
  font-size: 13px;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.1s var(--ease-out);
}

.tag-filter-chip.active {
  border-color: var(--accent-fg);
  color: var(--accent-fg);
}

#blog-search {
  width: 100%;
  padding: 12px 16px;
  border: 1px solid var(--hairline);
  border-radius: 10px;
  font-family: inherit;
  font-size: 15px;
  background: var(--card-bg);
  color: var(--ink);
}

/* --- article detail --- */

.breadcrumbs {
  margin: 0 0 18px;
  font-size: 13px;
  color: var(--ink-muted);
}

.breadcrumbs ol {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: 6px;
  margin: 0;
  padding: 0;
  list-style: none;
}

.breadcrumbs li {
  display: flex;
  align-items: baseline;
  gap: 6px;
}

.breadcrumbs li:not(:last-child)::after {
  content: "/";
  color: var(--hairline);
}

.breadcrumbs a {
  color: var(--ink-muted);
  text-decoration: none;
}

@media (hover: hover) and (pointer: fine) {
  .breadcrumbs a:hover {
    color: var(--accent-fg);
  }
}

.breadcrumbs li[aria-current="page"] {
  color: var(--ink);
  font-weight: 600;
  /* A full headline in the trail can run long — truncate rather than let
     it wrap the whole breadcrumb row onto a second line. */
  max-width: 320px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.post-detail .back {
  display: inline-block;
  font-size: 14px;
  color: var(--ink-muted);
  margin-bottom: 32px;
}

@media (hover: hover) and (pointer: fine) {
  .post-detail .back:hover {
    color: var(--accent-fg);
  }
}

.post-detail h1 {
  font-size: clamp(1.9rem, 1.35rem + 2vw, 3.1rem);
  line-height: 1.14;
  letter-spacing: -0.015em;
  margin: 0 0 14px;
}

.post-detail .post-meta {
  margin-bottom: 28px;
}

.hero-image-frame {
  width: 100%;
  aspect-ratio: 21 / 9;
  overflow: hidden;
  border-radius: 14px;
  background: var(--hairline);
  margin-bottom: 6px;
}

.hero-image {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.photo-credit {
  font-size: 12.5px;
  color: var(--ink-muted);
  margin: 0 0 36px;
}

.post-body {
  padding-top: 8px;
}

.post-body p {
  margin: 0 0 22px;
}

.post-body h2 {
  font-size: 26px;
  line-height: 1.3;
  letter-spacing: -0.01em;
  margin: 44px 0 18px;
}

.post-body h3 {
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 20px;
  line-height: 1.3;
  letter-spacing: -0.005em;
  margin: 32px 0 12px;
}

.post-body a {
  color: var(--accent-fg);
  text-decoration: underline;
}

/* --- key takeaways / TL;DR box --- */

.takeaways-box {
  margin: 0 0 32px;
  padding: 22px 24px;
  border: 1px solid var(--hairline);
  border-left: 3px solid var(--accent-fg);
  border-radius: 12px;
  background: var(--card-bg);
}

.takeaways-title {
  margin: 0 0 10px;
  font-weight: 700;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-muted);
}

.takeaways-box ul {
  margin: 0;
  padding-left: 20px;
}

.takeaways-box li {
  margin-bottom: 8px;
  font-size: 15.5px;
  line-height: 1.5;
}

.takeaways-box li:last-child {
  margin-bottom: 0;
}

/* --- table of contents --- */

.toc {
  margin: 0 0 32px;
  padding: 20px 22px;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: var(--card-bg);
}

.toc-title {
  margin: 0 0 8px;
  font-weight: 700;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--ink-muted);
}

.toc ul {
  margin: 0;
  padding-left: 18px;
}

.toc li {
  margin-bottom: 4px;
  font-size: 14.5px;
}

.toc a {
  color: var(--accent-fg);
}

/* --- share row --- */

.share-row {
  display: flex;
  align-items: center;
  gap: 10px;
  margin: 40px 0 56px;
  padding-top: 28px;
  border-top: 1px solid var(--hairline);
}

.share-label {
  font-size: 12px;
  color: var(--ink-muted);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 700;
  margin-right: 4px;
}

/* Reason: 40x40px, not the previous 34x34px — same real touch-target
   finding as .theme-toggle above. */
.share-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  border-radius: 50%;
  border: 1px solid var(--hairline);
  color: var(--ink-muted);
  background: none;
  cursor: pointer;
  font-size: 11px;
  font-family: inherit;
  padding: 0;
  transition: color 0.15s var(--ease-out), border-color 0.15s var(--ease-out), transform 0.1s var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .share-btn:hover {
    color: var(--accent-fg);
    border-color: var(--accent-fg);
  }
}

.share-btn:active {
  transform: scale(0.94);
}

.copy-link-btn {
  width: auto;
  min-width: 40px;
  padding: 0 12px;
}

/* --- CTA block: a real color fill, not another bordered card --- */

.cta-block {
  margin: 44px 0;
  padding: 36px;
  border-radius: 18px;
  background: var(--accent);
  color: #fdfdfc;
  display: flex;
  flex-direction: column;
  gap: 18px;
}

.cta-title {
  margin: 0;
  font-size: 20px;
  color: #fdfdfc;
}

.cta-text {
  margin: 0;
  color: rgba(253, 253, 252, 0.82);
  font-size: 15px;
  max-width: 46ch;
}

.cta-button {
  display: inline-block;
  align-self: flex-start;
  padding: 12px 24px;
  border-radius: 9px;
  background: #fdfdfc;
  color: var(--accent-fg);
  font-weight: 700;
  font-size: 14px;
  transition: transform 0.12s var(--ease-out);
}

.cta-button:active {
  transform: scale(0.97);
}

@media (min-width: 640px) {
  .cta-block {
    flex-direction: row;
    align-items: center;
    justify-content: space-between;
  }
  .cta-button {
    flex-shrink: 0;
  }
}

/* --- email capture --- */

.subscribe-block {
  margin: 24px 0 44px;
  padding: 26px;
  border: 1px solid var(--hairline);
  border-radius: 14px;
  background: var(--card-bg);
}

.subscribe-title {
  margin: 0 0 14px;
  font-family: var(--font-display);
  font-weight: 600;
  font-size: 17px;
}

.subscribe-form {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.subscribe-form input[type="email"] {
  flex: 1;
  min-width: 200px;
  padding: 11px 14px;
  border: 1px solid var(--hairline);
  border-radius: 9px;
  font-family: inherit;
  font-size: 14.5px;
  background: var(--bg);
  color: var(--ink);
}

.subscribe-form button[type="submit"] {
  padding: 11px 22px;
  border: none;
  border-radius: 9px;
  background: var(--accent);
  color: #fff;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  transition: transform 0.12s var(--ease-out);
}

.subscribe-form button[type="submit"]:active {
  transform: scale(0.97);
}

.subscribe-status {
  margin: 8px 0 0;
  font-size: 13px;
  color: var(--ink-muted);
}

/* --- like button --- */

.like-button {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  margin-bottom: 32px;
  padding: 9px 18px;
  border: 1px solid var(--hairline);
  border-radius: 22px;
  background: var(--card-bg);
  color: var(--ink);
  font-size: 14px;
  font-weight: 600;
  cursor: pointer;
  transition: border-color 0.15s var(--ease-out), color 0.15s var(--ease-out), transform 0.15s var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .like-button:hover {
    border-color: var(--accent-fg);
    color: var(--accent-fg);
  }
}

.like-button:active {
  transform: scale(0.96);
}

.like-button[data-liked="true"] {
  border-color: var(--accent-fg);
  color: var(--accent-fg);
}

/* --- comments --- */

.comments-section {
  margin-top: 28px;
  padding-top: 44px;
  border-top: 1px solid var(--hairline);
}

.comments-heading,
.related-heading {
  font-size: 22px;
  margin: 0 0 22px;
}

.comments-empty {
  color: var(--ink-muted);
  font-size: 14.5px;
}

.comment-list {
  display: flex;
  flex-direction: column;
  gap: 16px;
  margin-bottom: 28px;
}

.comment {
  padding: 16px 18px;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  background: var(--card-bg);
}

.comment-name {
  margin: 0 0 4px;
  font-weight: 700;
  font-size: 13.5px;
}

.comment-text {
  margin: 0;
  font-size: 14.5px;
  color: var(--ink);
}

.comment-form {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.comment-form input[type="text"],
.comment-form textarea {
  width: 100%;
  padding: 11px 14px;
  border: 1px solid var(--hairline);
  border-radius: 9px;
  font-family: inherit;
  font-size: 14.5px;
  background: var(--card-bg);
  color: var(--ink);
}

.comment-form textarea {
  min-height: 90px;
  resize: vertical;
}

.comment-form button[type="submit"] {
  align-self: flex-start;
  padding: 11px 22px;
  border: none;
  border-radius: 9px;
  background: var(--accent);
  color: #fff;
  font-weight: 600;
  font-size: 14px;
  cursor: pointer;
  transition: transform 0.12s var(--ease-out);
}

.comment-form button[type="submit"]:active {
  transform: scale(0.97);
}

.comment-form button[type="submit"]:disabled {
  opacity: 0.6;
  cursor: default;
}

.comment-status {
  margin: 0;
  font-size: 13px;
  color: var(--ink-muted);
}

/* Reason: hidden via off-screen positioning, not display:none — a real
   bot filling every visible-looking field often skips display:none
   elements deliberately, but rarely checks computed position. */
.honeypot-field {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  opacity: 0;
}

/* --- related posts --- */

.related-section {
  margin-top: 28px;
  padding-top: 44px;
  border-top: 1px solid var(--hairline);
}

/* --- pagination --- */

.pagination {
  display: flex;
  gap: 6px;
  margin-top: 8px;
}

.page-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 40px;
  height: 40px;
  padding: 0 8px;
  border-radius: 8px;
  font-size: 13px;
  font-weight: 700;
  color: var(--ink-muted);
}

.page-link.active {
  background: var(--accent);
  color: #fff;
}

@media (hover: hover) and (pointer: fine) {
  .page-link:not(.active):hover {
    background: var(--hairline);
  }
}

/* --- footer --- */

footer.site {
  border-top: 1px solid var(--hairline);
  margin-top: 24px;
}

footer.site .masthead-inner {
  padding: 32px 24px;
  font-size: 13px;
  color: var(--ink-muted);
}

/* --- responsive --- */

@media (max-width: 720px) {
  .hero-post,
  .hero-post-content {
    min-height: 340px;
  }
  .hero-post {
    border-radius: 10px;
  }
  .hero-post-content {
    padding: 28px 24px;
  }
  .hero-image-frame {
    aspect-ratio: 16 / 9;
    border-radius: 0;
  }
  .wrap-wide {
    padding: 0;
  }
  .hero-post {
    margin-left: 0;
  }
}

@media (max-width: 620px) {
  .post-row-media {
    width: 72px;
    height: 72px;
  }
  .post-row-number {
    width: 24px;
    font-size: 14px;
  }
}

@media (max-width: 480px) {
  body {
    font-size: 16px;
  }
  .post-detail h1 {
    font-size: 30px;
  }
  .post-row-body h2 {
    font-size: 17px;
  }
  .share-row {
    flex-wrap: wrap;
  }
  .post-row {
    gap: 14px;
  }
}

/* --- social post pages (Phase 16p) --- */
/* The per-platform pages at /blog/social/<platform>/. Same tokens and
   restraint as the rest of the blog — these are pages on the product's
   blog, not a separate tool with its own look. Phase 22: the post's full
   copy is no longer a permanently-visible block on the card — it lives
   behind a "read transcript" icon that opens .social-transcript-dialog
   (monospaced/boxed there instead, same "literal text to paste verbatim"
   treatment the old always-visible .social-copy block used to carry). */

.masthead-nav {
  display: flex;
  align-items: baseline;
  gap: 20px;
}

.social-hub-title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 30px;
  letter-spacing: -0.015em;
  margin: 12px 0 20px;
}

.social-breadcrumb {
  margin-top: 16px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-weight: 700;
  color: var(--ink-muted);
}

.social-hub-list {
  list-style: none;
  margin: 0 0 72px;
  padding: 0;
  border-top: 1px solid var(--hairline);
}

.social-hub-row a {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
  padding: 20px 0;
  border-bottom: 1px solid var(--hairline);
}

.social-hub-name {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 22px;
}

.social-hub-count {
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-weight: 700;
  color: var(--ink-muted);
}

@media (hover: hover) and (pointer: fine) {
  .social-hub-row a:hover .social-hub-name {
    color: var(--accent-fg);
  }
}

.social-list {
  margin-bottom: 72px;
}

/* Phase 22: dense video-catalog grid for the two exclusively-video groups
   (vertical_video, youtube) — a YouTube-listing-style tile layout, replacing
   the one-per-row list for just these two pages. Every other platform
   (x/reddit/linkedin/medium) keeps .social-list untouched above. */
.social-grid {
  display: grid;
  gap: 28px;
  margin-bottom: 72px;
}

.social-grid-vertical {
  grid-template-columns: repeat(5, 1fr);
}

.social-grid-youtube {
  grid-template-columns: repeat(3, 1fr);
}

@media (max-width: 1100px) {
  .social-grid-vertical {
    grid-template-columns: repeat(3, 1fr);
  }
  .social-grid-youtube {
    grid-template-columns: repeat(2, 1fr);
  }
}

@media (max-width: 780px) {
  .social-grid-vertical {
    grid-template-columns: repeat(2, 1fr);
  }
  .social-grid-youtube {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 480px) {
  .social-grid-vertical,
  .social-grid-youtube {
    grid-template-columns: 1fr;
  }
}

/* A tile is a self-contained card: media on top, compact body below —
   distinct from .social-card's wide two-column row (see .social-tile-media/
   .social-tile-body). */
.social-tile {
  display: flex;
  flex-direction: column;
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 12px;
  gap: 10px;
  min-width: 0;
}

.social-tile-published {
  border-color: var(--accent-fg);
}

.social-tile-media {
  background: var(--hairline);
  border-radius: 10px;
  padding: 8px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
}

.social-tile-media .social-asset {
  border-radius: 6px;
}

.social-tile-body {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.social-tile-title {
  font-family: var(--font-display);
  font-weight: 800;
  font-size: 16px;
  line-height: 1.35;
  letter-spacing: -0.005em;
  margin: 6px 0 8px;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}

.social-tile .social-card-meta {
  font-size: 10.5px;
  gap: 8px;
  flex-wrap: wrap;
}

.social-tile .social-actions {
  margin-top: 10px;
  flex-wrap: wrap;
  gap: 8px;
}

.social-tile .social-downloads {
  margin-top: 8px;
}

/* A card/tile linked to directly (Phase 22 deep link, #post-<id>) gets a
   brief highlight so the reader can see which one they were sent to. */
.social-card:target,
.social-tile:target {
  outline: 2px solid var(--accent-fg);
  outline-offset: 4px;
}

.social-card {
  border-top: 1px solid var(--hairline);
  padding: 28px 0;
}

/* Phase 19: wide two-column layout — media on the left (just wide enough
   for a 9:16 clip to read comfortably, not the whole column), copy/actions
   on the right, so more posts fit in the viewport than the old stacked
   layout. Only kicks in once there's room; narrow viewports stack instead
   (media on top) via the media query below. */
.social-card-row {
  display: flex;
  align-items: flex-start;
  gap: 28px;
}

.social-card-media {
  flex: 0 0 30%;
  max-width: 30%;
}

/* YouTube's 16:9 content needs more horizontal room than a 9:16 clip. */
.social-card-row-wide-media .social-card-media {
  flex-basis: 50%;
  max-width: 50%;
}

.social-card-body {
  flex: 1 1 auto;
  min-width: 0;
}

@media (max-width: 780px) {
  .social-card-row,
  .social-card-row-wide-media {
    flex-direction: column;
  }
  .social-card-media,
  .social-card-row-wide-media .social-card-media {
    flex-basis: auto;
    max-width: 100%;
    width: 100%;
  }
}

.social-card-meta {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 12px;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  font-weight: 700;
  color: var(--ink-muted);
}

.social-badge {
  border: 1px solid var(--hairline);
  border-radius: 2px;
  padding: 2px 8px;
  letter-spacing: 0.06em;
}

.social-badge-approved,
.social-badge-published {
  border-color: var(--accent-fg);
  color: var(--accent-fg);
}

/* A post that actually went out (Phase 17: published to the platform, or to
   this blog as the fallback destination) reads as settled content — accent
   edge rather than a louder treatment. */
.social-card-published {
  border-left: 3px solid var(--accent-fg);
  padding-left: 20px;
}

.social-card-title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 24px;
  letter-spacing: -0.01em;
  margin: 10px 0 6px;
}

.social-angle {
  color: var(--ink-muted);
  font-size: 14px;
  margin-bottom: 16px;
}

/* 2026-08-04 (founder): a card whose media is a real video renders its
   heading visually hidden — the video's cover frame already has the
   headline burned into the pixels, so showing it again under the player is
   duplication. It stays in the DOM because burned-in pixels are invisible
   to assistive tech; this element is what still names the card. The
   compound selector (0,2,0) is needed because .social-tile-title /
   .social-card-title are declared after .sr-only and would otherwise win
   the equal-specificity cascade on margin/overflow/display. */
.social-tile-title.sr-only,
.social-card-title.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;
  display: block;
}

/* Phase 19: the media column reads as a real player card — rounded
   corners and a soft neutral surface behind the asset, closer to how
   YouTube/Vimeo embeds and most schedulers present video, rather than a
   bare clip bleeding into the page background. */
.social-card-media {
  background: var(--hairline);
  border-radius: 12px;
  padding: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 10px;
}

.social-asset {
  display: block;
  max-width: 100%;
  width: 100%;
  height: auto;
  border-radius: 8px;
  overflow: hidden;
}

/* Rendered social videos are portrait (1080x1920) — capped so a vertical
   clip in the now-narrower media column still reads at a comfortable size
   rather than stretching to fill all available width. */
video.social-asset {
  width: auto;
  max-height: 520px;
  max-width: 100%;
}

/* 2026-08-05 (founder: "expand the video when playing to full view"): an
   own expand-to-fullscreen button overlaid on the video, distinct from the
   <video>'s native controls-bar icon — that icon is the first thing
   Chromium/Firefox drop once the controls bar gets this narrow (a capped
   9:16 clip here is ~290px wide). Positioned top-right so it never
   overlaps the native controls bar along the bottom. */
.social-video-frame {
  position: relative;
  display: inline-block;
  max-width: 100%;
}

.social-video-expand-btn {
  position: absolute;
  top: 10px;
  right: 10px;
  z-index: 5;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 32px;
  height: 32px;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: rgba(0, 0, 0, 0.55);
  color: #fff;
  cursor: pointer;
  line-height: 1;
}

.social-video-expand-btn:hover,
.social-video-expand-btn:focus-visible {
  background: rgba(0, 0, 0, 0.75);
}

.social-video-expand-btn .social-icon {
  width: 18px;
  height: 18px;
}

/* A fullscreened element keeps its own intrinsic size by default (the
   browser only takes over the backdrop) — without this, .social-video-frame
   sits small in the corner of a big black rect instead of filling it.
   Vendor-prefixed pseudo-classes cover older Safari/Firefox. Real bug found
   testing this live: grouping `:fullscreen, :-webkit-full-screen,
   :-moz-full-screen` in ONE comma-separated selector meant Chromium's own
   unfamiliarity with `:-moz-full-screen` invalidated the WHOLE rule (an
   unparseable selector in a grouped list drops the entire rule, not just
   that branch) — so NONE of it applied, even the plain `:fullscreen` part
   Chromium does support. Each prefix gets its own standalone rule block
   instead, so one browser's unsupported prefix can't take the others
   down with it. */
.social-video-frame:fullscreen {
  width: 100%;
  height: 100%;
  max-width: none;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
}

.social-video-frame:-webkit-full-screen {
  width: 100%;
  height: 100%;
  max-width: none;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
}

.social-video-frame:-moz-full-screen {
  width: 100%;
  height: 100%;
  max-width: none;
  display: flex;
  align-items: center;
  justify-content: center;
  background: #000;
}

.social-video-frame:fullscreen video.social-asset {
  width: auto;
  height: 100%;
  max-height: 100%;
  max-width: 100%;
}

.social-video-frame:-webkit-full-screen video.social-asset {
  width: auto;
  height: 100%;
  max-height: 100%;
  max-width: 100%;
}

.social-video-frame:-moz-full-screen video.social-asset {
  width: auto;
  height: 100%;
  max-height: 100%;
  max-width: 100%;
}

.social-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 16px;
}

/* 2026-08-03 four-icon redesign: the card's actions are exactly four
   borderless icon triggers (Share / Download / Copy / Transcript), each
   opening a small popout menu of labeled actions. No outline (founder),
   affordance carried by a hover/focus background tint instead. */
.social-icon-action {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 36px;
  height: 36px;
  padding: 0;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--ink);
  cursor: pointer;
  line-height: 1;
  text-decoration: none;
}

.social-popout {
  position: relative;
  display: inline-flex;
}

.social-popout-menu {
  display: none;
  position: absolute;
  top: calc(100% + 6px);
  left: 0;
  z-index: 30;
  min-width: 190px;
  padding: 6px;
  background: var(--card-bg);
  border: 1px solid var(--hairline);
  border-radius: 8px;
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.14);
}

.social-popout.open .social-popout-menu {
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.social-popout.open > .social-popout-trigger {
  background: color-mix(in srgb, var(--ink) 10%, transparent);
}

/* Labeled menu entries — the same buttons that used to sit inline on the
   card (identical classes/data-*, so social.js handlers are unchanged),
   now full-width rows with the label always visible. */
.social-popout-item {
  display: flex;
  align-items: center;
  gap: 10px;
  width: 100%;
  padding: 8px 10px;
  border: none;
  border-radius: 6px;
  background: none;
  color: var(--ink);
  cursor: pointer;
  font-size: 13px;
  font-weight: 600;
  line-height: 1.2;
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
}

.social-popout-item .social-icon {
  flex: 0 0 auto;
}

@media (hover: hover) and (pointer: fine) {
  .social-popout-item:hover {
    background: color-mix(in srgb, var(--ink) 8%, transparent);
  }
}

.social-share-button {
  /* Legacy co-class kept for social.js dispatch — visual styling now
     comes from .social-popout-item (2026-08-03 redesign). */
}

.social-icon {
  width: 16px;
  height: 16px;
  flex: 0 0 auto;
}

.social-share-icon-button .social-icon {
  width: 16px;
  height: 16px;
}

/* The flash-message span (e.g. "Copied — paste it") takes no space while
   empty, so the button stays icon-only until social.js briefly fills it in
   on a copy-fallback share/copy action. Shared by every icon-only button
   that uses social.js's flash() — share row, copy, and copy-url. */
.social-icon-action span:empty {
  display: none;
}

.social-icon-action span:not(:empty) {
  margin-left: 8px;
  font-size: 10px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  white-space: nowrap;
}

/* 2026-08-05: .like-button (blog's own pill-button class, reused here for
   free existing styling — see agent.tenancy.blog_social_render._like_button)
   also carries .social-icon-action for the compact action-row treatment.
   Blog's own margin-bottom (spacing it stands alone with, below a post
   body) has no equivalent meaning inline in a card's action row — override
   it here rather than in the shared .like-button rule, which blog's own
   post-detail page still needs unchanged. */
.social-actions .like-button {
  margin-bottom: 0;
}

.social-actions .like-count {
  text-transform: none;
  letter-spacing: normal;
}

/* Phase 18: a post's branded cover/thumbnail image — shown smaller and
   separate from the main media (video/gallery) so it reads as "here's the
   cover art", not just another gallery image. */
.social-cover-asset {
  max-width: 280px;
  border-radius: 8px;
}

@media (hover: hover) and (pointer: fine) {
  .social-icon-action:hover {
    background: color-mix(in srgb, var(--ink) 8%, transparent);
  }
}

/* The platform glyph next to a heading/hub row sits on the text baseline
   rather than filling the accent button. */
.social-hub-name .social-icon,
.social-hub-title .social-icon {
  vertical-align: -0.15em;
  margin-right: 10px;
}

.social-hub-title .social-icon {
  width: 30px;
  height: 30px;
  margin-right: 14px;
}

@media (hover: hover) and (pointer: fine) {
  .social-share-button:hover {
    opacity: 0.9;
  }
}

@media (max-width: 640px) {
  .masthead-nav {
    gap: 14px;
  }
  .social-hub-title {
    font-size: 30px;
  }
  .social-actions {
    flex-wrap: wrap;
  }
}

/* Phase 22: the transcript modal — a single reusable native <dialog> per
   page (see blog_social_render._TRANSCRIPT_DIALOG), populated on open by
   social.js. Simple, centered, scrollable for a long post; the browser
   supplies the backdrop and Escape-to-close for free. */
.social-transcript-dialog {
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 0;
  width: min(640px, 92vw);
  max-height: 80vh;
  color: var(--ink);
  background: var(--bg);
}

.social-transcript-dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

.social-transcript-dialog-inner {
  display: flex;
  flex-direction: column;
  max-height: 80vh;
  padding: 20px 24px 24px;
}

.social-transcript-dialog-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 14px;
}

.social-transcript-dialog-title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 20px;
  letter-spacing: -0.01em;
  margin: 0;
}

.social-transcript-dialog-close {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border: 1px solid var(--hairline);
  border-radius: 2px;
  background: none;
  color: var(--ink);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}

.social-transcript-dialog-body {
  background: var(--card-bg);
  border: 1px solid var(--hairline);
  border-radius: 3px;
  padding: 18px 20px;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 14px;
  line-height: 1.7;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
  overflow-y: auto;
  margin: 0;
}

/* 2026-08-05: the comments modal — same reusable-native-<dialog> pattern
   as .social-transcript-dialog above (see blog_social_render._comments_
   dialog), just with a real .comment-list + .comment-form inside instead
   of a read-only <pre>. Reuses blog's own .comment-list/.comment/
   .comment-form styling (below, under "--- comments ---" /
   "--- comment form ---") wholesale — only the dialog chrome itself is new. */
.social-comments-dialog {
  border: 1px solid var(--hairline);
  border-radius: 12px;
  padding: 0;
  width: min(560px, 92vw);
  max-height: 85vh;
  color: var(--ink);
  background: var(--bg);
}

.social-comments-dialog::backdrop {
  background: rgba(0, 0, 0, 0.5);
}

.social-comments-dialog-inner {
  display: flex;
  flex-direction: column;
  max-height: 85vh;
  padding: 20px 24px 24px;
  overflow-y: auto;
}

.social-comments-dialog-head {
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 16px;
  margin-bottom: 14px;
}

.social-comments-dialog-title {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 20px;
  letter-spacing: -0.01em;
  margin: 0;
}

.social-comments-dialog-close {
  flex: 0 0 auto;
  width: 32px;
  height: 32px;
  border: 1px solid var(--hairline);
  border-radius: 2px;
  background: none;
  color: var(--ink);
  font-size: 20px;
  line-height: 1;
  cursor: pointer;
}

.social-comments-dialog-list {
  margin-bottom: 16px;
}

/* --- print --- */
/* Reason: force light colors regardless of the reader's screen dark-mode
   preference — printed dark backgrounds waste ink and read badly on
   paper, and @media print rules apply independently of @media
   (prefers-color-scheme: dark) above, so this needs its own explicit
   overrides rather than relying on the light :root defaults. */
@media print {
  .masthead,
  .share-row,
  .cta-block,
  .subscribe-block,
  .like-button,
  .comments-section,
  .tag-filters,
  #blog-search,
  .related-section,
  footer.site,
  .pagination {
    display: none !important;
  }

  :root {
    --bg: #ffffff;
    --ink: #000000;
    --ink-muted: #444444;
    --hairline: #cccccc;
    --card-bg: #ffffff;
  }

  body {
    font-size: 12pt;
  }

  a {
    color: inherit;
    text-decoration: underline;
  }
}

/* --- post sidebar (2026-08-03): other posts beside the article body --- */
.post-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr) 264px;
  gap: 48px;
  align-items: start;
}

.post-sidebar {
  position: sticky;
  top: 24px;
  border-left: 1px solid var(--hairline);
  padding-left: 24px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.post-sidebar-heading {
  font-size: 12px;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--ink-muted);
  margin: 0 0 10px;
}

.post-sidebar-item {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 9px 10px;
  margin-left: -10px;
  border-radius: 8px;
  text-decoration: none;
  color: var(--ink);
}

.post-sidebar-item-title {
  font-weight: 600;
  font-size: 14px;
  line-height: 1.35;
}

.post-sidebar-item-date {
  font-size: 12px;
  color: var(--ink-muted);
}

@media (hover: hover) and (pointer: fine) {
  .post-sidebar-item:hover {
    background: color-mix(in srgb, var(--ink) 6%, transparent);
  }
}

@media (max-width: 960px) {
  .post-layout {
    grid-template-columns: minmax(0, 1fr);
  }
  .post-sidebar {
    position: static;
    border-left: none;
    padding-left: 0;
    border-top: 1px solid var(--hairline);
    padding-top: 20px;
    margin-top: 8px;
  }
}
