/* ============================================================
   InternDoor
   Live-ticker / terminal register. Acid lime on warm black,
   heavy condensed display type, monospace figures, film grain.
   ============================================================ */

:root {
  --ink:        #f2f2ec;
  --ink-2:      #9d9d94;
  --ink-3:      #6a6a62;
  --bg:         #0a0a0b;
  --bg-2:       #0f0f11;
  --card:       #121214;
  --card-2:     #17171a;
  --rule:       #222226;
  --rule-2:     #303036;

  --live:       #c8ff00;   /* the one loud colour. never a gradient. */
  --live-ink:   #14170a;
  --hot:        #ff5c1a;
  --cash:       #00e57a;

  --r:          4px;
  --r-2:        10px;
  --r-pill:     999px;

  --display: 'Archivo', 'Helvetica Neue', Impact, sans-serif;
  --ui:      'Space Grotesk', ui-sans-serif, -apple-system, sans-serif;
  --mono:    'JetBrains Mono', ui-monospace, SFMono-Regular, Menlo, monospace;

  /* ---- Type scale -------------------------------------------------------
     Tracking is size-specific, never one value for everything. Letters read
     too far apart as they grow, so display sizes get negative tracking; body
     sits near zero; small monospace labels get positive tracking to stay
     legible. Leading moves the opposite way to size — tight on headlines,
     loose on body.
     Sizes are rem so that a reader who raises their browser text size scales
     the layout with the text instead of bursting out of it. */
  --t-display:  clamp(1.75rem, 3.4vw, 2.5rem);
  --t-display-lh: 1.02;
  --t-display-tr: -.045em;

  --t-title:    1.0625rem;   /* the role — the line people actually scan */
  --t-title-lh: 1.3;
  --t-title-tr: -.015em;

  --t-body:     .9375rem;
  --t-body-lh:  1.55;
  --t-body-tr:  0;

  --t-small:    .8125rem;
  --t-small-lh: 1.45;

  --t-micro:    .6875rem;    /* mono labels, eyebrows, chips */
  --t-micro-lh: 1.2;
  --t-micro-tr: .09em;

  /* ---- Spacing ----------------------------------------------------------
     One scale, in rem, so spacing scales with text size too. */
  --s1: .25rem;  --s2: .5rem;   --s3: .75rem;  --s4: 1rem;
  --s5: 1.5rem;  --s6: 2rem;    --s7: 3rem;    --s8: 4rem;

  /* ---- Motion -----------------------------------------------------------
     One curve family. --snap is a strong ease-out for anything entering or
     responding; --glide is for things moving across the screen. */
  --snap:    cubic-bezier(.2,.9,.25,1);
  --glide:   cubic-bezier(.77,0,.175,1);
  --d-press: .14s;   /* button press feedback: 100-160ms */
  --d-ui:    .2s;    /* dropdowns, chips */
  --d-sheet: .3s;    /* the detail sheet */

  --bar-h:   62px;
  /* Replaced at runtime by syncStickyOffset(); this is only the first paint. */
  --stack-h: 152px;
}

:root[data-theme="light"] {
  --ink:      #131311;
  --ink-2:    #56564e;
  --ink-3:    #86867c;
  --bg:       #f4f3ee;
  --bg-2:     #eceae3;
  --card:     #ffffff;
  --card-2:   #f7f6f1;
  --rule:     #dddbd2;
  --rule-2:   #c6c4b9;
  --live:     #5d7a00;
  --live-ink: #ffffff;
  --hot:      #c2410c;
  --cash:     #067a52;
}

*, *::before, *::after { box-sizing: border-box; }
[hidden] { display: none !important; }

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

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--ui);
  font-size: 15px;
  line-height: 1.5;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* Film grain. Replaces the blurred gradient blobs that make a page read as
   machine-made — texture is the cheapest signal that a human chose something. */
.grain {
  position: fixed; inset: 0; z-index: 999; pointer-events: none; opacity: .038;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}
/* No blend mode in light theme. A full-viewport multiply layer composites
   unpredictably over light surfaces — it rendered a selected row as a black
   block even though the row's computed background was pure white. A plain
   low-opacity overlay is boring and always correct. */
:root[data-theme="light"] .grain { opacity: .028; }

h1, h2, h3 { margin: 0; font-family: var(--display); font-weight: 900; }
p { margin: 0; }
ol, ul, dl { margin: 0; padding: 0; list-style: none; }
a { color: inherit; }
button, input, select, textarea { font: inherit; color: inherit; }
:focus-visible { outline: 2px solid var(--live); outline-offset: 2px; }

.wrap { width: min(1320px, 100% - 44px); margin-inline: auto; }

.skip { position: absolute; left: -9999px; }
.skip:focus { left: 0; top: 0; z-index: 1000; background: var(--live); color: var(--live-ink); padding: 10px 16px; }

/* ---------- top bar ---------- */

.bar {
  position: sticky; top: 0; z-index: 60; height: var(--bar-h);
  background: color-mix(in oklab, var(--bg) 72%, transparent);
  backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px) saturate(180%);
  /* No hard rule. A 1px border draws a line whether or not anything is behind
     it; a soft edge only appears where content actually passes under the
     chrome, which is the thing the divider was standing in for. */
  border-bottom: 0;
}
.bar::after {
  content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 20px;
  pointer-events: none;
  background: linear-gradient(to bottom, color-mix(in oklab, var(--bg) 60%, transparent), transparent);
}
.bar-in { height: 100%; display: flex; align-items: center; justify-content: space-between; gap: 16px; }

.brand { display: inline-flex; align-items: center; gap: 11px; text-decoration: none; }
/* The radar scope, restored from InternZo unchanged. Three concentric rings, a
   61-degree wedge sweeping them on a 2.6s linear rotation, and a solid centre
   dot — the dot is what keeps the mark legible once the strokes disappear at
   favicon sizes, the same job the kite's solid panel used to do.
   Transform-only, so the sweep stays on the compositor and never repaints. It
   also needs no reduced-motion resting frame: a full 360 turn ends exactly
   where it started, so the global rule that collapses an animation to one
   .001ms iteration lands on the geometry already in the markup. The kite
   keyframes needed 0% AND 100% rest frames precisely because they did not. */
.scope { width: 30px; height: 30px; flex: none; }
.scope svg { width: 100%; height: 100%; display: block; overflow: visible; }
.s-ring { fill: none; stroke: var(--live); stroke-width: 1.1; opacity: .3; }
.s-sweep { transform-origin: 22px 22px; animation: sweep 2.6s linear infinite; }
.s-sweep path { fill: var(--live); opacity: .3; }
.s-dot { fill: var(--live); }
@keyframes sweep { to { transform: rotate(360deg); } }


.word {
  font-family: var(--display); font-weight: 900; font-size: 18px;
  letter-spacing: -.045em; line-height: 1;
}
.word em { font-style: normal; color: var(--live); }

/* The masthead is a fixed width budget: brand + bar-right must clear the
   viewport minus 15px of padding a side, which is 345px at 375. The right
   cluster measures 206, so the brand gets 139 and not a pixel more.

   INTERNDOOR is two characters longer than INTERNZO, and that is what makes
   this rule bigger than the one the kite needed. Measured at 375 before
   touching anything: mark 30 + gap 9 + word 127 = 166, which is 27 over
   budget and gave the whole page a horizontal scroll. The word is the
   dominant term, so the font size is the lever that actually moves it —
   shrinking the mark alone recovers 4px of the 27.

   Measure, do not eyeball: document.documentElement.scrollWidth must equal
   clientWidth at 375. Note the Browser pane reports innerWidth one pixel over
   clientWidth, so a 1px reading is the baseline, not a regression. */
@media (max-width: 480px) {
  .scope { width: 26px; height: 26px; }
  .brand { gap: 8px; }
  .word { font-size: 14.5px; letter-spacing: -.05em; }
}

