:root {
  --font-size-xs: 0.75rem;
  --font-size-sm: 0.875rem;
  --font-size-base: 1rem;
  --font-size-md: 1.125rem;
  --font-size-lg: 1.25rem;
  --font-size-xl: 1.5rem;
  --font-size-2xl: 2rem;
  --font-size-3xl: 3rem;

  --space-1: 0.25rem;
  --space-2: 0.5rem;
  --space-3: 0.75rem;
  --space-4: 1rem;
  --space-5: 1.25rem;
  --space-6: 1.5rem;
  --space-8: 2rem;
  --space-12: 3rem;
  --space-16: 4rem;
  --space-24: 6rem;
  --space-32: 8rem;

  --font-family-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;

  --font-serif: 'Source Serif 4', Charter, 'Iowan Old Style', Georgia, serif;
  --font-sans: 'Inter', system-ui, -apple-system, 'Segoe UI', Roboto, sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, Menlo, monospace;

  --line-height-tight: 1.2;
  --line-height-base: 1.5;
  --line-height-relaxed: 1.7;

  --font-weight-regular: 400;
  --font-weight-medium: 500;
  --font-weight-bold: 700;

  /* Heading scale used by .admin-page-header and section h2/h3 chrome. Anchors
     downstream rules to a shared ladder so a single font-size change here
     ripples to every page. */
  --heading-1-size: var(--font-size-2xl);
  --heading-2-size: var(--font-size-xl);
  --heading-3-size: var(--font-size-lg);
  --heading-tracking: -0.01em;
  --eyebrow-tracking: 0.12em;

  /* Page chrome — wraps every admin and sales page. Inline padding bumps to
     --space-8 on the wide breakpoint via a media-query override in the page
     stylesheet. */
  --page-max-width: 72rem;
  --page-padding-block: var(--space-12);
  --page-padding-inline: var(--space-4);

  /* Form field rhythm. .admin-form spaces fields with --field-spacing-y;
     labels read at --font-size-sm in --color-text-tertiary to give the
     input itself visual primacy. */
  --field-spacing-y: var(--space-5);

  /* Editorial palette (Sprint 4A.2). Replaces pure-black / pure-white anchor
     values with warmer tinted equivalents — backgrounds #000 → #0a0a0b and
     #fff → #fafaf7 (paper-like in light, less harsh in dark); text and
     hairlines pick up paired warmth so chrome reads warm-on-warm or
     cool-on-cool consistent with the mode. The text ladder
     (-secondary/-tertiary/-quaternary), hairline-strong, accent
     positive/negative, and grid alpha tokens are consumed across the
     editorial public surfaces and the 4A.3 bg_grid controller.

     Sprint 4A.7 closed in 4D.6: every legacy token (--color-{black,white,
     near-black,near-white,neutral,muted}) retired. --color-muted's 18
     application.css consumers all migrated to --color-text-tertiary in
     the same commit. tokens.css now carries only the editorial
     vocabulary. */
  --color-background: #0a0a0b;
  --color-text: #ece9df;
  --color-text-secondary: #c9c5b8;
  --color-text-tertiary: #898680;
  --color-text-quaternary: #6c6963;
  --color-hairline-faint: rgba(236, 233, 223, 0.08);
  --color-hairline-soft: rgba(236, 233, 223, 0.10);
  --color-hairline: rgba(236, 233, 223, 0.12);
  --color-hairline-strong: rgba(236, 233, 223, 0.3);
  /* Subtle background tints — stripe for table row striping and the services
     grid card hover background (4B.5); hover for table row hover and the
     services grid card mouse-follow grid lines (4B.5). */
  --color-stripe: rgba(236, 233, 223, 0.018);
  --color-hover: rgba(236, 233, 223, 0.04);
  --color-background-inverse: #ece9df;
  --color-text-inverse: #0a0a0b;
  --color-accent-positive: #b6e3a4;
  --color-accent-negative: #c84e3f;
  --grid-line-alpha: 0.08;
  --grid-dot-alpha-max: 0.5;

  /* Hints native form controls (<select> popups, date/time pickers,
     scrollbars) to use dark-scheme variants. Paired with the per-theme
     override below, this matches the data-theme toggle. */
  color-scheme: dark;
}

[data-theme="light"] {
  --color-background: #fafaf7;
  --color-text: #1a1a1c;
  --color-text-secondary: #3d3b36;
  --color-text-tertiary: #6c6963;
  --color-text-quaternary: #898680;
  --color-hairline-faint: rgba(10, 10, 11, 0.10);
  --color-hairline-soft: rgba(10, 10, 11, 0.12);
  --color-hairline: rgba(10, 10, 11, 0.14);
  --color-hairline-strong: rgba(10, 10, 11, 0.32);
  /* Stripe and hover — see consumers documented in the dark-mode block. */
  --color-stripe: rgba(10, 10, 11, 0.022);
  --color-hover: rgba(10, 10, 11, 0.05);
  --color-background-inverse: #1a1a1c;
  --color-text-inverse: #fafaf7;
  --color-accent-positive: #5e8c52;
  --color-accent-negative: #a83a2c;
  --grid-line-alpha: 0.05;
  --grid-dot-alpha-max: 0.35;

  color-scheme: light;
}
*, *::before, *::after {
  box-sizing: border-box;
}

* {
  margin: 0;
  padding: 0;
}

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

