/* ============================================================================
   CrystalBits - Mineral design system

   Art direction is taken from the subject: bits are cut from crystal, so the
   surfaces are cut rather than rounded, edges are hairlines, and the accent is
   the garnet red of the specimen photography rather than an arbitrary brand
   colour. Type is the IBM Plex superfamily: Condensed carries the vertical,
   cut feel in headings, Sans does the reading, Mono carries dates, counts and
   code because they are data, not prose.

   CrystalBits is the reading surface of the family, so the post body gets the
   typographic care: a 68ch measure, a 1.75 line height, and real styles for
   blockquotes, lists and inline code.

   Light is the default because this is a long-form reading surface. Dark is
   the same system with the polarity inverted, and is honoured automatically
   via prefers-color-scheme.

   Accessibility decisions that are load bearing, do not undo them casually:
   - --focus is 2px at >= 3:1 against both grounds. Never set outline:none
     without an equivalent replacement.
   - --edge-strong is the border for anything whose boundary is the only
     indicator of a control. Plain --edge is decorative and deliberately faint.
   - Interactive targets get --tap (24px) minimum height.
   - Links inside prose are underlined; the accent alone does not carry meaning.
   ========================================================================= */

:root {
  /* ---- ground and ink -------------------------------------------------- */
  --paper:        #f4f6f6;
  --surface:      #ffffff;
  --surface-sunk: #eef1f1;
  --ink:          #0e1416;   /* 17.13:1 on --paper */
  --ink-muted:    #55666b;   /* 6.05:1 on --surface */
  --ink-faint:    #5f7075;   /* 5.17:1 on --surface, 4.77:1 on --paper */

  /* ---- edges ----------------------------------------------------------- */
  --edge:         #d8dfe0;   /* decorative hairline */
  --edge-strong:  #7b8e92;   /* 3.43:1 on --surface, 3.16:1 on --paper, 3.02:1 on --surface-sunk */

  /* ---- accent, sampled from the specimen ------------------------------- */
  --accent:       #96233a;   /* 8.08:1 on --surface */
  --accent-deep:  #6b182a;   /* 11.74:1 with white */
  --accent-wash:  #f6e5e8;
  --on-accent:    #ffffff;   /* 8.08:1 on --accent */

  /* ---- status ---------------------------------------------------------- */
  --ok:           #1e7e34;   /* 5.14:1 with white */
  --warn:         #a15c00;   /* 4.62:1 on --surface */
  --danger:       #b3261e;   /* 5.94:1 with white */
  --ore:          #8a5a2b;   /* metadata icon tint, 5.28:1 on --surface */

  /* ---- focus ----------------------------------------------------------- */
  --focus:        #96233a;
  --focus-ring:   0 0 0 2px var(--surface), 0 0 0 4px var(--focus);

  /* ---- type ------------------------------------------------------------ */
  --sans: "IBM Plex Sans", system-ui, -apple-system, "Segoe UI", sans-serif;
  --cond: "IBM Plex Sans Condensed", var(--sans);
  --mono: "IBM Plex Mono", ui-monospace, "SF Mono", Menlo, monospace;

  --step--1: 0.8125rem;
  --step-0:  1rem;
  --step-1:  1.125rem;
  --step-2:  clamp(1.25rem, 1.1rem + 0.6vw, 1.5rem);
  --step-3:  clamp(1.5rem, 1.3rem + 1vw, 1.9rem);
  --step-4:  clamp(2.1rem, 1.6rem + 2.4vw, 3.1rem);
  --step-5:  clamp(2.6rem, 1.8rem + 3.6vw, 3.9rem);

  /* ---- space and geometry ---------------------------------------------- */
  --gap:   1.125rem;
  --pad:   1.375rem;
  --bay:   4rem;
  --shell: 74rem;
  --facet: 14px;   /* the cut corner */
  --tap:   24px;   /* WCAG 2.2 target minimum */
}

@media (prefers-color-scheme: dark) {
  :root {
    --paper:        #070a0b;
    --surface:      #101718;
    --surface-sunk: #0b1112;
    --ink:          #e9f1f0;   /* 17.31:1 on --paper */
    --ink-muted:    #9fb2b3;   /* 8.24:1 on --surface */
    --ink-faint:    #83989a;   /* 5.94:1 on --surface */

    --edge:         #222e30;
    --edge-strong:  #5b6e70;   /* 3.38:1 on --surface, 3.70:1 on --paper, 3.54:1 on --surface-sunk */

    --accent:       #f0808f;   /* 7.07:1 on --surface */
    --accent-deep:  #ca6a79;   /* 5.15:1 with --on-accent */
    --accent-wash:  #361318;
    --on-accent:    #2a0710;   /* 7.21:1 on --accent */

    --ok:           #4ade80;
    --warn:         #f0b357;
    --danger:       #ff7b72;
    --ore:          #d9a066;

    --focus:        #f0808f;
    --focus-ring:   0 0 0 2px var(--paper), 0 0 0 4px var(--focus);
  }
}

