/* ============================================================================
   MSRX IncognitoCV — "Daylight desk" design system
   ----------------------------------------------------------------------------
   One rule governs the whole palette: PAPER is your document, DESK is the tool.
   The ground is a cool, flat working surface. Everything holding the user's own
   words — the two paste sheets, the ten style cards, the finished resume — is a
   warm white sheet lying ON that surface, brighter and warmer than everything
   around it, lifted by a real shadow. Nothing else in the interface is allowed
   to be a raised warm sheet, so the eye always knows where the document is.

   Temperature does the work colour usually does: the tool is cool grey, the
   document is warm white. That difference survives at a glance, at a distance,
   and on a bad monitor.

   No Tailwind. No inline <style>. No inline event handlers — the site's CSP is
   `script-src 'self' <cdn allowlist>` with no 'unsafe-inline', which silently
   nulls onclick= attributes (see the 2026-06-07 incident). Every interaction is
   bound with addEventListener in redesign.js.

   Typography is ONE variable font (Archivo) used at three widths. The width
   axis does the work a second family usually does: 118% for display, 100% for
   running text, 78% for the uppercase utility labels. Fewer bytes, more voice.
   ========================================================================== */

/* --- 1. Font -------------------------------------------------------------- */
/* Self-hosted so it is served from 'self' — the CSP has no font-src directive,
   so it falls back to `default-src 'self'` and any Google Fonts CDN request
   would be blocked outright. Run the fetch command in the README section of
   redesign.html's header comment to populate /fonts. Until then the fallback
   stack below renders a close-enough grotesk and nothing breaks. */
@font-face {
  font-family: "Archivo";
  src: url("/fonts/archivo-var.woff2") format("woff2-variations");
  font-weight: 100 900;
  font-stretch: 62% 125%;
  font-style: normal;
  font-display: swap;
}

/* --- 2. Tokens ------------------------------------------------------------ */
:root {
  /* The desk. Cool and slightly blue so the warm document sitting on it reads
     as a different material rather than a lighter shade of the same one. */
  --surface-sunk: #e5e8ed;   /* recessed wells (raw markdown, code) */
  --surface: #eef0f3;        /* the desk itself */
  --surface-raised: #f7f8fa; /* chrome panels */
  --surface-hi: #ffffff;     /* controls */
  --line: #dce0e6;
  --line-strong: #c4cad3;
  --text-faint: #8a919c;     /* borders and disabled ONLY — 2.6:1, never text */
  --text-muted: #646b77;     /* 4.6:1 on --surface — the floor for real text */
  --text: #14171c;           /* 14.8:1 */

  /* The document. Warm white — the ONE warm surface in the interface. */
  --paper: #fffdf9;
  --paper-edge: #e8e3d8;
  --paper-ink: #23252a;

  /* Accent. Deep brass: 5.0:1 on the desk, so it is safe for real text, not
     just for rules and icons. The bright gold that worked on a dark ground is
     2.1:1 here and would have been decoration pretending to be information. */
  --accent: #8a5f1c;
  --accent-deep: #6e4a14;
  --accent-glow: rgba(138, 95, 28, 0.16);
  --accent-tint: #f4ead6;

  /* Primary action is ink, not brass. On a light ground a filled brass button
     is the weakest possible contrast for the most important control; near-black
     on light is 14:1 and reads as deliberate rather than decorative. */
  --action: #14171c;
  --action-hover: #262b33;
  --on-action: #ffffff;

  --flag: #a8342a;      /* destructive / error — 5.9:1 */
  --flag-tint: #fbeae8;
  --good: #1f6b45;      /* score gains — 5.5:1 */
  --good-tint: #e4f2ea;

  /* MSRX house marks. Deliberately quarantined to the 36px colophon in the
     header and nowhere else — the brand is the publisher's signature, not the
     product's voice. */
  --brand-a: #00c4df;
  --brand-b: #8b5cf6;
  --brand-gradient: linear-gradient(135deg, var(--brand-a) 0%, var(--brand-b) 100%);

  /* 8pt grid. Every margin, padding and gap in this file resolves to one of
     these — there are no loose pixel values below. */
  --s1: 4px;  --s2: 8px;  --s3: 16px; --s4: 24px;
  --s5: 32px; --s6: 48px; --s7: 64px; --s8: 96px;

  --r-sm: 8px; --r-md: 14px; --r-lg: 20px;

  /* Elevation. Two shadows per level: a tight contact shadow that anchors the
     element to the bed, and a wide soft one that gives it air. */
  --lift-1: 0 1px 2px rgba(20,28,45,.07);
  --lift-2: 0 1px 2px rgba(20,28,45,.06), 0 6px 16px -6px rgba(20,28,45,.14);
  --lift-3: 0 2px 4px rgba(20,28,45,.07), 0 24px 48px -16px rgba(20,28,45,.22);

  /* The one easing everything uses. */
  --ease: cubic-bezier(0.16, 1, 0.3, 1);
  --dur: 420ms;
  --dur-fast: 160ms;

  --font-ui: "Archivo", "Archivo Expanded", "Helvetica Neue", Helvetica, Arial, sans-serif;
  --font-mono: ui-monospace, "SF Mono", SFMono-Regular, Menlo, Consolas, monospace;

  --measure: 880px;   /* state A column */
  --rail: 264px;      /* state B left rail */
}

