/* ===============================================================
   Jolly Associates — Careers

   A dark private-client system: a midnight-navy canvas holding
   pearl ink, champagne pill CTAs, 16px cards, and sapphire-and-
   champagne glows drifting behind the headlines.

   Type is all-sans: Inter Tight for display, pulled tight, and
   Inter for everything else. It reads crisper on screen at these
   sizes than a serif does.

   One accent family: champagne. It is the CTA fill, the eyebrows,
   the rules, the markers and the hover moments. Everything else is
   blue-tinted darkness and pearl.
   =============================================================== */

/* Google Fonts loads via a <link rel="stylesheet"> in each page's <head>
   (right after the preconnect hints those pages already carry), not an
   @import here. @import makes the browser fetch and resolve the imported
   stylesheet before it can apply ANY of the rules below — including the
   masthead's own layout — so a slow or first-visit font request was
   delaying the whole navbar's appearance, not just its type. A parallel
   <link> can't block this file at all. */

/* ------------------------------ tokens ------------------------------ */

:root {
  /* ink & text — pearl and blue-tinted greys on the dark canvas */
  --ink: #eef0e9;
  --primary: #d3b578;
  --primary-active: #e2c78e;
  --body-text: #aeb6c2;
  --body-strong: #d9dee6;
  --muted: #8791a1;
  --muted-soft: #5d6879;

  /* champagne — the one accent. A text cut, a brighter decorative
     cut, and a wash for glows and highlights. */
  --brass: #d0b075;
  --brass-bright: #e3c88f;
  --brass-soft: rgba(211, 181, 120, 0.14);

  /* surfaces — each one a step up out of the dark */
  --canvas: #0b1220;
  --canvas-soft: #0e1626;
  --surface-card: #131c2e;
  --surface-strong: #1c2739;
  --on-primary: #191309;

  /* hairlines — the only borders in the system */
  --hairline: #202b3e;
  --hairline-soft: #182238;
  --hairline-strong: #31405a;

  /* atmosphere: decoration only, never a fill or a text colour.
     The names are legacy; the values are glows for the dark canvas:
     sapphire, champagne, steel, deep sea and old bronze. */
  --orb-mint: #23406e;
  --orb-peach: #8a7440;
  --orb-lavender: #2e4a63;
  --orb-sky: #24365c;
  --orb-rose: #77613a;

  --success: #45c07a;
  --error: #e06e6e;

  --display: 'Inter Tight', 'Inter', system-ui, sans-serif;
  --body: 'Inter', system-ui, -apple-system, sans-serif;

  /* radii */
  --r-xs: 4px;
  --r-sm: 6px;
  --r-md: 8px;
  --r-lg: 12px;
  --r-xl: 16px;
  --r-xxl: 24px;
  --r-pill: 9999px;

  /* rhythm */
  --shell: 1200px;
  --gutter: clamp(1.25rem, 5vw, 3rem);
  --section: clamp(2.5rem, 5vw, 4rem);

  /* on a dark canvas, shadows are pools of deeper dark */
  --drop: 0 6px 20px rgba(0, 0, 0, 0.35);
  --drop-lg: 0 28px 64px -16px rgba(0, 0, 0, 0.55);

  --ease: cubic-bezier(0.22, 0.61, 0.36, 1);
}

/* ------------------------------ reset ------------------------------ */

*,
*::before,
*::after {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/* The UA rule for [hidden] is display:none, but any author rule that sets
   display — .field-row is a grid, .filters is a flex — outranks it and the
   element stays visible. This is what kept the salary fields on screen with
   "Show compensation" unticked. */
[hidden] {
  display: none !important;
}

body {
  min-height: 100vh;
  background: var(--canvas);
  color: var(--ink);
  font: 400 1rem/1.5 var(--body);
  letter-spacing: 0.01em;
  -webkit-font-smoothing: antialiased;
}

img {
  max-width: 100%;
  display: block;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

a {
  color: inherit;
  text-decoration: none;
}

:focus-visible {
  outline: 2px solid var(--primary);
  outline-offset: 2px;
  border-radius: var(--r-xs);
}

::selection {
  background: rgba(211, 181, 120, 0.85);
  color: #101423;
}

/* A fixed film of grain over everything — it breaks the digital flatness
   of the ivory canvas. Three percent, and only ever texture. */
.page::after {
  content: '';
  position: fixed;
  inset: 0;
  z-index: 80;
  pointer-events: none;
  opacity: 0.3;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='160' height='160'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3CfeComponentTransfer%3E%3CfeFuncA type='linear' slope='0.09'/%3E%3C/feComponentTransfer%3E%3C/filter%3E%3Crect width='160' height='160' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* --------------------------- typography --------------------------- */

/* Display is Inter Tight at 600, tracked in. A grotesque needs weight and
   negative tracking to hold a headline the way a serif holds it with shape. */
h1,
h2,
h3,
h4 {
  font-family: var(--display);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -0.02em;
}

/* Named .serif from the old type system. The name is a lie, but it is
   spread across every page's markup and it still means "display face". */
.serif {
  font-family: var(--display);
  font-weight: 600;
  letter-spacing: -0.02em;
}

/* caption-uppercase — section labels and badges, in brass */
.label {
  display: inline-block;
  font: 600 0.72rem/1.4 var(--body);
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--brass);
}

/* Eyebrow position only — a short brass rule leads the label. Inline labels
   (card heads, the count pill) stay a plain brass caption. */
.band__head > .label,
.page-head > div > .label:first-child,
.detail__head .label:first-child,
.rail__head > .label:first-child {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
}

.band__head > .label::before,
.page-head > div > .label:first-child::before,
.detail__head .label:first-child::before,
.rail__head > .label:first-child::before {
  content: '';
  width: 1.4rem;
  height: 1px;
  background: var(--brass-bright);
}

.label--brass {
  color: var(--brass);
}

.muted {
  color: var(--muted);
}

/* ------------------------------ shell ------------------------------ */

.shell {
  width: 100%;
  max-width: var(--shell);
  margin-inline: auto;
  padding-inline: var(--gutter);
  position: relative;
}

.page {
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  /* Full-bleed rows are sized against 100vw, which counts the scrollbar and
     would otherwise leave the page scrollable sideways by its width. `clip`
     rather than `hidden`: it does not create a scroll container, so sticky
     positioning and in-page anchors keep working. */
  overflow-x: clip;
}

main {
  flex: 1;
}

/* ------------------------------ banner ----------------------------- */

.demo-banner {
  background: var(--primary);
  color: var(--on-primary);
  text-align: center;
  padding: 0.7rem 1rem;
  font: 500 0.8rem/1.5 var(--body);
}

/* ------------------------------ header ----------------------------- */

.masthead {
  background: var(--canvas);
  background: color-mix(in srgb, var(--canvas) 86%, transparent);
  -webkit-backdrop-filter: blur(12px);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid var(--hairline);
  position: sticky;
  top: 0;
  z-index: 20;
  transition: box-shadow 0.3s var(--ease);
}

/* Once the page moves, the bar earns a shadow so it reads as floating. */
.masthead.is-scrolled {
  box-shadow: 0 12px 32px -16px rgba(0, 0, 0, 0.6);
}

/* The reading position, drawn in gold along the very top edge.
   ui.js creates it and drives the scaleX; without a script it is
   simply never there. */
.scroll-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  z-index: 90;
  pointer-events: none;
  background: linear-gradient(90deg, var(--brass), var(--brass-bright));
  transform-origin: 0 50%;
  transform: scaleX(0);
}

.masthead__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 2rem;
  min-height: 72px;
}

.wordmark {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.wordmark__name {
  font-family: var(--display);
  font-size: 1.3rem;
  font-weight: 600;
  letter-spacing: -0.025em;
  line-height: 1.1;
  color: var(--ink);
}

.wordmark__rule {
  font: 500 0.7rem/1.3 var(--body);
  letter-spacing: 0.02em;
  color: var(--muted);
}

/* Hidden above the nav-collapse breakpoint (below); shown as a hamburger
   once the six links no longer fit the row. */
.nav-toggle {
  display: none;
  align-items: center;
  justify-content: center;
  width: 40px;
  height: 40px;
  padding: 0;
  flex-shrink: 0;
  background: transparent;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-pill);
  color: var(--ink);
  cursor: pointer;
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease);
}

.nav-toggle:hover {
  background: var(--surface-strong);
}

.nav-toggle__bars {
  position: relative;
  width: 16px;
  height: 11px;
}

.nav-toggle__bars span {
  position: absolute;
  left: 0;
  right: 0;
  height: 1.5px;
  background: currentColor;
  border-radius: 1px;
  transition: transform 0.25s var(--ease), opacity 0.2s var(--ease), top 0.25s var(--ease);
}

.nav-toggle__bars span:nth-child(1) {
  top: 0;
}

.nav-toggle__bars span:nth-child(2) {
  top: 5px;
}

.nav-toggle__bars span:nth-child(3) {
  top: 10px;
}

/* The bars cross into an "X" once the panel is open. */
.nav-toggle[aria-expanded='true'] .nav-toggle__bars span:nth-child(1) {
  top: 5px;
  transform: rotate(45deg);
}

.nav-toggle[aria-expanded='true'] .nav-toggle__bars span:nth-child(2) {
  opacity: 0;
}

.nav-toggle[aria-expanded='true'] .nav-toggle__bars span:nth-child(3) {
  top: 5px;
  transform: rotate(-45deg);
}

.nav {
  display: flex;
  align-items: center;
  gap: 1.75rem;
}

