/* Shared design system for the OffCycle account pages (account / settings / alerts).
   Mirrors the tracker's tokens so the whole site feels like one product. */
:root{
  --bg:#f6f7f9; --panel:#ffffff; --ink:#141a21; --ink2:#454f5b; --mute:#6a7480;
  --line:#e3e7ec; --line2:#eef0f3; --accent:#17416e; --accent2:#2563a3;
  --accent-soft:#eef2f7; --gold:#8a6410; --gold-soft:#f6efdd; --green:#157a52;
  --green-soft:#e7f1ea; --danger:#b23b3b; --danger-soft:#f7e7e7;
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;
  --serif:ui-serif,"New York","Iowan Old Style",Georgia,"Times New Roman",serif;
  --mono:ui-monospace,"SF Mono",Menlo,Consolas,monospace;
  /* One motion language shared across the whole site: a refined ease-out (fast
     start, soft stop) at medium presence — the Stripe-like feel we're after. */
  --ease:cubic-bezier(.22,.7,.2,1);
  --t-fast:.15s; --t-mid:.24s; --t-slow:.42s;
}
/* Dark mode — applied when data-theme="dark" is on <html>. Persisted in localStorage
   ('oc-theme') and carried across every page by paintNav() in js/auth.js. */
:root[data-theme="dark"]{
  --bg:#0e1319; --panel:#151b23; --ink:#e8edf3; --ink2:#aeb8c4; --mute:#7d8794;
  --line:#262e39; --line2:#1c232c; --accent:#5a90cf; --accent2:#7aa8dd;
  --accent-soft:#182533; --gold:#d4a24a; --gold-soft:#2a2213; --green:#3fa877;
  --green-soft:#14261e; --danger:#e06a6a; --danger-soft:#2a1515;
}
/* theme toggle button injected into the nav by paintNav() */
.theme-btn{background:none;border:1px solid var(--line);border-radius:6px;width:34px;height:32px;
  display:inline-flex;align-items:center;justify-content:center;color:var(--mute);cursor:pointer;padding:0;flex:none}
.theme-btn:hover{border-color:var(--accent2);color:var(--accent)}
.theme-btn svg{width:16px;height:16px}
*{box-sizing:border-box}
/* The hidden attribute must always win — otherwise display:block rules (e.g. .field)
   override it and elements like the register-only name field leak onto other views. */
[hidden]{display:none !important}
body{margin:0;background:var(--bg);color:var(--ink);font-family:var(--sans);font-size:14px;line-height:1.5;
  -webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale;text-rendering:optimizeLegibility;
  font-feature-settings:"kern" 1,"liga" 1}
a{color:var(--accent2);text-decoration:none}
a:hover{text-decoration:underline}

/* header (shared with tracker). .shrink is toggled by js/auth.js's wireShrinkNav() past a
   scroll threshold: the bar detaches into a floating rounded pill, like astarai.co.uk /
   whali.co.uk's nav-on-scroll behaviour, rather than just staying a flat sticky bar. Same
   colours as the flat state throughout - only shape/position change on scroll. */
header{background:var(--panel);border-bottom:1px solid var(--line);position:sticky;top:0;z-index:20;
  margin:0;border-radius:0;box-shadow:none;
  transition:margin .25s ease,border-radius .25s ease,box-shadow .25s ease,border-color .25s ease}
header.shrink{margin:30px 18px 0;border-radius:14px;border-color:transparent;box-shadow:0 8px 24px -12px rgba(16,24,40,.28)}
/* three zones, evenly balanced regardless of how much either side holds: logo | centred
   product links | account controls (notifications, profile / sign in). */
.hd{max-width:1100px;margin:0 auto;padding:12px 20px;display:grid;grid-template-columns:auto 1fr auto;
  align-items:center;column-gap:16px;transition:padding .25s ease;position:relative}
header.shrink .hd{padding:6px 20px}
.brand{font-weight:800;font-size:18px;letter-spacing:-.01em;display:flex;align-items:center;gap:8px}
.brand a{color:var(--ink)}
.brand a:hover{text-decoration:none}
/* offcycle logo — the cycle-ring mark locked up with a clean two-tone wordmark:
   lowercase "off" in ink + "cycle" in the accent. The mark is inline SVG (not a
   background-image) so it can actually animate: the ring draws itself in once on
   load, and does a single confident spin on hover. */