.bar-right { display: flex; align-items: center; gap: 10px; }

.ticker {
  display: inline-flex; align-items: center; gap: 8px;
  font-family: var(--mono); font-size: 11px; letter-spacing: .02em;
  color: var(--ink-2); text-transform: uppercase;
  border: 1px solid var(--rule); padding: 6px 11px; border-radius: var(--r);
}
.beat {
  width: 6px; height: 6px; background: var(--live); flex: none;
  animation: beat 1.6s steps(1) infinite;
}
@keyframes beat { 0%,60% { opacity: 1; } 61%,100% { opacity: .18; } }

/* The one link on the page whose job is to bring somebody back.
   ------------------------------------------------------------------------
   Outlined rather than filled: Apply is the loud lime button and this must not
   compete with it on a card-by-card basis. It earns attention by being the only
   accented thing in the chrome, not by shouting louder than the primary action. */
.alerts {
  display: inline-flex; align-items: center; gap: 7px;
  height: 33px; padding: 0 12px; border-radius: var(--r-pill);
  border: 1px solid color-mix(in oklab, var(--live) 45%, transparent);
  color: var(--live); background: color-mix(in oklab, var(--live) 8%, transparent);
  font-size: .8125rem; font-weight: 600; letter-spacing: -.01em;
  text-decoration: none; white-space: nowrap;
  transition: background .16s, border-color .16s, transform var(--d-press) var(--snap);
}
.alerts:active { transform: scale(.97); }
@media (hover: hover) and (pointer: fine) {
  .alerts:hover { background: color-mix(in oklab, var(--live) 16%, transparent); border-color: var(--live); }
}

.ghost-btn {
  display: grid; place-items: center; width: 33px; height: 33px; padding: 0;
  background: none; border: 1px solid var(--rule); border-radius: var(--r);
  color: var(--ink-2); cursor: pointer;
  transition: color .16s, border-color .16s, background .16s;
}
.ghost-btn:hover { color: var(--live); border-color: var(--live); }
.i-moon { display: none; }
:root:not([data-theme="light"]) .i-sun { display: none; }
:root:not([data-theme="light"]) .i-moon { display: block; }

/* ---------- region switch ---------- */
/* Upgraded from a plain dropdown once more than one region shipped: it is the
   control that changes WHICH BOARD you are on, so it should read as heavier
   than a filter and lighter than the Apply button. */

/* A <details> disclosure, so it needs no JavaScript.
   The chrome it sits in is rendered by src/pages.js and loaded by app.js on the
   board and page.js on generated pages; a scripted dropdown would have to live
   in both files and stay in sync. Native <details> is also keyboard accessible
   and open to a crawler, which is what makes every region's board reachable by
   following an ordinary anchor.

   Present only when more than one region is published. */
.rg { position: relative; }

.rg > summary {
  display: inline-flex; align-items: center; gap: 7px;
  height: 33px; padding: 0 10px 0 11px; border-radius: var(--r);
  border: 1px solid var(--rule); color: var(--ink-2);
  background: color-mix(in oklab, var(--ink) 4%, transparent);
  font-size: .8125rem; font-weight: 600; letter-spacing: -.01em;
  white-space: nowrap; cursor: pointer; list-style: none;
  transition: color .16s, border-color .16s, background .16s;
}
/* The live dot. Same language as the .beat in the freshness ticker, so the
   header reads as one family rather than three unrelated controls. */
.rg > summary::before {
  content: ''; width: 5px; height: 5px; flex: none; border-radius: 50%;
  background: var(--live); box-shadow: 0 0 0 3px color-mix(in oklab, var(--live) 18%, transparent);
}
/* Both are needed: WebKit uses the pseudo-element, everything else the property. */
.rg > summary::-webkit-details-marker { display: none; }
.rg > summary::marker { content: ''; }
.rg > summary:focus-visible { outline: 2px solid var(--live); outline-offset: 2px; }

.rg-caret { transition: transform .18s var(--snap); }
.rg[open] > summary { color: var(--ink); border-color: color-mix(in oklab, var(--ink) 35%, transparent); }
.rg[open] .rg-caret { transform: rotate(180deg); }

@media (hover: hover) and (pointer: fine) {
  .rg > summary:hover { color: var(--live); border-color: var(--live); }
}

.rg-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 60;
  min-width: 190px; padding: 5px;
  background: var(--card); border: 1px solid var(--rule); border-radius: var(--r);
  box-shadow: 0 18px 40px -12px rgb(0 0 0 / .55);
  display: flex; flex-direction: column; gap: 1px;
  transform-origin: top right;
  animation: rg-open .16s var(--snap) both;
}
/* Named for this file only — `pop` and `sheen` are already taken twice over,
   and the later definition silently wins. */
@keyframes rg-open { from { opacity: 0; transform: translateY(-4px); } }

.rg-opt {
  display: flex; align-items: center; gap: 9px;
  padding: 9px 10px; border-radius: 3px;
  color: var(--ink-2); text-decoration: none;
  font-size: .875rem; font-weight: 500; letter-spacing: -.01em;
  transition: background .14s, color .14s;
}
/* The two-letter code, set in the mono face like every other hard fact on the
   site — the ages, the counts, the chips. */
.rg-opt::before {
  content: attr(data-region);
  font-family: var(--mono); font-size: 9.5px; font-weight: 700; letter-spacing: .06em;
  padding: 3px 5px; border-radius: 3px; min-width: 26px; text-align: center;
  background: var(--card-2); color: var(--ink-3);
  transition: background .14s, color .14s;
}
.rg-opt.is-on::before { background: var(--live); color: var(--live-ink); }
.rg-opt.is-on { color: var(--live); font-weight: 650; }
.rg-opt.is-on::after { content: '✓'; margin-left: auto; font-size: .8125rem; }

@media (hover: hover) and (pointer: fine) {
  .rg-opt:hover { background: color-mix(in oklab, var(--ink) 8%, transparent); color: var(--ink); }
  .rg-opt.is-on:hover { color: var(--live); }
}

/* The header runs out of room long before the listings do. Below 720px the
   globe alone carries it — the current region is still announced to a screen
   reader through the summary's aria-label. */
@media (max-width: 720px) {
  .rg-cur, .rg-caret { display: none; }
  .rg > summary { padding: 0 9px; }
}

@media (prefers-reduced-motion: reduce) {
  .rg-menu { animation: none; }
  .rg-caret { transition: none; }
}

/* ---------- lede ---------- */

/* Deliberately compact. The headline is a label, not a billboard — the
   listings are the product, and every pixel spent here pushes them down. */
.lede { border-bottom: 1px solid var(--rule); padding: 22px 0 20px; }
.lede-in { display: flex; align-items: baseline; gap: 22px; flex-wrap: wrap; }

.lede h1 {
  font-size: clamp(26px, 3.4vw, 38px); line-height: 1;
  letter-spacing: -.045em; text-transform: uppercase; flex: none;
}
.lede h1::after { content: ""; display: inline-block; width: .13em; height: .13em; margin-left: .05em; background: var(--live); vertical-align: baseline; }
.lede p { max-width: 68ch; color: var(--ink-2); font-size: 13.5px; line-height: 1.5; }
.lede strong { color: var(--ink); font-weight: 600; }

/* ---------- control rail ---------- */

.rail {
  position: sticky; top: var(--bar-h); z-index: 50;
  background: color-mix(in oklab, var(--bg) 78%, transparent);
  backdrop-filter: blur(20px) saturate(180%); -webkit-backdrop-filter: blur(20px) saturate(180%);
  border-bottom: 1px solid color-mix(in oklab, var(--rule) 60%, transparent);
}
.rail-in { display: flex; align-items: center; gap: 14px; padding: 12px 0; flex-wrap: wrap; }