.nav a {
  position: relative;
  font: 500 0.94rem/1.4 var(--body);
  color: var(--muted);
  transition: color 0.2s var(--ease);
}

/* A brass underline that draws in from the left. */
.nav a::after {
  content: '';
  position: absolute;
  left: 0;
  right: 100%;
  bottom: -5px;
  height: 1.5px;
  background: var(--brass-bright);
  transition: right 0.28s var(--ease);
}

.nav a:hover,
.nav a[aria-current='page'] {
  color: var(--ink);
}

/* Touch has no hover to lean on, so the link itself needs a bigger hit
   area — text-line-height alone (~21px) is well under the 44px touch
   target guideline. Scoped to coarse pointers only: a mouse-driven
   desktop keeps the tighter nav exactly as designed. */
@media (pointer: coarse) {
  .nav a {
    padding-block: 0.65rem;
  }

  .nav a::after {
    bottom: 0.1rem;
  }
}

.nav a:hover::after,
.nav a[aria-current='page']::after {
  right: 0;
}

/* The signed-in account. Lives here and nowhere else on the page. */
.nav__account {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding-left: 1.5rem;
  border-left: 1px solid var(--hairline);
}

.nav__email {
  font: 400 0.88rem/1.4 var(--body);
  color: var(--muted);
  max-width: 16rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.nav__signout {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  flex-shrink: 0;
  background: transparent;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-pill);
  color: var(--body-text);
  cursor: pointer;
  transition: background 0.2s var(--ease), color 0.2s var(--ease),
    border-color 0.2s var(--ease);
}

.nav__signout:hover {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}

/* ------------------------------- hero ------------------------------ */

/* The hero owns the first screen: full viewport height under the 72px
   masthead, with the copy dead-centre. */
.hero {
  padding-block: var(--section);
  position: relative;
  overflow: hidden;
  text-align: center;
  min-height: calc(100vh - 72px);
  min-height: calc(100svh - 72px);
  display: grid;
  align-items: center;
}

/* The atmospheric orbs — sage and champagne blooms drifting slowly behind
   the headline. They carry no content, only weather. */
.hero::before,
.hero::after {
  content: '';
  position: absolute;
  z-index: 0;
  border-radius: 50%;
  pointer-events: none;
  filter: blur(60px);
  opacity: 0.55;
}

.hero::before {
  width: 34rem;
  height: 34rem;
  top: -12rem;
  left: 50%;
  transform: translateX(-62%);
  background: radial-gradient(
    circle at 50% 50%,
    var(--orb-mint) 0%,
    rgba(35, 64, 110, 0) 68%
  );
  animation: orb-drift-a 26s ease-in-out infinite alternate;
}

.hero::after {
  width: 30rem;
  height: 30rem;
  top: -7rem;
  left: 50%;
  transform: translateX(-8%);
  background: radial-gradient(
    circle at 50% 50%,
    var(--orb-peach) 0%,
    rgba(138, 116, 64, 0) 66%
  );
  animation: orb-drift-b 32s ease-in-out infinite alternate;
}

@keyframes orb-drift-a {
  from {
    transform: translateX(-62%) translateY(0) scale(1);
  }
  to {
    transform: translateX(-50%) translateY(2.5rem) scale(1.1);
  }
}

@keyframes orb-drift-b {
  from {
    transform: translateX(-8%) translateY(0) scale(1);
  }
  to {
    transform: translateX(-22%) translateY(1.75rem) scale(1.07);
  }
}

/* Sits above the ambient orbs (z-index: 0) and the particle canvas home.js
   mounts here (z-index: 1) — empty and inert until then, so nothing above
   this line depends on it existing. */
#hero-field {
  position: absolute;
  inset: 0;
  z-index: 1;
}

.hero__inner {
  position: relative;
  z-index: 2;
  max-width: 52rem;
  margin-inline: auto;
}

/* Parallax: ui.js feeds --sy with the scroll position, and the copy slides
   down slower than the page while fading — depth against the orbs and the
   ghost cursors. The var is never set with reduced motion or no script. */
html.anim .hero__inner {
  transform: translateY(calc(var(--sy, 0) * 0.28px));
  opacity: clamp(0, calc(1 - var(--sy, 0) / 650), 1);
}

/* Two sentences, one line each on desktop. Sized to hold the longer of the
   two — the second line — inside .hero__inner without wrapping. */
.hero h1 {
  font-size: clamp(1.9rem, 4.4vw, 3.1rem);
  line-height: 1.08;
  letter-spacing: -0.025em;
  margin-block: 0 1.5rem;
}

.hero__line1 {
  display: block;
}

/* A size down from the opening line, at the same weight. */
.hero__line2 {
  display: block;
  font-size: 0.74em;
  margin-top: 0.2em;
}

/* The opening cascade: line, line, paragraph, actions — each a beat apart.
   Pure CSS, so it plays with or without scripts; the reduced-motion block
   at the end of this file collapses it to an instant appearance. */
.hero__line1 {
  animation: riseIn 0.7s var(--ease) 0.05s backwards;
}

.hero__line2 {
  animation: riseIn 0.7s var(--ease) 0.2s backwards;
}

.hero p {
  animation: riseIn 0.7s var(--ease) 0.36s backwards;
}

.hero__actions {
  animation: riseIn 0.7s var(--ease) 0.5s backwards;
}

.hero h1 em {
  font-style: italic;
  font-weight: 500;
  color: var(--brass);
}

/* The typewriter caret. ui.js empties the target and types it back in
   ahead of this gold bar, which keeps blinking after the line is
   complete. A real element, not a pseudo — headings already spend
   their ::after on the gold rule. */
.tw-caret {
  display: inline-block;
  width: 0.06em;
  height: 0.9em;
  margin-left: 0.09em;
  vertical-align: -0.06em;
  background: var(--brass-bright);
  animation: caret 0.85s steps(1) infinite;
}

@keyframes caret {
  50% {
    opacity: 0;
  }
}


.hero p {
  font-size: 1.06rem;
  line-height: 1.6;
  color: var(--body-text);
  max-width: 38rem;
  margin-inline: auto;
}

.hero__actions {
  display: flex;
  justify-content: center;
  gap: 0.6rem;
  margin-top: 2.25rem;
}

.hero__count {
  font: 600 0.85rem/1 var(--body);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* --------------------------- home: bands --------------------------- */

.band {
  padding-block: var(--section);
  border-top: 1px solid var(--hairline);
}

.band--soft {
  background: var(--canvas-soft);
}

.band__head {
  max-width: 40rem;
  margin-bottom: 2.75rem;
}

.band__head h2 {
  font-size: clamp(1.4rem, 2.4vw, 1.75rem);
  margin-top: 0.75rem;
}


.band__head p {
  color: var(--body-text);
  line-height: 1.6;
  margin-top: 1rem;
}

.pillars {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: 0.75rem;
}

.pillar {
  position: relative;
  overflow: hidden;
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  padding: 1.6rem;
  /* Lift and tilt live in custom properties so the hover lift and the
     pointer-driven 3D tilt from ui.js can compose instead of fighting. */
  transform: perspective(700px) rotateX(var(--rx, 0deg)) rotateY(var(--ry, 0deg))
    translateY(var(--lift, 0));
  transition: box-shadow 0.25s var(--ease), border-color 0.25s var(--ease),
    transform 0.3s var(--ease);
}

/* A brass spotlight that follows the cursor across the card. The --mx/--my
   coordinates are set by ui.js on pointer-fine devices; without them the
   glow simply blooms from the centre. */
.pillar::before {
  content: '';
  position: absolute;
  inset: 0;
  opacity: 0;
  pointer-events: none;
  background: radial-gradient(
    240px circle at var(--mx, 50%) var(--my, 40%),
    var(--brass-soft),
    transparent 70%
  );
  transition: opacity 0.3s var(--ease);
}

.pillar:hover::before {
  opacity: 1;
}

.pillar:hover {
  --lift: -3px;
  border-color: var(--hairline-strong);
  box-shadow: var(--drop);
}

/* A light sweep across the card border on hover — a second, slower layer
   on top of the brass cursor-spotlight above (.pillar::before). */
.pillar::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  padding: 1px;
  background: linear-gradient(
    115deg,
    transparent 30%,
    var(--brass-bright) 48%,
    transparent 66%
  );
  background-size: 250% 100%;
  background-position: 150% 0;
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
  pointer-events: none;
  opacity: 0;
  transition: opacity 0.2s var(--ease), background-position 1.6s var(--ease);
}

.pillar:hover::after {
  opacity: 1;
  background-position: -50% 0;
}

.pillar h3 {
  font-size: 1.15rem;
  margin-bottom: 0.6rem;
}

.pillar p {
  color: var(--body-text);
  font-size: 0.94rem;
  line-height: 1.6;
}

/* numbered "what to expect" list */

/* Four across, then two, then one. Explicit steps rather than auto-fit: with
   four items auto-fit drops to three-plus-an-orphan at tablet widths. */
.expect {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 2rem;
}

@media (max-width: 1040px) {
  .expect {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 2rem 2.5rem;
  }
}

@media (max-width: 560px) {
  .expect {
    grid-template-columns: 1fr;
  }
}

.expect__n {
  display: block;
  font: 600 0.8rem/1 var(--body);
  letter-spacing: 0.08em;
  color: var(--brass);
  font-variant-numeric: tabular-nums;
  margin-bottom: 0.9rem;
}

.expect__item h3 {
  font-size: 1.2rem;
  margin-bottom: 0.6rem;
}

.expect__item p {
  color: var(--body-text);
  font-size: 0.94rem;
  line-height: 1.65;
}

