: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;
}

.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);
}

/* The prototype hid nav links at <=768px (display: none on every link) which
   is fine for a static demo but breaks production navigation on phones.
   Instead: keep links visible, tighten gap and font, allow .nv and .lk-row
   to wrap so brand sits on its own row when needed. A proper hamburger /
   drawer pattern is tracked as a follow-up dogfood ticket. */
@media (max-width: 768px) {
  .nv {
    flex-wrap: wrap;
    row-gap: 10px;
  }
  /* When .lk-row wraps onto its own line below the brand, width: 100% lets
     justify-content: flex-end push the nav cluster to the right edge of the
     row. Without it the row sits at its natural content width on the left. */
  .lk-row {
    gap: 16px;
    font-size: 12.5px;
    flex-wrap: wrap;
    justify-content: flex-end;
    width: 100%;
  }
}

/* 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 900px (wider than the 768px mobile
   breakpoint because at 768-900px the columns get too cramped for the
   heading to coexist with dense body copy). */
.shift {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 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: 900px) {
  .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: right;
  font-size: clamp(14px, 1.1vw, 15px);
  font-style: italic;
  line-height: 1.5;
  color: var(--color-text-tertiary);
}

.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;
  }
}

/* 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 {
  padding: clamp(72px, 10vw, 128px) 0;
}

.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.45;
  color: var(--color-text);
}

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

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

.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);
}
/*






 */

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: 12px 24px;
  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-secondary,
.button_to.button-secondary > button {
  display: inline-block;
  background: transparent;
  color: var(--color-text);
  padding: 12px 24px;
  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: transparent;
  color: var(--color-text);
}

.button-destructive,
.button_to.button-destructive > button {
  display: inline-block;
  background: transparent;
  color: var(--color-text);
  padding: 12px 24px;
  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);
}

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: var(--font-size-sm);
}

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

.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);
  white-space: nowrap;
}

/* Subtle zebra striping at low opacity, targeting rows directly under the
   table element so nested tables (none today, but defensive) don't restripe
   their parent's rows by accident. */
.admin-table > tbody > tr:nth-child(even) > td {
  background-color: var(--color-stripe);
}

/* Row-hover affordance. Stronger overlay than the stripe so it reads on
   both odd (no stripe) and even (striped) rows. */
.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. */
.admin-page-lede {
  margin: 0 0 var(--space-8);
  max-width: 65ch;
  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-6);
  background: var(--color-stripe);
  border: 0.5px solid var(--color-hairline-soft);
}

.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 {
  background: transparent;
  color: var(--color-text);
  border: 0.5px solid var(--color-hairline-strong);
  padding: 10px 12px;
  font: inherit;
  font-size: 14px;
  width: 100%;
  outline: none;
  transition: border-color 0.15s;
}

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

.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 bordered block with a headline, a one-line
  rationale, and an optional CTA. Section-level emptiness inside show
  pages stays on .admin-meta — the bordered block would be too heavy
  inside an already-bordered section. */

.admin-empty-state {
  border: 0.5px dashed var(--color-hairline-strong);
  padding: var(--space-8) var(--space-6);
  text-align: center;
  margin: var(--space-8) 0;
  color: var(--color-text-tertiary);
}

.admin-empty-state h2 {
  font-size: clamp(20px, 2vw, 24px);
  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-5);
  max-width: 50ch;
  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 {
  background: transparent;
  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;
}

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

.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;
  }
}