/* ============================================================================
   Base
   ========================================================================= */

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

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

body {
  margin: 0;
  background: var(--paper);
  color: var(--ink);
  font: 400 var(--step-0)/1.6 var(--sans);
  -webkit-font-smoothing: antialiased;
}

h1, h2, h3, h4 {
  font-family: var(--cond);
  font-weight: 700;
  line-height: 1.08;
  letter-spacing: -0.015em;
  margin: 0 0 0.5em;
}
h1 { font-size: var(--step-4); }
h2 { font-size: var(--step-3); }
h3 { font-size: var(--step-2); }
h4 { font-size: var(--step-1); }

p { margin: 0 0 1em; }

a { color: var(--accent); text-underline-offset: 0.18em; }

/* Prose links carry an underline: the accent alone is not a sufficient cue. */
p a, li a, .post-body a, .post-excerpt a, .featured-excerpt a { text-decoration: underline; }

/* Navigational and component links opt out, they have their own affordances. */
.nav-link, .logo, .post-title a, .featured-title a, .read-more,
.pagination-link, .footer-links a, .tag, .btn-primary, .btn-secondary,
.search-button { text-decoration: none; }

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

code, kbd, samp { font-family: var(--mono); font-size: 0.92em; }

/* One focus treatment, everywhere. */
:where(a, button, input, select, textarea, summary, [tabindex]):focus-visible {
  outline: 2px solid var(--focus);
  outline-offset: 2px;
  border-radius: 1px;
}

::selection { background: var(--accent); color: var(--on-accent); }

/* ============================================================================
   Primitives
   ========================================================================= */

.container { max-width: var(--shell); margin: 0 auto; padding: 0 1.5rem; }

/* The cut corner. One clipped bevel, never a uniform radius. */
.facet {
  clip-path: polygon(0 0, calc(100% - var(--facet)) 0, 100% var(--facet), 100% 100%, 0 100%);
}

.skip-link {
  position: absolute;
  left: 0.5rem;
  top: -3rem;
  z-index: 100;
  padding: 0.7rem 1.1rem;
  background: var(--accent);
  color: var(--on-accent);
  font-weight: 600;
  transition: top 0.12s ease-out;
}
.skip-link:focus { top: 0.5rem; }

.visually-hidden {
  position: absolute !important;
  width: 1px; height: 1px;
  margin: -1px; padding: 0; border: 0;
  clip-path: inset(50%);
  overflow: hidden; white-space: nowrap;
}

.text-muted { color: var(--ink-muted); }

/* ============================================================================
   Header
   ========================================================================= */

.site-header { background: var(--surface); border-bottom: 1px solid var(--edge); }

.navbar {
  display: flex; align-items: center; gap: 2rem;
  max-width: var(--shell); margin: 0 auto; padding: 0 1.5rem;
  min-height: 4.125rem;
}

.navbar-brand { display: flex; align-items: center; }

.logo {
  display: inline-flex; align-items: center; gap: 0.65rem;
  font: 700 1.3rem/1 var(--cond); letter-spacing: 0.005em;
  color: var(--ink);
}
/* The mark is a drawn hexagonal section, not an emoji. */
.logo::before {
  content: "";
  width: 1.32rem; height: 1.55rem;
  background: var(--accent);
  clip-path: polygon(50% 0, 100% 27%, 100% 73%, 50% 100%, 0 73%, 0 27%);
}

.navbar-menu { display: flex; flex-wrap: wrap; gap: 1.6rem; margin-left: auto; }

.nav-link {
  display: inline-flex; align-items: center;
  min-height: var(--tap);
  color: var(--ink-muted);
  font-size: 0.925rem; font-weight: 500;
  border-bottom: 2px solid transparent;
}
.nav-link:hover { color: var(--ink); border-bottom-color: var(--accent); }

/* ============================================================================
   Intro band

   A publication landing page should get you into an article. This stays
   short so the featured post sits near the top, and search lives in the
   masthead rather than in a hero block.
   ========================================================================= */

.intro {
  display: flex; flex-wrap: wrap; align-items: end; gap: 1.25rem 3rem;
  padding: clamp(1.75rem, 3.5vw, 2.75rem) 0 clamp(1.25rem, 2.5vw, 1.75rem);
  border-bottom: 1px solid var(--edge);
}
.intro-copy { flex: 1 1 28rem; min-width: 0; }

.intro-title { font-size: var(--step-4); margin: 0 0 0.35em; }
.intro-title .accent { color: var(--accent); }

.intro-lede {
  font-size: var(--step-1); color: var(--ink-muted);
  max-width: 54ch; margin: 0;
}