/* --- border-glow card --------------------------------------------------
   Ported from a React component supplied for this (border-glow.js/.css,
   kept at the repo root as source reference, same as grid-scan/dot-field)
   into plain JS + CSS custom properties: home.js tracks the pointer over
   each card and writes --edge-proximity (0–100, how close the cursor is
   to the card's edge) and --cursor-angle (which direction the mesh-
   gradient border and outer glow sweep from). Pointer-fine only — see
   initBorderGlowCards() in home.js; without it --edge-proximity simply
   stays at its 0 default and every layer below stays fully transparent,
   same progressive-enhancement fallback as the .pillar spotlight.

   The original component took a `colors` prop for an arbitrary mesh-
   gradient palette; this site has exactly one accent (champagne/brass —
   see the file header), so the three colors below are three brass tones
   rather than the demo's purple/pink/teal, and are just written directly
   as the fallback values instead of being computed and set from JS. */
.border-glow-card {
  --edge-proximity: 0;
  --cursor-angle: 45deg;
  --edge-sensitivity: 30;
  --color-sensitivity: calc(var(--edge-sensitivity) + 20);
  --cone-spread: 25;
  --glow-padding: 28px;

  position: relative;
  isolation: isolate;
  transform: translate3d(0, var(--lift, 0), 0.01px);
  border-radius: var(--r-xl);
  border: 1px solid var(--hairline);
  background: var(--surface-card);
  transition: border-color 0.25s var(--ease), transform 0.3s var(--ease);
}

.border-glow-card:hover {
  --lift: -3px;
  border-color: var(--hairline-strong);
}

.border-glow-card::before,
.border-glow-card::after,
.border-glow-card > .edge-light {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: inherit;
  transition: opacity 0.25s var(--ease);
  z-index: -1;
}

.border-glow-card:not(:hover)::before,
.border-glow-card:not(:hover)::after,
.border-glow-card:not(:hover) > .edge-light {
  opacity: 0;
  transition: opacity 0.75s var(--ease);
}

/* Mesh-gradient border: three brass tones, masked to a cone around the
   cursor so only the near edge lights up rather than the whole frame. */
.border-glow-card::before {
  border: 1px solid transparent;
  background:
    linear-gradient(var(--surface-card) 0 100%) padding-box,
    radial-gradient(at 80% 55%, var(--brass-bright) 0px, transparent 55%) border-box,
    radial-gradient(at 10% 15%, var(--primary-active) 0px, transparent 55%) border-box,
    radial-gradient(at 50% 90%, var(--brass) 0px, transparent 60%) border-box;
  opacity: calc((var(--edge-proximity) - var(--color-sensitivity)) / (100 - var(--color-sensitivity)));
  mask-image: conic-gradient(
    from var(--cursor-angle) at center,
    black calc(var(--cone-spread) * 1%),
    transparent calc((var(--cone-spread) + 15) * 1%),
    transparent calc((100 - var(--cone-spread) - 15) * 1%),
    black calc((100 - var(--cone-spread)) * 1%)
  );
}

/* Same mesh, softly washed across the card face near the lit edge. */
.border-glow-card::after {
  background:
    radial-gradient(at 80% 55%, var(--brass-bright) 0px, transparent 55%) padding-box,
    radial-gradient(at 10% 15%, var(--primary-active) 0px, transparent 55%) padding-box,
    radial-gradient(at 50% 90%, var(--brass) 0px, transparent 60%) padding-box;
  mask-image:
    radial-gradient(ellipse at 50% 50%, black 35%, transparent 65%),
    conic-gradient(from var(--cursor-angle) at center, transparent 5%, black 15%, black 85%, transparent 95%);
  mask-composite: intersect;
  opacity: calc(0.4 * (var(--edge-proximity) - var(--color-sensitivity)) / (100 - var(--color-sensitivity)));
  mix-blend-mode: soft-light;
}

/* Outer bloom: a champagne rim-light just outside the card edge. */
.border-glow-card > .edge-light {
  inset: calc(var(--glow-padding) * -1);
  pointer-events: none;
  z-index: 1;
  mask-image: conic-gradient(
    from var(--cursor-angle) at center, black 2.5%, transparent 10%, transparent 90%, black 97.5%
  );
  opacity: calc((var(--edge-proximity) - var(--edge-sensitivity)) / (100 - var(--edge-sensitivity)));
  mix-blend-mode: plus-lighter;
}

.border-glow-card > .edge-light::before {
  content: '';
  position: absolute;
  inset: var(--glow-padding);
  border-radius: inherit;
  box-shadow:
    inset 0 0 0 1px color-mix(in srgb, var(--brass-bright) 100%, transparent),
    inset 0 0 3px 0 color-mix(in srgb, var(--brass-bright) 55%, transparent),
    inset 0 0 8px 0 color-mix(in srgb, var(--brass-bright) 35%, transparent),
    0 0 3px 0 color-mix(in srgb, var(--brass-bright) 55%, transparent),
    0 0 10px 1px color-mix(in srgb, var(--brass-bright) 30%, transparent),
    0 0 24px 2px color-mix(in srgb, var(--brass-bright) 16%, transparent);
}

.border-glow-inner {
  position: relative;
  z-index: 1;
  padding: 1.75rem 1.6rem;
}

/* closing call to action */

.cta-band {
  padding-block: var(--section);
  border-top: 1px solid var(--hairline);
  position: relative;
  overflow: hidden;
}

/* One eucalyptus bloom, low and wide, so the page closes the way it opened. */
.cta-band::before {
  content: '';
  position: absolute;
  width: 40rem;
  height: 26rem;
  bottom: -16rem;
  left: 50%;
  transform: translateX(-50%);
  border-radius: 50%;
  filter: blur(70px);
  opacity: 0.5;
  pointer-events: none;
  background: radial-gradient(
    circle at 50% 50%,
    var(--orb-lavender) 0%,
    rgba(46, 74, 99, 0) 68%
  );
  animation: orb-breathe 18s ease-in-out infinite alternate;
}

@keyframes orb-breathe {
  from {
    transform: translateX(-50%) scale(1);
  }
  to {
    transform: translateX(-50%) scale(1.15) translateY(-1.5rem);
  }
}

#cta-field {
  position: absolute;
  inset: 0;
  z-index: 0;
}

.cta-band__inner {
  text-align: center;
  position: relative;
  z-index: 1;
}

.cta-band h2 {
  font-size: clamp(1.5rem, 2.6vw, 1.9rem);
  max-width: 24ch;
  margin-inline: auto;
}

.cta-band p {
  color: var(--body-text);
  margin: 1rem auto 2rem;
  max-width: 34rem;
  line-height: 1.6;
}

/* ---------------------- careers: page header ---------------------- */

/* The listing gets a plain page header, not a landing hero. The selling is
   done on the home page; by the time someone is here they want the list. */
.page-head {
  display: flex;
  align-items: flex-end;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  padding-block: clamp(2.5rem, 5vw, 3.5rem) 1.5rem;
  border-bottom: 1px solid var(--hairline);
  margin-bottom: 1.75rem;
}

.page-head h1 {
  font-size: clamp(1.7rem, 3vw, 2.1rem);
  margin-top: 0.5rem;
}

.page-head__meta {
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.45rem 0.9rem 0.45rem 0.7rem;
  background: var(--surface-strong);
  border-radius: var(--r-pill);
}

.page-head__meta .label {
  font-size: 0.7rem;
  letter-spacing: 0.06em;
}

/* ----------------------------- filters ----------------------------- */

.filters {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  padding-bottom: 1.75rem;
}

.filters__group {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem;
}

/* Two filter groups each carry their own "All" chip. Without a divider they
   read as one confused row with two identical buttons. */
.filters__group:not(:empty) + .filters__group:not(:empty) {
  margin-left: 0.75rem;
  padding-left: 1.15rem;
  border-left: 1px solid var(--hairline-strong);
}

.chip {
  background: transparent;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-pill);
  padding: 0.5rem 1rem;
  font: 500 0.85rem/1 var(--body);
  color: var(--body-text);
  cursor: pointer;
  transition: all 0.2s var(--ease);
  white-space: nowrap;
}

.chip:hover {
  border-color: var(--primary);
  color: var(--ink);
}

.chip[aria-pressed='true'] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}

/* --------------------------- job listing --------------------------- */

.listing {
  display: flex;
  flex-direction: column;
  gap: 0.6rem;
  padding-bottom: 2.5rem;
}

.job-row {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: 1.5rem;
  padding: 1.5rem 1.6rem;
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  transition: box-shadow 0.25s var(--ease), transform 0.25s var(--ease),
    border-color 0.25s var(--ease);
}

.job-row:hover {
  border-color: var(--hairline-strong);
  box-shadow: var(--drop);
  transform: translateY(-2px);
}

.job-row__title {
  font-family: var(--display);
  font-size: 1.35rem;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin-bottom: 0.35rem;
}

.job-row__meta {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.55rem;
  font: 400 0.9rem/1.5 var(--body);
  color: var(--muted);
}

.job-row__meta .dot {
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: var(--muted-soft);
}

.job-row__aside {
  display: flex;
  align-items: center;
  gap: 1.25rem;
}

.job-row__arrow {
  display: grid;
  place-items: center;
  width: 36px;
  height: 36px;
  border-radius: var(--r-pill);
  background: var(--surface-strong);
  color: var(--ink);
  font-size: 0.95rem;
  transition: background 0.25s var(--ease), color 0.25s var(--ease);
}

.job-row:hover .job-row__arrow {
  background: var(--primary);
  color: var(--on-primary);
}