body {
  min-height: 100vh;
  min-height: 100dvh;
  line-height: var(--line-height-base);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

img, picture, video, canvas, svg {
  display: block;
  max-width: 100%;
}

input, button, textarea, select {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: none;
  cursor: pointer;
}

ul[role="list"], ol[role="list"] {
  list-style: none;
}

a {
  color: inherit;
  text-decoration: none;
}
trix-editor {
  border: 1px solid #bbb;
  border-radius: 3px;
  margin: 0;
  padding: 0.4em 0.6em;
  min-height: 5em;
  outline: none; }

trix-toolbar * {
  box-sizing: border-box; }

trix-toolbar .trix-button-row {
  display: flex;
  flex-wrap: nowrap;
  justify-content: space-between;
  overflow-x: auto; }

trix-toolbar .trix-button-group {
  display: flex;
  margin-bottom: 10px;
  border: 1px solid #bbb;
  border-top-color: #ccc;
  border-bottom-color: #888;
  border-radius: 3px; }
  trix-toolbar .trix-button-group:not(:first-child) {
    margin-left: 1.5vw; }
    @media (max-width: 768px) {
      trix-toolbar .trix-button-group:not(:first-child) {
        margin-left: 0; } }

trix-toolbar .trix-button-group-spacer {
  flex-grow: 1; }
  @media (max-width: 768px) {
    trix-toolbar .trix-button-group-spacer {
      display: none; } }

trix-toolbar .trix-button {
  position: relative;
  float: left;
  color: rgba(0, 0, 0, 0.6);
  font-size: 0.75em;
  font-weight: 600;
  white-space: nowrap;
  padding: 0 0.5em;
  margin: 0;
  outline: none;
  border: none;
  border-bottom: 1px solid #ddd;
  border-radius: 0;
  background: transparent; }
  trix-toolbar .trix-button:not(:first-child) {
    border-left: 1px solid #ccc; }
  trix-toolbar .trix-button.trix-active {
    background: #cbeefa;
    color: black; }
  trix-toolbar .trix-button:not(:disabled) {
    cursor: pointer; }
  trix-toolbar .trix-button:disabled {
    color: rgba(0, 0, 0, 0.125); }
  @media (max-width: 768px) {
    trix-toolbar .trix-button {
      letter-spacing: -0.01em;
      padding: 0 0.3em; } }

trix-toolbar .trix-button--icon {
  font-size: inherit;
  width: 2.6em;
  height: 1.6em;
  max-width: calc(0.8em + 4vw);
  text-indent: -9999px; }
  @media (max-width: 768px) {
    trix-toolbar .trix-button--icon {
      height: 2em;
      max-width: calc(0.8em + 3.5vw); } }
  trix-toolbar .trix-button--icon::before {
    display: inline-block;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    opacity: 0.6;
    content: "";
    background-position: center;
    background-repeat: no-repeat;
    background-size: contain; }
    @media (max-width: 768px) {
      trix-toolbar .trix-button--icon::before {
        right: 6%;
        left: 6%; } }
  trix-toolbar .trix-button--icon.trix-active::before {
    opacity: 1; }
  trix-toolbar .trix-button--icon:disabled::before {
    opacity: 0.125; }

trix-toolbar .trix-button--icon-attach::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M10.5%2018V7.5c0-2.25%203-2.25%203%200V18c0%204.125-6%204.125-6%200V7.5c0-6.375%209-6.375%209%200V18%22%20stroke%3D%22%23000%22%20stroke-width%3D%222%22%20stroke-miterlimit%3D%2210%22%20stroke-linecap%3D%22round%22%20stroke-linejoin%3D%22round%22%2F%3E%3C%2Fsvg%3E");
  top: 8%;
  bottom: 4%; }

trix-toolbar .trix-button--icon-bold::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M6.522%2019.242a.5.5%200%200%201-.5-.5V5.35a.5.5%200%200%201%20.5-.5h5.783c1.347%200%202.46.345%203.24.982.783.64%201.216%201.562%201.216%202.683%200%201.13-.587%202.129-1.476%202.71a.35.35%200%200%200%20.049.613c1.259.56%202.101%201.742%202.101%203.22%200%201.282-.483%202.334-1.363%203.063-.876.726-2.132%201.12-3.66%201.12h-5.89ZM9.27%207.347v3.362h1.97c.766%200%201.347-.17%201.733-.464.38-.291.587-.716.587-1.27%200-.53-.183-.928-.513-1.198-.334-.273-.838-.43-1.505-.43H9.27Zm0%205.606v3.791h2.389c.832%200%201.448-.177%201.853-.497.399-.315.614-.786.614-1.423%200-.62-.22-1.077-.63-1.385-.418-.313-1.053-.486-1.905-.486H9.27Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-italic::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M9%205h6.5v2h-2.23l-2.31%2010H13v2H6v-2h2.461l2.306-10H9V5Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-link::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M18.948%205.258a4.337%204.337%200%200%200-6.108%200L11.217%206.87a.993.993%200%200%200%200%201.41c.392.39%201.027.39%201.418%200l1.623-1.613a2.323%202.323%200%200%201%203.271%200%202.29%202.29%200%200%201%200%203.251l-2.393%202.38a3.021%203.021%200%200%201-4.255%200l-.05-.049a1.007%201.007%200%200%200-1.418%200%20.993.993%200%200%200%200%201.41l.05.049a5.036%205.036%200%200%200%207.091%200l2.394-2.38a4.275%204.275%200%200%200%200-6.072Zm-13.683%2013.6a4.337%204.337%200%200%200%206.108%200l1.262-1.255a.993.993%200%200%200%200-1.41%201.007%201.007%200%200%200-1.418%200L9.954%2017.45a2.323%202.323%200%200%201-3.27%200%202.29%202.29%200%200%201%200-3.251l2.344-2.331a2.579%202.579%200%200%201%203.631%200c.392.39%201.027.39%201.419%200a.993.993%200%200%200%200-1.41%204.593%204.593%200%200%200-6.468%200l-2.345%202.33a4.275%204.275%200%200%200%200%206.072Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-strike::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M6%2014.986c.088%202.647%202.246%204.258%205.635%204.258%203.496%200%205.713-1.728%205.713-4.463%200-.275-.02-.536-.062-.781h-3.461c.398.293.573.654.573%201.123%200%201.035-1.074%201.787-2.646%201.787-1.563%200-2.773-.762-2.91-1.924H6ZM6.432%2010h3.763c-.632-.314-.914-.715-.914-1.273%200-1.045.977-1.739%202.432-1.739%201.475%200%202.52.723%202.617%201.914h2.764c-.05-2.548-2.11-4.238-5.39-4.238-3.145%200-5.392%201.719-5.392%204.316%200%20.363.04.703.12%201.02ZM4%2011a1%201%200%201%200%200%202h15a1%201%200%201%200%200-2H4Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-quote::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M4.581%208.471c.44-.5%201.056-.834%201.758-.995C8.074%207.17%209.201%207.822%2010%208.752c1.354%201.578%201.33%203.555.394%205.277-.941%201.731-2.788%203.163-4.988%203.56a.622.622%200%200%201-.653-.317c-.113-.205-.121-.49.16-.764.294-.286.567-.566.791-.835.222-.266.413-.54.524-.815.113-.28.156-.597.026-.908-.128-.303-.39-.524-.72-.69a3.02%203.02%200%200%201-1.674-2.7c0-.905.283-1.59.72-2.088Zm9.419%200c.44-.5%201.055-.834%201.758-.995%201.734-.306%202.862.346%203.66%201.276%201.355%201.578%201.33%203.555.395%205.277-.941%201.731-2.789%203.163-4.988%203.56a.622.622%200%200%201-.653-.317c-.113-.205-.122-.49.16-.764.294-.286.567-.566.791-.835.222-.266.412-.54.523-.815.114-.28.157-.597.026-.908-.127-.303-.39-.524-.72-.69a3.02%203.02%200%200%201-1.672-2.701c0-.905.283-1.59.72-2.088Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-heading-1::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M21.5%207.5v-3h-12v3H14v13h3v-13h4.5ZM9%2013.5h3.5v-3h-10v3H6v7h3v-7Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-code::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M3.293%2011.293a1%201%200%200%200%200%201.414l4%204a1%201%200%201%200%201.414-1.414L5.414%2012l3.293-3.293a1%201%200%200%200-1.414-1.414l-4%204Zm13.414%205.414%204-4a1%201%200%200%200%200-1.414l-4-4a1%201%200%201%200-1.414%201.414L18.586%2012l-3.293%203.293a1%201%200%200%200%201.414%201.414Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-bullet-list::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M5%207.5a1.5%201.5%200%201%200%200-3%201.5%201.5%200%200%200%200%203ZM8%206a1%201%200%200%201%201-1h11a1%201%200%201%201%200%202H9a1%201%200%200%201-1-1Zm1%205a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm0%206a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm-2.5-5a1.5%201.5%200%201%201-3%200%201.5%201.5%200%200%201%203%200ZM5%2019.5a1.5%201.5%200%201%200%200-3%201.5%201.5%200%200%200%200%203Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-number-list::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M3%204h2v4H4V5H3V4Zm5%202a1%201%200%200%201%201-1h11a1%201%200%201%201%200%202H9a1%201%200%200%201-1-1Zm1%205a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm0%206a1%201%200%201%200%200%202h11a1%201%200%201%200%200-2H9Zm-3.5-7H6v1l-1.5%202H6v1H3v-1l1.667-2H3v-1h2.5ZM3%2017v-1h3v4H3v-1h2v-.5H4v-1h1V17H3Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-undo::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M3%2014a1%201%200%200%200%201%201h6a1%201%200%201%200%200-2H6.257c2.247-2.764%205.151-3.668%207.579-3.264%202.589.432%204.739%202.356%205.174%205.405a1%201%200%200%200%201.98-.283c-.564-3.95-3.415-6.526-6.825-7.095C11.084%207.25%207.63%208.377%205%2011.39V8a1%201%200%200%200-2%200v6Zm2-1Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-redo::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M21%2014a1%201%200%200%201-1%201h-6a1%201%200%201%201%200-2h3.743c-2.247-2.764-5.151-3.668-7.579-3.264-2.589.432-4.739%202.356-5.174%205.405a1%201%200%200%201-1.98-.283c.564-3.95%203.415-6.526%206.826-7.095%203.08-.513%206.534.614%209.164%203.626V8a1%201%200%201%201%202%200v6Zm-2-1Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-decrease-nesting-level::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M5%206a1%201%200%200%201%201-1h12a1%201%200%201%201%200%202H6a1%201%200%200%201-1-1Zm4%205a1%201%200%201%200%200%202h9a1%201%200%201%200%200-2H9Zm-3%206a1%201%200%201%200%200%202h12a1%201%200%201%200%200-2H6Zm-3.707-5.707a1%201%200%200%200%200%201.414l2%202a1%201%200%201%200%201.414-1.414L4.414%2012l1.293-1.293a1%201%200%200%200-1.414-1.414l-2%202Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-button--icon-increase-nesting-level::before {
  background-image: url("data:image/svg+xml,%3Csvg%20width%3D%2224%22%20height%3D%2224%22%20fill%3D%22none%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20fill-rule%3D%22evenodd%22%20clip-rule%3D%22evenodd%22%20d%3D%22M5%206a1%201%200%200%201%201-1h12a1%201%200%201%201%200%202H6a1%201%200%200%201-1-1Zm4%205a1%201%200%201%200%200%202h9a1%201%200%201%200%200-2H9Zm-3%206a1%201%200%201%200%200%202h12a1%201%200%201%200%200-2H6Zm-2.293-2.293%202-2a1%201%200%200%200%200-1.414l-2-2a1%201%200%201%200-1.414%201.414L3.586%2012l-1.293%201.293a1%201%200%201%200%201.414%201.414Z%22%20fill%3D%22%23000%22%2F%3E%3C%2Fsvg%3E"); }

trix-toolbar .trix-dialogs {
  position: relative; }

trix-toolbar .trix-dialog {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  font-size: 0.75em;
  padding: 15px 10px;
  background: #fff;
  box-shadow: 0 0.3em 1em #ccc;
  border-top: 2px solid #888;
  border-radius: 5px;
  z-index: 5; }

trix-toolbar .trix-input--dialog {
  font-size: inherit;
  font-weight: normal;
  padding: 0.5em 0.8em;
  margin: 0 10px 0 0;
  border-radius: 3px;
  border: 1px solid #bbb;
  background-color: #fff;
  box-shadow: none;
  outline: none;
  -webkit-appearance: none;
  -moz-appearance: none; }
  trix-toolbar .trix-input--dialog.validate:invalid {
    box-shadow: #F00 0px 0px 1.5px 1px; }

trix-toolbar .trix-button--dialog {
  font-size: inherit;
  padding: 0.5em;
  border-bottom: none; }

trix-toolbar .trix-dialog--link {
  max-width: 600px; }

trix-toolbar .trix-dialog__link-fields {
  display: flex;
  align-items: baseline; }
  trix-toolbar .trix-dialog__link-fields .trix-input {
    flex: 1; }
  trix-toolbar .trix-dialog__link-fields .trix-button-group {
    flex: 0 0 content;
    margin: 0; }

trix-editor [data-trix-mutable]:not(.attachment__caption-editor) {
  -webkit-user-select: none;
  -moz-user-select: none;
  -ms-user-select: none;
  user-select: none; }

trix-editor [data-trix-mutable]::-moz-selection,
trix-editor [data-trix-cursor-target]::-moz-selection, trix-editor [data-trix-mutable] ::-moz-selection {
  background: none; }

trix-editor [data-trix-mutable]::selection,
trix-editor [data-trix-cursor-target]::selection, trix-editor [data-trix-mutable] ::selection {
  background: none; }

trix-editor .attachment__caption-editor:focus[data-trix-mutable]::-moz-selection {
  background: highlight; }

trix-editor .attachment__caption-editor:focus[data-trix-mutable]::selection {
  background: highlight; }

trix-editor [data-trix-mutable].attachment.attachment--file {
  box-shadow: 0 0 0 2px highlight;
  border-color: transparent; }

trix-editor [data-trix-mutable].attachment img {
  box-shadow: 0 0 0 2px highlight; }

trix-editor .attachment {
  position: relative; }
  trix-editor .attachment:hover {
    cursor: default; }

trix-editor .attachment--preview .attachment__caption:hover {
  cursor: text; }

trix-editor .attachment__progress {
  position: absolute;
  z-index: 1;
  height: 20px;
  top: calc(50% - 10px);
  left: 5%;
  width: 90%;
  opacity: 0.9;
  transition: opacity 200ms ease-in; }
  trix-editor .attachment__progress[value="100"] {
    opacity: 0; }

trix-editor .attachment__caption-editor {
  display: inline-block;
  width: 100%;
  margin: 0;
  padding: 0;
  font-size: inherit;
  font-family: inherit;
  line-height: inherit;
  color: inherit;
  text-align: center;
  vertical-align: top;
  border: none;
  outline: none;
  -webkit-appearance: none;
  -moz-appearance: none; }

trix-editor .attachment__toolbar {
  position: absolute;
  z-index: 1;
  top: -0.9em;
  left: 0;
  width: 100%;
  text-align: center; }

trix-editor .trix-button-group {
  display: inline-flex; }

trix-editor .trix-button {
  position: relative;
  float: left;
  color: #666;
  white-space: nowrap;
  font-size: 80%;
  padding: 0 0.8em;
  margin: 0;
  outline: none;
  border: none;
  border-radius: 0;
  background: transparent; }
  trix-editor .trix-button:not(:first-child) {
    border-left: 1px solid #ccc; }
  trix-editor .trix-button.trix-active {
    background: #cbeefa; }
  trix-editor .trix-button:not(:disabled) {
    cursor: pointer; }

trix-editor .trix-button--remove {
  text-indent: -9999px;
  display: inline-block;
  padding: 0;
  outline: none;
  width: 1.8em;
  height: 1.8em;
  line-height: 1.8em;
  border-radius: 50%;
  background-color: #fff;
  border: 2px solid highlight;
  box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.25); }
  trix-editor .trix-button--remove::before {
    display: inline-block;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    left: 0;
    opacity: 0.7;
    content: "";
    background-image: url("data:image/svg+xml,%3Csvg%20height%3D%2224%22%20width%3D%2224%22%20xmlns%3D%22http%3A%2F%2Fwww.w3.org%2F2000%2Fsvg%22%3E%3Cpath%20d%3D%22M19%206.41%2017.59%205%2012%2010.59%206.41%205%205%206.41%2010.59%2012%205%2017.59%206.41%2019%2012%2013.41%2017.59%2019%2019%2017.59%2013.41%2012z%22%2F%3E%3Cpath%20d%3D%22M0%200h24v24H0z%22%20fill%3D%22none%22%2F%3E%3C%2Fsvg%3E");
    background-position: center;
    background-repeat: no-repeat;
    background-size: 90%; }
  trix-editor .trix-button--remove:hover {
    border-color: #333; }
    trix-editor .trix-button--remove:hover::before {
      opacity: 1; }

trix-editor .attachment__metadata-container {
  position: relative; }

trix-editor .attachment__metadata {
  position: absolute;
  left: 50%;
  top: 2em;
  transform: translate(-50%, 0);
  max-width: 90%;
  padding: 0.1em 0.6em;
  font-size: 0.8em;
  color: #fff;
  background-color: rgba(0, 0, 0, 0.7);
  border-radius: 3px; }
  trix-editor .attachment__metadata .attachment__name {
    display: inline-block;
    max-width: 100%;
    vertical-align: bottom;
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap; }
  trix-editor .attachment__metadata .attachment__size {
    margin-left: 0.2em;
    white-space: nowrap; }

.trix-content {
  line-height: 1.5;
  overflow-wrap: break-word;
  word-break: break-word; }
  .trix-content * {
    box-sizing: border-box;
    margin: 0;
    padding: 0; }
  .trix-content h1 {
    font-size: 1.2em;
    line-height: 1.2; }
  .trix-content blockquote {
    border: 0 solid #ccc;
    border-left-width: 0.3em;
    margin-left: 0.3em;
    padding-left: 0.6em; }
  .trix-content [dir=rtl] blockquote,
  .trix-content blockquote[dir=rtl] {
    border-width: 0;
    border-right-width: 0.3em;
    margin-right: 0.3em;
    padding-right: 0.6em; }
  .trix-content li {
    margin-left: 1em; }
  .trix-content [dir=rtl] li {
    margin-right: 1em; }
  .trix-content pre {
    display: inline-block;
    width: 100%;
    vertical-align: top;
    font-family: monospace;
    font-size: 0.9em;
    padding: 0.5em;
    white-space: pre;
    background-color: #eee;
    overflow-x: auto; }
  .trix-content img {
    max-width: 100%;
    height: auto; }
  .trix-content .attachment {
    display: inline-block;
    position: relative;
    max-width: 100%; }
    .trix-content .attachment a {
      color: inherit;
      text-decoration: none; }
      .trix-content .attachment a:hover, .trix-content .attachment a:visited:hover {
        color: inherit; }
  .trix-content .attachment__caption {
    text-align: center; }
    .trix-content .attachment__caption .attachment__name + .attachment__size::before {
      content: ' \2022 '; }
  .trix-content .attachment--preview {
    width: 100%;
    text-align: center; }
    .trix-content .attachment--preview .attachment__caption {
      color: #666;
      font-size: 0.9em;
      line-height: 1.2; }
  .trix-content .attachment--file {
    color: #333;
    line-height: 1;
    margin: 0 2px 2px 2px;
    padding: 0.4em 1em;
    border: 1px solid #bbb;
    border-radius: 5px; }
  .trix-content .attachment-gallery {
    display: flex;
    flex-wrap: wrap;
    position: relative; }
    .trix-content .attachment-gallery .attachment {
      flex: 1 0 33%;
      padding: 0 0.5em;
      max-width: 33%; }
    .trix-content .attachment-gallery.attachment-gallery--2 .attachment, .trix-content .attachment-gallery.attachment-gallery--4 .attachment {
      flex-basis: 50%;
      max-width: 50%; }
/*
 * Provides a drop-in pointer for the default Trix stylesheet that will format the toolbar and
 * the trix-editor content (whether displayed or under editing). Feel free to incorporate this
 * inclusion directly in any other asset bundle and remove this file.
 *

*/

/*
 * We need to override trix.css’s image gallery styles to accommodate the
 * <action-text-attachment> element we wrap around attachments. Otherwise,
 * images in galleries will be squished by the max-width: 33%; rule.
*/
.trix-content .attachment-gallery > action-text-attachment,
.trix-content .attachment-gallery > .attachment {
  flex: 1 0 33%;
  padding: 0 0.5em;
  max-width: 33%;
}

.trix-content .attachment-gallery.attachment-gallery--2 > action-text-attachment,
.trix-content .attachment-gallery.attachment-gallery--2 > .attachment, .trix-content .attachment-gallery.attachment-gallery--4 > action-text-attachment,
.trix-content .attachment-gallery.attachment-gallery--4 > .attachment {
  flex-basis: 50%;
  max-width: 50%;
}

.trix-content action-text-attachment .attachment {
  padding: 0 !important;
  max-width: 100% !important;
}
/* The whitespace-include attribute selector ([data-controller~="reveal"])
   matches any element where "reveal" is one of the space-separated values
   in data-controller, so reveal composes cleanly with other Stimulus
   controllers on the same element (e.g. data-controller="reveal cursor-glow").
   Don't "fix" to data-controller="reveal" — that silently breaks composition. */

[data-controller~="reveal"] {
  opacity: 0;
  transform: translateY(18px);
  transition: opacity 600ms ease-out, transform 600ms ease-out;
  will-change: opacity, transform;
}

[data-controller~="reveal"].in {
  opacity: 1;
  transform: none;
}

@media (prefers-reduced-motion: reduce) {
  [data-controller~="reveal"] {
    transition: none;
  }
}
/* Public-layout shell (Sprint 4B.1).
   Translated from design/CKS_Landing.html for the bg_grid placement,
   cursor-glow placement, content wrapper, sticky header, and footer scaffold.
   The hero, sections, services grid, articles, how-we-work, work-with-us,
   and reveal styles ship in subsequent 4B tasks alongside their content.

   Color values use design tokens from tokens.css. Translucent overlays of
   background or text colors use color-mix(in srgb, ...) so they follow the
   theme automatically — the prototype's literal rgba(10, 10, 11, 0.55) maps
   to color-mix(in srgb, var(--color-background) 55%, transparent) and
   becomes the off-white equivalent in light mode without per-mode rules. */

/* In-page anchor offset. The .nv-w header is position: sticky, so a plain
   anchor jump lands the target's top edge under the header. scroll-padding-top
   on the root element makes anchor scrolling and Tab-focus scroll account for
   the sticky header height across every public page. */
html {
  scroll-padding-top: clamp(72px, 9vw, 96px);
}

/* Background layers — bg_grid sits at z 0, cursor-glow at z 1, content at z 2. */
.bg-grid {
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: var(--color-background);
}

.bg-grid canvas {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
}

.bg-grid::after {
  content: '';
  position: absolute;
  inset: 0;
  pointer-events: none;
  background: radial-gradient(
    ellipse at 50% 0%,
    transparent 0%,
    color-mix(in srgb, var(--color-background) 55%, transparent) 70%,
    color-mix(in srgb, var(--color-background) 85%, transparent) 100%
  );
}

.cursor-glow {
  position: fixed;
  z-index: 1;
  width: 520px;
  height: 520px;
  border-radius: 50%;
  pointer-events: none;
  transform: translate(-50%, -50%);
}

/* Content wrapper — establishes z-index 2 above the background layers and
   sets the editorial typography baseline. The mono utility class lets
   specific elements opt back into JetBrains Mono. */
.fr {
  position: relative;
  z-index: 2;
  color: var(--color-text);
  font-family: var(--font-serif);
  font-feature-settings: "ss01", "onum";
}

.mn {
  font-family: var(--font-mono);
}

.in {
  max-width: 1280px;
  margin: 0 auto;
  padding: 0 64px;
}

@media (max-width: 768px) {
  .in {
    padding: 0 24px;
  }
}

/* Sticky header. Translucent backdrop (color-mix derives from the active
   theme background), faint hairline below, blur on scroll content beneath. */
.nv-w {
  position: sticky;
  top: 0;
  z-index: 50;
  background: color-mix(in srgb, var(--color-background) 55%, transparent);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  border-bottom: 0.5px solid var(--color-hairline-faint);
}

.nv {
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 22px 0;
  font-size: 13px;
}

.bd {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  letter-spacing: 0.01em;
  color: var(--color-text);
  text-decoration: none;
  /* Keep "<brand name>" on one line at every viewport — the
     mark-then-name pattern reads as a unit and breaks visually if
     the words wrap mid-line. nv flex-wrap drops the whole brand to
     its own row before any character wrap happens. */
  white-space: nowrap;
}

.bd .mark {
  position: relative;
  display: inline-block;
  width: 10px;
  height: 10px;
  background: var(--color-text);
}

.bd .mark::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--color-background);
  transform: scaleX(0.5);
  transform-origin: right;
}

.lk-row {
  display: flex;
  gap: 32px;
  align-items: center;
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--color-text-tertiary);
}

.lk-row a {
  color: inherit;
  text-decoration: none;
  transition: color 0.2s;
}

.lk-row a:hover {
  color: var(--color-text);
}

/* Theme toggle inside the nav row. Sized to match link visual weight. */
.lk-row .theme-toggle {
  display: inline-flex;
  align-items: center;
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--color-text-tertiary);
  cursor: pointer;
  transition: color 0.2s;
}