/* The masthead field flexes with the bar; its button is icon-only. */
.search-form-compact { flex: 1 1 18rem; max-width: 30rem; margin-right: 0.5rem; }
.search-form-compact .search-button { padding: 0 0.85rem; }

/* ============================================================================
   Sections
   ========================================================================= */

.featured-section, .recent-posts-section, .newsletter-section,
.posts-section {
  max-width: 56rem; margin: 0 auto;
  padding: var(--bay) 1.5rem 0;
}

/* The article column leaves room for the prose inside to hold its 68ch
   measure (68ch at the body size plus the horizontal padding). */
.post-content {
  max-width: 50rem; margin: 0 auto;
  padding: var(--bay) 1.5rem 0;
}

/* ============================================================================
   Post cards and the featured post
   ========================================================================= */

.posts-grid, .posts-list { display: grid; gap: var(--gap); margin-top: 1.5rem; }

.post-card, .featured-post {
  --facet: 16px;
  position: relative;
  background: var(--surface);
  border: 1px solid var(--edge);
  padding: var(--pad) var(--pad) 1.1rem;
  clip-path: polygon(0 0, calc(100% - var(--facet)) 0, 100% var(--facet), 100% 100%, 0 100%);
  transition: border-color 0.14s ease, background 0.14s ease;
}
/* The whole card is the target, so the whole card reacts, and it reacts the
   same way to a pointer as it does to keyboard focus landing inside it. */
.post-card:hover, .post-card:focus-within { border-color: var(--accent); }
/* The cut corner catches light, the way a real bevel would. Decorative only:
   without pointer-events:none it would swallow clicks in the top-right
   corner, which is now part of the card's click target. */
.post-card::after {
  content: "";
  position: absolute; top: 0; right: 0;
  width: calc(var(--facet) + 8px); height: calc(var(--facet) + 8px);
  background: linear-gradient(225deg, var(--accent) 0 50%, transparent 50%);
  opacity: 0.28; transition: opacity 0.14s ease;
  pointer-events: none;
}
.post-card:hover::after, .post-card:focus-within::after { opacity: 0.9; }

/* The featured post is the same card with a garnet leading edge. Its left
   edge is already accent, so hover carries the other three round to match. */
.featured-post { border-left: 3px solid var(--accent); }
.featured-post:hover, .featured-post:focus-within { border-color: var(--accent); }

.post-card .post-header { margin-bottom: 0.75rem; }

.post-title {
  font: 600 var(--step-2)/1.2 var(--sans);
  letter-spacing: 0; margin: 0 0 0.5rem;
}
.post-title a { color: var(--ink); }
.post-title a:hover { color: var(--accent); }

.featured-title {
  font: 600 var(--step-3)/1.15 var(--sans);
  letter-spacing: 0; margin: 0 0 0.75rem;
}
.featured-title a { color: var(--ink); }
.featured-title a:hover { color: var(--accent); }

/* ---- whole-card click target ------------------------------------------- */

/* The title link stretches over the card with a pseudo-element instead of the
   card being wrapped in an anchor. That keeps the card body to one tab stop
   and keeps the link's accessible name the post title rather than the whole
   card. Known tradeoff: the overlay sits over the excerpt and meta text, so
   drag-selecting that text is harder than it was. */
.post-title a::after, .featured-title a::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
}

/* Every other link in the card rides above the overlay so it keeps its own
   hit area, hover and focus. This is what keeps the featured post's Read More
   and any linked tag independently clickable. The title link is the
   exception: it has to stay unpositioned or its ::after would resolve against
   the title text instead of the card, covering only the title. */
.post-card a, .featured-post a { position: relative; z-index: 1; }
.post-card .post-title a, .featured-post .featured-title a { position: static; }

/* Not outline:none without a replacement. The outline moves from the anchor,
   which is only as wide as the title, onto the overlay, which is the card, so
   the ring is drawn where the click target actually is. Offset inward because
   the card is clip-path'd and an outward ring would be cut away. Still 2px
   var(--focus). */
.post-title a:focus-visible, .featured-title a:focus-visible { outline: none; }
.post-title a:focus-visible::after, .featured-title a:focus-visible::after {
  outline: 2px solid var(--focus);
  outline-offset: -2px;
}

.post-meta {
  display: flex; align-items: center; flex-wrap: wrap; gap: 0.5rem;
  font: 400 0.78rem/1.4 var(--mono); color: var(--ink-muted);
}
.post-separator { color: var(--ink-faint); }

.post-excerpt, .featured-excerpt {
  color: var(--ink-muted); line-height: 1.65; margin: 0.75rem 0 0;
}

.read-more {
  display: inline-flex; align-items: center; gap: 0.4rem;
  min-height: var(--tap);
  margin-top: 1rem;
  color: var(--accent); font-weight: 500; font-size: 0.95rem;
}
.read-more:hover { text-decoration: underline; }

/* ---- tags -------------------------------------------------------------- */

.post-tags { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }

.tag {
  display: inline-flex; align-items: center;
  min-height: var(--tap);
  font: 500 0.72rem/1.55 var(--mono);
  padding: 0.05rem 0.45rem;
  color: var(--accent); background: var(--accent-wash);
  border: 1px solid transparent;
}
a.tag:hover { border-color: var(--accent); }

/* ============================================================================
   Post detail, the reading surface
   ========================================================================= */

.post-content > .post-header {
  margin-bottom: 2rem;
  padding-bottom: 1.5rem;
  border-bottom: 1px solid var(--edge);
}
.post-content .post-title { font-size: var(--step-4); }

.post-body {
  font-size: var(--step-1);
  line-height: 1.75;
  overflow-wrap: break-word;
}
.post-body > * { max-width: 68ch; }

.post-body p { margin: 0 0 1.5em; }

.post-body h1, .post-body h2, .post-body h3, .post-body h4 {
  margin: 2em 0 0.6em;
}
.post-body h1 { font-size: var(--step-3); }
.post-body h2 { font-size: var(--step-2); }
.post-body h3 { font-size: var(--step-1); }
.post-body h4 { font-size: var(--step-0); }

.post-body ul, .post-body ol { margin: 0 0 1.5em; padding-left: 1.5em; }
.post-body li { margin-bottom: 0.4em; }
.post-body li::marker { color: var(--accent); }

.post-body blockquote {
  margin: 1.75em 0;
  padding: 0.25rem 0 0.25rem 1.25rem;
  border-left: 3px solid var(--accent);
  color: var(--ink-muted);
}
.post-body blockquote p:last-child { margin-bottom: 0; }

/* Inline code is data, so it sets in Mono on a sunk chip. */
.post-body code {
  background: var(--surface-sunk);
  border: 1px solid var(--edge);
  padding: 0.1rem 0.35rem;
  font-size: 0.88em;
  overflow-wrap: anywhere;
}

.post-body pre {
  background: var(--surface-sunk);
  border: 1px solid var(--edge);
  padding: 1rem 1.15rem;
  margin: 0 0 1.5em;
  overflow-x: auto;
}
.post-body pre code {
  background: none; border: 0; padding: 0;
  font-size: 0.85rem; line-height: 1.55;
  overflow-wrap: normal;
}

.post-body img { margin: 1.5rem 0; }

.post-body hr { border: 0; border-top: 1px solid var(--edge); margin: 2.5em 0; }

.post-tags-section {
  border-top: 1px solid var(--edge);
  margin-top: 2.5rem; padding-top: 1.5rem;
}
.post-tags-section h2 {
  font: 500 0.7rem/1 var(--mono);
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--ink-muted); margin-bottom: 0.85rem;
}

/* ============================================================================
   Newsletter
   ========================================================================= */

.newsletter-signup, .newsletter-cta {
  --facet: 16px;
  background: var(--surface); border: 1px solid var(--edge);
  padding: clamp(1.5rem, 3vw, 2.25rem);
  clip-path: polygon(0 0, calc(100% - var(--facet)) 0, 100% var(--facet), 100% 100%, 0 100%);
}
.newsletter-cta { margin-top: var(--bay); }
.newsletter-cta .newsletter-signup { border: 0; padding: 0; clip-path: none; }

.newsletter-header h2, .newsletter-header h3 { margin-bottom: 0.4rem; }
.newsletter-header p { color: var(--ink-muted); margin-bottom: 1.25rem; }

.newsletter-cta > h2 { margin-bottom: 0.4rem; }
.newsletter-cta > p { color: var(--ink-muted); }

.newsletter-form, .newsletter-form-inline { display: flex; flex-wrap: wrap; gap: 0.5rem; }
.newsletter-form { max-width: 30rem; }

.newsletter-input, .newsletter-input-inline {
  flex: 1 1 12rem; min-width: 0;
  min-height: 2.5rem;
  border: 1px solid var(--edge-strong);
  background: var(--surface); color: var(--ink);
  padding: 0.6rem 0.85rem; font: 400 1rem var(--sans);
}
.newsletter-input-inline { font-size: 0.9rem; }
.newsletter-input::placeholder, .newsletter-input-inline::placeholder { color: var(--ink-faint); }

.newsletter-button, .newsletter-button-inline {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 2.5rem; padding: 0.6rem 1.35rem;
  border: 1px solid var(--accent);
  background: var(--accent); color: var(--on-accent);
  font: 600 0.92rem var(--sans); cursor: pointer;
}
.newsletter-button:hover, .newsletter-button-inline:hover {
  background: var(--accent-deep); border-color: var(--accent-deep);
}

.newsletter-note {
  margin: 0.85rem 0 0;
  font: 400 0.78rem var(--mono); color: var(--ink-faint);
}

.newsletter-signup-inline { margin-top: 1rem; }

/* ============================================================================
   Search, buttons, pagination
   ========================================================================= */