/* ------------------------------- tags ------------------------------ */

.tag {
  display: inline-flex;
  align-items: center;
  padding: 0.3rem 0.7rem;
  background: var(--surface-strong);
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  font: 600 0.7rem/1.4 var(--body);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--body-strong);
  white-space: nowrap;
}

.tag--solid {
  background: var(--primary);
  color: var(--on-primary);
}

/* Kept as an alias: the system has no accent, so this is the plain badge. */
.tag--brass {
  background: var(--surface-strong);
  color: var(--body-strong);
}

.tag--closed {
  background: transparent;
  border-color: var(--hairline-strong);
  color: var(--muted);
}

.status {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  font: 500 0.82rem/1 var(--body);
  white-space: nowrap;
}

.status::before {
  content: '';
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: currentColor;
}

.status--new {
  color: var(--body-strong);
}
.status--shortlisted {
  color: var(--success);
}
.status--rejected {
  color: var(--error);
}
.status--hired {
  color: var(--ink);
}

/* ------------------------------ buttons ---------------------------- */

/* One CTA shape: the pill. One CTA fill: ink. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.5rem;
  min-height: 40px;
  padding: 0.65rem 1.25rem;
  border: 1px solid var(--primary);
  border-radius: var(--r-pill);
  background: var(--primary);
  color: var(--on-primary);
  font: 500 0.94rem/1 var(--body);
  cursor: pointer;
  transition: background 0.2s var(--ease), border-color 0.2s var(--ease),
    color 0.2s var(--ease), opacity 0.2s var(--ease),
    transform 0.2s var(--ease), box-shadow 0.2s var(--ease);
  white-space: nowrap;
}

.btn:hover:not(:disabled) {
  background: var(--primary-active);
  border-color: var(--primary-active);
  transform: translateY(-1px);
  box-shadow: 0 10px 28px -10px rgba(211, 181, 120, 0.45);
}

/* Pressing has weight: the pill settles back down under the finger. */
.btn:active:not(:disabled) {
  transform: translateY(0) scale(0.98);
  box-shadow: none;
}

.btn:disabled {
  opacity: 0.45;
  cursor: not-allowed;
}

.btn--ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--hairline-strong);
}

.btn--ghost:hover:not(:disabled) {
  background: var(--surface-strong);
  border-color: var(--hairline-strong);
  color: var(--ink);
}

/* The system has a single primary. This alias keeps the markup honest. */
.btn--brass {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}

.btn--sm {
  min-height: 34px;
  padding: 0.45rem 0.9rem;
  font-size: 0.85rem;
}

.btn--danger:hover:not(:disabled) {
  background: var(--error);
  border-color: var(--error);
  color: #1c1210;
}

.btn--block {
  width: 100%;
}

/* ------------------------------- forms ----------------------------- */

.field {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin-bottom: 1.15rem;
}

/* The file-drop zone is itself a <label>, so it must be excluded here or it
   inherits the caption treatment meant for field captions. */
.field > label:not(.filedrop) {
  font: 500 0.88rem/1.4 var(--body);
  color: var(--body-strong);
}

.field .req {
  color: var(--muted-soft);
}

.field .hint {
  font-size: 0.82rem;
  color: var(--muted);
  line-height: 1.5;
}

.input,
.select,
.textarea {
  width: 100%;
  min-height: 44px;
  padding: 0.7rem 1rem;
  background: var(--surface-card);
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-md);
  /* 16px is the iOS Safari threshold: anything smaller and focusing the
     field zooms the whole page in, which then has to be manually zoomed
     back out. Barely reads as different from the old 0.95rem. */
  font-size: 1rem;
  color: var(--ink);
  transition: border-color 0.18s var(--ease), box-shadow 0.18s var(--ease);
}

/* On focus the border turns gold with a soft outer ring. */
.input:focus,
.select:focus,
.textarea:focus {
  outline: none;
  border-color: var(--primary);
  box-shadow: inset 0 0 0 1px var(--primary), 0 0 0 3px rgba(211, 181, 120, 0.15);
}

.input::placeholder,
.textarea::placeholder {
  color: var(--muted-soft);
}

.textarea {
  min-height: 7rem;
  resize: vertical;
  line-height: 1.6;
}

.select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%23777169' stroke-width='1.5' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 1rem center;
  padding-right: 2.5rem;
  cursor: pointer;
}

.field--invalid .input,
.field--invalid .select,
.field--invalid .textarea,
.field--invalid .filedrop {
  border-color: var(--error);
}

.field__error {
  font: 400 0.82rem/1.4 var(--body);
  color: var(--error);
}

.field-row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 1rem;
}

/* Honeypot: invisible to people, irresistible to naive bots. */
.hp {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

/* ---------------------------- file drop ---------------------------- */

.filedrop {
  display: block;
  border: 1px dashed var(--hairline-strong);
  border-radius: var(--r-lg);
  background: var(--canvas-soft);
  padding: 1.6rem 1.2rem;
  text-align: center;
  cursor: pointer;
  transition: border-color 0.2s var(--ease), background 0.2s var(--ease);
  font: 400 0.95rem/1.5 var(--body);
  color: var(--ink);
}

.filedrop:hover,
.filedrop.is-over {
  border-color: var(--primary);
  background: var(--surface-card);
}

.filedrop input {
  display: none;
}

.filedrop__icon {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  margin: 0 auto 0.65rem;
  border-radius: var(--r-pill);
  background: var(--surface-strong);
  color: var(--ink);
  font-size: 0.95rem;
}

.filedrop__main {
  font-size: 0.92rem;
  line-height: 1.5;
  color: var(--body-text);
  margin-bottom: 0.2rem;
}

.filedrop__main strong {
  font-weight: 500;
  color: var(--ink);
}

.filedrop:hover .filedrop__main strong,
.filedrop.is-over .filedrop__main strong {
  text-decoration: underline;
  text-underline-offset: 3px;
}

.filedrop__sub {
  font: 400 0.8rem/1.4 var(--body);
  color: var(--muted);
}

/* Once a file is chosen the name is the point — let it read plainly. */
.filedrop.has-file {
  border-style: solid;
  border-color: var(--hairline-strong);
  background: var(--surface-card);
  text-align: left;
  display: flex;
  align-items: center;
  gap: 0.9rem;
}

.filedrop.has-file .filedrop__main {
  color: var(--ink);
  font-weight: 500;
  word-break: break-word;
}

.filedrop.has-file .filedrop__icon {
  margin: 0;
  flex-shrink: 0;
  background: rgba(69, 192, 122, 0.15);
  color: var(--success);
}

/* ------------------------------ cards ------------------------------ */

.card {
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
}

/* No accent rule any more — the card is defined by its hairline. */
.card--brass-top {
  border-color: var(--hairline);
}

.card__head {
  padding: 1.6rem 1.6rem 0;
}

.card__body {
  padding: 1.6rem;
}

.card__head + .card__body {
  padding-top: 1.4rem;
}

/* --------------------------- job detail ---------------------------- */

.backlink {
  display: inline-flex;
  align-items: center;
  gap: 0.45rem;
  font: 500 0.9rem/1 var(--body);
  color: var(--muted);
  padding-block: 2rem 0;
  transition: color 0.2s var(--ease), gap 0.2s var(--ease);
}

.backlink:hover {
  color: var(--ink);
  gap: 0.7rem;
}

.detail {
  display: grid;
  grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
  gap: clamp(2rem, 5vw, 4rem);
  padding-block: 2.5rem var(--section);
  align-items: start;
}

.detail__head {
  padding-bottom: 1.75rem;
  border-bottom: 1px solid var(--hairline);
  margin-bottom: 2rem;
}

.detail__head h1 {
  font-size: clamp(1.7rem, 3vw, 2.1rem);
  line-height: 1.1;
  letter-spacing: -0.02em;
  margin-block: 0.75rem 1.1rem;
}

.detail__tags {
  display: flex;
  flex-wrap: wrap;
  gap: 0.45rem;
}

.prose h2 {
  font: 600 0.75rem/1.4 var(--body);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-block: 2.25rem 0.9rem;
}

.prose h2:first-child {
  margin-top: 0;
}

.prose p {
  color: var(--body-text);
  line-height: 1.6;
  margin-bottom: 1rem;
}

.prose ul {
  list-style: none;
}

.prose li {
  position: relative;
  padding-left: 1.4rem;
  margin-bottom: 0.65rem;
  color: var(--body-text);
  line-height: 1.6;
}

.prose li::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.7em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--brass-bright);
}

/* facts panel */

.facts {
  display: grid;
  gap: 0;
}

.facts__row {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 1rem;
  padding-block: 0.8rem;
  border-bottom: 1px solid var(--hairline);
  /* .facts is an implicit single-column grid with no explicit track
     size, so this row — a grid item — defaults to min-width: auto same
     as everywhere else in this pass: it was overflowing its own track
     (and the card) by exactly the .facts__val fix two levels down,
     because that fix only stopped the *value* from forcing its own
     overflow, not this row from being allowed to render wider than the
     column that's supposed to contain it. */
  min-width: 0;
}

.facts__row:last-child {
  border-bottom: 0;
  padding-bottom: 0;
}

.facts__key {
  font: 400 0.88rem/1.5 var(--body);
  color: var(--muted);
  flex-shrink: 0;
}

.facts__val {
  text-align: right;
  font-size: 0.9rem;
  font-weight: 500;
  color: var(--ink);
  /* A flex item's default min-width is its content's natural width, and
     an email address has no spaces to wrap at — without this, a long
     one (or a long job title) simply pushes past the row's edge instead
     of wrapping, and on a phone that's most of the address rendered
     off-screen rather than merely tight. */
  min-width: 0;
  overflow-wrap: break-word;
}