.lk-row .theme-toggle:hover {
  color: var(--color-text);
}

/* Hamburger button. Hidden at >=768px (the horizontal nav fits); on
   phones it sits next to the brand and toggles the drawer below. Three
   stacked bars with a 1px hairline weight matching the rest of the
   editorial chrome. */
.nv-burger {
  display: none;
  flex-direction: column;
  justify-content: center;
  gap: 5px;
  width: 28px;
  height: 28px;
  padding: 0;
  border: none;
  background: transparent;
  color: var(--color-text);
  cursor: pointer;
}

.nv-burger-bar {
  display: block;
  width: 18px;
  height: 1px;
  background: currentColor;
  transition: transform 0.18s ease, opacity 0.18s ease;
}

/* Open state: morph the three bars into an X. Top bar rotates down,
   middle fades, bottom rotates up. The translateY values offset the
   rotation pivot so the X centers cleanly on the button. */
.nv[data-open="true"] .nv-burger-bar:nth-child(1) {
  transform: translateY(6px) rotate(45deg);
}
.nv[data-open="true"] .nv-burger-bar:nth-child(2) {
  opacity: 0;
}
.nv[data-open="true"] .nv-burger-bar:nth-child(3) {
  transform: translateY(-6px) rotate(-45deg);
}

@media (max-width: 768px) {
  .nv {
    flex-wrap: wrap;
    row-gap: 10px;
  }
  .nv-burger {
    display: flex;
    margin-left: auto;
  }
  /* Drawer state — collapse the link row by default and show only when
     the Stimulus controller flips data-open. width: 100% pushes the
     drawer to its own row below the brand+burger; flex-direction column
     stacks the links vertically with comfortable tap targets. */
  .lk-row {
    display: none;
    flex-direction: column;
    align-items: flex-start;
    gap: 18px;
    font-size: 14px;
    width: 100%;
    padding: 8px 0 12px;
  }
  .nv[data-open="true"] .lk-row {
    display: flex;
  }
  .lk-row .theme-toggle {
    margin-top: 4px;
  }
}

/* Hero (4B.1 shell, 4B.3 ships the real headline / lead / CTA pair). */
.he {
  padding: clamp(80px, 12vw, 160px) 0 clamp(80px, 11vw, 140px);
  position: relative;
}

.he-eyebrow {
  display: flex;
  align-items: center;
  gap: 14px;
  margin: 0 0 36px;
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-text-tertiary);
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.he-eyebrow .ln {
  flex: 0 0 56px;
  height: 0.5px;
  background: var(--color-hairline-strong);
}

.he h1 {
  margin: 0 0 clamp(28px, 3.5vw, 44px);
  font-size: clamp(44px, 7.5vw, 96px);
  line-height: 1.0;
  letter-spacing: -0.028em;
  font-weight: 400;
  max-width: 980px;
}

.he h1 em {
  font-style: italic;
  font-weight: 400;
  color: var(--color-text);
}

.he h1 .car {
  display: inline-block;
  width: 0.06em;
  height: 0.85em;
  margin-left: 0.04em;
  vertical-align: -0.05em;
  background: var(--color-text);
  animation: blink 1.05s steps(2) infinite;
}

@keyframes blink {
  50% { opacity: 0; }
}

.he .ld {
  margin: 0 0 clamp(40px, 5vw, 56px);
  font-size: clamp(16px, 1.55vw, 21px);
  line-height: 1.55;
  color: var(--color-text-secondary);
  max-width: 600px;
}

.cta {
  display: flex;
  gap: 28px;
  align-items: center;
  flex-wrap: wrap;
}

/* Hero CTA button. The ::before pseudo-element slides up on hover to reveal
   the inverse color, with the inner <span> sitting at z-index 1 so its text
   color can transition independently. The token color flip means the button
   inverts correctly in both dark and light modes. */
.btn {
  display: inline-block;
  position: relative;
  overflow: hidden;
  padding: 15px 28px;
  border: none;
  background: var(--color-text);
  color: var(--color-background);
  font-family: var(--font-mono);
  font-size: 14px;
  letter-spacing: 0.01em;
  text-decoration: none;
  cursor: pointer;
  transition: transform 0.2s;
}

.btn:hover {
  transform: translateY(-1px);
}

.btn::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--color-background);
  transform: translateY(101%);
  transition: transform 0.35s cubic-bezier(0.7, 0, 0.3, 1);
}

.btn:hover::before {
  transform: translateY(0);
}

.btn span {
  position: relative;
  z-index: 1;
  transition: color 0.35s;
}

.btn:hover span {
  color: var(--color-text);
}

.lk {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 4px;
  font-size: 15px;
}

@media (prefers-reduced-motion: reduce) {
  .he h1 .car {
    animation: none;
  }
}

/* Section primitive — every editorial section after the hero uses .sc as the
   wrapper. Top hairline divides sections; padding clamp scales with viewport.
   The .bo class is a generic body paragraph used by section intros (services,
   recent writing); shipping it here alongside its first consumer keeps the
   prototype-CSS translation grouped. */
.sc {
  padding: clamp(72px, 10vw, 128px) 0;
  border-top: 0.5px solid var(--color-hairline-soft);
  position: relative;
}

.sc h2 {
  margin: 0 0 36px;
  font-size: clamp(32px, 4.5vw, 60px);
  line-height: 1.08;
  letter-spacing: -0.022em;
  font-weight: 400;
  max-width: 820px;
}

.sc h2 em {
  font-style: italic;
  font-weight: 400;
}

.bo {
  margin: 0 0 16px;
  font-size: clamp(15px, 1.3vw, 18px);
  line-height: 1.65;
  color: var(--color-text-secondary);
  max-width: 620px;
}

.bo:last-child {
  margin-bottom: 0;
}

/* Shift section — two-column framing. Heading left, three-paragraph body
   right. Collapses to single-column at 1100px (wider than the 900px we
   originally set, and meaningfully wider than the 768px mobile breakpoint:
   the heading is long enough that columns at 768-1100px get to ~4 words
   per line, which reads worse than a stacked single-column at the same
   viewport). The gap also clamps so there's some breathing room even at
   the desktop floor. */
.shift {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(48px, 7vw, 96px);
  align-items: start;
}

.shift h2 {
  margin: 0;
  max-width: 100%;
}

.shift-bd p {
  margin: 0 0 18px;
  font-size: clamp(15px, 1.25vw, 17px);
  line-height: 1.7;
  color: var(--color-text-secondary);
}

.shift-bd p:last-child {
  margin: 0;
}

@media (max-width: 1100px) {
  .shift {
    grid-template-columns: 1fr;
    gap: 32px;
  }
}

/* Services grid (4B.5). Two-by-two card grid at desktop, single column at
   <=768px. Cards are anchor elements (the whole card is clickable) with a
   subtle var(--color-stripe) hover tint. */
.svs2 {
  display: grid;
  grid-template-columns: 1fr 1fr;
  margin-top: 64px;
  position: relative;
}

.sv2 {
  display: block;
  position: relative;
  padding: 52px 44px 48px;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.2s;
}

.sv2:hover {
  background: var(--color-stripe);
}

.sv2 .num {
  position: absolute;
  top: 22px;
  right: 26px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--color-text-quaternary);
  letter-spacing: 0.08em;
}

.sv2 svg {
  display: block;
  width: 30px;
  height: 30px;
  margin-bottom: 28px;
}

.sv2 h3 {
  position: relative;
  margin: 0 0 16px;
  font-size: clamp(22px, 2.4vw, 30px);
  font-weight: 400;
  letter-spacing: -0.018em;
  transition: font-style 0.2s;
}

.sv2:hover h3 {
  font-style: italic;
}

.sv2 p {
  position: relative;
  margin: 0 0 24px;
  font-size: clamp(14px, 1.15vw, 15.5px);
  line-height: 1.6;
  color: var(--color-text-secondary);
  max-width: 380px;
}

.sv2 .arr2 {
  position: relative;
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--color-text-tertiary);
  letter-spacing: 0.04em;
  transition: color 0.2s, letter-spacing 0.3s;
}

.sv2:hover .arr2 {
  color: var(--color-text);
  letter-spacing: 0.08em;
}

@media (max-width: 768px) {
  .svs2 {
    grid-template-columns: 1fr;
  }
  .sv2 {
    padding: 36px 0 36px;
  }
  .sv2 p {
    max-width: 100%;
  }
  .sv2 .num {
    right: 0;
  }
}

@media (prefers-reduced-motion: reduce) {
  .sv2,
  .sv2 h3,
  .sv2 .arr2 {
    transition: none;
  }
}

/* Home "How we work." numbered steps. Four .hww-steps in a row at desktop,
   single column at mobile. The .hww::before timeline is a single hairline
   running between the dots — combined with the four .hww-dot circles it
   reads as a milestone path. */
.hww {
  --num: clamp(44px, 5.4vw, 72px);
  --col-gap: 48px;
  position: relative;
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  column-gap: var(--col-gap);
  margin-top: 72px;
}

.hww::before {
  content: '';
  position: absolute;
  top: calc(var(--num) + 32px + 4.5px);
  left: 4.5px;
  right: calc((100% - 3 * var(--col-gap)) / 4 - 4.5px);
  height: 1px;
  background: var(--color-hairline-strong);
}

.hww-step {
  display: flex;
  flex-direction: column;
}

.hww-num {
  margin: 0 0 32px;
  font-size: var(--num);
  font-style: italic;
  font-weight: 400;
  line-height: 1;
  color: var(--color-text-tertiary);
}

.hww-dot {
  position: relative;
  z-index: 2;
  width: 9px;
  height: 9px;
  margin-bottom: 36px;
  border-radius: 50%;
  background: var(--color-text);
}

.hww-h {
  margin: 0 0 14px;
  font-size: clamp(18px, 1.65vw, 22px);
  font-weight: 400;
  letter-spacing: -0.005em;
}

.hww-p {
  margin: 0;
  font-size: clamp(14px, 1.15vw, 15.5px);
  line-height: 1.6;
  color: var(--color-text-secondary);
}

@media (max-width: 900px) {
  .hww {
    grid-template-columns: 1fr;
    column-gap: 0;
  }

  .hww::before {
    display: none;
  }

  .hww-step {
    padding: 32px 0 36px;
    border-top: 0.5px solid var(--color-hairline);
  }

  .hww-step:first-child {
    padding-top: 0;
    border-top: none;
  }

  .hww-num {
    margin-bottom: 14px;
    font-size: 36px;
  }

  .hww-dot {
    display: none;
  }
}

/* Home "Work with us." two-column block. Left: heading + lede.
   Right (.wk-o): stacked .wr contact rows separated by hairlines. */
.wk {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 80px;
  align-items: start;
}

.wk-o {
  padding-top: 14px;
}

.wr {
  padding: 28px 0;
  border-top: 0.5px solid var(--color-hairline);
}

.wr:last-child {
  border-bottom: 0.5px solid var(--color-hairline);
}

.wr h4 {
  margin: 0 0 8px;
  font-size: 18px;
  font-weight: 400;
  letter-spacing: -0.005em;
}

.wr h4 a {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 4px;
}

.wr p {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--color-text-tertiary);
}

@media (max-width: 900px) {
  .wk {
    grid-template-columns: 1fr;
    gap: 32px;
  }
}

/* Service detail pages (4B.6) — full editorial pages, not heroes. All four
   content blocks (h1, body, CTA, howto) share a centered 65ch column inside
   the .in wrapper, matching the .post precedent from Sprint 1. The first
   body paragraph is upsized via :first-child to act as the positioning
   lede. "How an engagement starts" sits in the same section, separated by
   a hairline. */
.detail {
  padding: clamp(72px, 10vw, 128px) 0;
}

.detail h1,
.detail-bd,
.detail-cta,
.detail-howto {
  max-width: 65ch;
  margin-left: auto;
  margin-right: auto;
}

.detail h1 {
  margin-top: 0;
  margin-bottom: clamp(36px, 4vw, 48px);
  font-size: clamp(44px, 5.5vw, 72px);
  line-height: 1.05;
  letter-spacing: -0.025em;
  font-weight: 400;
}

.detail-bd p {
  margin: 0 0 24px;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.65;
  color: var(--color-text-secondary);
}

/* The lede treatment fires only on the first .detail-bd inside a non-essay
   .detail page. Service detail pages each render a single .detail-bd and
   pick this up to upsize their positioning lede. Essay-form pages opt out
   via .detail-essay so a six-section manifesto reads as one continuous
   register rather than re-introducing a 24px paragraph at every break. */
.detail:not(.detail-essay) .detail-bd:first-of-type p:first-child {
  margin-bottom: 36px;
  font-size: clamp(20px, 1.7vw, 24px);
  line-height: 1.45;
  color: var(--color-text);
}