.seg { display: flex; border: 1px solid var(--rule); border-radius: var(--r); overflow: hidden; }
.seg-b {
  background: none; border: 0; cursor: pointer;
  padding: 8px 15px; font-size: 13px; font-weight: 600; color: var(--ink-3);
  display: inline-flex; align-items: center; gap: 8px;
  transition: color .16s, background .16s;
}
.seg-b + .seg-b { border-left: 1px solid var(--rule); }
.seg-b b {
  font-family: var(--mono); font-size: 10.5px; font-weight: 700;
  padding: 2px 6px; border-radius: 3px; background: var(--card-2); color: var(--ink-3);
  font-variant-numeric: tabular-nums;
}
.seg-b:hover { color: var(--ink); }
.seg-b[aria-selected="true"] { background: var(--live); color: var(--live-ink); }
.seg-b[aria-selected="true"] b { background: color-mix(in oklab, var(--live-ink) 16%, transparent); color: var(--live-ink); }

/* The role split is gone — the site is engineering-only — so this is now a
   label showing the count, not a control. Keep the segment's shape so the rail
   still reads as one row, but drop the affordances that imply it is clickable. */
.seg-static { cursor: default; background: var(--live); color: var(--live-ink); }
.seg-static:hover { color: var(--live-ink); }
.seg-static b { background: color-mix(in oklab, var(--live-ink) 16%, transparent); color: var(--live-ink); }

.find {
  flex: 1 1 240px; min-width: 190px; display: flex; align-items: center; gap: 9px;
  border: 1px solid var(--rule); border-radius: var(--r); padding: 0 12px; height: 34px;
  color: var(--ink-3); transition: border-color .16s;
}
.find:focus-within { border-color: var(--live); }
.find input { flex: 1; border: 0; background: none; outline: none; font-size: 13.5px; color: var(--ink); min-width: 0; }
.find input::-webkit-search-cancel-button { display: none; }
.x { border: 0; background: none; color: var(--ink-3); cursor: pointer; font-size: 19px; line-height: 1; padding: 0 2px; }
.x:hover { color: var(--ink); }

.picks { display: flex; gap: 8px; flex-wrap: wrap; }
.picks label { display: inline-flex; align-items: center; gap: 7px; border: 1px solid var(--rule); border-radius: var(--r); padding: 0 10px 0 11px; height: 34px; }
.picks span { font-family: var(--mono); font-size: 9.5px; text-transform: uppercase; letter-spacing: .12em; color: var(--ink-3); }
.picks select {
  appearance: none; -webkit-appearance: none; background: none; border: 0; outline: none;
  font-size: 13px; color: var(--ink); cursor: pointer; max-width: 140px;
  padding-right: 14px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%236a6a62' stroke-width='2.6' stroke-linecap='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat; background-position: right center; background-size: 11px;
}
.picks label:hover { border-color: var(--rule-2); }