.apply-panel {
  position: sticky;
  top: 6rem;
}

/* ------------------------------ notices ---------------------------- */

.notice {
  padding: 0.9rem 1.1rem;
  border-radius: var(--r-md);
  border: 1px solid;
  font-size: 0.9rem;
  line-height: 1.55;
  margin-bottom: 1.15rem;
}

.notice--error {
  background: rgba(224, 110, 110, 0.09);
  border-color: rgba(224, 110, 110, 0.32);
  color: #eaa3a3;
}

.notice--info {
  background: var(--surface-strong);
  border-color: var(--hairline-strong);
  color: var(--body-strong);
}

.notice--ok {
  background: rgba(69, 192, 122, 0.1);
  border-color: rgba(69, 192, 122, 0.3);
  color: #86d9ab;
}

/* --------------------------- empty / states ------------------------ */

.empty {
  text-align: center;
  padding: clamp(3rem, 8vw, 5rem) 1.5rem;
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  background: var(--canvas-soft);
}

.empty__mark {
  font-family: var(--display);
  font-size: 2.5rem;
  font-weight: 500;
  line-height: 1;
  color: var(--brass-bright);
  margin-bottom: 0.9rem;
}

.empty h2 {
  font-size: 1.6rem;
  margin-bottom: 0.6rem;
}

.empty p {
  color: var(--body-text);
  max-width: 30rem;
  margin-inline: auto;
  line-height: 1.6;
}

.skeleton {
  height: 104px;
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  background: linear-gradient(
    90deg,
    var(--surface-card) 0%,
    var(--surface-strong) 50%,
    var(--surface-card) 100%
  );
  background-size: 200% 100%;
  animation: sweep 1.4s infinite linear;
}

@keyframes sweep {
  to {
    background-position: -200% 0;
  }
}

/* ------------------------------ success ---------------------------- */

.success {
  text-align: center;
  padding: clamp(2.5rem, 7vw, 4rem) 1.5rem;
  position: relative;
  overflow: hidden;
  border-radius: var(--r-xl);
}

/* A single sage bloom to mark the moment. */
.success::before {
  content: '';
  position: absolute;
  width: 22rem;
  height: 22rem;
  top: -11rem;
  left: 50%;
  transform: translateX(-50%);
  border-radius: 50%;
  filter: blur(50px);
  opacity: 0.5;
  pointer-events: none;
  background: radial-gradient(
    circle at 50% 50%,
    var(--orb-mint) 0%,
    rgba(35, 64, 110, 0) 68%
  );
}

.success > * {
  position: relative;
  z-index: 1;
}

.success__seal {
  width: 64px;
  height: 64px;
  margin: 0 auto 1.4rem;
  border-radius: var(--r-pill);
  background: var(--primary);
  color: var(--on-primary);
  display: grid;
  place-items: center;
  font-size: 1.4rem;
  animation: seal 0.5s var(--ease) backwards;
}

@keyframes seal {
  from {
    transform: scale(0.7);
    opacity: 0;
  }
}

.success h2 {
  font-size: clamp(1.75rem, 3.4vw, 2.25rem);
  margin-bottom: 0.75rem;
}

.success p {
  color: var(--body-text);
  max-width: 28rem;
  margin: 0 auto 1.75rem;
  line-height: 1.6;
}

/* ------------------------------- admin ----------------------------- */

.auth {
  display: grid;
  place-items: center;
  padding-block: clamp(3rem, 10vh, 6rem);
}

.auth__card {
  width: 100%;
  max-width: 26rem;
}

.auth__head {
  text-align: center;
  margin-bottom: 1.75rem;
}

.auth__head h1 {
  font-size: 2.1rem;
  letter-spacing: -0.02em;
}

.auth__head p {
  color: var(--muted);
  font-size: 0.94rem;
  margin-top: 0.5rem;
}

/* --- the dashboard: a fixed left rail, and a workspace beside it --- */

.admin {
  display: grid;
  grid-template-columns: 248px minmax(0, 1fr);
  gap: clamp(2rem, 4vw, 3.5rem);
  align-items: start;
  padding-block: 2.5rem var(--section);
}

/* The rail follows you down a long list of applicants. 72px masthead + air. */
.rail {
  position: sticky;
  top: 6rem;
  display: flex;
  flex-direction: column;
  gap: 1.5rem;
}

.rail__head h1 {
  font-size: 2rem;
  margin-top: 0.35rem;
}

.rail__nav {
  display: flex;
  flex-direction: column;
  gap: 0.15rem;
}

.rail__link {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.75rem;
  width: 100%;
  padding: 0.6rem 0.85rem;
  background: transparent;
  border: 0;
  border-radius: var(--r-md);
  font: 500 0.94rem/1.3 var(--body);
  color: var(--muted);
  text-align: left;
  cursor: pointer;
  transition: background 0.18s var(--ease), color 0.18s var(--ease);
}

.rail__link:hover {
  background: var(--surface-strong);
  color: var(--ink);
}

.rail__link[aria-current='true'] {
  background: var(--primary);
  color: var(--on-primary);
}

.rail__count {
  font-size: 0.82rem;
  font-weight: 600;
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}

.rail__link:hover .rail__count {
  color: var(--body-strong);
}

.rail__link[aria-current='true'] .rail__count {
  color: var(--on-primary);
  opacity: 0.7;
}

/* Counts as a quiet ledger, not four big tiles competing with the work. */
.rail__stats {
  display: grid;
  gap: 0;
  padding-top: 1.25rem;
  border-top: 1px solid var(--hairline);
}

.rail__stat {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 1rem;
  padding-block: 0.55rem;
}

.rail__stat dt {
  font: 400 0.88rem/1.4 var(--body);
  color: var(--muted);
}

.rail__stat dd {
  font: 600 0.95rem/1.4 var(--body);
  color: var(--ink);
  font-variant-numeric: tabular-nums;
}

/* The one number worth looking at twice. */
.rail__stat--live dd {
  color: var(--ink);
}

.rail__stat--live dt {
  color: var(--body-strong);
  font-weight: 500;
}

.workspace__bar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  padding-bottom: 1.1rem;
  margin-bottom: 1.5rem;
  border-bottom: 1px solid var(--hairline);
}

.workspace__bar h2 {
  font-size: 1.35rem;
}

.workspace__sub {
  font: 400 0.88rem/1.4 var(--body);
  color: var(--muted);
  margin-top: 0.2rem;
}

/* admin job list */

.admin-job {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  padding: 1.35rem 1.5rem;
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  background: var(--surface-card);
  margin-bottom: 0.6rem;
  transition: box-shadow 0.22s var(--ease), border-color 0.22s var(--ease);
}

.admin-job:hover {
  border-color: var(--hairline-strong);
  box-shadow: var(--drop);
}

.admin-job__title {
  font-family: var(--display);
  font-size: 1.3rem;
  font-weight: 500;
  margin-bottom: 0.25rem;
}

.admin-job__meta {
  font-size: 0.88rem;
  color: var(--muted);
}

.admin-job__actions {
  display: flex;
  align-items: center;
  gap: 0.45rem;
  flex-wrap: wrap;
}

.admin-job.is-closed {
  background: var(--canvas-soft);
  opacity: 0.75;
}

/* applications */

.app-group {
  margin-bottom: 2rem;
}

.app-group__head {
  display: flex;
  align-items: baseline;
  gap: 0.75rem;
  padding-bottom: 0.75rem;
  margin-bottom: 0.5rem;
}

.app-group__head h3 {
  font-size: 1.4rem;
}

.applicant {
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  margin-bottom: 0.5rem;
  overflow: hidden;
}

.applicant__summary {
  display: grid;
  grid-template-columns: minmax(0, 1.4fr) minmax(0, 1fr) auto auto auto;
  align-items: center;
  gap: 1rem;
  padding: 1.1rem 1.4rem;
  cursor: pointer;
  list-style: none;
  transition: background 0.2s var(--ease);
}

.applicant__summary::-webkit-details-marker {
  display: none;
}

.applicant__summary:hover,
.applicant[open] .applicant__summary {
  background: var(--canvas-soft);
}

.applicant__name {
  font-weight: 500;
  font-size: 1rem;
}

.applicant__sub {
  font-size: 0.86rem;
  color: var(--muted);
  margin-top: 0.1rem;
  /* Same reasoning as .facts__val: this holds the applicant's email in
     the summary row, and a grid item's default min-width is its
     content's natural (unbroken) width — a long address needs somewhere
     to wrap instead of extending past the card on a narrow screen. */
  min-width: 0;
  overflow-wrap: break-word;
}

.applicant__when {
  font: 400 0.84rem/1 var(--body);
  color: var(--muted);
  white-space: nowrap;
}

.applicant__chev {
  color: var(--muted);
  transition: transform 0.22s var(--ease);
  font-size: 0.85rem;
}

.applicant[open] .applicant__chev {
  transform: rotate(90deg);
}

.applicant__detail {
  padding: 1.4rem;
  border-top: 1px solid var(--hairline);
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 260px);
  gap: 2rem;
  animation: unfurl 0.28s var(--ease);
}

@keyframes unfurl {
  from {
    opacity: 0;
    transform: translateY(-6px);
  }
}

.applicant__note {
  white-space: pre-wrap;
  color: var(--body-text);
  font-size: 0.94rem;
  line-height: 1.65;
}

.statusbar {
  display: flex;
  flex-wrap: wrap;
  gap: 0.35rem;
  margin-top: 0.9rem;
}