/* Manifesto section breaks. Short centered editorial mark — present to give
   the eye a rest between unmarked sections, not to impose hierarchy. Scoped
   inside .in so it doesn't catch <hr> that may appear inside a future Action
   Text body rendered through a .detail ancestor. */
.detail .in > hr {
  width: 80px;
  height: 0;
  border: 0;
  border-top: 0.5px solid var(--color-hairline-soft);
  margin: clamp(48px, 5vw, 72px) auto;
}

.detail-cta {
  margin-top: clamp(32px, 4vw, 48px);
  margin-bottom: clamp(48px, 5vw, 72px);
}

/* Print-essay signature line, used in two places — the foot of the manifesto
   closing section (.manifesto-byline) and the foot of each public blog post
   (.post-signature). Right-aligned within the same 65ch column the body
   prose runs in, italic and tertiary so it reads as a quiet signature rather
   than a structural heading. The manifesto consumer sits inside the closing
   .detail-bd so it shares that section's reveal mount; the post consumer
   ships always-visible since the post show partial has no reveal cascade. */
.manifesto-byline,
.post-signature {
  max-width: 65ch;
  margin: clamp(48px, 5vw, 72px) auto 0;
  text-align: center;
  /* Sized to match the body type (16-19px) so the bold reads visibly
     at the close. Earlier 14-15px got accidentally overridden on the
     manifesto by `.detail-bd p`'s higher specificity, which made the
     manifesto's signature look correctly sized while the post one
     stayed visually undersized — operator-confirmed visual mismatch. */
  font-size: clamp(16px, 1.4vw, 19px);
  font-style: italic;
  font-weight: var(--font-weight-bold);
  line-height: 1.5;
  /* Matches what the manifesto byline already renders at (its color was
     winning via `.detail-bd p`'s higher specificity, not via this rule).
     Setting --color-text-secondary here makes the post signature render
     identically — both signatures now visibly bold + slightly darker. */
  color: var(--color-text-secondary);
}

/* The manifesto closes a longer-form essay than the average post and
   benefits from extra vertical breathing room above the signature so
   it reads as a deliberate sign-off rather than tagged onto the body. */
.manifesto-byline {
  margin-top: clamp(96px, 11vw, 144px);
}

.detail-howto {
  padding-top: clamp(40px, 4vw, 56px);
  border-top: 0.5px solid var(--color-hairline-soft);
}

.detail-howto h2 {
  margin: 0 0 18px;
  font-size: clamp(22px, 2vw, 28px);
  line-height: 1.2;
  letter-spacing: -0.018em;
  font-weight: 400;
}

.detail-howto p {
  margin: 0;
  font-size: clamp(15px, 1.25vw, 17px);
  line-height: 1.7;
  color: var(--color-text-secondary);
}

/* Footer scaffold — populated in 4B.12. */
.ft-w {
  border-top: 0.5px solid var(--color-hairline);
  margin-top: 80px;
}

.ft {
  padding: 64px 0 36px;
}

.ft-g {
  display: grid;
  grid-template-columns: 1.6fr 1fr 1fr 1fr;
  gap: 48px;
  margin-bottom: 56px;
}