.brand .wm{display:inline-flex;align-items:center;font-weight:800;font-size:19px;
  letter-spacing:-.03em;line-height:1;color:var(--ink);white-space:nowrap}
.wmmark{width:1.34em;height:1.34em;margin-right:.44em;flex:none;overflow:visible}
.wmmark .wmbg{fill:var(--accent)}
.wmmark .wmring{stroke:#fff;stroke-dasharray:84.4 22.4;animation:wm-draw .9s var(--ease) both}
.brand a:hover .wmmark{animation:wm-spin .6s var(--ease) 1}
@keyframes wm-draw{from{stroke-dashoffset:84.4}to{stroke-dashoffset:0}}
@keyframes wm-spin{to{transform:rotate(360deg)}}
.brand .wm b{color:var(--accent);font-weight:800;letter-spacing:-.02em;
  transition:color .16s var(--ease,ease)}
.brand a:hover .wm b{color:var(--accent2)}
.brand .tag{font-weight:600;font-size:11px;color:var(--mute);border:1px solid var(--line);
  padding:2px 7px;border-radius:20px;text-transform:uppercase;letter-spacing:.05em}
/* centred product links */
#navCenter{display:flex;align-items:center;justify-content:center;gap:26px;font-weight:600;
  font-size:13.5px;flex-wrap:wrap}
#navCenter>a{color:var(--ink)}
#navCenter>a:hover{color:var(--accent);text-decoration:none}
/* right-side account controls only: notifications + profile / sign in */
#navAuth{display:flex;align-items:center;gap:16px;font-weight:600;justify-self:end}
#navAuth a.signin-link{white-space:nowrap}

/* Hamburger toggle, inserted into #navAuth by wireProductNav() in auth.js. Hidden by
   default (desktop); the media query below both reveals it and turns #navCenter from
   an inline row into a dropdown sheet. Plain flex-wrap alone (still the fallback if JS
   fails to load) works but looks broken — items split arbitrarily above/below the
   header row instead of a single coherent list. */
.navburger{display:none;border:none;background:none;cursor:pointer;padding:7px;
  border-radius:8px;color:var(--ink);flex:none}
.navburger:hover{background:var(--accent-soft)}
.navburger svg{width:21px;height:21px;display:block}

@media(max-width:640px){
  .navburger{display:inline-flex;align-items:center;justify-content:center}
  #navCenter{display:none;position:absolute;top:100%;left:0;right:0;flex-direction:column;
    align-items:stretch;gap:0;padding:4px 20px 14px;margin:0;background:var(--panel);
    border-bottom:1px solid var(--line);box-shadow:0 18px 32px -18px rgba(16,24,40,.28);
    max-height:calc(100vh - 100%);overflow-y:auto}
  #navCenter.nav-open{display:flex}
  #navCenter>a{width:100%;padding:13px 2px;border-bottom:1px solid var(--line2)}
  /* the Interview mega-menu becomes an inline expandable row instead of a floating panel */
  #navCenter .ocmenu{width:100%}
  #navCenter .ocmenu-trigger{width:100%;padding:13px 2px;border-bottom:1px solid var(--line2);
    justify-content:space-between}
  #navCenter .ocmenu-panel{position:static;opacity:1;visibility:visible;transform:none;
    box-shadow:none;border:none;min-width:0;padding:0 0 6px 14px;display:none}
  #navCenter .ocmenu.open .ocmenu-panel{display:block}
  #navCenter .ocmenu.open .ocmenu-trigger{border-bottom-color:transparent}
}

/* One button shape for the whole site. It used to be defined three times with three
   different results: 6px radius / 14px / weight 600 here, 13px in jobs.html, and 9px radius
   / 15.5px / weight 700 on the homepage's join CTA. Same class name, three shapes, which is
   most of why the pages never looked related. Sizes now come from the scale above. */