.statusbar button {
  background: transparent;
  border: 1px solid var(--hairline-strong);
  border-radius: var(--r-pill);
  padding: 0.4rem 0.85rem;
  font: 500 0.82rem/1 var(--body);
  color: var(--body-text);
  cursor: pointer;
  transition: all 0.18s var(--ease);
}

.statusbar button:hover {
  border-color: var(--primary);
  color: var(--ink);
}

.statusbar button[aria-pressed='true'] {
  background: var(--primary);
  border-color: var(--primary);
  color: var(--on-primary);
}

/* modal */

/* Not display: grid/flex — tried both a grid with place-items and
   plain padding first, and separately margin on .modal__panel instead;
   neither ever let this scroll to reveal the trailing gap (a real,
   long-standing Chrome/Firefox bug: a flex or grid scroll container's
   own trailing space isn't reliably included in its scrollable area).
   Plain block layout + text-align: center to center the panel doesn't
   have that bug — it's the same pattern modals used before flexbox
   existed, specifically because it scrolls correctly. */
.modal {
  position: fixed;
  inset: 0;
  z-index: 50;
  text-align: center;
  padding-inline: 1rem;
  overflow-y: auto;
  background: rgba(0, 0, 0, 0.6);
  backdrop-filter: blur(4px);
  animation: fade 0.22s var(--ease);
}

@keyframes fade {
  from {
    opacity: 0;
  }
}

.modal__panel {
  display: inline-block;
  width: 100%;
  max-width: 42rem;
  text-align: left;
  vertical-align: top;
  margin-block: clamp(1rem, 5vh, 3rem);
  background: var(--surface-card);
  border-radius: var(--r-xl);
  box-shadow: var(--drop-lg);
  animation: rise 0.3s var(--ease);
  overflow: hidden;
}

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
}

.modal__head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.5rem 1.75rem;
  border-bottom: 1px solid var(--hairline);
}

.modal__head h2 {
  font-size: 1.6rem;
  letter-spacing: -0.01em;
}

.modal__x {
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  background: transparent;
  border: 0;
  border-radius: var(--r-pill);
  font-size: 1.4rem;
  line-height: 1;
  color: var(--muted);
  cursor: pointer;
  transition: background 0.18s var(--ease), color 0.18s var(--ease);
}

.modal__x:hover {
  background: var(--surface-strong);
  color: var(--ink);
}

.modal__body {
  padding: 1.75rem;
}

.modal__foot {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  padding: 1.25rem 1.75rem;
  border-top: 1px solid var(--hairline);
  background: var(--canvas-soft);
}

/* ------------------------------ footer ----------------------------- */

.footer {
  background: var(--canvas-soft);
  border-top: 1px solid var(--hairline);
  color: var(--muted);
  padding-block: 2.5rem;
  margin-top: auto;
}

.footer__col a {
  transition: color 0.2s var(--ease);
}

.footer__inner {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 1rem;
  font: 400 0.9rem/1.5 var(--body);
}

/* ------------------------------ motion ----------------------------- */

/* `backwards`, not `both`.
   With `both` the animation keeps filling after it finishes, and a filling
   animation outranks normal declarations in the cascade — so it goes on
   owning `transform` forever. The hover lift then gets stamped on instantly
   instead of transitioning, while the shadow fades in normally: the card
   jumps and only half of it looks animated.
   `backwards` still applies the from-keyframe during the stagger delay (so
   nothing flashes in un-animated), then releases the property on finish. */
.rise-in {
  animation: riseIn 0.6s var(--ease) backwards;
}

@keyframes riseIn {
  from {
    opacity: 0;
    transform: translateY(14px);
  }
}

.stagger > * {
  animation: riseIn 0.55s var(--ease) backwards;
}

.stagger > *:nth-child(1) {
  animation-delay: 0.04s;
}
.stagger > *:nth-child(2) {
  animation-delay: 0.09s;
}
.stagger > *:nth-child(3) {
  animation-delay: 0.14s;
}
.stagger > *:nth-child(4) {
  animation-delay: 0.19s;
}
.stagger > *:nth-child(5) {
  animation-delay: 0.24s;
}
.stagger > *:nth-child(6) {
  animation-delay: 0.29s;
}
.stagger > *:nth-child(n + 7) {
  animation-delay: 0.34s;
}

/* --- scroll reveals -------------------------------------------------
   ui.js tags below-the-fold blocks with .reveal and flips .is-in as they
   enter the viewport, staggering siblings via --reveal-i. Everything is
   gated behind html.anim, which the script only adds when it is running
   and the visitor has not asked for reduced motion — so with no script,
   or with reduced motion, nothing is ever hidden. */
html.anim .reveal {
  opacity: 0;
  transform: translateY(20px);
  transition: opacity 0.7s var(--ease), transform 0.7s var(--ease);
  transition-delay: calc(var(--reveal-i, 0) * 80ms);
}

html.anim .reveal.is-in {
  opacity: 1;
  transform: none;
}

/* whoweare items get a clip-path wipe instead of the generic fade —
   layered on top of the same .reveal/.is-in/--reveal-i system, so the
   stagger timing still comes from ui.js; only the visual differs. */
html.anim .whoweare__item.reveal {
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.7s var(--ease), opacity 0.7s var(--ease);
  transition-delay: calc(var(--reveal-i, 0) * 80ms);
}

html.anim .whoweare__item.reveal.is-in {
  clip-path: inset(0 0 0% 0);
}

.spin {
  display: inline-block;
  width: 12px;
  height: 12px;
  border: 1.5px solid currentColor;
  border-top-color: transparent;
  border-radius: 50%;
  animation: spin 0.7s linear infinite;
}

@keyframes spin {
  to {
    transform: rotate(360deg);
  }
}

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

/* ---------------------------- responsive --------------------------- */

@media (max-width: 900px) {
  .detail {
    grid-template-columns: 1fr;
  }

  /* No room for a rail — it unfolds into a header strip above the work.
     minmax(0, 1fr), not a bare 1fr: a bare 1fr track's minimum is auto,
     so if content inside it refuses to shrink (the tab row below, once
     it's forced horizontal) the track grows to fit instead — which is
     exactly how the six tabs ended up silently overflowing the page
     rather than scrolling within it. The desktop column already uses
     minmax(0, 1fr) for this same reason. */
  .admin {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.75rem;
  }

  .rail {
    position: static;
    gap: 1.25rem;
  }

  /* Six tabs in a row don't fit even a tablet width, and flex items
     refuse to shrink below their text's natural size — without an
     explicit escape hatch they just overflow the rail silently (.page's
     overflow-x: clip stops that from becoming page-level scroll, but
     gives the overflow nowhere to go, so Articles/Authors/Write ended
     up completely unreachable, not just visually cut off). Scrolling
     the strip itself, the same technique .tabs and .rail-cards already
     use elsewhere on this site, keeps every tab reachable with an
     ordinary swipe. */
  .rail__nav {
    flex-direction: row;
    gap: 0.4rem;
    overflow-x: auto;
    scrollbar-width: none;
  }

  /* Same as .rail-cards elsewhere on this site — a persistent scrollbar
     track sitting right under the pills read as visual clutter (almost
     like the row itself was misaligned), when the swipe gesture alone
     is the affordance mobile users already expect here. */
  .rail__nav::-webkit-scrollbar {
    display: none;
  }

  .rail__link {
    width: auto;
    flex-shrink: 0;
    border-radius: var(--r-pill);
    padding: 0.5rem 1rem;
  }

  .rail__stats {
    grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
    column-gap: 1.5rem;
  }

  .apply-panel {
    position: static;
  }

  /* minmax(0, 1fr), not a bare 1fr — same reasoning as .admin above: a
     bare 1fr's minimum is auto, so the unwrapped email in the facts
     column below was pushing this track wider than the card, past the
     card's own padding, rather than actually being constrained by it. */
  .applicant__detail {
    grid-template-columns: minmax(0, 1fr);
    gap: 1.2rem;
  }

  /* minmax(0, 1fr) for the same reason as .admin/.applicant__detail
     above — the name/email column shouldn't be able to force this row
     wider than the card just because its text doesn't happen to wrap. */
  .applicant__summary {
    grid-template-columns: minmax(0, 1fr) auto;
    row-gap: 0.5rem;
  }

  /* The email is the only direct .applicant__sub — the name's phone line is
     nested. Give it its own row or it squeezes the name into wrapping. */
  .applicant__summary > .applicant__sub {
    grid-column: 1 / -1;
  }

  .applicant__when {
    display: none;
  }
}

/* Below ~800px the wordmark plus all six links no longer fit one row
   (tested by bisection — breaks from 641px, clean again at 795px+: on
   iPad portrait, most Android tablets, and every phone). Rather than
   wrapping the links into a ragged multi-row block, the nav collapses
   behind a hamburger and reopens as a full-width dropdown panel — the
   masthead itself stays a compact single row (logo + toggle) at every
   width, so it never needs the taller stacked treatment the old fix
   used, and the hero's height math never has to compensate for it. */