/* --- 3. Reset ------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
html { -webkit-text-size-adjust: 100%; }
body {
  margin: 0;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  background: var(--surface);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: 15px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}
/* Daylight falling across the desk from above. Barely there by design — at
   .05 it reads as the room the desk is in; any stronger and it reads as a
   gradient, which is a different and much cheaper thing. */
body::before {
  content: "";
  position: fixed;
  inset: 0 0 auto 0;
  height: 70vh;
  background: linear-gradient(180deg, rgba(255,255,255,.85), rgba(255,255,255,0) 60%);
  pointer-events: none;
  z-index: 0;
}
h1, h2, h3, p, figure { margin: 0; }
button { font: inherit; color: inherit; background: none; border: 0; cursor: pointer; }
a { color: inherit; }
::selection { background: var(--accent-glow); }

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: var(--r-sm);
}

/* --- 4. Type scale -------------------------------------------------------- */
/* Display: the width axis pushed wide and the tracking pulled tight. Reads as
   something stamped onto a document rather than typed into one. */
.t-display {
  font-size: clamp(30px, 4.4vw, 46px);
  font-stretch: 118%;
  font-weight: 600;
  line-height: 1.06;
  letter-spacing: -0.028em;
}
.t-lede {
  font-size: clamp(15px, 1.9vw, 18px);
  font-weight: 400;
  line-height: 1.5;
  color: var(--text-muted);
  letter-spacing: -0.008em;
}
/* Utility: the same font condensed. Used for every label, every section
   marker, every piece of metadata. Consistency here is what makes the machine
   side of the palette feel like one instrument. */
.t-label {
  font-size: 10px;
  font-stretch: 78%;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: var(--text-muted);
}
.t-meta { font-size: 12px; color: var(--text-muted); letter-spacing: -0.005em; }

/* --- 5. Header ------------------------------------------------------------ */
/* The one place backdrop-blur is used. Glass everywhere is a texture; glass in
   exactly one place is a material. */
.masthead {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  gap: var(--s3);
  padding: var(--s3) var(--s4);
  background: rgba(247, 248, 250, 0.78);
  backdrop-filter: saturate(160%) blur(18px);
  -webkit-backdrop-filter: saturate(160%) blur(18px);
  border-bottom: 1px solid var(--line);
}
.colophon { display: flex; align-items: center; gap: var(--s2); min-width: 0; }
.colophon-mark {
  width: 32px; height: 32px; border-radius: 9px; flex: none;
  box-shadow: var(--lift-1);
}
.colophon-name {
  font-stretch: 112%; font-weight: 700; font-size: 14px; letter-spacing: -0.01em;
  background: var(--brand-gradient);
  -webkit-background-clip: text; background-clip: text; color: transparent;
}
.colophon-product {
  font-size: 14px; font-weight: 500; color: var(--text); letter-spacing: -0.01em;
}
.colophon-sep { color: var(--line-strong); }
/* Carries the product descriptor into state B, where the hero is gone. */
.colophon-desc {
  padding-left: var(--s2); margin-left: var(--s1);
  border-left: 1px solid var(--line);
  font-size: 12px; color: var(--text-muted); white-space: nowrap;
}

.masthead-spacer { flex: 1 1 auto; }

/* The privacy pledge. It is the product's whole differentiator, so it gets the
   only always-on live indicator in the interface — and nothing else does. */
.pledge {
  display: inline-flex; align-items: center; gap: var(--s2);
  padding: 6px var(--s3);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-raised);
  font-size: 11px; font-weight: 500; color: var(--text-muted);
  white-space: nowrap;
}
.pledge-dot {
  width: 6px; height: 6px; border-radius: 50%; flex: none;
  background: var(--accent);
  box-shadow: 0 0 0 3px rgba(227,168,87,.14);
}

/* --- 6. Shell / two states ------------------------------------------------ */
/* Everything below keys off `body.has-output`, toggled in redesign.js from the
   one place the app already knows whether a rewrite exists. Nothing about
   state B is styled speculatively — the controls that only make sense once you
   have a page (styles, exports, the page itself) do not exist until then. */
.shell {
  position: relative;
  z-index: 1;
  flex: 1 1 auto;
  width: 100%;
  margin: 0 auto;
  padding: var(--s5) var(--s4) var(--s7);
  max-width: var(--measure);
  transition: max-width var(--dur) var(--ease);
}
body.has-output .shell {
  max-width: 1280px;
  display: grid;
  grid-template-columns: var(--rail) minmax(0, 1fr);
  gap: var(--s6);
  align-items: start;
  padding-top: var(--s5);
}

/* --- 7. Hero -------------------------------------------------------------- */
.hero { margin-bottom: var(--s4); }
/* The two inputs go in together, so on anything wider than a tablet they sit
   side by side: one decision, one row, and the primary action stays above the
   fold on a 1280x720 laptop. Stacked, the button landed 217px below it. */
@media (min-width: 820px) {
  .composer {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--s4);
    /* stretch, not start: the CV sheet carries an extra note line, and two
       paper sheets of different heights side by side look like a mistake. */
    align-items: stretch;
  }
  .composer .sheet + .sheet { margin-top: 0; }
  .composer .action-row { grid-column: 1 / -1; }
}
.hero-eyebrow { margin-bottom: var(--s3); }
.hero-title { margin-bottom: var(--s3); }
/* The only coloured word on the page in state A. It names the thing the lamp
   is pointed at. */