.search-form {
  display: flex; width: 100%; max-width: 34rem;
  border: 1px solid var(--edge-strong); background: var(--surface);
}
.search-form:focus-within { outline: 2px solid var(--focus); outline-offset: 2px; }
.search-input {
  flex: 1; min-width: 0;
  border: 0; background: none; color: var(--ink);
  padding: 0.6rem 0.85rem; font: 400 0.95rem var(--sans);
}
.search-input::placeholder { color: var(--ink-faint); }
/* The ring lands on the form via focus-within instead. */
.search-input:focus { outline: none; }
.search-button {
  border: 0; cursor: pointer;
  background: var(--ink); color: var(--paper);
  font: 600 0.9rem var(--sans); padding: 0 1.5rem;
  min-height: var(--tap);
  display: inline-flex; align-items: center; gap: 0.4rem;
}
.search-button:hover { background: var(--accent); color: var(--on-accent); }

.btn-primary, .btn-secondary {
  display: inline-flex; align-items: center; justify-content: center; gap: 0.45rem;
  min-height: 2.5rem; padding: 0.6rem 1.35rem;
  font: 600 0.92rem var(--sans); cursor: pointer;
  border: 1px solid var(--accent);
}
.btn-primary { background: var(--accent); color: var(--on-accent); }
.btn-primary:hover { background: var(--accent-deep); border-color: var(--accent-deep); }
.btn-secondary { background: var(--surface); color: var(--accent); }
.btn-secondary:hover { background: var(--accent-wash); }

.view-all { margin-top: 1.5rem; }

.pagination {
  display: flex; align-items: center; justify-content: center; gap: 1rem;
  padding: 2rem 0 0;
}
.pagination-link {
  display: inline-flex; align-items: center; gap: 0.4rem;
  min-height: var(--tap);
  padding: 0.4rem 0.8rem;
  border: 1px solid var(--edge-strong); color: var(--ink);
  font-size: 0.9rem;
}
.pagination-link:hover { border-color: var(--accent); color: var(--accent); }
.pagination-current { font: 400 0.82rem var(--mono); color: var(--ink-muted); }

/* ============================================================================
   Confirmation pages
   ========================================================================= */

.confirmation-message, .confirmation-success, .unsubscribe-message {
  --facet: 16px;
  max-width: 38rem; margin: 0 auto;
  background: var(--surface); border: 1px solid var(--edge);
  padding: clamp(1.75rem, 4vw, 2.75rem);
  margin-top: var(--bay);
  clip-path: polygon(0 0, calc(100% - var(--facet)) 0, 100% var(--facet), 100% 100%, 0 100%);
}
.confirmation-message h1, .confirmation-success h1, .unsubscribe-message h1 {
  font-size: var(--step-3);
}
.confirmation-message p, .confirmation-success p, .unsubscribe-message p {
  color: var(--ink-muted);
}
.confirmation-icon { color: var(--accent); margin-right: 0.35rem; }

.confirmation-actions, .unsubscribe-actions {
  display: flex; flex-wrap: wrap; gap: 0.75rem;
  margin-top: 1.5rem;
}

/* ============================================================================
   Footer
   ========================================================================= */

.site-footer {
  border-top: 1px solid var(--edge); background: var(--surface);
  padding: 2.25rem 0; margin-top: var(--bay);
  font-size: 0.9rem; color: var(--ink-muted);
}

.footer-content {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 15rem), 1fr));
  gap: 2rem;
}

.footer-section h3 {
  font: 500 0.7rem/1 var(--mono);
  letter-spacing: 0.13em; text-transform: uppercase;
  color: var(--ink-muted); margin-bottom: 0.85rem;
}
.footer-section p { font-size: 0.9rem; }

.footer-links { list-style: none; margin: 0; padding: 0; }
.footer-links a {
  display: inline-flex; align-items: center; min-height: var(--tap);
  color: var(--ink-muted);
}
.footer-links a:hover { color: var(--accent); text-decoration: underline; }

.footer-bottom {
  border-top: 1px solid var(--edge);
  margin-top: 2rem; padding-top: 1.5rem;
  font: 400 0.78rem var(--mono); color: var(--ink-faint);
}
.footer-bottom p { margin: 0; }

/* ============================================================================
   Responsive
   ========================================================================= */

@media (max-width: 60rem) {
  .hero-content { grid-template-columns: minmax(0, 1fr); }
  .hero-figure { order: -1; max-width: 22rem; }
}

@media (max-width: 40rem) {
  :root { --bay: 2.75rem; }
  .navbar { flex-wrap: wrap; gap: 0.75rem; padding-top: 0.75rem; padding-bottom: 0.75rem; }
  .navbar-menu { margin-left: 0; width: 100%; gap: 1.1rem; }
}

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