@media (max-width: 800px) {
  .nav-toggle {
    display: inline-flex;
  }

  .nav {
    position: absolute;
    left: 0;
    right: 0;
    top: 100%;
    flex-direction: column;
    align-items: stretch;
    gap: 0;
    margin: 0;
    background: var(--canvas-soft);
    border-bottom: 1px solid var(--hairline);
    box-shadow: var(--drop);
    padding-inline: var(--gutter);
    max-height: 0;
    overflow: hidden;
    opacity: 0;
    transition: max-height 0.3s var(--ease), opacity 0.25s var(--ease);
  }

  /* JS toggles this on the toggle button's click; with no script the
     nav simply never opens, same as any other progressive-enhancement
     control on this site. */
  /* --nav-h is set from the panel's real scrollHeight right before this
     class lands (see ui.js) — animating to the actual content height
     instead of a flat guess like 70vh means the transition finishes
     exactly as the last link settles, rather than continuing to expand
     into empty space after everything's already visible. Falls back to
     70vh (then just clamped by the viewport) if JS never sets it. */
  .nav.is-open {
    max-height: var(--nav-h, 70vh);
    opacity: 1;
    overflow-y: auto;
    padding-block: 0.5rem 1rem;
  }

  .nav a {
    padding-block: 0.9rem;
    border-bottom: 1px solid var(--hairline-soft);
  }

  /* The draw-in underline reads as a stray line under a full-width
     stacked link rather than an underline "on" the word — the current-
     page/hover colour change already carries that job here. */
  .nav a::after {
    display: none;
  }

  .nav__account {
    width: 100%;
    justify-content: space-between;
    padding: 0.9rem 0 0;
    margin-top: 0.4rem;
    border-left: 0;
    border-top: 1px solid var(--hairline-soft);
  }
}

@media (max-width: 640px) {
  .nav__email {
    max-width: 11rem;
  }

  /* Once the groups wrap onto separate lines the divider just indents the
     second row for no reason. */
  .filters__group:not(:empty) + .filters__group:not(:empty) {
    margin-left: 0;
    padding-left: 0;
    border-left: 0;
  }

  .job-row {
    grid-template-columns: 1fr;
    gap: 1rem;
  }

  .job-row__aside {
    justify-content: space-between;
  }

  .field-row {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .tabs {
    overflow-x: auto;
  }

  .modal__foot {
    flex-direction: column-reverse;
  }

  .modal__foot .btn {
    width: 100%;
  }
}

@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;
  }
}

@media print {
  .masthead,
  .footer,
  .apply-panel,
  .demo-banner,
  .backlink,
  .page::after,
  .scroll-progress {
    display: none;
  }

  /* Paper is light. Re-declare the dark theme's tokens in light values
     so every component prints legibly without per-component overrides. */
  :root {
    --canvas: #fff;
    --canvas-soft: #fff;
    --surface-card: #fff;
    --surface-strong: #eee;
    --ink: #111;
    --body-text: #333;
    --body-strong: #222;
    --muted: #555;
    --muted-soft: #888;
    --primary: #222;
    --primary-active: #000;
    --on-primary: #fff;
    --brass: #8a6a2f;
    --brass-bright: #8a6a2f;
    --hairline: #ddd;
    --hairline-soft: #eee;
    --hairline-strong: #bbb;
  }

  body {
    background: #fff;
  }

  /* Paper does not scroll — everything the observer was waiting to reveal
     must simply be there. */
  html.anim .reveal {
    opacity: 1 !important;
    transform: none !important;
  }
}

/* --- expanded footer + nav wrapping (Project A) ---
   Only meaningful at/above the nav-collapse breakpoint, where .nav is
   still the inline row — below it .nav is the hamburger dropdown
   (flex-direction: column), and this same wrap would fight the
   dropdown's max-height opening transition: with too little height to
   hold every link in one column yet, flex-wrap sends the overflow
   sideways into extra columns, which is exactly the "links arrange
   themselves horizontally, then snap into a vertical list" jank. */
@media (min-width: 801px) {
  .nav { flex-wrap: wrap; row-gap: 0.4rem; }
}

.footer__inner {
  display: grid;
  grid-template-columns: 1.5fr 1fr 1fr;
  gap: 2rem;
  padding-block: 1.4rem 1rem;
  align-items: start;
  justify-content: normal;
}
/* The footer wordmark is the exact navbar wordmark; keep it left-aligned. */
.footer__brand .wordmark { align-items: flex-start; }
.footer__col { display: flex; flex-direction: column; gap: 0.55rem; }
.footer__col a { color: var(--muted); text-decoration: none; width: fit-content; }
.footer__col a:hover { color: var(--ink); }
.footer__h {
  font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--muted-soft); margin-bottom: 0.25rem;
}
.footer__name { font-family: var(--display); font-weight: 600; color: var(--body-strong); }
.footer__tag { color: var(--muted); font-size: 0.9rem; }
.footer__base {
  padding-block: 0.85rem;
  color: var(--muted); font-size: 0.85rem;
}
@media (max-width: 640px) {
  .footer__inner { grid-template-columns: 1fr 1fr; gap: 1.5rem; }
  .footer__brand { grid-column: 1 / -1; }
}

/* --- contact page (Project A) --- */
.contact {
  display: grid;
  grid-template-columns: fit-content(22rem) 1fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  padding-bottom: 2.5rem;
  align-items: start;
}
.contact__offices { display: flex; flex-direction: column; gap: 2rem; }
.contact__form-wrap .label { display: block; margin-bottom: 1rem; }
.office__name { font-family: var(--display); font-size: 1.15rem; color: var(--body-strong); margin-bottom: 0.5rem; }
.office__addr { font-style: normal; display: flex; flex-direction: column; gap: 0.2rem; color: var(--body-text); }
.office__addr a { color: var(--body-strong); text-decoration: none; }
.office__addr a:hover { text-decoration: underline; }
@media (max-width: 760px) { .contact { grid-template-columns: 1fr; } }

/* --- message statuses (Project A) --- */
.status--read { background: var(--surface-strong); color: var(--body-strong); }
.status--archived { background: var(--surface-strong); color: var(--muted); }

/* --- services page (Project A) --- */
.service {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: clamp(1.5rem, 4vw, 3rem);
  padding-block: var(--section);
  border-top: 1px solid var(--hairline);
  scroll-margin-top: 6rem;
}
.service:first-child { border-top: none; }
.service__head h2 { font-family: var(--display); font-size: clamp(1.25rem, 2.2vw, 1.55rem); color: var(--ink); }
.service__head p { margin-top: 0.8rem; color: var(--body-text); max-width: 34ch; }
.service__list { list-style: none; display: flex; flex-direction: column; gap: 0.7rem; }
.service__list li {
  padding-left: 1.4rem; position: relative; color: var(--body-strong);
}
/* Escaped rather than a literal §: this stylesheet carries no @charset and a
   server that serves text/css without one lets the browser fall back to
   Latin-1, which renders the two UTF-8 bytes as "Â§". */
.service__list li::before {
  content: '\0000A7'; position: absolute; left: 0; color: var(--brass-bright);
}
@media (max-width: 720px) { .service { grid-template-columns: 1fr; padding-block: 2.5rem; } }

/* --- team page (Project A) --- */
.team-section { padding-block: 2.25rem 0; scroll-margin-top: 6rem; }
.team-section:last-child { padding-bottom: 2.5rem; }
.people { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 2rem; margin-top: 2rem; }
.person { display: flex; flex-direction: column; }
/* Image-forward cards: a large media block with the name and role beneath it. */
.person__photo, .person__monogram {
  width: 100%; aspect-ratio: 4 / 3; border-radius: var(--r-xl);
  object-fit: cover; margin-bottom: 1.1rem;
}
.person__photo {
  filter: grayscale(1) contrast(0.96);
  transition: filter 0.45s var(--ease), transform 0.45s var(--ease);
}
/* Portraits keep their archival grayscale until met — then colour arrives. */
.person:hover .person__photo {
  filter: grayscale(0) contrast(1);
  transform: scale(1.015);
}
.person__monogram {
  display: grid; place-items: center;
  background: linear-gradient(150deg, var(--surface-strong), var(--surface-card));
  color: var(--muted-soft); font-family: var(--display); font-size: 2.75rem; letter-spacing: -0.02em;
}
.person__name { font-family: var(--display); font-size: 1.25rem; color: var(--body-strong); }
.person__role { color: var(--muted); font-size: 0.92rem; margin-top: 0.2rem; }
.person__bio { color: var(--body-text); font-size: 0.92rem; margin-top: 0.7rem; }

/* --- card rail ------------------------------------------------------
   A horizontally scrolling row of the same person cards, sized so the
   next one is part-visible — that overhang is what tells you it scrolls.
   The left edge stays aligned with the page text while the right bleeds
   to the viewport edge.

   Movement is native scroll-snap, so a trackpad, touchscreen, keyboard
   or screen reader all work whether or not the script runs; the arrows
   only call scrollBy(). If every card already fits, team.js adds
   .is-static and the arrows are hidden rather than sitting there dead. */
.rail-cards {
  /* One knob for card width: the trailing padding below is derived from it,
     so the two can never drift apart at a breakpoint. */
  --rail-card: clamp(18rem, 46vw, 40rem);
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: var(--rail-card);
  gap: 2rem;
  margin-top: 2rem;
  align-items: start;
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  /* Bleed right to the viewport edge. */
  margin-right: calc(50% - 50vw);
  /* Trailing space so the *last* card can still scroll into the left slot.
     It has to equal the visible width minus one card — which is the track's
     own width (100% + the bleed) less a card. Anything smaller and the final
     card can never reach the slot, leaving the next arrow permanently stuck
     one short. Resolves to 0 when a single card fills the row, so a short
     list gains no phantom scroll. */
  padding-right: calc(50% + 50vw - var(--rail-card));
  scrollbar-width: none;
}
.rail-cards::-webkit-scrollbar { display: none; }
.rail-cards > .person { scroll-snap-align: start; }