.hero-title em { font-style: normal; color: var(--accent); }
.hero-lede { max-width: 56ch; }
body.has-output .hero { display: none; }
body.has-output.is-editing .hero { display: block; }

/* --- 7b. Steps -----------------------------------------------------------
   Three numbered steps, kept from the current site. Numbering earns its place
   here because the order IS the instruction — you cannot paste the posting
   before you have a CV in. Set on the machine side of the palette so it reads
   as a caption to the two paper sheets below, not as a third input. */
.steps {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: var(--s2) var(--s4);
  margin: 0 0 var(--s3); padding: 0 0 var(--s2);
  border-bottom: 1px solid var(--line);
  list-style: none;
}
.step {
  display: flex; align-items: baseline; gap: var(--s2);
  font-size: 12.5px; color: var(--text-muted); line-height: 1.45;
}
.step-n {
  flex: none;
  font-size: 10px; font-stretch: 78%; font-weight: 700;
  letter-spacing: 0.1em; color: var(--accent);
  font-variant-numeric: tabular-nums;
}
body.has-output .steps { display: none; }
body.has-output.is-editing .steps { display: grid; }

/* --- 8. Sheets (the paper inputs) ----------------------------------------- */
/* Paste areas are paper because they hold the user's own words. They are the
   only light surfaces in state A, which makes the eye go straight to the one
   thing it has to do. */