/* ============================================================================
   Job ad (CrystalGigs)

   Paid placement, so it is drawn as an inset rather than as one more section
   of this site: sunk ground, a rule along the top, and the disclosure line
   before anything else. It deliberately does not reuse the card styles this
   site uses for its own content, because an ad dressed as a listing is a dark
   pattern.

   The component renders nothing when there is nothing to advertise, so none
   of these rules need an empty state.
   ========================================================================= */

.job-ad {
  /* Same gutters and shell as .container, so the strip lines up with the
     content above it without having to be wrapped in one. */
  width: min(calc(var(--shell) - 3rem), calc(100% - 3rem));
  margin: var(--bay) auto 0;
  padding: 1.1rem var(--pad) 1.25rem;
  background: var(--surface-sunk);
  border: 1px solid var(--edge);
  border-top: 2px solid var(--edge-strong);
  clip-path: polygon(0 0, calc(100% - var(--facet)) 0, 100% var(--facet), 100% 100%, 0 100%);
}

.job-ad-head {
  display: flex; align-items: baseline; flex-wrap: wrap;
  gap: 0.35rem 0.75rem;
  margin-bottom: 0.9rem;
}

/* The disclosure comes first in the markup and reads first, because a reader
   should know this is an ad before they read the offer. */
.job-ad-disclosure {
  order: -1; flex-basis: 100%;
  margin: 0 0 0.15rem;
  font: 600 var(--step--1)/1.2 var(--mono);
  letter-spacing: 0.09em; text-transform: uppercase;
  color: var(--ink-muted);   /* 5.28:1 on --surface-sunk light, 8.61:1 dark */
}
.job-ad-icon { margin-right: 0.4rem; color: var(--ink-faint); }

.job-ad-heading {
  margin: 0;
  font: 700 var(--step-1)/1.2 var(--cond);
  letter-spacing: -0.01em;
  color: var(--ink);
}

.job-ad-list {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
  gap: var(--gap);
  list-style: none; margin: 0; padding: 0;
}

.job-ad-item {
  display: flex; flex-direction: column; align-items: flex-start;
  gap: 0.3rem;
  padding: 0.85rem 1rem;
  background: var(--surface);
  border: 1px solid var(--edge);
}
.job-ad-item-featured { border-left: 3px solid var(--accent); }

.job-ad-title {
  display: inline-flex; align-items: center; min-height: var(--tap);
  font: 600 var(--step-0)/1.3 var(--sans);
  color: var(--ink);
  /* Underlined, because the accent alone does not carry meaning. */
  text-decoration: underline; text-underline-offset: 2px;
}
.job-ad-title:hover { color: var(--accent); }

.job-ad-featured {
  padding: 0.05rem 0.45rem;
  font: 600 var(--step--1)/1.5 var(--mono);
  color: var(--accent);            /* 6.66:1 light, 6.48:1 dark on --accent-wash */
  background: var(--accent-wash);
  /* The wash alone barely separates from the card, so the hairline draws it. */
  border: 1px solid var(--accent);
}

.job-ad-meta {
  display: flex; flex-wrap: wrap; gap: 0 0.5rem;
  margin: 0;
  font-size: var(--step--1);
  color: var(--ink-muted);
}
/* Separators are drawn, never typed, so a screen reader reads the fields as a
   list of facts rather than announcing punctuation between them. */
.job-ad-meta span + span::before { content: "\00b7"; margin-right: 0.5rem; }

@media (max-width: 40rem) {
  .job-ad { padding: 1rem 1.1rem 1.15rem; }
  .job-ad-list { grid-template-columns: minmax(0, 1fr); }
}


/* ============================================================================
   Editorial pipeline: contribution, news index, provenance, moderation

   Provenance is the point of this section, so it is styled as content rather
   than as chrome. The origin badge sits above the attribution at readable
   size, and the machine-drafted badge is the loudest of the three because
   that is the one a reader most needs to notice.

   Colour never carries the meaning on its own: every badge pairs its tint
   with an icon and with the label spelled out in words.
   ========================================================================= */

/* ---- provenance --------------------------------------------------------- */

.provenance { margin-top: 0.9rem; }

.provenance-badge {
  display: inline-flex; align-items: center; gap: 0.4rem;
  min-height: var(--tap);
  padding: 0.25rem 0.6rem;
  border: 1px solid var(--edge-strong);
  background: var(--surface-sunk);
  color: var(--ink-muted);
  font: 600 var(--step--1)/1.3 var(--cond);
  letter-spacing: 0.02em;
  text-transform: uppercase;
}

.provenance-badge-human    { color: var(--ok); border-color: var(--ok); }
.provenance-badge-upstream { color: var(--ore); border-color: var(--ore); }

/* The one badge that gets the accent ground. A reader should not have to
   look for the answer to "did a person write this". */
.provenance-badge-machine {
  background: var(--accent-wash);
  border-color: var(--accent);
  color: var(--accent-deep);
}