.ft-c h5 {
  margin: 0 0 18px;
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 400;
  color: var(--color-text-quaternary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.ft-c ul {
  list-style: none;
  padding: 0;
  margin: 0;
}

.ft-c li {
  margin-bottom: 10px;
  font-size: 14px;
}

.ft-c li a {
  color: inherit;
  text-decoration: none;
  transition: color 0.2s;
}

.ft-c li a:hover {
  color: var(--color-text);
}

.ft-b p {
  max-width: 280px;
  margin: 14px 0 0;
  font-size: 14px;
  line-height: 1.55;
  color: var(--color-text-tertiary);
}

.ft-bot {
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  padding-top: 28px;
  border-top: 0.5px solid var(--color-hairline-faint);
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-text-tertiary);
  letter-spacing: 0.02em;
}

@media (max-width: 768px) {
  .ft-g {
    grid-template-columns: 1fr 1fr;
    gap: 32px;
    margin-bottom: 40px;
  }
  .ft-bot {
    flex-direction: column;
    align-items: flex-start;
  }
  .ft-w {
    margin-top: 56px;
  }
}

/* Below 480px the two-column footer grid gets too tight — drop to a
   single column so each section header has full width to breathe. */
@media (max-width: 480px) {
  .ft-g {
    grid-template-columns: 1fr;
    gap: 28px;
  }
}

/* Editorial-list family (Sprint 4B.14 audit). Shared base for the centered
   editorial-column pages: /readings/books, /readings/resources, /services,
   /readings, /writings (and /writings/tag/:slug). All five share the same
   outer rhythm — 72–128px vertical padding, 44–72px h1 centered on a 65ch
   column, repeating <article> entries below — so the rhythm lives here
   and per-page blocks carry only their genuine overrides (per-entry meta
   treatment, .readings-lead, .books-footer, .writings-pagination, the
   .services-index-num eyebrow positioning, entry margin variants on
   .readings).

   Additive: each consumer keeps its per-page wrapper class
   (.books / .resources / .services-index / .readings / .writings) and adds
   "editorial-list" alongside, so existing rules and request-spec class
   assertions continue to work without churn. The per-page selector remains
   the right place to override anything genuinely page-specific. */
.editorial-list {
  padding: clamp(72px, 10vw, 128px) 0;
}

.editorial-list h1 {
  max-width: 65ch;
  margin: 0 auto clamp(36px, 4vw, 48px);
  font-size: clamp(44px, 5.5vw, 72px);
  line-height: 1.05;
  letter-spacing: -0.025em;
  font-weight: 400;
}

/* Entry-h2-as-link convention. Books entries have plain <h2>title</h2>;
   the other four pages render <h2><a href>...</a></h2> with this exact
   color-text / no-underline-at-rest / underline-on-hover treatment. The
   .readings-lead h2 a (featured manifesto callout) shares the same rule.
   Sized per-page (services/readings/writings entry h2 differ from lead
   h2 sizing). */
.editorial-list article h2 a {
  color: var(--color-text);
  text-decoration: none;
}

.editorial-list article h2 a:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Books page (/readings/books). 23-entry editorial list. */
.books-intro,
.books-list,
.books-footer {
  max-width: 65ch;
  margin-left: auto;
  margin-right: auto;
}

.books-intro {
  margin-bottom: clamp(56px, 7vw, 80px);
}

.books-intro p {
  margin: 0 0 24px;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.65;
  color: var(--color-text-secondary);
}

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

.book-entry {
  margin-bottom: clamp(40px, 5vw, 56px);
}

.book-entry:last-child {
  margin-bottom: 0;
}

.book-entry h2 {
  margin: 0 0 6px;
  font-size: clamp(22px, 2vw, 28px);
  line-height: 1.2;
  letter-spacing: -0.015em;
  font-weight: 400;
}

.book-meta {
  margin: 0 0 16px;
  font-size: clamp(14px, 1.1vw, 15px);
  font-style: italic;
  color: var(--color-text-tertiary);
}

.book-entry p:not(.book-meta) {
  margin: 0;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.65;
  color: var(--color-text-secondary);
}

.books-footer {
  margin-top: clamp(56px, 7vw, 80px);
  font-size: clamp(14px, 1.15vw, 15.5px);
  font-style: italic;
  color: var(--color-text-tertiary);
}

.books-footer a {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Resources placeholder page (/readings/resources). Header plus a single
   framing paragraph; real entries land in later commits as they earn the
   list. Page-specific styling is just the intro centering and link color;
   everything structural is in .editorial-list. */
.resources-intro {
  max-width: 65ch;
  margin-left: auto;
  margin-right: auto;
}

.resources-intro p {
  margin: 0 0 24px;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.65;
  color: var(--color-text-secondary);
}

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

.resources-intro a {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* /services index — canonical Services destination. The home page services
   grid (.svs2) stays as the home preview; this page is the listing. Each
   entry carries a numeric eyebrow (.services-index-num) above the h2,
   distinguishing it from the books/writings convention where the meta line
   sits below the title. */
.services-index-intro,
.services-index-list {
  max-width: 65ch;
  margin-left: auto;
  margin-right: auto;
}

.services-index-intro {
  margin-bottom: clamp(56px, 7vw, 80px);
}

.services-index-intro p {
  margin: 0;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.65;
  color: var(--color-text-secondary);
}

.services-index-entry {
  margin-bottom: clamp(40px, 5vw, 56px);
}

.services-index-entry:last-child {
  margin-bottom: 0;
}

.services-index-num {
  margin: 0 0 6px;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

.services-index-entry h2 {
  margin: 0 0 12px;
  font-size: clamp(22px, 2vw, 28px);
  line-height: 1.2;
  letter-spacing: -0.015em;
  font-weight: 400;
}

.services-index-entry p:not(.services-index-num) {
  margin: 0 0 12px;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.65;
  color: var(--color-text-secondary);
}

.services-index-entry p:last-child {
  margin-bottom: 0;
}

/* Readings index page (/readings). Editorial discovery surface linking
   the manifesto + writings + books + resources. The manifesto sits in a
   featured .readings-lead block (with hairline-soft borders top/bottom)
   above the .readings-list of three entries. Tighter entry margins than
   the other editorial-list pages — readings is a directory, not a long
   list. */
.readings-intro,
.readings-lead,
.readings-list {
  max-width: 65ch;
  margin-left: auto;
  margin-right: auto;
}

.readings-intro {
  margin-bottom: clamp(48px, 6vw, 72px);
}

.readings-intro p {
  margin: 0;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.65;
  color: var(--color-text-secondary);
}

/* Featured manifesto callout. Sits above the entry list with a soft
   hairline frame, eyebrow above the heading, and a CTA below the body —
   distinct enough to read as the lead without a heavy box treatment. */
.readings-lead {
  margin-bottom: clamp(56px, 7vw, 80px);
  padding: clamp(28px, 3vw, 36px) 0;
  border-top: 0.5px solid var(--color-hairline-soft);
  border-bottom: 0.5px solid var(--color-hairline-soft);
}

.readings-lead-eyebrow {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
  text-transform: uppercase;
}

.readings-lead h2 {
  margin: 0 0 14px;
  font-size: clamp(26px, 2.6vw, 34px);
  line-height: 1.15;
  letter-spacing: -0.018em;
  font-weight: 400;
}

.readings-lead p:not(.readings-lead-eyebrow):not(.readings-lead-cta) {
  margin: 0 0 18px;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.6;
  color: var(--color-text-secondary);
}

.readings-lead-cta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
}

.readings-lead-cta a {
  color: var(--color-text);
}

.readings-entry {
  margin-bottom: clamp(36px, 4vw, 48px);
}

.readings-entry:last-child {
  margin-bottom: 0;
}

.readings-entry h2 {
  margin: 0 0 8px;
  font-size: clamp(22px, 2vw, 28px);
  line-height: 1.2;
  letter-spacing: -0.015em;
  font-weight: 400;
}

.readings-entry p {
  margin: 0;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.65;
  color: var(--color-text-secondary);
}

/* Writings index (/writings) and tag pages (/writings/tag/:slug). Repeating
   editorial entries with no dividers between, mono meta and tag rows in
   tertiary text. Tag pages get the "Tag" eyebrow above the heading and
   otherwise share the wrapper. Show partial remains on the .post / .post-*
   family in application.css per the no-regression rule. */
.writings-eyebrow,
.writings-list,
.writings-empty,
.writings-pagination {
  max-width: 65ch;
  margin-left: auto;
  margin-right: auto;
}

.writings-eyebrow {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
  text-transform: uppercase;
}

.writings-list {
  margin-bottom: clamp(48px, 6vw, 72px);
}

.writings-entry {
  margin-bottom: clamp(40px, 5vw, 56px);
}

.writings-entry:last-child {
  margin-bottom: 0;
}

.writings-entry h2 {
  margin: 0 0 8px;
  font-size: clamp(22px, 2vw, 28px);
  line-height: 1.2;
  letter-spacing: -0.015em;
  font-weight: 400;
}

.writings-entry-meta {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

.writings-entry-meta time {
  font-variant-numeric: tabular-nums;
}

.writings-entry-excerpt {
  margin: 0 0 14px;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.65;
  color: var(--color-text-secondary);
}

.writings-entry-tags {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

.writings-entry-tag {
  color: var(--color-text-tertiary);
  text-decoration: none;
}

.writings-entry-tag:hover {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 4px;
}

.writings-empty {
  margin: 0;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.65;
  color: var(--color-text-tertiary);
  font-style: italic;
}

/* Pagination at the foot of the listing. Mono labels, hairline divider
   above. When only one direction has a link, push it to its natural side
   so a lone "Older →" sits on the right and a lone "← Newer" sits on the
   left. */
.writings-pagination {
  display: flex;
  justify-content: space-between;
  gap: clamp(16px, 2vw, 24px);
  padding-top: clamp(36px, 4vw, 48px);
  border-top: 0.5px solid var(--color-hairline-soft);
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
}

.writings-pagination a {
  color: var(--color-text);
  text-decoration: none;
}

.writings-pagination a:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}

.writings-pagination a[rel="prev"] {
  margin-right: auto;
}

.writings-pagination a[rel="next"] {
  margin-left: auto;
}

/* Sprint 4B.11: recent writings tease on the landing page. Three-card
   row consuming the most recent published posts (newest first). Sits
   between How-we-work and Work-with-us. Card shape rhymes with .sv2
   (full-card-as-link, mono eyebrow, hover-italic title, mono READ MORE
   arrow with letter-spacing animation) but at the lighter editorial
   weight appropriate to a tease — date eyebrow instead of icon+number,
   serif teaser instead of structural body copy, no body-max-width
   ceiling. Per-card data-controller="reveal" produces a 0/40/80ms
   stagger via the shared IntersectionObserver — first deliberate use
   of the controller's stagger feature on the landing page. */
.recent {
  display: grid;
  grid-template-columns: 1fr 1fr 1fr;
  margin-top: 64px;
  position: relative;
}

.recent-card {
  display: block;
  position: relative;
  padding: 48px 36px 44px;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  transition: background 0.2s;
}

.recent-card:hover {
  background: var(--color-stripe);
}

.recent-card-meta {
  margin: 0 0 18px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

.recent-card-meta time {
  font-variant-numeric: tabular-nums;
}

.recent-card-title {
  margin: 0 0 14px;
  font-size: clamp(20px, 2vw, 26px);
  font-weight: 400;
  line-height: 1.2;
  letter-spacing: -0.018em;
  transition: font-style 0.2s;
}

.recent-card:hover .recent-card-title {
  font-style: italic;
}

.recent-card-teaser {
  margin: 0 0 24px;
  font-size: clamp(14px, 1.15vw, 15.5px);
  line-height: 1.6;
  color: var(--color-text-secondary);
}

.recent-card-arr {
  font-family: var(--font-mono);
  font-size: 12.5px;
  color: var(--color-text-tertiary);
  letter-spacing: 0.04em;
  transition: color 0.2s, letter-spacing 0.3s;
}

.recent-card:hover .recent-card-arr {
  color: var(--color-text);
  letter-spacing: 0.08em;
}

.recent-foot {
  margin: 64px 0 0;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

.recent-foot-link {
  color: var(--color-text);
  text-decoration: none;
}

.recent-foot-link:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}

@media (max-width: 768px) {
  .recent {
    grid-template-columns: 1fr;
  }
  .recent-card {
    padding: 32px 0 32px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .recent-card,
  .recent-card-title,
  .recent-card-arr {
    transition: none;
  }
}

/* Sprint 4C-shape: post show pages (/writings/:slug). Brings the article
   reading surface — built in Sprint 1.6 against the original B&W shell —
   onto the editorial token vocabulary. Class names (.post, .post-header,
   .post-meta, .post-author, .post-tag, .post-signature) preserved because
   request and system specs lock them; only the styling moves to the new
   vocabulary. Reading register pairs with the manifesto's .detail-essay
   family but slightly looser line-height for blog-shaped content (lists,
   headings, code) which breathes better than the manifesto's flowing essay
   form. .post-signature itself already styled in landing.css alongside
   .manifesto-byline (no change needed there). */
.writing-show {
  /* Horizontal padding scales with viewport so the post body doesn't go
     edge-to-edge on narrow phones (the 65ch max-width on .post only
     constrains the column when the viewport is wider than 65ch — at
     mobile widths it's the viewport that's the binding constraint).
     24px floor gives readable margins at the narrowest phones. */
  padding: clamp(72px, 10vw, 128px) clamp(24px, 5vw, 64px);
}

.post {
  max-width: 65ch;
  margin: 0 auto;
}

.post-header {
  margin-bottom: clamp(48px, 6vw, 72px);
}

.post-header h1 {
  margin: 0 0 clamp(20px, 2vw, 28px);
  font-size: clamp(40px, 5vw, 64px);
  line-height: 1.05;
  letter-spacing: -0.025em;
  font-weight: 400;
}

.post-header .post-meta {
  margin: 0 0 8px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

.post-header .post-meta time {
  font-variant-numeric: tabular-nums;
}

.post-author {
  color: var(--color-text-tertiary);
}

.post-header .post-tags {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

.post-tag {
  color: var(--color-text-tertiary);
  text-decoration: none;
}

.post-tag:hover {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Lede paragraph — upsized, primary text color, sits above the body. */
.post-summary {
  margin: 0 0 clamp(36px, 4vw, 48px);
  font-size: clamp(20px, 1.7vw, 24px);
  line-height: 1.55;
  color: var(--color-text);
}

.post-body {
  font-size: clamp(17px, 1.4vw, 19px);
  line-height: 1.8;
  color: var(--color-text-secondary);
}

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

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

.post-body h2 {
  margin: clamp(40px, 4vw, 56px) 0 16px;
  font-size: clamp(24px, 2.4vw, 32px);
  line-height: 1.2;
  letter-spacing: -0.018em;
  font-weight: 400;
  color: var(--color-text);
}

.post-body h3 {
  margin: clamp(32px, 3vw, 40px) 0 12px;
  font-size: clamp(20px, 2vw, 26px);
  line-height: 1.25;
  letter-spacing: -0.015em;
  font-weight: 400;
  color: var(--color-text);
}

.post-body strong {
  font-weight: 500;
  color: var(--color-text);
}

.post-body em {
  font-style: italic;
}

.post-body a {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 4px;
}

.post-body a:hover {
  text-decoration-thickness: 1.5px;
}

.post-body ul,
.post-body ol {
  margin: 0 0 24px;
  padding-left: 1.5em;
}

.post-body li {
  margin-bottom: 8px;
}

.post-body li:last-child {
  margin-bottom: 0;
}

.post-body blockquote {
  margin: 24px 0;
  padding: 0 0 0 20px;
  border-left: 0.5px solid var(--color-hairline-soft);
  font-style: italic;
  color: var(--color-text-tertiary);
}

.post-body code {
  font-family: var(--font-mono);
  font-size: 0.9em;
  padding: 1px 5px;
  background: var(--color-stripe);
  border-radius: 2px;
  color: var(--color-text);
}

.post-body pre {
  margin: 24px 0;
  padding: 20px;
  background: var(--color-stripe);
  border: 0.5px solid var(--color-hairline-soft);
  border-radius: 4px;
  overflow-x: auto;
  font-family: var(--font-mono);
  font-size: 14px;
  line-height: 1.5;
  color: var(--color-text);
}

.post-body pre code {
  padding: 0;
  background: none;
  font-size: inherit;
}

.post-body img {
  max-width: 100%;
  height: auto;
  margin: 24px 0;
}

.post-body hr {
  width: 80px;
  height: 0;
  border: 0;
  border-top: 0.5px solid var(--color-hairline-soft);
  margin: clamp(40px, 5vw, 56px) auto;
}

/* Sprint 4C.1: /teaching page polish. Reading register pairs with the
   manifesto's .detail-essay family — centered 65ch column, serif body,
   40–64px h1, h2 section breaks at 24–32px. Existing copy from Sprint 1.8
   intact; layout/typography only. Real curriculum content lands in
   Sprint 5A's joint design session. */
.teaching {
  padding: clamp(72px, 10vw, 128px) 0;
}

.teaching-header,
.teaching-body {
  max-width: 65ch;
  margin: 0 auto;
}

.teaching-header {
  margin-bottom: clamp(36px, 4vw, 48px);
}

.teaching-header h1 {
  margin: 0;
  font-size: clamp(40px, 5vw, 64px);
  line-height: 1.05;
  letter-spacing: -0.025em;
  font-weight: 400;
}

.teaching-lede {
  margin: 0 0 clamp(36px, 4vw, 48px);
  font-size: clamp(20px, 1.7vw, 24px);
  line-height: 1.45;
  color: var(--color-text);
}

.teaching-section {
  margin-bottom: clamp(36px, 4vw, 48px);
}

.teaching-section:last-child {
  margin-bottom: 0;
}

.teaching-section h2 {
  margin: 0 0 16px;
  font-size: clamp(24px, 2.4vw, 32px);
  line-height: 1.2;
  letter-spacing: -0.018em;
  font-weight: 400;
  color: var(--color-text);
}

.teaching-section p {
  margin: 0 0 20px;
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.7;
  color: var(--color-text-secondary);
}

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

.teaching-section a {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 4px;
}

.teaching-cta {
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
}

.teaching-cta a {
  text-decoration: none;
}

.teaching-cta a:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}

/* Sprint 4C.3: devise sign-in (/admin_users/sign_in). Public-reachable
   doorway to admin; rendered through the public editorial layout via the
   AdminUsers::SessionsController override. The 2FA flow that follows
   stays on the application layout — admin/sales/portal redesign is
   Sprint 4D. Form chrome: centered editorial card with mono labels,
   serif body, hairline-bordered inputs, primary submit using the
   existing inverse-fill pattern from .btn but at form-action weight. */
.sign-in {
  padding: clamp(72px, 10vw, 128px) 0;
}

.sign-in-panel {
  max-width: 420px;
  margin: 0 auto;
}

.sign-in-eyebrow {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
  text-transform: uppercase;
}

.sign-in-panel h1 {
  margin: 0 0 16px;
  font-size: clamp(36px, 4vw, 48px);
  line-height: 1.1;
  letter-spacing: -0.022em;
  font-weight: 400;
}

.sign-in-lede {
  margin: 0 0 clamp(28px, 3vw, 36px);
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.55;
  color: var(--color-text-secondary);
}

.sign-in-form {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.sign-in-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.sign-in-field label {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
  text-transform: uppercase;
}

.sign-in-field input[type="email"],
.sign-in-field input[type="password"] {
  padding: 12px 14px;
  background: transparent;
  color: var(--color-text);
  border: 0.5px solid var(--color-hairline-strong);
  border-radius: 0;
  font-family: var(--font-mono);
  font-size: 15px;
  line-height: 1.4;
  outline: none;
  transition: border-color 0.15s;
}

.sign-in-field input[type="email"]:focus,
.sign-in-field input[type="password"]:focus {
  border-color: var(--color-text);
}

.sign-in-field-inline {
  flex-direction: row;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
  text-transform: uppercase;
}

.sign-in-field-inline label {
  text-transform: uppercase;
}

.sign-in-field-inline input[type="checkbox"] {
  accent-color: var(--color-text);
}

.sign-in-actions {
  margin-top: 8px;
}

.sign-in-submit {
  display: inline-block;
  padding: 12px 24px;
  background: var(--color-background-inverse);
  color: var(--color-text-inverse);
  border: 0.5px solid var(--color-background-inverse);
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.sign-in-submit:hover {
  background: transparent;
  color: var(--color-text);
  border-color: var(--color-text);
}

/* Newsletter inline — sits at the bottom of editorial pages (writings
   index, individual posts) where readers most-engaged surface their
   intent. Width and centering match the .post column above (max-width
   65ch, margin auto) so the panel feels like a continuation of the
   article rather than chrome plopped underneath. The hairline separator
   provides the visual break. The act of submitting is the consent, so
   no separate opt-in checkbox. */
.newsletter-inline {
  padding: clamp(48px, 6vw, 72px) 0;
  margin-top: clamp(56px, 6vw, 80px);
}

.newsletter-inline-content {
  max-width: 65ch;
  margin: 0 auto;
  text-align: center;
}

.newsletter-inline-content h2 {
  margin: 0 0 clamp(20px, 2.5vw, 28px);
  font-family: var(--font-serif);
  font-size: clamp(24px, 2.4vw, 30px);
  font-weight: 400;
  letter-spacing: -0.01em;
  color: var(--color-text);
}

.newsletter-inline-form {
  display: flex;
  gap: 10px;
  max-width: 460px;
  margin: 0 auto;
  align-items: stretch;
}

.newsletter-inline-form input[type="email"] {
  flex: 1;
  min-width: 0;
  background: var(--color-background);
  color: var(--color-text);
  border: 0.5px solid var(--color-hairline-strong);
  padding: 12px 14px;
  font: inherit;
  font-size: 15px;
  outline: none;
  transition: border-color 0.15s;
}

.newsletter-inline-form input[type="email"]:focus {
  border-color: var(--color-text);
}

.newsletter-inline-submit {
  flex-shrink: 0;
  background: var(--color-text);
  color: var(--color-background);
  border: 0.5px solid var(--color-text);
  padding: 12px 22px;
  font-family: var(--font-mono);
  font-size: 12px;
  font-weight: 400;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.newsletter-inline-submit:hover {
  background: transparent;
  color: var(--color-text);
  border-color: var(--color-text);
}

/* Disclosure line under the form: sets expectations on cadence and
   surfaces the unsubscribe option upfront so the consent meaning of
   the submit button is obvious before the click. Mono small caps
   echoes the submit button so the line reads as form chrome rather
   than body copy. */
.newsletter-inline-note {
  margin: 16px auto 0;
  max-width: 460px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

@media (max-width: 560px) {
  .newsletter-inline-form {
    flex-direction: column;
    max-width: 360px;
  }
  .newsletter-inline-submit {
    width: 100%;
  }
}

/* Public form chrome — used by /contact and the per-program /teaching/<slug>/apply
   pages. The intent is editorial-form: serif body, generous spacing, no
   visual gimmicks. Not the same as .admin-form (which is data-dense and
   sans-body); these forms read as part of the public copy. */
.public-form {
  padding: 64px 0 96px;
}

.public-form-header {
  max-width: 720px;
  margin: 0 auto 56px;
}

.public-form-header h1 {
  margin: 0 0 24px;
  font-family: var(--font-serif);
  font-size: 48px;
  font-weight: 400;
  letter-spacing: -0.01em;
}

.public-form-lede {
  margin: 0;
  font-size: 18px;
  line-height: 1.6;
  color: var(--color-text-secondary);
}

.public-form-body {
  max-width: 600px;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  gap: 28px;
}

.public-field {
  display: flex;
  flex-direction: column;
  gap: 10px;
}

.public-field label {
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 400;
  color: var(--color-text-tertiary);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.public-field input[type="text"],
.public-field input[type="email"],
.public-field textarea,
.public-field select {
  background: var(--color-background);
  color: var(--color-text);
  border: 0.5px solid var(--color-hairline-strong);
  padding: 14px 16px;
  font: inherit;
  font-size: 16px;
  outline: none;
  transition: border-color 0.15s;
}

.public-field input:focus,
.public-field textarea:focus,
.public-field select:focus {
  border-color: var(--color-text);
}

.public-field textarea {
  min-height: 8rem;
  font-family: inherit;
  line-height: 1.5;
  resize: vertical;
}

.public-checkbox-group {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px 24px;
  border: 0;
  padding: 0;
  margin: 0;
}

.public-checkbox-group label,
.public-checkbox label {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-family: var(--font-serif);
  font-size: 15px;
  text-transform: none;
  letter-spacing: 0;
  color: var(--color-text);
  cursor: pointer;
  line-height: 1.4;
}

.public-checkbox-group input[type="checkbox"],
.public-checkbox input[type="checkbox"] {
  margin-top: 4px;
}

.public-actions {
  margin-top: 8px;
}

@media (max-width: 600px) {
  .public-form-header h1 {
    font-size: 36px;
  }
  .public-checkbox-group {
    grid-template-columns: 1fr;
  }
}

/* Policy pages — privacy notice and terms. Editorial-form static
   pages where the copy is the entire surface; no nav, no CTAs, just
   a single column of serif body with sectional h2s. The eyebrow is
   the route name in mono uppercase so the page is recognizable as
   chrome rather than an essay. Last-updated meta sits below the h1
   in tertiary muted; body text is full --color-text because the
   content is consequential, not decorative. */
.policy-page {
  padding: clamp(64px, 7vw, 96px) 0 clamp(80px, 8vw, 120px);
}

.policy-page .in {
  max-width: 65ch;
  margin: 0 auto;
  padding: 0 var(--page-padding-inline);
}

.policy-page-header {
  margin-bottom: clamp(40px, 5vw, 56px);
}

.policy-page-eyebrow {
  margin: 0 0 clamp(20px, 2vw, 28px);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-tertiary);
}

.policy-page-header h1 {
  margin: 0 0 clamp(16px, 1.6vw, 20px);
  font-family: var(--font-serif);
  font-size: clamp(32px, 3.4vw, 44px);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--color-text);
}

.policy-page-meta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

.policy-page-body {
  font-family: var(--font-serif);
  font-size: 17px;
  line-height: 1.65;
  color: var(--color-text);
}

.policy-page-body h2 {
  margin: clamp(36px, 4vw, 48px) 0 clamp(12px, 1.4vw, 16px);
  font-family: var(--font-serif);
  font-size: clamp(20px, 2vw, 24px);
  font-weight: 400;
  letter-spacing: -0.012em;
  line-height: 1.2;
  color: var(--color-text);
}

.policy-page-body p {
  margin: 0 0 clamp(16px, 1.6vw, 20px);
}

.policy-page-body ol,
.policy-page-body ul {
  margin: 0 0 clamp(16px, 1.6vw, 20px);
  padding-left: 1.4em;
}

.policy-page-body li {
  margin: 0 0 clamp(12px, 1.2vw, 16px);
}

.policy-page-body a {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 0.5px;
}

.policy-page-body a:hover {
  text-decoration-thickness: 1px;
}

.policy-page-body code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  padding: 1px 4px;
  background: var(--color-stripe);
  border: 0.5px solid var(--color-hairline-soft);
}

/* Footer legal-link strip — privacy + terms appended to the bottom
   row alongside copyright + canonical domain so the legal surface
   is one click away from any page without taking up a whole footer
   column. Mono small caps to match the surrounding meta. */
.ft-bot-legal {
  display: inline-flex;
  gap: 16px;
}

.ft-bot-legal a {
  color: inherit;
  text-decoration: none;
}

.ft-bot-legal a:hover {
  text-decoration: underline;
  text-underline-offset: 3px;
}

/* Public search page — single-column form + results pattern. The
   header chrome echoes .policy-page (mono eyebrow, serif h1) so the
   editorial utility surfaces stay visually adjacent. Form is a
   minimal text input + button row; results are a clean list with
   serif title links and meta. */
.search-page {
  padding: clamp(64px, 7vw, 96px) 0 clamp(80px, 8vw, 120px);
}

.search-page .in {
  max-width: 65ch;
  margin: 0 auto;
  padding: 0 var(--page-padding-inline);
}

.search-page-header {
  margin-bottom: clamp(32px, 4vw, 40px);
}

.search-page-eyebrow {
  margin: 0 0 clamp(20px, 2vw, 28px);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-tertiary);
}

.search-page-header h1 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(32px, 3.4vw, 44px);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--color-text);
}

.search-form {
  display: flex;
  gap: 10px;
  margin-bottom: clamp(40px, 5vw, 56px);
}

.search-form input[type="text"] {
  flex: 1;
  min-width: 0;
  background: var(--color-background);
  color: var(--color-text);
  border: 0.5px solid var(--color-hairline-strong);
  padding: 12px 14px;
  font: inherit;
  font-size: 15px;
  outline: none;
  transition: border-color 0.15s;
}

.search-form input[type="text"]:focus {
  border-color: var(--color-text);
}

.search-form-submit {
  flex-shrink: 0;
  background: var(--color-text);
  color: var(--color-background);
  border: 0.5px solid var(--color-text);
  padding: 12px 22px;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.15s, color 0.15s;
}

.search-form-submit:hover {
  background: transparent;
  color: var(--color-text);
}

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

.search-result {
  padding: clamp(20px, 2.4vw, 28px) 0;
  border-top: 0.5px solid var(--color-hairline-soft);
}

.search-result:first-child {
  border-top: none;
}

.search-result h2 {
  margin: 0 0 8px;
  font-family: var(--font-serif);
  font-size: clamp(20px, 2vw, 24px);
  font-weight: 400;
  letter-spacing: -0.012em;
  line-height: 1.25;
}

.search-result h2 a {
  color: var(--color-text);
  text-decoration: none;
}

.search-result h2 a:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}

.search-result p {
  margin: 0 0 8px;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: 1.55;
  color: var(--color-text-secondary);
}

.search-result-meta {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

.search-empty {
  font-family: var(--font-serif);
  font-size: 17px;
  color: var(--color-text-tertiary);
  margin: clamp(32px, 4vw, 48px) 0;
}

@media (max-width: 560px) {
  .search-form {
    flex-direction: column;
  }
  .search-form-submit {
    width: 100%;
  }
}

/* Newsletter archive — public reverse-chronological list of past
   issues, plus per-issue show. Same editorial chrome vocabulary as
   /search and /privacy/terms (mono eyebrow, serif h1, single-column
   65ch body) so the utility/content split stays visually adjacent. */
.newsletter-archive,
.newsletter-archive-show {
  padding: clamp(64px, 7vw, 96px) 0 clamp(80px, 8vw, 120px);
}

.newsletter-archive .in,
.newsletter-archive-show .in {
  max-width: 65ch;
  margin: 0 auto;
  padding: 0 var(--page-padding-inline);
}

.newsletter-archive-eyebrow {
  margin: 0 0 clamp(20px, 2vw, 28px);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--color-text-tertiary);
}

.newsletter-archive-header h1,
.newsletter-archive-show-header h1 {
  margin: 0;
  font-family: var(--font-serif);
  font-size: clamp(32px, 3.4vw, 44px);
  font-weight: 400;
  letter-spacing: -0.02em;
  line-height: 1.15;
  color: var(--color-text);
}

.newsletter-archive-header {
  margin-bottom: clamp(40px, 5vw, 56px);
}

.newsletter-archive-lede {
  margin: clamp(16px, 1.6vw, 20px) 0 0;
  font-family: var(--font-serif);
  font-size: 17px;
  line-height: 1.55;
  color: var(--color-text-secondary);
}

.newsletter-archive-list {
  list-style: none;
  margin: 0 0 clamp(48px, 6vw, 80px);
  padding: 0;
}

.newsletter-archive-list li {
  padding: clamp(20px, 2.4vw, 28px) 0;
  border-top: 0.5px solid var(--color-hairline-soft);
}

.newsletter-archive-list li:first-child {
  border-top: none;
}

.newsletter-archive-list h2 {
  margin: 0 0 6px;
  font-family: var(--font-serif);
  font-size: clamp(20px, 2vw, 24px);
  font-weight: 400;
  letter-spacing: -0.012em;
  line-height: 1.25;
}

.newsletter-archive-list h2 a {
  color: var(--color-text);
  text-decoration: none;
}

.newsletter-archive-list h2 a:hover {
  text-decoration: underline;
  text-underline-offset: 4px;
}

.newsletter-archive-meta {
  margin: 0;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

.newsletter-archive-empty {
  margin: clamp(32px, 4vw, 48px) 0;
  font-family: var(--font-serif);
  font-size: 17px;
  color: var(--color-text-tertiary);
}

.newsletter-archive-back {
  margin: 0 0 clamp(24px, 3vw, 32px);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
}

.newsletter-archive-back a {
  color: var(--color-text-tertiary);
  text-decoration: none;
}

.newsletter-archive-back a:hover {
  color: var(--color-text);
}

.newsletter-archive-show-header {
  margin-bottom: clamp(32px, 4vw, 40px);
}

.newsletter-archive-show-header .newsletter-archive-meta {
  margin-top: clamp(16px, 1.6vw, 20px);
}

.newsletter-archive-body {
  font-family: var(--font-serif);
  font-size: 18px;
  line-height: 1.65;
  color: var(--color-text);
  margin-bottom: clamp(48px, 6vw, 80px);
}

.newsletter-archive-body p {
  margin: 0 0 clamp(16px, 1.6vw, 20px);
}

.newsletter-archive-body h2 {
  margin: clamp(36px, 4vw, 48px) 0 clamp(12px, 1.4vw, 16px);
  font-family: var(--font-serif);
  font-size: clamp(22px, 2.2vw, 28px);
  font-weight: 400;
  letter-spacing: -0.012em;
  line-height: 1.2;
}

.newsletter-archive-body a {
  color: var(--color-text);
  text-decoration: underline;
  text-underline-offset: 3px;
  text-decoration-thickness: 0.5px;
}
/*






 */

body {
  background: var(--color-background);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--font-size-base);
  line-height: var(--line-height-base);
}

:focus-visible {
  outline: 2px solid var(--color-text);
  outline-offset: 2px;
}

.skip-link {
  position: absolute;
  left: var(--space-4);
  top: -100vh;
  padding: var(--space-2) var(--space-4);
  background: var(--color-background);
  color: var(--color-text);
  border: 1px solid var(--color-text);
}

.skip-link:focus {
  top: var(--space-4);
}

/* Sprint 4D.1: tools layout shell. Wraps every authenticated chrome page
   (admin, sales, portal, 2FA flows) in a global header strip with brand
   mark + sign-out + theme toggle. Sans body via --font-sans (data-dense
   readability); no bg_grid / cursor_glow (those belong to public
   surfaces). Per-page admin-header / admin-page-lede etc. continue to
   render below this strip. */
.tools-shell {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
}

.tools-header {
  border-bottom: 0.5px solid var(--color-hairline);
  background: var(--color-background);
}

.tools-header-in {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  max-width: 1280px;
  margin: 0 auto;
  padding: 14px clamp(16px, 3vw, 32px);
}

.tools-brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.01em;
  color: var(--color-text);
  text-decoration: none;
}

.tools-brand-mark {
  position: relative;
  display: inline-block;
  width: 10px;
  height: 10px;
  background: var(--color-text);
}

.tools-brand-mark::after {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--color-background);
  transform: scaleX(0.5);
  transform-origin: right;
}

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

.tools-signout-form {
  display: inline-flex;
  margin: 0;
}

.tools-signout {
  background: transparent;
  border: none;
  padding: 0;
  font: inherit;
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
  cursor: pointer;
  transition: color 0.2s;
}

.tools-signout:hover {
  color: var(--color-text);
}

.tools-theme-toggle {
  display: inline-flex;
  align-items: center;
  margin: 0;
  padding: 0;
  border: none;
  background: none;
  color: var(--color-text-tertiary);
  cursor: pointer;
  transition: color 0.2s;
}

.tools-theme-toggle:hover {
  color: var(--color-text);
}

.tools-main {
  flex: 1;
}

.theme-toggle {
  color: var(--color-text);
  padding: var(--space-2);
  display: inline-flex;
  align-items: center;
  justify-content: center;
  order: 1;
}

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

[data-theme="light"] .theme-toggle [data-dark-mode-target="moon"] {
  display: none;
}

[data-theme="light"] .theme-toggle [data-dark-mode-target="sun"] {
  display: block;
}

main > section {
  max-width: 72rem;
  margin: 0 auto;
  padding: var(--space-16) var(--space-4);
  border-top: 1px solid var(--color-hairline);
}

main > section:first-child {
  border-top: 0;
}

main > section > h2 {
  font-size: var(--font-size-xl);
  font-weight: 700;
  margin-bottom: var(--space-8);
  letter-spacing: 0.02em;
}

main > section > p,
main > section > ol,
main > section > ul {
  max-width: 65ch;
}

main > section + section > p:first-of-type {
  margin-top: 0;
}

main > section p + p {
  margin-top: var(--space-4);
}

/* Button variants. Three flavors: primary (filled), secondary (bordered,
   transparent), destructive (heavier border, no accent color — the brand
   has none, so destructive is signaled by weight + confirmation, not red).
   .cta-primary is the legacy alias used on the public landing page; new
   admin/sales markup should reach for .button-primary. */
/* Sprint 4D.3b: button family editorial polish. Three variants reworked
   onto the editorial vocabulary used by .sign-in-submit and the auth-page
   submit (mono uppercase 13px / 0.06em / weight 400, hairline-strong
   borders, 12/24 padding, inverse-fill hover for primary, hairline-fill
   for destructive). Same class names and inheritance behavior, just
   typography + chrome. */
.button-primary,
.cta-primary {
  display: inline-block;
  background: var(--color-background-inverse);
  color: var(--color-text-inverse);
  padding: 13px 26px;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border: 0.5px solid var(--color-background-inverse);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.button-primary:hover,
.cta-primary:hover {
  background: transparent;
  color: var(--color-text);
  border-color: var(--color-text);
}

.button-primary:focus-visible,
.cta-primary:focus-visible {
  outline: 2px solid var(--color-text);
  outline-offset: 3px;
}

.button-secondary,
.button_to.button-secondary > button {
  display: inline-block;
  background: transparent;
  color: var(--color-text);
  padding: 13px 26px;
  font: inherit;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border: 0.5px solid var(--color-hairline-strong);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.button-secondary:hover,
.button_to.button-secondary > button:hover {
  border-color: var(--color-text);
  background: var(--color-hover);
  color: var(--color-text);
}

.button-secondary:focus-visible,
.button_to.button-secondary > button:focus-visible {
  outline: 2px solid var(--color-text);
  outline-offset: 3px;
}

.button-destructive,
.button_to.button-destructive > button {
  display: inline-block;
  background: transparent;
  color: var(--color-text);
  padding: 13px 26px;
  font: inherit;
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  border: 0.5px solid var(--color-text);
  text-decoration: none;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.button-destructive:hover,
.button_to.button-destructive > button:hover {
  background: var(--color-text);
  color: var(--color-text-inverse);
  border-color: var(--color-text);
}

.button-destructive:focus-visible,
.button_to.button-destructive > button:focus-visible {
  outline: 2px solid var(--color-text);
  outline-offset: 3px;
}

footer {
  padding: var(--space-8) var(--space-4);
  border-top: 1px solid var(--color-hairline);
  color: var(--color-text-tertiary);
  font-size: var(--font-size-sm);
  max-width: 72rem;
  margin: 0 auto;
}

@media (min-width: 48em) {
  header {
    padding: var(--space-4) var(--space-8);
  }

  header nav {
    flex-basis: auto;
    order: 0;
  }

  .theme-toggle {
    order: 0;
  }

  main > section {
    padding: var(--space-24) var(--space-8);
  }

  footer {
    padding: var(--space-8);
  }
}

.admin-table-wrapper {
  overflow-x: auto;
  margin: var(--space-4) 0 var(--space-6);
}

.admin-table {
  border-collapse: collapse;
  width: 100%;
  font-size: 14.5px;
}

.admin-table th,
.admin-table td {
  padding: 14px 16px;
  border-bottom: 0.5px solid var(--color-hairline-soft);
  text-align: left;
  vertical-align: top;
}

/* Default cell color is the secondary text token so primary cells —
   marked with `.primary` (typically the row's main identifier
   column) — get clear visual weight. Without this hierarchy, every
   cell competes for attention and lists feel dense and undifferentiated. */
.admin-table tbody td {
  color: var(--color-text-secondary);
}

/* Primary cell — the linked entity name / title that identifies the
   row. Full text color + medium weight so the eye lands here first
   when scanning a long list. Tables that don't have an obvious
   "primary" cell (e.g. audit_logs with timestamp first) just don't
   tag any cell with .primary; the whole row reads at the same
   secondary weight. */
.admin-table tbody td.primary {
  color: var(--color-text);
  font-weight: var(--font-weight-medium);
}

/* Links inside primary cells render as plain text with a hover
   underline so the column looks like a name, not a sea of underlines.
   Hover on the row now telegraphs interactivity better than
   always-underlined links did. */
.admin-table tbody td.primary a {
  color: inherit;
  text-decoration: none;
  border-bottom: 0.5px solid transparent;
  transition: border-color 0.15s;
}

.admin-table tbody td.primary a:hover {
  border-bottom-color: currentColor;
}

/* Sticky column headers — stay visible while scrolling long lists.
   The wrapper handles the actual scroll; the header sticks to the
   top of the wrapper's viewport. Background pinned to --color-background
   so the row behind doesn't bleed through. */
.admin-table thead th {
  font-family: var(--font-mono);
  color: var(--color-text-tertiary);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-weight: 400;
  font-size: 11.5px;
  border-bottom: 0.5px solid var(--color-hairline);
  background-color: var(--color-background);
  position: sticky;
  top: 0;
  z-index: 1;
  white-space: nowrap;
}

/* Row hover. Removed the zebra-striped fallback (the old "every other
   row tinted" pattern reads dated; modern admins rely on hover for row
   tracking + hairline-soft borders for separation). */
.admin-table > tbody > tr:hover > td {
  background-color: var(--color-hover);
}

.admin-table tbody tr:last-child td {
  border-bottom: 0;
}

.admin-table td.num,
.admin-table th.num {
  text-align: right;
  font-variant-numeric: tabular-nums;
}

.kanban {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-4);
  margin-top: var(--space-6);
}

.kanban-column {
  border: 0.5px solid var(--color-hairline-soft);
  padding: var(--space-4);
  min-height: 6rem;
}

.kanban-column h2 {
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
  font-weight: var(--font-weight-regular);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-tertiary);
  margin-bottom: var(--space-2);
}

/* One-line description under each kanban column header. Sits above the
   cards in muted color to read as orientation, not data. Bottom margin
   matches the prior h2-to-cards gap so the rhythm is preserved. */
.kanban-column-meta {
  font-size: var(--font-size-xs);
  color: var(--color-text-tertiary);
  line-height: var(--line-height-relaxed);
  margin-bottom: var(--space-4);
}

/* Closed-stage columns recede visually so the active pipeline reads first.
   Border opacity dim and column header text in muted; cards inside still
   render at full weight so individual won/lost details stay legible. */
.kanban-column[data-stage="won"],
.kanban-column[data-stage="lost"] {
  background: transparent;
}

.kanban-column[data-stage="won"] h2,
.kanban-column[data-stage="lost"] h2 {
  color: var(--color-text-tertiary);
}

.kanban-card {
  border: 0.5px solid var(--color-hairline-soft);
  padding: var(--space-5);
  margin-bottom: var(--space-4);
  cursor: grab;
}

.kanban-card:active {
  cursor: grabbing;
}

.kanban-card > a:first-child {
  display: block;
  font-size: clamp(15px, 1.5vw, 17px);
  font-weight: var(--font-weight-medium);
  letter-spacing: -0.005em;
  margin-bottom: var(--space-3);
}

.kanban-card p {
  margin-top: var(--space-1);
}

@media (min-width: 48em) {
  .kanban {
    grid-template-columns: repeat(4, minmax(220px, 1fr)) repeat(2, minmax(160px, 0.7fr));
    overflow-x: auto;
  }
}

/* Pipeline rollup at the top of /admin/deals — promotes the open-pipeline
   number from a single muted line into a bordered stat band. The eyebrow
   labels the value; tabular-nums keeps multi-currency rows visually
   aligned. */
.admin-pipeline-rollup {
  margin: var(--space-6) 0;
  padding: var(--space-5) 0;
  border-top: 0.5px solid var(--color-hairline-soft);
  border-bottom: 0.5px solid var(--color-hairline-soft);
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
}

.admin-pipeline-rollup .admin-eyebrow {
  font-family: var(--font-mono);
  text-transform: uppercase;
  letter-spacing: 0.06em;
  font-size: var(--font-size-xs);
  color: var(--color-text-tertiary);
  font-weight: var(--font-weight-regular);
}

.admin-pipeline-totals {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
  align-items: baseline;
}

.admin-pipeline-pair {
  display: inline-flex;
  align-items: baseline;
  gap: var(--space-2);
}

.admin-pipeline-value {
  font-size: clamp(22px, 2.4vw, 30px);
  font-weight: var(--font-weight-regular);
  letter-spacing: -0.012em;
  font-variant-numeric: tabular-nums;
}

.admin-pipeline-currency {
  font-family: var(--font-mono);
  color: var(--color-text-tertiary);
  font-size: var(--font-size-xs);
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

/* ==== Admin and sales page chrome ====

  Every signed-in surface (admin, sales) wraps its content in a <section>
  with a per-page hook class (.admin-contacts, .sales-deals, …) that picks
  up the global main > section padding and max-width. Inside that, the
  patterns below establish typographic hierarchy and section rhythm.

  The .admin- prefix is the de-facto "logged-in surface" token — it covers
  /sales views too. Renaming is deferred (see ticket backlog). */

/* Sprint 4D.3a: admin chrome typography. Page header + section headings
   moved off the legacy bold weights onto editorial weight 400 with
   tighter tracking and clamp-based sizing. Hairline-soft borders for
   section dividers (was hairline) so the chrome reads quieter and the
   data inside reads louder. Cascades to every admin/sales/portal page
   that uses .admin-header / .admin-section. */
.admin-header {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-3) var(--space-6);
  margin-bottom: var(--space-8);
  padding-bottom: var(--space-4);
  border-bottom: 0.5px solid var(--color-hairline-soft);
}

.admin-header h1 {
  font-size: clamp(28px, 3vw, 40px);
  font-weight: 400;
  letter-spacing: -0.018em;
  line-height: 1.15;
  margin-right: auto;
}

/* Page-level orientation copy — one short paragraph between the header and
   the first content block, explaining what the page is for. Reads at body
   weight in --color-text (not muted) because it's primary instructional
   content, not metadata. The 65ch max-width keeps it editorial-readable
   on wide viewports. Reusable across admin and sales pages.
   Serif at 17px softens the page rhythm: mono tools strip → sans h1
   → serif lede, the editorial descent from system chrome to author
   voice. The h1 stays sans because it's a label-shaped record name,
   not a headline; the lede is the only place serif belongs in the
   admin chrome. */
.admin-page-lede {
  margin: 0 0 var(--space-8);
  max-width: 65ch;
  font-family: var(--font-serif);
  font-size: 17px;
  color: var(--color-text);
  line-height: var(--line-height-relaxed);
}

/* Anything inline-block in the header that isn't the title pins to the
   right edge of the title row. <p>, .admin-meta, and .admin-stat-row
   wrap below by claiming the full row. */
.admin-header > p,
.admin-header > .admin-meta,
.admin-header > .admin-stat-row {
  flex-basis: 100%;
  margin-right: 0;
}

/* Stat row pattern: a horizontal grid of label-over-value pairs that wraps
   on narrow widths. Replaces the dot-separated meta paragraphs that were
   previously the show-page header convention. Each stat is a <div> wrapper
   inside a <dl>, with <dt> as the eyebrow label and <dd> as the value. */
.admin-stat-row {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-4) var(--space-8);
  margin-top: var(--space-3);
}

.admin-stat-row .admin-stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
}

.admin-stat-row dt {
  font-family: var(--font-mono);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-tertiary);
  font-weight: 400;
}

.admin-stat-row dd {
  font-size: var(--font-size-base);
  font-weight: var(--font-weight-medium);
  margin: 0;
  line-height: var(--line-height-tight);
}

.admin-stat-row dd a {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* Definition-list pattern for compact key-value reporting on /admin/reports.
   Used in place of a <table> when the data is two columns and a handful of
   rows — the table chrome was fighting the section h2 weight on those
   sections. Activities by week keeps its table since it has 12 rows. */
.admin-stat-list {
  display: grid;
  grid-template-columns: max-content 1fr;
  column-gap: var(--space-8);
  row-gap: var(--space-3);
  margin-top: var(--space-4);
}

.admin-stat-list dt {
  font-size: var(--font-size-sm);
  color: var(--color-text-tertiary);
  font-weight: var(--font-weight-regular);
  align-self: baseline;
}

/* The dd is the data — the visual anchor on the reports page. Larger size
   and bolder weight so the eye lands here first; the dt label reads as
   supporting context to its right. */
.admin-stat-list dd {
  margin: 0;
  font-size: var(--font-size-lg);
  font-variant-numeric: tabular-nums;
  font-weight: var(--font-weight-bold);
  text-align: right;
  line-height: var(--line-height-tight);
}

/* Soften the heavy thead under-rule on tables nested inside an .admin-section
   so it doesn't compete with the section h2's authority. Outside a section
   (e.g. on plain index pages) the stronger rule still applies. */
.admin-section .admin-table thead th {
  border-bottom-color: var(--color-hairline);
}

/* Top-of-page summary band on /admin/reports — four critical numbers
   bracketed by hairlines. Each stat is label-over-value with the value at
   3xl bold so the eye lands there before reading the label. Stacks on
   mobile and goes 4-column at the wide breakpoint. */
.admin-summary-band {
  display: grid;
  grid-template-columns: 1fr;
  gap: var(--space-5);
  margin: var(--space-6) 0 var(--space-12);
  padding: var(--space-6) 0;
  border-top: 0.5px solid var(--color-hairline-soft);
  border-bottom: 0.5px solid var(--color-hairline-soft);
}

.admin-summary-band .admin-summary-stat {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
}

.admin-summary-band .admin-summary-label {
  font-family: var(--font-mono);
  font-size: 11.5px;
  text-transform: uppercase;
  letter-spacing: 0.06em;
  color: var(--color-text-tertiary);
  font-weight: 400;
}

.admin-summary-band .admin-summary-value {
  margin: 0;
  font-size: var(--font-size-3xl);
  font-weight: var(--font-weight-bold);
  font-variant-numeric: tabular-nums;
  line-height: var(--line-height-tight);
}

@media (min-width: 48em) {
  .admin-summary-band {
    grid-template-columns: repeat(4, 1fr);
    gap: var(--space-8);
  }
}

.admin-section {
  margin-top: var(--space-12);
}

.admin-section + .admin-section {
  padding-top: var(--space-8);
  border-top: 0.5px solid var(--color-hairline-soft);
}

.admin-section h2 {
  font-size: clamp(20px, 2vw, 24px);
  font-weight: 400;
  letter-spacing: -0.012em;
  margin-bottom: var(--space-4);
  line-height: 1.2;
}

.admin-section h3 {
  font-size: clamp(16px, 1.5vw, 18px);
  font-weight: 500;
  letter-spacing: -0.005em;
  margin-top: var(--space-6);
  margin-bottom: var(--space-3);
  line-height: 1.25;
}

.admin-section > p,
.admin-section > ul,
.admin-section > ol {
  line-height: var(--line-height-relaxed);
}

.admin-section > p + p {
  margin-top: var(--space-4);
}

/* Top-level index lists and section-nested lists share the same hairline
   rhythm. The selectors target both contexts so a list at /admin/posts
   reads the same as the activities list inside /admin/contacts/:id.
   Single items stay flat — the border kicks in only between siblings. */
.admin-list {
  list-style: none;
}

.admin-list > li {
  padding: var(--space-4) 0;
}

.admin-list > li:first-child {
  padding-top: 0;
}

.admin-list > li + li {
  border-top: 0.5px solid var(--color-hairline-soft);
}

/* Index-row two-line rhythm: when a row's first child is a link (the
   record's primary affordance), promote it to its own visual line and let
   inline meta wrap below. Activity/comment rows that lead with <strong>
   instead of <a> keep their natural inline flow. */
.admin-list > li > a:first-child {
  display: block;
  font-weight: 500;
  letter-spacing: -0.005em;
  margin-bottom: var(--space-1);
}

.admin-list > li > .admin-meta + .admin-meta::before {
  content: "·";
  margin: 0 var(--space-2);
  color: var(--color-text-tertiary);
}

.admin-footer {
  margin-top: var(--space-12);
  padding-top: var(--space-6);
  border-top: 0.5px solid var(--color-hairline-soft);
}

/* Show-page action footer: primary actions land left in DOM order,
   destructive actions pin right via margin-left:auto on the variant
   class. The hairline above gives the page a clear closing edge,
   matching the form-footer treatment. */
.admin-actions-footer {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  margin-top: var(--space-12);
  padding-top: var(--space-6);
  border-top: 0.5px solid var(--color-hairline-soft);
}

.admin-actions-footer .button-destructive {
  margin-left: auto;
}

/* Tab strip used on engagements, tickets, and contacts indexes to switch
   between views (open/closed, active/archived). The active tab carries the
   body color and an under-rule that overlaps the strip's bottom hairline;
   inactive tabs sit tertiary and pick up body color on hover. */
.admin-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-6);
  margin-bottom: var(--space-6);
  border-bottom: 0.5px solid var(--color-hairline-soft);
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.admin-tabs > a {
  display: inline-block;
  padding: var(--space-3) 0;
  margin-bottom: -0.5px;
  color: var(--color-text-tertiary);
  font-weight: 400;
  text-decoration: none;
  border-bottom: 0.5px solid transparent;
  transition: color 0.15s, border-bottom-color 0.15s;
}

.admin-tabs > a:hover {
  color: var(--color-text);
}

.admin-tabs > a.is-active {
  color: var(--color-text);
  border-bottom-color: var(--color-text);
}

/* Filter form: an inset container so it reads as supporting chrome rather
   than primary content. The page-level "New X" CTA stays prominent; the
   filter Apply/Filter submit uses the .button-secondary variant in markup
   to recede in line with the inset treatment. */
.admin-filters {
  display: grid;
  gap: var(--space-4);
  padding: var(--space-5);
  margin-bottom: var(--space-4);
  background: var(--color-stripe);
  border: 0.5px solid var(--color-hairline-soft);
}

/* Active filter chips — render between the .admin-filters form and the
   table itself when the operator has applied filters. Each chip shows
   the field name + value with a "remove this filter" × link. The
   strip echoes which filters are currently narrowing the result set
   without making the operator decode the form's current state. */
.admin-active-filters {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2);
  margin-bottom: var(--space-6);
}

.admin-active-filter-chip {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
  padding: 6px 4px 6px 12px;
  background: var(--color-stripe);
  border: 0.5px solid var(--color-hairline-soft);
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--color-text-secondary);
}