/* Spotlight mode. Only applied once team.js runs: without it the cards keep
   their own captions and the row is a plain scrollable list, so no name or
   role is ever hidden behind a script that failed to load. */
.rail--spotlight .rail-cards > .person { cursor: pointer; }
.rail--spotlight .person__body { display: none; }
.rail--spotlight .person__photo,
.rail--spotlight .person__monogram {
  aspect-ratio: 16 / 10;
  margin-bottom: 0;
  transition: opacity 0.25s ease;
}
/* The off-slot cards recede rather than disappear — they are a peek, not
   content you are meant to read yet. */
.rail--spotlight .person:not(.is-active) .person__photo,
.rail--spotlight .person:not(.is-active) .person__monogram { opacity: 0.45; }

.rail-foot {
  display: flex; align-items: flex-start; justify-content: space-between;
  gap: 2rem; margin-top: 1.5rem;
}
.rail-caption { max-width: 34rem; min-height: 4.5rem; }
.rail-caption .person__name { font-size: 1.15rem; }
.rail--spotlight .rail-caption .person__body { display: block; }

.rail-controls { display: flex; gap: 0.5rem; flex-shrink: 0; }
.is-static .rail-controls { display: none; }

.rail-btn {
  width: 2.75rem; height: 2.75rem; border-radius: 50%;
  display: grid; place-items: center;
  border: 1px solid var(--hairline); background: var(--surface-card);
  color: var(--body-strong); font-size: 1.1rem; line-height: 1;
  cursor: pointer; transition: background 0.15s ease, border-color 0.15s ease;
}
.rail-btn:hover:not(:disabled) { background: var(--surface-strong); border-color: var(--muted-soft); }
.rail-btn:disabled { opacity: 0.3; cursor: default; }

/* Below the breakpoint the row is one card wide and reads as a normal
   swipeable list, so the bleed is dropped. */
@media (max-width: 620px) {
  .rail-cards { --rail-card: 78vw; gap: 1.25rem; }
  .rail-foot { flex-direction: column; gap: 1.25rem; }
  .rail-controls { align-self: flex-end; }
}
.recognitions { display: flex; flex-direction: column; gap: 1.25rem; }
.recognition {
  display: flex; gap: 1.25rem; align-items: flex-start;
  border: 1px solid var(--hairline); border-radius: var(--r-xl);
  padding: 1.5rem; background: var(--surface-card);
}
.recognition__img { width: 96px; height: 96px; object-fit: contain; }
.recognition__title { font-family: var(--display); font-size: 1.05rem; color: var(--body-strong); }
.recognition__desc { color: var(--body-text); margin-top: 0.4rem; }

/* --- article cards (Project B) — editorial cards with an optional cover --- */
.article-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.5rem; align-items: start; }
/* Bottom breathing room only on the standalone Articles page; on the landing the
   surrounding band already provides it (avoids a double gap under the strip). */
#articles.article-grid { padding-bottom: var(--section); }

/* The landing "Featured articles" strip scrolls horizontally with snap —
   articles.html keeps the normal wrapping grid above, this only overrides
   #featured. */
#featured.article-grid {
  display: flex;
  overflow-x: auto;
  scroll-snap-type: x proximity;
  gap: 1.5rem;
  padding-bottom: 0.5rem;
  scrollbar-width: thin;
}

#featured.article-grid > .article-card {
  flex: 0 0 min(320px, 85vw);
  scroll-snap-align: start;
}
.article-card {
  background: var(--surface-card); border: 1px solid var(--hairline);
  border-radius: var(--r-xl); box-shadow: var(--drop);
  display: flex; flex-direction: column; overflow: hidden;
  transition: box-shadow 0.2s var(--ease);
}
.article-card:hover { box-shadow: var(--drop-lg); }
.article-card__body { padding: 1.5rem; display: flex; flex-direction: column; gap: 0.7rem; }
.article-card__title { font-family: var(--display); font-size: 1.25rem; line-height: 1.22; }
.article-card__link { color: var(--body-strong); text-decoration: underline; text-underline-offset: 3px; text-decoration-thickness: 1px; }
.article-card__link:hover { color: var(--ink); }
.article-card__synopsis { color: var(--body-text); font-size: 0.92rem; }
.article-card__meta { display: flex; align-items: center; gap: 0.6rem; font-size: 0.85rem; color: var(--muted); }
.article-card__cat { font-weight: 600; color: var(--body-strong); }
.article-card__sep { width: 1px; height: 0.9em; background: var(--hairline-strong); }
.article-card__media { display: block; margin-top: auto; }
.article-card__media img { width: 100%; aspect-ratio: 16 / 10; object-fit: cover; display: block; }

/* --- legal pages (Project A) --- */
.legal { padding-bottom: var(--section); }
.legal .prose { max-width: 68ch; margin-top: 2rem; }
.legal .prose h2 { margin-top: 2rem; }

/* --- landing who-we-are (Project A) ---
   Icon-led cards: a brass line-icon per item, on the same card language
   as the rest of the site (surface, hairline, r-xl), but with a simpler
   lift-only hover — no spotlight or tilt — so it reads as related to,
   not a duplicate of, the practice cards below it. */
.whoweare { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: 1.5rem; margin-top: 2rem; }
.whoweare__item {
  padding: 1.75rem 1.5rem;
  background: var(--surface-card);
  border: 1px solid var(--hairline);
  border-radius: var(--r-xl);
  transition: border-color 0.25s var(--ease), transform 0.25s var(--ease), box-shadow 0.25s var(--ease);
}
.whoweare__item:hover {
  border-color: var(--hairline-strong);
  transform: translateY(-3px);
  box-shadow: var(--drop);
}
.whoweare__icon { width: 30px; height: 30px; color: var(--brass); margin-bottom: 1rem; }
.whoweare__item h3 { font-family: var(--display); font-size: 1.15rem; color: var(--body-strong); }
.whoweare__item p { color: var(--body-text); margin: 0.6rem 0 0.9rem; }
.textlink { color: var(--primary); text-decoration: none; font-weight: 500; font-size: 0.9rem; transition: color 0.2s var(--ease); }
.textlink:hover { color: var(--brass); text-decoration: underline; text-underline-offset: 3px; }
/* No transition here — it would override .pillar's own (box-shadow,
   border-color, transform), which is what actually animates the hover
   lift's translateY. This rule only needs to reset <a>'s defaults. */
a.pillar { text-decoration: none; color: inherit; display: block; }
a.pillar:hover { box-shadow: var(--drop-lg); }
.empty--flush { text-align: center; color: var(--muted); padding: 2rem 0; margin-top: 1rem; }

/* --- general application band (Project A) --- */
.general-apply {
  margin: 2.5rem 0 var(--section);
  border-top: 1px solid var(--hairline);
  padding-top: 2.5rem;
}
.general-apply__inner {
  display: flex; justify-content: space-between; align-items: center;
  gap: 1.5rem; flex-wrap: wrap;
}
.general-apply h2 { font-family: var(--display); font-size: clamp(1.2rem, 2vw, 1.5rem); color: var(--ink); }
.general-apply p { color: var(--body-text); margin-top: 0.5rem; max-width: 48ch; }

/* --- role-aware dashboard (Project B) --- */
.workspace--solo { grid-column: 1 / -1; }
.linklike { background: none; border: none; padding: 0; color: var(--ink); font-weight: 500; cursor: pointer; text-decoration: underline; font: inherit; }
.auth__alt { color: var(--muted); }

/* --- article/author status pills (Project B) ---
   A self-contained pill (its own class, so it never inherits the applications
   grid-cell stretch and never restyles the applications status). */
.pill {
  display: inline-flex; align-items: center; gap: 0.4rem;
  justify-self: start; width: fit-content;
  padding: 0.28rem 0.7rem; border-radius: var(--r-pill);
  font: 600 0.75rem/1 var(--body); letter-spacing: 0.01em; white-space: nowrap;
}
.pill::before { content: ''; width: 6px; height: 6px; border-radius: 50%; background: currentColor; }
.pill--draft { background: var(--surface-strong); color: var(--muted); }
.pill--submitted { background: rgba(211, 181, 120, 0.16); color: var(--brass-bright); }
.pill--approved { background: rgba(69, 192, 122, 0.16); color: var(--success); }
.pill--rejected { background: rgba(224, 110, 110, 0.16); color: var(--error); }

/* --- cover-photo picker + focal-point crop in the article editor (Project B) --- */
.filedrop--cover { margin: 0; max-width: 420px; }
/* cover thumbnail in the owner's article-review card */
.review-cover {
  width: 100%; max-width: 320px; aspect-ratio: 16 / 10; object-fit: cover;
  border-radius: var(--r-lg); display: block; margin-bottom: 1rem;
}
/* applications status filter */
.filters--apps { margin-bottom: 1.5rem; }
.cover-crop {
  position: relative; width: 100%; max-width: 420px; aspect-ratio: 16 / 10;
  border-radius: var(--r-lg); overflow: hidden; background: var(--surface-strong);
  cursor: grab; touch-action: none; user-select: none;
}
.cover-crop:active { cursor: grabbing; }
.cover-crop img { width: 100%; height: 100%; object-fit: cover; display: block; pointer-events: none; }
.cover-crop__hint {
  position: absolute; left: 50%; bottom: 0.6rem; transform: translateX(-50%);
  background: rgba(12, 10, 9, 0.72); color: #fff; font-size: 0.72rem;
  padding: 0.2rem 0.6rem; border-radius: var(--r-pill); pointer-events: none;
}
.editor-actions { display: flex; gap: 0.6rem; flex-wrap: wrap; margin-top: 1.4rem; }