.btn{font-family:var(--sans);font-size:var(--fs-md);font-weight:700;border:1px solid var(--line);
  background:var(--panel);color:var(--ink);border-radius:var(--r-sm);min-height:var(--ctl-h);
  padding:0 16px;cursor:pointer;display:inline-flex;align-items:center;gap:7px;
  justify-content:center;text-decoration:none;line-height:1;
  transition:border-color var(--t-fast) var(--ease),background-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease)}
.btn:hover{border-color:var(--accent2);color:var(--accent);text-decoration:none}
.btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}
.btn.primary:hover{background:var(--accent2);color:#fff}
.btn.small{min-height:30px;padding:0 11px;font-size:var(--fs-sm)}
.btn.lg{min-height:46px;padding:0 24px;font-size:var(--fs-base)}
.btn.danger{color:var(--danger);border-color:var(--danger-soft)}
.btn.danger:hover{background:var(--danger);color:#fff;border-color:var(--danger)}
.btn:disabled{opacity:.55;cursor:default}
.btn.block{width:100%}
.linkbtn{background:none;border:none;color:var(--mute);font-size:14px;cursor:pointer;text-decoration:underline;
  padding:0;font-family:var(--sans);font-weight:600}
.linkbtn:hover{color:var(--accent)}

/* page shell */
main{max-width:1100px;margin:28px auto 60px;padding:0 20px}
.narrow{max-width:460px;margin-inline:auto}
h1{font-size:24px;font-weight:700;letter-spacing:-.02em;margin:0 0 4px}
.lead{color:var(--mute);margin:0 0 20px}
h2{font-size:16px;letter-spacing:-.005em;margin:0 0 14px}

.card{background:var(--panel);border:1px solid var(--line);border-radius:8px;padding:20px;margin-bottom:16px}
.card h2{border-bottom:1px solid var(--line2);padding-bottom:12px}

/* forms */
/* ── Scale ───────────────────────────────────────────────────────────────────
   Measured before this existed: 63 distinct font sizes, 24 border radii, 47 shadows and
   223 padding values across the site, plus 28 separate button classes and 32 card classes.
   Individually invisible; collectively it is why two pages never quite look related.

   These are the canonical steps. New work uses them. Existing pages are moved over
   component by component rather than in one sweep, because a blanket find-and-replace
   across 37 pages changes every screen at once with no way to review it.

   The values are chosen from what the site ALREADY uses most, so adopting them is a
   convergence on the existing look rather than a restyle. */
:root{
  /* type */
  --fs-xs:11px; --fs-sm:12.5px; --fs-md:13.5px; --fs-base:15px;
  --fs-lg:17px; --fs-xl:20px; --fs-2xl:26px; --fs-3xl:33px;
  /* radius: the four the site actually needs */
  --r-sm:8px; --r-md:10px; --r-lg:14px; --r-pill:999px;
  /* elevation: flat, raised, floating. Nothing else. */
  --sh-1:0 1px 2px rgba(16,24,40,.04);
  --sh-2:0 1px 2px rgba(16,24,40,.04), 0 10px 26px -16px rgba(16,24,40,.22);
  --sh-3:0 18px 40px -16px rgba(16,24,40,.34);
  /* spacing rhythm */
  --sp-1:4px; --sp-2:8px; --sp-3:12px; --sp-4:16px; --sp-5:22px; --sp-6:30px; --sp-7:44px;
  /* one control height, so a button, an input and a select line up in a row */
  --ctl-h:38px;
}
:root[data-theme="dark"], :root.dark{
  --sh-1:0 1px 2px rgba(0,0,0,.4);
  --sh-2:0 1px 2px rgba(0,0,0,.4), 0 10px 26px -16px rgba(0,0,0,.6);
  --sh-3:0 18px 40px -16px rgba(0,0,0,.7);
}

/* ── Buttons ─────────────────────────────────────────────────────────────────
   One shape, three sizes, three emphases. Pages keep their own class names so no markup
   or JS selector changes, but anything opting into .ui-btn inherits the same geometry. */
.ui-btn{display:inline-flex;align-items:center;justify-content:center;gap:7px;
  min-height:var(--ctl-h);padding:0 16px;border:1px solid var(--line);border-radius:var(--r-sm);
  background:var(--panel);color:var(--ink);font-family:var(--sans);font-size:var(--fs-md);
  font-weight:700;line-height:1;text-decoration:none;cursor:pointer;white-space:nowrap;
  transition:border-color var(--t-fast) var(--ease),background-color var(--t-fast) var(--ease),
    color var(--t-fast) var(--ease),transform var(--t-fast) var(--ease)}
.ui-btn:hover{border-color:var(--accent2);color:var(--accent)}
.ui-btn:active{transform:translateY(1px)}
.ui-btn:disabled,.ui-btn[aria-disabled="true"]{opacity:.5;cursor:default;transform:none}
.ui-btn.sm{min-height:30px;padding:0 11px;font-size:var(--fs-sm)}
.ui-btn.lg{min-height:46px;padding:0 24px;font-size:var(--fs-base)}
.ui-btn.primary{background:var(--accent);border-color:var(--accent);color:#fff}
.ui-btn.primary:hover{background:var(--accent2);border-color:var(--accent2);color:#fff}
.ui-btn.quiet{border-color:transparent;background:transparent;color:var(--ink2)}
.ui-btn.quiet:hover{background:var(--accent-soft);color:var(--accent)}

/* ── Surfaces ────────────────────────────────────────────────────────────────
   32 card classes existed. This is the one they should all resolve to. */
.ui-card{background:var(--panel);border:1px solid var(--line);border-radius:var(--r-md);
  padding:var(--sp-4)}
.ui-card.raised{box-shadow:var(--sh-2)}
.ui-pill{display:inline-flex;align-items:center;gap:6px;padding:3px 9px;border-radius:var(--r-pill);
  font-size:var(--fs-xs);font-weight:700;letter-spacing:.02em;white-space:nowrap}
/* Section label, the small uppercase heading used above groups on nearly every page. */
.ui-eyebrow{font-size:var(--fs-xs);font-weight:800;letter-spacing:.06em;text-transform:uppercase;
  color:var(--mute);line-height:1}

label.field{display:block;margin-bottom:14px}
label.field .lab{display:block;font-size:12px;font-weight:600;color:var(--ink2);margin-bottom:5px}
input[type=text],input[type=email],input[type=password],select,textarea{
  width:100%;padding:10px 12px;border:1px solid var(--line);border-radius:6px;background:var(--panel);
  color:var(--ink);font-size:14px;font-family:var(--sans)}
input:focus,select:focus,textarea:focus{outline:2px solid var(--accent-soft);border-color:var(--accent2)}
select{appearance:none;cursor:pointer;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236b7686' stroke-width='2'><path d='M6 9l6 6 6-6'/></svg>");
  background-repeat:no-repeat;background-position:right 12px center;padding-right:34px}

/* A select used as an inline control, not as a stacked form field, sizes to its own content.
   The width:100% above is right for settings and contribute, where every select is one
   labelled field in a column. A toolbar control inherits it and then goes wrong in one of
   two ways: the Hunt Board status dropdown stretched to 1022px for five one-word options,
   and the headhunting route filter was pinned back with max-width:130px, which clipped its
   longest option to "Any way of reachir". Sizing to content fixes both without a per-page
   magic number, and max-width:100% keeps a long option from overflowing a narrow phone. */
select.filt,select.st{width:auto;max-width:100%}
.row2{display:grid;grid-template-columns:1fr 1fr;gap:12px}
@media(max-width:560px){.row2{grid-template-columns:1fr}}

/* tabs */
.tabs{display:flex;gap:4px;background:var(--line2);padding:4px;border-radius:8px;margin-bottom:20px}
.tabs button{flex:1;padding:9px;border:none;background:none;border-radius:5px;font-weight:600;font-size:14px;
  color:var(--ink2);cursor:pointer;font-family:var(--sans)}
.tabs button[aria-selected="true"]{background:var(--panel);color:var(--accent);box-shadow:0 1px 2px rgba(0,0,0,.06)}

/* notices */
.note{padding:11px 14px;border-radius:6px;font-size:13px;margin-bottom:14px;display:none}
.note.show{display:block}
.note.err{background:var(--danger-soft);color:var(--danger)}
.note.ok{background:var(--green-soft);color:var(--green)}
.note.info{background:var(--accent-soft);color:var(--accent)}

/* alerts list */
.alert-item{display:flex;gap:14px;align-items:flex-start;padding:16px;border:1px solid var(--line);
  border-radius:8px;margin-bottom:12px;background:var(--panel)}
.alert-item .body{flex:1}
.alert-item .title{font-weight:700;margin-bottom:6px}
.chips{display:flex;flex-wrap:wrap;gap:6px}
.chip{font-size:11px;font-weight:600;background:var(--accent-soft);color:var(--accent);padding:3px 9px;border-radius:20px}
.muted{color:var(--mute)}
.center{text-align:center}
footer{max-width:1100px;margin:0 auto;padding:24px 20px 50px;color:var(--mute);font-size:12.5px}

/* Ad slots (free tier only; Premium is ad-free). Filled by js/ads.js. */
.adslot{margin:14px 0}
.ad-house{display:block;border:1px dashed var(--line);border-radius:8px;padding:15px 18px;text-decoration:none;color:var(--ink2);background:var(--panel);position:relative}
.ad-house:hover{border-color:var(--accent2)}
.ad-house .ad-tag{position:absolute;top:8px;right:10px;font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;color:var(--mute);border:1px solid var(--line);border-radius:4px;padding:1px 5px}
.ad-house b{display:block;color:var(--ink);font-size:15px;margin-bottom:3px}
.ad-house .ad-cta{display:inline-block;margin-top:8px;color:var(--accent);font-weight:700;font-size:13px}

/* ── Motion: subtle, fast, professional. Interactive elements ease on state
   change, primary actions depress slightly on press, and content settles in
   with a gentle rise on load. All of it is switched off for users who ask for
   reduced motion. ── */
a,button,summary,[role="button"],.btn,.theme-btn,.linkbtn,.tabs button,input,select,textarea,.alert-item,.ad-house,.chip,.card{
  transition:background-color var(--t-fast) var(--ease),border-color var(--t-fast) var(--ease),color var(--t-fast) var(--ease),box-shadow var(--t-fast) var(--ease),transform var(--t-fast) var(--ease)}
.btn:active,button:active{transform:translateY(1px)}
.alert-item:hover{border-color:var(--accent2);box-shadow:0 1px 2px rgba(16,24,40,.04),0 6px 18px -14px rgba(16,24,40,.20)}

/* ── Light polish: soft resting depth on cards, a touch more presence on the
   primary CTA. Kept subtle so nothing reads as heavy or "templatey". ── */
.card{box-shadow:0 1px 2px rgba(16,24,40,.04),0 1px 3px rgba(16,24,40,.03)}
.btn.primary{box-shadow:0 1px 2px rgba(23,65,110,.18)}
.btn.primary:hover{box-shadow:0 3px 10px -2px rgba(23,65,110,.30)}
:root[data-theme="dark"] .card{box-shadow:0 1px 2px rgba(0,0,0,.30)}
:root[data-theme="dark"] .btn.primary{box-shadow:0 1px 2px rgba(0,0,0,.35)}

/* ── Page transitions: a light cross-fade + slight rise between full page
   loads, via the cross-document View Transitions API. Progressive enhancement
   — browsers without support just navigate normally. ── */
@view-transition{navigation:auto}
::view-transition-old(root){animation:oc-vt-out .2s var(--ease) both}
::view-transition-new(root){animation:oc-vt-in .28s var(--ease) both}
@keyframes oc-vt-out{to{opacity:0}}
@keyframes oc-vt-in{from{opacity:0;transform:translateY(6px)}to{opacity:1;transform:none}}

/* ── Section reveal: elements tagged .reveal settle in with a gentle fade + rise,
   once, as they enter view (a small IntersectionObserver adds .shown - see
   js/reveal.js for pages that don't already carry their own copy of this logic).
   --i (set inline per element, optional) staggers a cascade of several at once.
   Gated on html.js so no-JS visitors always see content immediately. ── */
html.js .reveal{opacity:0;transform:translateY(18px);
  transition:opacity var(--t-slow) var(--ease),transform var(--t-slow) var(--ease);
  transition-delay:calc(var(--i,0) * 70ms);will-change:opacity,transform}
html.js .reveal.shown{opacity:1;transform:none}

/* ── Skeleton loaders: faintly pulsing placeholders in the shape of the content,
   swapped for real data (which fades in) once it's ready. ── */
@keyframes oc-sk{0%,100%{opacity:1}50%{opacity:.45}}
.sk{display:block;height:12px;border-radius:6px;background:var(--line2);animation:oc-sk 1.25s var(--ease) infinite}
:root[data-theme="dark"] .sk{background:var(--line)}
.sk-card{background:var(--panel);border:1px solid var(--line);border-radius:8px;padding:16px;margin-bottom:12px;display:flex;flex-direction:column;gap:10px}
@keyframes oc-fade-in{from{opacity:0;transform:translateY(4px)}to{opacity:1;transform:none}}
.fade-in{animation:oc-fade-in var(--t-mid) var(--ease) both}

@media(prefers-reduced-motion:reduce){
  *,*::before,*::after{animation-duration:.001ms!important;animation-iteration-count:1!important;transition-duration:.001ms!important;scroll-behavior:auto!important}
  ::view-transition-old(root),::view-transition-new(root){animation:none!important}
  html.js .reveal{opacity:1!important;transform:none!important}
  .sk{animation:none!important}
}

/* ── Mobile: tighten spacing so pages don't feel cramped / overflow on phones ── */
@media(max-width:560px){
  .hd{padding:12px 16px;gap:10px 14px}
  #navAuth{gap:14px;font-size:13px;flex-wrap:wrap}
  main{padding:0 16px;margin:20px auto 44px}
  main h1{font-size:26px;line-height:1.15}
  .lead{font-size:14.5px}
  .card{padding:18px}
  footer{padding-left:16px;padding-right:16px}
  /* flex:1 (see base .tabs rule) still refuses to shrink a button below its text's
     intrinsic width, so a row with several/longer-labelled tabs (e.g. Rankings'
     category switcher) was overflowing the viewport instead of shrinking to fit.
     Let the row scroll horizontally instead of trying to cram everything in. */
  .tabs{overflow-x:auto;-webkit-overflow-scrolling:touch}
  .tabs button{font-size:13px;padding:8px;flex:0 0 auto;white-space:nowrap}
  .alert-item{flex-direction:column;gap:10px}
}

/* ── Readiness meter (shared: Quick Drill, the interview hub, every track page) ──
   Lives here rather than interview.css because Quick Drill loads only app.css, and all
   three render from readyBarHTML() in js/readiness.js. Deliberately minimal: topic,
   score, bar. A previous pass added rank badges, an overall headline and a goal line,
   which made a glanceable strip noisy. */
.readybar{display:grid;grid-template-columns:repeat(auto-fit,minmax(150px,1fr));gap:14px;margin:0 0 20px}
.rtopic .rtop{display:flex;justify-content:space-between;font-size:12px;font-weight:700;color:var(--ink2);margin-bottom:6px}
.rtopic .rtop span:last-child{font-family:var(--mono);color:var(--ink);font-weight:800}
.rbar{height:10px;border-radius:20px;background:var(--line2,var(--line));overflow:hidden}
.rbar i{display:block;height:100%;border-radius:20px;background:var(--gold);
  transition:width .45s cubic-bezier(.22,.7,.2,1)}

/* A followed firm is stored as an alert, so it appears on /alerts alongside saved
   searches. The badge separates "I follow this employer" from "I saved this filter". */
.fbadge{display:inline-block;font-size:10.5px;font-weight:800;letter-spacing:.05em;
  text-transform:uppercase;color:var(--accent);background:color-mix(in srgb,var(--accent) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--accent) 30%,transparent);border-radius:999px;
  padding:2px 8px;vertical-align:1px;margin-right:3px}