.provenance-attribution {
  margin: 0.55rem 0 0;
  color: var(--ink);
  font-size: var(--step--1);
}

.provenance-date,
.provenance-source,
.provenance-license {
  margin: 0.2rem 0 0;
  color: var(--ink-muted);
  font: 400 var(--step--1)/1.5 var(--mono);
}

.provenance-source a { text-decoration: underline; overflow-wrap: anywhere; }

.provenance-license { font-family: var(--sans); font-style: italic; }

.provenance-sources { margin-top: 0.7rem; }
.provenance-sources-label { margin: 0 0 0.3rem; font-size: var(--step--1); color: var(--ink-muted); }
.provenance-sources ul { margin: 0; padding-left: 1.1rem; }
.provenance-sources li { font: 400 var(--step--1)/1.6 var(--mono); overflow-wrap: anywhere; }

/* ---- news index --------------------------------------------------------- */

.news-section { padding: var(--bay) 0; }
.news-header { margin-bottom: 1.5rem; }
.news-lede { max-width: 62ch; color: var(--ink-muted); font-size: var(--step-1); }

.news-filters { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.75rem; }

.news-filter {
  display: inline-flex; align-items: center;
  min-height: var(--tap); padding: 0.4rem 0.9rem;
  border: 1px solid var(--edge-strong);
  background: var(--surface);
  color: var(--ink);
  font: 600 0.9rem var(--sans);
  text-decoration: none;
}
.news-filter:hover { background: var(--surface-sunk); }

/* Current is marked by fill and by aria-current, not by fill alone. */
.news-filter-current {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--on-accent);
}

.news-list { display: grid; gap: 1.25rem; }

.content-card {
  border: 1px solid var(--edge);
  border-top: 2px solid var(--edge-strong);
  background: var(--surface);
  padding: var(--pad) var(--pad) 1.2rem;
  clip-path: polygon(0 0, calc(100% - var(--facet)) 0, 100% var(--facet), 100% 100%, 0 100%);
}
.content-card-generated { border-top-color: var(--accent); }
.content-card-crystal-blog { border-top-color: var(--ore); }
.content-card-contribution { border-top-color: var(--ok); }

.content-card-title { font-size: var(--step-2); margin: 0 0 0.4rem; }
.content-card-title a { color: var(--ink); text-decoration: none; }
.content-card-title a:hover { color: var(--accent); text-decoration: underline; }
.content-card-external { font-size: 0.7em; color: var(--ink-faint); }

.content-card-summary { margin: 0; color: var(--ink-muted); max-width: 68ch; }

.news-empty {
  border: 1px dashed var(--edge-strong);
  padding: clamp(1.5rem, 4vw, 2.5rem);
  text-align: center;
  color: var(--ink-muted);
}

.news-sources-note {
  margin-top: var(--bay);
  border-top: 1px solid var(--edge);
  padding-top: 1.5rem;
  color: var(--ink-muted);
  font-size: var(--step--1);
}
.news-sources-note h2 { font-size: var(--step-1); color: var(--ink); }
.news-sources-note li { margin-bottom: 0.4rem; max-width: 72ch; }

/* ---- news detail -------------------------------------------------------- */

.content-detail { max-width: 68ch; margin: 0 auto; padding: var(--bay) 0; }
.content-detail-title { font-size: var(--step-4); }
.content-detail-summary { color: var(--ink-muted); font-size: var(--step-1); }
.content-detail-body { line-height: 1.75; }
.content-detail-body a { text-decoration: underline; }
.content-detail-body pre {
  background: var(--surface-sunk);
  border-left: 2px solid var(--edge-strong);
  padding: 0.9rem 1.1rem;
  overflow-x: auto;
}
.content-detail-body blockquote {
  margin: 1.2rem 0;
  padding-left: 1.1rem;
  border-left: 2px solid var(--accent);
  color: var(--ink-muted);
}

/* Placed above the text on purpose: a reader is told what this is before
   they read it, not after. */
.machine-notice {
  display: flex; gap: 0.85rem; align-items: flex-start;
  margin: 0 0 1.75rem;
  padding: 1rem 1.15rem;
  background: var(--accent-wash);
  border-left: 3px solid var(--accent);
  color: var(--accent-deep);
}
.machine-notice p { margin: 0.25rem 0 0; color: var(--ink); font-size: var(--step--1); }
.machine-notice strong { font-family: var(--cond); letter-spacing: 0.02em; text-transform: uppercase; }

/* ---- contribute --------------------------------------------------------- */

.contribute-section, .contribute-thanks { padding: var(--bay) 0; max-width: 72ch; }
.contribute-lede { font-size: var(--step-1); color: var(--ink-muted); max-width: 62ch; }

.contribute-expectations { display: grid; gap: 1.25rem; margin: 2rem 0 2.5rem; }