.flags { display: flex; gap: 8px; }
.flag {
  background: none; border: 1px solid var(--rule); border-radius: var(--r);
  color: var(--ink-3); height: 34px; padding: 0 13px; cursor: pointer;
  font-family: var(--mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: .1em;
  /* Named properties, not `all`: `all` animates whatever else happens to
     change — including layout properties, off the GPU. */
  transition: color .16s, background-color .16s, border-color .16s;
}
.flag:hover { color: var(--ink); border-color: var(--rule-2); }
.flag[aria-pressed="true"] { background: var(--live); border-color: var(--live); color: var(--live-ink); font-weight: 700; }
.flag-reset { color: var(--hot); border-color: color-mix(in oklab, var(--hot) 40%, transparent); }

/* ---------- board ---------- */

.board { display: grid; grid-template-columns: minmax(0,1.15fr) minmax(0,1fr); gap: 26px; align-items: start; padding: 20px 0 80px; }
.feed-head {
  font-family: var(--mono); font-size: 10.5px; text-transform: uppercase;
  letter-spacing: .13em; color: var(--ink-3); padding-bottom: 12px;
  border-bottom: 1px solid var(--rule);
}

/* ---------- the register ---------- */

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

/* Each job is its own bordered block. Hairline-separated rows blurred into one
   another; an outline makes every listing a distinct object you can aim at. */
.row {
  scroll-margin-top: calc(var(--stack-h) + 16px);
  position: relative; display: grid;
  grid-template-columns: 40px minmax(0,1fr) auto;
  gap: var(--s4); align-items: start;
  padding: var(--s4); cursor: pointer;
  background: var(--card);
  border: 1px solid var(--rule);
  border-radius: var(--r-2);
  overflow: hidden;
  transition: border-color .16s, transform var(--d-press) var(--snap), background .16s;
}
/* Apple's first rule: respond on the press, not on release. The card is a
   button; without this it stays inert until the sheet opens and the tap reads
   as lag. Small — 0.99 on a full-width surface is the same perceived travel as
   0.97 on a chip. */
.row:active { transform: scale(.99); }

/* Entrance only on the first paint — .intro is set by renderList() once and
   never again, so filtering and searching swap the list silently. 280ms keeps
   it under the 300ms ceiling for UI motion. */
.feed.intro .row { animation: rowIn .28s var(--snap) both; }
/* The stagger itself is applied inline in renderList() — 32ms per row, capped
   at 14 — which is inside the 30–80ms band. It cannot live here: .row is the
   only child of its <li>, so a :nth-child() on .row always matches 1. */
@keyframes rowIn { from { opacity: 0; transform: translateY(9px); } to { opacity: 1; transform: none; } }

/* the lit edge — how selection and freshness are signalled */
.row::before {
  content: ""; position: absolute; left: 0; top: 0; bottom: 0; width: 2px;
  background: transparent; transition: background .16s, width .2s var(--snap);
}
.row:hover { border-color: var(--rule-2); }
.row:hover::before { background: var(--rule-2); }
.row[aria-current="true"] {
  border-color: var(--live); background: var(--card-2);
}
.row[aria-current="true"]::before { background: var(--live); width: 4px; }
.row.is-hot::before { background: var(--hot); }
.row.is-hot { border-color: color-mix(in oklab, var(--hot) 42%, var(--rule)); }

.crest {
  width: 40px; height: 40px; border-radius: var(--r); overflow: hidden; position: relative;
  display: grid; place-items: center; background: var(--card-2);
  font-family: var(--display); font-weight: 800; font-size: 15px; color: var(--ink-2);
  border: 1px solid var(--rule);
}
.crest img { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: contain; padding: 4px; background: #fff; }

/* Hierarchy, corrected.
   ------------------------------------------------------------------------
   The company used to be a 25px display-caps headline and the role a 14px
   grey subtitle. That is backwards: nobody scans a job board for "NoBroker",
   they scan for "Backend Intern". It also broke on real data — LinkedIn
   company names are arbitrary strings, and "Interloop - Zoho Partner | Manage
   Engine | Managed HR Services" set in 800-weight caps took three lines and
   pushed the actual job below the fold.

   The role is now the heading; the company is an eyebrow above it. Emphasis
   comes from weight and colour, not size, so the card stays compact. */
.co {
  font-family: var(--ui);
  font-size: var(--t-micro); line-height: var(--t-micro-lh);
  letter-spacing: var(--t-micro-tr); text-transform: uppercase;
  font-weight: 600; color: var(--ink-2);
  /* Two lines maximum. A pathological company name truncates instead of
     taking over the card. */
  display: -webkit-box; -webkit-box-orient: vertical; -webkit-line-clamp: 2;
  overflow: hidden; overflow-wrap: anywhere;
}
.role {
  margin-top: var(--s1);
  font-family: var(--ui); font-weight: 600;
  font-size: var(--t-title); line-height: var(--t-title-lh);
  letter-spacing: var(--t-title-tr);
  color: var(--ink); overflow-wrap: anywhere;
}

/* What the job actually is, shown only when the title does not say — a quarter of
   postings are titled just "Apprentice". Carries the accent so the eye lands on the
   distinguishing half of the line rather than the word every card shares. The
   separator is a pseudo-element so it never appears without a qualifier. */
.role .qual { color: var(--ink); }
.role .qual::before { content: "·"; margin: 0 7px; color: var(--ink-3); }
.meta { display: flex; flex-wrap: wrap; gap: 6px 14px; margin-top: 10px; font-family: var(--mono); font-size: 10.5px; letter-spacing: .05em; color: var(--ink-3); text-transform: uppercase; }
.meta .cash { color: var(--cash); font-weight: 700; }
.meta .ea { color: var(--hot); }
.meta .unpaid { color: var(--ink-3); }
.meta .dunno { color: var(--ink-3); opacity: .72; }

/* Eligibility. The only boxed item in the row, because it is the one fact that
   can rule you out entirely — everything else is detail you read afterwards. */
.elig {
  display: inline-flex; align-items: center; gap: 6px;
  border: 1px solid color-mix(in oklab, var(--live) 42%, transparent);
  border-radius: var(--r); padding: 2px 7px; margin: -2px 0;
}
.elig b { color: var(--live); font-weight: 700; letter-spacing: .08em; }
.elig i { font-style: normal; color: var(--ink-2); text-transform: none; letter-spacing: .02em; }

.skills { display: flex; flex-wrap: wrap; gap: 5px; margin-top: 9px; }
.skill {
  font-family: var(--mono); font-size: 10px; letter-spacing: .06em; text-transform: uppercase;
  color: var(--ink-2); background: var(--card-2); border: 1px solid var(--rule);
  border-radius: 3px; padding: 3px 7px;
}

.gist {
  margin-top: 10px; font-size: 13.5px; color: var(--ink-2); max-width: 62ch;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; line-clamp: 2; overflow: hidden;
}

/* Bullets replace the description blurb: the old paragraph was clamped to two
   lines and almost always spent them on company boilerplate. */
.gist-list { margin-top: 10px; max-width: 66ch; display: grid; gap: 5px; }
.gist-list li {
  position: relative; padding-left: 15px;
  font-size: 13.5px; line-height: 1.45; color: var(--ink-2);
}
.gist-list li::before {
  content: ""; position: absolute; left: 0; top: .55em;
  width: 5px; height: 5px; background: var(--live); opacity: .55;
}

.age { text-align: right; padding-top: 4px; }
.age b {
  display: block; font-family: var(--mono); font-size: 13px; font-weight: 700;
  color: var(--ink-2); font-variant-numeric: tabular-nums;
}
.age.fresh b { color: var(--live); }
.age.blazing b { color: var(--hot); }
.age s {
  display: block; margin-top: 6px; margin-left: auto; height: 2px; width: 44px;
  background: var(--rule); text-decoration: none; overflow: hidden;
}
.age s i { display: block; height: 100%; background: var(--live); }
.age.blazing s i { background: var(--hot); }

/* ---------- card footer: age + apply ---------- */

/* Occupies the slot .age used to hold, so the .row grid is unchanged: on wide
   screens it is the 4th column and stacks; on a phone it drops under the text
   and lays out as a row, age left and the button right where a thumb is. */
.card-foot { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; }

.card-go {
  position: relative; overflow: hidden;
  display: inline-flex; align-items: center; gap: 7px;
  padding: 0 14px; height: 34px; flex: none;
  border-radius: 999px; border: 1px solid var(--live);
  background: var(--live); color: var(--live-ink);
  font-family: var(--ui); font-size: 13px; font-weight: 600; letter-spacing: -.01em;
  text-decoration: none; white-space: nowrap; cursor: pointer;
  /* 140ms: button press feedback belongs in 100-160ms. At 180ms the press
     read soft rather than tactile. */
  transition: transform .14s var(--snap), box-shadow .18s, filter .18s;
}
.card-go-t { position: relative; z-index: 1; }

/* The arrow is drawn rather than typed so it can move on its own. */
.card-go-a {
  position: relative; z-index: 1;
  width: 13px; height: 9px; flex: none;
  background: currentColor;
  clip-path: polygon(0 38%, 62% 38%, 62% 0, 100% 50%, 62% 100%, 62% 62%, 0 62%);
  transition: transform .2s var(--snap);
}
.card-go:active { transform: translateY(0) scale(.96); }
.card-go:focus-visible { outline: 2px solid var(--ink); outline-offset: 2px; }

/* A sheen that crosses the button on hover. Purely decorative, and skipped
   entirely under prefers-reduced-motion by the global rule near the bottom. */
.card-go::after {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(100deg, transparent 20%, rgba(255,255,255,.55) 50%, transparent 80%);
  transform: translateX(-120%);
}
@keyframes sheen { to { transform: translateX(120%); } }

/* A hot role gets the hot colour, so the button matches the urgency the age
   badge is already signalling rather than fighting it. */
.row.is-hot .card-go { background: var(--hot); border-color: var(--hot); }


/* ============================================================
   THE APPLY BUTTON — the ambient loop
   ------------------------------------------------------------
   Shared by every apply button on the site: the card list and
   the detail pane here, and the generated job page's rail
   button through page.css, which loads after this file.

   The frequency rule says do not animate what somebody sees
   dozens of times a day. Apply is the opposite case — it is the
   one action every visitor came to take, and on a job page a
   stranger from a search sees it exactly once. So it moves on
   its own until they touch it.

   One 2.6s cycle: about 900ms of motion, then most of two
   seconds of stillness. Anything that never rests stops being
   seen within about three passes.
   ============================================================ */

/* The wrapper exists so the halo and the ping can escape the overflow:hidden
   that the sheen requires. Any button that wants the full treatment gets one;
   the card buttons do not, for reasons in the stagger note below. */
/* THE GLOW IS PERMANENT AND EVERY MOVING PART STAYS INSIDE THE BUTTON.
 *
 * Both halves are deliberate, and the reason is layer promotion. An animated
 * element gets its own compositor layer, Chrome promotes whatever overlaps it,
 * and text on a promoted layer drops from subpixel to greyscale antialiasing —
 * thinner and greyer. In a dense panel like the detail pane, an effect that
 * spills past the button (a blurred halo, a ring, an expanding shadow) reaches
 * the company name, the facts grid and the summary; the sheen and the arrow
 * are clipped inside the button and reach nothing.
 *
 * Caveat worth recording, because it cost a lot of time: the greyed-out pane
 * is INTERMITTENT and shows up in screenshots only when the capture happens to
 * catch the promoted state. Two captures of an identical page gave different
 * results. So it is not something to bisect by eye — several confident
 * conclusions drawn that way here turned out to be wrong. Keeping the reach of
 * anything animated inside the button sidesteps the question entirely, and
 * costs nothing worth having.
 *
 * A permanent glow is also simply more visible than one that breathes: it is
 * never in its off phase. */

.apply-glow { position: relative; display: inline-block; }

/* The bloom. Static, and on the button rather than the wrapper so it traces
   the button's own radius. */
.apply-glow > .go, .apply-glow > .btn-apply {
  box-shadow:
    0 0 14px 0 color-mix(in oklab, var(--live) 85%, transparent),
    0 0 52px 8px color-mix(in oklab, var(--live) 60%, transparent);
  transition: box-shadow .2s;
}

/* The detail pane's apply button. Rounded like its neighbours, so the halo and
   the ping follow the same radius. */
/* relative + overflow so the sheen below can sit inside it. .btn-apply already
   carries both from page.css. */
.apply-glow > .go { position: relative; overflow: hidden; }
.apply-glow > .go .go-t { position: relative; z-index: 1; }
.apply-glow > .go::after {
  content: ""; position: absolute; inset: 0; z-index: 0;
  background: linear-gradient(100deg, transparent 16%, rgba(255,255,255,.85) 50%, transparent 84%);
  transform: translateX(-130%);
  animation: sheen-loop 2.6s linear .8s infinite;
}
.apply-glow > .go .card-go-a { animation: nudge 2.6s var(--snap) .8s infinite; }

/* LINEAR, not --snap. A sheen is constant motion, like a marquee, and the site
   curve is a strong ease-out: at --snap the band covered the whole button in
   180ms and then spent 800ms crawling across dead space off the right edge. It
   read as a blink. Two passes rather than one — the second is what makes it
   read as deliberate rather than as a stray reflection. */
@keyframes sheen-loop {
  0%   { transform: translateX(-130%); }
  20%  { transform: translateX(130%); }
  26%  { transform: translateX(-130%); }
  42%  { transform: translateX(130%); }
  100% { transform: translateX(130%); }
}

/* The arrow leans out as each pass reaches it. The numbers are not decorative:
   the arrow sits at the right-hand end and the sheen is over that end at 17%
   and again at 36%, so the leans peak there. Timed any later the two stop
   reading as one gesture and become a flash followed by an unrelated twitch. */
@keyframes nudge {
  0%, 11%   { transform: translateX(0); }
  17%       { transform: translateX(9px); }
  26%       { transform: translateX(2px); }
  36%       { transform: translateX(9px); }
  48%, 100% { transform: translateX(0); }
}

/* ---------- the card buttons ---------- */

/* 134 of these are in the DOM at once, so they get the two cheap effects and
   neither of the expensive ones. No halo: that is 134 blurred layers, each
   rasterised and composited whether or not it is on screen. No ping: that is
   134 elements repainting on a timer. Sheen and arrow are transforms on
   compositor layers and cost effectively nothing at any count.
   ------------------------------------------------------------------------
   And they are STAGGERED. Fired in unison, ten lime pills flashing together
   down a column reads as a fault in the page — the eye cannot pick a target
   because they all move at once. Offset, the same motion becomes a wave
   travelling down the list, which is both calmer and far more noticeable.
   Six phases. Note that the phase count does not change HOW MANY are lit at
   once — two passes put the band on the button for about 34% of the cycle, so
   about a third of them are mid-sweep whatever you choose. What the phases
   decide is whether that third reads as a wave down the column or as ten
   things twitching at once. Measured on the real list: 46 of 134. */
.card-go::after { animation: sheen-loop 2.6s linear var(--go-lag, 0s) infinite; }
.card-go-a { animation: nudge 2.6s var(--snap) var(--go-lag, 0s) infinite; }

/* They get the bloom as well — it is static, so 134 of them are 134 paints and
   nothing more. Smaller than the two big buttons get: at their strength a
   column of lime pills glowing at full power reads as a fault rather than as
   emphasis. */
/* Two shadows, not one: a tight bright core and a wide soft falloff. A single
   large blur at high alpha reads as fog around the pill rather than as light
   coming off it — the core is what makes it read as emission. Still a plain
   box-shadow, so 145 of them are 145 paints and no compositor layers, which is
   the whole reason the card buttons can have this at all. */
.card-go {
  box-shadow:
    0 0 10px 0 color-mix(in oklab, var(--live) 78%, transparent),
    0 0 30px 4px color-mix(in oklab, var(--live) 46%, transparent);
}
.row.is-hot .card-go {
  box-shadow:
    0 0 10px 0 color-mix(in oklab, var(--hot) 80%, transparent),
    0 0 30px 4px color-mix(in oklab, var(--hot) 50%, transparent);
}

.feed > li:nth-child(6n+1) .card-go { --go-lag: .8s; }
.feed > li:nth-child(6n+2) .card-go { --go-lag: 1.23s; }
.feed > li:nth-child(6n+3) .card-go { --go-lag: 1.67s; }
.feed > li:nth-child(6n+4) .card-go { --go-lag: 2.1s; }
.feed > li:nth-child(6n+5) .card-go { --go-lag: 2.53s; }
.feed > li:nth-child(6n+6) .card-go { --go-lag: 2.97s; }

/* ---------- hover ---------- */

/* Hover CANCELS the loops rather than pausing them. Paused, a sheen freezes as
   a bright band across the middle of the button and the arrow strands itself
   mid-lean. Cancelled, each falls back to its transition and answers the
   pointer instead — and the halo settles at its bright end and holds, because
   nothing should keep breathing under a finger already on it. */
@media (hover: hover) and (pointer: fine) {
  .apply-glow:hover > .go, .apply-glow:hover > .btn-apply {
    box-shadow:
      0 0 18px 0 color-mix(in oklab, var(--live) 95%, transparent),
      0 0 66px 12px color-mix(in oklab, var(--live) 85%, transparent);
  }
  .apply-glow > .go:hover::after { animation: sheen-loop .62s linear; }
  .apply-glow > .go:hover .card-go-a { animation: none; transform: translateX(3px); }
  .card-go:hover {
    box-shadow:
      0 0 14px 0 color-mix(in oklab, var(--live) 95%, transparent),
      0 0 42px 8px color-mix(in oklab, var(--live) 70%, transparent);
  }
  .card-go:hover::after { animation: sheen-loop .62s linear; }
  .card-go:hover .card-go-a { animation: none; transform: translateX(3px); }
}

/* ---------- the light theme ---------- */

/* NO SHEEN IN THE LIGHT THEME, on any of these buttons.
 *
 * The two themes invert them: dark is near-black ink on bright lime, light is
 * white ink on olive. A white band sweeping over the first LIFTS the label's
 * contrast, 15.4:1 to 17.5:1. Over the second it erases it — 4.9:1 falls to
 * 1.2:1, which is white text on a white button, and the word "Apply"
 * disappearing every few seconds. Measured, not guessed: composite the sheen
 * alpha over the button colour and run the contrast formula before touching
 * any of this.
 *
 * A dark band would be legible but reads as a shadow crossing the button
 * rather than as light coming off it. The halo and the arrow carry the light
 * theme instead, at about half strength — olive on cream needs far less than
 * lime on black. */
:root[data-theme="light"] .card-go::after,
:root[data-theme="light"] .apply-glow > .go::after,
:root[data-theme="light"] .btn-apply::after { display: none; }

/* Olive on cream, not lime on black: the same bloom reads as a dirty smudge
   under the button at the dark theme's strength. */
:root[data-theme="light"] .apply-glow > .go,
:root[data-theme="light"] .apply-glow > .btn-apply {
  box-shadow:
    0 0 12px 0 color-mix(in oklab, var(--live) 44%, transparent),
    0 0 34px 4px color-mix(in oklab, var(--live) 30%, transparent);
}
/* The card pills too, at less again. Olive on cream carries far less light
   than lime on black before it stops reading as glow and starts reading as a
   smudge under the button — this is deliberately about a third of the dark
   theme's alpha, not a match for it. */
:root[data-theme="light"] .card-go {
  box-shadow:
    0 0 8px 0 color-mix(in oklab, var(--live) 40%, transparent),
    0 0 22px 3px color-mix(in oklab, var(--live) 24%, transparent);
}
:root[data-theme="light"] .row.is-hot .card-go {
  box-shadow:
    0 0 8px 0 color-mix(in oklab, var(--hot) 42%, transparent),
    0 0 22px 3px color-mix(in oklab, var(--hot) 26%, transparent);
}

/* ---------- reduced motion ---------- */

@media (prefers-reduced-motion: reduce) {
  .apply-glow > .go::after, .card-go::after { display: none; }
  .card-go-a, .apply-glow > .go .card-go-a { animation: none; }
}

/* ---------- empty ---------- */

.void { padding: 66px 20px; text-align: center; border: 1px dashed var(--rule-2); border-radius: var(--r-2); }
.void-mark {
  display: block; width: 46px; height: 46px; margin: 0 auto 20px;
  border: 1px solid var(--rule-2); border-radius: 50%; position: relative;
}
.void-mark::after { content: ""; position: absolute; inset: 12px; border: 1px solid var(--rule-2); border-radius: 50%; }
.void h3 { font-size: 22px; text-transform: uppercase; letter-spacing: -.03em; }
.void p { margin-top: 8px; color: var(--ink-3); font-size: 14px; }

/* ---------- detail pane ---------- */

.pane-col { position: sticky; top: calc(var(--stack-h) + 16px); }
.pane, .pane-idle { border: 1px solid var(--rule); border-radius: var(--r-2); background: var(--card); }
.pane-idle { display: grid; place-items: center; text-align: center; padding: 84px 30px; min-height: 380px; }
.pane-idle p { font-family: var(--display); font-weight: 800; font-size: 20px; text-transform: uppercase; letter-spacing: -.03em; }
.pane-idle p span { display: block; margin-top: 9px; font-family: var(--ui); font-weight: 400; font-size: 13.5px; text-transform: none; letter-spacing: 0; color: var(--ink-3); }

.idle-scope, .wait-scope { position: relative; display: block; width: 72px; height: 72px; margin-bottom: 26px; }
.idle-scope i, .wait-scope i {
  position: absolute; inset: 0; border: 1px solid var(--live); border-radius: 50%;
  animation: ripple 2.8s var(--snap) infinite;
}
.idle-scope i:nth-child(2), .wait-scope i:nth-child(2) { animation-delay: .95s; }
.idle-scope i:nth-child(3), .wait-scope i:nth-child(3) { animation-delay: 1.9s; }
@keyframes ripple { 0% { transform: scale(.3); opacity: .9; } 100% { transform: scale(1); opacity: 0; } }

.pane { padding: 26px; max-height: calc(100vh - var(--stack-h) - 44px); overflow: auto; overscroll-behavior: contain; }
.pane.is-in { animation: rowIn .3s var(--snap) both; }
.back {
  display: none; background: none; border: 0; color: var(--live); cursor: pointer;
  font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: .1em;
  padding: 0; margin-bottom: 18px;
}
.p-co { font-family: var(--display); font-weight: 900; font-size: 34px; line-height: .96; letter-spacing: -.045em; text-transform: uppercase; }
.p-role { margin-top: 9px; font-size: 16px; color: var(--ink); }
.p-loc { margin-top: 6px; font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: .08em; color: var(--ink-3); }

.p-acts { display: flex; gap: 9px; margin: 22px 0; flex-wrap: wrap; }

.go, .alt, .bare {
  border-radius: var(--r); height: 40px; padding: 0 18px; cursor: pointer;
  font-size: 13.5px; font-weight: 700; text-decoration: none;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  transition: transform .14s var(--snap), background .16s, border-color .16s, color .16s;
}
.go { background: var(--live); border: 1px solid var(--live); color: var(--live-ink); }
.go:active { transform: none; }
.go:disabled { opacity: .35; cursor: not-allowed; transform: none; }
.go-block { width: 100%; }
.alt { background: none; border: 1px solid var(--rule-2); color: var(--ink); }
.alt:hover { border-color: var(--live); color: var(--live); }
.alt svg { flex: none; }
.bare { background: none; border: 1px solid transparent; color: var(--ink-3); }
.bare:hover { color: var(--ink); }

.facts { display: grid; grid-template-columns: repeat(auto-fit, minmax(118px,1fr)); border: 1px solid var(--rule); border-radius: var(--r); overflow: hidden; margin-bottom: 22px; }
.fact { padding: 12px 14px; box-shadow: 0 0 0 1px var(--rule); }
.fact dt { font-family: var(--mono); font-size: 9.5px; text-transform: uppercase; letter-spacing: .12em; color: var(--ink-3); }
.fact dd { margin: 5px 0 0; font-size: 14.5px; font-weight: 600; }
.fact dd.cash { color: var(--cash); }

.pane h3 { font-family: var(--mono); font-weight: 700; font-size: 10px; text-transform: uppercase; letter-spacing: .16em; color: var(--ink-3); margin: 22px 0 10px; }
.p-gist { font-size: 14.5px; white-space: pre-line; }
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
.chip { border: 1px solid var(--rule); border-radius: var(--r); padding: 4px 9px; font-family: var(--mono); font-size: 10.5px; color: var(--ink-2); text-transform: uppercase; letter-spacing: .05em; }
.src { margin-top: 24px; padding-top: 15px; border-top: 1px solid var(--rule); font-size: 12px; color: var(--ink-3); }
.src a { color: var(--ink-2); }

/* ---------- footer ---------- */

.foot { border-top: 1px solid var(--rule); background: var(--bg-2); padding: 30px 0 52px; font-size: 12px; color: var(--ink-3); }
.foot p { max-width: 80ch; }
.dim { margin-top: 8px; opacity: .75; }

/* ---------- modal ---------- */

.veil { position: fixed; inset: 0; z-index: 90; background: rgba(5,5,6,.78); animation: fade .2s; }
@keyframes fade { from { opacity: 0; } }
.modal {
  position: fixed; z-index: 91; top: 50%; left: 50%; transform: translate(-50%,-50%);
  width: min(790px, calc(100vw - 32px)); max-height: min(89vh, 940px);
  background: var(--bg-2); border: 1px solid var(--rule-2); border-radius: var(--r-2);
  display: flex; flex-direction: column; overflow: hidden;
  animation: pop .3s var(--snap);
}
@keyframes pop { from { opacity: 0; transform: translate(-50%, calc(-50% + 14px)); } }
.modal-top { display: flex; justify-content: space-between; gap: 16px; padding: 20px 22px; border-bottom: 1px solid var(--rule); flex: none; }
.modal-top h2 { font-size: 21px; text-transform: uppercase; letter-spacing: -.035em; }
.modal-sub { margin-top: 5px; font-family: var(--mono); font-size: 11px; color: var(--ink-3); text-transform: uppercase; letter-spacing: .06em; }
.modal-body { padding: 22px; overflow: auto; overscroll-behavior: contain; }

.drop { display: grid; place-items: center; gap: 7px; text-align: center; border: 1px dashed var(--rule-2); border-radius: var(--r); padding: 40px 22px; cursor: pointer; color: var(--ink-3); transition: border-color .16s, color .16s, background .16s; }
.drop:hover, .drop.over { border-color: var(--live); color: var(--live); background: color-mix(in oklab, var(--live) 5%, transparent); }
.drop b { font-family: var(--display); font-weight: 800; font-size: 17px; color: var(--ink); text-transform: uppercase; letter-spacing: -.02em; }
.drop:hover b, .drop.over b { color: var(--live); }
.drop span { font-family: var(--mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: .07em; }

.paste { margin-top: 14px; }
.paste summary { cursor: pointer; font-family: var(--mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3); }
.paste summary:hover { color: var(--live); }
.paste textarea { width: 100%; margin-top: 10px; padding: 12px; border: 1px solid var(--rule); border-radius: var(--r); background: var(--card); color: var(--ink); resize: vertical; font-size: 13px; outline: none; }
.paste textarea:focus { border-color: var(--live); }

.filestate { margin-top: 14px; padding: 11px 13px; border-radius: var(--r); border: 1px solid color-mix(in oklab, var(--cash) 40%, transparent); color: var(--cash); font-family: var(--mono); font-size: 11px; text-transform: uppercase; letter-spacing: .05em; }
.filestate.bad { border-color: color-mix(in oklab, var(--hot) 45%, transparent); color: var(--hot); text-transform: none; letter-spacing: 0; font-family: var(--ui); font-size: 13px; }

.warn { margin: 16px 0 18px; padding: 14px 16px; border-left: 2px solid var(--hot); background: var(--card); font-size: 12.5px; color: var(--ink-2); display: flex; flex-direction: column; gap: 8px; }
.warn b { color: var(--ink); }

.wait { display: grid; place-items: center; text-align: center; padding: 60px 20px; }
.wait b { font-family: var(--display); font-weight: 800; font-size: 19px; text-transform: uppercase; letter-spacing: -.02em; }
.wait > span { margin-top: 7px; font-family: var(--mono); font-size: 10.5px; text-transform: uppercase; letter-spacing: .1em; color: var(--ink-3); }

.acts { display: flex; gap: 9px; flex-wrap: wrap; margin-bottom: 18px; }
.flagbox { border-left: 2px solid var(--hot); background: var(--card); padding: 13px 15px; margin-bottom: 12px; font-size: 13px; color: var(--ink-2); }
.flagbox b { display: block; color: var(--ink); margin-bottom: 5px; }
.flagbox ul { list-style: disc; padding-left: 18px; margin-top: 5px; }
.flagbox-gap { border-left-color: var(--live); }

.diffs { margin-bottom: 18px; }
.diffs h4 { margin: 0 0 9px; font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .16em; color: var(--ink-3); font-weight: 700; }
.diffs ul { display: flex; flex-direction: column; gap: 6px; }
.diffs li { font-size: 13px; color: var(--ink-2); padding-left: 18px; position: relative; }
.diffs li::before { content: "+"; position: absolute; left: 0; color: var(--live); font-family: var(--mono); font-weight: 700; }

.sheet { background: #fff; color: #16160f; border-radius: var(--r); padding: 38px 42px; font-family: ui-serif, Georgia, serif; font-size: 13px; line-height: 1.5; }
.sheet .r-name { font-family: var(--display); font-weight: 900; font-size: 26px; letter-spacing: -.035em; text-transform: uppercase; }
.sheet .r-contact { font-family: var(--mono); font-size: 11px; color: #55554c; margin-top: 4px; }
.sheet .r-summary { margin-top: 14px; }
.sheet .r-sec { margin-top: 19px; }
.sheet .r-sec > h5 { margin: 0 0 8px; font-family: var(--mono); font-size: 10px; text-transform: uppercase; letter-spacing: .16em; font-weight: 700; border-bottom: 1.5px solid #16160f; padding-bottom: 4px; }
.sheet .r-item { margin-bottom: 12px; break-inside: avoid; }
.sheet .r-item-head { display: flex; justify-content: space-between; gap: 12px; align-items: baseline; }
.sheet .r-role { font-weight: 700; }
.sheet .r-org { font-style: italic; color: #3d3d35; }
.sheet .r-dates { font-family: var(--mono); font-size: 10.5px; color: #62625a; white-space: nowrap; }
.sheet .r-item ul { list-style: disc; padding-left: 18px; margin-top: 4px; }
.sheet .r-skills { font-family: var(--mono); font-size: 11.5px; }

.oops { text-align: center; padding: 48px 26px; color: var(--ink-2); }
.oops b { display: block; font-family: var(--display); font-weight: 800; font-size: 20px; color: var(--ink); text-transform: uppercase; margin-bottom: 8px; }
.oops p { margin-bottom: 18px; font-size: 14px; }

.snack {
  position: fixed; left: 50%; bottom: 26px; transform: translateX(-50%); z-index: 95;
  background: var(--live); color: var(--live-ink); padding: 11px 20px; border-radius: var(--r);
  font-family: var(--mono); font-size: 11.5px; font-weight: 700; text-transform: uppercase; letter-spacing: .08em;
  /* A transition, not a keyframe. Keyframes restart from zero, so a second
     toast arriving during the first snapped it back to the start; a transition
     retargets from wherever it currently is. */
  opacity: 1;
  transition: opacity .26s var(--snap), transform .26s var(--snap);
}
.snack:not(.is-up) { opacity: 0; transform: translate(-50%, 12px); }

/* ---------- hover motion, gated ----------
   A tap on a touchscreen fires a :hover before the click, so every one of these
   lifts fired on a phone — the device most of this traffic arrives on — and then
   stuck until the next tap elsewhere. Colour and border cues above stay ungated
   because they read correctly either way; only movement is gated. */
@media (hover: hover) and (pointer: fine) {
  .row:hover { transform: translateY(-2px); }
  .go:hover { transform: translateY(-2px); }
  .alt:hover { transform: translateY(-2px); }
  .card-go:hover { transform: translateY(-2px); box-shadow: 0 6px 18px -6px color-mix(in oklab, var(--live) 70%, transparent); }
  .card-go:hover .card-go-a { transform: translateX(3px); }
  .card-go:hover::after { animation: sheen .62s var(--snap); }
  .row.is-hot .card-go:hover { box-shadow: 0 6px 18px -6px color-mix(in oklab, var(--hot) 70%, transparent); }
}

/* ---------- responsive ---------- */

/* ============================================================
   VARIANT A — the mobile / tablet / iPad design.
   Everything from here down applies at 1024px and under. Desktop above that
   is deliberately untouched: the two-pane register works there.
   1024 rather than 1000 so an iPad Pro in portrait gets the touch design.
   ============================================================ */
@media (max-width: 1024px) {
  .board { grid-template-columns: 1fr; }
  .pane-col { position: fixed; inset: 0; z-index: 80; background: var(--bg); overflow: auto; display: none; }
  /* Opening a role used to be an instant cut to a full screen of new text,
     which on a phone reads as a page load rather than a detail view. Sliding
     it up keeps the sense that the list is still underneath. */
  .pane-col.open { display: block; animation: paneIn .3s var(--snap) both; }
  /* Not ease-in. It starts slow and delays the moment the user is watching;
     ease-out at the same duration reads as faster. */
  .pane-col.closing { animation: paneOut .2s var(--snap) both; }
  @keyframes paneIn { from { opacity: 0; transform: translateY(22px); } }
  @keyframes paneOut { to { opacity: 0; transform: translateY(16px); } }
  .pane-idle { display: none; }
  .pane { max-height: none; min-height: 100vh; border: 0; border-radius: 0; padding: 22px 22px 70px; }
  .back { display: inline-block !important; }

}

@media (max-width: 1024px) {
  .wrap { width: calc(100% - 30px); }

  /* No hero on a phone.
     ---------------------------------------------------------------------
     This is where ad traffic lands, and a first screen made of a slogan is
     a first screen with nothing to scroll. The headline plus its paragraph
     cost ~210px — most of the fold — to say something the listings below
     say better by simply being there.
     Removing it puts real roles above the fold, which is the only thing
     that earns the second scroll. */
  .lede { display: none; }

  /* The filter rail was three stacked rows (~400px): a search box, four
     dropdowns wrapped 2x2, then the toggles. Together with the hero the
     first actual listing began roughly 600px down — a phone user saw no
     jobs at all without scrolling.
     One horizontally-scrollable strip of controls replaces the 2x2 grid,
     so the rail is a fixed ~120px whatever the screen height. */
  .picks {
    flex-wrap: nowrap;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    -webkit-overflow-scrolling: touch;
    scrollbar-width: none;
    /* Bleed to the screen edges so the strip reads as scrollable rather
       than clipped, and the last chip is not glued to the margin. */
    margin: 0 -15px;
    padding: 0 15px;
    scroll-padding-left: 15px;
    /* A hard vertical cut through a chip at the screen edge reads as a broken
       layout. Fading the last 34px turns the same overflow into an obvious
       "there is more this way", and the fade retracts once you reach the end. */
    -webkit-mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent 100%);
    mask-image: linear-gradient(to right, #000 calc(100% - 34px), transparent 100%);
  }
  .picks.at-end {
    -webkit-mask-image: none;
    mask-image: none;
  }
  .picks::-webkit-scrollbar { display: none; }
  .picks label { flex: 0 0 auto; min-width: 0; }
  /* Narrow enough that the next chip is always part-visible at the right edge.
     A half-shown chip is the affordance that says "this strip scrolls"; at a
     wider cap the first chip alone filled the screen and the strip looked
     like a plain full-width control that had been clipped. */
  .picks select { max-width: 28vw; }

  /* Was hidden when it was only a count, which the "N ROLES" line above the
     first card already gave. It is a real control again — internship vs
     full-time — so it stays, just tighter. */
  .seg { order: -1; }
  .seg-b { padding: 8px 12px; font-size: 12.5px; }

  .ticker { display: none; }
  /* Stays on mobile. The ticker goes so this can: a visitor who arrived from an
     ad and leaves without following the channel is a visitor paid for twice. */
  .alerts { height: 34px; padding: 0 11px; }

  /* ---- The card, rebuilt as the feed card -----------------------------
     One column, not a grid: logo and company sit on a header line, the role
     is the headline beneath it, and Apply is a full-width target at the
     bottom. Nothing competes with the role for the first glance. */
  .row {
    display: block;
    padding: var(--s4) var(--s4) var(--s3);
    border-radius: 20px;
    border-color: transparent;
    background: var(--card);
  }
  .row::before { display: none; }        /* the lit left edge belongs to the register */
  .row[aria-current="true"] { border-color: transparent; background: var(--card-2); }

  /* Logo + company + age on one line above the role. */
  .row > .crest { float: left; margin-right: var(--s3); }
  .crest { width: 34px; height: 34px; font-size: 12px; border-radius: 9px; }

  .co {
    font-size: .8125rem; font-weight: 600; letter-spacing: .01em;
    text-transform: none; color: var(--ink-2);
    -webkit-line-clamp: 1; line-height: 34px;
  }

  /* The headline. Big enough to be read while a thumb is moving. */
  .role {
    clear: both; padding-top: var(--s2);
    font-family: var(--display); font-weight: 800;
    font-size: clamp(1.25rem, 5.4vw, 1.5rem); line-height: 1.14; letter-spacing: -.03em;
  }

  /* Facts become pills rather than a monospace run-on. */
  .meta { gap: 6px; margin-top: var(--s3); text-transform: none; letter-spacing: .01em; }
  .meta > span:not(.elig) {
    font-family: var(--ui); font-size: .75rem; font-weight: 600;
    background: var(--card-2); border-radius: 999px; padding: 5px 11px; color: var(--ink-2);
  }
  .meta .ea { color: var(--hot); background: color-mix(in oklab, var(--hot) 12%, transparent); }
  .elig { border-radius: 999px; padding: 4px 11px; background: color-mix(in oklab, var(--live) 12%, transparent); }

  .gist-list { margin-top: var(--s3); }
  .gist-list li { font-size: .90625rem; }

  /* Apply spans the card. The single biggest target on the screen, sitting
     where the thumb already rests. */
  .card-foot {
    display: flex; flex-direction: column-reverse; align-items: stretch;
    gap: var(--s2); padding-top: var(--s4); width: 100%;
  }
  .card-go {
    height: 50px; border-radius: 14px; padding: 0;
    justify-content: center; font-size: 1rem; font-weight: 700;
  }
  .age { text-align: left; padding-top: 0; display: flex; align-items: center; gap: 8px; }
  .age s { margin-left: 0; }
  /* The selects still need min-width:0 and the ellipsis. Their intrinsic width
     is the widest company or city name in the option list, which without this
     becomes an unshrinkable floor — that is what used to push the rail ~150px
     past the viewport and make the whole PAGE scroll sideways. Now only the
     .picks strip scrolls, and it does so on purpose. */
  .picks select { min-width: 0; text-overflow: ellipsis; white-space: nowrap; overflow: hidden; }

  /* Only the 62px bar stays pinned. The rail used to wrap to three rows here,
     and sticking it too froze ~350px — nearly half a phone screen — above every
     scroll. It scrolls away now; the bar is what you need while scrolling. */
  .rail { position: static; backdrop-filter: none; -webkit-backdrop-filter: none; }
  .modal { width: 100vw; max-width: 100vw; height: 100vh; max-height: 100vh; top: 0; left: 0; transform: none; border: 0; border-radius: 0; }
  @keyframes pop { from { opacity: 0; transform: translateY(14px); } }
  .sheet { padding: 24px 20px; }
  .p-co { font-size: 27px; }
}

/* Phones only: cards run to the screen edges. On a tablet the inset reads as
   deliberate; on a 390px screen it is 30px of wasted width. */
@media (max-width: 600px) {
  .feed { margin-inline: -15px; }
  .row { border-radius: 0; padding-inline: var(--s4); }
}

/* Translucency is a preference, not a given. Someone who has asked for less of
   it gets solid chrome instead — same layout, no blur, no see-through. */
@media (prefers-reduced-transparency: reduce) {
  .bar, .rail {
    background: var(--bg);
    backdrop-filter: none; -webkit-backdrop-filter: none;
    border-bottom: 1px solid var(--rule);
  }
  .bar::after { display: none; }
  .grain { display: none; }
}

/* More contrast: solid surfaces and a defined border on everything that was
   relying on a subtle tint to separate itself. */
@media (prefers-contrast: more) {
  :root { --ink-2: #d6d6ce; --ink-3: #b0b0a6; --rule: #4a4a52; --rule-2: #6b6b74; }
  :root[data-theme="light"] { --ink-2: #2f2f2a; --ink-3: #4a4a44; --rule: #8f8d84; --rule-2: #6a6862; }
  .row, .crest, .ticker, .ghost-btn, .flag, .find, .picks label { border-width: 1px; border-style: solid; }
  .bar, .rail { background: var(--bg); backdrop-filter: none; -webkit-backdrop-filter: none; }
  .grain { display: none; }
}

@media (prefers-reduced-motion: reduce) {
  /* Reduced motion means gentler, not none. Killing every transition also
     killed the colour and opacity fades that explain what just changed, which
     leaves the UI harder to follow rather than calmer.
     Keyframes here are all movement, so they collapse. Transitions survive,
     narrowed to the properties that do not move anything. */
  *, *::before, *::after { animation-duration: .001ms !important; animation-iteration-count: 1 !important; }
  *, *::before, *::after {
    transition-property: color, background-color, border-color, box-shadow, opacity !important;
  }
  /* No lift, no press travel, no arrow slide. */
  .row:hover, .go:hover, .alt:hover, .card-go:hover,
  .card-go:hover .card-go-a, .card-go:active { transform: none !important; }
  .grain { display: none; }
}

@media print {
  .bar, .lede, .rail, .board, .foot, .grain, .veil, .snack,
  .modal-top, .acts, .flagbox, .diffs { display: none !important; }
  body { background: #fff; }
  .modal { position: static; transform: none; width: auto; max-height: none; border: 0; border-radius: 0; animation: none; background: #fff; }
  .modal-body { padding: 0; overflow: visible; }
  .sheet { border-radius: 0; padding: 0; font-size: 10.5pt; line-height: 1.42; color: #000; }
  .sheet .r-name { font-size: 19pt; }
  .sheet .r-sec { margin-top: 13pt; break-inside: avoid; }
  @page { margin: 14mm 15mm; }
}

/* The crawlable index of every current listing, in the footer.
   Collapsed by default: it exists so a crawler has real links to follow, and
   so a reader who wants the whole list in one place can open it. It was
   originally rendered into the results list, where it flashed as a stack of
   bare links before app.js replaced them. */
.all-roles { margin: 1.1rem 0 0; }
.all-roles > summary {
  cursor: pointer; font: 600 0.78rem/1.4 var(--mono, ui-monospace, monospace);
  letter-spacing: 0.04em; text-transform: uppercase; opacity: 0.55;
}
.all-roles > summary:hover { opacity: 0.85; }
.all-roles > ul {
  margin: 0.8rem 0 0; padding: 0 0 0 1rem; max-height: 22rem; overflow-y: auto;
  columns: 2; column-gap: 2rem;
}
.all-roles > ul > li { margin: 0 0 0.45rem; font-size: 0.82rem; break-inside: avoid; }
.all-roles > ul > li > a { color: inherit; }
.all-roles .tiny { opacity: 0.5; }
@media (max-width: 720px) { .all-roles > ul { columns: 1; } }