.admin-active-filter-chip-text {
  white-space: nowrap;
}

.admin-active-filter-chip-clear {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 22px;
  height: 22px;
  font-size: 16px;
  line-height: 1;
  color: var(--color-text-tertiary);
  text-decoration: none;
  transition: color 0.15s, background 0.15s;
}

.admin-active-filter-chip-clear:hover {
  color: var(--color-text);
  background: var(--color-hover);
}

.admin-filters .admin-field {
  display: grid;
  gap: var(--space-2);
}

.admin-filters .admin-field > label {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-text-tertiary);
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.admin-filters input[type="text"],
.admin-filters input[type="search"],
.admin-filters input[type="number"],
.admin-filters select {
  /* Chromium opts <select> popups out of document color-scheme theming
     when the element is set to background: transparent, leaving options
     unreadable in dark mode. Pin to --color-background (which already
     swaps per data-theme) so the closed control still matches the page
     surface visually but the popup keeps native dark theming. */
  background: var(--color-background);
  color: var(--color-text);
  border: 0.5px solid var(--color-hairline-strong);
  padding: 11px 14px;
  font: inherit;
  font-size: 15px;
  width: 100%;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.admin-filters input:hover,
.admin-filters select:hover {
  border-color: var(--color-text-tertiary);
}

.admin-filters input:focus,
.admin-filters select:focus {
  border-color: var(--color-text);
  box-shadow: inset 0 0 0 1px var(--color-text);
}

.admin-filters input::placeholder {
  color: var(--color-text-quaternary);
  opacity: 1;
}

.admin-filters .admin-actions {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  align-items: center;
  margin-top: var(--space-2);
}

@media (min-width: 48em) {
  .admin-filters {
    grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
    align-items: end;
  }

  .admin-filters .admin-actions {
    grid-column: 1 / -1;
    margin-top: 0;
  }
}

/* Dashboard "section links" list — large, click-target list on /admin and
   /sales home. Uses the same hairline rhythm but with extra breathing
   room and a stronger heading-link affordance. */
.admin-sections {
  margin-top: var(--space-8);
}

.admin-sections > .admin-list {
  display: grid;
  gap: 0;
}

.admin-sections > .admin-list > li {
  padding: var(--space-5) 0;
}

.admin-sections > .admin-list > li:first-child {
  padding-top: 0;
}

.admin-sections > .admin-list > li + li {
  border-top: 0.5px solid var(--color-hairline-soft);
}

.admin-sections > .admin-list > li > a {
  display: inline-block;
  font-size: clamp(18px, 1.6vw, 22px);
  font-weight: 400;
  letter-spacing: -0.012em;
  margin-bottom: var(--space-1);
}

.admin-sections > .admin-list > li > a:hover {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* ==== Flash messages ==== */

.flash {
  max-width: 72rem;
  margin: var(--space-3) auto 0;
  padding: var(--space-3) var(--space-4);
  border: 0.5px solid var(--color-hairline-strong);
  color: var(--color-text);
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.02em;
}

.flash-alert {
  border-color: var(--color-text);
}

/* ==== Empty states ====

  Index-page emptiness gets a quiet typographic treatment — a single
  top hairline echoes the page header's bottom border, then plenty of
  vertical breathing room, a serif h2, and a serif body sentence
  scoped to 50ch. The previous dashed-block treatment read as a
  templated component; this reads as an editorial "nothing here yet"
  pause that lets per-page copy carry the character. Section-level
  emptiness inside show pages stays on .admin-meta — the same softness
  applies, scaled down. */

.admin-empty-state {
  padding: var(--space-12) var(--space-4);
  text-align: center;
  margin: 0;
  color: var(--color-text-tertiary);
  border-top: 0.5px solid var(--color-hairline-soft);
}

.admin-empty-state h2 {
  font-family: var(--font-serif);
  font-size: clamp(22px, 2.4vw, 28px);
  font-weight: 400;
  color: var(--color-text);
  margin-bottom: var(--space-3);
  letter-spacing: -0.012em;
  line-height: 1.2;
}

.admin-empty-state p {
  margin: 0 auto var(--space-6);
  max-width: 50ch;
  font-family: var(--font-serif);
  font-size: 16px;
  line-height: var(--line-height-relaxed);
}

.admin-empty-state > .button-primary {
  margin-top: var(--space-2);
}

/* ==== Auth-page shell (sign-in, 2FA enroll/verify) ====

  Centered narrow column inside the regular app layout. The brand mark
  in <header> stays as the only chrome above; the auth page itself is
  intentionally quiet. Eyebrow names which surface (Admin / Client /
  Two-factor) so a misclicked nav lands on a recognizable page. */

/* Sprint 4D.2: auth-flow polish. .auth-page chrome reworked onto the
   editorial token vocabulary — same shape as the 4C.3 sign-in polish
   (centered panel, mono eyebrow, hairline-strong inputs, inverse-fill
   submit) — so the 2FA registration / verification and portal magic-link
   sign-in surfaces all read as one auth family. Stays on
   application.html.erb (post-sign-in or portal-shaped, not the public
   doorway). Class names preserved; markup untouched. */
.auth-page {
  max-width: 420px;
  margin: clamp(72px, 10vw, 128px) auto;
  padding: 0 clamp(16px, 4vw, 24px);
}

.auth-page .auth-eyebrow {
  margin: 0 0 12px;
  font-family: var(--font-mono);
  font-size: 12.5px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
  text-transform: uppercase;
}

.auth-page h1 {
  margin: 0 0 16px;
  font-size: clamp(36px, 4vw, 48px);
  line-height: 1.1;
  letter-spacing: -0.022em;
  font-weight: 400;
}

.auth-page .auth-lede {
  margin: 0 0 clamp(28px, 3vw, 36px);
  font-size: clamp(16px, 1.4vw, 19px);
  line-height: 1.55;
  color: var(--color-text-secondary);
}

.auth-page .admin-form {
  margin: 0;
  max-width: none;
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.auth-page .admin-form .admin-field {
  display: flex;
  flex-direction: column;
  gap: 6px;
}

.auth-page .admin-form .admin-field > label {
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
  text-transform: uppercase;
  font-weight: var(--font-weight-regular);
}

.auth-page .admin-form input[type="email"],
.auth-page .admin-form input[type="text"],
.auth-page .admin-form input[type="password"] {
  padding: 12px 14px;
  background: transparent;
  color: var(--color-text);
  border: 0.5px solid var(--color-hairline-strong);
  border-radius: 0;
  font-family: var(--font-mono);
  font-size: 15px;
  line-height: 1.4;
  outline: none;
  transition: border-color 0.15s;
  max-width: none;
}

.auth-page .admin-form input:focus {
  border-color: var(--color-text);
}

.auth-page .admin-actions {
  margin-top: 8px;
}

.auth-page .admin-actions button,
.auth-page .admin-actions input[type="submit"] {
  display: inline-block;
  padding: 12px 24px;
  background: var(--color-background-inverse);
  color: var(--color-text-inverse);
  border: 0.5px solid var(--color-background-inverse);
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  cursor: pointer;
  transition: background 0.15s, color 0.15s, border-color 0.15s;
}

.auth-page .admin-actions button:hover,
.auth-page .admin-actions input[type="submit"]:hover {
  background: transparent;
  color: var(--color-text);
  border-color: var(--color-text);
}

.auth-page .auth-status {
  margin: 16px 0 0;
  font-family: var(--font-mono);
  font-size: 13px;
  letter-spacing: 0.04em;
  color: var(--color-text-tertiary);
}

/* ==== Admin meta text + link affordance ==== */

.admin-meta {
  color: var(--color-text-tertiary);
  font-size: var(--font-size-sm);
}

.admin-meta a,
.admin-table a,
.admin-list a,
.admin-header a {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

/* ==== Admin back-link (breadcrumb-style) ==== */

.admin-back {
  margin-bottom: var(--space-3);
}

/* ==== Accessibility utility ==== */

.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ==== Admin-facing and portal forms (shared .admin-form) ==== */

.admin-form {
  display: grid;
  gap: var(--field-spacing-y);
  max-width: 40rem;
  margin: var(--space-6) 0;
}

.admin-form.admin-inline-form {
  display: flex;
  gap: var(--space-2);
  align-items: center;
  max-width: none;
  margin: 0;
}

.admin-form .admin-field {
  display: grid;
  gap: var(--space-2);
}

.admin-form .admin-field-inline {
  grid-auto-flow: column;
  grid-auto-columns: max-content;
  align-items: center;
  gap: var(--space-3);
}

.admin-form .admin-field > label {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--color-text-tertiary);
  font-weight: 400;
  letter-spacing: 0.04em;
  text-transform: uppercase;
}

.admin-form .admin-field > small,
.admin-form .admin-help-text {
  color: var(--color-text-tertiary);
  font-size: var(--font-size-xs);
  line-height: var(--line-height-relaxed);
}

.admin-form input[type="text"],
.admin-form input[type="email"],
.admin-form input[type="password"],
.admin-form input[type="number"],
.admin-form input[type="url"],
.admin-form input[type="tel"],
.admin-form input[type="search"],
.admin-form input[type="date"],
.admin-form input[type="datetime-local"],
.admin-form input[type="file"],
.admin-form textarea,
.admin-form select {
  /* See the .admin-filters block above for why selects need an explicit
     background instead of `transparent` — same Chromium popup-theming
     quirk applies. The shared rule keeps inputs/textareas/selects
     visually identical (var(--color-background) IS the page surface)
     while restoring readable dropdown options in dark mode. */
  background: var(--color-background);
  color: var(--color-text);
  border: 0.5px solid var(--color-hairline-strong);
  padding: 12px 14px;
  font: inherit;
  font-size: 15px;
  line-height: 1.4;
  width: 100%;
  max-width: 40rem;
  outline: none;
  transition: border-color 0.15s, box-shadow 0.15s;
}

.admin-form input:hover,
.admin-form textarea:hover,
.admin-form select:hover {
  border-color: var(--color-text-tertiary);
}

.admin-form input:focus,
.admin-form textarea:focus,
.admin-form select:focus {
  border-color: var(--color-text);
  box-shadow: inset 0 0 0 1px var(--color-text);
}

.admin-form input::placeholder,
.admin-form textarea::placeholder {
  color: var(--color-text-quaternary);
  opacity: 1;
}

/* aria-invalid="true" — invalidated form field marker. Inverts the
   border + focus weight to make a failed field unmistakable without
   reaching for red (the brand has no accent color). The field still
   reads as the same shape; just its weight changes. */
.admin-form input[aria-invalid="true"],
.admin-form textarea[aria-invalid="true"],
.admin-form select[aria-invalid="true"] {
  border-color: var(--color-text);
  border-width: 1px;
}

.admin-form textarea {
  min-height: 6rem;
  font-family: inherit;
  line-height: 1.5;
}

.admin-form fieldset.admin-fieldset {
  border: 0.5px solid var(--color-hairline-soft);
  padding: var(--space-4);
  display: grid;
  gap: var(--space-3);
}

.admin-form fieldset.admin-fieldset legend {
  padding: 0 var(--space-2);
  color: var(--color-text-tertiary);
  font-family: var(--font-mono);
  font-size: 11.5px;
  font-weight: 400;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.admin-form .admin-errors {
  border: 0.5px solid var(--color-text);
  padding: var(--space-3) var(--space-4);
}

.admin-form .admin-errors h2 {
  font-size: var(--font-size-sm);
  font-weight: 700;
  margin-bottom: var(--space-2);
}

.admin-form .admin-errors ul {
  padding-left: var(--space-6);
  color: var(--color-text-tertiary);
  font-size: var(--font-size-sm);
}

/* Form footer row. Markup convention is `<submit/> <cancel-link/>` —
   row-reverse pins the primary submit to the right and the secondary
   cancel/back link to the left without requiring every form to flip the
   order. Hairline above gives the form a clear closing edge. */
.admin-form .admin-actions {
  display: flex;
  flex-direction: row-reverse;
  flex-wrap: wrap;
  justify-content: flex-start;
  gap: var(--space-4);
  align-items: center;
  margin-top: var(--space-4);
  padding-top: var(--space-5);
  border-top: 0.5px solid var(--color-hairline-soft);
}

.admin-form .admin-actions a {
  text-decoration: underline;
  text-underline-offset: 0.25em;
}

.admin-form .admin-actions a.button-secondary {
  text-decoration: none;
}

/* Submit controls — form submits and button_to-wrapped actions both render
   as <button> / <input type="submit">. button_to is only used inside admin
   and portal views (grep-verified), so targeting .button_to globally is
   safe and covers Delete / Sign out / Publish / Unpublish buttons. Variant
   classes (.button-secondary, .button-destructive) override on the form
   wrapper via higher specificity. */
.admin-form input[type="submit"],
.admin-form button[type="submit"],
.button_to > button {
  display: inline-block;
  background: var(--color-background-inverse);
  color: var(--color-text-inverse);
  padding: var(--space-3) var(--space-6);
  font: inherit;
  font-weight: var(--font-weight-medium);
  border: 1px solid var(--color-background-inverse);
  cursor: pointer;
}

.admin-form input[type="submit"]:hover,
.admin-form button[type="submit"]:hover,
.button_to > button:hover {
  background: transparent;
  color: var(--color-text);
  border-color: var(--color-text);
}

/* Trix editor: the toolbar ships with black SVG icons embedded as data URLs
   that disappear on a dark background. Invert in the default (dark) theme;
   the light-theme override restores original colors. Give the editor area
   a visible border + tokenized background so it matches other form inputs. */
trix-toolbar {
  filter: invert(1);
}

[data-theme="light"] trix-toolbar {
  filter: none;
}

trix-editor {
  background: var(--color-background);
  color: var(--color-text);
  border: 0.5px solid var(--color-hairline-strong);
  padding: var(--space-3) var(--space-4);
  min-height: 8rem;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
    scroll-behavior: auto !important;
  }
}