.contribute-panel {
  border: 1px solid var(--edge);
  border-top: 2px solid var(--edge-strong);
  background: var(--surface);
  padding: var(--pad);
  clip-path: polygon(0 0, calc(100% - var(--facet)) 0, 100% var(--facet), 100% 100%, 0 100%);
}
.contribute-panel h2 { font-size: var(--step-2); }
.contribute-panel li { margin-bottom: 0.4rem; }

.contribute-note {
  margin: 1rem 0 0;
  padding-top: 0.75rem;
  border-top: 1px solid var(--edge);
  color: var(--ink-muted);
  font-size: var(--step--1);
}

.contribute-form { display: grid; gap: 1.4rem; }

.form-field { display: grid; gap: 0.35rem; }
.form-field label { font: 600 0.95rem var(--sans); color: var(--ink); }

/* A hint, not a placeholder. Placeholders vanish on input and are not a
   dependable accessible name (WCAG 3.3.2). */
.form-hint { margin: 0; color: var(--ink-muted); font-size: var(--step--1); }

.form-input, .form-textarea {
  width: 100%;
  min-height: 2.6rem;
  padding: 0.6rem 0.8rem;
  /* The border is the only thing marking where the control is, so it uses
     --edge-strong, which clears 3:1 against every ground in both schemes. */
  border: 1px solid var(--edge-strong);
  background: var(--surface);
  color: var(--ink);
  font: 400 var(--step-0) var(--sans);
}
.form-textarea { font-family: var(--mono); font-size: var(--step--1); line-height: 1.65; resize: vertical; }

.form-field-invalid .form-input,
.form-field-invalid .form-textarea { border-color: var(--danger); border-width: 2px; }

/* Errors are announced in words and tied to the field with aria-describedby;
   the red is reinforcement, never the message. */
.form-error { margin: 0; color: var(--danger); font-size: var(--step--1); font-weight: 600; }

.contribute-submit { justify-self: start; }

/* ---- moderation queue --------------------------------------------------- */

.moderation { padding: var(--bay) 0; }
.moderation-lede { color: var(--ink-muted); max-width: 66ch; }

.moderation-status {
  display: flex; align-items: flex-start; gap: 0.6rem;
  margin-bottom: 1.5rem; padding: 0.85rem 1rem;
  border: 1px solid var(--edge-strong);
  background: var(--surface-sunk);
  color: var(--ink-muted);
  font-size: var(--step--1);
}
.moderation-status p { margin: 0; }
.moderation-status code { background: var(--surface); padding: 0.1rem 0.35rem; border: 1px solid var(--edge); }
.moderation-status-off { border-color: var(--warn); color: var(--warn); }

.moderation-tabs { display: flex; flex-wrap: wrap; gap: 0.5rem; margin-bottom: 1.75rem; }
.moderation-tab {
  display: inline-flex; align-items: center;
  min-height: var(--tap); padding: 0.4rem 0.9rem;
  border: 1px solid var(--edge-strong);
  background: var(--surface); color: var(--ink);
  font: 600 0.9rem var(--sans); text-decoration: none;
}
.moderation-tab-current { background: var(--accent); border-color: var(--accent); color: var(--on-accent); }

.moderation-list { display: grid; gap: 1.25rem; }

.moderation-item {
  border: 1px solid var(--edge);
  border-left: 3px solid var(--edge-strong);
  background: var(--surface);
  padding: var(--pad);
}

.moderation-item-head {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between; gap: 0.75rem;
}
.moderation-item-title { font-size: var(--step-2); margin: 0; }

.moderation-state {
  padding: 0.15rem 0.55rem;
  border: 1px solid currentColor;
  font: 600 var(--step--1) var(--mono);
  text-transform: uppercase;
}
.moderation-state-submitted { color: var(--ore); }
.moderation-state-draft     { color: var(--ink-muted); }
.moderation-state-approved  { color: var(--ok); }
.moderation-state-rejected  { color: var(--danger); }

.moderation-contact { margin: 0.6rem 0 0; color: var(--ink-muted); font-size: var(--step--1); }

.moderation-preview { margin-top: 1rem; border-top: 1px solid var(--edge); padding-top: 0.75rem; }
.moderation-preview summary { cursor: pointer; min-height: var(--tap); font-weight: 600; color: var(--accent); }
.moderation-preview .content-detail-body { margin-top: 0.9rem; max-width: 68ch; }

.moderation-summary { margin: 0.8rem 0 0; color: var(--ink-muted); }

.moderation-actions { display: flex; flex-wrap: wrap; gap: 0.6rem; margin-top: 1.1rem; }
.moderation-decision { margin: 0; }

@media (min-width: 48rem) {
  .contribute-expectations { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 40rem) {
  .content-card { padding: 1rem 1.1rem 1.15rem; }
  .moderation-item-head { flex-direction: column; align-items: flex-start; gap: 0.4rem; }
}