.sheet {
  display: flex; flex-direction: column;
  background: var(--paper);
  border: 1px solid var(--paper-edge);
  border-radius: var(--r-md);
  box-shadow: var(--lift-2);
  overflow: hidden;
  transition: box-shadow var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.sheet + .sheet { margin-top: var(--s4); }
.sheet:focus-within {
  box-shadow: var(--lift-3), 0 0 0 2px var(--accent);
}
.sheet-head {
  display: flex; align-items: center; gap: var(--s3);
  padding: var(--s3) var(--s3) var(--s2);
  border-bottom: 1px solid var(--paper-edge);
}
.sheet-head .t-label { color: #6b7180; }
.sheet-head-spacer { flex: 1 1 auto; }

/* File picker. A <label> wrapping a hidden input — no JS, no custom control,
   and it keeps native keyboard behaviour. */
.file-pick {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 4px var(--s2);
  border-radius: var(--r-sm);
  font-size: 11px; font-weight: 600; color: var(--accent-deep);
  cursor: pointer;
  transition: background var(--dur-fast) var(--ease);
}
.file-pick:hover { background: rgba(184,127,53,.1); }
.file-pick input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }
.file-pick:focus-within { outline: 2px solid var(--accent-deep); outline-offset: 2px; }

.dropzone { position: relative; flex: 1 1 auto; display: flex; }
.dropzone textarea {
  display: block; width: 100%; flex: 1 1 auto;
  padding: var(--s3);
  border: 0; background: transparent; resize: none;
  color: var(--paper-ink);
  font-family: var(--font-mono);   /* raw = monospace, typeset = the page. */
  font-size: 12.5px; line-height: 1.7;
}
.dropzone textarea:focus { outline: none; }
.dropzone textarea::placeholder { color: #9a9a94; }
.drop-hint {
  position: absolute; inset: 0; z-index: 2;
  display: flex; align-items: center; justify-content: center; gap: var(--s2);
  background: rgba(251,250,247,.94);
  border: 2px dashed var(--accent-deep);
  border-radius: var(--r-sm);
  color: var(--accent-deep); font-size: 12px; font-weight: 600;
  pointer-events: none;
}
.drop-hint.hidden { display: none; }

/* Sits on the paper, under the paste area — it is a statement about the file
   you just dropped, so it belongs on the document side, not in the chrome. */
/* The paste area scrolls its own content, so this needs an opaque background
   and a rule of its own — otherwise long text scrolls up behind it and reads
   as overlapping. */
.sheet-note {
  flex: none;
  padding: var(--s2) var(--s3) var(--s3);
  border-top: 1px solid var(--paper-edge);
  background: var(--paper);
  font-size: 11px; line-height: 1.45; color: #7f8189;
}

/* --- 9. Action ------------------------------------------------------------ */
.action-row {
  margin-top: var(--s4);
  display: flex; flex-direction: column; align-items: center; gap: var(--s3);
}
.btn-primary {
  display: inline-flex; align-items: center; justify-content: center;
  /* Capped rather than full-bleed: a 900px slab of brass out-shouts the lit
     page, which is the thing this design is actually built around. */
  width: 100%; max-width: 380px;
  padding: var(--s3) var(--s5);
  border-radius: var(--r-md);
  background: var(--action);
  color: var(--on-action);
  font-size: 15px; font-weight: 700; letter-spacing: -0.012em;
  box-shadow: 0 1px 2px rgba(20,28,45,.18), 0 10px 24px -10px rgba(20,28,45,.5);
  transition: transform var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.btn-primary:hover { background: var(--action-hover); box-shadow: 0 2px 4px rgba(20,28,45,.2), 0 16px 32px -12px rgba(20,28,45,.55); }
.btn-primary:active { transform: translateY(1px); }

/* Settings live here — one line of plain text, not a panel. The model choice
   matters to roughly nobody on their first run, so it does not get a card. */
.settings-line {
  display: flex; align-items: center; gap: var(--s2);
  font-size: 12px; color: var(--text-muted);
}
.settings-line select {
  appearance: none;
  padding: 4px var(--s4) 4px var(--s2);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-raised) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='6' fill='none'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23646b77' stroke-width='1.5' stroke-linecap='round'/%3E%3C/svg%3E") no-repeat right 8px center;
  color: var(--text); font: inherit; font-size: 12px;
  cursor: pointer;
}
.btn-quiet {
  padding: 4px var(--s2);
  border-radius: var(--r-sm);
  font-size: 12px; color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease);
}
.btn-quiet:hover { color: var(--text); background: var(--surface-hi); }
.btn-quiet.is-danger:hover { color: var(--flag); background: rgba(224,115,106,.1); }
.settings-sep { color: var(--line-strong); }

/* Nothing to rewrite yet — say so on the control rather than letting the click
   through to an error. The disabled reason is announced, not just implied. */
.btn-primary:disabled {
  background: var(--surface-sunk);
  color: var(--text-faint);
  box-shadow: inset 0 0 0 1px var(--line);
  cursor: not-allowed;
}
.btn-primary:disabled:hover { background: var(--surface-sunk); transform: none; }
.action-hint {
  min-height: 16px;
  font-size: 12px; color: var(--text-muted);
}

/* --- 10. Assurances ------------------------------------------------------- */
.assurances {
  margin-top: var(--s6);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; gap: var(--s2) var(--s4);
  font-size: 12px; color: var(--text-muted);
}
.assurances li { list-style: none; }
.assurances ul { display: contents; margin: 0; padding: 0; }

/* --- 11. State B: the rail ------------------------------------------------ */
/* Once there is a page, the inputs stop being the task. They collapse to a
   summary of what went in, with one control to reopen them. */
/* `.column` is a grid item in state B; without min-width:0 its default
   min-width:auto lets long content push the whole grid wider than the screen. */
.column { min-width: 0; }
/* Source order puts the assurances after the composer, which reads correctly
   in state A. Once the composer collapses they would float to the top of the
   column, above the gallery — flex order sends them back to the bottom without
   duplicating them in the markup. */
body.has-output .column { display: flex; flex-direction: column; }
body.has-output .stage { order: 1; }
body.has-output .assurances { order: 2; }

.rail { display: none; position: sticky; top: var(--s8); min-width: 0; }
body.has-output .rail { display: block; }
.rail-group + .rail-group { margin-top: var(--s4); }
.rail-label { margin-bottom: 6px; }
.rail-value {
  display: block; max-width: 100%;
  padding: var(--s2) var(--s3);
  border: 1px solid var(--line); border-left: 2px solid var(--accent);
  border-radius: 0 var(--r-sm) var(--r-sm) 0;
  background: var(--surface-raised);
  font-size: 12px; color: var(--text);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.rail-actions { margin-top: var(--s4); padding-top: var(--s4); border-top: 1px solid var(--line); display: flex; flex-direction: column; align-items: flex-start; gap: var(--s1); }

/* In state B the whole input block folds away behind one control. Real
   progressive disclosure: it is not hidden decoration, it is a step you have
   finished. */
body.has-output .composer { display: none; }
body.has-output.is-editing .composer { display: block; }
body.has-output.is-editing .stage { display: none; }

/* --- 12. State B: the stage (SIGNATURE) ----------------------------------- */
/* The single memorable thing on this site: the finished résumé, typeset at
   full size, lit. Every other résumé tool shows you a scrolling text blob and
   hides the typeset version behind a thumbnail. Here the page is the interface
   — the style strip below it re-typesets this same page in place. */
/* Always present. The current site shows an empty output panel and ten empty
   style cards from the first paint, and hiding them made the redesign read as
   a smaller product. What changes with state is the CONTENT and the layout,
   never whether a capability appears to exist. */
.stage { display: block; margin-top: var(--s6); }
body.has-output .stage { margin-top: 0; }

/* The blank sheet, and the lamp turned down because there is nothing on it. */
.stage-placeholder {
  width: 600px; max-width: 100%; min-height: 300px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: var(--s2);
  padding: var(--s6) var(--s4);
  border-radius: 2px;
  background: var(--paper);
  color: #8a8c92;
  text-align: center;
  box-shadow: 0 0 0 1px var(--paper-edge), 0 2px 4px rgba(20,28,45,.06), 0 20px 44px -20px rgba(20,28,45,.2);
}
.stage-placeholder p { font-size: 14px; }
.stage-placeholder-sub { font-size: 12px; color: #a4a6ac; }
body:not(.has-output) .stage-lamp::before { opacity: .3; }
body.has-output .stage-placeholder { display: none; }
body:not(.has-output) .stage-page { display: none; }

/* Exports and the raw-Markdown escape hatch stay visible but inert until there
   is something to export — visible-and-disabled tells the truth, whereas the
   current site lets you click them and silently does nothing. */
.btn-export:disabled,
.raw[data-empty="true"] > summary {
  color: var(--text-faint);
  cursor: not-allowed;
}
.btn-export:disabled:hover { border-color: var(--line); background: var(--surface-raised); transform: none; }

.stage-lamp {
  position: relative;
  display: flex; justify-content: center;
  padding: var(--s6) 0 var(--s6);
}
/* On a light ground a glow is invisible, so the page is separated the way a
   real sheet on a real desk is: a faint cool cast on the surface around it plus
   a genuine contact shadow. max-width caps this to the column so an absolutely
   positioned decoration can never widen the document on a phone. */
.stage-lamp::before {
  content: "";
  position: absolute;
  top: 0; left: 50%; transform: translateX(-50%);
  width: 1120px; max-width: 100%; height: 76%;
  background: radial-gradient(52% 46% at 50% 34%, rgba(20,28,45,.055), transparent 72%);
  filter: blur(30px);
  pointer-events: none;
}
.stage-page {
  position: relative;
  border-radius: 2px;
  /* The document sits ON the desk: a hairline edge, a tight contact shadow at
     the bottom, and a wide soft one for air. */
  box-shadow:
    0 0 0 1px var(--paper-edge),
    0 2px 4px rgba(20,28,45,.08),
    0 28px 56px -20px rgba(20,28,45,.28);
  animation: page-settle var(--dur) var(--ease) both;
}
@keyframes page-settle {
  from { opacity: 0; transform: translateY(12px) scale(.985); }
  to   { opacity: 1; transform: none; }
}

/* Style strip — the selector, not the show. Ten of them, so a horizontal strip
   beats a 5x2 grid: it stays one row of one decision. */
.strip-label { display: block; margin-bottom: var(--s1); }
.strip-note {
  max-width: 68ch;
  margin-bottom: var(--s3);
  font-size: 12px; color: var(--text-muted);
}
/* Names the output panel the way the current site's header did — the stage has
   to be identifiable before there is anything on it. */
.stage-title {
  display: block;
  margin-top: var(--s5);
  padding-top: var(--s4);
  border-top: 1px solid var(--line);
}
.strip {
  display: flex; gap: var(--s3);
  /* 4px of top padding so the hover lift and the brass selection ring are not
     clipped by the scroll container (overflow-x:auto forces overflow-y:auto). */
  padding: var(--s1) 0 var(--s3);
  overflow-x: auto;
  scroll-snap-type: x proximity;
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}
.strip::-webkit-scrollbar { height: 6px; }
.strip::-webkit-scrollbar-track { background: transparent; }
.strip::-webkit-scrollbar-thumb { background: var(--line-strong); border-radius: 3px; }
.strip::-webkit-scrollbar-thumb:hover { background: var(--text-faint); }
.preview-card {
  position: relative;
  flex: none; width: 84px;
  display: flex; flex-direction: column; align-items: center; gap: 6px;
  scroll-snap-align: start;
}

/* Per-style Word/PDF, kept from the current site: you can export ANY of the
   ten without first making it the one on the stage. They stay out of sight
   until you hover or tab into the card, so ten cards read as ten choices
   rather than thirty controls — the capability is intact, the clutter is not.
   The layer is pointer-events:none so a click anywhere else on the thumbnail
   still selects; only the two buttons take the pointer. */
.thumb-actions {
  position: absolute; top: var(--s1); left: 0; right: 0; height: 112px;
  display: flex; align-items: flex-end; justify-content: center; gap: 5px;
  padding-bottom: 7px;
  border-radius: var(--r-sm);
  background: linear-gradient(to top, rgba(15,17,21,.86) 34%, transparent 72%);
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--dur-fast) var(--ease);
}
.preview-card:hover .thumb-actions,
.preview-card:focus-within .thumb-actions { opacity: 1; }
.thumb-btn {
  pointer-events: auto;
  display: inline-flex; align-items: center; justify-content: center;
  padding: 3px 6px;
  border-radius: 5px;
  background: rgba(255,255,255,.1);
  transition: background var(--dur-fast) var(--ease);
}
.thumb-btn:hover { background: rgba(255,255,255,.22); }
.fmt {
  display: inline-block;
  padding: 1px 4px; border-radius: 3px;
  font-size: 8px; font-weight: 800; font-stretch: 78%; letter-spacing: 0.04em;
  color: #fff; line-height: 1.35;
}
.fmt-word { background: linear-gradient(135deg, #2f7fe8, #1851a3); }
.fmt-pdf  { background: linear-gradient(135deg, #ff6b5e, #d32a2a); }
.preview-thumb-wrap {
  position: relative; cursor: pointer; border-radius: var(--r-sm);
  transition: transform var(--dur-fast) var(--ease);
}
.preview-thumb-wrap:hover { transform: translateY(-2px); }
.preview-thumb {
  position: relative; width: 84px; height: 112px; overflow: hidden;
  border-radius: var(--r-sm);
  border: 1px solid var(--line);
  background: var(--paper);
  box-shadow: var(--lift-1);
  transition: border-color var(--dur-fast) var(--ease), box-shadow var(--dur-fast) var(--ease);
}
.preview-thumb .resume-preview-page { transform: scale(0.14); transform-origin: top left; }
.preview-card .strip-name {
  font-size: 11px; font-weight: 500; color: var(--text-muted);
  transition: color var(--dur-fast) var(--ease);
}
.preview-card.is-selected .preview-thumb {
  border-color: var(--accent);
  box-shadow: 0 0 0 2px var(--accent), 0 6px 16px -8px rgba(20,28,45,.25);
}
.preview-card.is-selected .strip-name { color: var(--accent); }

/* Exports act on whatever style is showing. One row, three verbs, no per-card
   buttons — those turned ten cards into thirty controls. */
/* No border-top here — .stage-title above it already draws the divider that
   separates the gallery from the output. Two rules 70px apart read as a bug. */
.exports {
  margin-top: var(--s3);
  display: flex; flex-wrap: wrap; align-items: center; gap: var(--s2);
}
.btn-export {
  display: inline-flex; align-items: center; gap: 6px;
  padding: var(--s2) var(--s3);
  border: 1px solid var(--line); border-radius: var(--r-sm);
  background: var(--surface-raised);
  font-size: 13px; font-weight: 600; color: var(--text);
  transition: border-color var(--dur-fast) var(--ease), background var(--dur-fast) var(--ease), transform var(--dur-fast) var(--ease);
}
.btn-export:hover { border-color: var(--text-faint); background: var(--surface-hi); transform: translateY(-1px); }
.exports-spacer { flex: 1 1 auto; }

/* Raw Markdown is a power-user escape hatch, so it lives behind a disclosure
   rather than occupying the largest panel on the screen (which is what the
   current site does). */
.raw { margin-top: var(--s4); }
.raw > summary {
  display: inline-flex; align-items: center; gap: 6px;
  cursor: pointer; list-style: none;
  font-size: 12px; color: var(--text-muted);
}
.raw > summary::-webkit-details-marker { display: none; }
.raw > summary:hover { color: var(--text); }
.raw[open] > summary { margin-bottom: var(--s2); }
.raw textarea {
  width: 100%; min-height: 260px;
  padding: var(--s3);
  border: 1px solid var(--line); border-radius: var(--r-md);
  background: var(--surface-sunk);
  color: var(--paper-ink);
  font-family: var(--font-mono); font-size: 12px; line-height: 1.7;
  resize: vertical;
}

/* --- 13. Working overlay -------------------------------------------------- */
/* Ten seconds of waiting, so it says what it is doing rather than spinning. */
.working {
  position: fixed; inset: 0; z-index: 60;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: var(--s4);
  background: rgba(238,240,243,.9);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}
.working.hidden { display: none; }
.working-lamp {
  width: 56px; height: 56px; border-radius: 50%;
  background: radial-gradient(circle, var(--accent) 0%, transparent 68%);
  animation: breathe 2.4s var(--ease) infinite;
}
@keyframes breathe {
  0%, 100% { opacity: .35; transform: scale(.86); }
  50%      { opacity: 1;   transform: scale(1.06); }
}

/* --- 14. Toast ------------------------------------------------------------ */
/* Replaces every window.alert() in core.js. A blocking OS dialog is the single
   loudest "this is a weekend project" signal a polished tool can emit. */
.toast-stack {
  position: fixed; z-index: 80;
  left: 50%; bottom: var(--s4); transform: translateX(-50%);
  display: flex; flex-direction: column; gap: var(--s2);
  width: min(420px, calc(100vw - var(--s5)));
}
.toast {
  padding: var(--s3);
  border: 1px solid var(--line); border-left: 3px solid var(--accent);
  border-radius: var(--r-sm);
  background: var(--surface-hi);
  box-shadow: var(--lift-3);
  font-size: 13px; color: var(--text);
  line-height: 1.45;
  animation: toast-in 320ms var(--ease) both;
}
@keyframes toast-in {
  from { opacity: 0; transform: translateY(10px); }
  to   { opacity: 1; transform: none; }
}

/* --- 15. Footer ----------------------------------------------------------- */
.footer {
  position: relative; z-index: 1;
  padding: var(--s4);
  border-top: 1px solid var(--line);
  display: flex; flex-wrap: wrap; align-items: center; justify-content: center;
  gap: var(--s2) var(--s4);
  font-size: 12px; color: var(--text-muted);
}
.footer a { text-decoration: none; }
.footer a:hover { color: var(--accent); }

/* --- 16. Modal stubs ------------------------------------------------------ */
/* core.js caches these five nodes unconditionally in initializeInterface() and
   would throw on a null. The redesign replaces the zoom modal with the stage,
   so the nodes stay in the DOM, inert, and redesign.js no-ops the open call.
   Removing them is a core.js change and this file is meant to be droppable
   without one. */
#previewModal { display: none !important; }

/* --- 17. Résumé page renderer -------------------------------------------- */
/* Carried over VERBATIM from the old index.html <style> block. core.js writes
   --rp-accent / --rp-faint / --rp-name-font / --rp-body-font / --rp-density
   onto .resume-preview-page per theme, and the DOCX and PDF builders mirror
   these exact rules — the preview is a promise about the downloaded file, so
   nothing here may drift. Notably the font stacks stay as system serif/sans
   (Georgia/Cambria, Helvetica/Calibri) rather than the site's webfont: those
   are the families Word and the PDF actually embed. Restyling the page in
   Archivo would make every thumbnail lie about the export. */
.resume-preview-page {
  width: 600px; padding: 42px 48px; background: #ffffff; color: #2a2a2d;
  font-family: var(--rp-body-font, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif);
  font-size: 11px; line-height: calc(1.6 * var(--rp-density, 1));
}
.resume-preview-page .rp-name {
  margin: 0 0 calc(14px * var(--rp-density, 1)); padding-bottom: calc(14px * var(--rp-density, 1));
  border-bottom: 2px solid var(--rp-accent); font-family: var(--rp-name-font, inherit);
  text-align: center; font-size: 21px; font-weight: 700; letter-spacing: 0.01em; color: #1d1d1f;
}
.resume-preview-page .rp-name.rp-name--band {
  text-align: left; border-bottom: none; border-radius: 4px;
  background: var(--rp-accent); color: #ffffff; padding: 12px 18px;
}
.resume-preview-page .rp-name.rp-name--monogram {
  text-align: left; border-bottom: none; display: flex; align-items: center; gap: 10px;
}
.resume-preview-page .rp-name.rp-name--sideRule {
  text-align: left; border-bottom: none; padding-bottom: 0;
  border-left: 4px solid var(--rp-accent); padding-left: 14px;
}
.resume-preview-page .rp-monogram-badge {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 28px; height: 28px; border-radius: 50%; background: var(--rp-accent);
  color: #ffffff; font-size: 11px; font-weight: 700; font-family: var(--rp-body-font, inherit);
}
.resume-preview-page .rp-section {
  margin: calc(18px * var(--rp-density, 1)) 0 calc(8px * var(--rp-density, 1));
  padding-bottom: 5px; border-bottom: 1px solid var(--rp-faint);
  font-size: 12px; font-weight: 700; letter-spacing: 0.09em; text-transform: uppercase; color: var(--rp-accent);
}
.resume-preview-page .rp-section:first-child { margin-top: 0; }
.resume-preview-page .rp-section.rp-section--bracket {
  border-bottom: none; letter-spacing: 0.04em;
  font-family: ui-monospace, "SF Mono", Menlo, Consolas, monospace;
}
.resume-preview-page .rp-section.rp-section--bracket::before { content: "[ "; }
.resume-preview-page .rp-section.rp-section--bracket::after { content: " ]"; }
.resume-preview-page .rp-section.rp-section--band {
  display: inline-block; border-bottom: none; border-radius: 3px;
  background: var(--rp-accent); color: #ffffff; padding: 3px 12px;
}
.resume-preview-page .rp-subhead {
  margin: calc(10px * var(--rp-density, 1)) 0 calc(3px * var(--rp-density, 1));
  font-size: 12px; font-weight: 700; color: var(--rp-accent);
}
.resume-preview-page .rp-paragraph { margin: 0 0 calc(7px * var(--rp-density, 1)); }
.resume-preview-page .rp-bullet { position: relative; margin: 0 0 calc(5px * var(--rp-density, 1)); padding-left: 15px; }
.resume-preview-page .rp-bullet .rp-dot { position: absolute; left: 0; color: var(--rp-accent); }

/* --- 18. Utilities -------------------------------------------------------- */
.hidden { display: none !important; }
.sr-only {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}

/* --- 19. Responsive ------------------------------------------------------- */
/* The stage page is a fixed 600px because core.js builds it that way and the
   DOCX/PDF renderers share those metrics. `zoom` scales it without leaving a
   600px-wide layout box behind, which `transform: scale()` would. */
/* Below the two-column threshold the rail stops being a sidebar and becomes a
   wrapping summary row. Each cell needs min-width:0 so its nowrap text
   ellipsises instead of shrink-wrapping to its full length and overflowing. */
@media (max-width: 1100px) {
  body.has-output .shell { grid-template-columns: 1fr; gap: var(--s5); }
  body.has-output .rail {
    display: flex; flex-wrap: wrap; align-items: flex-end;
    gap: var(--s3) var(--s4);
    position: static;
  }
  .rail-group { flex: 1 1 200px; min-width: 0; }
  .rail-group + .rail-group { margin-top: 0; }
  .rail-actions {
    flex: 1 1 100%;
    flex-direction: row; align-items: center; gap: var(--s4);
    margin-top: 0; padding-top: var(--s3);
  }
}
@media (max-width: 760px) {
  .shell { padding: var(--s5) var(--s3) var(--s7); }
  .masthead { padding: var(--s3); }
  .colophon-product, .colophon-sep, .colophon-desc { display: none; }
  /* Three steps in three columns is ~110px each on a phone — one per line. */
  .steps { grid-template-columns: 1fr; gap: var(--s2); }
  .settings-line { flex-wrap: wrap; justify-content: center; }
  /* zoom rather than transform: scale() — scale leaves the original 600px
     layout box behind, which is exactly what overflows a phone. */
  .stage-page { zoom: 0.58; }
  .stage-lamp { padding: var(--s4) 0 var(--s3); }
  .assurances { gap: var(--s2) var(--s3); }
}
@media (max-width: 420px) {
  .stage-page { zoom: 0.46; }
  /* Hide the label, keep the dot — .pledge-dot is a span too, so a bare
     `.pledge span` rule blanks the pill into an empty circle. */
  .pledge > span:not(.pledge-dot) { display: none; }
  .pledge { padding: 7px; }
}

/* --- 20. Reduced motion --------------------------------------------------- */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after {
    animation-duration: 1ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 1ms !important;
  }
  .working-lamp { opacity: 1; }
}

/* --- 21. Fit report -------------------------------------------------------
   The product's centre of gravity, so it gets the one piece of chrome nothing
   else has: a raised panel with a real edge. Everything in it is computed by
   match.js from the two text boxes — no inference, no network, no variance. */
.report {
  margin-top: var(--s5);
  padding: var(--s4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--surface-raised);
  box-shadow: var(--lift-1);
}
.report[hidden] { display: none; }
.report-head {
  display: flex; align-items: flex-start; justify-content: space-between; gap: var(--s3);
  margin-bottom: var(--s4);
}
.report-sub { margin-top: var(--s1); font-size: 12px; color: var(--text-muted); }
.report-body {
  display: grid;
  grid-template-columns: 168px minmax(0, 1fr);
  gap: var(--s5);
  align-items: start;
}
.report-note {
  margin-top: var(--s4); padding-top: var(--s3);
  border-top: 1px solid var(--line);
  font-size: 11px; line-height: 1.5; color: var(--text-muted);
  max-width: 76ch;
}

/* The score. A conic-gradient ring rather than an SVG arc: no path maths, no
   viewBox to keep in sync, and it animates the sweep for free. */
.gauge { text-align: center; }
.gauge-ring {
  --pct: 0;
  width: 132px; height: 132px; margin: 0 auto var(--s2);
  border-radius: 50%;
  background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--line) 0);
  display: flex; align-items: center; justify-content: center;
  transition: background var(--dur) var(--ease);
}
.gauge-face {
  width: 106px; height: 106px; border-radius: 50%;
  background: var(--surface-raised);
  display: flex; align-items: baseline; justify-content: center; gap: 1px;
}
.gauge-score {
  font-size: 38px; font-stretch: 108%; font-weight: 700;
  letter-spacing: -0.03em; color: var(--text);
  font-variant-numeric: tabular-nums;
}
.gauge-unit { font-size: 15px; font-weight: 600; color: var(--text-muted); }
.gauge-delta {
  display: inline-flex; align-items: center; gap: 4px;
  padding: 3px var(--s2); border-radius: 999px;
  font-size: 12px; font-weight: 700;
  background: var(--good-tint); color: var(--good);
}
.gauge-delta:empty { display: none; }
.gauge-caption { margin-top: var(--s2); font-size: 11px; line-height: 1.45; color: var(--text-muted); }

.report-cols {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(190px, 1fr));
  gap: var(--s4);
}
.report-col > .t-label { display: block; margin-bottom: var(--s2); }
.report-count { color: var(--text-faint); letter-spacing: 0.08em; }
.report-hint { margin-top: var(--s2); font-size: 11px; line-height: 1.45; color: var(--text-muted); }

/* Keyword chips. Monospace because these are literal strings to paste, not
   prose — the reader needs to see the exact token the posting used. */
.chips { display: flex; flex-wrap: wrap; gap: 6px; margin: 0; padding: 0; list-style: none; }
.chips li {
  padding: 3px var(--s2);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--surface-hi);
  font-family: var(--font-mono); font-size: 11px; color: var(--text);
}
.chips li.is-hard { border-color: var(--accent); background: var(--accent-tint); color: var(--accent-deep); }
.chips-good li { border-color: var(--good); background: var(--good-tint); color: var(--good); }

.findings { margin: 0; padding: 0; list-style: none; display: flex; flex-direction: column; gap: var(--s2); }
.findings li { font-size: 12px; line-height: 1.45; color: var(--text-muted); }
.findings b { display: block; font-weight: 700; font-size: 12px; }
.findings .is-fail b { color: var(--flag); }
.findings .is-warn b { color: var(--accent-deep); }
.findings .is-pass b { color: var(--good); }

/* --- 22. Cover letter ----------------------------------------------------- */
.btn-export--alt { border-style: dashed; }
.cover { margin-top: var(--s4); }
.cover[hidden] { display: none; }
.cover > summary {
  cursor: pointer; list-style: none;
  font-size: 12px; font-stretch: 78%; font-weight: 700;
  letter-spacing: 0.16em; text-transform: uppercase; color: var(--text-muted);
}
.cover > summary::-webkit-details-marker { display: none; }
.cover textarea {
  width: 100%; min-height: 300px; margin-top: var(--s2);
  padding: var(--s4);
  border: 1px solid var(--paper-edge); border-radius: var(--r-sm);
  background: var(--paper); color: var(--paper-ink);
  font-family: var(--font-ui); font-size: 13.5px; line-height: 1.65;
  resize: vertical;
  box-shadow: var(--lift-1);
}
.cover-actions { margin-top: var(--s2); display: flex; flex-wrap: wrap; gap: var(--s2); }

/* --- 23. Streaming -------------------------------------------------------- */
/* While tokens are arriving the page is real but incomplete, so it says so
   rather than pretending to be finished. */
body.is-streaming .stage-page { animation: none; }
.stream-flag {
  display: none;
  align-items: center; gap: var(--s2);
  margin-bottom: var(--s2);
  font-size: 12px; color: var(--accent-deep);
}
body.is-streaming .stream-flag { display: inline-flex; }
.stream-dot {
  width: 7px; height: 7px; border-radius: 50%; background: var(--accent);
  animation: pulse 1.1s ease-in-out infinite;
}
@keyframes pulse { 0%,100% { opacity: .25; } 50% { opacity: 1; } }

@media (max-width: 760px) {
  .report-body { grid-template-columns: 1fr; gap: var(--s4); }
  .gauge-ring { width: 108px; height: 108px; }
  .gauge-face { width: 86px; height: 86px; }
  .gauge-score { font-size: 30px; }
}
